diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/alloc.zig | 2 | ||||
-rw-r--r-- | src/js_lexer.zig | 10 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 37 | ||||
-rw-r--r-- | src/js_parser/js_parser_test.zig | 4 | ||||
-rw-r--r-- | src/string_immutable.zig | 18 |
5 files changed, 48 insertions, 23 deletions
diff --git a/src/alloc.zig b/src/alloc.zig index 1fbdc734e..ec6a678e8 100644 --- a/src/alloc.zig +++ b/src/alloc.zig @@ -3,10 +3,12 @@ const std = @import("std"); const STATIC_MEMORY_SIZE = 256000; pub var static_manager: ?std.heap.ArenaAllocator = null; pub var root_manager: ?RootAlloc = null; +pub var needs_setup: bool = true; pub var static: *std.mem.Allocator = undefined; pub var dynamic: *std.mem.Allocator = undefined; pub fn setup(root: *std.mem.Allocator) !void { + needs_setup = false; static = std.heap.c_allocator; dynamic = std.heap.c_allocator; // static = @ptrCast(*std.mem.Allocator, &stat.allocator); diff --git a/src/js_lexer.zig b/src/js_lexer.zig index 9ce678392..4d6b16b31 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -350,7 +350,15 @@ pub const Lexer = struct { pub fn expectContextualKeyword(self: *LexerType, comptime keyword: string) void { if (!self.isContextualKeyword(keyword)) { - self.addError(self.start, "\"{s}\"", .{keyword}, true); + if (std.builtin.mode == std.builtin.Mode.Debug) { + self.addError(self.start, "Expected \"{s}\" but found \"{s}\" (token: {s})", .{ + keyword, + self.raw(), + self.token, + }, true); + } else { + self.addError(self.start, "Expected \"{s}\" but found \"{s}\"", .{ keyword, self.raw() }, true); + } } self.next(); } diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 5afdade21..3321d0ed3 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -993,8 +993,9 @@ const ExprOut = struct { const Tup = std.meta.Tuple; // This function exists to tie all of these checks together in one place +// This can sometimes show up on benchmarks as a small thing. fn isEvalOrArguments(name: string) bool { - return strings.eql(name, "eval") or strings.eql(name, "arguments"); + return strings.eqlComptime(name, "eval") or strings.eqlComptime(name, "arguments"); } const PrependTempRefsOpts = struct { @@ -1649,7 +1650,7 @@ pub const P = struct { // symbols must be separate from the pass that binds identifiers to declared // symbols to handle declaring a hoisted "var" symbol in a nested scope and // binding a name to it in a parent or sibling scope. - scopes_in_order: List(ScopeOrder), + scopes_in_order: std.ArrayListUnmanaged(ScopeOrder), // These properties are for the visit pass, which runs after the parse pass. // The visit pass binds identifiers to declared symbols, does constant @@ -2240,12 +2241,18 @@ pub const P = struct { } pub fn pushScopeForVisitPass(p: *P, comptime kind: js_ast.Scope.Kind, loc: logger.Loc) !void { + assert(p.scopes_in_order.items.len > 0); const order = p.scopes_in_order.items[0]; - p.scopes_in_order.items = p.scopes_in_order.items[1..p.scopes_in_order.items.len]; + if (p.scopes_in_order.items.len > 1) { + p.scopes_in_order.items = p.scopes_in_order.items[1..p.scopes_in_order.items.len]; + } else { + p.scopes_in_order.items = &([_]ScopeOrder{}); + } // Sanity-check that the scopes generated by the first and second passes match if (order.loc.start != loc.start or order.scope.kind != kind) { - p.panic("Expected scope ({s}, {d}) in {s}, found scope ({s}, {d})", .{ kind, loc.start, p.source.path.pretty, order.scope.kind, order.loc.start }); + std.debug.print("Expected scope ({s}, {d}) in {s}, found scope ({s}, {d})", .{ kind, loc.start, p.source.path.pretty, order.scope.kind, order.loc.start }); + p.panic("", .{}); } p.current_scope = order.scope; @@ -2284,7 +2291,7 @@ pub const P = struct { // errors if a statement in the function body tries to re-declare any of the // arguments. if (kind == js_ast.Scope.Kind.function_body) { - assert(parent.kind != js_ast.Scope.Kind.function_args); + assert(parent.kind == js_ast.Scope.Kind.function_args); var iter = scope.parent.?.members.iterator(); while (iter.next()) |entry| { @@ -2299,7 +2306,7 @@ pub const P = struct { // Remember the length in case we call popAndDiscardScope() later const scope_index = p.scopes_in_order.items.len; - try p.scopes_in_order.append(ScopeOrder{ .loc = loc, .scope = scope }); + try p.scopes_in_order.append(p.allocator, ScopeOrder{ .loc = loc, .scope = scope }); return scope_index; } @@ -4057,7 +4064,7 @@ pub const P = struct { } // Truncate the scope order where we started to pretend we never saw this scope - p.scopes_in_order.shrinkAndFree(scope_index); + p.scopes_in_order.shrinkRetainingCapacity(scope_index); } pub fn skipTypescriptTypeStmt(p: *P, opts: *ParseStatementOptions) void { @@ -4122,7 +4129,7 @@ pub const P = struct { if (p.lexer.isContextualKeyword("as")) { p.lexer.next(); original_name = p.lexer.identifier; - name = LocRef{ .loc = alias_loc, .ref = try p.storeNameInRef(alias) }; + name = LocRef{ .loc = alias_loc, .ref = try p.storeNameInRef(original_name) }; p.lexer.expect(.t_identifier); } else if (!isIdentifier) { // An import where the name is a keyword must have an alias @@ -10690,21 +10697,25 @@ pub const P = struct { p.panic("", .{}); } + // This code is tricky. + // - Doing it incorrectly will cause segfaults. + // - Doing it correctly drastically affects runtime performance while parsing larger files + // The key is in how we remove scopes from the list + // If we do an orderedRemove, it gets very slow. + // swapRemove is fast. But a little more dangerous. pub fn popAndFlattenScope(p: *P, scope_index: usize) void { // Move up to the parent scope var to_flatten = p.current_scope; var parent = to_flatten.parent.?; p.current_scope = parent; - var scopes_in_order_end = p.scopes_in_order.capacity; - var _scopes_in_order = p.scopes_in_order.allocatedSlice(); - var scopes_in_order = _scopes_in_order[0..scopes_in_order_end]; + // Erase this scope from the order. This will shift over the indices of all // the scopes that were created after us. However, we shouldn't have to // worry about other code with outstanding scope indices for these scopes. // These scopes were all created in between this scope's push and pop // operations, so they should all be child scopes and should all be popped // by the time we get here. - std.mem.copyBackwards(ScopeOrder, scopes_in_order[scope_index..scopes_in_order.len], scopes_in_order[scope_index + 1 .. scopes_in_order.len]); + _ = p.scopes_in_order.swapRemove(scope_index); // Remove the last child from the parent scope const last = parent.children.items.len - 1; @@ -10895,7 +10906,7 @@ pub const P = struct { .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 = std.ArrayList(ScopeOrder).init(allocator), + .scopes_in_order = try std.ArrayListUnmanaged(ScopeOrder).initCapacity(allocator, 1), .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, diff --git a/src/js_parser/js_parser_test.zig b/src/js_parser/js_parser_test.zig index 6bba00707..62cb2525b 100644 --- a/src/js_parser/js_parser_test.zig +++ b/src/js_parser/js_parser_test.zig @@ -331,7 +331,7 @@ pub const Tester = struct { }; fn expectPrinted(t: *Tester, contents: string, expected: string, src: anytype) !void { - if (alloc.dynamic_manager == null) { + if (alloc.needs_setup) { try alloc.setup(std.heap.page_allocator); } @@ -380,8 +380,8 @@ const PRINT_AST = false; test "expectPrint" { var t_ = Tester.t(std.heap.page_allocator); var t = &t_; + try expectPrinted(t, @embedFile("../test/fixtures/function-scope-bug.jsx"), @embedFile("../test/fixtures/function-scope-bug.jsx"), @src()); try expectPrinted(t, @embedFile("../test/fixtures/simple.jsx"), @embedFile("../test/fixtures/simple.jsx"), @src()); - try expectPrinted(t, "if (true) { console.log(<div>true</div>); }", "if (true) { console.log(\"hi\"); }", @src()); // try expectPrinted(t, "if (true) { console.log(\"hi\"); }", "if (true) { console.log(\"hi\"); }", @src()); // try expectPrinted(t, "try { console.log(\"hi\"); }\ncatch(er) { console.log('noooo'); }", "class Foo {\n foo() {\n }\n}\n", @src()); diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 9fa8c4134..fcd0edb4a 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -81,18 +81,16 @@ pub fn eql(self: string, other: anytype) bool { return true; } pub fn eqlComptime(self: string, comptime alt: string) bool { - if (self.len != alt.len) return false; - comptime var matcher_size: usize = 0; switch (comptime alt.len) { 0 => { @compileError("Invalid size passed to eqlComptime"); }, - 1...3 => { + 1...4 => { matcher_size = 4; }, - 4...8 => { + 5...8 => { matcher_size = 8; }, 8...12 => { @@ -108,7 +106,7 @@ pub fn eqlComptime(self: string, comptime alt: string) bool { } comptime const Matcher = ExactSizeMatcher(matcher_size); comptime const alt_hash = Matcher.case(alt); - return Matcher.hashNoCheck(self) != alt_hash; + return Matcher.match(self) == alt_hash; } pub fn append(allocator: *std.mem.Allocator, self: string, other: string) !string { @@ -326,7 +324,6 @@ test "sortDesc" { std.testing.expectEqualStrings(sorted_join, string_join); } - pub fn ExactSizeMatcher(comptime max_bytes: usize) type { const T = std.meta.Int( .unsigned, @@ -364,8 +361,15 @@ pub fn ExactSizeMatcher(comptime max_bytes: usize) type { const eight = ExactSizeMatcher(8); -test "ExactSizeMatcher" { +test "ExactSizeMatcher 5 letter" { const word = "yield"; expect(eight.match(word) == eight.case("yield")); expect(eight.match(word) != eight.case("yields")); } + +test "ExactSizeMatcher 4 letter" { + const Four = ExactSizeMatcher(4); + const word = "from"; + expect(Four.match(word) == Four.case("from")); + expect(Four.match(word) != Four.case("fro")); +} |