mod assignment;
mod left_hand_side;
mod primary;
#[cfg(test)]
mod tests;
mod unary;
mod update;
pub(in crate::syntax::parser) mod await_expr;
use self::assignment::ExponentiationExpression;
pub(super) use self::{assignment::AssignmentExpression, primary::Initializer};
use super::{AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser};
use crate::{
profiler::BoaProfiler,
syntax::{
ast::op::LogOp,
ast::{
node::{BinOp, Node},
Keyword, Punctuator,
},
lexer::{InputElement, TokenKind},
parser::ParseError,
},
};
use std::io::Read;
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(self, cursor: &mut Cursor<R>)-> ParseResult {
let _timer = BoaProfiler::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)?;
while let Some(tok) = cursor.peek(0)? {
match *tok.kind() {
TokenKind::Punctuator(op) if $( op == $op )||* => {
let _ = cursor.next().expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
$lower::new($( self.$low_param ),*).parse(cursor)?
).into();
}
TokenKind::Keyword(op) if $( op == $op )||* => {
let _ = cursor.next().expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
$lower::new($( self.$low_param ),*).parse(cursor)?
).into();
}
_ => break
}
}
Ok(lhs)
}
}
} }
#[derive(Debug, Clone, Copy)]
pub(super) struct Expression {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl Expression {
pub(super) 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(),
}
}
}
expression!(
Expression,
AssignmentExpression,
[Punctuator::Comma],
[allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct ShortCircuitExpression {
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<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(),
previous: PreviousExpr::None,
}
}
fn with_previous<I, Y, A>(
allow_in: I,
allow_yield: Y,
allow_await: A,
previous: PreviousExpr,
) -> 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(),
previous,
}
}
}
impl<R> TokenParser<R> for ShortCircuitExpression
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("ShortCircuitExpression", "Parsing");
let mut current_node =
BitwiseORExpression::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?;
let mut previous = self.previous;
while let Some(tok) = cursor.peek(0)? {
match tok.kind() {
TokenKind::Punctuator(Punctuator::BoolAnd) => {
if previous == PreviousExpr::Coalesce {
return Err(ParseError::expected(
[TokenKind::Punctuator(Punctuator::Coalesce)],
tok.clone(),
"logical expression (cannot use '??' without parentheses within '||' or '&&')",
));
}
let _ = cursor.next()?.expect("'&&' expected");
previous = PreviousExpr::Logical;
let rhs =
BitwiseORExpression::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?;
current_node = BinOp::new(LogOp::And, current_node, rhs).into();
}
TokenKind::Punctuator(Punctuator::BoolOr) => {
if previous == PreviousExpr::Coalesce {
return Err(ParseError::expected(
[TokenKind::Punctuator(Punctuator::Coalesce)],
tok.clone(),
"logical expression (cannot use '??' without parentheses within '||' or '&&')",
));
}
let _ = cursor.next()?.expect("'||' expected");
previous = PreviousExpr::Logical;
let rhs = ShortCircuitExpression::with_previous(
self.allow_in,
self.allow_yield,
self.allow_await,
PreviousExpr::Logical,
)
.parse(cursor)?;
current_node = BinOp::new(LogOp::Or, current_node, rhs).into();
}
TokenKind::Punctuator(Punctuator::Coalesce) => {
if previous == PreviousExpr::Logical {
return Err(ParseError::expected(
[
TokenKind::Punctuator(Punctuator::BoolAnd),
TokenKind::Punctuator(Punctuator::BoolOr),
],
tok.clone(),
"cannot use '??' unparenthesized within '||' or '&&'",
));
}
let _ = cursor.next()?.expect("'??' expected");
previous = PreviousExpr::Coalesce;
let rhs =
BitwiseORExpression::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?;
current_node = BinOp::new(LogOp::Coalesce, current_node, rhs).into();
}
_ => break,
}
}
Ok(current_node)
}
}
#[derive(Debug, Clone, Copy)]
struct BitwiseORExpression {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BitwiseORExpression {
pub(super) 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(),
}
}
}
expression!(
BitwiseORExpression,
BitwiseXORExpression,
[Punctuator::Or],
[allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct BitwiseXORExpression {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BitwiseXORExpression {
pub(super) 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(),
}
}
}
expression!(
BitwiseXORExpression,
BitwiseANDExpression,
[Punctuator::Xor],
[allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct BitwiseANDExpression {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BitwiseANDExpression {
pub(super) 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(),
}
}
}
expression!(
BitwiseANDExpression,
EqualityExpression,
[Punctuator::And],
[allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct EqualityExpression {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl EqualityExpression {
pub(super) 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(),
}
}
}
expression!(
EqualityExpression,
RelationalExpression,
[
Punctuator::Eq,
Punctuator::NotEq,
Punctuator::StrictEq,
Punctuator::StrictNotEq
],
[allow_in, allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct RelationalExpression {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl RelationalExpression {
pub(super) 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<R> TokenParser<R> for RelationalExpression
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>) -> ParseResult {
let _timer = BoaProfiler::global().start_event("Relation Expression", "Parsing");
if None::<InputElement>.is_some() {
cursor.set_goal(None::<InputElement>.unwrap());
}
let mut lhs = ShiftExpression::new(self.allow_yield, self.allow_await).parse(cursor)?;
while let Some(tok) = cursor.peek(0)? {
match *tok.kind() {
TokenKind::Punctuator(op)
if op == Punctuator::LessThan
|| op == Punctuator::GreaterThan
|| op == Punctuator::LessThanOrEq
|| op == Punctuator::GreaterThanOrEq =>
{
let _ = cursor.next().expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
ShiftExpression::new(self.allow_yield, self.allow_await).parse(cursor)?,
)
.into();
}
TokenKind::Keyword(op)
if op == Keyword::InstanceOf
|| (op == Keyword::In && self.allow_in == AllowIn(true)) =>
{
let _ = cursor.next().expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
lhs,
ShiftExpression::new(self.allow_yield, self.allow_await).parse(cursor)?,
)
.into();
}
_ => break,
}
}
Ok(lhs)
}
}
#[derive(Debug, Clone, Copy)]
struct ShiftExpression {
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl ShiftExpression {
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(),
}
}
}
expression!(
ShiftExpression,
AdditiveExpression,
[
Punctuator::LeftSh,
Punctuator::RightSh,
Punctuator::URightSh
],
[allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct AdditiveExpression {
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl AdditiveExpression {
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(),
}
}
}
expression!(
AdditiveExpression,
MultiplicativeExpression,
[Punctuator::Add, Punctuator::Sub],
[allow_yield, allow_await],
None::<InputElement>
);
#[derive(Debug, Clone, Copy)]
struct MultiplicativeExpression {
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl MultiplicativeExpression {
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(),
}
}
}
expression!(
MultiplicativeExpression,
ExponentiationExpression,
[Punctuator::Mul, Punctuator::Div, Punctuator::Mod],
[allow_yield, allow_await],
Some(InputElement::Div)
);