Browse Source

Added `BindingIdentifier` parsing. (#389)

pull/391/head
Iban Eguia 5 years ago committed by GitHub
parent
commit
143434f643
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      boa/src/exec/tests.rs
  2. 43
      boa/src/syntax/parser/expression/assignment/arrow_function.rs
  3. 4
      boa/src/syntax/parser/expression/assignment/mod.rs
  4. 19
      boa/src/syntax/parser/expression/primary/function_expression.rs
  5. 2
      boa/src/syntax/parser/expression/primary/mod.rs
  6. 65
      boa/src/syntax/parser/function/mod.rs
  7. 1
      boa/src/syntax/parser/statement/break_stm/mod.rs
  8. 1
      boa/src/syntax/parser/statement/continue_stm/mod.rs
  9. 17
      boa/src/syntax/parser/statement/declaration/hoistable.rs
  10. 101
      boa/src/syntax/parser/statement/declaration/lexical.rs
  11. 119
      boa/src/syntax/parser/statement/declaration/tests.rs
  12. 47
      boa/src/syntax/parser/statement/mod.rs
  13. 20
      boa/src/syntax/parser/statement/try_stm/mod.rs
  14. 33
      boa/src/syntax/parser/statement/variable.rs

28
boa/src/exec/tests.rs

@ -10,9 +10,7 @@ fn empty_let_decl_undefined() {
a == undefined;
"#;
let pass = String::from("true");
assert_eq!(exec(scenario), pass);
assert_eq!(&exec(scenario), "true");
}
#[test]
@ -23,9 +21,7 @@ fn semicolon_expression_stop() {
a
"#;
let pass = String::from("1");
assert_eq!(exec(scenario), pass);
assert_eq!(&exec(scenario), "1");
}
#[test]
@ -35,9 +31,7 @@ fn empty_var_decl_undefined() {
b == undefined;
"#;
let pass = String::from("true");
assert_eq!(exec(scenario), pass);
assert_eq!(&exec(scenario), "true");
}
#[test]
@ -189,10 +183,10 @@ fn early_return() {
#[test]
fn short_circuit_evaluation() {
// OR operation
assert_eq!(exec("true || true"), String::from("true"));
assert_eq!(exec("true || false"), String::from("true"));
assert_eq!(exec("false || true"), String::from("true"));
assert_eq!(exec("false || false"), String::from("false"));
assert_eq!(&exec("true || true"), "true");
assert_eq!(&exec("true || false"), "true");
assert_eq!(&exec("false || true"), "true");
assert_eq!(&exec("false || false"), "false");
// the second operand must NOT be evaluated if the first one resolve to `true`.
let short_circuit_eval = r#"
@ -219,10 +213,10 @@ fn short_circuit_evaluation() {
assert_eq!(&exec(short_circuit_eval), "2");
// AND operation
assert_eq!(exec("true && true"), String::from("true"));
assert_eq!(exec("true && false"), String::from("false"));
assert_eq!(exec("false && true"), String::from("false"));
assert_eq!(exec("false && false"), String::from("false"));
assert_eq!(&exec("true && true"), "true");
assert_eq!(&exec("true && false"), "false");
assert_eq!(&exec("false && true"), "false");
assert_eq!(&exec("false && false"), "false");
// the second operand must be evaluated if the first one resolve to `true`.
let short_circuit_eval = r#"

43
boa/src/syntax/parser/expression/assignment/arrow_function.rs

@ -16,6 +16,7 @@ use crate::syntax::{
},
parser::{
function::{FormalParameters, FunctionBody},
statement::BindingIdentifier,
AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser,
},
};
@ -59,30 +60,30 @@ impl TokenParser for ArrowFunction {
type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let next_token = cursor.next().ok_or(ParseError::AbruptEnd)?;
let params = match &next_token.kind {
TokenKind::Punctuator(Punctuator::OpenParen) => {
let params =
FormalParameters::new(self.allow_yield, self.allow_await).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "arrow function")?;
params
}
TokenKind::Identifier(param_name) => vec![FormalParameter {
let next_token = cursor.peek(0).ok_or(ParseError::AbruptEnd)?;
let params = if let TokenKind::Punctuator(Punctuator::OpenParen) = &next_token.kind {
// CoverParenthesizedExpressionAndArrowParameterList
cursor.expect(Punctuator::OpenParen, "arrow function")?;
let params = FormalParameters::new(self.allow_yield, self.allow_await).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "arrow function")?;
params.into_boxed_slice()
} else {
let param = BindingIdentifier::new(self.allow_yield, self.allow_await)
.parse(cursor)
.map_err(|e| match e {
ParseError::Expected(mut exp, tok, _) => {
exp.push(Punctuator::OpenParen.into());
ParseError::Expected(exp, tok, "arrow function")
}
e => e,
})?;
Box::new([FormalParameter {
init: None,
name: param_name.clone(),
name: param,
is_rest_param: false,
}],
_ => {
return Err(ParseError::Expected(
vec![
TokenKind::Punctuator(Punctuator::OpenParen),
TokenKind::identifier("identifier"),
],
next_token.clone(),
"arrow function",
))
}
}])
};
cursor.peek_expect_no_lineterminator(0, "arrow function")?;
cursor.expect(Punctuator::Arrow, "arrow function")?;

4
boa/src/syntax/parser/expression/assignment/mod.rs

@ -13,7 +13,7 @@ mod exponentiation;
use self::{arrow_function::ArrowFunction, conditional::ConditionalExpression};
use crate::syntax::{
ast::{node::Node, punc::Punctuator, token::TokenKind},
ast::{keyword::Keyword, node::Node, punc::Punctuator, token::TokenKind},
parser::{AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser},
};
pub(super) use exponentiation::ExponentiationExpression;
@ -72,6 +72,8 @@ impl TokenParser for AssignmentExpression {
match next_token.kind {
// a=>{}
TokenKind::Identifier(_)
| TokenKind::Keyword(Keyword::Yield)
| TokenKind::Keyword(Keyword::Await)
if cursor
.peek_expect_no_lineterminator(1, "arrow function")
.is_ok() =>

19
boa/src/syntax/parser/expression/primary/function_expression.rs

@ -8,10 +8,11 @@
//! [spec]: https://tc39.es/ecma262/#prod-FunctionExpression
use crate::syntax::{
ast::{node::Node, punc::Punctuator, token::TokenKind},
ast::{node::Node, punc::Punctuator},
parser::{
function::{FormalParameters, FunctionBody},
Cursor, ParseError, ParseResult, TokenParser,
statement::BindingIdentifier,
Cursor, ParseResult, TokenParser,
},
};
@ -30,17 +31,7 @@ impl TokenParser for FunctionExpression {
type Output = Node;
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
let name = if let TokenKind::Identifier(name) =
&cursor.peek(0).ok_or(ParseError::AbruptEnd)?.kind
{
Some(name)
} else {
None
};
if name.is_some() {
// We move the cursor forward.
let _ = cursor.next().expect("nex token disappeared");
}
let name = BindingIdentifier::new(false, false).try_parse(cursor);
cursor.expect(Punctuator::OpenParen, "function expression")?;
@ -55,6 +46,6 @@ impl TokenParser for FunctionExpression {
cursor.expect(Punctuator::CloseBlock, "function expression")?;
Ok(Node::function_expr::<_, &String, _, _>(name, params, body))
Ok(Node::function_expr::<_, String, _, _>(name, params, body))
}
}

2
boa/src/syntax/parser/expression/primary/mod.rs

@ -81,7 +81,7 @@ impl TokenParser for PrimaryExpression {
// TODO: ADD TokenKind::UndefinedLiteral
TokenKind::Identifier(ref i) if i == "undefined" => Ok(Node::Const(Const::Undefined)),
TokenKind::NullLiteral => Ok(Node::Const(Const::Null)),
TokenKind::Identifier(ident) => Ok(Node::local(ident)),
TokenKind::Identifier(ident) => Ok(Node::local(ident)), // TODO: IdentifierReference
TokenKind::StringLiteral(s) => Ok(Node::const_node(s)),
TokenKind::NumericLiteral(NumericLiteral::Integer(num)) => Ok(Node::const_node(*num)),
TokenKind::NumericLiteral(NumericLiteral::Rational(num)) => Ok(Node::const_node(*num)),

65
boa/src/syntax/parser/function/mod.rs

@ -16,7 +16,11 @@ use crate::syntax::{
punc::Punctuator,
token::TokenKind,
},
parser::{statement::StatementList, AllowAwait, AllowYield, Cursor, ParseError, TokenParser},
parser::{
expression::Initializer,
statement::{BindingIdentifier, StatementList},
AllowAwait, AllowYield, Cursor, ParseError, TokenParser,
},
};
/// Formal parameters parsing.
@ -100,14 +104,24 @@ impl TokenParser for FormalParameters {
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
/// [spec]: https://tc39.es/ecma262/#prod-FunctionRestParameter
type FunctionRestParameter = BindingRestElement;
/// Rest parameter parsing.
///
/// More information:
/// - [MDN documentation][mdn]
/// - [ECMAScript specification][spec]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
/// [spec]: https://tc39.es/ecma262/#prod-BindingRestElement
#[derive(Debug, Clone, Copy)]
struct FunctionRestParameter {
struct BindingRestElement {
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl FunctionRestParameter {
/// Creates a new `FunctionRestParameter` parser.
impl BindingRestElement {
/// Creates a new `BindingRestElement` parser.
fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
where
Y: Into<AllowYield>,
@ -120,24 +134,17 @@ impl FunctionRestParameter {
}
}
impl TokenParser for FunctionRestParameter {
impl TokenParser for BindingRestElement {
type Output = node::FormalParameter;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let token = cursor.next().ok_or(ParseError::AbruptEnd)?;
Ok(Self::Output::new(
if let TokenKind::Identifier(name) = &token.kind {
name
} else {
return Err(ParseError::Expected(
vec![TokenKind::identifier("identifier")],
token.clone(),
"rest parameter",
));
},
None,
true,
))
// FIXME: we are reading the spread operator before the rest element.
// cursor.expect(Punctuator::Spread, "rest parameter")?;
let param = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
// TODO: BindingPattern
Ok(Self::Output::new(param, None, true))
}
}
@ -173,19 +180,13 @@ impl TokenParser for FormalParameter {
type Output = node::FormalParameter;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let token = cursor.next().ok_or(ParseError::AbruptEnd)?;
let name = if let TokenKind::Identifier(name) = &token.kind {
name
} else {
return Err(ParseError::Expected(
vec![TokenKind::identifier("identifier")],
token.clone(),
"formal parameter",
));
};
// TODO: Implement initializer.
Ok(Self::Output::new(name, None, false))
// TODO: BindingPattern
let param = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
let init = Initializer::new(true, self.allow_yield, self.allow_await).try_parse(cursor);
Ok(Self::Output::new(param, init.map(Box::new), false))
}
}

1
boa/src/syntax/parser/statement/break_stm/mod.rs

@ -61,6 +61,7 @@ impl TokenParser for BreakStatement {
}
let tok = cursor.next().ok_or(ParseError::AbruptEnd)?;
// TODO: LabelIdentifier
let node = if let TokenKind::Identifier(name) = &tok.kind {
Node::break_node(name)
} else {

1
boa/src/syntax/parser/statement/continue_stm/mod.rs

@ -61,6 +61,7 @@ impl TokenParser for ContinueStatement {
}
let tok = cursor.next().ok_or(ParseError::AbruptEnd)?;
// TODO: LabelIdentifier
let node = if let TokenKind::Identifier(name) = &tok.kind {
Node::continue_node(name)
} else {

17
boa/src/syntax/parser/statement/declaration/hoistable.rs

@ -6,10 +6,10 @@
//! [spec]: https://tc39.es/ecma262/#prod-HoistableDeclaration
use crate::syntax::{
ast::{keyword::Keyword, node::Node, punc::Punctuator, token::TokenKind},
ast::{keyword::Keyword, node::Node, punc::Punctuator},
parser::{
function::FormalParameters, function::FunctionBody, AllowAwait, AllowDefault, AllowYield,
Cursor, ParseError, ParseResult, TokenParser,
function::FormalParameters, function::FunctionBody, statement::BindingIdentifier,
AllowAwait, AllowDefault, AllowYield, Cursor, ParseResult, TokenParser,
},
};
@ -89,16 +89,7 @@ impl TokenParser for FunctionDeclaration {
fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult {
cursor.expect(Keyword::Function, "function declaration")?;
let token = cursor.next().ok_or(ParseError::AbruptEnd)?;
let name = if let TokenKind::Identifier(name) = &token.kind {
name.clone()
} else {
return Err(ParseError::Expected(
vec![TokenKind::identifier("function name")],
token.clone(),
"function declaration",
));
};
let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
cursor.expect(Punctuator::OpenParen, "function declaration")?;

101
boa/src/syntax/parser/statement/declaration/lexical.rs

@ -10,8 +10,8 @@
use crate::syntax::{
ast::{keyword::Keyword, node::Node, punc::Punctuator, token::TokenKind},
parser::{
expression::Initializer, AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult,
TokenParser,
expression::Initializer, statement::BindingIdentifier, AllowAwait, AllowIn, AllowYield,
Cursor, ParseError, ParseResult, TokenParser,
},
};
@ -69,7 +69,10 @@ impl TokenParser for LexicalDeclaration {
/// It will return an error if a `const` declaration is being parsed and there is no
/// initializer.
///
/// More information: <https://tc39.es/ecma262/#prod-BindingList>.
/// More information:
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-BindingList
#[derive(Debug, Clone, Copy)]
struct BindingList {
allow_in: AllowIn,
@ -105,44 +108,22 @@ impl TokenParser for BindingList {
let mut const_decls = Vec::new();
loop {
let token = cursor.next().ok_or(ParseError::AbruptEnd)?;
let name = if let TokenKind::Identifier(ref name) = token.kind {
name.clone()
} else {
return Err(ParseError::Expected(
vec![TokenKind::identifier("identifier")],
token.clone(),
if self.is_const {
"const declaration"
} else {
"let declaration"
},
));
};
match cursor.peek(0) {
Some(token) if token.kind == TokenKind::Punctuator(Punctuator::Assign) => {
let init = Some(
Initializer::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?,
);
if self.is_const {
const_decls.push((name, init.unwrap()));
} else {
let_decls.push((name, init));
};
}
_ => {
if self.is_const {
return Err(ParseError::Expected(
vec![TokenKind::Punctuator(Punctuator::Assign)],
cursor.next().ok_or(ParseError::AbruptEnd)?.clone(),
"const declaration",
));
} else {
let_decls.push((name, None));
}
let lexical_binding =
LexicalBinding::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?;
if self.is_const {
if let (ident, Some(init)) = lexical_binding {
const_decls.push((ident, init));
} else {
return Err(ParseError::Expected(
vec![TokenKind::Punctuator(Punctuator::Assign)],
cursor.next().ok_or(ParseError::AbruptEnd)?.clone(),
"const declaration",
));
}
} else {
let_decls.push(lexical_binding);
}
match cursor.peek_semicolon(false) {
@ -170,3 +151,43 @@ impl TokenParser for BindingList {
}
}
}
/// Lexical binding parsing.
///
/// More information:
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-LexicalBinding
struct LexicalBinding {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl LexicalBinding {
/// Creates a new `BindingList` parser.
fn new<I, Y, A>(allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
impl TokenParser for LexicalBinding {
type Output = (String, Option<Node>);
fn parse(self, cursor: &mut Cursor<'_>) -> Result<(String, Option<Node>), ParseError> {
let ident = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
let initializer =
Initializer::new(self.allow_in, self.allow_yield, self.allow_await).try_parse(cursor);
Ok((ident, initializer))
}
}

119
boa/src/syntax/parser/statement/declaration/tests.rs

@ -5,7 +5,7 @@ use crate::syntax::{
/// Checks `var` declaration parsing.
#[test]
fn check_var_declaration() {
fn var_declaration() {
check_parser(
"var a = 5;",
vec![Node::var_decl(vec![(
@ -15,9 +15,29 @@ fn check_var_declaration() {
);
}
/// Checks `var` declaration parsing with reserved words.
#[test]
fn var_declaration_keywords() {
check_parser(
"var yield = 5;",
vec![Node::var_decl(vec![(
String::from("yield"),
Some(Node::const_node(5)),
)])],
);
check_parser(
"var await = 5;",
vec![Node::var_decl(vec![(
String::from("await"),
Some(Node::const_node(5)),
)])],
);
}
/// Checks `var` declaration parsing with no spaces.
#[test]
fn check_var_declaration_no_spaces() {
fn var_declaration_no_spaces() {
check_parser(
"var a=5;",
vec![Node::var_decl(vec![(
@ -29,7 +49,7 @@ fn check_var_declaration_no_spaces() {
/// Checks empty `var` declaration parsing.
#[test]
fn check_empty_var_declaration() {
fn empty_var_declaration() {
check_parser(
"var a;",
vec![Node::var_decl(vec![(String::from("a"), None)])],
@ -38,7 +58,7 @@ fn check_empty_var_declaration() {
/// Checks multiple `var` declarations.
#[test]
fn check_multiple_var_declaration() {
fn multiple_var_declaration() {
check_parser(
"var a = 5, b, c = 6;",
vec![Node::var_decl(vec![
@ -51,7 +71,7 @@ fn check_multiple_var_declaration() {
/// Checks `let` declaration parsing.
#[test]
fn check_let_declaration() {
fn let_declaration() {
check_parser(
"let a = 5;",
vec![Node::let_decl(vec![(
@ -61,9 +81,29 @@ fn check_let_declaration() {
);
}
/// Checks `let` declaration parsing with reserved words.
#[test]
fn let_declaration_keywords() {
check_parser(
"let yield = 5;",
vec![Node::let_decl(vec![(
String::from("yield"),
Some(Node::const_node(5)),
)])],
);
check_parser(
"let await = 5;",
vec![Node::let_decl(vec![(
String::from("await"),
Some(Node::const_node(5)),
)])],
);
}
/// Checks `let` declaration parsing with no spaces.
#[test]
fn check_let_declaration_no_spaces() {
fn let_declaration_no_spaces() {
check_parser(
"let a=5;",
vec![Node::let_decl(vec![(
@ -75,7 +115,7 @@ fn check_let_declaration_no_spaces() {
/// Checks empty `let` declaration parsing.
#[test]
fn check_empty_let_declaration() {
fn empty_let_declaration() {
check_parser(
"let a;",
vec![Node::let_decl(vec![(String::from("a"), None)])],
@ -84,7 +124,7 @@ fn check_empty_let_declaration() {
/// Checks multiple `let` declarations.
#[test]
fn check_multiple_let_declaration() {
fn multiple_let_declaration() {
check_parser(
"let a = 5, b, c = 6;",
vec![Node::let_decl(vec![
@ -97,7 +137,7 @@ fn check_multiple_let_declaration() {
/// Checks `const` declaration parsing.
#[test]
fn check_const_declaration() {
fn const_declaration() {
check_parser(
"const a = 5;",
vec![Node::const_decl(vec![(
@ -107,9 +147,29 @@ fn check_const_declaration() {
);
}
/// Checks `const` declaration parsing with reserved words.
#[test]
fn const_declaration_keywords() {
check_parser(
"const yield = 5;",
vec![Node::const_decl(vec![(
String::from("yield"),
Node::const_node(5),
)])],
);
check_parser(
"const await = 5;",
vec![Node::const_decl(vec![(
String::from("await"),
Node::const_node(5),
)])],
);
}
/// Checks `const` declaration parsing with no spaces.
#[test]
fn check_const_declaration_no_spaces() {
fn const_declaration_no_spaces() {
check_parser(
"const a=5;",
vec![Node::const_decl(vec![(
@ -121,13 +181,13 @@ fn check_const_declaration_no_spaces() {
/// Checks empty `const` declaration parsing.
#[test]
fn check_empty_const_declaration() {
fn empty_const_declaration() {
check_invalid("const a;");
}
/// Checks multiple `const` declarations.
#[test]
fn check_multiple_const_declaration() {
fn multiple_const_declaration() {
check_parser(
"const a = 5, c = 6;",
vec![Node::const_decl(vec![
@ -136,3 +196,38 @@ fn check_multiple_const_declaration() {
])],
);
}
/// Function declaration parsing.
#[test]
fn function_declaration() {
check_parser(
"function hello() {}",
vec![Node::function_decl(
"hello",
vec![],
Node::statement_list(vec![]),
)],
);
}
/// Function declaration parsing with keywords.
#[test]
fn function_declaration_keywords() {
check_parser(
"function yield() {}",
vec![Node::function_decl(
"yield",
vec![],
Node::statement_list(vec![]),
)],
);
check_parser(
"function await() {}",
vec![Node::function_decl(
"await",
vec![],
Node::statement_list(vec![]),
)],
);
}

47
boa/src/syntax/parser/statement/mod.rs

@ -316,3 +316,50 @@ impl TokenParser for ExpressionStatement {
Ok(expr)
}
}
/// Binding identifier parsing.
///
/// More information:
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-BindingIdentifier
#[derive(Debug, Clone, Copy)]
pub(super) struct BindingIdentifier {
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BindingIdentifier {
/// Creates a new `BindingIdentifier` parser.
pub(super) fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
impl TokenParser for BindingIdentifier {
type Output = String;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<String, ParseError> {
// TODO: strict mode.
let next_token = cursor.next().ok_or(ParseError::AbruptEnd)?;
match next_token.kind {
TokenKind::Identifier(ref s) => Ok(s.clone()),
TokenKind::Keyword(k @ Keyword::Yield) if !self.allow_yield.0 => Ok(k.to_string()),
TokenKind::Keyword(k @ Keyword::Await) if !self.allow_await.0 => Ok(k.to_string()),
_ => Err(ParseError::Expected(
vec![TokenKind::identifier("identifier")],
next_token.clone(),
"binding identifier",
)),
}
}
}

20
boa/src/syntax/parser/statement/try_stm/mod.rs

@ -4,7 +4,10 @@ mod tests;
use super::block::Block;
use crate::syntax::{
ast::{keyword::Keyword, node::Node, punc::Punctuator, token::TokenKind},
parser::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, ParseResult, TokenParser},
parser::{
statement::BindingIdentifier, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError,
ParseResult, TokenParser,
},
};
/// Try...catch statement parsing
@ -67,17 +70,10 @@ impl TokenParser for TryStatement {
let (catch, param) = if next_token.kind == TokenKind::Keyword(Keyword::Catch) {
// Catch binding
cursor.expect(Punctuator::OpenParen, "catch in try statement")?;
// TODO: should accept BindingPattern
let tok = cursor.next().ok_or(ParseError::AbruptEnd)?;
let catch_param = if let TokenKind::Identifier(s) = &tok.kind {
Node::local(s)
} else {
return Err(ParseError::Expected(
vec![TokenKind::identifier("identifier")],
tok.clone(),
"catch in try statement",
));
};
// TODO: CatchParameter - BindingPattern
let catch_param = BindingIdentifier::new(self.allow_yield, self.allow_await)
.parse(cursor)
.map(Node::local)?;
cursor.expect(Punctuator::CloseParen, "catch in try statement")?;
// Catch block

33
boa/src/syntax/parser/statement/variable.rs

@ -2,8 +2,8 @@
use crate::syntax::{
ast::{keyword::Keyword, node::Node, punc::Punctuator, token::TokenKind},
parser::{
expression::Initializer, AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult,
TokenParser,
expression::Initializer, statement::BindingIdentifier, AllowAwait, AllowIn, AllowYield,
Cursor, ParseError, ParseResult, TokenParser,
},
};
@ -154,26 +154,13 @@ impl TokenParser for VariableDeclaration {
type Output = (String, Option<Node>);
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let tok = cursor.next().ok_or(ParseError::AbruptEnd)?;
let name = if let TokenKind::Identifier(name) = &tok.kind {
name.clone()
} else {
return Err(ParseError::Expected(
vec![TokenKind::identifier("identifier")],
tok.clone(),
"variable declaration",
));
};
match cursor.peek(0) {
Some(tk) if tk.kind == TokenKind::Punctuator(Punctuator::Assign) => Ok((
name,
Some(
Initializer::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?,
),
)),
_ => Ok((name, None)),
}
// TODO: BindingPattern
let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
let ident =
Initializer::new(self.allow_in, self.allow_yield, self.allow_await).try_parse(cursor);
Ok((name, ident))
}
}

Loading…
Cancel
Save