Skip to content

Commit 1033c64

Browse files
authored
feat(jsruntime): async/await (#340)
* feat(jstb): add `--as` * feat(jsparser): `Module` and `AwaitExpression` * feat(jsruntime)!: dump only when "1" is set * style(jsruntime): format * feat(jsruntime): implement async/await TODO: enable the scope cleanup checker again TODO: refactoring * test(jsruntime): add test cases * feat(jsruntime): await promise * feat(jsruntime): top-level await expressions in modules * feat(jsruntime): AsyncFunctionExpression * feat(jsruntime): AsyncArrowFunction * refactor(jsruntime): refactoring * style(jsruntime): format * test(jsruntime): reorganize files * fix(jsparser): StatementList_Await * test(jsruntime): add test cases * feat(jsruntime): simplify the scope cleanup checker * refactor(jsruntime): refactoring * refactor(jsruntime): refactoring * fix(jsruntime): support the scope cleanup checker in coroutines * refactor(jsruntime): pass FunctionId to peer * refactor(jsruntime): refactoring * feat(jsruntime): save operands to the scratch buffer * fix(jsruntime): await_in_if_else.mjs * refactor(jsruntime): refactoring for the switch statement * fix(jsruntime): await_in_switch_case.mjs * style(jsruntime): format * feat(jsruntime): compute the size of the scratch buffer * fix(jsruntime): await_in_arguments.mjs * fix(jsruntime): save closures and promises to the scratch buffer * fix(jsruntime): await_in_arguments.mjs * build(deps): update Cargo.lock * fix(jstb): remove unused crates * fix(jsparser): remove unused hidden symbols * refactor(jsruntime): refactoring * fix(jsruntime): fix a borrow checker issue * refactor(jsruntime): refactoring * fix(jsruntime): fix comments * docs(jsruntime): implementation notes * refactor(jsruntime): refactoring * refactor(jsruntime): refactoring
1 parent 8d2903c commit 1033c64

File tree

205 files changed

+3672
-1218
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

205 files changed

+3672
-1218
lines changed

Cargo.lock

Lines changed: 159 additions & 196 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bins/estree/src/builder/actions.yaml

Lines changed: 79 additions & 58 deletions
Large diffs are not rendered by default.

bins/jstb/src/main.rs

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ struct CommandLine {
1212
#[command(subcommand)]
1313
command: Command,
1414

15+
/// The type of the source text.
16+
///
17+
/// Specify `module` explicitly when the source text read from STDIN is parsed as a module.
18+
#[arg(
19+
global = true,
20+
long = "as",
21+
default_value = "auto",
22+
value_name = "SOURCE_TYPE"
23+
)]
24+
parse_as: SourceType,
25+
1526
/// Enables the scope cleanup checker.
1627
#[arg(global = true, long)]
1728
scope_cleanup_checker: bool,
@@ -65,6 +76,20 @@ struct Run {
6576
no_optimize: bool,
6677
}
6778

