Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ecmascript/parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub struct Error {

#[derive(Debug, Clone, PartialEq)]
pub enum SyntaxError {
TopLevelAwait,

LegacyDecimal,
LegacyOctal,
InvalidIdentChar,
Expand Down Expand Up @@ -226,6 +228,9 @@ impl<'a> From<ErrorToDiag<'a>> for DiagnosticBuilder<'a> {
#[cold]
fn from(e: ErrorToDiag<'a>) -> Self {
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(),
LegacyOctal => "Legacy octal escape is not permitted in strict mode".into(),
InvalidIdentChar => "Invalid character in identifier".into(),
Expand Down
16 changes: 16 additions & 0 deletions ecmascript/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,18 @@ impl Syntax {
_ => 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)]
Expand Down Expand Up @@ -378,6 +390,10 @@ pub struct EsConfig {
/// Stage 3.
#[serde(default)]
pub import_meta: bool,

/// Stage 3.
#[serde(default)]
pub top_level_await: bool,
}

/// Syntactic context.
Expand Down
3 changes: 1 addition & 2 deletions ecmascript/parser/src/parser/expr/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,10 @@ impl<'a, I: Tokens> Parser<'a, I> {
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!();

assert_and_bump!("await");
debug_assert!(self.ctx().in_async);

if is!('*') {
syntax_error!(SyntaxError::AwaitStar);
Expand Down
2 changes: 1 addition & 1 deletion ecmascript/parser/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ where
F: for<'a> FnOnce(&'a mut Parser<'a, Lexer<'a, crate::SourceFileInput<'_>>>) -> Result<Ret, ()>,
{
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))
})
.unwrap_or_else(|output| panic!("test_parser(): failed to parse \n{}\n{}", s, output))
Expand Down
30 changes: 30 additions & 0 deletions ecmascript/parser/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ impl<'a, I: Tokens> Parser<'a, I> {
top_level: bool,
decorators: Vec<Decorator>,
) -> 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") {
assert_and_bump!("const");
assert_and_bump!("enum");
Expand Down Expand Up @@ -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();
})
},
);
}
}
Original file line number Diff line number Diff line change
@@ -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
|
1 | await
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
await foo
Original file line number Diff line number Diff line change
@@ -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
| ^^^^^

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"declare": false,
"span": {
"start": 0,
"start": 5,
"end": 196,
"ctxt": 0
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"declare": false,
"span": {
"start": 0,
"start": 21,
"end": 34,
"ctxt": 0
},
Expand Down