Skip to content

Commit

Permalink
feat(ecmascript/parser): Add tests for binding patterns (#1289)
Browse files Browse the repository at this point in the history
  • Loading branch information
besok authored Dec 22, 2020
1 parent 8a8db58 commit c2a9994
Show file tree
Hide file tree
Showing 4 changed files with 372 additions and 1 deletion.
2 changes: 1 addition & 1 deletion ecmascript/parser/src/parser/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl<I: Tokens> ParseObject<Box<Expr>> for Parser<I> {
// Parse as 'MethodDefinition'

if eat!("...") {
// spread elemnent
// spread element
let dot3_token = span!(start);

let expr = self.include_in_expr(true).parse_assignment_expr()?;
Expand Down
214 changes: 214 additions & 0 deletions ecmascript/parser/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ impl<'a, I: Tokens> Parser<I> {
self.parse_formal_params()
}
}

///
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PatType {
Expand All @@ -435,6 +436,7 @@ pub enum PatType {
AssignPat,
AssignElement,
}

impl PatType {
pub fn element(self) -> Self {
match self {
Expand Down Expand Up @@ -798,10 +800,23 @@ mod tests {
test_parser(s, Syntax::default(), |p| p.parse_array_binding_pat())
}

fn object_pat(s: &'static str) -> Pat {
test_parser(s, Syntax::default(), |p| p.parse_binding_pat_or_ident())
}

fn ident(s: &str) -> Ident {
Ident::new(s.into(), span)
}

fn rest() -> Option<Pat> {
Some(Pat::Rest(RestPat {
span,
dot3_token: span,
type_ann: None,
arg: Box::new(Pat::Ident(ident("tail"))),
}))
}

#[test]
fn array_pat_simple() {
assert_eq_ignore_span!(
Expand Down Expand Up @@ -884,4 +899,203 @@ mod tests {
})
);
}

#[test]
fn array_binding_pattern_tail() {
assert_eq_ignore_span!(
array_pat("[...tail]"),
Pat::Array(ArrayPat {
span,
optional: false,
elems: vec![rest()],
type_ann: None
})
);
}

#[test]
fn array_binding_pattern_assign() {
assert_eq_ignore_span!(
array_pat("[,a=1,]"),
Pat::Array(ArrayPat {
span,
optional: false,
elems: vec![
None,
Some(Pat::Assign(AssignPat {
type_ann: None,
span,
left: Box::new(Pat::Ident(ident("a"))),
right: Box::new(Expr::Lit(Lit::Num(Number { span, value: 1.0 })))
}))
],
type_ann: None
})
);
}

#[test]
fn array_binding_pattern_tail_with_elems() {
assert_eq_ignore_span!(
array_pat("[,,,...tail]"),
Pat::Array(ArrayPat {
span,
optional: false,
elems: vec![None, None, None, rest()],
type_ann: None
})
);
}

#[test]
fn array_binding_pattern_tail_inside_tail() {
assert_eq_ignore_span!(
array_pat("[,,,...[...tail]]"),
Pat::Array(ArrayPat {
span,
optional: false,
elems: vec![
None,
None,
None,
Some(Pat::Rest(RestPat {
span,
dot3_token: span,
type_ann: None,
arg: Box::new(Pat::Array(ArrayPat {
span,
optional: false,
elems: vec![rest()],
type_ann: None
}))
}))
],
type_ann: None
})
);
}

#[test]
fn object_binding_pattern_tail() {
assert_eq_ignore_span!(
object_pat("{...obj}"),
Pat::Object(ObjectPat {
span,
type_ann: None,
optional: false,
props: vec![ObjectPatProp::Rest(RestPat {
span,
dot3_token: span,
type_ann: None,
arg: Box::new(Pat::Ident(ident("obj")))
})]
})
);
}

#[test]
fn object_binding_pattern_with_prop() {
assert_eq_ignore_span!(
object_pat("{prop = 10 }"),
Pat::Object(ObjectPat {
span,
type_ann: None,
optional: false,
props: vec![ObjectPatProp::Assign(AssignPatProp {
span,
key: ident("prop"),
value: Some(Box::new(Expr::Lit(Lit::Num(Number { span, value: 10.0 }))))
})]
})
);
}

#[test]
fn object_binding_pattern_with_prop_and_label() {
fn prop(key: PropName, assign_name: &str, expr: Expr) -> PropOrSpread {
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key,
value: Box::new(Expr::Assign(AssignExpr {
span,
op: AssignOp::Assign,
left: PatOrExpr::Pat(Box::new(Pat::Ident(ident(assign_name)))),
right: Box::new(expr),
})),
})))
}

assert_eq_ignore_span!(
object_pat(
"{obj = {$: num = 10, '': sym = '', \" \": quote = \" \", _: under = [...tail],}}"
),
Pat::Object(ObjectPat {
span,
type_ann: None,
optional: false,
props: vec![ObjectPatProp::Assign(AssignPatProp {
span,
key: ident("obj"),
value: Some(Box::new(Expr::Object(ObjectLit {
span,
props: vec![
prop(
PropName::Ident(ident("$")),
"num",
Expr::Lit(Lit::Num(Number { span, value: 10.0 }))
),
prop(
PropName::Str(Str {
span,
has_escape: false,
value: "".into(),
kind: StrKind::Normal {
contains_quote: true
}
}),
"sym",
Expr::Lit(Lit::Str(Str {
span,
has_escape: false,
value: "".into(),
kind: StrKind::Normal {
contains_quote: true
}
}))
),
prop(
PropName::Str(Str {
span,
has_escape: false,
value: " ".into(),
kind: StrKind::Normal {
contains_quote: true
}
}),
"quote",
Expr::Lit(Lit::Str(Str {
span,
has_escape: false,
value: " ".into(),
kind: StrKind::Normal {
contains_quote: true
}
}))
),
prop(
PropName::Ident(ident("_")),
"under",
Expr::Array(ArrayLit {
span,
elems: vec![Some(ExprOrSpread {
spread: Some(span),
expr: Box::new(Expr::Ident(ident("tail")))
})]
})
),
]
})))
})]
})
);
}
}
61 changes: 61 additions & 0 deletions ecmascript/parser/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1713,4 +1713,65 @@ export default function waitUntil(callback, options = {}) {
assert!(trailing.borrow().is_empty());
assert_eq!(leading.borrow().len(), 1);
}
fn parse_for_head(str: &'static str) -> ForHead {
test_parser(str, Syntax::default(), |p| p.parse_for_head())
}

