use crate::parser::tests::{check_invalid_script, check_script_parser};
use boa_ast::{
Expression, Span, Statement, StatementListItem,
declaration::{VarDeclaration, Variable},
expression::{
Call, Identifier,
access::SimplePropertyAccess,
literal::Literal,
operator::{
Assign, Binary, Update,
assign::AssignOp,
binary::RelationalOp,
update::{UpdateOp, UpdateTarget},
},
},
statement::{Block, Break, DoWhileLoop, WhileLoop},
};
use boa_interner::Interner;
use boa_macros::utf16;
use indoc::indoc;
const PSEUDO_LINEAR_POS: boa_ast::LinearPosition = boa_ast::LinearPosition::new(0);
#[test]
fn check_do_while() {
let interner = &mut Interner::default();
check_script_parser(
indoc! {"
do {
a += 1;
} while (true)
"},
vec![
Statement::DoWhileLoop(DoWhileLoop::new(
Statement::Block(
(
vec![StatementListItem::Statement(
Statement::Expression(Expression::from(Assign::new(
AssignOp::Add,
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
Span::new((2, 5), (2, 6)),
)
.into(),
Literal::new(1, Span::new((2, 10), (2, 11))).into(),
)))
.into(),
)],
PSEUDO_LINEAR_POS,
)
.into(),
),
Literal::new(true, Span::new((3, 10), (3, 14))).into(),
))
.into(),
],
interner,
);
}
#[test]
fn check_do_while_semicolon_insertion() {
let interner = &mut Interner::default();
check_script_parser(
indoc! {r#"
var i = 0;
do {console.log("hello");} while(i++ < 10) console.log("end");
"#},
vec![
Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
Identifier::new(
interner.get_or_intern_static("i", utf16!("i")),
Span::new((1, 5), (1, 6)),
),
Some(Literal::new(0, Span::new((1, 9), (1, 10))).into()),
)]
.try_into()
.unwrap(),
))
.into(),
Statement::DoWhileLoop(DoWhileLoop::new(
Statement::Block(
(
vec![StatementListItem::Statement(
Statement::Expression(
Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static(
"console",
utf16!("console"),
),
Span::new((2, 5), (2, 12)),
)
.into(),
Identifier::new(
interner.get_or_intern_static("log", utf16!("log")),
Span::new((2, 13), (2, 16)),
),
)
.into(),
),
vec![
Literal::new(
interner.get_or_intern_static("hello", utf16!("hello")),
Span::new((2, 17), (2, 24)),
)
.into(),
]
.into(),
Span::new((2, 16), (2, 25)),
)
.into(),
)
.into(),
)],
PSEUDO_LINEAR_POS,
)
.into(),
),
Binary::new(
RelationalOp::LessThan.into(),
Update::new(
UpdateOp::IncrementPost,
UpdateTarget::Identifier(Identifier::new(
interner.get_or_intern_static("i", utf16!("i")),
Span::new((2, 34), (2, 35)),
)),
Span::new((2, 34), (2, 37)),
)
.into(),
Literal::new(10, Span::new((2, 40), (2, 42))).into(),
)
.into(),
))
.into(),
Statement::Expression(
Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static("console", utf16!("console")),
Span::new((2, 44), (2, 51)),
)
.into(),
Identifier::new(
interner.get_or_intern_static("log", utf16!("log")),
Span::new((2, 52), (2, 55)),
),
)
.into(),
),
vec![
Literal::new(
interner.get_or_intern_static("end", utf16!("end")),
Span::new((2, 56), (2, 61)),
)
.into(),
]
.into(),
Span::new((2, 55), (2, 62)),
)
.into(),
)
.into(),
],
interner,
);
}
#[test]
fn check_do_while_semicolon_insertion_no_space() {
let interner = &mut Interner::default();
check_script_parser(
indoc! {r#"
var i = 0;
do {console.log("hello");} while(i++ < 10)console.log("end");
"#},
vec![
Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
Identifier::new(
interner.get_or_intern_static("i", utf16!("i")),
Span::new((1, 5), (1, 6)),
),
Some(Literal::new(0, Span::new((1, 9), (1, 10))).into()),
)]
.try_into()
.unwrap(),
))
.into(),
Statement::DoWhileLoop(DoWhileLoop::new(
Statement::Block(
(
vec![StatementListItem::Statement(
Statement::Expression(
Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static(
"console",
utf16!("console"),
),
Span::new((2, 5), (2, 12)),
)
.into(),
Identifier::new(
interner.get_or_intern_static("log", utf16!("log")),
Span::new((2, 13), (2, 16)),
),
)
.into(),
),
vec![
Literal::new(
interner.get_or_intern_static("hello", utf16!("hello")),
Span::new((2, 17), (2, 24)),
)
.into(),
]
.into(),
Span::new((2, 16), (2, 25)),
)
.into(),
)
.into(),
)],
PSEUDO_LINEAR_POS,
)
.into(),
),
Binary::new(
RelationalOp::LessThan.into(),
Update::new(
UpdateOp::IncrementPost,
UpdateTarget::Identifier(Identifier::new(
interner.get_or_intern_static("i", utf16!("i")),
Span::new((2, 34), (2, 35)),
)),
Span::new((2, 34), (2, 37)),
)
.into(),
Literal::new(10, Span::new((2, 40), (2, 42))).into(),
)
.into(),
))
.into(),
Statement::Expression(
Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static("console", utf16!("console")),
Span::new((2, 43), (2, 50)),
)
.into(),
Identifier::new(
interner.get_or_intern_static("log", utf16!("log")),
Span::new((2, 51), (2, 54)),
),
)
.into(),
),
vec![
Literal::new(
interner.get_or_intern_static("end", utf16!("end")),
Span::new((2, 55), (2, 60)),
)
.into(),
]
.into(),
Span::new((2, 54), (2, 61)),
)
.into(),
)
.into(),
],
interner,
);
}
#[test]
fn while_spaces() {
check_script_parser(
indoc! {"
while
(
true
)
break;
"},
vec![
Statement::WhileLoop(WhileLoop::new(
Literal::new(true, Span::new((6, 1), (6, 5))).into(),
Break::new(None).into(),
))
.into(),
],
&mut Interner::default(),
);
}
#[test]
fn do_while_spaces() {
check_script_parser(
indoc! {"
do
{
break;
}
while (true)
"},
vec![
Statement::DoWhileLoop(DoWhileLoop::new(
Block::from((
vec![StatementListItem::Statement(
Statement::Break(Break::new(None)).into(),
)],
PSEUDO_LINEAR_POS,
))
.into(),
Literal::new(true, Span::new((10, 8), (10, 12))).into(),
))
.into(),
],
&mut Interner::default(),
);
}
#[test]
fn reject_const_no_init_for_loop() {
check_invalid_script("for (const h;;);");
}
#[test]
fn reject_for_await_in_loop() {
check_invalid_script("for await (x in [1,2,3]);");
}