aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alloc.zig2
-rw-r--r--src/js_lexer.zig10
-rw-r--r--src/js_parser/js_parser.zig37
-rw-r--r--src/js_parser/js_parser_test.zig4
-rw-r--r--src/string_immutable.zig18
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"));
+}