aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-04-21 19:00:21 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-04-21 19:00:21 -0700
commitba472faea1a5ed8943916c5a602b415f3242f5c9 (patch)
treed50e9e07e69dde95443d23337e8f3dbbbdaa617b /src
parentad46a05ea5b2f1a86ef56bc946ebbe3589e21d43 (diff)
downloadbun-ba472faea1a5ed8943916c5a602b415f3242f5c9.tar.gz
bun-ba472faea1a5ed8943916c5a602b415f3242f5c9.tar.zst
bun-ba472faea1a5ed8943916c5a602b415f3242f5c9.zip
e_identifier!!
Diffstat (limited to 'src')
-rw-r--r--src/js_ast.zig125
-rw-r--r--src/js_parser.zig249
-rw-r--r--src/logger.zig4
3 files changed, 351 insertions, 27 deletions
diff --git a/src/js_ast.zig b/src/js_ast.zig
index c8631ca1b..cf476bc54 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -50,7 +50,7 @@ pub const Ref = struct {
const None = Ref{ .source_index = null, .inner_index = std.math.maxInt(u32) };
};
-pub const ImportItemStatus = enum(u8) {
+pub const ImportItemStatus = packed enum {
none,
// The linker doesn't report import/export mismatch errors
@@ -171,7 +171,7 @@ pub const G = struct {
name: logger.Loc,
extends: ?ExprNodeIndex = null,
body_loc: logger.Loc,
- properties: ?[]Property = null,
+ properties: []Property = &([_]Property{}),
};
// invalid shadowing if left as Comment
@@ -209,7 +209,7 @@ pub const G = struct {
pub const Fn = struct {
name: ?LocRef,
open_parens_loc: logger.Loc,
- args: ?[]Arg = null,
+ args: []Arg = &([_]Arg{}),
body: ?FnBody = null,
arguments_ref: ?Ref = null,
@@ -487,7 +487,7 @@ pub const Symbol = struct {
}
};
-pub const OptionalChain = enum {
+pub const OptionalChain = packed enum {
// "a?.b"
start,
@@ -504,7 +504,7 @@ pub const E = struct {
is_parenthesized: bool = false,
};
- pub const Unary = struct {
+ pub const Unary = packed struct {
op: Op.Code,
value: ExprNodeIndex,
};
@@ -518,6 +518,7 @@ pub const E = struct {
pub const Boolean = struct { value: bool };
pub const Super = struct {};
pub const Null = struct {};
+ pub const This = struct {};
pub const Undefined = struct {};
pub const New = struct {
target: ExprNodeIndex,
@@ -1019,6 +1020,9 @@ pub const Expr = struct {
E.Null => {
return Expr{ .loc = loc, .data = Data{ .e_null = data } };
},
+ E.This => {
+ return Expr{ .loc = loc, .data = Data{ .e_this = data } };
+ },
E.Undefined => {
return Expr{ .loc = loc, .data = Data{ .e_undefined = data } };
},
@@ -1140,12 +1144,14 @@ pub const Expr = struct {
e_if,
e_require_or_require_resolve,
e_import,
+ e_this,
};
pub const Data = union(Tag) {
e_array: E.Array,
e_unary: E.Unary,
e_binary: E.Binary,
+ e_this: E.This,
e_boolean: E.Boolean,
e_super: E.Super,
e_null: E.Null,
@@ -1295,12 +1301,13 @@ pub const S = struct {
pub const With = struct {
value: ExprNodeIndex,
body: StmtNodeIndex,
- body_loc: logger.Log,
+ body_loc: logger.Loc,
};
pub const Try = struct {
+ body_loc: logger.Loc,
body: StmtNodeList,
- body_loc: logger.Log,
+
catch_: ?Catch = null,
finally: ?Finally = null,
};
@@ -1349,11 +1356,11 @@ pub const S = struct {
};
pub const Break = struct {
- label: *LocRef,
+ label: ?LocRef = null,
};
pub const Continue = struct {
- label: *LocRef,
+ label: ?LocRef = null,
};
};
@@ -1372,7 +1379,7 @@ pub const Case = struct { loc: logger.Loc, value: ?ExprNodeIndex, body: StmtNode
pub const Op = struct {
// If you add a new token, remember to add it to "OpTable" too
- pub const Code = enum {
+ pub const Code = packed enum(u8) {
// Prefix
un_pos,
un_neg,
@@ -1439,7 +1446,7 @@ pub const Op = struct {
bin_logical_and_assign,
};
- pub const Level = enum(u8) {
+ pub const Level = packed enum(u23) {
lowest,
comma,
spread,
@@ -1817,7 +1824,7 @@ pub const NamedExport = struct {
alias_loc: logger.Loc,
};
-pub const StrictModeKind = enum {
+pub const StrictModeKind = packed enum(u7) {
sloppy_mode,
explicit_strict_mode,
implicit_strict_mode_import,
@@ -1888,16 +1895,106 @@ test "Binding.init" {
);
std.testing.expect(binding.loc.start == 1);
std.testing.expect(@as(Binding.Tag, binding.data) == Binding.Tag.b_identifier);
+
+ std.debug.print("-------Binding: {d} bits\n", .{@bitSizeOf(Binding)});
+ std.debug.print("B.Identifier: {d} bits\n", .{@bitSizeOf(B.Identifier)});
+ std.debug.print("B.Array: {d} bits\n", .{@bitSizeOf(B.Array)});
+ std.debug.print("B.Property: {d} bits\n", .{@bitSizeOf(B.Property)});
+ std.debug.print("B.Object: {d} bits\n", .{@bitSizeOf(B.Object)});
+ std.debug.print("B.Missing: {d} bits\n", .{@bitSizeOf(B.Missing)});
+ std.debug.print("-------Binding: {d} bits\n", .{@bitSizeOf(Binding)});
+}
+
+test "Stmt.init" {
+ var stmt = Stmt.init(
+ S.Continue{},
+ logger.Loc{ .start = 1 },
+ );
+ std.testing.expect(stmt.loc.start == 1);
+ std.testing.expect(@as(Stmt.Tag, stmt.data) == Stmt.Tag.s_continue);
+
+ std.debug.print("-----Stmt {d} bits\n", .{@bitSizeOf(Stmt)});
+ std.debug.print("StmtNodeList: {d} bits\n", .{@bitSizeOf(StmtNodeList)});
+ std.debug.print("StmtOrExpr: {d} bits\n", .{@bitSizeOf(StmtOrExpr)});
+ std.debug.print("S.Block {d} bits\n", .{@bitSizeOf(S.Block)});
+ std.debug.print("S.Comment {d} bits\n", .{@bitSizeOf(S.Comment)});
+ std.debug.print("S.Directive {d} bits\n", .{@bitSizeOf(S.Directive)});
+ std.debug.print("S.ExportClause {d} bits\n", .{@bitSizeOf(S.ExportClause)});
+ std.debug.print("S.Empty {d} bits\n", .{@bitSizeOf(S.Empty)});
+ std.debug.print("S.TypeScript {d} bits\n", .{@bitSizeOf(S.TypeScript)});
+ std.debug.print("S.Debugger {d} bits\n", .{@bitSizeOf(S.Debugger)});
+ std.debug.print("S.ExportFrom {d} bits\n", .{@bitSizeOf(S.ExportFrom)});
+ std.debug.print("S.ExportDefault {d} bits\n", .{@bitSizeOf(S.ExportDefault)});
+ std.debug.print("S.Enum {d} bits\n", .{@bitSizeOf(S.Enum)});
+ std.debug.print("S.Namespace {d} bits\n", .{@bitSizeOf(S.Namespace)});
+ std.debug.print("S.Function {d} bits\n", .{@bitSizeOf(S.Function)});
+ std.debug.print("S.Class {d} bits\n", .{@bitSizeOf(S.Class)});
+ std.debug.print("S.If {d} bits\n", .{@bitSizeOf(S.If)});
+ std.debug.print("S.For {d} bits\n", .{@bitSizeOf(S.For)});
+ std.debug.print("S.ForIn {d} bits\n", .{@bitSizeOf(S.ForIn)});
+ std.debug.print("S.ForOf {d} bits\n", .{@bitSizeOf(S.ForOf)});
+ std.debug.print("S.DoWhile {d} bits\n", .{@bitSizeOf(S.DoWhile)});
+ std.debug.print("S.While {d} bits\n", .{@bitSizeOf(S.While)});
+ std.debug.print("S.With {d} bits\n", .{@bitSizeOf(S.With)});
+ std.debug.print("S.Try {d} bits\n", .{@bitSizeOf(S.Try)});
+ std.debug.print("S.Switch {d} bits\n", .{@bitSizeOf(S.Switch)});
+ std.debug.print("S.Import {d} bits\n", .{@bitSizeOf(S.Import)});
+ std.debug.print("S.Return {d} bits\n", .{@bitSizeOf(S.Return)});
+ std.debug.print("S.Throw {d} bits\n", .{@bitSizeOf(S.Throw)});
+ std.debug.print("S.Local {d} bits\n", .{@bitSizeOf(S.Local)});
+ std.debug.print("S.Break {d} bits\n", .{@bitSizeOf(S.Break)});
+ std.debug.print("S.Continue {d} bits\n", .{@bitSizeOf(S.Continue)});
+ std.debug.print("-----Stmt {d} bits\n", .{@bitSizeOf(Stmt)});
}
test "Expr.init" {
const ident = Expr.init(E.Identifier{}, logger.Loc{ .start = 100 });
- const list = [_]Expr{ident};
- const expr = Expr.init(
+ var list = [_]Expr{ident};
+ var expr = Expr.init(
E.Array{ .items = list[0..] },
logger.Loc{ .start = 1 },
);
std.testing.expect(expr.loc.start == 1);
std.testing.expect(@as(Expr.Tag, expr.data) == Expr.Tag.e_array);
std.testing.expect(expr.data.e_array.items[0].loc.start == 100);
+
+ std.debug.print("--logger.Loc {d} bits\n", .{@bitSizeOf(logger.Loc)});
+ std.debug.print("--logger.Range {d} bits\n", .{@bitSizeOf(logger.Range)});
+ std.debug.print("----------Expr: {d} bits\n", .{@bitSizeOf(Expr)});
+ std.debug.print("ExprNodeList: {d} bits\n", .{@bitSizeOf(ExprNodeList)});
+ std.debug.print("E.Array: {d} bits\n", .{@bitSizeOf(E.Array)});
+
+ std.debug.print("E.Unary: {d} bits\n", .{@bitSizeOf(E.Unary)});
+ std.debug.print("E.Binary: {d} bits\n", .{@bitSizeOf(E.Binary)});
+ std.debug.print("E.Boolean: {d} bits\n", .{@bitSizeOf(E.Boolean)});
+ std.debug.print("E.Super: {d} bits\n", .{@bitSizeOf(E.Super)});
+ std.debug.print("E.Null: {d} bits\n", .{@bitSizeOf(E.Null)});
+ std.debug.print("E.Undefined: {d} bits\n", .{@bitSizeOf(E.Undefined)});
+ std.debug.print("E.New: {d} bits\n", .{@bitSizeOf(E.New)});
+ std.debug.print("E.NewTarget: {d} bits\n", .{@bitSizeOf(E.NewTarget)});
+ std.debug.print("E.Function: {d} bits\n", .{@bitSizeOf(E.Function)});
+ std.debug.print("E.ImportMeta: {d} bits\n", .{@bitSizeOf(E.ImportMeta)});
+ std.debug.print("E.Call: {d} bits\n", .{@bitSizeOf(E.Call)});
+ std.debug.print("E.Dot: {d} bits\n", .{@bitSizeOf(E.Dot)});
+ std.debug.print("E.Index: {d} bits\n", .{@bitSizeOf(E.Index)});
+ std.debug.print("E.Arrow: {d} bits\n", .{@bitSizeOf(E.Arrow)});
+ std.debug.print("E.Identifier: {d} bits\n", .{@bitSizeOf(E.Identifier)});
+ std.debug.print("E.ImportIdentifier: {d} bits\n", .{@bitSizeOf(E.ImportIdentifier)});
+ std.debug.print("E.PrivateIdentifier: {d} bits\n", .{@bitSizeOf(E.PrivateIdentifier)});
+ std.debug.print("E.JSXElement: {d} bits\n", .{@bitSizeOf(E.JSXElement)});
+ std.debug.print("E.Missing: {d} bits\n", .{@bitSizeOf(E.Missing)});
+ std.debug.print("E.Number: {d} bits\n", .{@bitSizeOf(E.Number)});
+ std.debug.print("E.BigInt: {d} bits\n", .{@bitSizeOf(E.BigInt)});
+ std.debug.print("E.Object: {d} bits\n", .{@bitSizeOf(E.Object)});
+ std.debug.print("E.Spread: {d} bits\n", .{@bitSizeOf(E.Spread)});
+ std.debug.print("E.String: {d} bits\n", .{@bitSizeOf(E.String)});
+ std.debug.print("E.TemplatePart: {d} bits\n", .{@bitSizeOf(E.TemplatePart)});
+ std.debug.print("E.Template: {d} bits\n", .{@bitSizeOf(E.Template)});
+ std.debug.print("E.RegExp: {d} bits\n", .{@bitSizeOf(E.RegExp)});
+ std.debug.print("E.Await: {d} bits\n", .{@bitSizeOf(E.Await)});
+ std.debug.print("E.Yield: {d} bits\n", .{@bitSizeOf(E.Yield)});
+ std.debug.print("E.If: {d} bits\n", .{@bitSizeOf(E.If)});
+ std.debug.print("E.RequireOrRequireResolve: {d} bits\n", .{@bitSizeOf(E.RequireOrRequireResolve)});
+ std.debug.print("E.Import: {d} bits\n", .{@bitSizeOf(E.Import)});
+ std.debug.print("----------Expr: {d} bits\n", .{@bitSizeOf(Expr)});
}
diff --git a/src/js_parser.zig b/src/js_parser.zig
index ed74e3a22..963b8e108 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -99,6 +99,12 @@ const ScopeOrder = struct {
scope: *js_ast.Scope,
};
+const ParenExprOpts = struct {
+ async_range: logger.Range = logger.Range.None,
+ is_async: bool = false,
+ force_arrow_fn: bool = false,
+};
+
// This is function-specific information used during parsing. It is saved and
// restored on the call stack around code that parses nested functions and
// arrow expressions.
@@ -204,12 +210,12 @@ const DeferredErrors = struct {
to.array_spread_feature = inv;
}
}
-};
-const ParenExprOpts = struct {
- async_range: ?logger.Range = null,
- is_async: bool = false,
- force_arrow_fn: bool = false,
+ var None = DeferredErrors{
+ .invalid_expr_default_value = null,
+ .invalid_expr_after_question = null,
+ .array_spread_feature = null,
+ };
};
const ModuleType = enum { esm };
@@ -1538,7 +1544,7 @@ const P = struct {
return p.source.contents[ref.inner_index .. ref.inner_index - source_index];
} else {
- std.debug.panic("Internal error: invalid symbol reference.", .{ref});
+ std.debug.panic("Internal error: invalid symbol reference. {s}", .{ref});
}
}
@@ -1591,15 +1597,15 @@ const P = struct {
// "async () => {}"
.t_open_paren => {
p.lexer.next();
- return p.parseParenExpr(async_range.loc, ParenExprOptions{ .is_async = true, .async_range = asyncRange });
+ return p.parseParenExpr(async_range.loc, ParenExprOpts{ .is_async = true, .async_range = async_range });
},
// "async<T>()"
// "async <T>() => {}"
.t_less_than => {
- if (p.options.ts and p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking) {
+ if (p.options.ts and p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking()) {
p.lexer.next();
- return p.parseParenExpr(async_range.loc, ParenExprOptions{ .is_async = true, .async_range = asyncRange });
+ return p.parseParenExpr(async_range.loc, ParenExprOpts{ .is_async = true, .async_range = async_range });
}
},
@@ -1610,12 +1616,12 @@ const P = struct {
// "async"
// "async + 1"
return Expr.init(
- E.Identifier{ .ref = p.storeNameInRef("async") },
+ E.Identifier{ .ref = try p.storeNameInRef("async") },
async_range.loc,
);
}
- pub fn trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking() void {
+ pub fn trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking(self: *P) bool {
notimpl();
}
@@ -1639,6 +1645,7 @@ const P = struct {
// engineering, it looks like they apply to the next CallExpression or
// NewExpression. So in "/* @__PURE__ */ a().b() + c()" the comment applies
// to the expression "a().b()".
+
if (had_pure_comment_before and level.lt(.call)) {
expr = p.parseSuffix(expr, .call - 1, errors, flags);
switch (expr.data) {
@@ -1757,8 +1764,228 @@ const P = struct {
p.current_scope = current_scope.parent;
}
+ pub fn markExprAsParenthesized(p: *P, expr: *Expr) void {
+ switch (expr.data) {
+ .e_array => |*ex| {
+ ex.is_parenthesized = true;
+ },
+ .e_object => |*ex| {
+ ex.is_parenthesized = true;
+ },
+ else => {
+ return;
+ },
+ }
+ }
+
+ pub fn parseYieldExpr(p: *P, loc: logger.Loc) Expr {
+ // Parse a yield-from expression, which yields from an iterator
+ const isStar = p.lexer.token == T.t_asterisk;
+
+ if (isStar) {
+ if (p.lexer.has_newline_before) {
+ p.lexer.unexpected();
+ }
+ p.lexer.next();
+ }
+
+ var value: ?ExprNodeIndex = null;
+ switch (p.lexer.token) {
+ .t_close_brace, .t_close_paren, .t_colon, .t_comma, .t_semicolon => {},
+ else => {
+ if (isStar or !p.lexer.has_newline_before) {
+ var expr = p.parseExpr(.yield);
+ value = p.m(expr);
+ }
+ },
+ }
+
+ return e(E.Yield{
+ .value = value,
+ .is_star = isStar,
+ }, loc);
+ }
+
pub fn parseSuffix(p: *P, left: Expr, level: Level, errors: ?*DeferredErrors, flags: Expr.Flags) Expr {
+ return _parseSuffix(p, left, level, errors orelse &DeferredErrors.None, flags);
+ }
+ pub fn _parseSuffix(p: *P, left: Expr, level: Level, errors: *DeferredErrors, flags: Expr.Flags) callconv(.Inline) Expr {
+ var expr: Expr = undefined;
var loc = p.lexer.loc();
+
+ return expr;
+ }
+ pub fn _parsePrefix(p: *P, level: Level, errors: *DeferredErrors, flags: Expr.Flags) callconv(.Inline) Expr {
+ const loc = p.lexer.loc();
+ const l = @enumToInt(level);
+
+ switch (p.lexer.token) {
+ .t_super => {
+ const superRange = p.lexer.range();
+ p.lexer.next();
+
+ switch (p.lexer.token) {
+ .t_open_paren => {
+ if (l < @enumToInt(Level.call) and p.fn_or_arrow_data_parse.allow_super_call) {
+ return e(E.Super{}, loc);
+ }
+ },
+ .t_dot, .t_open_bracket => {
+ return e(E.Super{}, loc);
+ },
+ else => {},
+ }
+
+ p.log.addRangeError(p.source, superRange, "Unexpected \"super\"") catch unreachable;
+ return e(E.Super{}, loc);
+ },
+ .t_open_paren => {
+ p.lexer.next();
+
+ // Arrow functions aren't allowed in the middle of expressions
+ if (l > @enumToInt(Level.assign)) {
+ const oldAllowIn = p.allow_in;
+ p.allow_in = true;
+
+ var value = p.parseExpr(Level.lowest);
+ p.markExprAsParenthesized(&value);
+ p.lexer.expect(.t_close_paren);
+ p.allow_in = oldAllowIn;
+ return value;
+ }
+
+ return p.parseParenExpr(loc, ParenExprOpts{}) catch unreachable;
+ },
+ .t_false => {
+ p.lexer.next();
+ return e(E.Boolean{ .value = false }, loc);
+ },
+ .t_true => {
+ p.lexer.next();
+ return e(E.Boolean{ .value = true }, loc);
+ },
+ .t_null => {
+ p.lexer.next();
+ return e(E.Null{}, loc);
+ },
+ .t_this => {
+ p.lexer.next();
+ return e(E.This{}, loc);
+ },
+ .t_identifier => {
+ const name = p.lexer.identifier;
+ const name_range = p.lexer.range();
+ const raw = p.lexer.raw();
+ p.lexer.next();
+
+ // Handle async and await expressions
+ if (name.len == 5) {
+ if (strings.eql(name, "async")) {
+ if (strings.eql(raw, "async")) {
+ return p.parseAsyncPrefixExpr(name_range, level) catch unreachable;
+ }
+ } else if (strings.eql(name, "await")) {
+ if (p.fn_or_arrow_data_parse.allow_await) {
+ if (!strings.eql(raw, "await")) {
+ p.log.addRangeError(p.source, name_range, "The keyword \"await\" cannot be escaped.") catch unreachable;
+ } else {
+ if (p.fn_or_arrow_data_parse.is_top_level) {
+ p.top_level_await_keyword = name_range;
+ // p.markSyntaxFeature()
+ }
+
+ if (p.fn_or_arrow_data_parse.arrow_arg_errors) |*err| {
+ err.invalid_expr_await = name_range;
+ } else {
+ p.fn_or_arrow_data_parse.arrow_arg_errors = DeferredArrowArgErrors{ .invalid_expr_await = name_range };
+ }
+
+ var value = p.m(p.parseExpr(.prefix));
+ if (p.lexer.token == T.t_asterisk_asterisk) {
+ p.lexer.unexpected();
+ }
+
+ return e(E.Await{ .value = value }, loc);
+ }
+ }
+ } else if (strings.eql(name, "yield")) {
+ if (p.fn_or_arrow_data_parse.allow_yield) {
+ if (strings.eql(raw, "yield")) {
+ p.log.addRangeError(p.source, name_range, "The keyword \"yield\" cannot be escaped") catch unreachable;
+ } else {
+ if (l > @enumToInt(Level.assign)) {
+ p.log.addRangeError(p.source, name_range, "Cannot use a \"yield\" here without parentheses") catch unreachable;
+ }
+
+ if (p.fn_or_arrow_data_parse.arrow_arg_errors) |*err| {
+ err.invalid_expr_yield = name_range;
+ }
+
+ return p.parseYieldExpr(loc);
+ }
+ } else if (!p.lexer.has_newline_before) {
+ // Try to gracefully recover if "yield" is used in the wrong place
+
+ switch (p.lexer.token) {
+ .t_null, .t_identifier, .t_false, .t_true, .t_numeric_literal, .t_big_integer_literal, .t_string_literal => {
+ p.log.addRangeError(p.source, name_range, "Cannot use \"yield\" outside a generator function") catch unreachable;
+ },
+ else => {},
+ }
+ }
+ }
+
+ // Handle the start of an arrow expression
+ if (p.lexer.token == .t_equals_greater_than) {
+ const ref = p.storeNameInRef(name) catch unreachable;
+ var args = p.allocator.alloc(Arg, 1) catch unreachable;
+ args[0] = Arg{ .binding = p.m(Binding.init(B.Identifier{
+ .ref = ref,
+ }, loc)) };
+
+ _ = p.pushScopeForParsePass(.function_args, loc) catch unreachable;
+ defer p.popScope();
+ return e(p.parseArrowBody(args, p.m(FnOrArrowDataParse{})) catch unreachable, loc);
+ }
+
+ const ref = p.storeNameInRef(name) catch unreachable;
+
+ return e(E.Identifier{
+ .ref = ref,
+ }, loc);
+ }
+ },
+ .t_string_literal, .t_no_substitution_template_literal => {},
+ .t_template_head => {},
+ .t_numeric_literal => {},
+ .t_big_integer_literal => {},
+ .t_slash, .t_slash_equals => {},
+ .t_void => {},
+ .t_typeof => {},
+ .t_delete => {},
+ .t_plus => {},
+ .t_minus => {},
+ .t_tilde => {},
+ .t_exclamation => {},
+ .t_minus_minus => {},
+ .t_plus_plus => {},
+ .t_function => {},
+ .t_class => {},
+ .t_new => {},
+ .t_open_bracket => {},
+ .t_open_brace => {},
+ .t_less_than => {},
+ .t_import => {},
+ else => {
+ p.lexer.unexpected();
+ return Expr.init(E.Missing{}, logger.Loc.Empty);
+ },
+ }
+
+ return Expr.init(E.Missing{}, logger.Loc.Empty);
+ }
+ pub fn parsePrefix(p: *P, level: Level, errors: ?*DeferredErrors, flags: Expr.Flags) Expr {
+ return p._parsePrefix(level, errors orelse &DeferredErrors.None, flags);
}
pub fn init(allocator: *std.mem.Allocator, log: logger.Log, source: logger.Source, lexer: js_lexer.Lexer, opts: Parser.Options) !*P {
diff --git a/src/logger.zig b/src/logger.zig
index 933e20667..492761f8d 100644
--- a/src/logger.zig
+++ b/src/logger.zig
@@ -25,7 +25,7 @@ pub const Kind = enum {
}
};
-pub const Loc = struct {
+pub const Loc = packed struct {
start: i32 = -1,
pub fn toUsize(self: *Loc) usize {
@@ -95,7 +95,7 @@ pub const Data = struct { text: string, location: ?Location = null };
pub const Msg = struct { kind: Kind = Kind.err, data: Data, notes: ?[]Data = null };
-pub const Range = struct {
+pub const Range = packed struct {
loc: Loc = Loc.Empty,
len: i32 = 0,
pub const None = Range{ .loc = Loc.Empty, .len = 0 };