#[test]
fn for_array_binding_pattern() {
match parse_for_head("let [, , t] = simple_array; t < 10; t++") {
ForHead::For { init: Some(v), .. } => assert_eq_ignore_span!(
v,
VarDeclOrExpr::VarDecl(VarDecl {
span,
declare: false,
kind: VarDeclKind::Let,
decls: vec![VarDeclarator {
span,
name: Pat::Array(ArrayPat {
span,
type_ann: None,
optional: false,
elems: vec![None, None, Some(Pat::Ident(Ident::new("t".into(), span)))]
}),
init: Some(Box::new(Expr::Ident(Ident::new(
"simple_array".into(),
span
)))),
definite: false
}]
})
),
_ => assert!(false),
}
}
#[test]
fn for_object_binding_pattern() {
match parse_for_head("let {num} = obj; num < 11; num++") {
ForHead::For { init: Some(v), .. } => assert_eq_ignore_span!(
v,
VarDeclOrExpr::VarDecl(VarDecl {
span,
declare: false,
kind: VarDeclKind::Let,
decls: vec![VarDeclarator {
span,
name: Pat::Object(ObjectPat {
optional: false,
type_ann: None,
span,
props: vec![ObjectPatProp::Assign(AssignPatProp {
span,
key: Ident::new("num".into(), span),
value: None
})]
}),
init: Some(Box::new(Expr::Ident(Ident::new("obj".into(), span)))),
definite: false
}]
})
),
_ => assert!(false),
}
}
}
Loading

0 comments on commit c2a9994

Please sign in to comment.