authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-22 12:34:12-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-22 12:34:12-04:00
log8df0841d6ab964e2aec750a8ceeda51912ae448b
treefa2a7f30a4eaa8f94f6d5c251ff109cd4bb0427c
parent295bca9b5f397ff98e5a0162fcb2a9f5e0a3e35c

stage2 parser: token ids in their own array

To prevent cache misses, token ids go in their own array, and the start/end offsets go in a different one. perf measurement before: 2,667,914 cache-misses:u 2,139,139,935 instructions:u 894,167,331 cycles:u perf measurement after: 1,757,723 cache-misses:u 2,069,932,298 instructions:u 858,105,570 cycles:u

6 files changed, 217 insertions(+), 240 deletions(-)

lib/std/zig/ast.zig+26-24
......@@ -10,7 +10,8 @@ pub const NodeIndex = usize;
1010pub const Tree = struct {
1111 /// Reference to externally-owned data.
1212 source: []const u8,
13 tokens: []const Token,
13 token_ids: []const Token.Id,
14 token_locs: []const Token.Loc,
1415 errors: []const Error,
1516 /// undefined on parse error (when errors field is not empty)
1617 root_node: *Node.Root,
......@@ -23,26 +24,27 @@ pub const Tree = struct {
2324 generated: bool = false,
2425
2526 pub fn deinit(self: *Tree) void {
26 self.gpa.free(self.tokens);
27 self.gpa.free(self.token_ids);
28 self.gpa.free(self.token_locs);
2729 self.gpa.free(self.errors);
2830 self.arena.promote(self.gpa).deinit();
2931 }
3032
3133 pub fn renderError(self: *Tree, parse_error: *const Error, stream: var) !void {
32 return parse_error.render(self.tokens, stream);
34 return parse_error.render(self.token_ids, stream);
3335 }
3436
3537 pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 {
36 return self.tokenSlicePtr(self.tokens[token_index]);
38 return self.tokenSliceLoc(self.token_locs[token_index]);
3739 }
3840
39 pub fn tokenSlicePtr(self: *Tree, token: Token) []const u8 {
41 pub fn tokenSliceLoc(self: *Tree, token: Token.Loc) []const u8 {
4042 return self.source[token.start..token.end];
4143 }
4244
4345 pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 {
44 const first_token = self.tokens[node.firstToken()];
45 const last_token = self.tokens[node.lastToken()];
46 const first_token = self.token_locs[node.firstToken()];
47 const last_token = self.token_locs[node.lastToken()];
4648 return self.source[first_token.start..last_token.end];
4749 }
4850
......@@ -54,7 +56,7 @@ pub const Tree = struct {
5456 };
5557
5658 /// Return the Location of the token relative to the offset specified by `start_index`.
57 pub fn tokenLocationPtr(self: *Tree, start_index: usize, token: Token) Location {
59 pub fn tokenLocationLoc(self: *Tree, start_index: usize, token: Token.Loc) Location {
5860 var loc = Location{
5961 .line = 0,
6062 .column = 0,
......@@ -82,14 +84,14 @@ pub const Tree = struct {
8284 }
8385
8486 pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location {
85 return self.tokenLocationPtr(start_index, self.tokens[token_index]);
87 return self.tokenLocationLoc(start_index, self.token_locs[token_index]);
8688 }
8789
8890 pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool {
89 return self.tokensOnSameLinePtr(self.tokens[token1_index], self.tokens[token2_index]);
91 return self.tokensOnSameLineLoc(self.token_locs[token1_index], self.token_locs[token2_index]);
9092 }
9193
92 pub fn tokensOnSameLinePtr(self: *Tree, token1: Token, token2: Token) bool {
94 pub fn tokensOnSameLineLoc(self: *Tree, token1: Token.Loc, token2: Token.Loc) bool {
9395 return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null;
9496 }
9597
......@@ -100,7 +102,7 @@ pub const Tree = struct {
100102 /// Skips over comments
101103 pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {
102104 var index = token_index - 1;
103 while (self.tokens[index].id == Token.Id.LineComment) {
105 while (self.token_ids[index] == Token.Id.LineComment) {
104106 index -= 1;
105107 }
106108 return index;
......@@ -109,7 +111,7 @@ pub const Tree = struct {
109111 /// Skips over comments
110112 pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {
111113 var index = token_index + 1;
112 while (self.tokens[index].id == Token.Id.LineComment) {
114 while (self.token_ids[index] == Token.Id.LineComment) {
113115 index += 1;
114116 }
115117 return index;
......@@ -166,7 +168,7 @@ pub const Error = union(enum) {
166168 DeclBetweenFields: DeclBetweenFields,
167169 InvalidAnd: InvalidAnd,
168170
169 pub fn render(self: *const Error, tokens: []const Token, stream: var) !void {
171 pub fn render(self: *const Error, tokens: []const Token.Id, stream: var) !void {
170172 switch (self.*) {
171173 .InvalidToken => |*x| return x.render(tokens, stream),
172174 .ExpectedContainerMembers => |*x| return x.render(tokens, stream),
......@@ -321,7 +323,7 @@ pub const Error = union(enum) {
321323 pub const ExpectedCall = struct {
322324 node: *Node,
323325
324 pub fn render(self: *const ExpectedCall, tokens: []const Token, stream: var) !void {
326 pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: var) !void {
325327 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{
326328 @tagName(self.node.id),
327329 });
......@@ -331,7 +333,7 @@ pub const Error = union(enum) {
331333 pub const ExpectedCallOrFnProto = struct {
332334 node: *Node,
333335
334 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token, stream: var) !void {
336 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: var) !void {
335337 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++
336338 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
337339 }
......@@ -341,14 +343,14 @@ pub const Error = union(enum) {
341343 token: TokenIndex,
342344 expected_id: Token.Id,
343345
344 pub fn render(self: *const ExpectedToken, tokens: []const Token, stream: var) !void {
346 pub fn render(self: *const ExpectedToken, tokens: []const Token.Id, stream: var) !void {
345347 const found_token = tokens[self.token];
346 switch (found_token.id) {
348 switch (found_token) {
347349 .Invalid => {
348350 return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
349351 },
350352 else => {
351 const token_name = found_token.id.symbol();
353 const token_name = found_token.symbol();
352354 return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name });
353355 },
354356 }
......@@ -359,11 +361,11 @@ pub const Error = union(enum) {
359361 token: TokenIndex,
360362 end_id: Token.Id,
361363
362 pub fn render(self: *const ExpectedCommaOrEnd, tokens: []const Token, stream: var) !void {
364 pub fn render(self: *const ExpectedCommaOrEnd, tokens: []const Token.Id, stream: var) !void {
363365 const actual_token = tokens[self.token];
364366 return stream.print("expected ',' or '{}', found '{}'", .{
365367 self.end_id.symbol(),
366 actual_token.id.symbol(),
368 actual_token.symbol(),
367369 });
368370 }
369371 };
......@@ -374,9 +376,9 @@ pub const Error = union(enum) {
374376
375377 token: TokenIndex,
376378
377 pub fn render(self: *const ThisError, tokens: []const Token, stream: var) !void {
379 pub fn render(self: *const ThisError, tokens: []const Token.Id, stream: var) !void {
378380 const actual_token = tokens[self.token];
379 return stream.print(msg, .{actual_token.id.symbol()});
381 return stream.print(msg, .{actual_token.symbol()});
380382 }
381383 };
382384 }
......@@ -387,7 +389,7 @@ pub const Error = union(enum) {
387389
388390 token: TokenIndex,
389391
390 pub fn render(self: *const ThisError, tokens: []const Token, stream: var) !void {
392 pub fn render(self: *const ThisError, tokens: []const Token.Id, stream: var) !void {
391393 return stream.writeAll(msg);
392394 }
393395 };
lib/std/zig/parse.zig+73-95
......@@ -16,28 +16,32 @@ pub const Error = error{ParseError} || Allocator.Error;
1616pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree {
1717 // TODO optimization idea: ensureCapacity on the tokens list and
1818 // then appendAssumeCapacity inside the loop.
19 var tokens = std.ArrayList(Token).init(gpa);
20 defer tokens.deinit();
19 var token_ids = std.ArrayList(Token.Id).init(gpa);
20 defer token_ids.deinit();
21 var token_locs = std.ArrayList(Token.Loc).init(gpa);
22 defer token_locs.deinit();
2123
2224 var tokenizer = std.zig.Tokenizer.init(source);
2325 while (true) {
24 const tree_token = try tokens.addOne();
25 tree_token.* = tokenizer.next();
26 if (tree_token.id == .Eof) break;
26 const token = tokenizer.next();
27 try token_ids.append(token.id);
28 try token_locs.append(token.loc);
29 if (token.id == .Eof) break;
2730 }
2831
2932 var parser: Parser = .{
3033 .source = source,
3134 .arena = std.heap.ArenaAllocator.init(gpa),
3235 .gpa = gpa,
33 .tokens = tokens.items,
36 .token_ids = token_ids.items,
37 .token_locs = token_locs.items,
3438 .errors = .{},
3539 .tok_i = 0,
3640 };
3741 defer parser.errors.deinit(gpa);
3842 errdefer parser.arena.deinit();
3943
40 while (tokens.items[parser.tok_i].id == .LineComment) parser.tok_i += 1;
44 while (token_ids.items[parser.tok_i] == .LineComment) parser.tok_i += 1;
4145
4246 const root_node = try parser.parseRoot();
4347
......@@ -45,7 +49,8 @@ pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree {
4549 tree.* = .{
4650 .gpa = gpa,
4751 .source = source,
48 .tokens = tokens.toOwnedSlice(),
52 .token_ids = token_ids.toOwnedSlice(),
53 .token_locs = token_locs.toOwnedSlice(),
4954 .errors = parser.errors.toOwnedSlice(gpa),
5055 .root_node = root_node,
5156 .arena = parser.arena.state,
......@@ -58,9 +63,8 @@ const Parser = struct {
5863 arena: std.heap.ArenaAllocator,
5964 gpa: *Allocator,
6065 source: []const u8,
61 /// TODO: Optimization idea: have this be several arrays of the token fields rather
62 /// than an array of structs.
63 tokens: []const Token,
66 token_ids: []const Token.Id,
67 token_locs: []const Token.Loc,
6468 tok_i: TokenIndex,
6569 errors: std.ArrayListUnmanaged(AstError),
6670
......@@ -80,19 +84,6 @@ const Parser = struct {
8084 return node;
8185 }
8286
83 /// Helper function for appending elements to a singly linked list.
84 fn llpush(
85 p: *Parser,
86 comptime T: type,
87 it: *?*std.SinglyLinkedList(T).Node,
88 data: T,
89 ) !*?*std.SinglyLinkedList(T).Node {
90 const llnode = try p.arena.allocator.create(std.SinglyLinkedList(T).Node);
91 llnode.* = .{ .data = data };
92 it.* = llnode;
93 return &llnode.next;
94 }
95
9687 /// ContainerMembers
9788 /// <- TestDecl ContainerMembers
9889 /// / TopLevelComptime ContainerMembers
......@@ -228,7 +219,7 @@ const Parser = struct {
228219 // try to continue parsing
229220 const index = p.tok_i;
230221 p.findNextContainerMember();
231 const next = p.tokens[p.tok_i].id;
222 const next = p.token_ids[p.tok_i];
232223 switch (next) {
233224 .Eof => break,
234225 else => {
......@@ -257,7 +248,7 @@ const Parser = struct {
257248 });
258249 }
259250
260 const next = p.tokens[p.tok_i].id;
251 const next = p.token_ids[p.tok_i];
261252 switch (next) {
262253 .Eof => break,
263254 .Keyword_comptime => {
......@@ -291,7 +282,7 @@ const Parser = struct {
291282 var level: u32 = 0;
292283 while (true) {
293284 const tok = p.nextToken();
294 switch (tok.ptr.id) {
285 switch (p.token_ids[tok]) {
295286 // any of these can start a new top level declaration
296287 .Keyword_test,
297288 .Keyword_comptime,
......@@ -308,7 +299,7 @@ const Parser = struct {
308299 .Identifier,
309300 => {
310301 if (level == 0) {
311 p.putBackToken(tok.index);
302 p.putBackToken(tok);
312303 return;
313304 }
314305 },
......@@ -325,13 +316,13 @@ const Parser = struct {
325316 .RBrace => {
326317 if (level == 0) {
327318 // end of container, exit
328 p.putBackToken(tok.index);
319 p.putBackToken(tok);
329320 return;
330321 }
331322 level -= 1;
332323 },
333324 .Eof => {
334 p.putBackToken(tok.index);
325 p.putBackToken(tok);
335326 return;
336327 },
337328 else => {},
......@@ -344,11 +335,11 @@ const Parser = struct {
344335 var level: u32 = 0;
345336 while (true) {
346337 const tok = p.nextToken();
347 switch (tok.ptr.id) {
338 switch (p.token_ids[tok]) {
348339 .LBrace => level += 1,
349340 .RBrace => {
350341 if (level == 0) {
351 p.putBackToken(tok.index);
342 p.putBackToken(tok);
352343 return;
353344 }
354345 level -= 1;
......@@ -359,7 +350,7 @@ const Parser = struct {
359350 }
360351 },
361352 .Eof => {
362 p.putBackToken(tok.index);
353 p.putBackToken(tok);
363354 return;
364355 },
365356 else => {},
......@@ -454,8 +445,8 @@ const Parser = struct {
454445 }
455446
456447 if (extern_export_inline_token) |token| {
457 if (p.tokens[token].id == .Keyword_inline or
458 p.tokens[token].id == .Keyword_noinline)
448 if (p.token_ids[token] == .Keyword_inline or
449 p.token_ids[token] == .Keyword_noinline)
459450 {
460451 try p.errors.append(p.gpa, .{
461452 .ExpectedFn = .{ .token = p.tok_i },
......@@ -722,7 +713,7 @@ const Parser = struct {
722713
723714 const defer_token = p.eatToken(.Keyword_defer) orelse p.eatToken(.Keyword_errdefer);
724715 if (defer_token) |token| {
725 const payload = if (p.tokens[token].id == .Keyword_errdefer)
716 const payload = if (p.token_ids[token] == .Keyword_errdefer)
726717 try p.parsePayload()
727718 else
728719 null;
......@@ -2269,7 +2260,7 @@ const Parser = struct {
22692260 /// / EQUAL
22702261 fn parseAssignOp(p: *Parser) !?*Node {
22712262 const token = p.nextToken();
2272 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2263 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
22732264 .AsteriskEqual => .AssignMul,
22742265 .SlashEqual => .AssignDiv,
22752266 .PercentEqual => .AssignMod,
......@@ -2285,14 +2276,14 @@ const Parser = struct {
22852276 .MinusPercentEqual => .AssignSubWrap,
22862277 .Equal => .Assign,
22872278 else => {
2288 p.putBackToken(token.index);
2279 p.putBackToken(token);
22892280 return null;
22902281 },
22912282 };
22922283
22932284 const node = try p.arena.allocator.create(Node.InfixOp);
22942285 node.* = .{
2295 .op_token = token.index,
2286 .op_token = token,
22962287 .lhs = undefined, // set by caller
22972288 .op = op,
22982289 .rhs = undefined, // set by caller
......@@ -2309,7 +2300,7 @@ const Parser = struct {
23092300 /// / RARROWEQUAL
23102301 fn parseCompareOp(p: *Parser) !?*Node {
23112302 const token = p.nextToken();
2312 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2303 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
23132304 .EqualEqual => .EqualEqual,
23142305 .BangEqual => .BangEqual,
23152306 .AngleBracketLeft => .LessThan,
......@@ -2317,12 +2308,12 @@ const Parser = struct {
23172308 .AngleBracketLeftEqual => .LessOrEqual,
23182309 .AngleBracketRightEqual => .GreaterOrEqual,
23192310 else => {
2320 p.putBackToken(token.index);
2311 p.putBackToken(token);
23212312 return null;
23222313 },
23232314 };
23242315
2325 return p.createInfixOp(token.index, op);
2316 return p.createInfixOp(token, op);
23262317 }
23272318
23282319 /// BitwiseOp
......@@ -2333,19 +2324,19 @@ const Parser = struct {
23332324 /// / KEYWORD_catch Payload?
23342325 fn parseBitwiseOp(p: *Parser) !?*Node {
23352326 const token = p.nextToken();
2336 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2327 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
23372328 .Ampersand => .BitAnd,
23382329 .Caret => .BitXor,
23392330 .Pipe => .BitOr,
23402331 .Keyword_orelse => .UnwrapOptional,
23412332 .Keyword_catch => .{ .Catch = try p.parsePayload() },
23422333 else => {
2343 p.putBackToken(token.index);
2334 p.putBackToken(token);
23442335 return null;
23452336 },
23462337 };
23472338
2348 return p.createInfixOp(token.index, op);
2339 return p.createInfixOp(token, op);
23492340 }
23502341
23512342 /// BitShiftOp
......@@ -2353,16 +2344,16 @@ const Parser = struct {
23532344 /// / RARROW2
23542345 fn parseBitShiftOp(p: *Parser) !?*Node {
23552346 const token = p.nextToken();
2356 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2347 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
23572348 .AngleBracketAngleBracketLeft => .BitShiftLeft,
23582349 .AngleBracketAngleBracketRight => .BitShiftRight,
23592350 else => {
2360 p.putBackToken(token.index);
2351 p.putBackToken(token);
23612352 return null;
23622353 },
23632354 };
23642355
2365 return p.createInfixOp(token.index, op);
2356 return p.createInfixOp(token, op);
23662357 }
23672358
23682359 /// AdditionOp
......@@ -2373,19 +2364,19 @@ const Parser = struct {
23732364 /// / MINUSPERCENT
23742365 fn parseAdditionOp(p: *Parser) !?*Node {
23752366 const token = p.nextToken();
2376 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2367 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
23772368 .Plus => .Add,
23782369 .Minus => .Sub,
23792370 .PlusPlus => .ArrayCat,
23802371 .PlusPercent => .AddWrap,
23812372 .MinusPercent => .SubWrap,
23822373 else => {
2383 p.putBackToken(token.index);
2374 p.putBackToken(token);
23842375 return null;
23852376 },
23862377 };
23872378
2388 return p.createInfixOp(token.index, op);
2379 return p.createInfixOp(token, op);
23892380 }
23902381
23912382 /// MultiplyOp
......@@ -2397,7 +2388,7 @@ const Parser = struct {
23972388 /// / ASTERISKPERCENT
23982389 fn parseMultiplyOp(p: *Parser) !?*Node {
23992390 const token = p.nextToken();
2400 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2391 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
24012392 .PipePipe => .MergeErrorSets,
24022393 .Asterisk => .Mul,
24032394 .Slash => .Div,
......@@ -2405,12 +2396,12 @@ const Parser = struct {
24052396 .AsteriskAsterisk => .ArrayMult,
24062397 .AsteriskPercent => .MulWrap,
24072398 else => {
2408 p.putBackToken(token.index);
2399 p.putBackToken(token);
24092400 return null;
24102401 },
24112402 };
24122403
2413 return p.createInfixOp(token.index, op);
2404 return p.createInfixOp(token, op);
24142405 }
24152406
24162407 /// PrefixOp
......@@ -2423,7 +2414,7 @@ const Parser = struct {
24232414 /// / KEYWORD_await
24242415 fn parsePrefixOp(p: *Parser) !?*Node {
24252416 const token = p.nextToken();
2426 const op: Node.PrefixOp.Op = switch (token.ptr.id) {
2417 const op: Node.PrefixOp.Op = switch (p.token_ids[token]) {
24272418 .Bang => .BoolNot,
24282419 .Minus => .Negation,
24292420 .Tilde => .BitNot,
......@@ -2432,14 +2423,14 @@ const Parser = struct {
24322423 .Keyword_try => .Try,
24332424 .Keyword_await => .Await,
24342425 else => {
2435 p.putBackToken(token.index);
2426 p.putBackToken(token);
24362427 return null;
24372428 },
24382429 };
24392430
24402431 const node = try p.arena.allocator.create(Node.PrefixOp);
24412432 node.* = .{
2442 .op_token = token.index,
2433 .op_token = token,
24432434 .op = op,
24442435 .rhs = undefined, // set by caller
24452436 };
......@@ -2493,7 +2484,7 @@ const Parser = struct {
24932484 // If the token encountered was **, there will be two nodes instead of one.
24942485 // The attributes should be applied to the rightmost operator.
24952486 const prefix_op = node.cast(Node.PrefixOp).?;
2496 var ptr_info = if (p.tokens[prefix_op.op_token].id == .AsteriskAsterisk)
2487 var ptr_info = if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk)
24972488 &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
24982489 else
24992490 &prefix_op.op.PtrType;
......@@ -2812,7 +2803,8 @@ const Parser = struct {
28122803 return null;
28132804 };
28142805 if (p.eatToken(.Identifier)) |ident| {
2815 const token_slice = p.source[p.tokens[ident].start..p.tokens[ident].end];
2806 const token_loc = p.token_locs[ident];
2807 const token_slice = p.source[token_loc.start..token_loc.end];
28162808 if (!std.mem.eql(u8, token_slice, "c")) {
28172809 p.putBackToken(ident);
28182810 } else {
......@@ -2879,7 +2871,7 @@ const Parser = struct {
28792871 fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {
28802872 const kind_token = p.nextToken();
28812873
2882 const init_arg_expr = switch (kind_token.ptr.id) {
2874 const init_arg_expr = switch (p.token_ids[kind_token]) {
28832875 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
28842876 .Keyword_enum => blk: {
28852877 if (p.eatToken(.LParen) != null) {
......@@ -2914,13 +2906,13 @@ const Parser = struct {
29142906 break :blk Node.ContainerDecl.InitArg{ .None = {} };
29152907 },
29162908 else => {
2917 p.putBackToken(kind_token.index);
2909 p.putBackToken(kind_token);
29182910 return null;
29192911 },
29202912 };
29212913
29222914 return ContainerDeclType{
2923 .kind_token = kind_token.index,
2915 .kind_token = kind_token,
29242916 .init_arg_expr = init_arg_expr,
29252917 };
29262918 }
......@@ -2973,7 +2965,7 @@ const Parser = struct {
29732965 while (try nodeParseFn(p)) |item| {
29742966 try list.append(item);
29752967
2976 switch (p.tokens[p.tok_i].id) {
2968 switch (p.token_ids[p.tok_i]) {
29772969 .Comma => _ = p.nextToken(),
29782970 // all possible delimiters
29792971 .Colon, .RParen, .RBrace, .RBracket => break,
......@@ -2994,13 +2986,13 @@ const Parser = struct {
29942986 fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
29952987 return struct {
29962988 pub fn parse(p: *Parser) Error!?*Node {
2997 const op_token = if (token == .Keyword_and) switch (p.tokens[p.tok_i].id) {
2998 .Keyword_and => p.nextToken().index,
2989 const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) {
2990 .Keyword_and => p.nextToken(),
29992991 .Invalid_ampersands => blk: {
30002992 try p.errors.append(p.gpa, .{
30012993 .InvalidAnd = .{ .token = p.tok_i },
30022994 });
3003 break :blk p.nextToken().index;
2995 break :blk p.nextToken();
30042996 },
30052997 else => return null,
30062998 } else p.eatToken(token) orelse return null;
......@@ -3104,7 +3096,7 @@ const Parser = struct {
31043096 var tok_i = start_tok_i;
31053097 var count: usize = 1; // including first_line
31063098 while (true) : (tok_i += 1) {
3107 switch (p.tokens[tok_i].id) {
3099 switch (p.token_ids[tok_i]) {
31083100 .LineComment => continue,
31093101 .MultilineStringLiteralLine => count += 1,
31103102 else => break,
......@@ -3118,7 +3110,7 @@ const Parser = struct {
31183110 lines[0] = first_line;
31193111 count = 1;
31203112 while (true) : (tok_i += 1) {
3121 switch (p.tokens[tok_i].id) {
3113 switch (p.token_ids[tok_i]) {
31223114 .LineComment => continue,
31233115 .MultilineStringLiteralLine => {
31243116 lines[count] = tok_i;
......@@ -3215,7 +3207,7 @@ const Parser = struct {
32153207 }
32163208
32173209 fn tokensOnSameLine(p: *Parser, token1: TokenIndex, token2: TokenIndex) bool {
3218 return std.mem.indexOfScalar(u8, p.source[p.tokens[token1].end..p.tokens[token2].start], '\n') == null;
3210 return std.mem.indexOfScalar(u8, p.source[p.token_locs[token1].end..p.token_locs[token2].start], '\n') == null;
32193211 }
32203212
32213213 /// Eat a single-line doc comment on the same line as another node
......@@ -3239,7 +3231,7 @@ const Parser = struct {
32393231 .PrefixOp => {
32403232 var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
32413233 // If the token encountered was **, there will be two nodes
3242 if (p.tokens[prefix_op.op_token].id == .AsteriskAsterisk) {
3234 if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) {
32433235 rightmost_op = prefix_op.rhs;
32443236 prefix_op = rightmost_op.cast(Node.PrefixOp).?;
32453237 }
......@@ -3328,11 +3320,7 @@ const Parser = struct {
33283320 }
33293321
33303322 fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {
3331 return if (p.eatAnnotatedToken(id)) |token| token.index else null;
3332 }
3333
3334 fn eatAnnotatedToken(p: *Parser, id: Token.Id) ?AnnotatedToken {
3335 return if (p.tokens[p.tok_i].id == id) p.nextToken() else null;
3323 return if (p.token_ids[p.tok_i] == id) p.nextToken() else null;
33363324 }
33373325
33383326 fn expectToken(p: *Parser, id: Token.Id) Error!TokenIndex {
......@@ -3341,29 +3329,25 @@ const Parser = struct {
33413329
33423330 fn expectTokenRecoverable(p: *Parser, id: Token.Id) !?TokenIndex {
33433331 const token = p.nextToken();
3344 if (token.ptr.id != id) {
3332 if (p.token_ids[token] != id) {
33453333 try p.errors.append(p.gpa, .{
3346 .ExpectedToken = .{ .token = token.index, .expected_id = id },
3334 .ExpectedToken = .{ .token = token, .expected_id = id },
33473335 });
33483336 // go back so that we can recover properly
3349 p.putBackToken(token.index);
3337 p.putBackToken(token);
33503338 return null;
33513339 }
3352 return token.index;
3340 return token;
33533341 }
33543342
3355 fn nextToken(p: *Parser) AnnotatedToken {
3356 const result = AnnotatedToken{
3357 .index = p.tok_i,
3358 .ptr = &p.tokens[p.tok_i],
3359 };
3343 fn nextToken(p: *Parser) TokenIndex {
3344 const result = p.tok_i;
33603345 p.tok_i += 1;
3361 assert(result.ptr.id != .LineComment);
3362 if (p.tok_i >= p.tokens.len) return result;
3346 assert(p.token_ids[result] != .LineComment);
3347 if (p.tok_i >= p.token_ids.len) return result;
33633348
33643349 while (true) {
3365 const next_tok = p.tokens[p.tok_i];
3366 if (next_tok.id != .LineComment) return result;
3350 if (p.token_ids[p.tok_i] != .LineComment) return result;
33673351 p.tok_i += 1;
33683352 }
33693353 }
......@@ -3371,18 +3355,12 @@ const Parser = struct {
33713355 fn putBackToken(p: *Parser, putting_back: TokenIndex) void {
33723356 while (p.tok_i > 0) {
33733357 p.tok_i -= 1;
3374 const prev_tok = p.tokens[p.tok_i];
3375 if (prev_tok.id == .LineComment) continue;
3358 if (p.token_ids[p.tok_i] == .LineComment) continue;
33763359 assert(putting_back == p.tok_i);
33773360 return;
33783361 }
33793362 }
33803363
3381 const AnnotatedToken = struct {
3382 index: TokenIndex,
3383 ptr: *const Token,
3384 };
3385
33863364 fn expectNode(
33873365 p: *Parser,
33883366 parseFn: NodeParseFn,
lib/std/zig/parser_test.zig+1-1
......@@ -3181,7 +3181,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
31813181 defer tree.deinit();
31823182
31833183 for (tree.errors) |*parse_error| {
3184 const token = tree.tokens[parse_error.loc()];
3184 const token = tree.token_locs[parse_error.loc()];
31853185 const loc = tree.tokenLocation(0, parse_error.loc());
31863186 try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });
31873187 try tree.renderError(parse_error, stderr);
lib/std/zig/render.zig+99-89
......@@ -68,11 +68,12 @@ fn renderRoot(
6868 tree: *ast.Tree,
6969) (@TypeOf(stream).Error || Error)!void {
7070 // render all the line comments at the beginning of the file
71 for (tree.tokens) |token, i| {
72 if (token.id != .LineComment) break;
73 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSlicePtr(token), " ")});
74 const next_token = &tree.tokens[i + 1];
75 const loc = tree.tokenLocationPtr(token.end, next_token.*);
71 for (tree.token_ids) |token_id, i| {
72 if (token_id != .LineComment) break;
73 const token_loc = tree.token_locs[i];
74 try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
75 const next_token = tree.token_locs[i + 1];
76 const loc = tree.tokenLocationLoc(token_loc.end, next_token);
7677 if (loc.line >= 2) {
7778 try stream.writeByte('\n');
7879 }
......@@ -101,8 +102,8 @@ fn renderRoot(
101102
102103 while (token_index != 0) {
103104 token_index -= 1;
104 const token = tree.tokens[token_index];
105 switch (token.id) {
105 const token_id = tree.token_ids[token_index];
106 switch (token_id) {
106107 .LineComment => {},
107108 .DocComment => {
108109 copy_start_token_index = token_index;
......@@ -111,12 +112,13 @@ fn renderRoot(
111112 else => break,
112113 }
113114
114 if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) {
115 const token_loc = tree.token_locs[token_index];
116 if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) {
115117 if (!found_fmt_directive) {
116118 fmt_active = false;
117119 found_fmt_directive = true;
118120 }
119 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) {
121 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) {
120122 if (!found_fmt_directive) {
121123 fmt_active = true;
122124 found_fmt_directive = true;
......@@ -135,7 +137,7 @@ fn renderRoot(
135137 if (decl_i >= root_decls.len) {
136138 // If there's no next reformatted `decl`, just copy the
137139 // remaining input tokens and bail out.
138 const start = tree.tokens[copy_start_token_index].start;
140 const start = tree.token_locs[copy_start_token_index].start;
139141 try copyFixingWhitespace(stream, tree.source[start..]);
140142 return;
141143 }
......@@ -143,15 +145,16 @@ fn renderRoot(
143145 var decl_first_token_index = decl.firstToken();
144146
145147 while (token_index < decl_first_token_index) : (token_index += 1) {
146 const token = tree.tokens[token_index];
147 switch (token.id) {
148 const token_id = tree.token_ids[token_index];
149 switch (token_id) {
148150 .LineComment => {},
149151 .Eof => unreachable,
150152 else => continue,
151153 }
152 if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) {
154 const token_loc = tree.token_locs[token_index];
155 if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) {
153156 fmt_active = true;
154 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) {
157 } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) {
155158 fmt_active = false;
156159 }
157160 }
......@@ -163,8 +166,8 @@ fn renderRoot(
163166 token_index = copy_end_token_index;
164167 while (token_index != 0) {
165168 token_index -= 1;
166 const token = tree.tokens[token_index];
167 switch (token.id) {
169 const token_id = tree.token_ids[token_index];
170 switch (token_id) {
168171 .LineComment => {},
169172 .DocComment => {
170173 copy_end_token_index = token_index;
......@@ -174,8 +177,8 @@ fn renderRoot(
174177 }
175178 }
176179
177 const start = tree.tokens[copy_start_token_index].start;
178 const end = tree.tokens[copy_end_token_index].start;
180 const start = tree.token_locs[copy_start_token_index].start;
181 const end = tree.token_locs[copy_end_token_index].start;
179182 try copyFixingWhitespace(stream, tree.source[start..end]);
180183 }
181184
......@@ -194,13 +197,13 @@ fn renderExtraNewlineToken(tree: *ast.Tree, stream: var, start_col: *usize, firs
194197 var prev_token = first_token;
195198 if (prev_token == 0) return;
196199 var newline_threshold: usize = 2;
197 while (tree.tokens[prev_token - 1].id == .DocComment) {
198 if (tree.tokenLocation(tree.tokens[prev_token - 1].end, prev_token).line == 1) {
200 while (tree.token_ids[prev_token - 1] == .DocComment) {
201 if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) {
199202 newline_threshold += 1;
200203 }
201204 prev_token -= 1;
202205 }
203 const prev_token_end = tree.tokens[prev_token - 1].end;
206 const prev_token_end = tree.token_locs[prev_token - 1].end;
204207 const loc = tree.tokenLocation(prev_token_end, first_token);
205208 if (loc.line >= newline_threshold) {
206209 try stream.writeByte('\n');
......@@ -265,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,
265268
266269 const src_has_trailing_comma = blk: {
267270 const maybe_comma = tree.nextToken(field.lastToken());
268 break :blk tree.tokens[maybe_comma].id == .Comma;
271 break :blk tree.token_ids[maybe_comma] == .Comma;
269272 };
270273
271274 // The trailing comma is emitted at the end, but if it's not present
......@@ -327,11 +330,11 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree,
327330
328331 .DocComment => {
329332 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
330 const kind = tree.tokens[comment.first_line].id;
333 const kind = tree.token_ids[comment.first_line];
331334 try renderToken(tree, stream, comment.first_line, indent, start_col, .Newline);
332335 var tok_i = comment.first_line + 1;
333336 while (true) : (tok_i += 1) {
334 const tok_id = tree.tokens[tok_i].id;
337 const tok_id = tree.token_ids[tok_i];
335338 if (tok_id == kind) {
336339 try stream.writeByteNTimes(' ', indent);
337340 try renderToken(tree, stream, tok_i, indent, start_col, .Newline);
......@@ -436,13 +439,13 @@ fn renderExpression(
436439 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
437440
438441 const after_op_space = blk: {
439 const loc = tree.tokenLocation(tree.tokens[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
442 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
440443 break :blk if (loc.line == 0) op_space else Space.Newline;
441444 };
442445
443446 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
444447 if (after_op_space == Space.Newline and
445 tree.tokens[tree.nextToken(infix_op_node.op_token)].id != .MultilineStringLiteralLine)
448 tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine)
446449 {
447450 try stream.writeByteNTimes(' ', indent + indent_delta);
448451 start_col.* = indent + indent_delta;
......@@ -463,10 +466,10 @@ fn renderExpression(
463466
464467 switch (prefix_op_node.op) {
465468 .PtrType => |ptr_info| {
466 const op_tok_id = tree.tokens[prefix_op_node.op_token].id;
469 const op_tok_id = tree.token_ids[prefix_op_node.op_token];
467470 switch (op_tok_id) {
468471 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
469 .LBracket => if (tree.tokens[prefix_op_node.op_token + 2].id == .Identifier)
472 .LBracket => if (tree.token_ids[prefix_op_node.op_token + 2] == .Identifier)
470473 try stream.writeAll("[*c")
471474 else
472475 try stream.writeAll("[*"),
......@@ -578,8 +581,8 @@ fn renderExpression(
578581
579582 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
580583
581 const starts_with_comment = tree.tokens[lbracket + 1].id == .LineComment;
582 const ends_with_comment = tree.tokens[rbracket - 1].id == .LineComment;
584 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
585 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
583586 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
584587 const new_space = if (ends_with_comment) Space.Newline else Space.None;
585588 try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
......@@ -653,7 +656,7 @@ fn renderExpression(
653656 return renderToken(tree, stream, rtoken, indent, start_col, space);
654657 }
655658
656 if (exprs.len == 1 and tree.tokens[exprs[0].lastToken() + 1].id == .RBrace) {
659 if (exprs.len == 1 and tree.token_ids[exprs[0].lastToken() + 1] == .RBrace) {
657660 const expr = exprs[0];
658661 switch (lhs) {
659662 .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None),
......@@ -675,17 +678,17 @@ fn renderExpression(
675678 for (exprs) |expr, i| {
676679 if (i + 1 < exprs.len) {
677680 const expr_last_token = expr.lastToken() + 1;
678 const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, exprs[i+1].firstToken());
681 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i+1].firstToken());
679682 if (loc.line != 0) break :blk count;
680683 count += 1;
681684 } else {
682685 const expr_last_token = expr.lastToken();
683 const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, rtoken);
686 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken);
684687 if (loc.line == 0) {
685688 // all on one line
686689 const src_has_trailing_comma = trailblk: {
687690 const maybe_comma = tree.prevToken(rtoken);
688 break :trailblk tree.tokens[maybe_comma].id == .Comma;
691 break :trailblk tree.token_ids[maybe_comma] == .Comma;
689692 };
690693 if (src_has_trailing_comma) {
691694 break :blk 1; // force row size 1
......@@ -723,7 +726,7 @@ fn renderExpression(
723726
724727 var new_indent = indent + indent_delta;
725728
726 if (tree.tokens[tree.nextToken(lbrace)].id != .MultilineStringLiteralLine) {
729 if (tree.token_ids[tree.nextToken(lbrace)] != .MultilineStringLiteralLine) {
727730 try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline);
728731 try stream.writeByteNTimes(' ', new_indent);
729732 } else {
......@@ -750,7 +753,7 @@ fn renderExpression(
750753 }
751754 col = 1;
752755
753 if (tree.tokens[tree.nextToken(comma)].id != .MultilineStringLiteralLine) {
756 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
754757 try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
755758 } else {
756759 try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // ,
......@@ -819,11 +822,11 @@ fn renderExpression(
819822
820823 const src_has_trailing_comma = blk: {
821824 const maybe_comma = tree.prevToken(rtoken);
822 break :blk tree.tokens[maybe_comma].id == .Comma;
825 break :blk tree.token_ids[maybe_comma] == .Comma;
823826 };
824827
825828 const src_same_line = blk: {
826 const loc = tree.tokenLocation(tree.tokens[lbrace].end, rtoken);
829 const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken);
827830 break :blk loc.line == 0;
828831 };
829832
......@@ -929,7 +932,7 @@ fn renderExpression(
929932
930933 const src_has_trailing_comma = blk: {
931934 const maybe_comma = tree.prevToken(call.rtoken);
932 break :blk tree.tokens[maybe_comma].id == .Comma;
935 break :blk tree.token_ids[maybe_comma] == .Comma;
933936 };
934937
935938 if (src_has_trailing_comma) {
......@@ -983,8 +986,8 @@ fn renderExpression(
983986 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
984987 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
985988
986 const starts_with_comment = tree.tokens[lbracket + 1].id == .LineComment;
987 const ends_with_comment = tree.tokens[rbracket - 1].id == .LineComment;
989 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
990 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
988991 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
989992 const new_space = if (ends_with_comment) Space.Newline else Space.None;
990993 try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);
......@@ -1226,9 +1229,9 @@ fn renderExpression(
12261229 var maybe_comma = tree.prevToken(container_decl.lastToken());
12271230 // Doc comments for a field may also appear after the comma, eg.
12281231 // field_name: T, // comment attached to field_name
1229 if (tree.tokens[maybe_comma].id == .DocComment)
1232 if (tree.token_ids[maybe_comma] == .DocComment)
12301233 maybe_comma = tree.prevToken(maybe_comma);
1231 break :blk tree.tokens[maybe_comma].id == .Comma;
1234 break :blk tree.token_ids[maybe_comma] == .Comma;
12321235 };
12331236
12341237 const fields_and_decls = container_decl.fieldsAndDecls();
......@@ -1321,7 +1324,7 @@ fn renderExpression(
13211324
13221325 const src_has_trailing_comma = blk: {
13231326 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
1324 break :blk tree.tokens[maybe_comma].id == .Comma;
1327 break :blk tree.token_ids[maybe_comma] == .Comma;
13251328 };
13261329
13271330 if (src_has_trailing_comma) {
......@@ -1353,7 +1356,7 @@ fn renderExpression(
13531356 try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
13541357
13551358 const comma_token = tree.nextToken(node.lastToken());
1356 assert(tree.tokens[comma_token].id == .Comma);
1359 assert(tree.token_ids[comma_token] == .Comma);
13571360 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
13581361 try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
13591362 } else {
......@@ -1378,7 +1381,7 @@ fn renderExpression(
13781381 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
13791382
13801383 var skip_first_indent = true;
1381 if (tree.tokens[multiline_str_literal.firstToken() - 1].id != .LineComment) {
1384 if (tree.token_ids[multiline_str_literal.firstToken() - 1] != .LineComment) {
13821385 try stream.print("\n", .{});
13831386 skip_first_indent = false;
13841387 }
......@@ -1406,7 +1409,7 @@ fn renderExpression(
14061409 if (builtin_call.params_len < 2) break :blk false;
14071410 const last_node = builtin_call.params()[builtin_call.params_len - 1];
14081411 const maybe_comma = tree.nextToken(last_node.lastToken());
1409 break :blk tree.tokens[maybe_comma].id == .Comma;
1412 break :blk tree.token_ids[maybe_comma] == .Comma;
14101413 };
14111414
14121415 const lparen = tree.nextToken(builtin_call.builtin_token);
......@@ -1443,8 +1446,8 @@ fn renderExpression(
14431446 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
14441447
14451448 if (fn_proto.visib_token) |visib_token_index| {
1446 const visib_token = tree.tokens[visib_token_index];
1447 assert(visib_token.id == .Keyword_pub or visib_token.id == .Keyword_export);
1449 const visib_token = tree.token_ids[visib_token_index];
1450 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
14481451
14491452 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
14501453 }
......@@ -1466,7 +1469,7 @@ fn renderExpression(
14661469 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
14671470 break :blk tree.nextToken(fn_proto.fn_token);
14681471 };
1469 assert(tree.tokens[lparen].id == .LParen);
1472 assert(tree.token_ids[lparen] == .LParen);
14701473
14711474 const rparen = tree.prevToken(
14721475 // the first token for the annotation expressions is the left
......@@ -1482,10 +1485,10 @@ fn renderExpression(
14821485 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
14831486 .Invalid => unreachable,
14841487 });
1485 assert(tree.tokens[rparen].id == .RParen);
1488 assert(tree.token_ids[rparen] == .RParen);
14861489
14871490 const src_params_trailing_comma = blk: {
1488 const maybe_comma = tree.tokens[rparen - 1].id;
1491 const maybe_comma = tree.token_ids[rparen - 1];
14891492 break :blk maybe_comma == .Comma or maybe_comma == .LineComment;
14901493 };
14911494
......@@ -1622,7 +1625,7 @@ fn renderExpression(
16221625 const src_has_trailing_comma = blk: {
16231626 const last_node = switch_case.items()[switch_case.items_len - 1];
16241627 const maybe_comma = tree.nextToken(last_node.lastToken());
1625 break :blk tree.tokens[maybe_comma].id == .Comma;
1628 break :blk tree.token_ids[maybe_comma] == .Comma;
16261629 };
16271630
16281631 if (switch_case.items_len == 1 or !src_has_trailing_comma) {
......@@ -1967,7 +1970,7 @@ fn renderExpression(
19671970 try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
19681971 try stream.writeByteNTimes(' ', indent_once);
19691972 const comma_or_colon = tree.nextToken(asm_output.lastToken());
1970 break :blk switch (tree.tokens[comma_or_colon].id) {
1973 break :blk switch (tree.token_ids[comma_or_colon]) {
19711974 .Comma => tree.nextToken(comma_or_colon),
19721975 else => comma_or_colon,
19731976 };
......@@ -2002,7 +2005,7 @@ fn renderExpression(
20022005 try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
20032006 try stream.writeByteNTimes(' ', indent_once);
20042007 const comma_or_colon = tree.nextToken(asm_input.lastToken());
2005 break :blk switch (tree.tokens[comma_or_colon].id) {
2008 break :blk switch (tree.token_ids[comma_or_colon]) {
20062009 .Comma => tree.nextToken(comma_or_colon),
20072010 else => comma_or_colon,
20082011 };
......@@ -2205,7 +2208,7 @@ fn renderStatement(
22052208 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None);
22062209
22072210 const semicolon_index = tree.nextToken(base.lastToken());
2208 assert(tree.tokens[semicolon_index].id == .Semicolon);
2211 assert(tree.token_ids[semicolon_index] == .Semicolon);
22092212 try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline);
22102213 } else {
22112214 try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline);
......@@ -2243,22 +2246,25 @@ fn renderTokenOffset(
22432246 return;
22442247 }
22452248
2246 var token = tree.tokens[token_index];
2247 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));
2249 var token_loc = tree.token_locs[token_index];
2250 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " "));
22482251
22492252 if (space == Space.NoComment)
22502253 return;
22512254
2252 var next_token = tree.tokens[token_index + 1];
2255 var next_token_id = tree.token_ids[token_index + 1];
2256 var next_token_loc = tree.token_locs[token_index + 1];
22532257
2254 if (space == Space.Comma) switch (next_token.id) {
2258 if (space == Space.Comma) switch (next_token_id) {
22552259 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
22562260 .LineComment => {
22572261 try stream.writeAll(", ");
22582262 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
22592263 },
22602264 else => {
2261 if (token_index + 2 < tree.tokens.len and tree.tokens[token_index + 2].id == .MultilineStringLiteralLine) {
2265 if (token_index + 2 < tree.token_ids.len and
2266 tree.token_ids[token_index + 2] == .MultilineStringLiteralLine)
2267 {
22622268 try stream.writeAll(",");
22632269 return;
22642270 } else {
......@@ -2271,19 +2277,20 @@ fn renderTokenOffset(
22712277
22722278 // Skip over same line doc comments
22732279 var offset: usize = 1;
2274 if (next_token.id == .DocComment) {
2275 const loc = tree.tokenLocationPtr(token.end, next_token);
2280 if (next_token_id == .DocComment) {
2281 const loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
22762282 if (loc.line == 0) {
22772283 offset += 1;
2278 next_token = tree.tokens[token_index + offset];
2284 next_token_id = tree.token_ids[token_index + offset];
2285 next_token_loc = tree.token_locs[token_index + offset];
22792286 }
22802287 }
22812288
2282 if (next_token.id != .LineComment) blk: {
2289 if (next_token_id != .LineComment) blk: {
22832290 switch (space) {
22842291 Space.None, Space.NoNewline => return,
22852292 Space.Newline => {
2286 if (next_token.id == .MultilineStringLiteralLine) {
2293 if (next_token_id == .MultilineStringLiteralLine) {
22872294 return;
22882295 } else {
22892296 try stream.writeAll("\n");
......@@ -2292,7 +2299,7 @@ fn renderTokenOffset(
22922299 }
22932300 },
22942301 Space.Space, Space.SpaceOrOutdent => {
2295 if (next_token.id == .MultilineStringLiteralLine)
2302 if (next_token_id == .MultilineStringLiteralLine)
22962303 return;
22972304 try stream.writeByte(' ');
22982305 return;
......@@ -2302,14 +2309,15 @@ fn renderTokenOffset(
23022309 }
23032310
23042311 while (true) {
2305 const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2;
2312 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ").len == 2;
23062313 if (comment_is_empty) {
23072314 switch (space) {
23082315 Space.Newline => {
23092316 offset += 1;
2310 token = next_token;
2311 next_token = tree.tokens[token_index + offset];
2312 if (next_token.id != .LineComment) {
2317 token_loc = next_token_loc;
2318 next_token_id = tree.token_ids[token_index + offset];
2319 next_token_loc = tree.token_locs[token_index + offset];
2320 if (next_token_id != .LineComment) {
23132321 try stream.writeByte('\n');
23142322 start_col.* = 0;
23152323 return;
......@@ -2322,18 +2330,19 @@ fn renderTokenOffset(
23222330 }
23232331 }
23242332
2325 var loc = tree.tokenLocationPtr(token.end, next_token);
2333 var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
23262334 if (loc.line == 0) {
2327 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")});
2335 try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")});
23282336 offset = 2;
2329 token = next_token;
2330 next_token = tree.tokens[token_index + offset];
2331 if (next_token.id != .LineComment) {
2337 token_loc = next_token_loc;
2338 next_token_loc = tree.token_locs[token_index + offset];
2339 next_token_id = tree.token_ids[token_index + offset];
2340 if (next_token_id != .LineComment) {
23322341 switch (space) {
23332342 Space.None, Space.Space => {
23342343 try stream.writeByte('\n');
2335 const after_comment_token = tree.tokens[token_index + offset];
2336 const next_line_indent = switch (after_comment_token.id) {
2344 const after_comment_token = tree.token_ids[token_index + offset];
2345 const next_line_indent = switch (after_comment_token) {
23372346 .RParen, .RBrace, .RBracket => indent,
23382347 else => indent + indent_delta,
23392348 };
......@@ -2346,7 +2355,7 @@ fn renderTokenOffset(
23462355 start_col.* = indent;
23472356 },
23482357 Space.Newline => {
2349 if (next_token.id == .MultilineStringLiteralLine) {
2358 if (next_token_id == .MultilineStringLiteralLine) {
23502359 return;
23512360 } else {
23522361 try stream.writeAll("\n");
......@@ -2359,7 +2368,7 @@ fn renderTokenOffset(
23592368 }
23602369 return;
23612370 }
2362 loc = tree.tokenLocationPtr(token.end, next_token);
2371 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
23632372 }
23642373
23652374 while (true) {
......@@ -2369,15 +2378,16 @@ fn renderTokenOffset(
23692378 const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2);
23702379 try stream.writeByteNTimes('\n', newline_count);
23712380 try stream.writeByteNTimes(' ', indent);
2372 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
2381 try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " "));
23732382
23742383 offset += 1;
2375 token = next_token;
2376 next_token = tree.tokens[token_index + offset];
2377 if (next_token.id != .LineComment) {
2384 token_loc = next_token_loc;
2385 next_token_loc = tree.token_locs[token_index + offset];
2386 next_token_id = tree.token_ids[token_index + offset];
2387 if (next_token_id != .LineComment) {
23782388 switch (space) {
23792389 Space.Newline => {
2380 if (next_token.id == .MultilineStringLiteralLine) {
2390 if (next_token_id == .MultilineStringLiteralLine) {
23812391 return;
23822392 } else {
23832393 try stream.writeAll("\n");
......@@ -2388,8 +2398,8 @@ fn renderTokenOffset(
23882398 Space.None, Space.Space => {
23892399 try stream.writeByte('\n');
23902400
2391 const after_comment_token = tree.tokens[token_index + offset];
2392 const next_line_indent = switch (after_comment_token.id) {
2401 const after_comment_token = tree.token_ids[token_index + offset];
2402 const next_line_indent = switch (after_comment_token) {
23932403 .RParen, .RBrace, .RBracket => blk: {
23942404 if (indent > indent_delta) {
23952405 break :blk indent - indent_delta;
......@@ -2412,7 +2422,7 @@ fn renderTokenOffset(
24122422 }
24132423 return;
24142424 }
2415 loc = tree.tokenLocationPtr(token.end, next_token);
2425 loc = tree.tokenLocationLoc(token_loc.end, next_token_loc);
24162426 }
24172427}
24182428
......@@ -2448,7 +2458,7 @@ fn renderDocCommentsToken(
24482458) (@TypeOf(stream).Error || Error)!void {
24492459 var tok_i = comment.first_line;
24502460 while (true) : (tok_i += 1) {
2451 switch (tree.tokens[tok_i].id) {
2461 switch (tree.token_ids[tok_i]) {
24522462 .DocComment, .ContainerDocComment => {
24532463 if (comment.first_line < first_token) {
24542464 try renderToken(tree, stream, tok_i, indent, start_col, Space.Newline);
lib/std/zig/tokenizer.zig+18-10
......@@ -3,8 +3,12 @@ const mem = std.mem;
33
44pub const Token = struct {
55 id: Id,
6 start: usize,
7 end: usize,
6 loc: Loc,
7
8 pub const Loc = struct {
9 start: usize,
10 end: usize,
11 };
812
913 pub const Keyword = struct {
1014 bytes: []const u8,
......@@ -426,8 +430,10 @@ pub const Tokenizer = struct {
426430 var state: State = .start;
427431 var result = Token{
428432 .id = .Eof,
429 .start = self.index,
430 .end = undefined,
433 .loc = .{
434 .start = self.index,
435 .end = undefined,
436 },
431437 };
432438 var seen_escape_digits: usize = undefined;
433439 var remaining_code_units: usize = undefined;
......@@ -436,7 +442,7 @@ pub const Tokenizer = struct {
436442 switch (state) {
437443 .start => switch (c) {
438444 ' ', '\n', '\t', '\r' => {
439 result.start = self.index + 1;
445 result.loc.start = self.index + 1;
440446 },
441447 '"' => {
442448 state = .string_literal;
......@@ -686,7 +692,7 @@ pub const Tokenizer = struct {
686692 .identifier => switch (c) {
687693 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
688694 else => {
689 if (Token.getKeyword(self.buffer[result.start..self.index])) |id| {
695 if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| {
690696 result.id = id;
691697 }
692698 break;
......@@ -1313,7 +1319,7 @@ pub const Tokenizer = struct {
13131319 => {},
13141320
13151321 .identifier => {
1316 if (Token.getKeyword(self.buffer[result.start..self.index])) |id| {
1322 if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| {
13171323 result.id = id;
13181324 }
13191325 },
......@@ -1420,7 +1426,7 @@ pub const Tokenizer = struct {
14201426 }
14211427 }
14221428
1423 result.end = self.index;
1429 result.loc.end = self.index;
14241430 return result;
14251431 }
14261432
......@@ -1430,8 +1436,10 @@ pub const Tokenizer = struct {
14301436 if (invalid_length == 0) return;
14311437 self.pending_invalid_token = .{
14321438 .id = .Invalid,
1433 .start = self.index,
1434 .end = self.index + invalid_length,
1439 .loc = .{
1440 .start = self.index,
1441 .end = self.index + invalid_length,
1442 },
14351443 };
14361444 }
14371445
src-self-hosted/translate_c.zig-21
......@@ -247,27 +247,6 @@ pub const Context = struct {
247247 }
248248 };
249249
250 /// Helper function to append items to a singly linked list.
251 fn llpusher(c: *Context, list: *std.SinglyLinkedList(*ast.Node)) LinkedListPusher {
252 assert(list.first == null);
253 return .{
254 .c = c,
255 .it = &list.first,
256 };
257 }
258
259 fn llpush(
260 c: *Context,
261 comptime T: type,
262 it: *?*std.SinglyLinkedList(T).Node,
263 data: T,
264 ) !*?*std.SinglyLinkedList(T).Node {
265 const llnode = try c.arena.create(std.SinglyLinkedList(T).Node);
266 llnode.* = .{ .data = data };
267 it.* = llnode;
268 return &llnode.next;
269 }
270
271250 fn getMangle(c: *Context) u32 {
272251 c.mangle_count += 1;
273252 return c.mangle_count;