Browse Source

Fix property access of call expression (#2273)

Fix a syntax error when accessing literal-like property names of call expression.
e.g.) `fn().true`
pull/2277/head
Choongwoo Han 2 years ago
parent
commit
90ec460b3f
  1. 17
      boa_engine/src/syntax/parser/expression/left_hand_side/call.rs
  2. 30
      boa_engine/src/syntax/parser/expression/left_hand_side/member.rs
  3. 3
      boa_engine/src/syntax/parser/expression/left_hand_side/mod.rs
  4. 51
      boa_engine/src/syntax/parser/expression/left_hand_side/tests.rs
  5. 8
      boa_interner/src/sym.rs

17
boa_engine/src/syntax/parser/expression/left_hand_side/call.rs

@ -11,7 +11,7 @@ use super::arguments::Arguments;
use crate::syntax::{
ast::{
node::{
field::{GetConstField, GetField},
field::{get_private_field::GetPrivateField, GetConstField, GetField},
Call, Node,
},
Punctuator,
@ -22,7 +22,7 @@ use crate::syntax::{
AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser,
},
};
use boa_interner::Interner;
use boa_interner::{Interner, Sym};
use boa_profiler::Profiler;
use std::io::Read;
@ -97,6 +97,19 @@ where
TokenKind::Keyword((kw, _)) => {
lhs = GetConstField::new(lhs, kw.to_sym(interner)).into();
}
TokenKind::BooleanLiteral(true) => {
lhs = GetConstField::new(lhs, Sym::TRUE).into();
}
TokenKind::BooleanLiteral(false) => {
lhs = GetConstField::new(lhs, Sym::FALSE).into();
}
TokenKind::NullLiteral => {
lhs = GetConstField::new(lhs, Sym::NULL).into();
}
TokenKind::PrivateIdentifier(name) => {
cursor.push_used_private_identifier(*name, token.span().start())?;
lhs = GetPrivateField::new(lhs, *name).into();
}
_ => {
return Err(ParseError::expected(
["identifier".to_owned()],

30
boa_engine/src/syntax/parser/expression/left_hand_side/member.rs

@ -95,15 +95,9 @@ where
let field = match token.kind() {
TokenKind::Identifier(name) => GetSuperField::from(*name),
TokenKind::Keyword((kw, _)) => GetSuperField::from(kw.to_sym(interner)),
TokenKind::BooleanLiteral(true) => {
GetSuperField::from(Keyword::True.to_sym(interner))
}
TokenKind::BooleanLiteral(false) => {
GetSuperField::from(Keyword::False.to_sym(interner))
}
TokenKind::NullLiteral => {
GetSuperField::from(Keyword::Null.to_sym(interner))
}
TokenKind::BooleanLiteral(true) => GetSuperField::from(Sym::TRUE),
TokenKind::BooleanLiteral(false) => GetSuperField::from(Sym::FALSE),
TokenKind::NullLiteral => GetSuperField::from(Sym::NULL),
TokenKind::PrivateIdentifier(_) => {
return Err(ParseError::general(
"unexpected private identifier",
@ -153,20 +147,14 @@ where
TokenKind::Keyword((kw, _)) => {
lhs = GetConstField::new(lhs, kw.to_sym(interner)).into();
}
TokenKind::BooleanLiteral(bool) => {
match bool {
true => {
lhs = GetConstField::new(lhs, Keyword::True.to_sym(interner))
.into();
}
false => {
lhs = GetConstField::new(lhs, Keyword::False.to_sym(interner))
.into();
}
};
TokenKind::BooleanLiteral(true) => {
lhs = GetConstField::new(lhs, Sym::TRUE).into();
}
TokenKind::BooleanLiteral(false) => {
lhs = GetConstField::new(lhs, Sym::FALSE).into();
}
TokenKind::NullLiteral => {
lhs = GetConstField::new(lhs, Keyword::Null.to_sym(interner)).into();
lhs = GetConstField::new(lhs, Sym::NULL).into();
}
TokenKind::PrivateIdentifier(name) => {
cursor.push_used_private_identifier(*name, token.span().start())?;

3
boa_engine/src/syntax/parser/expression/left_hand_side/mod.rs

@ -7,6 +7,9 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Left-hand-side_expressions
//! [spec]: https://tc39.es/ecma262/#sec-left-hand-side-expressions
#[cfg(test)]
mod tests;
mod arguments;
mod call;
mod member;

51
boa_engine/src/syntax/parser/expression/left_hand_side/tests.rs

@ -0,0 +1,51 @@
use crate::syntax::{
ast::node::{field::GetConstField, Call, Identifier},
parser::tests::check_parser,
};
use boa_interner::Interner;
#[track_caller]
fn check_call_property_identifier(property_name: &'static str) {
let mut interner = Interner::default();
check_parser(
format!("a().{}", property_name).as_str(),
vec![GetConstField::new(
Call::new(Identifier::new(interner.get_or_intern_static("a")), vec![]),
interner.get_or_intern_static(property_name),
)
.into()],
interner,
);
}
#[test]
fn check_call_properties() {
check_call_property_identifier("prop");
check_call_property_identifier("true");
check_call_property_identifier("false");
check_call_property_identifier("null");
check_call_property_identifier("let");
}
#[track_caller]
fn check_member_property_identifier(property_name: &'static str) {
let mut interner = Interner::default();
check_parser(
format!("a.{}", property_name).as_str(),
vec![GetConstField::new(
Identifier::new(interner.get_or_intern_static("a")),
interner.get_or_intern_static(property_name),
)
.into()],
interner,
);
}
#[test]
fn check_member_properties() {
check_member_property_identifier("prop");
check_member_property_identifier("true");
check_member_property_identifier("false");
check_member_property_identifier("null");
check_member_property_identifier("let");
}

8
boa_interner/src/sym.rs

@ -85,6 +85,12 @@ impl Sym {
/// Symbol for the `"anonymous"` string.
pub const ANONYMOUS: Self = unsafe { Self::new_unchecked(23) };
/// Symbol for the `"true"` string.
pub const TRUE: Self = unsafe { Self::new_unchecked(24) };
/// Symbol for the `"false"` string.
pub const FALSE: Self = unsafe { Self::new_unchecked(25) };
/// Creates a new [`Sym`] from the provided `value`, or returns `None` if `index` is zero.
#[inline]
pub(super) fn new(value: usize) -> Option<Self> {
@ -145,6 +151,8 @@ pub(super) static COMMON_STRINGS: phf::OrderedSet<&'static str> = {
"protected",
"public",
"anonymous",
"true",
"false",
};
// A `COMMON_STRINGS` of size `usize::MAX` would cause an overflow on our `Interner`
sa::const_assert!(COMMON_STRINGS.len() < usize::MAX);

Loading…
Cancel
Save