79+
#[derive(clap::ValueEnum, Clone)]
80+
enum SourceType {
81+
/// Parse as a script if the file extension of the input file is "js".
82+
/// Parse as a module if the file extension of the input file is "mjs".
83+
/// Otherwise, parse as a script.
84+
Auto,
85+
86+
/// Parse as a script.
87+
Script,
88+
89+
/// Parse as a module.
90+
Module,
91+
}
92+
6893
fn main() -> Result<()> {
6994
logging::init();
7095

@@ -80,9 +105,26 @@ fn main() -> Result<()> {
80105

81106
let source = read_source(cl.source.as_ref())?;
82107

108+
// This is not a good practice, but we define a macro instead of a function in order to avoid
109+
// code clones. By using the macro, we can avoid additional `use` directives needed for the
110+
// return type.
111+
macro_rules! parse {
112+
($source:expr, $cl:expr) => {
113+
match $cl.parse_as {
114+
SourceType::Auto => match $cl.source.as_ref().and_then(|path| path.extension()) {
115+
Some(ext) if ext == "js" => runtime.parse_script($source),
116+
Some(ext) if ext == "mjs" => runtime.parse_module($source),
117+
_ => runtime.parse_script($source),
118+
},
119+
SourceType::Script => runtime.parse_script($source),
120+
SourceType::Module => runtime.parse_module($source),
121+
}
122+
};
123+
}
124+
83125
match cl.command {
84126
Command::Parse(args) => {
85-
let program = runtime.parse_script(&source)?;
127+
let program = parse!(&source, cl)?;
86128
for kind in args.print.chars() {
87129
match kind {
88130
'f' => {
@@ -99,15 +141,16 @@ fn main() -> Result<()> {
99141
}
100142
Command::Compile(args) => {
101143
runtime.enable_llvmir_labels();
102-
let program = runtime.parse_script(&source)?;
144+
let program = parse!(&source, cl)?;
103145
let module = runtime.compile(&program, !args.no_optimize)?;
104146
module.print(false); // to STDOUT
105147
}
106148
Command::Run(args) => {
107-
let program = runtime.parse_script(&source)?;
149+
let program = parse!(&source, cl)?;
108150
let module = runtime.compile(&program, !args.no_optimize)?;
109-
if let Err(v) = runtime.evaluate(module) {
110-
println!("Uncaught {v:?}");
151+
match runtime.evaluate(module) {
152+
Ok(_) => runtime.run(),
153+
Err(v) => println!("Uncaught {v:?}"),
111154
}
112155
}
113156
}

libs/jsparser/src/parser/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ GOAL_SYMBOLS := \
3535
ArrowFormalParameters \
3636
ArrowFormalParameters_Yield \
3737
ArrowFormalParameters_Await \
38-
ArrowFormalParameters_Yield_Await
39-
38+
ArrowFormalParameters_Yield_Await \
39+
AsyncArrowHead
4040

4141
# targets
4242

libs/jsparser/src/symbol/builtins.rs.njk

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,27 @@ use super::SymbolRegistry;
88

99
impl Symbol {
1010
{%- for symbol in data %}
11-
pub const {{ symbol | upper }}: Self = Self({{ loop.index0 + 1 }});
11+
{%- if symbol.startsWith('##') %}
12+
pub const HIDDEN_{{ symbol | constantCase }}: Self = Self({{ loop.index }});
13+
{%- else %}
14+
{#- Use `upper` instead of `constantCase` so that 'NaN' is converted into 'NAN'. #}
15+
pub const {{ symbol | upper }}: Self = Self({{ loop.index }});
16+
{%- endif %}
1217
{%- endfor %}
18+
19+
pub fn is_hidden(&self) -> bool {
20+
self.0 <= {{ data | select('startsWith', '##') | length }}
21+
}
1322
}
1423

1524
impl SymbolRegistry {
1625
pub(super) fn register_builtin_symbols(&mut self) {
1726
{%- for symbol in data %}
27+
{%- if symbol.startsWith('##') %}
28+
self.register_builtin_symbol(Symbol::HIDDEN_{{ symbol | constantCase }}, "{{ symbol }}");
29+
{%- else %}
1830
self.register_builtin_symbol(Symbol::{{ symbol | upper }}, "{{ symbol }}");
31+
{%- endif %}
1932
{%- endfor %}
2033
}
2134

libs/jsparser/src/symbol/builtins.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# Hidden symbols must be defined before others.
2+
# Hidden symbols must start with `##`.
3+
- '##coroutine'
4+
- '##promise'
5+
- '##result'
6+
- '##error'
7+
8+
# Reserved words defined in the ECMA-262 specification.
19
- Infinity
210
- NaN
311
- async

libs/jsparser/src/symbol/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ pub struct Symbol(u32);
1010
impl Symbol {
1111
pub const NONE: Symbol = Symbol(0);
1212

13-
#[inline]
1413
pub fn id(&self) -> u32 {
1514
self.0
1615
}

0 commit comments

Comments
 (0)