mirror of https://github.com/boa-dev/boa.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
6.6 KiB
294 lines
6.6 KiB
//! Tests for the parser. |
|
|
|
use super::Parser; |
|
use crate::syntax::ast::{ |
|
node::{ |
|
field::GetConstField, ArrowFunctionDecl, Assign, BinOp, Call, FormalParameter, |
|
FunctionDecl, Identifier, LetDecl, LetDeclList, New, Node, Return, StatementList, UnaryOp, |
|
VarDecl, VarDeclList, |
|
}, |
|
op::{self, CompOp, LogOp, NumOp}, |
|
Const, |
|
}; |
|
|
|
/// Checks that the given JavaScript string gives the expected expression. |
|
#[allow(clippy::unwrap_used)] |
|
#[track_caller] |
|
pub(super) fn check_parser<L>(js: &str, expr: L) |
|
where |
|
L: Into<Box<[Node]>>, |
|
{ |
|
assert_eq!( |
|
Parser::new(js.as_bytes()) |
|
.parse_all() |
|
.expect("failed to parse"), |
|
StatementList::from(expr) |
|
); |
|
} |
|
|
|
/// Checks that the given javascript string creates a parse error. |
|
#[track_caller] |
|
pub(super) fn check_invalid(js: &str) { |
|
assert!(Parser::new(js.as_bytes()).parse_all().is_err()); |
|
} |
|
|
|
/// Should be parsed as `new Class().method()` instead of `new (Class().method())` |
|
#[test] |
|
fn check_construct_call_precedence() { |
|
check_parser( |
|
"new Date().getTime()", |
|
vec![Node::from(Call::new( |
|
GetConstField::new( |
|
New::from(Call::new(Identifier::from("Date"), vec![])), |
|
"getTime", |
|
), |
|
vec![], |
|
))], |
|
); |
|
} |
|
|
|
#[test] |
|
fn assign_operator_precedence() { |
|
check_parser( |
|
"a = a + 1", |
|
vec![Assign::new( |
|
Identifier::from("a"), |
|
BinOp::new(NumOp::Add, Identifier::from("a"), Const::from(1)), |
|
) |
|
.into()], |
|
); |
|
} |
|
|
|
#[test] |
|
fn hoisting() { |
|
check_parser( |
|
r" |
|
var a = hello(); |
|
a++; |
|
|
|
function hello() { return 10 }", |
|
vec![ |
|
FunctionDecl::new( |
|
Box::from("hello"), |
|
vec![], |
|
vec![Return::new(Const::from(10), None).into()], |
|
) |
|
.into(), |
|
VarDeclList::from(vec![VarDecl::new( |
|
"a", |
|
Node::from(Call::new(Identifier::from("hello"), vec![])), |
|
)]) |
|
.into(), |
|
UnaryOp::new(op::UnaryOp::IncrementPost, Identifier::from("a")).into(), |
|
], |
|
); |
|
|
|
check_parser( |
|
r" |
|
a = 10; |
|
a++; |
|
|
|
var a;", |
|
vec![ |
|
Assign::new(Identifier::from("a"), Const::from(10)).into(), |
|
UnaryOp::new(op::UnaryOp::IncrementPost, Identifier::from("a")).into(), |
|
VarDeclList::from(vec![VarDecl::new("a", None)]).into(), |
|
], |
|
); |
|
} |
|
|
|
#[test] |
|
fn ambigous_regex_divide_expression() { |
|
let s = "1 / a === 1 / b"; |
|
|
|
check_parser( |
|
s, |
|
vec![BinOp::new( |
|
CompOp::StrictEqual, |
|
BinOp::new(NumOp::Div, Const::Int(1), Identifier::from("a")), |
|
BinOp::new(NumOp::Div, Const::Int(1), Identifier::from("b")), |
|
) |
|
.into()], |
|
); |
|
} |
|
|
|
#[test] |
|
fn two_divisions_in_expression() { |
|
let s = "a !== 0 || 1 / a === 1 / b;"; |
|
|
|
check_parser( |
|
s, |
|
vec![BinOp::new( |
|
LogOp::Or, |
|
BinOp::new(CompOp::StrictNotEqual, Identifier::from("a"), Const::Int(0)), |
|
BinOp::new( |
|
CompOp::StrictEqual, |
|
BinOp::new(NumOp::Div, Const::Int(1), Identifier::from("a")), |
|
BinOp::new(NumOp::Div, Const::Int(1), Identifier::from("b")), |
|
), |
|
) |
|
.into()], |
|
); |
|
} |
|
|
|
#[test] |
|
fn comment_semi_colon_insertion() { |
|
let s = r#" |
|
let a = 10 // Comment |
|
let b = 20; |
|
"#; |
|
|
|
check_parser( |
|
s, |
|
vec![ |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"a", |
|
Some(Const::Int(10).into()), |
|
)]) |
|
.into(), |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"b", |
|
Some(Const::Int(20).into()), |
|
)]) |
|
.into(), |
|
], |
|
); |
|
} |
|
|
|
#[test] |
|
fn multiline_comment_semi_colon_insertion() { |
|
let s = r#" |
|
let a = 10 /* Test |
|
Multiline |
|
Comment |
|
*/ let b = 20; |
|
"#; |
|
|
|
check_parser( |
|
s, |
|
vec![ |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"a", |
|
Some(Const::Int(10).into()), |
|
)]) |
|
.into(), |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"b", |
|
Some(Const::Int(20).into()), |
|
)]) |
|
.into(), |
|
], |
|
); |
|
} |
|
|
|
#[test] |
|
fn multiline_comment_no_lineterminator() { |
|
let s = r#" |
|
let a = 10; /* Test comment */ let b = 20; |
|
"#; |
|
|
|
check_parser( |
|
s, |
|
vec![ |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"a", |
|
Some(Const::Int(10).into()), |
|
)]) |
|
.into(), |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"b", |
|
Some(Const::Int(20).into()), |
|
)]) |
|
.into(), |
|
], |
|
); |
|
} |
|
|
|
#[test] |
|
fn assignment_line_terminator() { |
|
let s = r#" |
|
let a = 3; |
|
|
|
a = |
|
5; |
|
"#; |
|
|
|
check_parser( |
|
s, |
|
vec![ |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"a", |
|
Some(Const::Int(3).into()), |
|
)]) |
|
.into(), |
|
Assign::new(Identifier::from("a"), Const::from(5)).into(), |
|
], |
|
); |
|
} |
|
|
|
#[test] |
|
fn assignment_multiline_terminator() { |
|
let s = r#" |
|
let a = 3; |
|
|
|
|
|
a = |
|
|
|
|
|
5; |
|
"#; |
|
|
|
check_parser( |
|
s, |
|
vec![ |
|
LetDeclList::from(vec![LetDecl::new::<&str, Option<Node>>( |
|
"a", |
|
Some(Const::Int(3).into()), |
|
)]) |
|
.into(), |
|
Assign::new(Identifier::from("a"), Const::from(5)).into(), |
|
], |
|
); |
|
} |
|
|
|
#[test] |
|
fn bracketed_expr() { |
|
let s = r#"(b)"#; |
|
|
|
check_parser(s, vec![Identifier::from("b").into()]); |
|
} |
|
|
|
#[test] |
|
fn increment_in_comma_op() { |
|
let s = r#"(b++, b)"#; |
|
|
|
check_parser( |
|
s, |
|
vec![BinOp::new::<_, Node, Node>( |
|
op::BinOp::Comma, |
|
UnaryOp::new::<Node>(op::UnaryOp::IncrementPost, Identifier::from("b").into()).into(), |
|
Identifier::from("b").into(), |
|
) |
|
.into()], |
|
); |
|
} |
|
|
|
#[test] |
|
fn spread_in_arrow_function() { |
|
let s = r#" |
|
(...b) => { |
|
b |
|
} |
|
"#; |
|
|
|
check_parser( |
|
s, |
|
vec![ |
|
ArrowFunctionDecl::new::<Box<[FormalParameter]>, StatementList>( |
|
Box::new([FormalParameter::new("b", None, true)]), |
|
vec![Identifier::from("b").into()].into(), |
|
) |
|
.into(), |
|
], |
|
); |
|
}
|
|
|