diff options
author | 2021-05-02 16:25:14 -0700 | |
---|---|---|
committer | 2021-05-02 16:25:14 -0700 | |
commit | 320e0460e096a15a58df154bdfa66c9c68ee0b00 (patch) | |
tree | b11f5c371c60c8da6db35c015e1e300dacbf31ff | |
parent | 97cb54de2e2990f4ba41f7b68c2b5113e40f2c2e (diff) | |
download | bun-320e0460e096a15a58df154bdfa66c9c68ee0b00.tar.gz bun-320e0460e096a15a58df154bdfa66c9c68ee0b00.tar.zst bun-320e0460e096a15a58df154bdfa66c9c68ee0b00.zip |
various
Former-commit-id: 8db9c7650ce699cf34eb5495037f823f760cd57a
-rw-r--r-- | .vscode/launch.json | 11 | ||||
-rw-r--r-- | .vscode/tasks.json | 12 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 124 | ||||
-rw-r--r-- | src/js_parser/js_parser_test.zig | 177 | ||||
-rw-r--r-- | src/js_printer.zig | 11 |
5 files changed, 239 insertions, 96 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index e1661ff88..ec36642d7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,15 @@ { "version": "0.2.0", "configurations": [ - + { + "type": "lldb", + "request": "launch", + "name": "Launch", + "program": "${workspaceFolder}/zig-cache/bin/test", + "preLaunchTask": "test", + "args": ["/usr/local/bin/zig"], + "cwd": "${workspaceFolder}", + "console": "internalConsole" + } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 93ad44cdc..41b6c24e7 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -23,9 +23,17 @@ }, { "label": "test", - "type": "process", + "type": "shell", "command": "zig", - "args": ["test", "${file}", "--main-pkg-path", "${workspaceFolder}"], + "args": [ + "test", + "${file}", + "--main-pkg-path", + "${workspaceFolder}", + "-femit-bin=${workspaceFolder}/zig-cache/bin/test", + ";", + "true" + ], "group": { "kind": "test", diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 07a9f037f..3e3cf0716 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -1430,6 +1430,11 @@ const ParseStatementOptions = struct { is_export: bool = false, is_name_optional: bool = false, // For "export default" pseudo-statements, is_typescript_declare: bool = false, + + pub fn hasNoDecorators(self: *ParseStatementOptions) bool { + const decs = self.ts_decorators orelse return false; + return decs.values.len > 0; + } }; // P is for Parser! @@ -2163,18 +2168,15 @@ pub const P = struct { // p.markSyntaxFeature(Destructing) var items = List(js_ast.ArrayBinding).init(p.allocator); - for (items.items) |item| { - var is_spread = true; - switch (item.default_value.?.data) { - .e_identifier => {}, - else => { - // nested rest binding - // p.markSyntaxFeature(compat.NestedRestBinding, p.source.RangeOfOperatorAfter(item.Loc, "[")) - }, - } + var is_spread = true; + for (ex.items) |_, i| { + var item = ex.items[i]; var _expr = expr; + if (@as(Expr.Tag, item.data) == .e_spread) { + is_spread = true; + item = item.data.e_spread.value; + } const res = p.convertExprToBindingAndInitializer(&_expr, invalid_loc, is_spread); - assert(res.binding != null); items.append(js_ast.ArrayBinding{ .binding = res.binding orelse unreachable, .default_value = res.override_expr }) catch unreachable; } @@ -3729,11 +3731,10 @@ pub const P = struct { }, } } - if (is_identifier) { switch (expr.data) { .e_identifier => |ident| { - if (p.lexer.token == .t_colon and opts.ts_decorators == null) { + if (p.lexer.token == .t_colon and opts.hasNoDecorators()) { _ = try p.pushScopeForParsePass(.label, loc); defer p.popScope(); @@ -3872,7 +3873,7 @@ pub const P = struct { } } } - + std.debug.print("\n\nmVALUE {s}:{s}\n", .{ expr, name }); p.lexer.expectOrInsertSemicolon(); return p.s(S.SExpr{ .value = expr }, loc); }, @@ -4025,8 +4026,8 @@ pub const P = struct { pub fn parseExprOrLetStmt(p: *P, opts: *ParseStatementOptions) !ExprOrLetStmt { var let_range = p.lexer.range(); var raw = p.lexer.raw(); - if (p.lexer.token != .t_identifier or !strings.eql(raw, "let")) { + std.debug.print("HI", .{}); return ExprOrLetStmt{ .stmt_or_expr = js_ast.StmtOrExpr{ .expr = p.parseExpr(.lowest) } }; } @@ -4057,7 +4058,7 @@ pub const P = struct { const ref = p.storeNameInRef(raw) catch unreachable; const expr = p.e(E.Identifier{ .ref = ref }, let_range.loc); - return ExprOrLetStmt{ .stmt_or_expr = js_ast.StmtOrExpr{ .expr = p.parseExpr(.lowest) } }; + return ExprOrLetStmt{ .stmt_or_expr = js_ast.StmtOrExpr{ .expr = p.parseSuffix(expr, .lowest, null, Expr.EFlags.none) } }; } pub fn requireInitializers(p: *P, decls: []G.Decl) !void { @@ -4783,7 +4784,9 @@ pub const P = struct { try p.declareBinding(Symbol.Kind.hoisted, arg.binding, &opts); } + // The ability to call "super()" is inherited by arrow functions data.allow_super_call = p.fn_or_arrow_data_parse.allow_super_call; + if (p.lexer.token == .t_open_brace) { var body = try p.parseFnBody(data); p.after_arrow_body_loc = p.lexer.loc(); @@ -4794,10 +4797,11 @@ pub const P = struct { defer p.popScope(); var old_fn_or_arrow_data = p.fn_or_arrow_data_parse; - p.fn_or_arrow_data_parse = data.*; + p.fn_or_arrow_data_parse = data.*; var expr = p.parseExpr(Level.comma); p.fn_or_arrow_data_parse = old_fn_or_arrow_data; + var stmts = try p.allocator.alloc(Stmt, 1); stmts[0] = p.s(S.Return{ .value = expr }, arrow_loc); @@ -4901,7 +4905,8 @@ pub const P = struct { // "async => {}" .t_equals_greater_than => { if (level.lte(.assign)) { - const arg = G.Arg{ .binding = p.b( + var args = try p.allocator.alloc(G.Arg, 1); + args[0] = G.Arg{ .binding = p.b( B.Identifier{ .ref = try p.storeNameInRef("async"), }, @@ -4909,7 +4914,8 @@ pub const P = struct { ) }; _ = p.pushScopeForParsePass(.function_args, async_range.loc) catch unreachable; defer p.popScope(); - var arrow_body = try p.parseArrowBodySingleArg(arg, FnOrArrowDataParse{}); + var data = FnOrArrowDataParse{}; + var arrow_body = try p.parseArrowBody(args, &data); return p.e(arrow_body, async_range.loc); } }, @@ -4918,17 +4924,22 @@ pub const P = struct { if (level.lte(.assign)) { // p.markLoweredSyntaxFeature(); const ref = try p.storeNameInRef(p.lexer.identifier); - var arg = G.Arg{ .binding = p.b(B.Identifier{ - .ref = ref, - }, p.lexer.loc()) }; + var args = try p.allocator.alloc(G.Arg, 1); + args[0] = G.Arg{ .binding = p.b( + B.Identifier{ + .ref = ref, + }, + async_range.loc, + ) }; p.lexer.next(); _ = try p.pushScopeForParsePass(.function_args, async_range.loc); defer p.popScope(); - var arrowBody = try p.parseArrowBodySingleArg(arg, FnOrArrowDataParse{ + var data = FnOrArrowDataParse{ .allow_await = .allow_expr, - }); + }; + var arrowBody = try p.parseArrowBody(args, &data); arrowBody.is_async = true; return p.e(arrowBody, async_range.loc); } @@ -4938,7 +4949,7 @@ pub const P = struct { // "async () => {}" .t_open_paren => { p.lexer.next(); - return p.parseParenExpr(async_range.loc, ParenExprOpts{ .is_async = true, .async_range = async_range }); + return p.parseParenExpr(async_range.loc, level, ParenExprOpts{ .is_async = true, .async_range = async_range }); }, // "async<T>()" @@ -4946,7 +4957,7 @@ pub const P = struct { .t_less_than => { if (p.options.ts and p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking()) { p.lexer.next(); - return p.parseParenExpr(async_range.loc, ParenExprOpts{ .is_async = true, .async_range = async_range }); + return p.parseParenExpr(async_range.loc, level, ParenExprOpts{ .is_async = true, .async_range = async_range }); } }, @@ -5736,7 +5747,7 @@ pub const P = struct { // treat "c.d" as OptionalChainContinue in "a?.b + c.d". var old_optional_chain = optional_chain; optional_chain = null; - + std.debug.print("\nTOKEN {s}", .{p.lexer.token}); switch (p.lexer.token) { .t_dot => { p.lexer.next(); @@ -6507,7 +6518,7 @@ pub const P = struct { return value; } - return p.parseParenExpr(loc, ParenExprOpts{}) catch unreachable; + return p.parseParenExpr(loc, level, ParenExprOpts{}) catch unreachable; }, .t_false => { p.lexer.next(); @@ -6529,12 +6540,13 @@ pub const P = struct { const name = p.lexer.identifier; const name_range = p.lexer.range(); const raw = p.lexer.raw(); + p.lexer.next(); // Handle async and await expressions switch (AsyncPrefixExpression.find(name)) { .is_async => { - if (AsyncPrefixExpression.find(raw) != .is_async) { + if ((raw.ptr == name.ptr and raw.len == name.len) or AsyncPrefixExpression.find(raw) == .is_async) { return p.parseAsyncPrefixExpr(name_range, level) catch unreachable; } }, @@ -6610,7 +6622,7 @@ pub const P = struct { } // Handle the start of an arrow expression - if (p.lexer.token == .t_equals_greater_than) { + if (p.lexer.token == .t_equals_greater_than and level.lte(.assign)) { const ref = p.storeNameInRef(name) catch unreachable; var args = p.allocator.alloc(Arg, 1) catch unreachable; args[0] = Arg{ .binding = p.b(B.Identifier{ @@ -6619,6 +6631,7 @@ pub const P = struct { _ = p.pushScopeForParsePass(.function_args, loc) catch unreachable; defer p.popScope(); + std.debug.print("HANDLE START ", .{}); return p.e(p.parseArrowBody(args, p.m(FnOrArrowDataParse{})) catch unreachable, loc); } @@ -6990,7 +7003,7 @@ pub const P = struct { if (is_ts_arrow_fn) { p.skipTypescriptTypeParameters(); p.lexer.expect(.t_open_paren); - return p.parseParenExpr(loc, ParenExprOpts{ .force_arrow_fn = true }) catch unreachable; + return p.parseParenExpr(loc, level, ParenExprOpts{ .force_arrow_fn = true }) catch unreachable; } } @@ -9842,13 +9855,13 @@ pub const P = struct { } // This assumes that the open parenthesis has already been parsed by the caller - pub fn parseParenExpr(p: *P, loc: logger.Loc, opts: ParenExprOpts) !Expr { - var items_list = try List(Expr).initCapacity(p.allocator, 1); + pub fn parseParenExpr(p: *P, loc: logger.Loc, level: Level, opts: ParenExprOpts) !Expr { + var items_list = List(Expr).init(p.allocator); var errors = DeferredErrors{}; var arrowArgErrors = DeferredArrowArgErrors{}; var spread_range = logger.Range{}; var type_colon_range = logger.Range{}; - var comma_after_spread = logger.Loc{}; + var comma_after_spread: ?logger.Loc = null; // Push a scope assuming this is an arrow function. It may not be, in which // case we'll need to roll this change back. This has to be done ahead of @@ -9894,6 +9907,7 @@ pub const P = struct { p.skipTypescriptType(.lowest); } + // There may be a "=" after the type (but not after an "as" cast) if (p.options.ts and p.lexer.token == .t_equals and !p.forbid_suffix_after_as_loc.eql(p.lexer.loc())) { p.lexer.next(); item = Expr.assign(item, p.parseExpr(.comma), p.allocator); @@ -9926,6 +9940,11 @@ pub const P = struct { // Are these arguments to an arrow function? if (p.lexer.token == .t_equals_greater_than or opts.force_arrow_fn or (p.options.ts and p.lexer.token == .t_colon)) { + // Arrow functions are not allowed inside certain expressions + if (level.gt(.assign)) { + p.lexer.unexpected(); + } + var invalidLog = List(logger.Loc).init(p.allocator); var args = List(G.Arg).init(p.allocator); @@ -9934,22 +9953,21 @@ pub const P = struct { } // First, try converting the expressions to bindings - for (items) |*_item| { - var item = _item; + var i: usize = 0; + while (i < items.len) : (i += 1) { var is_spread = false; - switch (item.data) { + switch (items[i].data) { .e_spread => |v| { is_spread = true; - item = &v.value; + items[i] = v.value; }, else => {}, } - const tuple = p.convertExprToBindingAndInitializer(item, &invalidLog, is_spread); - assert(tuple.binding != null); + const tuple = p.convertExprToBindingAndInitializer(&items[i], &invalidLog, is_spread); // double allocations args.append(G.Arg{ - .binding = tuple.binding orelse unreachable, + .binding = tuple.binding orelse p.b(B.Missing{}, items[i].loc), .default = tuple.expr, }) catch unreachable; } @@ -9959,9 +9977,25 @@ pub const P = struct { // attempt to convert the expressions to bindings first before deciding // whether this is an arrow function, and only pick an arrow function if // there were no conversion errors. - if (p.lexer.token == .t_equals_greater_than or (invalidLog.items.len == 0 and (p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking() or opts.force_arrow_fn))) { + if (p.lexer.token == .t_equals_greater_than or (invalidLog.items.len == 0 and p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking()) or opts.force_arrow_fn) { p.maybeCommaSpreadError(comma_after_spread); p.logArrowArgErrors(&arrowArgErrors); + + // Now that we've decided we're an arrow function, report binding pattern + // conversion errors + if (invalidLog.items.len > 0) { + for (invalidLog.items) |_loc| { + try p.log.addError(p.source, _loc, "Invalid binding pattern"); + } + } + var arrow_data = FnOrArrowDataParse{ + .allow_await = if (opts.is_async) AwaitOrYield.allow_expr else AwaitOrYield.allow_ident, + }; + var arrow = try p.parseArrowBody(args.items, &arrow_data); + arrow.is_async = opts.is_async; + arrow.has_rest_arg = spread_range.len > 0; + p.popScope(); + return p.e(arrow, loc); } } @@ -9984,7 +10018,6 @@ pub const P = struct { } // Is this a chain of expressions and comma operators? - if (items.len > 0) { p.logExprErrors(&errors); if (spread_range.len > 0) { @@ -10029,9 +10062,10 @@ pub const P = struct { } pub fn maybeCommaSpreadError(p: *P, _comma_after_spread: ?logger.Loc) void { - if (_comma_after_spread) |comma_after_spread| { - p.log.addRangeError(p.source, logger.Range{ .loc = comma_after_spread, .len = 1 }, "Unexpected \",\" after rest pattern") catch unreachable; - } + const comma_after_spread = _comma_after_spread orelse return; + if (comma_after_spread.start == -1) return; + + p.log.addRangeError(p.source, logger.Range{ .loc = comma_after_spread, .len = 1 }, "Unexpected \",\" after rest pattern") catch unreachable; } pub fn toAST(p: *P, _parts: []js_ast.Part) !js_ast.Ast { diff --git a/src/js_parser/js_parser_test.zig b/src/js_parser/js_parser_test.zig index e1b44c62b..5760e331b 100644 --- a/src/js_parser/js_parser_test.zig +++ b/src/js_parser/js_parser_test.zig @@ -381,19 +381,6 @@ test "expectPrint" { var t_ = Tester.t(std.heap.page_allocator); var t = &t_; - try expectPrinted(t, "(-x) ** 2", "(-x) ** 2;\n", @src()); - try expectPrinted(t, "(+x) ** 2", "(+x) ** 2;\n", @src()); - try expectPrinted(t, "(~x) ** 2", "(~x) ** 2;\n", @src()); - try expectPrinted(t, "(!x) ** 2", "(!x) ** 2;\n", @src()); - try expectPrinted(t, "(-1) ** 2", "(-1) ** 2;\n", @src()); - try expectPrinted(t, "(+1) ** 2", "1 ** 2;\n", @src()); - try expectPrinted(t, "(~1) ** 2", "(~1) ** 2;\n", @src()); - try expectPrinted(t, "(!1) ** 2", "false ** 2;\n", @src()); - try expectPrinted(t, "(void x) ** 2", "(void x) ** 2;\n", @src()); - try expectPrinted(t, "(delete x) ** 2", "(delete x) ** 2;\n", @src()); - try expectPrinted(t, "(typeof x) ** 2", "(typeof x) ** 2;\n", @src()); - try expectPrinted(t, "undefined ** 2", "(void 0) ** 2;\n", @src()); - try expectPrinted(t, "class Foo { foo() {} }", "class Foo {\n foo() {\n }\n}\n", @src()); try expectPrinted(t, "class Foo { *foo() {} }", "class Foo {\n *foo() {\n }\n}\n", @src()); try expectPrinted(t, "class Foo { get foo() {} }", "class Foo {\n get foo() {\n }\n}\n", @src()); @@ -454,46 +441,142 @@ test "expectPrint" { try expectPrinted(t, "class Foo { static *['prototype']() {} }", "class Foo {\n static *[\"prototype\"]() {\n }\n}\n", @src()); try expectPrinted(t, "class Foo { static async ['prototype']() {} }", "class Foo {\n static async [\"prototype\"]() {\n }\n}\n", @src()); try expectPrinted(t, "class Foo { static async *['prototype']() {} }", "class Foo {\n static async *[\"prototype\"]() {\n }\n}\n", @src()); + + try expectPrinted(t, "class Foo extends Bar { constructor() { super() } }", "class Foo extends Bar {\n constructor() {\n super();\n }\n}\n", @src()); + try expectPrinted(t, "class Foo extends Bar { constructor() { () => super() } }", "class Foo extends Bar {\n constructor() {\n () => super();\n }\n}\n", @src()); + try expectPrinted(t, "class Foo extends Bar { constructor() { () => { super() } } }", "class Foo extends Bar {\n constructor() {\n () => {\n super();\n };\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 extends Bar { constructor(x = () => super()) {} }", "class Foo extends Bar {\n constructor(x = () => super()) {\n }\n}\n", @src()); + + try expectPrinted(t, "(x) => function() {}", "(x) => function() {\n};\n", @src()); + + try expectPrinted(t, "x => function() {}", "(x) => function() {\n};\n", @src()); + + try expectPrinted(t, "(x => function() {})", "(x) => function() {\n};\n", @src()); + + try expectPrinted(t, "(x = () => {}) => {}", "(x = () => {\n}) => {\n};\n", @src()); + try expectPrinted(t, "async (x = () => {}) => {}", "async (x = () => {\n}) => {\n};\n", @src()); + + try expectPrinted(t, "(() => {}) ? a : b", "(() => {\n}) ? a : b;\n", @src()); + try expectPrinted(t, "1 < (() => {})", "1 < (() => {\n});\n", @src()); + try expectPrinted(t, "y = x => {}", "y = (x) => {\n};\n", @src()); + try expectPrinted(t, "y = () => {}", "y = () => {\n};\n", @src()); + try expectPrinted(t, "y = (x) => {}", "y = (x) => {\n};\n", @src()); + try expectPrinted(t, "y = async x => {}", "y = async (x) => {\n};\n", @src()); + try expectPrinted(t, "y = async () => {}", "y = async () => {\n};\n", @src()); + try expectPrinted(t, "y = async (x) => {}", "y = async (x) => {\n};\n", @src()); + try expectPrinted(t, "1 + function () {}", "1 + function() {\n};\n", @src()); + try expectPrinted(t, "1 + async function () {}", "1 + async function() {\n};\n", @src()); + try expectPrinted(t, "class Foo extends function () {} {}", "class Foo extends function() {\n} {\n}\n", @src()); + try expectPrinted(t, "class Foo extends async function () {} {}", "class Foo extends async function() {\n} {\n}\n", @src()); + + try expectPrinted(t, "() => {}\n(0)", "() => {\n};\n0;\n", @src()); + try expectPrinted(t, "x => {}\n(0)", "(x) => {\n};\n0;\n", @src()); + try expectPrinted(t, "async () => {}\n(0)", "async () => {\n};\n0;\n", @src()); + try expectPrinted(t, "async x => {}\n(0)", "async (x) => {\n};\n0;\n", @src()); + try expectPrinted(t, "async (x) => {}\n(0)", "async (x) => {\n};\n0;\n", @src()); + + try expectPrinted(t, "() => {}\n,0", "() => {\n}, 0;\n", @src()); + try expectPrinted(t, "x => {}\n,0", "(x) => {\n}, 0;\n", @src()); + try expectPrinted(t, "async () => {}\n,0", "async () => {\n}, 0;\n", @src()); + try expectPrinted(t, "async x => {}\n,0", "async (x) => {\n}, 0;\n", @src()); + try expectPrinted(t, "async (x) => {}\n,0", "async (x) => {\n}, 0;\n", @src()); + + try expectPrinted(t, "(() => {})\n(0)", "(() => {\n})(0);\n", @src()); + try expectPrinted(t, "(x => {})\n(0)", "((x) => {\n})(0);\n", @src()); + try expectPrinted(t, "(async () => {})\n(0)", "(async () => {\n})(0);\n", @src()); + try expectPrinted(t, "(async x => {})\n(0)", "(async (x) => {\n})(0);\n", @src()); + try expectPrinted(t, "(async (x) => {})\n(0)", "(async (x) => {\n})(0);\n", @src()); + try expectPrinted(t, "y = () => {}\n(0)", "y = () => {\n};\n0;\n", @src()); + try expectPrinted(t, "y = x => {}\n(0)", "y = (x) => {\n};\n0;\n", @src()); + try expectPrinted(t, "y = async () => {}\n(0)", "y = async () => {\n};\n0;\n", @src()); + try expectPrinted(t, "y = async x => {}\n(0)", "y = async (x) => {\n};\n0;\n", @src()); + try expectPrinted(t, "y = async (x) => {}\n(0)", "y = async (x) => {\n};\n0;\n", @src()); + + try expectPrinted(t, "y = () => {}\n,0", "y = () => {\n}, 0;\n", @src()); + try expectPrinted(t, "y = x => {}\n,0", "y = (x) => {\n}, 0;\n", @src()); + try expectPrinted(t, "y = async () => {}\n,0", "y = async () => {\n}, 0;\n", @src()); + try expectPrinted(t, "y = async x => {}\n,0", "y = async (x) => {\n}, 0;\n", @src()); + try expectPrinted(t, "y = async (x) => {}\n,0", "y = async (x) => {\n}, 0;\n", @src()); + + try expectPrinted(t, "y = (() => {})\n(0)", "y = (() => {\n})(0);\n", @src()); + try expectPrinted(t, "y = (x => {})\n(0)", "y = ((x) => {\n})(0);\n", @src()); + try expectPrinted(t, "y = (async () => {})\n(0)", "y = (async () => {\n})(0);\n", @src()); + try expectPrinted(t, "y = (async x => {})\n(0)", "y = (async (x) => {\n})(0);\n", @src()); + try expectPrinted(t, "y = (async (x) => {})\n(0)", "y = (async (x) => {\n})(0);\n", @src()); + try expectPrinted(t, "(() => {}\n,0)", "() => {\n}, 0;\n", @src()); + try expectPrinted(t, "(x => {}\n,0)", "(x) => {\n}, 0;\n", @src()); + try expectPrinted(t, "(async () => {}\n,0)", "async () => {\n}, 0;\n", @src()); + try expectPrinted(t, "(async x => {}\n,0)", "async (x) => {\n}, 0;\n", @src()); + try expectPrinted(t, "(async (x) => {}\n,0)", "async (x) => {\n}, 0;\n", @src()); + + try expectPrinted(t, "((() => {})\n(0))", "(() => {\n})(0);\n", @src()); + try expectPrinted(t, "((x => {})\n(0))", "((x) => {\n})(0);\n", @src()); + try expectPrinted(t, "((async () => {})\n(0))", "(async () => {\n})(0);\n", @src()); + try expectPrinted(t, "((async x => {})\n(0))", "(async (x) => {\n})(0);\n", @src()); + try expectPrinted(t, "((async (x) => {})\n(0))", "(async (x) => {\n})(0);\n", @src()); + + try expectPrinted(t, "y = (() => {}\n,0)", "y = (() => {\n}, 0);\n", @src()); + try expectPrinted(t, "y = (x => {}\n,0)", "y = ((x) => {\n}, 0);\n", @src()); + try expectPrinted(t, "y = (async () => {}\n,0)", "y = (async () => {\n}, 0);\n", @src()); + try expectPrinted(t, "y = (async x => {}\n,0)", "y = (async (x) => {\n}, 0);\n", @src()); + try expectPrinted(t, "y = (async (x) => {}\n,0)", "y = (async (x) => {\n}, 0);\n", @src()); + + try expectPrinted(t, "y = ((() => {})\n(0))", "y = (() => {\n})(0);\n", @src()); + try expectPrinted(t, "y = ((x => {})\n(0))", "y = ((x) => {\n})(0);\n", @src()); + try expectPrinted(t, "y = ((async () => {})\n(0))", "y = (async () => {\n})(0);\n", @src()); + try expectPrinted(t, "y = ((async x => {})\n(0))", "y = (async (x) => {\n})(0);\n", @src()); + try expectPrinted(t, "y = ((async (x) => {})\n(0))", "y = (async (x) => {\n})(0);\n", @src()); + + try expectPrinted(t, "(-x) ** 2", "(-x) ** 2;\n", @src()); + try expectPrinted(t, "(+x) ** 2", "(+x) ** 2;\n", @src()); + try expectPrinted(t, "(~x) ** 2", "(~x) ** 2;\n", @src()); + try expectPrinted(t, "(!x) ** 2", "(!x) ** 2;\n", @src()); + try expectPrinted(t, "(-1) ** 2", "(-1) ** 2;\n", @src()); + try expectPrinted(t, "(+1) ** 2", "1 ** 2;\n", @src()); + try expectPrinted(t, "(~1) ** 2", "(~1) ** 2;\n", @src()); + try expectPrinted(t, "(!1) ** 2", "false ** 2;\n", @src()); + try expectPrinted(t, "(void x) ** 2", "(void x) ** 2;\n", @src()); + try expectPrinted(t, "(delete x) ** 2", "(delete x) ** 2;\n", @src()); + try expectPrinted(t, "(typeof x) ** 2", "(typeof x) ** 2;\n", @src()); + try expectPrinted(t, "undefined ** 2", "(void 0) ** 2;\n", @src()); + try expectPrinted(t, "({ prototype: 1 })", "({prototype: 1});\n", @src()); try expectPrinted(t, "({ get prototype() {} })", "({get prototype() {\n}});\n", @src()); try expectPrinted(t, "({ set prototype(x) {} })", "({set prototype(x) {\n}});\n", @src()); try expectPrinted(t, "({ *prototype() {} })", "({*prototype() {\n}});\n", @src()); try expectPrinted(t, "({ async prototype() {} })", "({async prototype() {\n}});\n", @src()); try expectPrinted(t, "({ async* prototype() {} })", "({async *prototype() {\n}});\n", @src()); - // try expectPrinted(t, "class Foo extends Bar { constructor() { super() } }", "class Foo extends Bar {\n constructor() {\n super();\n }\n}\n", @src()); - // try expectPrinted(t, "class Foo extends Bar { constructor() { () => super() } }", "class Foo extends Bar {\n constructor() {\n () => super();\n }\n}\n", @src()); - // try expectPrinted(t, "class Foo extends Bar { constructor() { () => { super() } } }", "class Foo extends Bar {\n constructor() {\n () => {\n super();\n };\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 extends Bar { constructor(x = () => super()) {} }", "class Foo extends Bar {\n constructor(x = () => super()) {\n }\n}\n", @src()); - // try expectPrinted(t, "({foo})", "({foo});\n", @src()); - // try expectPrinted(t, "({foo:0})", "({foo: 0});\n", @src()); - // try expectPrinted(t, "({1e9:0})", "({1e9: 0});\n", @src()); - // try expectPrinted(t, "({1_2_3n:0})", "({123n: 0});\n", @src()); - // try expectPrinted(t, "({0x1_2_3n:0})", "({0x123n: 0});\n", @src()); - // try expectPrinted(t, "({foo() {}})", "({foo() {\n}});\n", @src()); - // try expectPrinted(t, "({*foo() {}})", "({*foo() {\n}});\n", @src()); - // try expectPrinted(t, "({get foo() {}})", "({get foo() {\n}});\n", @src()); - // try expectPrinted(t, "({set foo(x) {}})", "({set foo(x) {\n}});\n", @src()); - - // try expectPrinted(t, "({if:0})", "({if: 0});\n", @src()); - // try expectPrinted(t, "({if() {}})", "({if() {\n}});\n", @src()); - // try expectPrinted(t, "({*if() {}})", "({*if() {\n}});\n", @src()); - // 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, "({foo})", "({foo});\n", @src()); + try expectPrinted(t, "({foo:0})", "({foo: 0});\n", @src()); + try expectPrinted(t, "({1e9:0})", "({1e9: 0});\n", @src()); + try expectPrinted(t, "({1_2_3n:0})", "({123n: 0});\n", @src()); + try expectPrinted(t, "({0x1_2_3n:0})", "({0x123n: 0});\n", @src()); + try expectPrinted(t, "({foo() {}})", "({foo() {\n}});\n", @src()); + try expectPrinted(t, "({*foo() {}})", "({*foo() {\n}});\n", @src()); + try expectPrinted(t, "({get foo() {}})", "({get foo() {\n}});\n", @src()); + try expectPrinted(t, "({set foo(x) {}})", "({set foo(x) {\n}});\n", @src()); + + try expectPrinted(t, "({if:0})", "({if: 0});\n", @src()); + try expectPrinted(t, "({if() {}})", "({if() {\n}});\n", @src()); + try expectPrinted(t, "({*if() {}})", "({*if() {\n}});\n", @src()); + 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()); t.report(@src()); } diff --git a/src/js_printer.zig b/src/js_printer.zig index e6cbb85a4..f0c1fee2e 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -383,7 +383,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printBlock(func.body.?.loc, func.body.?.stmts); } pub fn printClass(p: *Printer, class: G.Class) void { - if (class.extends) |extends| {} + if (class.extends) |extends| { + p.print(" extends"); + p.printSpace(); + p.printExpr(extends, Level.new.sub(1), ExprFlag.None()); + } p.printSpace(); @@ -1087,6 +1091,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printSpace(); } + p.printFnArgs(e.args, e.has_rest_arg, true); + p.printSpace(); + p.print("=>"); + p.printSpace(); + var wasPrinted = false; if (e.body.stmts.len == 1 and e.prefer_expr) { switch (e.body.stmts[0].data) { |