mod assignment;
mod identifiers;
mod left_hand_side;
mod primary;
mod unary;
mod update;
pub(in crate::syntax::parser) mod await_expr;
#[cfg(test)]
mod tests;
use crate::syntax::{
ast::op::LogOp,
ast::{
node::{BinOp, Node},
Keyword, Punctuator,
},
lexer::{InputElement, TokenKind},
parser::{
expression::assignment::ExponentiationExpression, AllowAwait, AllowIn, AllowYield, Cursor,
ParseError, ParseResult, TokenParser,
},
};
use boa_interner::{Interner, Sym};
use boa_profiler::Profiler;
use std::io::Read;
pub(super) use self::{assignment::AssignmentExpression, primary::Initializer};
pub(in crate::syntax) use identifiers::RESERVED_IDENTIFIERS_STRICT;
pub(in crate::syntax::parser) use {
identifiers::{BindingIdentifier, LabelIdentifier},
left_hand_side::LeftHandSideExpression,
primary::object_initializer::{
AsyncGeneratorMethod, AsyncMethod, GeneratorMethod, PropertyName,
},
};
impl PartialEq<Keyword> for Punctuator {
fn eq(&self, _other: &Keyword) -> bool {
false
}
}
impl PartialEq<Punctuator> for Keyword {
fn eq(&self, _other: &Punctuator) -> bool {
false
}
}
macro_rules! expression { ($name:ident, $lower:ident, [$( $op:path ),*], [$( $low_param:ident ),*], $goal:expr ) => {
impl<R> TokenParser<R> for $name
where
R: Read
{
type Output = Node;
fn parse(mut self, cursor: &mut Cursor<R>, interner: &mut Interner)-> ParseResult {
let _timer = Profiler::global().start_event(stringify!($name), "Parsing");
if $goal.is_some() {
cursor.set_goal($goal.unwrap());
}
let mut lhs = $lower::new($( self.$low_param ),*).parse(cursor, interner)?;
self.name = None;
while let Some(tok) = cursor.peek(0, interner)? {
match *tok.kind() {
TokenKind::Punctuator(op) if $( op == $op )||* => {
let _next = cursor.next(interner).expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
$lower::new($( self.$low_param ),*).parse(cursor, interner)?
).into();
}
TokenKind::Keyword((op, false)) if $( op == $op )||* => {
let _next = cursor.next(interner).expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
$lower::new($( self.$low_param ),*).parse(cursor, interner)?
).into();
}
_ => break
}
}
Ok(lhs)
}
}
} }
#[derive(Debug, Clone, Copy)]
pub(super) struct Expression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl Expression {
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
impl<R> TokenParser<R> for Expression
where
R: Read,
{
type Output = Node;
fn parse(mut self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult {
let _timer = Profiler::global().start_event("Expression", "Parsing");
let mut lhs =
AssignmentExpression::new(self.name, self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
self.name = None;
while let Some(tok) = cursor.peek(0, interner)? {
match *tok.kind() {
TokenKind::Punctuator(Punctuator::Comma) => {
if cursor
.peek(1, interner)?
.ok_or(ParseError::AbruptEnd)?
.kind()
== &TokenKind::Punctuator(Punctuator::CloseParen)
{
return Ok(lhs);
}
if cursor
.peek(1, interner)?
.ok_or(ParseError::AbruptEnd)?
.kind()
== &TokenKind::Punctuator(Punctuator::Spread)
{
return Ok(lhs);
}
let _next = cursor.next(interner).expect("token disappeared");
lhs = BinOp::new(
Punctuator::Comma
.as_binop()
.expect("Could not get binary operation."),
lhs,
AssignmentExpression::new(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
)
.parse(cursor, interner)?,
)
.into();
}
_ => break,
}
}
Ok(lhs)
}
}
#[derive(Debug, Clone, Copy)]
struct ShortCircuitExpression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
previous: PreviousExpr,
}
#[derive(Debug, Clone, Copy, PartialEq)]
enum PreviousExpr {
None,
Logical,
Coalesce,
}
impl ShortCircuitExpression {
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
previous: PreviousExpr::None,
}
}
fn with_previous<N, I, Y, A>(
name: N,
allow_in: I,
allow_yield: Y,
allow_await: A,
previous: PreviousExpr,
) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
previous,
}
}
}
impl<R> TokenParser<R> for ShortCircuitExpression
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult {
let _timer = Profiler::global().start_event("ShortCircuitExpression", "Parsing");
let mut current_node =
BitwiseORExpression::new(self.name, self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
let mut previous = self.previous;
while let Some(tok) = cursor.peek(0, interner)? {
match tok.kind() {
TokenKind::Punctuator(Punctuator::BoolAnd) => {
if previous == PreviousExpr::Coalesce {
return Err(ParseError::expected(
["??".to_owned()],
tok.to_string(interner), tok.span(),
"logical expression (cannot use '??' without parentheses within '||' or '&&')",
));
}
let _next = cursor.next(interner)?.expect("'&&' expected");
previous = PreviousExpr::Logical;
let rhs = BitwiseORExpression::new(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
)
.parse(cursor, interner)?;
current_node = BinOp::new(LogOp::And, current_node, rhs).into();
}
TokenKind::Punctuator(Punctuator::BoolOr) => {
if previous == PreviousExpr::Coalesce {
return Err(ParseError::expected(
["??".to_owned()],
tok.to_string(interner), tok.span(),
"logical expression (cannot use '??' without parentheses within '||' or '&&')",
));
}
let _next = cursor.next(interner)?.expect("'||' expected");
previous = PreviousExpr::Logical;
let rhs = Self::with_previous(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
PreviousExpr::Logical,
)
.parse(cursor, interner)?;
current_node = BinOp::new(LogOp::Or, current_node, rhs).into();
}
TokenKind::Punctuator(Punctuator::Coalesce) => {
if previous == PreviousExpr::Logical {
return Err(ParseError::expected(
["&&".to_owned(), "||".to_owned()],
tok.to_string(interner),
tok.span(),
"cannot use '??' unparenthesized within '||' or '&&'",
));
}
let _next = cursor.next(interner)?.expect("'??' expected");
previous = PreviousExpr::Coalesce;
let rhs = BitwiseORExpression::new(
self.name,
self.allow_in,
self.allow_yield,
self.allow_await,
)
.parse(cursor, interner)?;
current_node = BinOp::new(LogOp::Coalesce, current_node, rhs).into();
}
_ => break,
}
}
Ok(current_node)
}
}
#[derive(Debug, Clone, Copy)]
struct BitwiseORExpression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BitwiseORExpression {
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
expression!(
BitwiseORExpression,
BitwiseXORExpression,
[Punctuator::Or],
[name, allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct BitwiseXORExpression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BitwiseXORExpression {
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
expression!(
BitwiseXORExpression,
BitwiseANDExpression,
[Punctuator::Xor],
[name, allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct BitwiseANDExpression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BitwiseANDExpression {
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
expression!(
BitwiseANDExpression,
EqualityExpression,
[Punctuator::And],
[name, allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct EqualityExpression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl EqualityExpression {
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
expression!(
EqualityExpression,
RelationalExpression,
[
Punctuator::Eq,
Punctuator::NotEq,
Punctuator::StrictEq,
Punctuator::StrictNotEq
],
[name, allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct RelationalExpression {
name: Option<Sym>,
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl RelationalExpression {
pub(super) fn new<N, I, Y, A>(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
impl<R> TokenParser<R> for RelationalExpression
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult {
let _timer = Profiler::global().start_event("Relation Expression", "Parsing");
let mut lhs = ShiftExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
while let Some(tok) = cursor.peek(0, interner)? {
match *tok.kind() {
TokenKind::Punctuator(op)
if op == Punctuator::LessThan
|| op == Punctuator::GreaterThan
|| op == Punctuator::LessThanOrEq
|| op == Punctuator::GreaterThanOrEq =>
{
let _next = cursor.next(interner).expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
ShiftExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?,
)
.into();
}
TokenKind::Keyword((Keyword::InstanceOf | Keyword::In, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
tok.span().start(),
));
}
TokenKind::Keyword((op, false))
if op == Keyword::InstanceOf
|| (op == Keyword::In && self.allow_in == AllowIn(true)) =>
{
let _next = cursor.next(interner).expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
ShiftExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?,
)
.into();
}
_ => break,
}
}
Ok(lhs)
}
}
#[derive(Debug, Clone, Copy)]
struct ShiftExpression {
name: Option<Sym>,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl ShiftExpression {
pub(super) fn new<N, Y, A>(name: N, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
expression!(
ShiftExpression,
AdditiveExpression,
[
Punctuator::LeftSh,
Punctuator::RightSh,
Punctuator::URightSh
],
[name, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct AdditiveExpression {
name: Option<Sym>,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl AdditiveExpression {
pub(super) fn new<N, Y, A>(name: N, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
expression!(
AdditiveExpression,
MultiplicativeExpression,
[Punctuator::Add, Punctuator::Sub],
[name, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct MultiplicativeExpression {
name: Option<Sym>,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl MultiplicativeExpression {
pub(super) fn new<N, Y, A>(name: N, allow_yield: Y, allow_await: A) -> Self
where
N: Into<Option<Sym>>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
name: name.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
expression!(
MultiplicativeExpression,
ExponentiationExpression,
[Punctuator::Mul, Punctuator::Div, Punctuator::Mod],
[name, allow_yield, allow_await],
Some(InputElement::Div)
);