diff --git a/src/js_lexer.zig b/src/js_lexer.zig index 1bfd57d68c..7c0ffef896 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -847,6 +847,10 @@ pub const Lexer = struct { return std.unicode.utf16leToUtf8Alloc(lexer.alloc, js) catch unreachable; } + pub fn nextInsideJSXElement() void { + std.debug.panic("JSX not implemented yet.", .{}); + } + fn scanRegExpValidateAndStep(lexer: *Lexer) void { if (lexer.code_point == '\\') { lexer.step(); diff --git a/src/js_parser.zig b/src/js_parser.zig index 2b3ee185e4..530215b2f9 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -2959,8 +2959,81 @@ const P = struct { .is_single_line = is_single_line, }, loc); }, - .t_less_than => {}, - .t_import => {}, + .t_less_than => { + // This is a very complicated and highly ambiguous area of TypeScript + // syntax. Many similar-looking things are overloaded. + // + // TS: + // + // A type cast: + // (x) + // <[]>(x) + // (x) + // + // An arrow function with type parameters: + // (x) => {} + // (x) => {} + // (x) => {} + // (x) => {} + // + // TSX: + // + // A JSX element: + // (x) => {} + // (x) => {} + // (x) => {} + // + // An arrow function with type parameters: + // (x) => {} + // (x) => {} + // + // A syntax error: + // <[]>(x) + // (x) + // (x) => {} + // (x) => {} + if (p.options.ts and p.options.jsx.parse) { + var oldLexer = p.lexer; + + p.lexer.next(); + // Look ahead to see if this should be an arrow function instead + var is_ts_arrow_fn = false; + + if (p.lexer.token == .t_identifier) { + p.lexer.next(); + if (p.lexer.token == .t_comma) { + is_ts_arrow_fn = true; + } else if (p.lexer.token == .t_extends) { + p.lexer.next(); + is_ts_arrow_fn = p.lexer.token != .t_equals and p.lexer.token != .t_greater_than; + } + } + + // Restore the lexer + p.lexer = oldLexer; + + if (is_ts_arrow_fn) { + p.skipTypescriptTypeParameters(); + p.lexer.expect(.t_open_paren); + return p.parseParenExpr(loc, ParenExprOpts{ .force_arrow_fn = true }) catch unreachable; + } + } + + if (p.options.jsx.parse) { + notimpl(); + } + + if (p.options.ts) { + notimpl(); + } + + p.lexer.unexpected(); + return p.e(E.Missing{}, logger.Loc.Empty); + }, + .t_import => { + p.lexer.next(); + return p.parseImportExpr(loc, level); + }, else => { p.lexer.unexpected(); return p.e(E.Missing{}, logger.Loc.Empty); @@ -2970,6 +3043,49 @@ const P = struct { return p.e(E.Missing{}, logger.Loc.Empty); } + // Note: The caller has already parsed the "import" keyword + pub fn parseImportExpr(p: *P, loc: logger.Loc, level: Level) Expr { + // Parse an "import.meta" expression + if (p.lexer.token == .t_dot) { + p.es6_import_keyword = js_lexer.rangeOfIdentifier(&p.source, loc); + p.lexer.next(); + if (p.lexer.isContextualKeyword("meta")) { + const r = p.lexer.range(); + p.lexer.next(); + p.has_import_meta = true; + return p.e(E.ImportMeta{}, loc); + } else { + p.lexer.expectedString("\"meta\""); + } + } + + if (level.gt(.call)) { + const r = js_lexer.rangeOfIdentifier(&p.source, loc); + p.log.addRangeError(p.source, r, "Cannot use an \"import\" expression here without parentheses") catch unreachable; + } + // allow "in" inside call arguments; + var old_allow_in = p.allow_in; + p.allow_in = true; + + p.lexer.preserve_all_comments_before = true; + p.lexer.expect(.t_open_paren); + const comments = p.lexer.comments_to_preserve_before; + p.lexer.preserve_all_comments_before = false; + + const value = p.parseExpr(.comma); + p.lexer.expect(.t_close_paren); + + p.allow_in = old_allow_in; + return p.e(E.Import{ .expr = value, .leading_interior_comments = comments orelse &([_]G.Comment{}), .import_record_index = 0 }, loc); + } + + pub fn parseJSXElement(loc: logger.Loc) Expr { + // Parse the tag + //var startRange, startText, startTag := p.parseJSXTag();รท + notimpl(); + return p.e(E.Missing{}, logger.Loc.Empty); + } + pub fn willNeedBindingPattern(p: *P) bool { switch (p.lexer.token) { .t_equals => {