diff options
author | 2021-05-02 18:24:46 -0700 | |
---|---|---|
committer | 2021-05-02 18:24:46 -0700 | |
commit | 0b1fc176364ffefaf1770598dd3addeabfb34b42 (patch) | |
tree | b58b09c6278fde22fcd40203ed4b8454bb3e1c4b | |
parent | 26f53dbcd8859a433fcada62f3184ad2edc4a124 (diff) | |
download | bun-0b1fc176364ffefaf1770598dd3addeabfb34b42.tar.gz bun-0b1fc176364ffefaf1770598dd3addeabfb34b42.tar.zst bun-0b1fc176364ffefaf1770598dd3addeabfb34b42.zip |
wip
Former-commit-id: c8a8da370c0fce638ecaa0a333f1512375b0d250
-rw-r--r-- | src/js_parser/js_parser.zig | 177 | ||||
-rw-r--r-- | src/js_parser/js_parser_test.zig | 117 | ||||
-rw-r--r-- | src/js_printer.zig | 5 |
3 files changed, 208 insertions, 91 deletions
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 3e3cf0716..facfd1be0 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -1437,6 +1437,11 @@ const ParseStatementOptions = struct { } }; +var e_missing_data = E.Missing{}; +var s_missing = S.Empty{}; +var nullExprData = Expr.Data{ .e_missing = &e_missing_data }; +var nullStmtData = Stmt.Data{ .s_empty = &s_missing }; + // P is for Parser! // public only because of Binding.ToExpr pub const P = struct { @@ -1452,10 +1457,10 @@ pub const P = struct { latest_return_had_semicolon: bool = false, has_import_meta: bool = false, has_es_module_syntax: bool = false, - top_level_await_keyword: logger.Range, - fn_or_arrow_data_parse: FnOrArrowDataParse, - fn_or_arrow_data_visit: FnOrArrowDataVisit, - fn_only_data_visit: FnOnlyDataVisit, + top_level_await_keyword: logger.Range = logger.Range.None, + fn_or_arrow_data_parse: FnOrArrowDataParse = FnOrArrowDataParse{}, + fn_or_arrow_data_visit: FnOrArrowDataVisit = FnOrArrowDataVisit{}, + fn_only_data_visit: FnOnlyDataVisit = FnOnlyDataVisit{}, allocated_names: List(string), latest_arrow_arg_loc: logger.Loc = logger.Loc.Empty, forbid_suffix_after_as_loc: logger.Loc = logger.Loc.Empty, @@ -1471,23 +1476,20 @@ pub const P = struct { data: js_ast.AstData, - injected_define_symbols: []js_ast.Ref, + injected_define_symbols: List(Ref), symbol_uses: SymbolUseMap, declared_symbols: List(js_ast.DeclaredSymbol), runtime_imports: StringRefMap, - duplicate_case_checker: void, - non_bmp_identifiers: StringBoolMap, - legacy_octal_literals: void, + // duplicate_case_checker: void, + // non_bmp_identifiers: StringBoolMap, + // legacy_octal_literals: void, // legacy_octal_literals: map[js_ast.E]logger.Range, - // For strict mode handling - hoistedRefForSloppyModeBlockFn: void, - // For lowering private methods - weak_map_ref: ?js_ast.Ref, - weak_set_ref: ?js_ast.Ref, - private_getters: RefRefMap, - private_setters: RefRefMap, + // weak_map_ref: ?js_ast.Ref, + // weak_set_ref: ?js_ast.Ref, + // private_getters: RefRefMap, + // private_setters: RefRefMap, // These are for TypeScript should_fold_numeric_constants: bool = false, @@ -1751,7 +1753,7 @@ pub const P = struct { } pub fn findSymbol(p: *P, loc: logger.Loc, name: string) !FindSymbolResult { - var ref: Ref = undefined; + var ref: Ref = Ref{}; var declare_loc: logger.Loc = undefined; var is_inside_with_scope = false; var did_forbid_argumen = false; @@ -1856,7 +1858,7 @@ pub const P = struct { // code regions since those will be culled. if (!p.is_control_flow_dead) { p.symbols.items[ref.inner_index].use_count_estimate += 1; - var use = p.symbol_uses.get(ref.*) orelse unreachable; + var use = p.symbol_uses.get(ref.*) orelse Symbol.Use{}; use.count_estimate += 1; p.symbol_uses.put(ref.*, use) catch unreachable; } @@ -2283,15 +2285,15 @@ pub const P = struct { // This assumes the "function" token has already been parsed pub fn parseFnStmt(p: *P, loc: logger.Loc, opts: *ParseStatementOptions, asyncRange: ?logger.Range) !Stmt { - const isGenerator = p.lexer.token == T.t_asterisk; - const isAsync = asyncRange != null; - - // if isGenerator { - // p.markSyntaxFeature(compat.Generator, p.lexer.Range()) - // p.lexer.Next() - // } else if isAsync { - // p.markLoweredSyntaxFeature(compat.AsyncAwait, asyncRange, compat.Generator) - // } + const is_generator = p.lexer.token == T.t_asterisk; + const is_async = asyncRange != null; + + if (is_generator) { + // p.markSyntaxFeature(compat.Generator, p.lexer.Range()) + p.lexer.next(); + } else if (is_async) { + // p.markLoweredSyntaxFeature(compat.AsyncAwait, asyncRange, compat.Generator) + } switch (opts.lexical_decl) { .forbid => { @@ -2300,7 +2302,7 @@ pub const P = struct { // Allow certain function statements in certain single-statement contexts .allow_fn_inside_if, .allow_fn_inside_label => { - if (opts.is_typescript_declare or isGenerator or isAsync) { + if (opts.is_typescript_declare or is_generator or is_async) { try p.forbidLexicalDecl(loc); } }, @@ -2338,8 +2340,8 @@ pub const P = struct { var scopeIndex = try p.pushScopeForParsePass(js_ast.Scope.Kind.function_args, p.lexer.loc()); var func = p.parseFn(name, FnOrArrowDataParse{ .async_range = asyncRange, - .allow_await = if (isAsync) AwaitOrYield.allow_expr else AwaitOrYield.allow_ident, - .allow_yield = if (isGenerator) AwaitOrYield.allow_expr else AwaitOrYield.allow_ident, + .allow_await = if (is_async) AwaitOrYield.allow_expr else AwaitOrYield.allow_ident, + .allow_yield = if (is_generator) AwaitOrYield.allow_expr else AwaitOrYield.allow_ident, .is_typescript_declare = opts.is_typescript_declare, // Only allow omitting the body if we're parsing TypeScript @@ -2371,7 +2373,7 @@ pub const P = struct { // function foo(): void {} // if (name) |*name_| { - const kind = if (isGenerator or isAsync) Symbol.Kind.generator_or_async_function else Symbol.Kind.hoisted_function; + const kind = if (is_generator or is_async) Symbol.Kind.generator_or_async_function else Symbol.Kind.hoisted_function; name_.ref = try p.declareSymbol(kind, name_.loc, nameText); } func.name = name; @@ -2861,7 +2863,8 @@ pub const P = struct { defaultName = try createDefaultName(p, loc); - var expr = p.parseSuffix(try p.parseAsyncPrefixExpr(async_range, Level.comma), Level.comma, null, Expr.EFlags.none); + const prefix_expr = try p.parseAsyncPrefixExpr(async_range, Level.comma); + var expr = p.parseSuffix(prefix_expr, Level.comma, null, Expr.EFlags.none); p.lexer.expectOrInsertSemicolon(); // this is probably a panic var value = js_ast.StmtOrExpr{ .expr = expr }; @@ -6576,7 +6579,7 @@ pub const P = struct { return p.e(E.Await{ .value = value }, loc); } }, - .allow_ident => {}, + else => {}, } }, @@ -6605,7 +6608,10 @@ pub const P = struct { return p.e(E.Yield{ .value = value }, loc); } }, - .allow_ident => { + // .allow_ident => { + + // }, + else => { // Try to gracefully recover if "yield" is used in the wrong place if (!p.lexer.has_newline_before) { switch (p.lexer.token) { @@ -7314,10 +7320,12 @@ pub const P = struct { p.fn_only_data_visit = FnOnlyDataVisit{ .is_this_nested = true, .arguments_ref = func.arguments_ref }; if (func.name) |name| { - p.recordDeclaredSymbol(name.ref.?) catch unreachable; - const symbol_name = p.symbols.items[name.ref.?.inner_index].original_name; - if (isEvalOrArguments(symbol_name)) { - p.markStrictModeFeature(.eval_or_arguments, js_lexer.rangeOfIdentifier(&p.source, name.loc), symbol_name) catch unreachable; + if (name.ref) |name_ref| { + p.recordDeclaredSymbol(name_ref) catch unreachable; + const symbol_name = p.symbols.items[name_ref.inner_index].original_name; + if (isEvalOrArguments(symbol_name)) { + p.markStrictModeFeature(.eval_or_arguments, js_lexer.rangeOfIdentifier(&p.source, name.loc), symbol_name) catch unreachable; + } } } @@ -8743,7 +8751,9 @@ pub const P = struct { } }, .s_export_default => |data| { - try p.recordDeclaredSymbol(data.default_name.ref orelse unreachable); + if (data.default_name.ref) |ref| { + try p.recordDeclaredSymbol(ref); + } switch (data.value) { .expr => |*expr| { @@ -8785,9 +8795,8 @@ pub const P = struct { p.visitFunc(&func.func, func.func.open_parens_loc); stmts.append(stmt.*) catch unreachable; - if (func.func.name) |name_ref| { - // TODO-REACT-REFRESH-SPOT - stmts.append(p.keepStmtSymbolName(name_ref.loc, name_ref.ref.?, name)) catch unreachable; + if (func.func.name != null and func.func.name.?.ref != null) { + stmts.append(p.keepStmtSymbolName(func.func.name.?.loc, func.func.name.?.ref.?, name)) catch unreachable; } }, .s_class => |class| { @@ -10212,42 +10221,56 @@ pub const P = struct { } pub fn init(allocator: *std.mem.Allocator, log: *logger.Log, source: logger.Source, define: *Define, lexer: js_lexer.Lexer, opts: Parser.Options) !*P { - var parser = try allocator.create(P); - parser.allocated_names = @TypeOf(parser.allocated_names).init(allocator); - parser.define = define; - parser.scopes_for_current_part = @TypeOf(parser.scopes_for_current_part).init(allocator); - parser.symbols = @TypeOf(parser.symbols).init(allocator); - parser.ts_use_counts = @TypeOf(parser.ts_use_counts).init(allocator); - parser.declared_symbols = @TypeOf(parser.declared_symbols).init(allocator); - parser.known_enum_values = @TypeOf(parser.known_enum_values).init(allocator); - parser.import_records = @TypeOf(parser.import_records).init(allocator); - parser.import_records_for_current_part = @TypeOf(parser.import_records_for_current_part).init(allocator); - parser.export_star_import_records = @TypeOf(parser.export_star_import_records).init(allocator); - parser.import_items_for_namespace = @TypeOf(parser.import_items_for_namespace).init(allocator); - parser.named_imports = @TypeOf(parser.named_imports).init(allocator); - parser.named_exports = @TypeOf(parser.named_exports).init(allocator); - parser.top_level_symbol_to_parts = @TypeOf(parser.top_level_symbol_to_parts).init(allocator); - parser.import_namespace_cc_map = @TypeOf(parser.import_namespace_cc_map).init(allocator); - parser.scopes_in_order = @TypeOf(parser.scopes_in_order).init(allocator); - parser.temp_refs_to_declare = @TypeOf(parser.temp_refs_to_declare).init(allocator); - parser.relocated_top_level_vars = @TypeOf(parser.relocated_top_level_vars).init(allocator); - parser.log = log; - parser.is_import_item = @TypeOf(parser.is_import_item).init(allocator); - parser.allocator = allocator; - parser.runtime_imports = StringRefMap.init(allocator); - parser.options = opts; - parser.to_expr_wrapper_namespace = Binding2ExprWrapper.Namespace.init(parser); - parser.to_expr_wrapper_hoisted = Binding2ExprWrapper.Hoisted.init(parser); - parser.source = source; - parser.import_transposer = @TypeOf(parser.import_transposer).init(parser); - parser.require_transposer = @TypeOf(parser.require_transposer).init(parser); - parser.require_resolve_transposer = @TypeOf(parser.require_resolve_transposer).init(parser); - parser.lexer = lexer; - parser.data = js_ast.AstData.init(allocator); - - _ = try parser.pushScopeForParsePass(.entry, locModuleScope); - - return parser; + var _parser = try allocator.create(P); + var parser = P{ + .symbol_uses = SymbolUseMap.init(allocator), + .call_target = nullExprData, + .delete_target = nullExprData, + .stmt_expr_value = nullExprData, + .loop_body = nullStmtData, + .injected_define_symbols = @TypeOf(_parser.injected_define_symbols).init(allocator), + .emitted_namespace_vars = @TypeOf(_parser.emitted_namespace_vars).init(allocator), + .is_exported_inside_namespace = @TypeOf(_parser.is_exported_inside_namespace).init(allocator), + .known_enum_values = @TypeOf(_parser.known_enum_values).init(allocator), + .local_type_names = @TypeOf(_parser.local_type_names).init(allocator), + .allocated_names = @TypeOf(_parser.allocated_names).init(allocator), + .define = define, + .scopes_for_current_part = @TypeOf(_parser.scopes_for_current_part).init(allocator), + .symbols = @TypeOf(_parser.symbols).init(allocator), + .ts_use_counts = @TypeOf(_parser.ts_use_counts).init(allocator), + .declared_symbols = @TypeOf(_parser.declared_symbols).init(allocator), + .import_records = @TypeOf(_parser.import_records).init(allocator), + .import_records_for_current_part = @TypeOf(_parser.import_records_for_current_part).init(allocator), + .export_star_import_records = @TypeOf(_parser.export_star_import_records).init(allocator), + .import_items_for_namespace = @TypeOf(_parser.import_items_for_namespace).init(allocator), + .named_imports = @TypeOf(_parser.named_imports).init(allocator), + .named_exports = @TypeOf(_parser.named_exports).init(allocator), + .top_level_symbol_to_parts = @TypeOf(_parser.top_level_symbol_to_parts).init(allocator), + .import_namespace_cc_map = @TypeOf(_parser.import_namespace_cc_map).init(allocator), + .scopes_in_order = @TypeOf(_parser.scopes_in_order).init(allocator), + .temp_refs_to_declare = @TypeOf(_parser.temp_refs_to_declare).init(allocator), + .relocated_top_level_vars = @TypeOf(_parser.relocated_top_level_vars).init(allocator), + .log = log, + .is_import_item = @TypeOf(_parser.is_import_item).init(allocator), + .allocator = allocator, + .runtime_imports = StringRefMap.init(allocator), + .options = opts, + .then_catch_chain = ThenCatchChain{ .next_target = nullExprData }, + .to_expr_wrapper_namespace = Binding2ExprWrapper.Namespace.init(_parser), + .to_expr_wrapper_hoisted = Binding2ExprWrapper.Hoisted.init(_parser), + .source = source, + .import_transposer = @TypeOf(_parser.import_transposer).init(_parser), + .require_transposer = @TypeOf(_parser.require_transposer).init(_parser), + .require_resolve_transposer = @TypeOf(_parser.require_resolve_transposer).init(_parser), + .lexer = lexer, + .data = js_ast.AstData.init(allocator), + }; + + _parser.* = parser; + + _ = try _parser.pushScopeForParsePass(.entry, locModuleScope); + + return _parser; } }; diff --git a/src/js_parser/js_parser_test.zig b/src/js_parser/js_parser_test.zig index 5760e331b..b89612e5f 100644 --- a/src/js_parser/js_parser_test.zig +++ b/src/js_parser/js_parser_test.zig @@ -448,6 +448,74 @@ test "expectPrint" { try expectPrinted(t, "class Foo extends Bar { constructor(x = super()) {} }", "class Foo extends Bar {\n constructor(x = super()) {\n }\n}\n", @src()); try expectPrinted(t, "class Foo extends Bar { constructor(x = () => super()) {} }", "class Foo extends Bar {\n constructor(x = () => super()) {\n }\n}\n", @src()); + try expectPrinted(t, "class Foo { a }", "class Foo {\n a;\n}\n", @src()); + try expectPrinted(t, "class Foo { a = 1 }", "class Foo {\n a = 1;\n}\n", @src()); + try expectPrinted(t, "class Foo { static a }", "class Foo {\n static a;\n}\n", @src()); + try expectPrinted(t, "class Foo { static a = 1 }", "class Foo {\n static a = 1;\n}\n", @src()); + try expectPrinted(t, "class Foo { static a = 1; b }", "class Foo {\n static a = 1;\n b;\n}\n", @src()); + try expectPrinted(t, "class Foo { static [a] }", "class Foo {\n static [a];\n}\n", @src()); + try expectPrinted(t, "class Foo { static [a] = 1 }", "class Foo {\n static [a] = 1;\n}\n", @src()); + try expectPrinted(t, "class Foo { static [a] = 1; [b] }", "class Foo {\n static [a] = 1;\n [b];\n}\n", @src()); + + try expectPrinted(t, "class Foo { prototype }", "class Foo {\n prototype;\n}\n", @src()); + try expectPrinted(t, "class Foo { 'prototype' }", "class Foo {\n prototype;\n}\n", @src()); + try expectPrinted(t, "class Foo { prototype = 1 }", "class Foo {\n prototype = 1;\n}\n", @src()); + try expectPrinted(t, "class Foo { 'prototype' = 1 }", "class Foo {\n prototype = 1;\n}\n", @src()); + try expectPrinted(t, "function* foo() { -(yield 100) }", "function* foo() {\n -(yield 100);\n}\n", @src()); + + try expectPrinted(t, "function *foo() { (x = yield y) }", "function* foo() {\n x = yield y;\n}\n", @src()); + try expectPrinted(t, "yield\n100", "yield;\n100;\n", @src()); + try expectPrinted(t, "let x = {yield}", "let x = {yield};\n", @src()); + try expectPrinted(t, "function foo() { ({yield} = x) }", "function foo() {\n ({yield} = x);\n}\n", @src()); + try expectPrinted(t, "({ *yield() {} })", "({*yield() {\n}});\n", @src()); + try expectPrinted(t, "(class { *yield() {} })", "(class {\n *yield() {\n }\n});\n", @src()); + try expectPrinted(t, "class Foo { *yield() {} }", "class Foo {\n *yield() {\n }\n}\n", @src()); + try expectPrinted(t, "function* yield() {}", "function* yield() {\n}\n", @src()); + try expectPrinted(t, "({ async *yield() {} })", "({async *yield() {\n}});\n", @src()); + try expectPrinted(t, "(class { async *yield() {} })", "(class {\n async *yield() {\n }\n});\n", @src()); + try expectPrinted(t, "class Foo { async *yield() {} }", "class Foo {\n async *yield() {\n }\n}\n", @src()); + try expectPrinted(t, "async function* yield() {}", "async function* yield() {\n}\n", @src()); + try expectPrinted(t, "-async function foo() { await 0 }", "-async function foo() {\n await 0;\n};\n", @src()); + try expectPrinted(t, "-async function() { await 0 }", "-async function() {\n await 0;\n};\n", @src()); + try expectPrinted(t, "1 - async function foo() { await 0 }", "1 - async function foo() {\n await 0;\n};\n", @src()); + try expectPrinted(t, "1 - async function() { await 0 }", "1 - async function() {\n await 0;\n};\n", @src()); + try expectPrinted(t, "(async function foo() { await 0 })", "(async function foo() {\n await 0;\n});\n", @src()); + try expectPrinted(t, "(async function() { await 0 })", "(async function() {\n await 0;\n});\n", @src()); + try expectPrinted(t, "(x, async function foo() { await 0 })", "x, async function foo() {\n await 0;\n};\n", @src()); + try expectPrinted(t, "(x, async function() { await 0 })", "x, async function() {\n await 0;\n};\n", @src()); + try expectPrinted(t, "new async function() { await 0 }", "new async function() {\n await 0;\n}();\n", @src()); + try expectPrinted(t, "new async function() { await 0 }.x", "new async function() {\n await 0;\n}.x();\n", @src()); + + try expectPrinted(t, "function foo() { await }", "function foo() {\n await;\n}\n", @src()); + try expectPrinted(t, "async function foo() { await 0 }", "async function foo() {\n await 0;\n}\n", @src()); + + try expectPrinted(t, "(async x => y), z", "async (x) => y, z;\n", @src()); + try expectPrinted(t, "(async x => y, z)", "async (x) => y, z;\n", @src()); + try expectPrinted(t, "(async x => (y, z))", "async (x) => (y, z);\n", @src()); + try expectPrinted(t, "(async (x) => y), z", "async (x) => y, z;\n", @src()); + try expectPrinted(t, "(async (x) => y, z)", "async (x) => y, z;\n", @src()); + try expectPrinted(t, "(async (x) => (y, z))", "async (x) => (y, z);\n", @src()); + try expectPrinted(t, "async x => y, z", "async (x) => y, z;\n", @src()); + try expectPrinted(t, "async x => (y, z)", "async (x) => (y, z);\n", @src()); + try expectPrinted(t, "async (x) => y, z", "async (x) => y, z;\n", @src()); + try expectPrinted(t, "async (x) => (y, z)", "async (x) => (y, z);\n", @src()); + try expectPrinted(t, "export default async x => (y, z)", "export default async (x) => (y, z);\n", @src()); + try expectPrinted(t, "export default async (x) => (y, z)", "export default async (x) => (y, z);\n", @src()); + + try expectPrinted(t, "(class { async \n foo() {} })", "(class {\n async;\n foo() {\n }\n});\n", @src()); + try expectPrinted(t, "(class { async \n *foo() {} })", "(class {\n async;\n *foo() {\n }\n});\n", @src()); + try expectPrinted(t, "async function foo(){for await(x of y);}", "async function foo() {\n for await (x of y)\n ;\n}\n", @src()); + try expectPrinted(t, "async function foo(){for await(let x of y);}", "async function foo() {\n for await (let x of y)\n ;\n}\n", @src()); + + // Await as a declaration + try expectPrinted(t, "({ async await() {} })", "({async await() {\n}});\n", @src()); + try expectPrinted(t, "(class { async await() {} })", "(class {\n async await() {\n }\n});\n", @src()); + try expectPrinted(t, "class Foo { async await() {} }", "class Foo {\n async await() {\n }\n}\n", @src()); + + try expectPrinted(t, "({ async *await() {} })", "({async *await() {\n}});\n", @src()); + try expectPrinted(t, "(class { async *await() {} })", "(class {\n async *await() {\n }\n});\n", @src()); + try expectPrinted(t, "class Foo { async *await() {} }", "class Foo {\n async *await() {\n }\n}\n", @src()); + try expectPrinted(t, "(x) => function() {}", "(x) => function() {\n};\n", @src()); try expectPrinted(t, "x => function() {}", "(x) => function() {\n};\n", @src()); @@ -564,19 +632,40 @@ test "expectPrint" { try expectPrinted(t, "({get if() {}})", "({get if() {\n}});\n", @src()); try expectPrinted(t, "({set if(x) {}})", "({set if(x) {\n}});\n", @src()); - try expectPrinted(t, "await x", "await x;\n", @src()); - try expectPrinted(t, "await +x", "await +x;\n", @src()); - try expectPrinted(t, "await -x", "await -x;\n", @src()); - try expectPrinted(t, "await ~x", "await ~x;\n", @src()); - try expectPrinted(t, "await !x", "await !x;\n", @src()); - try expectPrinted(t, "await --x", "await --x;\n", @src()); - try expectPrinted(t, "await ++x", "await ++x;\n", @src()); - try expectPrinted(t, "await x--", "await x--;\n", @src()); - try expectPrinted(t, "await x++", "await x++;\n", @src()); - try expectPrinted(t, "await void x", "await void x;\n", @src()); - try expectPrinted(t, "await typeof x", "await typeof x;\n", @src()); - try expectPrinted(t, "await (x * y)", "await (x * y);\n", @src()); - try expectPrinted(t, "await (x ** y)", "await (x ** y);\n", @src()); - + try expectPrinted(t, "async function foo() { await x; }", "await x;\n", @src()); + try expectPrinted(t, "async function foo() { await +x; }", "await +x;\n", @src()); + try expectPrinted(t, "async function foo() { await -x; }", "await -x;\n", @src()); + try expectPrinted(t, "async function foo() { await ~x; }", "await ~x;\n", @src()); + try expectPrinted(t, "async function foo() { await !x; }", "await !x;\n", @src()); + try expectPrinted(t, "async function foo() { await --x; }", "await --x;\n", @src()); + try expectPrinted(t, "async function foo() { await ++x; }", "await ++x;\n", @src()); + try expectPrinted(t, "async function foo() { await x--; }", "await x--;\n", @src()); + try expectPrinted(t, "async function foo() { await x++; }", "await x++;\n", @src()); + try expectPrinted(t, "async function foo() { await void x; }", "await void x;\n", @src()); + try expectPrinted(t, "async function foo() { await typeof x; }", "await typeof x;\n", @src()); + try expectPrinted(t, "async function foo() { await (x * y); }", "await (x * y);\n", @src()); + try expectPrinted(t, "async function foo() { await (x ** y); }", "await (x ** y);\n", @src()); + + try expectPrinted(t, "export default (1, 2)", "export default (1, 2);\n", @src()); + try expectPrinted(t, "export default async", "export default async;\n", @src()); + try expectPrinted(t, "export default async()", "export default async();\n", @src()); + try expectPrinted(t, "export default async + 1", "export default async + 1;\n", @src()); + try expectPrinted(t, "export default async => {}", "export default (async) => {\n};\n", @src()); + try expectPrinted(t, "export default async x => {}", "export default async (x) => {\n};\n", @src()); + try expectPrinted(t, "export default async () => {}", "export default async () => {\n};\n", @src()); + + // This is a corner case in the ES6 grammar. The "export default" statement + // normally takes an expression except for the function and class keywords + // which behave sort of like their respective declarations instead. + try expectPrinted(t, "export default function() {} - after", "export default function() {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default function*() {} - after", "export default function* () {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default function foo() {} - after", "export default function foo() {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default function* foo() {} - after", "export default function* foo() {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default async function() {} - after", "export default async function() {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default async function*() {} - after", "export default async function* () {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default async function foo() {} - after", "export default async function foo() {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default async function* foo() {} - after", "export default async function* foo() {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default class {} - after", "export default class {\n}\n-after;\n", @src()); + try expectPrinted(t, "export default class Foo {} - after", "export default class Foo {\n}\n-after;\n", @src()); t.report(@src()); } diff --git a/src/js_printer.zig b/src/js_printer.zig index a62246a56..864df661d 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -1492,6 +1492,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type { } } + if (wrap) { + p.print("("); + flags.forbid_in = true; + } + var left_level = entry.level.sub(1); var right_level = left_level; |