swc_ecma_parser:
 - fix parsing of type query (#338)
 - fix parsing of `in` in a let / const declaration (#337)

swc_ecma_transforms:
 - string literal is computed (#336)
 - modules: handle imports in lhs of assignment correctly (#335)
This commit is contained in:
강동윤 2019-03-11 20:33:15 +09:00 committed by GitHub
parent 2025f20e8c
commit 13bf89d08c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 208 additions and 211 deletions

View File

@ -366,3 +366,17 @@ fn issue_328() {
}))
);
}
#[test]
fn issue_337() {
test_parser(
"const foo = 'bar' in bas ? 'beep' : 'boop';",
Default::default(),
|p| {
p.parse_module().map_err(|mut e| {
e.emit();
()
})
},
);
}

View File

@ -438,7 +438,7 @@ impl<'a, I: Input> Parser<'a, I> {
tok!("var") => VarDeclKind::Var,
_ => unreachable!(),
};
let should_include_in = kind == VarDeclKind::Var;
let should_include_in = kind != VarDeclKind::Var;
let mut decls = vec![];
let mut first = true;

View File

@ -159,7 +159,11 @@ impl<'a, I: Input> Parser<'a, I> {
let mut entity = TsEntityName::Ident(self.parse_ident_name()?);
while eat!('.') {
let left = entity;
let right = self.parse_ident(allow_reserved_words, allow_reserved_words)?;
let right = if allow_reserved_words {
self.parse_ident_name()?
} else {
self.parse_ident(false, false)?
};
entity = TsEntityName::TsQualifiedName(Box::new(TsQualifiedName { left, right }));
}

View File

@ -1,6 +1,6 @@
error: Unexpected initializer in for in/of loop
--> $DIR/tests/test262-parser/fail/0ddab4a1a651034c.js:1:6
error: Expected Semi, got Some(RParen)
--> $DIR/tests/test262-parser/fail/0ddab4a1a651034c.js:1:24
|
1 | for (let x = 42 in list) process(x);
| ^^^^^^^^^^
| ^

View File

@ -1,6 +1,6 @@
error: Unexpected initializer in for in/of loop
--> $DIR/tests/test262-parser/fail/154f02d86fce5e81.js:1:6
error: Expected Semi, got Some(RParen)
--> $DIR/tests/test262-parser/fail/154f02d86fce5e81.js:1:22
|
1 | for (const x = 0 in y){}
| ^^^^^^^^^^^
| ^

View File

@ -1,6 +1,6 @@
error: Unexpected initializer in for in/of loop
--> $DIR/tests/test262-parser/fail/3162394f5bc07198.js:1:5
error: Expected Semi, got Some(RParen)
--> $DIR/tests/test262-parser/fail/3162394f5bc07198.js:1:21
|
1 | for(const a = 0 in b);
| ^^^^^^^^^^^
| ^

View File

@ -1,6 +1,6 @@
error: Unexpected initializer in for in/of loop
--> $DIR/tests/test262-parser/fail/33d43e9f01bda5ce.js:1:6
error: Expected Semi, got Some(RParen)
--> $DIR/tests/test262-parser/fail/33d43e9f01bda5ce.js:1:20
|
1 | for (let x = 0 in y){}
| ^^^^^^^^^
| ^

View File

@ -1,6 +1,6 @@
error: Unexpected initializer in for in/of loop
--> $DIR/tests/test262-parser/fail/c75e9f5ea55611f3.js:1:5
error: Expected Semi, got Some(RParen)
--> $DIR/tests/test262-parser/fail/c75e9f5ea55611f3.js:1:23
|
1 | for(let x=1 in [1,2,3]) 0
| ^^^^^^^
| ^

View File

@ -1,6 +1,6 @@
error: Unexpected initializer in for in/of loop
--> $DIR/tests/test262-parser/fail/e01265e2211e48b3.js:1:5
error: Expected Semi, got Some(RParen)
--> $DIR/tests/test262-parser/fail/e01265e2211e48b3.js:1:19
|
1 | for(let a = 0 in b);
| ^^^^^^^^^
| ^

View File

@ -1,6 +1,6 @@
error: Expected Semi, got Some(RParen)
--> $DIR/tests/test262-parser/fail/e3fbcf63d7e43ead.js:1:23
error: Unexpected initializer in for in/of loop
--> $DIR/tests/test262-parser/fail/e3fbcf63d7e43ead.js:1:5
|
1 | for(var x=1 in [1,2,3]) 0
| ^
| ^^^^^^^

View File

@ -0,0 +1 @@
const bar = bas as typeof beep.delete

View File

@ -0,0 +1,90 @@
{
"type": "Module",
"span": {
"start": 0,
"end": 37,
"ctxt": 0
},
"body": [
{
"type": "VariableDeclaration",
"span": {
"start": 0,
"end": 37,
"ctxt": 0
},
"kind": "const",
"declare": false,
"declarations": [
{
"type": "VariableDeclarator",
"span": {
"start": 6,
"end": 37,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 6,
"end": 9,
"ctxt": 0
},
"value": "bar",
"optional": false
},
"init": {
"type": "TsAsExpression",
"span": {
"start": 12,
"end": 15,
"ctxt": 0
},
"expression": {
"type": "Identifier",
"span": {
"start": 12,
"end": 15,
"ctxt": 0
},
"value": "bas",
"optional": false
},
"typeAnnotation": {
"type": "TsTypeQuery",
"span": {
"start": 19,
"end": 37,
"ctxt": 0
},
"exprName": {
"type": "TsQualifiedName",
"left": {
"type": "Identifier",
"span": {
"start": 26,
"end": 30,
"ctxt": 0
},
"value": "beep",
"optional": false
},
"right": {
"type": "Identifier",
"span": {
"start": 31,
"end": 37,
"ctxt": 0
},
"value": "delete",
"optional": false
}
}
}
},
"definite": false
}
]
}
]
}

