extern crate badger;
pub use badger::*;
pub use badger::grammar::*;
pub use badger::parser::parse;
pub use badger::grammar::OperatorType::*;
macro_rules! assert_parse {
($string:expr, $body:expr) => {
assert_eq!(parse($string.to_string()).body, $body);
}
}
macro_rules! assert_expression {
($string:expr, $ex:expr) => {
match parse($string.to_string()).body[0] {
Statement::Expression { ref value } => assert_eq!(*value, $ex),
_ => panic!("No expression found"),
}
}
}
macro_rules! assert_statement {
($string:expr, $ex:expr) => (assert_parse!($string, vec![$ex]))
}
macro_rules! num {
($num:expr) => (Expression::Literal(LiteralFloat($num)))
}
macro_rules! boxnum {
($num:expr) => (Box::new(num!($num)))
}
macro_rules! ident {
($name:expr) => (Expression::Identifier($name.to_string()))
}
macro_rules! param {
($name:expr) => (Parameter {
name: $name.to_string()
})
}
#[test]
fn block_statement() {
assert_statement!("{}", Statement::Block {
body: Vec::new(),
});
}
#[test]
fn labeled_statement() {
assert_statement!("foo: {}", Statement::Labeled {
label: "foo".to_string(),
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn break_statement() {
assert_statement!("break;", Statement::Break {
label: None
});
}
#[test]
fn break_label_statement() {
assert_statement!("break foo;", Statement::Break {
label: Some("foo".to_string())
});
}
#[test]
fn break_asi_statement() {
assert_parse!("
break
foo
", vec![
Statement::Break {
label: None
},
Statement::Expression { value: ident!("foo") }
]);
}
#[test]
fn return_statement() {
assert_statement!("return;", Statement::Return {
value: None,
});
}
#[test]
fn return_value_statement() {
assert_statement!("return foo;", Statement::Return {
value: Some(ident!("foo")),
});
}
#[test]
fn return_sequence_statement() {
assert_statement!("return 1, 2, 3;", Statement::Return {
value: Some(Expression::Sequence(vec![
num!(1.0),
num!(2.0),
num!(3.0),
])),
});
}
#[test]
fn return_asi_statement() {
assert_parse!("
return
foo
", vec![
Statement::Return {
value: None
},
Statement::Expression { value: ident!("foo") }
]);
}
#[test]
fn var_declare() {
assert_statement!("var foo;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Var,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: None,
}]
});
}
#[test]
fn var_declare_value() {
assert_statement!("var foo = 100;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Var,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: Some(num!(100.0)),
}]
});
}
#[test]
fn let_declare() {
assert_statement!("let foo;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Let,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: None,
}]
});
}
#[test]
fn let_declare_value() {
assert_statement!("let foo = 100;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Let,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: Some(num!(100.0)),
}]
});
}
#[test]
fn const_declare() {
assert_statement!("const foo;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Const,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: None,
}]
});
}
#[test]
fn const_declare_value() {
assert_statement!("const foo = 100;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Const,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: Some(num!(100.0)),
}]
});
}
#[test]
fn var_muliple_declare() {
assert_statement!("var foo, bar;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Var,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: None,
}, VariableDeclarator {
name: "bar".to_string(),
value: None,
}]
});
}
#[test]
fn var_muliple_declare_value() {
assert_statement!("var foo = 100, bar = 200;", Statement::VariableDeclaration {
kind: VariableDeclarationKind::Var,
declarators: vec![VariableDeclarator {
name: "foo".to_string(),
value: Some(num!(100.0)),
}, VariableDeclarator {
name: "bar".to_string(),
value: Some(num!(200.0)),
}]
});
}
#[test]
fn identifier_expression() {
assert_expression!("foobar", ident!("foobar"))
}
#[test]
fn null_expression() {
assert_expression!("null", Expression::Literal(LiteralNull));
}
#[test]
fn undefined_expression() {
assert_expression!("undefined", Expression::Literal(LiteralUndefined));
}
#[test]
fn true_expression() {
assert_expression!("true", Expression::Literal(LiteralTrue));
}
#[test]
fn false_expression() {
assert_expression!("false", Expression::Literal(LiteralFalse));
}
#[test]
fn number_expression() {
assert_expression!("100", num!(100.0));
}
#[test]
fn binary_number_expression() {
assert_expression!("0b1100100", Expression::Literal(LiteralInteger(100)));
}
#[test]
fn octal_number_expression() {
assert_expression!("0o144", Expression::Literal(LiteralInteger(100)));
}
#[test]
fn hexdec_number_expression() {
assert_expression!("0x64", Expression::Literal(LiteralInteger(100)));
}
#[test]
fn floating_number_expression() {
assert_expression!("3.14", num!(3.14));
}
#[test]
fn binary_expression() {
assert_expression!("true == 1", Expression::Binary {
left: Box::new(Expression::Literal(LiteralTrue)),
operator: Equality,
right: boxnum!(1.0)
});
}
#[test]
fn op_precedence_left() {
assert_expression!("1 + 2 * 3", Expression::Binary {
left: boxnum!(1.0),
operator: Addition,
right: Box::new(Expression::Binary {
left: boxnum!(2.0),
operator: Multiplication,
right: boxnum!(3.0),
}),
});
}
#[test]
fn op_precedence_right() {
assert_expression!("1 * 2 + 3", Expression::Binary {
left: Box::new(Expression::Binary {
left: boxnum!(1.0),
operator: Multiplication,
right: boxnum!(2.0),
}),
operator: Addition,
right: boxnum!(3.0),
});
}
#[test]
fn function_statement() {
assert_statement!("
function foo() {
return bar;
}
", Statement::Function {
name: "foo".to_string(),
params: vec![],
body: vec![
Statement::Return {
value: Some(ident!("bar"))
}
]
});
}
#[test]
fn function_with_params_statement() {
assert_statement!("
function foo(a, b, c) {
return bar;
}
", Statement::Function {
name: "foo".to_string(),
params: vec![
param!("a"),
param!("b"),
param!("c"),
],
body: vec![
Statement::Return {
value: Some(ident!("bar"))
}
]
});
}
#[test]
fn if_statement() {
assert_statement!("
if (true) {
foo;
}
", Statement::If {
test: Expression::Literal(LiteralTrue),
consequent: Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("foo")
}]
}),
alternate: None,
});
}
#[test]
fn if_else_statement() {
assert_statement!("
if (true) {
foo;
} else {
bar;
}
", Statement::If {
test: Expression::Literal(LiteralTrue),
consequent: Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("foo")
}]
}),
alternate: Some(Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("bar")
}]
})),
})
}
#[test]
fn if_else_if_else_statement() {
assert_statement!("
if (true) {
foo;
} else if(false) {
bar;
} else {
baz;
}
", Statement::If {
test: Expression::Literal(LiteralTrue),
consequent: Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("foo")
}]
}),
alternate: Some(Box::new(Statement::If {
test: Expression::Literal(LiteralFalse),
consequent: Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("bar")
}]
}),
alternate: Some(Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("baz")
}]
})),
})),
});
}
#[test]
fn if_no_block_statement() {
assert_statement!("if (true) foo;", Statement::If {
test: Expression::Literal(LiteralTrue),
consequent: Box::new(Statement::Expression {
value: ident!("foo")
}),
alternate: None,
});
}
#[test]
fn if_else_no_block_statement() {
assert_statement!("if (true) foo; else bar;", Statement::If {
test: Expression::Literal(LiteralTrue),
consequent: Box::new(Statement::Expression {
value: ident!("foo")
}),
alternate: Some(Box::new(Statement::Expression {
value: ident!("bar")
})),
})
}
#[test]
fn for_statement() {
assert_statement!("for (i = 0; i < 10; i++) {}", Statement::For {
init: Some(Box::new(Statement::Expression {
value: Expression::Binary {
left: Box::new(ident!("i")),
operator: OperatorType::Assign,
right: Box::new(num!(0.0)),
}
})),
test: Some(Expression::Binary {
left: Box::new(ident!("i")),
operator: OperatorType::Lesser,
right: Box::new(num!(10.0)),
}),
update: Some(Expression::Postfix {
operator: OperatorType::Increment,
operand: Box::new(ident!("i")),
}),
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn for_declare_statement() {
assert_statement!("for (let i = 0; i < 10; i++) {}", Statement::For {
init: Some(Box::new(Statement::VariableDeclaration {
kind: VariableDeclarationKind::Let,
declarators: vec![
VariableDeclarator {
name: "i".to_string(),
value: Some(num!(0.0)),
}
],
})),
test: Some(Expression::Binary {
left: Box::new(ident!("i")),
operator: OperatorType::Lesser,
right: Box::new(num!(10.0)),
}),
update: Some(Expression::Postfix {
operator: OperatorType::Increment,
operand: Box::new(ident!("i")),
}),
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn for_empty_statement() {
assert_statement!("for (;;) {}", Statement::For {
init: None,
test: None,
update: None,
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn for_in_statement() {
assert_statement!("for (item in object) {}", Statement::ForIn {
left: Box::new(Statement::Expression {
value: ident!("item")
}),
right: ident!("object"),
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn for_in_declare_statement() {
assert_statement!("for (let item in object) {}", Statement::ForIn {
left: Box::new(Statement::VariableDeclaration {
kind: VariableDeclarationKind::Let,
declarators: vec![
VariableDeclarator {
name: "item".to_string(),
value: None,
}
],
}),
right: ident!("object"),
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn for_of_statement() {
assert_statement!("for (item of array) {}", Statement::ForOf {
left: Box::new(Statement::Expression {
value: ident!("item")
}),
right: ident!("array"),
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn for_of_declare_statement() {
assert_statement!("for (let item of array) {}", Statement::ForOf {
left: Box::new(Statement::VariableDeclaration {
kind: VariableDeclarationKind::Let,
declarators: vec![
VariableDeclarator {
name: "item".to_string(),
value: None,
}
],
}),
right: ident!("array"),
body: Box::new(Statement::Block {
body: Vec::new(),
}),
});
}
#[test]
fn while_statement() {
assert_statement!("
while (true) {
foo;
}
", Statement::While {
test: Expression::Literal(LiteralTrue),
body: Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("foo")
}]
}),
});
}
#[test]
fn while_no_block_statement() {
assert_statement!("while (true) foo;", Statement::While {
test: Expression::Literal(LiteralTrue),
body: Box::new(Statement::Expression {
value: ident!("foo")
}),
});
}
#[test]
fn arrow_function() {
assert_expression!("
() => {
bar;
}
", Expression::ArrowFunction {
params: vec![],
body: Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("bar")
}]
})
});
}
#[test]
fn arrow_function_shorthand() {
assert_expression!("n => n * n", Expression::ArrowFunction {
params: vec![
param!("n")
],
body: Box::new(Statement::Expression {
value: Expression::Binary {
left: Box::new(ident!("n")),
operator: Multiplication,
right: Box::new(ident!("n")),
}
}),
});
}
#[test]
fn arrow_function_with_params() {
assert_expression!("
(a, b, c) => {
bar;
}
", Expression::ArrowFunction {
params: vec![
param!("a"),
param!("b"),
param!("c"),
],
body: Box::new(Statement::Block {
body: vec![Statement::Expression {
value: ident!("bar")
}]
})
});
}
#[test]
fn function_expression() {
assert_expression!("
(function () {
return bar;
})
", Expression::Function {
name: None,
params: vec![],
body: vec![
Statement::Return {
value: Some(ident!("bar"))
}
]
});
}
#[test]
fn named_function_expression() {
assert_expression!("
(function foo() {
return bar;
})
", Expression::Function {
name: Some("foo".to_string()),
params: vec![],
body: vec![
Statement::Return {
value: Some(ident!("bar"))
}
]
});
}
#[test]
fn expression_statement() {
assert_statement!("foo", Statement::Expression {
value: ident!("foo")
});
}
#[test]
fn sequence_expression_statement() {
assert_statement!("foo, bar, baz", Statement::Expression {
value: Expression::Sequence(vec![
ident!("foo"),
ident!("bar"),
ident!("baz"),
])
});
}
#[test]
fn sequence_in_accessor() {
assert_expression!("foo[1, 2, 3]", Expression::Member {
object: Box::new(ident!("foo")),
property: Box::new(MemberKey::Computed(
Expression::Sequence(vec![
num!(1.0),
num!(2.0),
num!(3.0),
])
))
});
}
#[test]
fn object_literal_member() {
assert_expression!("({foo:100})", Expression::Object(vec![
ObjectMember::Literal {
key: "foo".to_string(),
value: num!(100.0),
}
]));
}
#[test]
fn object_computed_member() {
assert_expression!("({[100]:100})", Expression::Object(vec![
ObjectMember::Computed {
key: num!(100.0),
value: num!(100.0),
}
]));
}
#[test]
fn object_shorthand_member() {
assert_expression!("({foo})", Expression::Object(vec![
ObjectMember::Shorthand {
key: "foo".to_string(),
}
]));
}
#[test]
fn object_method_member() {
assert_expression!("({foo() {} })", Expression::Object(vec![
ObjectMember::Method {
name: "foo".to_string(),
params: vec![],
body: vec![],
}
]));
}
#[test]
fn object_computed_method_member() {
assert_expression!("({[100]() {} })", Expression::Object(vec![
ObjectMember::ComputedMethod {
name: num!(100.0),
params: vec![],
body: vec![],
}
]));
}
#[test]
fn class_statement() {
assert_statement!("class Foo {}", Statement::Class {
name: "Foo".to_string(),
extends: None,
body: Vec::new(),
});
}
#[test]
fn class_extends_statement() {
assert_statement!("class Foo extends Bar {}", Statement::Class {
name: "Foo".to_string(),
extends: Some("Bar".to_string()),
body: Vec::new(),
});
}
#[test]
fn class_with_constructor_statement() {
assert_statement!("
class Foo {
constructor() {}
}
", Statement::Class {
name: "Foo".to_string(),
extends: None,
body: vec![
ClassMember::Constructor {
params: Vec::new(),
body: Vec::new(),
}
],
});
}
#[test]
fn class_with_method_statement() {
assert_statement!("
class Foo {
bar() {}
}
", Statement::Class {
name: "Foo".to_string(),
extends: None,
body: vec![
ClassMember::Method {
is_static: false,
name: "bar".to_string(),
params: Vec::new(),
body: Vec::new(),
}
],
});
}
#[test]
fn class_with_static_method_statement() {
assert_statement!("
class Foo {
static bar() {}
}
", Statement::Class {
name: "Foo".to_string(),
extends: None,
body: vec![
ClassMember::Method {
is_static: true,
name: "bar".to_string(),
params: Vec::new(),
body: Vec::new(),
}
],
});
}
#[test]
fn class_with_property_statement() {
assert_statement!("
class Foo {
bar = 100;
}
", Statement::Class {
name: "Foo".to_string(),
extends: None,
body: vec![
ClassMember::Property {
is_static: false,
name: "bar".to_string(),
value: num!(100.0),
}
],
});
}
#[test]
fn class_with_static_property_statement() {
assert_statement!("
class Foo {
static bar = 100;
}
", Statement::Class {
name: "Foo".to_string(),
extends: None,
body: vec![
ClassMember::Property {
is_static: true,
name: "bar".to_string(),
value: num!(100.0),
}
],
});
}