use super::*;
fn span() -> Span {
Span { line: 1, col: 1 }
}
#[test]
fn dump_pins_the_tree_shape() {
let script = Script {
stmts: vec![
Stmt::Decl {
names: vec!["age".into()],
rest: None,
expr: Expr::Int {
value: 7,
span: span(),
},
span: span(),
},
Stmt::Bark {
expr: Expr::Binary {
op: BinOp::Add,
lhs: Box::new(Expr::Str {
value: "age is ".into(),
span: span(),
}),
rhs: Box::new(Expr::Ident {
name: "age".into(),
span: span(),
}),
span: span(),
},
span: span(),
},
],
};
let expected = "\
Script
Decl age
Int 7
Bark
Binary +
Str \"age is \"
Ident age
";
assert_eq!(dump(&script), expected);
}
#[test]
fn dump_pins_the_destructuring_shape() {
let script = Script {
stmts: vec![
Stmt::Decl {
names: vec!["a".into()],
rest: Some("rest".into()),
expr: Expr::Ident {
name: "xs".into(),
span: span(),
},
span: span(),
},
Stmt::Assign {
targets: vec![
Expr::Ident {
name: "p".into(),
span: span(),
},
Expr::Ident {
name: "q".into(),
span: span(),
},
],
rest: None,
expr: Expr::List {
items: vec![
Expr::Ident {
name: "q".into(),
span: span(),
},
Expr::Ident {
name: "p".into(),
span: span(),
},
],
span: span(),
},
op: None,
flavored: false,
span: span(),
},
],
};
let expected = "\
Script
Decl a, many rest
Ident xs
Assign
target
Ident p
target
Ident q
value
List
Ident q
Ident p
";
assert_eq!(dump(&script), expected);
}
#[test]
fn hoisted_names_include_destructuring_targets_and_collectors() {
let script = Script {
stmts: vec![
Stmt::Decl {
names: vec!["a".into(), "b".into()],
rest: None,
expr: Expr::Ident {
name: "xs".into(),
span: span(),
},
span: span(),
},
Stmt::For {
vars: vec!["k".into()],
rest: Some("rest".into()),
iter: Expr::Ident {
name: "ys".into(),
span: span(),
},
body: vec![],
span: span(),
},
],
};
assert_eq!(hoisted_names(&script.stmts), vec!["a", "b", "k", "rest"]);
}
#[test]
fn hoisted_names_are_first_seen_order_and_unique() {
let script = Script {
stmts: vec![
Stmt::Decl {
names: vec!["a".into()],
rest: None,
expr: Expr::Int {
value: 1,
span: span(),
},
span: span(),
},
Stmt::For {
vars: vec!["b".into()],
rest: None,
iter: Expr::Ident {
name: "a".into(),
span: span(),
},
body: vec![Stmt::Decl {
names: vec!["a".into()],
rest: None,
expr: Expr::Int {
value: 2,
span: span(),
},
span: span(),
}],
span: span(),
},
Stmt::Try {
body: vec![],
err_name: "err".into(),
handler: vec![],
span: span(),
},
],
};
assert_eq!(hoisted_names(&script.stmts), vec!["a", "b", "err"]);
}
#[test]
fn for_each_child_block_skips_nested_function_bodies() {
let funcdef = Stmt::FuncDef {
name: "inner".into(),
params: Params::default(),
body: vec![Stmt::Decl {
names: vec!["hidden".into()],
rest: None,
expr: Expr::Int {
value: 0,
span: span(),
},
span: span(),
}],
span: span(),
};
let loop_stmt = Stmt::For {
vars: vec!["i".into()],
rest: None,
iter: Expr::List {
items: vec![],
span: span(),
},
body: vec![funcdef.clone()],
span: span(),
};
let mut blocks = 0;
for_each_child_block(&loop_stmt, &mut |body| {
blocks += 1;
assert_eq!(body.len(), 1);
});
assert_eq!(blocks, 1);
let mut inner_blocks = 0;
for_each_child_block(&funcdef, &mut |_| inner_blocks += 1);
assert_eq!(inner_blocks, 0);
}