View File

@ -716,7 +716,7 @@ fn make_ref_ident(decls: &mut Vec<VarDeclarator>, init: Option<Box<Expr>>) -> Id
fn make_ref_prop_expr(ref_ident: &Ident, prop: Box<Expr>, mut computed: bool) -> Expr {
computed |= match *prop {
Expr::Lit(Lit::Num(..)) => true,
Expr::Lit(Lit::Num(..)) | Expr::Lit(Lit::Str(..)) => true,
_ => false,
};

View File

@ -535,3 +535,12 @@ export const A = ref[0], B = ref[1], C = ref[2];
var ref1 = [4, 5, 6];
export const E = ref[0], D = ref[1], F = ref[2];"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| tr(),
issue_336,
"const { 'foo-bar': fooBar } = baz;",
"const ref = baz ? baz : _throw(new TypeError(\"Cannot destructure 'undefined' or 'null'\")), \
fooBar = ref['foo-bar'];"
);

View File

@ -9,7 +9,7 @@ use crate::{
use ast::*;
use fxhash::FxHashSet;
use serde::{Deserialize, Serialize};
use std::{collections::hash_map::Entry, iter};
use std::iter;
use swc_common::{Fold, FoldWith, Mark, VisitWith, DUMMY_SP};
#[cfg(test)]
@ -552,193 +552,9 @@ impl Fold<Prop> for Amd {
impl Fold<Expr> for Amd {
fn fold(&mut self, expr: Expr) -> Expr {
let exports_ident = self.exports.0.clone();
let top_level = self.in_top_level;
macro_rules! entry {
($i:expr) => {
self.scope
.exported_vars
.entry(($i.sym.clone(), $i.span.ctxt()))
};
}
macro_rules! chain_assign {
($entry:expr, $e:expr) => {{
let mut e = $e;
for i in $entry.get() {
e = box Expr::Assign(AssignExpr {
span: DUMMY_SP,
left: PatOrExpr::Expr(
box exports_ident
.clone()
.member(Ident::new(i.0.clone(), DUMMY_SP.with_ctxt(i.1))),
),
op: op!("="),
right: e,
});
}
e
}};
}
match expr {
Expr::Ident(i) => {
let v = self.scope.idents.get(&(i.sym.clone(), i.span.ctxt()));
match v {
None => return Expr::Ident(i),
Some((src, prop)) => {
let (ident, span) = self
.scope
.imports
.get(src)
.as_ref()
.unwrap()
.as_ref()
.unwrap();
let obj = {
let ident = Ident::new(ident.clone(), *span);
Expr::Ident(ident)
};
if *prop == js_word!("") {
// import * as foo from 'foo';
obj
} else {
obj.member(Ident::new(prop.clone(), DUMMY_SP))
}
}
}
}
Expr::Member(e) => {
if e.computed {
Expr::Member(MemberExpr {
obj: e.obj.fold_with(self),
prop: e.prop.fold_with(self),
..e
})
} else {
Expr::Member(MemberExpr {
obj: e.obj.fold_with(self),
..e
})
}
}
Expr::Update(UpdateExpr {
span,
arg: box Expr::Ident(arg),
op,
prefix,
}) => {
let entry = entry!(arg);
match entry {
Entry::Occupied(entry) => {
let e = chain_assign!(
entry,
box Expr::Assign(AssignExpr {
span: DUMMY_SP,
left: PatOrExpr::Pat(box Pat::Ident(arg.clone())),
op: op!("="),
right: box Expr::Bin(BinExpr {
span: DUMMY_SP,
left: box Expr::Unary(UnaryExpr {
span: DUMMY_SP,
op: op!(unary, "+"),
arg: box Expr::Ident(arg)
}),
op: match op {
op!("++") => op!(bin, "+"),
op!("--") => op!(bin, "-"),
},
right: box Expr::Lit(Lit::Num(Number {
span: DUMMY_SP,
value: 1.0,
})),
}),
})
);
*e
}
_ => {
return Expr::Update(UpdateExpr {
span,
arg: box Expr::Ident(arg),
op,
prefix,
});
}
}
}
Expr::Assign(mut expr) => {
//
expr.right = expr.right.fold_with(self);
match expr.left {
PatOrExpr::Pat(box Pat::Ident(ref i)) => {
let entry = entry!(i);
match entry {
Entry::Occupied(entry) => {
let e = chain_assign!(entry, box Expr::Assign(expr));
*e
}
_ => {
return Expr::Assign(AssignExpr {
left: expr.left,
..expr
});
}
}
}
_ => {
let mut found = vec![];
let mut v = DestructuringFinder { found: &mut found };
expr.left.visit_with(&mut v);
if v.found.is_empty() {
return Expr::Assign(AssignExpr {
left: expr.left,
..expr
});
}
let mut exprs = iter::once(box Expr::Assign(expr))
.chain(
found
.into_iter()
.map(|var| Ident::new(var.0, var.1))
.filter_map(|i| {
let entry = match entry!(i) {
Entry::Occupied(entry) => entry,
_ => {
return None;
}
};
let e = chain_assign!(entry, box Expr::Ident(i));
// exports.name = x
Some(e)
}),
)
.collect::<Vec<_>>();
if exprs.len() == 1 {
return *exprs.pop().unwrap();
}
Expr::Seq(SeqExpr {
span: DUMMY_SP,
exprs,
})
}
}
}
_ => expr.fold_children(self),
}
Scope::fold_expr(self, self.exports.0.clone(), top_level, expr)
}
}

View File

@ -12,6 +12,22 @@ fn tr(config: Config) -> impl Fold<Module> {
chain_at!(Module, resolver(), amd(config))
}
test!(
syntax(),
|_| tr(Config {
..Default::default()
}),
issue_335,
"import bar from 'bar';
obj[bar('bas')] = '123'",
"define(['bar'], function(_bar) {
'use strict';
_bar = _interopRequireDefault(_bar);
obj[_bar.default('bas')] = '123';
});"
);
test!(
syntax(),
|_| tr(Config {

View File

@ -11,6 +11,20 @@ fn tr(config: Config) -> impl Fold<Module> {
chain!(resolver(), common_js(config))
}
test!(
syntax(),
|_| tr(Config {
..Default::default()
}),
issue_335,
"import bar from 'bar';
obj[bar('bas')] = '123'",
"'use strict';
var _bar = _interopRequireDefault(require('bar'));
obj[_bar.default('bas')] = '123';"
);
test!(
syntax(),
|_| tr(Config {

View File

@ -9,6 +9,38 @@ fn tr(tester: &mut crate::tests::Tester, config: Config) -> impl Fold<Module> {
chain!(resolver(), umd(tester.cm.clone(), config))
}
test!(
syntax(),
|tester| tr(
tester,
Config {
..Default::default()
}
),
issue_335,
"import bar from 'bar';
obj[bar('bas')] = '123'",
"(function(global, factory) {
if (typeof define === 'function' && define.amd) {
define(['bar'], factory);
} else if (typeof exports !== 'undefined') {
factory(require('bar'));
} else {
var mod = {
exports: {
}
};
factory(global.bar);
global.input = mod.exports;
}
})(this, function(_bar) {
'use strict';
_bar = _interopRequireDefault(_bar);
obj[_bar.default('bas')] = '123';
});"
);
test!(
syntax(),
|tester| tr(

View File

@ -518,6 +518,7 @@ impl Scope {
}
Expr::Assign(mut expr) => {
expr.left = expr.left.fold_with(folder);
expr.right = expr.right.fold_with(folder);
let mut found = vec![];