mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 13:51:19 +03:00
Top level await (#627)
Implements a top level await for es2017+, and allow it for typescript and ecmascript (ecmascript requires topLevelAwait: true). Closes #626.
This commit is contained in:
parent
42373f975b
commit
94eac1de89
@ -46,6 +46,8 @@ pub struct Error {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum SyntaxError {
|
pub enum SyntaxError {
|
||||||
|
TopLevelAwait,
|
||||||
|
|
||||||
LegacyDecimal,
|
LegacyDecimal,
|
||||||
LegacyOctal,
|
LegacyOctal,
|
||||||
InvalidIdentChar,
|
InvalidIdentChar,
|
||||||
@ -226,6 +228,9 @@ impl<'a> From<ErrorToDiag<'a>> for DiagnosticBuilder<'a> {
|
|||||||
#[cold]
|
#[cold]
|
||||||
fn from(e: ErrorToDiag<'a>) -> Self {
|
fn from(e: ErrorToDiag<'a>) -> Self {
|
||||||
let msg: Cow<'static, _> = match e.error {
|
let msg: Cow<'static, _> = match e.error {
|
||||||
|
TopLevelAwait => "top level await requires target to es2017 or higher and \
|
||||||
|
topLevelAwait:true for ecmascript"
|
||||||
|
.into(),
|
||||||
LegacyDecimal => "Legacy decimal escape is not permitted in strict mode".into(),
|
LegacyDecimal => "Legacy decimal escape is not permitted in strict mode".into(),
|
||||||
LegacyOctal => "Legacy octal escape is not permitted in strict mode".into(),
|
LegacyOctal => "Legacy octal escape is not permitted in strict mode".into(),
|
||||||
InvalidIdentChar => "Invalid character in identifier".into(),
|
InvalidIdentChar => "Invalid character in identifier".into(),
|
||||||
|
@ -281,6 +281,18 @@ impl Syntax {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn top_level_await(self) -> bool {
|
||||||
|
match self {
|
||||||
|
Syntax::Es(EsConfig {
|
||||||
|
top_level_await: true,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| Syntax::Typescript(..) => true,
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
||||||
@ -378,6 +390,10 @@ pub struct EsConfig {
|
|||||||
/// Stage 3.
|
/// Stage 3.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub import_meta: bool,
|
pub import_meta: bool,
|
||||||
|
|
||||||
|
/// Stage 3.
|
||||||
|
#[serde(default)]
|
||||||
|
pub top_level_await: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Syntactic context.
|
/// Syntactic context.
|
||||||
|
@ -338,11 +338,10 @@ impl<'a, I: Tokens> Parser<'a, I> {
|
|||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_await_expr(&mut self) -> PResult<'a, Box<Expr>> {
|
pub(crate) fn parse_await_expr(&mut self) -> PResult<'a, Box<Expr>> {
|
||||||
let start = cur_pos!();
|
let start = cur_pos!();
|
||||||
|
|
||||||
assert_and_bump!("await");
|
assert_and_bump!("await");
|
||||||
debug_assert!(self.ctx().in_async);
|
|
||||||
|
|
||||||
if is!('*') {
|
if is!('*') {
|
||||||
syntax_error!(SyntaxError::AwaitStar);
|
syntax_error!(SyntaxError::AwaitStar);
|
||||||
|
@ -175,7 +175,7 @@ where
|
|||||||
F: for<'a> FnOnce(&'a mut Parser<'a, Lexer<'a, crate::SourceFileInput<'_>>>) -> Result<Ret, ()>,
|
F: for<'a> FnOnce(&'a mut Parser<'a, Lexer<'a, crate::SourceFileInput<'_>>>) -> Result<Ret, ()>,
|
||||||
{
|
{
|
||||||
crate::with_test_sess(s, |sess, input| {
|
crate::with_test_sess(s, |sess, input| {
|
||||||
let lexer = Lexer::new(sess, syntax, Default::default(), input, None);
|
let lexer = Lexer::new(sess, syntax, JscTarget::Es2019, input, None);
|
||||||
f(&mut Parser::new_from(sess, lexer))
|
f(&mut Parser::new_from(sess, lexer))
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|output| panic!("test_parser(): failed to parse \n{}\n{}", s, output))
|
.unwrap_or_else(|output| panic!("test_parser(): failed to parse \n{}\n{}", s, output))
|
||||||
|
@ -92,6 +92,20 @@ impl<'a, I: Tokens> Parser<'a, I> {
|
|||||||
top_level: bool,
|
top_level: bool,
|
||||||
decorators: Vec<Decorator>,
|
decorators: Vec<Decorator>,
|
||||||
) -> PResult<'a, Stmt> {
|
) -> PResult<'a, Stmt> {
|
||||||
|
let start = cur_pos!();
|
||||||
|
if top_level && is!("await") {
|
||||||
|
let valid = self.target() >= JscTarget::Es2017 && self.syntax().top_level_await();
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
self.emit_err(self.input.cur_span(), SyntaxError::TopLevelAwait);
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr = self.parse_await_expr()?;
|
||||||
|
|
||||||
|
let span = span!(start);
|
||||||
|
return Ok(Stmt::Expr(ExprStmt { span, expr }));
|
||||||
|
}
|
||||||
|
|
||||||
if self.input.syntax().typescript() && is!("const") && peeked_is!("enum") {
|
if self.input.syntax().typescript() && is!("const") && peeked_is!("enum") {
|
||||||
assert_and_bump!("const");
|
assert_and_bump!("const");
|
||||||
assert_and_bump!("enum");
|
assert_and_bump!("enum");
|
||||||
@ -1634,4 +1648,20 @@ export default function waitUntil(callback, options = {}) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn top_level_await() {
|
||||||
|
test_parser(
|
||||||
|
"await foo",
|
||||||
|
Syntax::Es(EsConfig {
|
||||||
|
top_level_await: true,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
|p| {
|
||||||
|
p.parse_module().map_err(|mut e| {
|
||||||
|
e.emit();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
error: Unexpected token Some(Word(await))
|
error: top level await requires target to es2017 or higher and topLevelAwait:true for ecmascript
|
||||||
|
--> $DIR/tests/test262-parser/fail/1aefe47e20eb91fa.module.js:1:1
|
||||||
|
|
|
||||||
|
1 | await
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: Unexpected token None
|
||||||
--> $DIR/tests/test262-parser/fail/1aefe47e20eb91fa.module.js:1:1
|
--> $DIR/tests/test262-parser/fail/1aefe47e20eb91fa.module.js:1:1
|
||||||
|
|
|
|
||||||
1 | await
|
1 | await
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
await foo
|
@ -0,0 +1,6 @@
|
|||||||
|
error: top level await requires target to es2017 or higher and topLevelAwait:true for ecmascript
|
||||||
|
--> $DIR/tests/typescript-errors/custom/top-level-await-jsc-target/input.ts:1:1
|
||||||
|
|
|
||||||
|
1 | await foo
|
||||||
|
| ^^^^^
|
||||||
|
|
@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"declare": false,
|
"declare": false,
|
||||||
"span": {
|
"span": {
|
||||||
"start": 0,
|
"start": 5,
|
||||||
"end": 196,
|
"end": 196,
|
||||||
"ctxt": 0
|
"ctxt": 0
|
||||||
},
|
},
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"declare": false,
|
"declare": false,
|
||||||
"span": {
|
"span": {
|
||||||
"start": 0,
|
"start": 21,
|
||||||
"end": 34,
|
"end": 34,
|
||||||
"ctxt": 0
|
"ctxt": 0
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user