3379 lines
129 KiB
Zig
3379 lines
129 KiB
Zig
|
// SPDX-License-Identifier: MIT
|
||
|
// Copyright (c) 2015-2020 Zig Contributors
|
||
|
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||
|
// The MIT license requires this copyright notice to be included in all copies
|
||
|
// and substantial portions of the software.
|
||
|
const std = @import("std");
|
||
|
const assert = std.debug.assert;
|
||
|
const Allocator = std.mem.Allocator;
|
||
|
const ast = @import("ast.zig");
|
||
|
const Node = ast.Node;
|
||
|
const Tree = ast.Tree;
|
||
|
const AstError = ast.Error;
|
||
|
const TokenIndex = ast.TokenIndex;
|
||
|
const NodeIndex = ast.NodeIndex;
|
||
|
|
||
|
const lexer = @import("tokenizer.zig");
|
||
|
const Token = lexer.Token;
|
||
|
const Tokenizer = lexer.Tokenizer;
|
||
|
|
||
|
pub const Error = error{ParseError} || Allocator.Error;
|
||
|
|
||
|
/// Result should be freed with tree.deinit() when there are
|
||
|
/// no more references to any of the tokens or nodes.
|
||
|
pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree {
|
||
|
|
||
|
var token_ids = std.ArrayList(Token.Id).init(gpa);
|
||
|
defer token_ids.deinit();
|
||
|
var token_locs = std.ArrayList(Token.Loc).init(gpa);
|
||
|
defer token_locs.deinit();
|
||
|
|
||
|
// Before starting, just check that we have about enough memory.
|
||
|
const estimated_token_count = source.len / 8;
|
||
|
try token_ids.ensureCapacity(estimated_token_count);
|
||
|
try token_locs.ensureCapacity(estimated_token_count);
|
||
|
|
||
|
// Use the lexer to get all the tokens from the source code.
|
||
|
var tokenizer = Tokenizer.init(source);
|
||
|
while (true) {
|
||
|
const token = tokenizer.next();
|
||
|
try token_ids.append(token.id);
|
||
|
try token_locs.append(token.loc);
|
||
|
if (token.id == .Eof) break;
|
||
|
}
|
||
|
|
||
|
// Create a Parser structure.
|
||
|
var parser: Parser = .{
|
||
|
.source = source, // Source code.
|
||
|
.arena = std.heap.ArenaAllocator.init(gpa), // Arena allocator.
|
||
|
.gpa = gpa, // General Purpose Allocator.
|
||
|
.token_ids = token_ids.items, // IDs of the tokens.
|
||
|
.token_locs = token_locs.items, // Location of the tokens.
|
||
|
.errors = .{}, // List of errors in our parsing.
|
||
|
.tok_i = 0, // Index of current token being analyzed.
|
||
|
};
|
||
|
defer parser.errors.deinit(gpa);
|
||
|
errdefer parser.arena.deinit();
|
||
|
|
||
|
// Ignore the first line comments from our code.
|
||
|
while (token_ids.items[parser.tok_i] == .LineComment) parser.tok_i += 1;
|
||
|
|
||
|
// Perform parsing, called once.
|
||
|
const root_node = try parser.parseRoot();
|
||
|
|
||
|
// Create a parsing Tree, with the nodes parsed early on.
|
||
|
// toOwnedSlice: free the memory and return the list. Arrays are empty,
|
||
|
// allocator can be free, arrays are owned by a different allocator.
|
||
|
const tree = try parser.arena.allocator.create(Tree);
|
||
|
tree.* = .{
|
||
|
.gpa = gpa,
|
||
|
.source = source,
|
||
|
.token_ids = token_ids.toOwnedSlice(),
|
||
|
.token_locs = token_locs.toOwnedSlice(),
|
||
|
.errors = parser.errors.toOwnedSlice(gpa),
|
||
|
.root_node = root_node,
|
||
|
.arena = parser.arena.state,
|
||
|
};
|
||
|
return tree;
|
||
|
}
|
||
|
|
||
|
/// Represents in-progress parsing, will be converted to an ast.Tree after completion.
|
||
|
const Parser = struct {
|
||
|
arena: std.heap.ArenaAllocator,
|
||
|
gpa: *Allocator,
|
||
|
source: []const u8,
|
||
|
token_ids: []const Token.Id,
|
||
|
token_locs: []const Token.Loc,
|
||
|
tok_i: TokenIndex,
|
||
|
errors: std.ArrayListUnmanaged(AstError),
|
||
|
|
||
|
/// Root <- skip ContainerMembers eof
|
||
|
fn parseRoot(p: *Parser) Allocator.Error!*Node.Root {
|
||
|
// Parse declarations.
|
||
|
const decls = try parseContainerMembers(p, true);
|
||
|
defer p.gpa.free(decls);
|
||
|
|
||
|
// parseContainerMembers will try to skip as much
|
||
|
// invalid tokens as it can so this can only be the EOF
|
||
|
// eatToken returns next token or null (if current token id isn't parameter).
|
||
|
// If current token is .Eof, next token is actually the first.
|
||
|
const eof_token = p.eatToken(.Eof).?;
|
||
|
|
||
|
// Nb of declarations becomes an ast.NodeIndex integer variable (usize).
|
||
|
const decls_len = @intCast(NodeIndex, decls.len);
|
||
|
const node = try Node.Root.create(&p.arena.allocator, decls_len, eof_token);
|
||
|
// std.mem.copy: T, dest, src
|
||
|
std.mem.copy(*Node, node.decls(), decls);
|
||
|
|
||
|
return node; // Root node.
|
||
|
}
|
||
|
|
||
|
/// ContainerMembers
|
||
|
/// <- TestDecl ContainerMembers
|
||
|
/// / TopLevelComptime ContainerMembers
|
||
|
/// / KEYWORD_pub? TopLevelDecl ContainerMembers
|
||
|
/// / ContainerField COMMA ContainerMembers
|
||
|
/// / ContainerField
|
||
|
/// /
|
||
|
// parseContainerMembers: actual parsing code starts here.
|
||
|
fn parseContainerMembers(p: *Parser, top_level: bool) ![]*Node {
|
||
|
std.debug.print("parseContainerMembers: is top? {}\n", .{top_level});
|
||
|
// list: all nodes in the ast.
|
||
|
var list = std.ArrayList(*Node).init(p.gpa);
|
||
|
defer list.deinit();
|
||
|
|
||
|
// field_state: union of enum.
|
||
|
// Tagged union: eligible to use in switch expressions and coerce their value.
|
||
|
// Example: switch (some_tagged_union) { SomeType => |value| print("{}\n", value); }
|
||
|
// If a '*' is placed before the variable name, it's a pointer to the value inside
|
||
|
// the tagged union.
|
||
|
// Example: switch (some_tagged_union) { SomeType => |*value| value.* += 1; }
|
||
|
// @TagType can be used to get the right enum type.
|
||
|
var field_state: union(enum) {
|
||
|
/// no fields have been seen
|
||
|
none,
|
||
|
/// currently parsing fields
|
||
|
seen,
|
||
|
/// saw fields and then a declaration after them.
|
||
|
/// payload is first token of previous declaration.
|
||
|
end: TokenIndex, // TokenIndex is defined as usize in std.zig.ast.
|
||
|
/// there was a declaration between fields, don't report more errors
|
||
|
err,
|
||
|
} = .none;
|
||
|
|
||
|
// True start of parsing.
|
||
|
while (true) {
|
||
|
const token = p.nextToken();
|
||
|
switch (p.token_ids[token]) {
|
||
|
.Eof => {
|
||
|
p.putBackToken(token);
|
||
|
break;
|
||
|
},
|
||
|
else => {
|
||
|
std.debug.print("token: {}\n", .{p.token_ids[token]});
|
||
|
continue;
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// // Documentation comments. Ignored.
|
||
|
// if (try p.parseContainerDocComments()) |node| {
|
||
|
// std.debug.print("found: Doc Comments: {}\n", .{node});
|
||
|
// try list.append(node);
|
||
|
// continue;
|
||
|
// }
|
||
|
//
|
||
|
// const doc_comments = try p.parseDocComment();
|
||
|
//
|
||
|
// if (p.parseContainerField() catch |err| switch (err) {
|
||
|
// error.OutOfMemory => return error.OutOfMemory,
|
||
|
// error.ParseError => {
|
||
|
// // attempt to recover
|
||
|
// p.findNextContainerMember();
|
||
|
// continue;
|
||
|
// },
|
||
|
// }) |node| {
|
||
|
// std.debug.print("found: ContainerField: {}\n", .{node});
|
||
|
// switch (field_state) {
|
||
|
// .none => field_state = .seen,
|
||
|
// .err, .seen => {},
|
||
|
// .end => |tok| {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .DeclBetweenFields = .{ .token = tok },
|
||
|
// });
|
||
|
// // continue parsing, error will be reported later
|
||
|
// field_state = .err;
|
||
|
// },
|
||
|
// }
|
||
|
//
|
||
|
// const field = node.cast(Node.ContainerField).?;
|
||
|
// field.doc_comments = doc_comments;
|
||
|
// try list.append(node);
|
||
|
// const comma = p.eatToken(.Comma) orelse {
|
||
|
// // try to continue parsing
|
||
|
// const index = p.tok_i;
|
||
|
// p.findNextContainerMember();
|
||
|
// const next = p.token_ids[p.tok_i];
|
||
|
// switch (next) {
|
||
|
// .Eof => {
|
||
|
// // no invalid tokens were found
|
||
|
// if (index == p.tok_i) break;
|
||
|
//
|
||
|
// // Invalid tokens, add error and exit
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedToken = .{ .token = index, .expected_id = .Comma },
|
||
|
// });
|
||
|
// break;
|
||
|
// },
|
||
|
// else => {
|
||
|
// if (next == .RBrace) {
|
||
|
// if (!top_level) break;
|
||
|
// _ = p.nextToken();
|
||
|
// }
|
||
|
//
|
||
|
// // add error and continue
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedToken = .{ .token = index, .expected_id = .Comma },
|
||
|
// });
|
||
|
// continue;
|
||
|
// },
|
||
|
// }
|
||
|
// };
|
||
|
// if (try p.parseAppendedDocComment(comma)) |appended_comment|
|
||
|
// field.doc_comments = appended_comment;
|
||
|
// continue;
|
||
|
// }
|
||
|
//
|
||
|
// // Dangling doc comment
|
||
|
// if (doc_comments != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },
|
||
|
// });
|
||
|
// }
|
||
|
//
|
||
|
// const next = p.token_ids[p.tok_i];
|
||
|
// switch (next) {
|
||
|
// .Eof => break,
|
||
|
// .Keyword_comptime => {
|
||
|
// _ = p.nextToken();
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedBlockOrField = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// },
|
||
|
// else => {
|
||
|
// const index = p.tok_i;
|
||
|
// if (next == .RBrace) {
|
||
|
// if (!top_level) break;
|
||
|
// _ = p.nextToken();
|
||
|
// }
|
||
|
//
|
||
|
// // this was likely not supposed to end yet,
|
||
|
// // try to find the next declaration
|
||
|
// p.findNextContainerMember();
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedContainerMembers = .{ .token = index },
|
||
|
// });
|
||
|
// },
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
return list.toOwnedSlice();
|
||
|
}
|
||
|
|
||
|
// /// Attempts to find next container member by searching for certain tokens
|
||
|
// fn findNextContainerMember(p: *Parser) void {
|
||
|
// var level: u32 = 0;
|
||
|
// while (true) {
|
||
|
// const tok = p.nextToken();
|
||
|
// switch (p.token_ids[tok]) {
|
||
|
// // any of these can start a new top level declaration
|
||
|
// .Keyword_test,
|
||
|
// .Keyword_comptime,
|
||
|
// .Keyword_pub,
|
||
|
// .Keyword_export,
|
||
|
// .Keyword_extern,
|
||
|
// .Keyword_inline,
|
||
|
// .Keyword_noinline,
|
||
|
// .Keyword_usingnamespace,
|
||
|
// .Keyword_threadlocal,
|
||
|
// .Keyword_const,
|
||
|
// .Keyword_var,
|
||
|
// .Keyword_fn,
|
||
|
// .Identifier,
|
||
|
// => {
|
||
|
// if (level == 0) {
|
||
|
// p.putBackToken(tok);
|
||
|
// return;
|
||
|
// }
|
||
|
// },
|
||
|
// .Comma, .Semicolon => {
|
||
|
// // this decl was likely meant to end here
|
||
|
// if (level == 0) {
|
||
|
// return;
|
||
|
// }
|
||
|
// },
|
||
|
// .LParen, .LBracket, .LBrace => level += 1,
|
||
|
// .RParen, .RBracket => {
|
||
|
// if (level != 0) level -= 1;
|
||
|
// },
|
||
|
// .RBrace => {
|
||
|
// if (level == 0) {
|
||
|
// // end of container, exit
|
||
|
// p.putBackToken(tok);
|
||
|
// return;
|
||
|
// }
|
||
|
// level -= 1;
|
||
|
// },
|
||
|
// .Eof => {
|
||
|
// p.putBackToken(tok);
|
||
|
// return;
|
||
|
// },
|
||
|
// else => {},
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// /// Attempts to find the next statement by searching for a semicolon
|
||
|
// fn findNextStmt(p: *Parser) void {
|
||
|
// var level: u32 = 0;
|
||
|
// while (true) {
|
||
|
// const tok = p.nextToken();
|
||
|
// switch (p.token_ids[tok]) {
|
||
|
// .LBrace => level += 1,
|
||
|
// .RBrace => {
|
||
|
// if (level == 0) {
|
||
|
// p.putBackToken(tok);
|
||
|
// return;
|
||
|
// }
|
||
|
// level -= 1;
|
||
|
// },
|
||
|
// .Semicolon => {
|
||
|
// if (level == 0) {
|
||
|
// return;
|
||
|
// }
|
||
|
// },
|
||
|
// .Eof => {
|
||
|
// p.putBackToken(tok);
|
||
|
// return;
|
||
|
// },
|
||
|
// else => {},
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// /// Eat a multiline container doc comment
|
||
|
// fn parseContainerDocComments(p: *Parser) !?*Node {
|
||
|
// if (p.eatToken(.ContainerDocComment)) |first_line| {
|
||
|
// while (p.eatToken(.ContainerDocComment)) |_| {}
|
||
|
// const node = try p.arena.allocator.create(Node.DocComment);
|
||
|
// node.* = .{ .first_line = first_line };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// TopLevelComptime <- KEYWORD_comptime BlockExpr
|
||
|
// fn parseTopLevelComptime(p: *Parser) !?*Node {
|
||
|
// const tok = p.eatToken(.Keyword_comptime) orelse return null;
|
||
|
// const lbrace = p.eatToken(.LBrace) orelse {
|
||
|
// p.putBackToken(tok);
|
||
|
// return null;
|
||
|
// };
|
||
|
// p.putBackToken(lbrace);
|
||
|
// const block_node = try p.expectNode(parseBlockExpr, .{
|
||
|
// .ExpectedLabelOrLBrace = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const comptime_node = try p.arena.allocator.create(Node.Comptime);
|
||
|
// comptime_node.* = .{
|
||
|
// .doc_comments = null,
|
||
|
// .comptime_token = tok,
|
||
|
// .expr = block_node,
|
||
|
// };
|
||
|
// return &comptime_node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
|
||
|
// fn parseFnProto(p: *Parser, level: enum { top_level, as_type }, fields: struct {
|
||
|
// doc_comments: ?*Node.DocComment = null,
|
||
|
// visib_token: ?TokenIndex = null,
|
||
|
// extern_export_inline_token: ?TokenIndex = null,
|
||
|
// lib_name: ?*Node = null,
|
||
|
// }) !?*Node {
|
||
|
// // TODO: Remove once extern/async fn rewriting is
|
||
|
// var is_async: ?void = null;
|
||
|
// var is_extern_prototype: ?void = null;
|
||
|
// const cc_token: ?TokenIndex = blk: {
|
||
|
// if (p.eatToken(.Keyword_extern)) |token| {
|
||
|
// is_extern_prototype = {};
|
||
|
// break :blk token;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_async)) |token| {
|
||
|
// is_async = {};
|
||
|
// break :blk token;
|
||
|
// }
|
||
|
// break :blk null;
|
||
|
// };
|
||
|
// const fn_token = p.eatToken(.Keyword_fn) orelse {
|
||
|
// if (cc_token) |token|
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// };
|
||
|
// const name_token = p.eatToken(.Identifier);
|
||
|
// const lparen = try p.expectToken(.LParen);
|
||
|
// const params = try p.parseParamDeclList();
|
||
|
// defer p.gpa.free(params);
|
||
|
// const var_args_token = p.eatToken(.Ellipsis3);
|
||
|
// const rparen = try p.expectToken(.RParen);
|
||
|
// const align_expr = try p.parseByteAlign();
|
||
|
// const section_expr = try p.parseLinkSection();
|
||
|
// const callconv_expr = try p.parseCallconv();
|
||
|
// const exclamation_token = p.eatToken(.Bang);
|
||
|
//
|
||
|
// const return_type_expr = (try p.parseAnyType()) orelse
|
||
|
// try p.expectNodeRecoverable(parseTypeExpr, .{
|
||
|
// // most likely the user forgot to specify the return type.
|
||
|
// // Mark return type as invalid and try to continue.
|
||
|
// .ExpectedReturnType = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// // TODO https://github.com/ziglang/zig/issues/3750
|
||
|
// const R = Node.FnProto.ReturnType;
|
||
|
// const return_type = if (return_type_expr == null)
|
||
|
// R{ .Invalid = rparen }
|
||
|
// else if (exclamation_token != null)
|
||
|
// R{ .InferErrorSet = return_type_expr.? }
|
||
|
// else
|
||
|
// R{ .Explicit = return_type_expr.? };
|
||
|
//
|
||
|
// const body_node: ?*Node = switch (level) {
|
||
|
// .top_level => blk: {
|
||
|
// if (p.eatToken(.Semicolon)) |_| {
|
||
|
// break :blk null;
|
||
|
// }
|
||
|
// const body_block = (try p.parseBlock(null)) orelse {
|
||
|
// // Since parseBlock only return error.ParseError on
|
||
|
// // a missing '}' we can assume this function was
|
||
|
// // supposed to end here.
|
||
|
// try p.errors.append(p.gpa, .{ .ExpectedSemiOrLBrace = .{ .token = p.tok_i } });
|
||
|
// break :blk null;
|
||
|
// };
|
||
|
// break :blk body_block;
|
||
|
// },
|
||
|
// .as_type => null,
|
||
|
// };
|
||
|
//
|
||
|
// const fn_proto_node = try Node.FnProto.create(&p.arena.allocator, .{
|
||
|
// .params_len = params.len,
|
||
|
// .fn_token = fn_token,
|
||
|
// .return_type = return_type,
|
||
|
// }, .{
|
||
|
// .doc_comments = fields.doc_comments,
|
||
|
// .visib_token = fields.visib_token,
|
||
|
// .name_token = name_token,
|
||
|
// .var_args_token = var_args_token,
|
||
|
// .extern_export_inline_token = fields.extern_export_inline_token,
|
||
|
// .body_node = body_node,
|
||
|
// .lib_name = fields.lib_name,
|
||
|
// .align_expr = align_expr,
|
||
|
// .section_expr = section_expr,
|
||
|
// .callconv_expr = callconv_expr,
|
||
|
// .is_extern_prototype = is_extern_prototype,
|
||
|
// .is_async = is_async,
|
||
|
// });
|
||
|
// std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
|
||
|
//
|
||
|
// return &fn_proto_node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
|
||
|
// fn parseVarDecl(p: *Parser, fields: struct {
|
||
|
// doc_comments: ?*Node.DocComment = null,
|
||
|
// visib_token: ?TokenIndex = null,
|
||
|
// thread_local_token: ?TokenIndex = null,
|
||
|
// extern_export_token: ?TokenIndex = null,
|
||
|
// lib_name: ?*Node = null,
|
||
|
// comptime_token: ?TokenIndex = null,
|
||
|
// }) !?*Node {
|
||
|
// const mut_token = p.eatToken(.Keyword_const) orelse
|
||
|
// p.eatToken(.Keyword_var) orelse
|
||
|
// return null;
|
||
|
//
|
||
|
// const name_token = try p.expectToken(.Identifier);
|
||
|
// const type_node = if (p.eatToken(.Colon) != null)
|
||
|
// try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// })
|
||
|
// else
|
||
|
// null;
|
||
|
// const align_node = try p.parseByteAlign();
|
||
|
// const section_node = try p.parseLinkSection();
|
||
|
// const eq_token = p.eatToken(.Equal);
|
||
|
// const init_node = if (eq_token != null) blk: {
|
||
|
// break :blk try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// } else null;
|
||
|
// const semicolon_token = try p.expectToken(.Semicolon);
|
||
|
//
|
||
|
// const doc_comments = fields.doc_comments orelse try p.parseAppendedDocComment(semicolon_token);
|
||
|
//
|
||
|
// const node = try Node.VarDecl.create(&p.arena.allocator, .{
|
||
|
// .mut_token = mut_token,
|
||
|
// .name_token = name_token,
|
||
|
// .semicolon_token = semicolon_token,
|
||
|
// }, .{
|
||
|
// .doc_comments = doc_comments,
|
||
|
// .visib_token = fields.visib_token,
|
||
|
// .thread_local_token = fields.thread_local_token,
|
||
|
// .eq_token = eq_token,
|
||
|
// .comptime_token = fields.comptime_token,
|
||
|
// .extern_export_token = fields.extern_export_token,
|
||
|
// .lib_name = fields.lib_name,
|
||
|
// .type_node = type_node,
|
||
|
// .align_node = align_node,
|
||
|
// .section_node = section_node,
|
||
|
// .init_node = init_node,
|
||
|
// });
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
|
||
|
// fn parseContainerField(p: *Parser) !?*Node {
|
||
|
// const comptime_token = p.eatToken(.Keyword_comptime);
|
||
|
// const name_token = p.eatToken(.Identifier) orelse {
|
||
|
// if (comptime_token) |t| p.putBackToken(t);
|
||
|
// return null;
|
||
|
// };
|
||
|
//
|
||
|
// var align_expr: ?*Node = null;
|
||
|
// var type_expr: ?*Node = null;
|
||
|
// if (p.eatToken(.Colon)) |_| {
|
||
|
// if (p.eatToken(.Keyword_anytype) orelse p.eatToken(.Keyword_var)) |anytype_tok| {
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .AnyType },
|
||
|
// .token = anytype_tok,
|
||
|
// };
|
||
|
// type_expr = &node.base;
|
||
|
// } else {
|
||
|
// type_expr = try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// align_expr = try p.parseByteAlign();
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// const value_expr = if (p.eatToken(.Equal)) |_|
|
||
|
// try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// })
|
||
|
// else
|
||
|
// null;
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.ContainerField);
|
||
|
// node.* = .{
|
||
|
// .doc_comments = null,
|
||
|
// .comptime_token = comptime_token,
|
||
|
// .name_token = name_token,
|
||
|
// .type_expr = type_expr,
|
||
|
// .value_expr = value_expr,
|
||
|
// .align_expr = align_expr,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// Statement
|
||
|
// /// <- KEYWORD_comptime? VarDecl
|
||
|
// /// / KEYWORD_comptime BlockExprStatement
|
||
|
// /// / KEYWORD_nosuspend BlockExprStatement
|
||
|
// /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
|
||
|
// /// / KEYWORD_defer BlockExprStatement
|
||
|
// /// / KEYWORD_errdefer Payload? BlockExprStatement
|
||
|
// /// / IfStatement
|
||
|
// /// / LabeledStatement
|
||
|
// /// / SwitchExpr
|
||
|
// /// / AssignExpr SEMICOLON
|
||
|
// fn parseStatement(p: *Parser) Error!?*Node {
|
||
|
// const comptime_token = p.eatToken(.Keyword_comptime);
|
||
|
//
|
||
|
// if (try p.parseVarDecl(.{
|
||
|
// .comptime_token = comptime_token,
|
||
|
// })) |node| {
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (comptime_token) |token| {
|
||
|
// const block_expr = try p.expectNode(parseBlockExprStatement, .{
|
||
|
// .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.Comptime);
|
||
|
// node.* = .{
|
||
|
// .doc_comments = null,
|
||
|
// .comptime_token = token,
|
||
|
// .expr = block_expr,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_nosuspend)) |nosuspend_token| {
|
||
|
// const block_expr = try p.expectNode(parseBlockExprStatement, .{
|
||
|
// .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.Nosuspend);
|
||
|
// node.* = .{
|
||
|
// .nosuspend_token = nosuspend_token,
|
||
|
// .expr = block_expr,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_suspend)) |suspend_token| {
|
||
|
// const semicolon = p.eatToken(.Semicolon);
|
||
|
//
|
||
|
// const body_node = if (semicolon == null) blk: {
|
||
|
// break :blk try p.expectNode(parseBlockExprStatement, .{
|
||
|
// .ExpectedBlockOrExpression = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// } else null;
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.Suspend);
|
||
|
// node.* = .{
|
||
|
// .suspend_token = suspend_token,
|
||
|
// .body = body_node,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// const defer_token = p.eatToken(.Keyword_defer) orelse p.eatToken(.Keyword_errdefer);
|
||
|
// if (defer_token) |token| {
|
||
|
// const payload = if (p.token_ids[token] == .Keyword_errdefer)
|
||
|
// try p.parsePayload()
|
||
|
// else
|
||
|
// null;
|
||
|
// const expr_node = try p.expectNode(parseBlockExprStatement, .{
|
||
|
// .ExpectedBlockOrExpression = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const node = try p.arena.allocator.create(Node.Defer);
|
||
|
// node.* = .{
|
||
|
// .defer_token = token,
|
||
|
// .expr = expr_node,
|
||
|
// .payload = payload,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseIfStatement()) |node| return node;
|
||
|
// if (try p.parseLabeledStatement()) |node| return node;
|
||
|
// if (try p.parseSwitchExpr()) |node| return node;
|
||
|
// if (try p.parseAssignExpr()) |node| {
|
||
|
// _ = try p.expectTokenRecoverable(.Semicolon);
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// IfStatement
|
||
|
// /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
|
||
|
// /// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
|
||
|
// fn parseIfStatement(p: *Parser) !?*Node {
|
||
|
// const if_node = (try p.parseIfPrefix()) orelse return null;
|
||
|
// const if_prefix = if_node.cast(Node.If).?;
|
||
|
//
|
||
|
// const block_expr = (try p.parseBlockExpr());
|
||
|
// const assign_expr = if (block_expr == null)
|
||
|
// try p.expectNode(parseAssignExpr, .{
|
||
|
// .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
|
||
|
// })
|
||
|
// else
|
||
|
// null;
|
||
|
//
|
||
|
// const semicolon = if (assign_expr != null) p.eatToken(.Semicolon) else null;
|
||
|
//
|
||
|
// const else_node = if (semicolon == null) blk: {
|
||
|
// const else_token = p.eatToken(.Keyword_else) orelse break :blk null;
|
||
|
// const payload = try p.parsePayload();
|
||
|
// const else_body = try p.expectNode(parseStatement, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.Else);
|
||
|
// node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = payload,
|
||
|
// .body = else_body,
|
||
|
// };
|
||
|
//
|
||
|
// break :blk node;
|
||
|
// } else null;
|
||
|
//
|
||
|
// if (block_expr) |body| {
|
||
|
// if_prefix.body = body;
|
||
|
// if_prefix.@"else" = else_node;
|
||
|
// return if_node;
|
||
|
// }
|
||
|
//
|
||
|
// if (assign_expr) |body| {
|
||
|
// if_prefix.body = body;
|
||
|
// if (semicolon != null) return if_node;
|
||
|
// if (else_node != null) {
|
||
|
// if_prefix.@"else" = else_node;
|
||
|
// return if_node;
|
||
|
// }
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedSemiOrElse = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// }
|
||
|
//
|
||
|
// return if_node;
|
||
|
// }
|
||
|
//
|
||
|
// /// LabeledStatement <- BlockLabel? (Block / LoopStatement)
|
||
|
// fn parseLabeledStatement(p: *Parser) !?*Node {
|
||
|
// var colon: TokenIndex = undefined;
|
||
|
// const label_token = p.parseBlockLabel(&colon);
|
||
|
//
|
||
|
// if (try p.parseBlock(label_token)) |node| return node;
|
||
|
//
|
||
|
// if (try p.parseLoopStatement()) |node| {
|
||
|
// if (node.cast(Node.For)) |for_node| {
|
||
|
// for_node.label = label_token;
|
||
|
// } else if (node.cast(Node.While)) |while_node| {
|
||
|
// while_node.label = label_token;
|
||
|
// } else unreachable;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (label_token != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedLabelable = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// return error.ParseError;
|
||
|
// }
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
|
||
|
// fn parseLoopStatement(p: *Parser) !?*Node {
|
||
|
// const inline_token = p.eatToken(.Keyword_inline);
|
||
|
//
|
||
|
// if (try p.parseForStatement()) |node| {
|
||
|
// node.cast(Node.For).?.inline_token = inline_token;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseWhileStatement()) |node| {
|
||
|
// node.cast(Node.While).?.inline_token = inline_token;
|
||
|
// return node;
|
||
|
// }
|
||
|
// if (inline_token == null) return null;
|
||
|
//
|
||
|
// // If we've seen "inline", there should have been a "for" or "while"
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedInlinable = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// return error.ParseError;
|
||
|
// }
|
||
|
//
|
||
|
// /// ForStatement
|
||
|
// /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )?
|
||
|
// /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement )
|
||
|
// fn parseForStatement(p: *Parser) !?*Node {
|
||
|
// const node = (try p.parseForPrefix()) orelse return null;
|
||
|
// const for_prefix = node.cast(Node.For).?;
|
||
|
//
|
||
|
// if (try p.parseBlockExpr()) |block_expr_node| {
|
||
|
// for_prefix.body = block_expr_node;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const statement_node = try p.expectNode(parseStatement, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = null,
|
||
|
// .body = statement_node,
|
||
|
// };
|
||
|
// for_prefix.@"else" = else_node;
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// for_prefix.body = try p.expectNode(parseAssignExpr, .{
|
||
|
// .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// if (p.eatToken(.Semicolon) != null) return node;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const statement_node = try p.expectNode(parseStatement, .{
|
||
|
// .ExpectedStatement = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = null,
|
||
|
// .body = statement_node,
|
||
|
// };
|
||
|
// for_prefix.@"else" = else_node;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedSemiOrElse = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// WhileStatement
|
||
|
// /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
|
||
|
// /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
|
||
|
// fn parseWhileStatement(p: *Parser) !?*Node {
|
||
|
// const node = (try p.parseWhilePrefix()) orelse return null;
|
||
|
// const while_prefix = node.cast(Node.While).?;
|
||
|
//
|
||
|
// if (try p.parseBlockExpr()) |block_expr_node| {
|
||
|
// while_prefix.body = block_expr_node;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const payload = try p.parsePayload();
|
||
|
//
|
||
|
// const statement_node = try p.expectNode(parseStatement, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = payload,
|
||
|
// .body = statement_node,
|
||
|
// };
|
||
|
// while_prefix.@"else" = else_node;
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// while_prefix.body = try p.expectNode(parseAssignExpr, .{
|
||
|
// .ExpectedBlockOrAssignment = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// if (p.eatToken(.Semicolon) != null) return node;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const payload = try p.parsePayload();
|
||
|
//
|
||
|
// const statement_node = try p.expectNode(parseStatement, .{
|
||
|
// .ExpectedStatement = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = payload,
|
||
|
// .body = statement_node,
|
||
|
// };
|
||
|
// while_prefix.@"else" = else_node;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedSemiOrElse = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// BlockExprStatement
|
||
|
// /// <- BlockExpr
|
||
|
// /// / AssignExpr SEMICOLON
|
||
|
// fn parseBlockExprStatement(p: *Parser) !?*Node {
|
||
|
// if (try p.parseBlockExpr()) |node| return node;
|
||
|
// if (try p.parseAssignExpr()) |node| {
|
||
|
// _ = try p.expectTokenRecoverable(.Semicolon);
|
||
|
// return node;
|
||
|
// }
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// BlockExpr <- BlockLabel? Block
|
||
|
// fn parseBlockExpr(p: *Parser) Error!?*Node {
|
||
|
// var colon: TokenIndex = undefined;
|
||
|
// const label_token = p.parseBlockLabel(&colon);
|
||
|
// const block_node = (try p.parseBlock(label_token)) orelse {
|
||
|
// if (label_token) |label| {
|
||
|
// p.putBackToken(label + 1); // ":"
|
||
|
// p.putBackToken(label); // IDENTIFIER
|
||
|
// }
|
||
|
// return null;
|
||
|
// };
|
||
|
// return block_node;
|
||
|
// }
|
||
|
//
|
||
|
// /// AssignExpr <- Expr (AssignOp Expr)?
|
||
|
// fn parseAssignExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(parseAssignOp, parseExpr, .Once);
|
||
|
// }
|
||
|
//
|
||
|
// /// Expr <- KEYWORD_try* BoolOrExpr
|
||
|
// fn parseExpr(p: *Parser) Error!?*Node {
|
||
|
// return p.parsePrefixOpExpr(parseTry, parseBoolOrExpr);
|
||
|
// }
|
||
|
//
|
||
|
// /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
|
||
|
// fn parseBoolOrExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(
|
||
|
// SimpleBinOpParseFn(.Keyword_or, .BoolOr),
|
||
|
// parseBoolAndExpr,
|
||
|
// .Infinitely,
|
||
|
// );
|
||
|
// }
|
||
|
//
|
||
|
// /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
|
||
|
// fn parseBoolAndExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(
|
||
|
// SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
|
||
|
// parseCompareExpr,
|
||
|
// .Infinitely,
|
||
|
// );
|
||
|
// }
|
||
|
//
|
||
|
// /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
|
||
|
// fn parseCompareExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(parseCompareOp, parseBitwiseExpr, .Once);
|
||
|
// }
|
||
|
//
|
||
|
// /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
|
||
|
// fn parseBitwiseExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(parseBitwiseOp, parseBitShiftExpr, .Infinitely);
|
||
|
// }
|
||
|
//
|
||
|
// /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
|
||
|
// fn parseBitShiftExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(parseBitShiftOp, parseAdditionExpr, .Infinitely);
|
||
|
// }
|
||
|
//
|
||
|
// /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
|
||
|
// fn parseAdditionExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(parseAdditionOp, parseMultiplyExpr, .Infinitely);
|
||
|
// }
|
||
|
//
|
||
|
// /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
|
||
|
// fn parseMultiplyExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseBinOpExpr(parseMultiplyOp, parsePrefixExpr, .Infinitely);
|
||
|
// }
|
||
|
//
|
||
|
// /// PrefixExpr <- PrefixOp* PrimaryExpr
|
||
|
// fn parsePrefixExpr(p: *Parser) !?*Node {
|
||
|
// return p.parsePrefixOpExpr(parsePrefixOp, parsePrimaryExpr);
|
||
|
// }
|
||
|
//
|
||
|
// /// PrimaryExpr
|
||
|
// /// <- AsmExpr
|
||
|
// /// / IfExpr
|
||
|
// /// / KEYWORD_break BreakLabel? Expr?
|
||
|
// /// / KEYWORD_comptime Expr
|
||
|
// /// / KEYWORD_nosuspend Expr
|
||
|
// /// / KEYWORD_continue BreakLabel?
|
||
|
// /// / KEYWORD_resume Expr
|
||
|
// /// / KEYWORD_return Expr?
|
||
|
// /// / BlockLabel? LoopExpr
|
||
|
// /// / Block
|
||
|
// /// / CurlySuffixExpr
|
||
|
// fn parsePrimaryExpr(p: *Parser) !?*Node {
|
||
|
// if (try p.parseAsmExpr()) |node| return node;
|
||
|
// if (try p.parseIfExpr()) |node| return node;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_break)) |token| {
|
||
|
// const label = try p.parseBreakLabel();
|
||
|
// const expr_node = try p.parseExpr();
|
||
|
// const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
|
||
|
// .tag = .Break,
|
||
|
// .ltoken = token,
|
||
|
// }, .{
|
||
|
// .label = label,
|
||
|
// .rhs = expr_node,
|
||
|
// });
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_comptime)) |token| {
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const node = try p.arena.allocator.create(Node.Comptime);
|
||
|
// node.* = .{
|
||
|
// .doc_comments = null,
|
||
|
// .comptime_token = token,
|
||
|
// .expr = expr_node,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_nosuspend)) |token| {
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const node = try p.arena.allocator.create(Node.Nosuspend);
|
||
|
// node.* = .{
|
||
|
// .nosuspend_token = token,
|
||
|
// .expr = expr_node,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_continue)) |token| {
|
||
|
// const label = try p.parseBreakLabel();
|
||
|
// const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
|
||
|
// .tag = .Continue,
|
||
|
// .ltoken = token,
|
||
|
// }, .{
|
||
|
// .label = label,
|
||
|
// .rhs = null,
|
||
|
// });
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_resume)) |token| {
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const node = try p.arena.allocator.create(Node.SimplePrefixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .Resume },
|
||
|
// .op_token = token,
|
||
|
// .rhs = expr_node,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_return)) |token| {
|
||
|
// const expr_node = try p.parseExpr();
|
||
|
// const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
|
||
|
// .tag = .Return,
|
||
|
// .ltoken = token,
|
||
|
// }, .{
|
||
|
// .rhs = expr_node,
|
||
|
// });
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// var colon: TokenIndex = undefined;
|
||
|
// const label = p.parseBlockLabel(&colon);
|
||
|
// if (try p.parseLoopExpr()) |node| {
|
||
|
// if (node.cast(Node.For)) |for_node| {
|
||
|
// for_node.label = label;
|
||
|
// } else if (node.cast(Node.While)) |while_node| {
|
||
|
// while_node.label = label;
|
||
|
// } else unreachable;
|
||
|
// return node;
|
||
|
// }
|
||
|
// if (label) |token| {
|
||
|
// p.putBackToken(token + 1); // ":"
|
||
|
// p.putBackToken(token); // IDENTIFIER
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseBlock(null)) |node| return node;
|
||
|
// if (try p.parseCurlySuffixExpr()) |node| return node;
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
|
||
|
// fn parseIfExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseIf(parseExpr);
|
||
|
// }
|
||
|
//
|
||
|
// /// Block <- LBRACE Statement* RBRACE
|
||
|
// fn parseBlock(p: *Parser, label_token: ?TokenIndex) !?*Node {
|
||
|
// const lbrace = p.eatToken(.LBrace) orelse return null;
|
||
|
//
|
||
|
// var statements = std.ArrayList(*Node).init(p.gpa);
|
||
|
// defer statements.deinit();
|
||
|
//
|
||
|
// while (true) {
|
||
|
// const statement = (p.parseStatement() catch |err| switch (err) {
|
||
|
// error.OutOfMemory => return error.OutOfMemory,
|
||
|
// error.ParseError => {
|
||
|
// // try to skip to the next statement
|
||
|
// p.findNextStmt();
|
||
|
// continue;
|
||
|
// },
|
||
|
// }) orelse break;
|
||
|
// try statements.append(statement);
|
||
|
// }
|
||
|
//
|
||
|
// const rbrace = try p.expectToken(.RBrace);
|
||
|
//
|
||
|
// const statements_len = @intCast(NodeIndex, statements.items.len);
|
||
|
//
|
||
|
// if (label_token) |label| {
|
||
|
// const block_node = try Node.LabeledBlock.alloc(&p.arena.allocator, statements_len);
|
||
|
// block_node.* = .{
|
||
|
// .label = label,
|
||
|
// .lbrace = lbrace,
|
||
|
// .statements_len = statements_len,
|
||
|
// .rbrace = rbrace,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, block_node.statements(), statements.items);
|
||
|
// return &block_node.base;
|
||
|
// } else {
|
||
|
// const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len);
|
||
|
// block_node.* = .{
|
||
|
// .lbrace = lbrace,
|
||
|
// .statements_len = statements_len,
|
||
|
// .rbrace = rbrace,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, block_node.statements(), statements.items);
|
||
|
// return &block_node.base;
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
|
||
|
// fn parseLoopExpr(p: *Parser) !?*Node {
|
||
|
// const inline_token = p.eatToken(.Keyword_inline);
|
||
|
//
|
||
|
// if (try p.parseForExpr()) |node| {
|
||
|
// node.cast(Node.For).?.inline_token = inline_token;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseWhileExpr()) |node| {
|
||
|
// node.cast(Node.While).?.inline_token = inline_token;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (inline_token == null) return null;
|
||
|
//
|
||
|
// // If we've seen "inline", there should have been a "for" or "while"
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedInlinable = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// return error.ParseError;
|
||
|
// }
|
||
|
//
|
||
|
// /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)?
|
||
|
// fn parseForExpr(p: *Parser) !?*Node {
|
||
|
// const node = (try p.parseForPrefix()) orelse return null;
|
||
|
// const for_prefix = node.cast(Node.For).?;
|
||
|
//
|
||
|
// const body_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// for_prefix.body = body_node;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const body = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = null,
|
||
|
// .body = body,
|
||
|
// };
|
||
|
//
|
||
|
// for_prefix.@"else" = else_node;
|
||
|
// }
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)?
|
||
|
// fn parseWhileExpr(p: *Parser) !?*Node {
|
||
|
// const node = (try p.parseWhilePrefix()) orelse return null;
|
||
|
// const while_prefix = node.cast(Node.While).?;
|
||
|
//
|
||
|
// const body_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// while_prefix.body = body_node;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const payload = try p.parsePayload();
|
||
|
// const body = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = payload,
|
||
|
// .body = body,
|
||
|
// };
|
||
|
//
|
||
|
// while_prefix.@"else" = else_node;
|
||
|
// }
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// CurlySuffixExpr <- TypeExpr InitList?
|
||
|
// fn parseCurlySuffixExpr(p: *Parser) !?*Node {
|
||
|
// const lhs = (try p.parseTypeExpr()) orelse return null;
|
||
|
// const suffix_op = (try p.parseInitList(lhs)) orelse return lhs;
|
||
|
// return suffix_op;
|
||
|
// }
|
||
|
//
|
||
|
// /// InitList
|
||
|
// /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
|
||
|
// /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
|
||
|
// /// / LBRACE RBRACE
|
||
|
// fn parseInitList(p: *Parser, lhs: *Node) !?*Node {
|
||
|
// const lbrace = p.eatToken(.LBrace) orelse return null;
|
||
|
// var init_list = std.ArrayList(*Node).init(p.gpa);
|
||
|
// defer init_list.deinit();
|
||
|
//
|
||
|
// if (try p.parseFieldInit()) |field_init| {
|
||
|
// try init_list.append(field_init);
|
||
|
// while (p.eatToken(.Comma)) |_| {
|
||
|
// const next = (try p.parseFieldInit()) orelse break;
|
||
|
// try init_list.append(next);
|
||
|
// }
|
||
|
// const node = try Node.StructInitializer.alloc(&p.arena.allocator, init_list.items.len);
|
||
|
// node.* = .{
|
||
|
// .lhs = lhs,
|
||
|
// .rtoken = try p.expectToken(.RBrace),
|
||
|
// .list_len = init_list.items.len,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.list(), init_list.items);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseExpr()) |expr| {
|
||
|
// try init_list.append(expr);
|
||
|
// while (p.eatToken(.Comma)) |_| {
|
||
|
// const next = (try p.parseExpr()) orelse break;
|
||
|
// try init_list.append(next);
|
||
|
// }
|
||
|
// const node = try Node.ArrayInitializer.alloc(&p.arena.allocator, init_list.items.len);
|
||
|
// node.* = .{
|
||
|
// .lhs = lhs,
|
||
|
// .rtoken = try p.expectToken(.RBrace),
|
||
|
// .list_len = init_list.items.len,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.list(), init_list.items);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.StructInitializer);
|
||
|
// node.* = .{
|
||
|
// .lhs = lhs,
|
||
|
// .rtoken = try p.expectToken(.RBrace),
|
||
|
// .list_len = 0,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// InitList
|
||
|
// /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
|
||
|
// /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
|
||
|
// /// / LBRACE RBRACE
|
||
|
// fn parseAnonInitList(p: *Parser, dot: TokenIndex) !?*Node {
|
||
|
// const lbrace = p.eatToken(.LBrace) orelse return null;
|
||
|
// var init_list = std.ArrayList(*Node).init(p.gpa);
|
||
|
// defer init_list.deinit();
|
||
|
//
|
||
|
// if (try p.parseFieldInit()) |field_init| {
|
||
|
// try init_list.append(field_init);
|
||
|
// while (p.eatToken(.Comma)) |_| {
|
||
|
// const next = (try p.parseFieldInit()) orelse break;
|
||
|
// try init_list.append(next);
|
||
|
// }
|
||
|
// const node = try Node.StructInitializerDot.alloc(&p.arena.allocator, init_list.items.len);
|
||
|
// node.* = .{
|
||
|
// .dot = dot,
|
||
|
// .rtoken = try p.expectToken(.RBrace),
|
||
|
// .list_len = init_list.items.len,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.list(), init_list.items);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseExpr()) |expr| {
|
||
|
// try init_list.append(expr);
|
||
|
// while (p.eatToken(.Comma)) |_| {
|
||
|
// const next = (try p.parseExpr()) orelse break;
|
||
|
// try init_list.append(next);
|
||
|
// }
|
||
|
// const node = try Node.ArrayInitializerDot.alloc(&p.arena.allocator, init_list.items.len);
|
||
|
// node.* = .{
|
||
|
// .dot = dot,
|
||
|
// .rtoken = try p.expectToken(.RBrace),
|
||
|
// .list_len = init_list.items.len,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.list(), init_list.items);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.StructInitializerDot);
|
||
|
// node.* = .{
|
||
|
// .dot = dot,
|
||
|
// .rtoken = try p.expectToken(.RBrace),
|
||
|
// .list_len = 0,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr
|
||
|
// fn parseTypeExpr(p: *Parser) Error!?*Node {
|
||
|
// return p.parsePrefixOpExpr(parsePrefixTypeOp, parseErrorUnionExpr);
|
||
|
// }
|
||
|
//
|
||
|
// /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
|
||
|
// fn parseErrorUnionExpr(p: *Parser) !?*Node {
|
||
|
// const suffix_expr = (try p.parseSuffixExpr()) orelse return null;
|
||
|
//
|
||
|
// if (try SimpleBinOpParseFn(.Bang, .ErrorUnion)(p)) |node| {
|
||
|
// const error_union = node.castTag(.ErrorUnion).?;
|
||
|
// const type_expr = try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// error_union.lhs = suffix_expr;
|
||
|
// error_union.rhs = type_expr;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// return suffix_expr;
|
||
|
// }
|
||
|
//
|
||
|
// /// SuffixExpr
|
||
|
// /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
|
||
|
// /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
|
||
|
// fn parseSuffixExpr(p: *Parser) !?*Node {
|
||
|
// const maybe_async = p.eatToken(.Keyword_async);
|
||
|
// if (maybe_async) |async_token| {
|
||
|
// const token_fn = p.eatToken(.Keyword_fn);
|
||
|
// if (token_fn != null) {
|
||
|
// // TODO: remove this hack when async fn rewriting is
|
||
|
// // HACK: If we see the keyword `fn`, then we assume that
|
||
|
// // we are parsing an async fn proto, and not a call.
|
||
|
// // We therefore put back all tokens consumed by the async
|
||
|
// // prefix...
|
||
|
// p.putBackToken(token_fn.?);
|
||
|
// p.putBackToken(async_token);
|
||
|
// return p.parsePrimaryTypeExpr();
|
||
|
// }
|
||
|
// var res = try p.expectNode(parsePrimaryTypeExpr, .{
|
||
|
// .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// while (try p.parseSuffixOp(res)) |node| {
|
||
|
// res = node;
|
||
|
// }
|
||
|
//
|
||
|
// const params = (try p.parseFnCallArguments()) orelse {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedParamList = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// // ignore this, continue parsing
|
||
|
// return res;
|
||
|
// };
|
||
|
// defer p.gpa.free(params.list);
|
||
|
// const node = try Node.Call.alloc(&p.arena.allocator, params.list.len);
|
||
|
// node.* = .{
|
||
|
// .lhs = res,
|
||
|
// .params_len = params.list.len,
|
||
|
// .async_token = async_token,
|
||
|
// .rtoken = params.rparen,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.params(), params.list);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// if (try p.parsePrimaryTypeExpr()) |expr| {
|
||
|
// var res = expr;
|
||
|
//
|
||
|
// while (true) {
|
||
|
// if (try p.parseSuffixOp(res)) |node| {
|
||
|
// res = node;
|
||
|
// continue;
|
||
|
// }
|
||
|
// if (try p.parseFnCallArguments()) |params| {
|
||
|
// defer p.gpa.free(params.list);
|
||
|
// const call = try Node.Call.alloc(&p.arena.allocator, params.list.len);
|
||
|
// call.* = .{
|
||
|
// .lhs = res,
|
||
|
// .params_len = params.list.len,
|
||
|
// .async_token = null,
|
||
|
// .rtoken = params.rparen,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, call.params(), params.list);
|
||
|
// res = &call.base;
|
||
|
// continue;
|
||
|
// }
|
||
|
// break;
|
||
|
// }
|
||
|
// return res;
|
||
|
// }
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// PrimaryTypeExpr
|
||
|
// /// <- BUILTINIDENTIFIER FnCallArguments
|
||
|
// /// / CHAR_LITERAL
|
||
|
// /// / ContainerDecl
|
||
|
// /// / DOT IDENTIFIER
|
||
|
// /// / ErrorSetDecl
|
||
|
// /// / FLOAT
|
||
|
// /// / FnProto
|
||
|
// /// / GroupedExpr
|
||
|
// /// / LabeledTypeExpr
|
||
|
// /// / IDENTIFIER
|
||
|
// /// / IfTypeExpr
|
||
|
// /// / INTEGER
|
||
|
// /// / KEYWORD_comptime TypeExpr
|
||
|
// /// / KEYWORD_error DOT IDENTIFIER
|
||
|
// /// / KEYWORD_false
|
||
|
// /// / KEYWORD_null
|
||
|
// /// / KEYWORD_anyframe
|
||
|
// /// / KEYWORD_true
|
||
|
// /// / KEYWORD_undefined
|
||
|
// /// / KEYWORD_unreachable
|
||
|
// /// / STRINGLITERAL
|
||
|
// /// / SwitchExpr
|
||
|
// fn parsePrimaryTypeExpr(p: *Parser) !?*Node {
|
||
|
// if (try p.parseBuiltinCall()) |node| return node;
|
||
|
// if (p.eatToken(.CharLiteral)) |token| {
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .CharLiteral },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// if (try p.parseContainerDecl()) |node| return node;
|
||
|
// if (try p.parseAnonLiteral()) |node| return node;
|
||
|
// if (try p.parseErrorSetDecl()) |node| return node;
|
||
|
// if (try p.parseFloatLiteral()) |node| return node;
|
||
|
// if (try p.parseFnProto(.as_type, .{})) |node| return node;
|
||
|
// if (try p.parseGroupedExpr()) |node| return node;
|
||
|
// if (try p.parseLabeledTypeExpr()) |node| return node;
|
||
|
// if (try p.parseIdentifier()) |node| return node;
|
||
|
// if (try p.parseIfTypeExpr()) |node| return node;
|
||
|
// if (try p.parseIntegerLiteral()) |node| return node;
|
||
|
// if (p.eatToken(.Keyword_comptime)) |token| {
|
||
|
// const expr = (try p.parseTypeExpr()) orelse return null;
|
||
|
// const node = try p.arena.allocator.create(Node.Comptime);
|
||
|
// node.* = .{
|
||
|
// .doc_comments = null,
|
||
|
// .comptime_token = token,
|
||
|
// .expr = expr,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_error)) |token| {
|
||
|
// const period = try p.expectTokenRecoverable(.Period);
|
||
|
// const identifier = try p.expectNodeRecoverable(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const global_error_set = try p.createLiteral(.ErrorType, token);
|
||
|
// if (period == null or identifier == null) return global_error_set;
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||
|
// node.* = .{
|
||
|
// .base = Node{ .tag = .Period },
|
||
|
// .op_token = period.?,
|
||
|
// .lhs = global_error_set,
|
||
|
// .rhs = identifier.?,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(.BoolLiteral, token);
|
||
|
// if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(.NullLiteral, token);
|
||
|
// if (p.eatToken(.Keyword_anyframe)) |token| {
|
||
|
// const node = try p.arena.allocator.create(Node.AnyFrameType);
|
||
|
// node.* = .{
|
||
|
// .anyframe_token = token,
|
||
|
// .result = null,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(.BoolLiteral, token);
|
||
|
// if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(.UndefinedLiteral, token);
|
||
|
// if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(.Unreachable, token);
|
||
|
// if (try p.parseStringLiteral()) |node| return node;
|
||
|
// if (try p.parseSwitchExpr()) |node| return node;
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
|
||
|
// fn parseContainerDecl(p: *Parser) !?*Node {
|
||
|
// const layout_token = p.eatToken(.Keyword_extern) orelse
|
||
|
// p.eatToken(.Keyword_packed);
|
||
|
//
|
||
|
// const node = (try p.parseContainerDeclAuto()) orelse {
|
||
|
// if (layout_token) |token|
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// };
|
||
|
// node.cast(Node.ContainerDecl).?.*.layout_token = layout_token;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
|
||
|
// fn parseErrorSetDecl(p: *Parser) !?*Node {
|
||
|
// const error_token = p.eatToken(.Keyword_error) orelse return null;
|
||
|
// if (p.eatToken(.LBrace) == null) {
|
||
|
// // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
|
||
|
// p.putBackToken(error_token);
|
||
|
// return null;
|
||
|
// }
|
||
|
// const decls = try p.parseErrorTagList();
|
||
|
// defer p.gpa.free(decls);
|
||
|
// const rbrace = try p.expectToken(.RBrace);
|
||
|
//
|
||
|
// const node = try Node.ErrorSetDecl.alloc(&p.arena.allocator, decls.len);
|
||
|
// node.* = .{
|
||
|
// .error_token = error_token,
|
||
|
// .decls_len = decls.len,
|
||
|
// .rbrace_token = rbrace,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.decls(), decls);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// GroupedExpr <- LPAREN Expr RPAREN
|
||
|
// fn parseGroupedExpr(p: *Parser) !?*Node {
|
||
|
// const lparen = p.eatToken(.LParen) orelse return null;
|
||
|
// const expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const rparen = try p.expectToken(.RParen);
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.GroupedExpression);
|
||
|
// node.* = .{
|
||
|
// .lparen = lparen,
|
||
|
// .expr = expr,
|
||
|
// .rparen = rparen,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
|
||
|
// fn parseIfTypeExpr(p: *Parser) !?*Node {
|
||
|
// return p.parseIf(parseTypeExpr);
|
||
|
// }
|
||
|
//
|
||
|
// /// LabeledTypeExpr
|
||
|
// /// <- BlockLabel Block
|
||
|
// /// / BlockLabel? LoopTypeExpr
|
||
|
// fn parseLabeledTypeExpr(p: *Parser) !?*Node {
|
||
|
// var colon: TokenIndex = undefined;
|
||
|
// const label = p.parseBlockLabel(&colon);
|
||
|
//
|
||
|
// if (label) |label_token| {
|
||
|
// if (try p.parseBlock(label_token)) |node| return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseLoopTypeExpr()) |node| {
|
||
|
// switch (node.tag) {
|
||
|
// .For => node.cast(Node.For).?.label = label,
|
||
|
// .While => node.cast(Node.While).?.label = label,
|
||
|
// else => unreachable,
|
||
|
// }
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (label) |token| {
|
||
|
// p.putBackToken(colon);
|
||
|
// p.putBackToken(token);
|
||
|
// }
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
|
||
|
// fn parseLoopTypeExpr(p: *Parser) !?*Node {
|
||
|
// const inline_token = p.eatToken(.Keyword_inline);
|
||
|
//
|
||
|
// if (try p.parseForTypeExpr()) |node| {
|
||
|
// node.cast(Node.For).?.inline_token = inline_token;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseWhileTypeExpr()) |node| {
|
||
|
// node.cast(Node.While).?.inline_token = inline_token;
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (inline_token == null) return null;
|
||
|
//
|
||
|
// // If we've seen "inline", there should have been a "for" or "while"
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedInlinable = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// return error.ParseError;
|
||
|
// }
|
||
|
//
|
||
|
// /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)?
|
||
|
// fn parseForTypeExpr(p: *Parser) !?*Node {
|
||
|
// const node = (try p.parseForPrefix()) orelse return null;
|
||
|
// const for_prefix = node.cast(Node.For).?;
|
||
|
//
|
||
|
// const type_expr = try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// for_prefix.body = type_expr;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const else_expr = try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = null,
|
||
|
// .body = else_expr,
|
||
|
// };
|
||
|
//
|
||
|
// for_prefix.@"else" = else_node;
|
||
|
// }
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
|
||
|
// fn parseWhileTypeExpr(p: *Parser) !?*Node {
|
||
|
// const node = (try p.parseWhilePrefix()) orelse return null;
|
||
|
// const while_prefix = node.cast(Node.While).?;
|
||
|
//
|
||
|
// const type_expr = try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// while_prefix.body = type_expr;
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const payload = try p.parsePayload();
|
||
|
//
|
||
|
// const else_expr = try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = null,
|
||
|
// .body = else_expr,
|
||
|
// };
|
||
|
//
|
||
|
// while_prefix.@"else" = else_node;
|
||
|
// }
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
|
||
|
// fn parseSwitchExpr(p: *Parser) !?*Node {
|
||
|
// const switch_token = p.eatToken(.Keyword_switch) orelse return null;
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// _ = try p.expectToken(.LBrace);
|
||
|
// const cases = try p.parseSwitchProngList();
|
||
|
// defer p.gpa.free(cases);
|
||
|
// const rbrace = try p.expectToken(.RBrace);
|
||
|
//
|
||
|
// const node = try Node.Switch.alloc(&p.arena.allocator, cases.len);
|
||
|
// node.* = .{
|
||
|
// .switch_token = switch_token,
|
||
|
// .expr = expr_node,
|
||
|
// .cases_len = cases.len,
|
||
|
// .rbrace = rbrace,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.cases(), cases);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
|
||
|
// /// AsmOutput <- COLON AsmOutputList AsmInput?
|
||
|
// /// AsmInput <- COLON AsmInputList AsmClobbers?
|
||
|
// /// AsmClobbers <- COLON StringList
|
||
|
// /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
|
||
|
// fn parseAsmExpr(p: *Parser) !?*Node {
|
||
|
// const asm_token = p.eatToken(.Keyword_asm) orelse return null;
|
||
|
// const volatile_token = p.eatToken(.Keyword_volatile);
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const template = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// var arena_outputs: []Node.Asm.Output = &[0]Node.Asm.Output{};
|
||
|
// var arena_inputs: []Node.Asm.Input = &[0]Node.Asm.Input{};
|
||
|
// var arena_clobbers: []*Node = &[0]*Node{};
|
||
|
//
|
||
|
// if (p.eatToken(.Colon) != null) {
|
||
|
// const outputs = try p.parseAsmOutputList();
|
||
|
// defer p.gpa.free(outputs);
|
||
|
// arena_outputs = try p.arena.allocator.dupe(Node.Asm.Output, outputs);
|
||
|
//
|
||
|
// if (p.eatToken(.Colon) != null) {
|
||
|
// const inputs = try p.parseAsmInputList();
|
||
|
// defer p.gpa.free(inputs);
|
||
|
// arena_inputs = try p.arena.allocator.dupe(Node.Asm.Input, inputs);
|
||
|
//
|
||
|
// if (p.eatToken(.Colon) != null) {
|
||
|
// const clobbers = try ListParseFn(*Node, parseStringLiteral)(p);
|
||
|
// defer p.gpa.free(clobbers);
|
||
|
// arena_clobbers = try p.arena.allocator.dupe(*Node, clobbers);
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.Asm);
|
||
|
// node.* = .{
|
||
|
// .asm_token = asm_token,
|
||
|
// .volatile_token = volatile_token,
|
||
|
// .template = template,
|
||
|
// .outputs = arena_outputs,
|
||
|
// .inputs = arena_inputs,
|
||
|
// .clobbers = arena_clobbers,
|
||
|
// .rparen = try p.expectToken(.RParen),
|
||
|
// };
|
||
|
//
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// DOT IDENTIFIER
|
||
|
// fn parseAnonLiteral(p: *Parser) !?*Node {
|
||
|
// const dot = p.eatToken(.Period) orelse return null;
|
||
|
//
|
||
|
// // anon enum literal
|
||
|
// if (p.eatToken(.Identifier)) |name| {
|
||
|
// const node = try p.arena.allocator.create(Node.EnumLiteral);
|
||
|
// node.* = .{
|
||
|
// .dot = dot,
|
||
|
// .name = name,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseAnonInitList(dot)) |node| {
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// p.putBackToken(dot);
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
|
||
|
// fn parseAsmOutputItem(p: *Parser) !?Node.Asm.Output {
|
||
|
// const lbracket = p.eatToken(.LBracket) orelse return null;
|
||
|
// const name = try p.expectNode(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RBracket);
|
||
|
//
|
||
|
// const constraint = try p.expectNode(parseStringLiteral, .{
|
||
|
// .ExpectedStringLiteral = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const kind: Node.Asm.Output.Kind = blk: {
|
||
|
// if (p.eatToken(.Arrow) != null) {
|
||
|
// const return_ident = try p.expectNode(parseTypeExpr, .{
|
||
|
// .ExpectedTypeExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// break :blk .{ .Return = return_ident };
|
||
|
// }
|
||
|
// const variable = try p.expectNode(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// break :blk .{ .Variable = variable.castTag(.Identifier).? };
|
||
|
// };
|
||
|
// const rparen = try p.expectToken(.RParen);
|
||
|
//
|
||
|
// return Node.Asm.Output{
|
||
|
// .lbracket = lbracket,
|
||
|
// .symbolic_name = name,
|
||
|
// .constraint = constraint,
|
||
|
// .kind = kind,
|
||
|
// .rparen = rparen,
|
||
|
// };
|
||
|
// }
|
||
|
//
|
||
|
// /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
|
||
|
// fn parseAsmInputItem(p: *Parser) !?Node.Asm.Input {
|
||
|
// const lbracket = p.eatToken(.LBracket) orelse return null;
|
||
|
// const name = try p.expectNode(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RBracket);
|
||
|
//
|
||
|
// const constraint = try p.expectNode(parseStringLiteral, .{
|
||
|
// .ExpectedStringLiteral = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const rparen = try p.expectToken(.RParen);
|
||
|
//
|
||
|
// return Node.Asm.Input{
|
||
|
// .lbracket = lbracket,
|
||
|
// .symbolic_name = name,
|
||
|
// .constraint = constraint,
|
||
|
// .expr = expr,
|
||
|
// .rparen = rparen,
|
||
|
// };
|
||
|
// }
|
||
|
//
|
||
|
// /// BreakLabel <- COLON IDENTIFIER
|
||
|
// fn parseBreakLabel(p: *Parser) !?TokenIndex {
|
||
|
// _ = p.eatToken(.Colon) orelse return null;
|
||
|
// const ident = try p.expectToken(.Identifier);
|
||
|
// return ident;
|
||
|
// }
|
||
|
//
|
||
|
// /// BlockLabel <- IDENTIFIER COLON
|
||
|
// fn parseBlockLabel(p: *Parser, colon_token: *TokenIndex) ?TokenIndex {
|
||
|
// const identifier = p.eatToken(.Identifier) orelse return null;
|
||
|
// if (p.eatToken(.Colon)) |colon| {
|
||
|
// colon_token.* = colon;
|
||
|
// return identifier;
|
||
|
// }
|
||
|
// p.putBackToken(identifier);
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// FieldInit <- DOT IDENTIFIER EQUAL Expr
|
||
|
// fn parseFieldInit(p: *Parser) !?*Node {
|
||
|
// const period_token = p.eatToken(.Period) orelse return null;
|
||
|
// const name_token = p.eatToken(.Identifier) orelse {
|
||
|
// // Because of anon literals `.{` is also valid.
|
||
|
// p.putBackToken(period_token);
|
||
|
// return null;
|
||
|
// };
|
||
|
// const eq_token = p.eatToken(.Equal) orelse {
|
||
|
// // `.Name` may also be an enum literal, which is a later rule.
|
||
|
// p.putBackToken(name_token);
|
||
|
// p.putBackToken(period_token);
|
||
|
// return null;
|
||
|
// };
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.FieldInitializer);
|
||
|
// node.* = .{
|
||
|
// .period_token = period_token,
|
||
|
// .name_token = name_token,
|
||
|
// .expr = expr_node,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
|
||
|
// fn parseWhileContinueExpr(p: *Parser) !?*Node {
|
||
|
// _ = p.eatToken(.Colon) orelse return null;
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const node = try p.expectNode(parseAssignExpr, .{
|
||
|
// .ExpectedExprOrAssignment = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
|
||
|
// fn parseLinkSection(p: *Parser) !?*Node {
|
||
|
// _ = p.eatToken(.Keyword_linksection) orelse return null;
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// return expr_node;
|
||
|
// }
|
||
|
//
|
||
|
// /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
|
||
|
// fn parseCallconv(p: *Parser) !?*Node {
|
||
|
// _ = p.eatToken(.Keyword_callconv) orelse return null;
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// return expr_node;
|
||
|
// }
|
||
|
//
|
||
|
// /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
||
|
// fn parseParamDecl(p: *Parser) !?Node.FnProto.ParamDecl {
|
||
|
// const doc_comments = try p.parseDocComment();
|
||
|
// const noalias_token = p.eatToken(.Keyword_noalias);
|
||
|
// const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
|
||
|
// const name_token = blk: {
|
||
|
// const identifier = p.eatToken(.Identifier) orelse break :blk null;
|
||
|
// if (p.eatToken(.Colon) != null) break :blk identifier;
|
||
|
// p.putBackToken(identifier); // ParamType may also be an identifier
|
||
|
// break :blk null;
|
||
|
// };
|
||
|
// const param_type = (try p.parseParamType()) orelse {
|
||
|
// // Only return cleanly if no keyword, identifier, or doc comment was found
|
||
|
// if (noalias_token == null and
|
||
|
// comptime_token == null and
|
||
|
// name_token == null and
|
||
|
// doc_comments == null)
|
||
|
// {
|
||
|
// return null;
|
||
|
// }
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedParamType = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// return error.ParseError;
|
||
|
// };
|
||
|
//
|
||
|
// return Node.FnProto.ParamDecl{
|
||
|
// .doc_comments = doc_comments,
|
||
|
// .comptime_token = comptime_token,
|
||
|
// .noalias_token = noalias_token,
|
||
|
// .name_token = name_token,
|
||
|
// .param_type = param_type,
|
||
|
// };
|
||
|
// }
|
||
|
//
|
||
|
// /// ParamType
|
||
|
// /// <- Keyword_anytype
|
||
|
// /// / DOT3
|
||
|
// /// / TypeExpr
|
||
|
// fn parseParamType(p: *Parser) !?Node.FnProto.ParamDecl.ParamType {
|
||
|
// // TODO cast from tuple to error union is broken
|
||
|
// const P = Node.FnProto.ParamDecl.ParamType;
|
||
|
// if (try p.parseAnyType()) |node| return P{ .any_type = node };
|
||
|
// if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
|
||
|
// fn parseIfPrefix(p: *Parser) !?*Node {
|
||
|
// const if_token = p.eatToken(.Keyword_if) orelse return null;
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const condition = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// const payload = try p.parsePtrPayload();
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.If);
|
||
|
// node.* = .{
|
||
|
// .if_token = if_token,
|
||
|
// .condition = condition,
|
||
|
// .payload = payload,
|
||
|
// .body = undefined, // set by caller
|
||
|
// .@"else" = null,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
|
||
|
// fn parseWhilePrefix(p: *Parser) !?*Node {
|
||
|
// const while_token = p.eatToken(.Keyword_while) orelse return null;
|
||
|
//
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const condition = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
//
|
||
|
// const payload = try p.parsePtrPayload();
|
||
|
// const continue_expr = try p.parseWhileContinueExpr();
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.While);
|
||
|
// node.* = .{
|
||
|
// .label = null,
|
||
|
// .inline_token = null,
|
||
|
// .while_token = while_token,
|
||
|
// .condition = condition,
|
||
|
// .payload = payload,
|
||
|
// .continue_expr = continue_expr,
|
||
|
// .body = undefined, // set by caller
|
||
|
// .@"else" = null,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
|
||
|
// fn parseForPrefix(p: *Parser) !?*Node {
|
||
|
// const for_token = p.eatToken(.Keyword_for) orelse return null;
|
||
|
//
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const array_expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
//
|
||
|
// const payload = try p.expectNode(parsePtrIndexPayload, .{
|
||
|
// .ExpectedPayload = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.For);
|
||
|
// node.* = .{
|
||
|
// .label = null,
|
||
|
// .inline_token = null,
|
||
|
// .for_token = for_token,
|
||
|
// .array_expr = array_expr,
|
||
|
// .payload = payload,
|
||
|
// .body = undefined, // set by caller
|
||
|
// .@"else" = null,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// Payload <- PIPE IDENTIFIER PIPE
|
||
|
// fn parsePayload(p: *Parser) !?*Node {
|
||
|
// const lpipe = p.eatToken(.Pipe) orelse return null;
|
||
|
// const identifier = try p.expectNode(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const rpipe = try p.expectToken(.Pipe);
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.Payload);
|
||
|
// node.* = .{
|
||
|
// .lpipe = lpipe,
|
||
|
// .error_symbol = identifier,
|
||
|
// .rpipe = rpipe,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
|
||
|
// fn parsePtrPayload(p: *Parser) !?*Node {
|
||
|
// const lpipe = p.eatToken(.Pipe) orelse return null;
|
||
|
// const asterisk = p.eatToken(.Asterisk);
|
||
|
// const identifier = try p.expectNode(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const rpipe = try p.expectToken(.Pipe);
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.PointerPayload);
|
||
|
// node.* = .{
|
||
|
// .lpipe = lpipe,
|
||
|
// .ptr_token = asterisk,
|
||
|
// .value_symbol = identifier,
|
||
|
// .rpipe = rpipe,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
|
||
|
// fn parsePtrIndexPayload(p: *Parser) !?*Node {
|
||
|
// const lpipe = p.eatToken(.Pipe) orelse return null;
|
||
|
// const asterisk = p.eatToken(.Asterisk);
|
||
|
// const identifier = try p.expectNode(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const index = if (p.eatToken(.Comma) == null)
|
||
|
// null
|
||
|
// else
|
||
|
// try p.expectNode(parseIdentifier, .{
|
||
|
// .ExpectedIdentifier = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const rpipe = try p.expectToken(.Pipe);
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.PointerIndexPayload);
|
||
|
// node.* = .{
|
||
|
// .lpipe = lpipe,
|
||
|
// .ptr_token = asterisk,
|
||
|
// .value_symbol = identifier,
|
||
|
// .index_symbol = index,
|
||
|
// .rpipe = rpipe,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
|
||
|
// fn parseSwitchProng(p: *Parser) !?*Node {
|
||
|
// const node = (try p.parseSwitchCase()) orelse return null;
|
||
|
// const arrow = try p.expectToken(.EqualAngleBracketRight);
|
||
|
// const payload = try p.parsePtrPayload();
|
||
|
// const expr = try p.expectNode(parseAssignExpr, .{
|
||
|
// .ExpectedExprOrAssignment = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const switch_case = node.cast(Node.SwitchCase).?;
|
||
|
// switch_case.arrow_token = arrow;
|
||
|
// switch_case.payload = payload;
|
||
|
// switch_case.expr = expr;
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// SwitchCase
|
||
|
// /// <- SwitchItem (COMMA SwitchItem)* COMMA?
|
||
|
// /// / KEYWORD_else
|
||
|
// fn parseSwitchCase(p: *Parser) !?*Node {
|
||
|
// var list = std.ArrayList(*Node).init(p.gpa);
|
||
|
// defer list.deinit();
|
||
|
//
|
||
|
// if (try p.parseSwitchItem()) |first_item| {
|
||
|
// try list.append(first_item);
|
||
|
// while (p.eatToken(.Comma) != null) {
|
||
|
// const next_item = (try p.parseSwitchItem()) orelse break;
|
||
|
// try list.append(next_item);
|
||
|
// }
|
||
|
// } else if (p.eatToken(.Keyword_else)) |else_token| {
|
||
|
// const else_node = try p.arena.allocator.create(Node.SwitchElse);
|
||
|
// else_node.* = .{
|
||
|
// .token = else_token,
|
||
|
// };
|
||
|
// try list.append(&else_node.base);
|
||
|
// } else return null;
|
||
|
//
|
||
|
// const node = try Node.SwitchCase.alloc(&p.arena.allocator, list.items.len);
|
||
|
// node.* = .{
|
||
|
// .items_len = list.items.len,
|
||
|
// .arrow_token = undefined, // set by caller
|
||
|
// .payload = null,
|
||
|
// .expr = undefined, // set by caller
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.items(), list.items);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// SwitchItem <- Expr (DOT3 Expr)?
|
||
|
// fn parseSwitchItem(p: *Parser) !?*Node {
|
||
|
// const expr = (try p.parseExpr()) orelse return null;
|
||
|
// if (p.eatToken(.Ellipsis3)) |token| {
|
||
|
// const range_end = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||
|
// node.* = .{
|
||
|
// .base = Node{ .tag = .Range },
|
||
|
// .op_token = token,
|
||
|
// .lhs = expr,
|
||
|
// .rhs = range_end,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// return expr;
|
||
|
// }
|
||
|
//
|
||
|
// /// AssignOp
|
||
|
// /// <- ASTERISKEQUAL
|
||
|
// /// / SLASHEQUAL
|
||
|
// /// / PERCENTEQUAL
|
||
|
// /// / PLUSEQUAL
|
||
|
// /// / MINUSEQUAL
|
||
|
// /// / LARROW2EQUAL
|
||
|
// /// / RARROW2EQUAL
|
||
|
// /// / AMPERSANDEQUAL
|
||
|
// /// / CARETEQUAL
|
||
|
// /// / PIPEEQUAL
|
||
|
// /// / ASTERISKPERCENTEQUAL
|
||
|
// /// / PLUSPERCENTEQUAL
|
||
|
// /// / MINUSPERCENTEQUAL
|
||
|
// /// / EQUAL
|
||
|
// fn parseAssignOp(p: *Parser) !?*Node {
|
||
|
// const token = p.nextToken();
|
||
|
// const op: Node.Tag = switch (p.token_ids[token]) {
|
||
|
// .AsteriskEqual => .AssignMul,
|
||
|
// .SlashEqual => .AssignDiv,
|
||
|
// .PercentEqual => .AssignMod,
|
||
|
// .PlusEqual => .AssignAdd,
|
||
|
// .MinusEqual => .AssignSub,
|
||
|
// .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft,
|
||
|
// .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight,
|
||
|
// .AmpersandEqual => .AssignBitAnd,
|
||
|
// .CaretEqual => .AssignBitXor,
|
||
|
// .PipeEqual => .AssignBitOr,
|
||
|
// .AsteriskPercentEqual => .AssignMulWrap,
|
||
|
// .PlusPercentEqual => .AssignAddWrap,
|
||
|
// .MinusPercentEqual => .AssignSubWrap,
|
||
|
// .Equal => .Assign,
|
||
|
// else => {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// };
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = op },
|
||
|
// .op_token = token,
|
||
|
// .lhs = undefined, // set by caller
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// CompareOp
|
||
|
// /// <- EQUALEQUAL
|
||
|
// /// / EXCLAMATIONMARKEQUAL
|
||
|
// /// / LARROW
|
||
|
// /// / RARROW
|
||
|
// /// / LARROWEQUAL
|
||
|
// /// / RARROWEQUAL
|
||
|
// fn parseCompareOp(p: *Parser) !?*Node {
|
||
|
// const token = p.nextToken();
|
||
|
// const op: Node.Tag = switch (p.token_ids[token]) {
|
||
|
// .EqualEqual => .EqualEqual,
|
||
|
// .BangEqual => .BangEqual,
|
||
|
// .AngleBracketLeft => .LessThan,
|
||
|
// .AngleBracketRight => .GreaterThan,
|
||
|
// .AngleBracketLeftEqual => .LessOrEqual,
|
||
|
// .AngleBracketRightEqual => .GreaterOrEqual,
|
||
|
// else => {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// };
|
||
|
//
|
||
|
// return p.createInfixOp(token, op);
|
||
|
// }
|
||
|
//
|
||
|
// /// BitwiseOp
|
||
|
// /// <- AMPERSAND
|
||
|
// /// / CARET
|
||
|
// /// / PIPE
|
||
|
// /// / KEYWORD_orelse
|
||
|
// /// / KEYWORD_catch Payload?
|
||
|
// fn parseBitwiseOp(p: *Parser) !?*Node {
|
||
|
// const token = p.nextToken();
|
||
|
// const op: Node.Tag = switch (p.token_ids[token]) {
|
||
|
// .Ampersand => .BitAnd,
|
||
|
// .Caret => .BitXor,
|
||
|
// .Pipe => .BitOr,
|
||
|
// .Keyword_orelse => .OrElse,
|
||
|
// .Keyword_catch => {
|
||
|
// const payload = try p.parsePayload();
|
||
|
// const node = try p.arena.allocator.create(Node.Catch);
|
||
|
// node.* = .{
|
||
|
// .op_token = token,
|
||
|
// .lhs = undefined, // set by caller
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// .payload = payload,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// },
|
||
|
// else => {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// };
|
||
|
//
|
||
|
// return p.createInfixOp(token, op);
|
||
|
// }
|
||
|
//
|
||
|
// /// BitShiftOp
|
||
|
// /// <- LARROW2
|
||
|
// /// / RARROW2
|
||
|
// fn parseBitShiftOp(p: *Parser) !?*Node {
|
||
|
// const token = p.nextToken();
|
||
|
// const op: Node.Tag = switch (p.token_ids[token]) {
|
||
|
// .AngleBracketAngleBracketLeft => .BitShiftLeft,
|
||
|
// .AngleBracketAngleBracketRight => .BitShiftRight,
|
||
|
// else => {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// };
|
||
|
//
|
||
|
// return p.createInfixOp(token, op);
|
||
|
// }
|
||
|
//
|
||
|
// /// AdditionOp
|
||
|
// /// <- PLUS
|
||
|
// /// / MINUS
|
||
|
// /// / PLUS2
|
||
|
// /// / PLUSPERCENT
|
||
|
// /// / MINUSPERCENT
|
||
|
// fn parseAdditionOp(p: *Parser) !?*Node {
|
||
|
// const token = p.nextToken();
|
||
|
// const op: Node.Tag = switch (p.token_ids[token]) {
|
||
|
// .Plus => .Add,
|
||
|
// .Minus => .Sub,
|
||
|
// .PlusPlus => .ArrayCat,
|
||
|
// .PlusPercent => .AddWrap,
|
||
|
// .MinusPercent => .SubWrap,
|
||
|
// else => {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// };
|
||
|
//
|
||
|
// return p.createInfixOp(token, op);
|
||
|
// }
|
||
|
//
|
||
|
// /// MultiplyOp
|
||
|
// /// <- PIPE2
|
||
|
// /// / ASTERISK
|
||
|
// /// / SLASH
|
||
|
// /// / PERCENT
|
||
|
// /// / ASTERISK2
|
||
|
// /// / ASTERISKPERCENT
|
||
|
// fn parseMultiplyOp(p: *Parser) !?*Node {
|
||
|
// const token = p.nextToken();
|
||
|
// const op: Node.Tag = switch (p.token_ids[token]) {
|
||
|
// .PipePipe => .MergeErrorSets,
|
||
|
// .Asterisk => .Mul,
|
||
|
// .Slash => .Div,
|
||
|
// .Percent => .Mod,
|
||
|
// .AsteriskAsterisk => .ArrayMult,
|
||
|
// .AsteriskPercent => .MulWrap,
|
||
|
// else => {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// };
|
||
|
//
|
||
|
// return p.createInfixOp(token, op);
|
||
|
// }
|
||
|
//
|
||
|
// /// PrefixOp
|
||
|
// /// <- EXCLAMATIONMARK
|
||
|
// /// / MINUS
|
||
|
// /// / TILDE
|
||
|
// /// / MINUSPERCENT
|
||
|
// /// / AMPERSAND
|
||
|
// /// / KEYWORD_try
|
||
|
// /// / KEYWORD_await
|
||
|
// fn parsePrefixOp(p: *Parser) !?*Node {
|
||
|
// const token = p.nextToken();
|
||
|
// switch (p.token_ids[token]) {
|
||
|
// .Bang => return p.allocSimplePrefixOp(.BoolNot, token),
|
||
|
// .Minus => return p.allocSimplePrefixOp(.Negation, token),
|
||
|
// .Tilde => return p.allocSimplePrefixOp(.BitNot, token),
|
||
|
// .MinusPercent => return p.allocSimplePrefixOp(.NegationWrap, token),
|
||
|
// .Ampersand => return p.allocSimplePrefixOp(.AddressOf, token),
|
||
|
// .Keyword_try => return p.allocSimplePrefixOp(.Try, token),
|
||
|
// .Keyword_await => return p.allocSimplePrefixOp(.Await, token),
|
||
|
// else => {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// fn allocSimplePrefixOp(p: *Parser, comptime tag: Node.Tag, token: TokenIndex) !?*Node {
|
||
|
// const node = try p.arena.allocator.create(Node.SimplePrefixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = tag },
|
||
|
// .op_token = token,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// // TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on
|
||
|
// // pointers. Consider updating this rule:
|
||
|
// // ...
|
||
|
// // / ArrayTypeStart
|
||
|
// // / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||
|
// // / PtrTypeStart ...
|
||
|
//
|
||
|
// /// PrefixTypeOp
|
||
|
// /// <- QUESTIONMARK
|
||
|
// /// / KEYWORD_anyframe MINUSRARROW
|
||
|
// /// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||
|
// /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||
|
// fn parsePrefixTypeOp(p: *Parser) !?*Node {
|
||
|
// if (p.eatToken(.QuestionMark)) |token| {
|
||
|
// const node = try p.arena.allocator.create(Node.SimplePrefixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .OptionalType },
|
||
|
// .op_token = token,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Keyword_anyframe)) |token| {
|
||
|
// const arrow = p.eatToken(.Arrow) orelse {
|
||
|
// p.putBackToken(token);
|
||
|
// return null;
|
||
|
// };
|
||
|
// const node = try p.arena.allocator.create(Node.AnyFrameType);
|
||
|
// node.* = .{
|
||
|
// .anyframe_token = token,
|
||
|
// .result = .{
|
||
|
// .arrow_token = arrow,
|
||
|
// .return_type = undefined, // set by caller
|
||
|
// },
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parsePtrTypeStart()) |node| {
|
||
|
// // If the token encountered was **, there will be two nodes instead of one.
|
||
|
// // The attributes should be applied to the rightmost operator.
|
||
|
// var ptr_info = if (node.cast(Node.PtrType)) |ptr_type|
|
||
|
// if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk)
|
||
|
// &ptr_type.rhs.cast(Node.PtrType).?.ptr_info
|
||
|
// else
|
||
|
// &ptr_type.ptr_info
|
||
|
// else if (node.cast(Node.SliceType)) |slice_type|
|
||
|
// &slice_type.ptr_info
|
||
|
// else
|
||
|
// unreachable;
|
||
|
//
|
||
|
// while (true) {
|
||
|
// if (p.eatToken(.Keyword_align)) |align_token| {
|
||
|
// const lparen = try p.expectToken(.LParen);
|
||
|
// const expr_node = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// // Optional bit range
|
||
|
// const bit_range = if (p.eatToken(.Colon)) |_| bit_range_value: {
|
||
|
// const range_start = try p.expectNode(parseIntegerLiteral, .{
|
||
|
// .ExpectedIntegerLiteral = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.Colon);
|
||
|
// const range_end = try p.expectNode(parseIntegerLiteral, .{
|
||
|
// .ExpectedIntegerLiteral = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// break :bit_range_value ast.PtrInfo.Align.BitRange{
|
||
|
// .start = range_start,
|
||
|
// .end = range_end,
|
||
|
// };
|
||
|
// } else null;
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
//
|
||
|
// if (ptr_info.align_info != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
//
|
||
|
// ptr_info.align_info = ast.PtrInfo.Align{
|
||
|
// .node = expr_node,
|
||
|
// .bit_range = bit_range,
|
||
|
// };
|
||
|
//
|
||
|
// continue;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_const)) |const_token| {
|
||
|
// if (ptr_info.const_token != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
// ptr_info.const_token = const_token;
|
||
|
// continue;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_volatile)) |volatile_token| {
|
||
|
// if (ptr_info.volatile_token != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
// ptr_info.volatile_token = volatile_token;
|
||
|
// continue;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
|
||
|
// if (ptr_info.allowzero_token != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
// ptr_info.allowzero_token = allowzero_token;
|
||
|
// continue;
|
||
|
// }
|
||
|
// break;
|
||
|
// }
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// if (try p.parseArrayTypeStart()) |node| {
|
||
|
// if (node.cast(Node.SliceType)) |slice_type| {
|
||
|
// // Collect pointer qualifiers in any order, but disallow duplicates
|
||
|
// while (true) {
|
||
|
// if (try p.parseByteAlign()) |align_expr| {
|
||
|
// if (slice_type.ptr_info.align_info != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
// slice_type.ptr_info.align_info = ast.PtrInfo.Align{
|
||
|
// .node = align_expr,
|
||
|
// .bit_range = null,
|
||
|
// };
|
||
|
// continue;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_const)) |const_token| {
|
||
|
// if (slice_type.ptr_info.const_token != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraConstQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
// slice_type.ptr_info.const_token = const_token;
|
||
|
// continue;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_volatile)) |volatile_token| {
|
||
|
// if (slice_type.ptr_info.volatile_token != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
// slice_type.ptr_info.volatile_token = volatile_token;
|
||
|
// continue;
|
||
|
// }
|
||
|
// if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
|
||
|
// if (slice_type.ptr_info.allowzero_token != null) {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
|
||
|
// });
|
||
|
// continue;
|
||
|
// }
|
||
|
// slice_type.ptr_info.allowzero_token = allowzero_token;
|
||
|
// continue;
|
||
|
// }
|
||
|
// break;
|
||
|
// }
|
||
|
// }
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// SuffixOp
|
||
|
// /// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET
|
||
|
// /// / DOT IDENTIFIER
|
||
|
// /// / DOTASTERISK
|
||
|
// /// / DOTQUESTIONMARK
|
||
|
// fn parseSuffixOp(p: *Parser, lhs: *Node) !?*Node {
|
||
|
// if (p.eatToken(.LBracket)) |_| {
|
||
|
// const index_expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// if (p.eatToken(.Ellipsis2) != null) {
|
||
|
// const end_expr = try p.parseExpr();
|
||
|
// const sentinel: ?*Node = if (p.eatToken(.Colon) != null)
|
||
|
// try p.parseExpr()
|
||
|
// else
|
||
|
// null;
|
||
|
// const rtoken = try p.expectToken(.RBracket);
|
||
|
// const node = try p.arena.allocator.create(Node.Slice);
|
||
|
// node.* = .{
|
||
|
// .lhs = lhs,
|
||
|
// .rtoken = rtoken,
|
||
|
// .start = index_expr,
|
||
|
// .end = end_expr,
|
||
|
// .sentinel = sentinel,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// const rtoken = try p.expectToken(.RBracket);
|
||
|
// const node = try p.arena.allocator.create(Node.ArrayAccess);
|
||
|
// node.* = .{
|
||
|
// .lhs = lhs,
|
||
|
// .rtoken = rtoken,
|
||
|
// .index_expr = index_expr,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .Deref },
|
||
|
// .lhs = lhs,
|
||
|
// .rtoken = period_asterisk,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.Period)) |period| {
|
||
|
// if (try p.parseIdentifier()) |identifier| {
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||
|
// node.* = .{
|
||
|
// .base = Node{ .tag = .Period },
|
||
|
// .op_token = period,
|
||
|
// .lhs = lhs,
|
||
|
// .rhs = identifier,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// if (p.eatToken(.QuestionMark)) |question_mark| {
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .UnwrapOptional },
|
||
|
// .lhs = lhs,
|
||
|
// .rtoken = question_mark,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedSuffixOp = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// FnCallArguments <- LPAREN ExprList RPAREN
|
||
|
// /// ExprList <- (Expr COMMA)* Expr?
|
||
|
// fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
|
||
|
// if (p.eatToken(.LParen) == null) return null;
|
||
|
// const list = try ListParseFn(*Node, parseExpr)(p);
|
||
|
// errdefer p.gpa.free(list);
|
||
|
// const rparen = try p.expectToken(.RParen);
|
||
|
// return AnnotatedParamList{ .list = list, .rparen = rparen };
|
||
|
// }
|
||
|
//
|
||
|
// const AnnotatedParamList = struct {
|
||
|
// list: []*Node,
|
||
|
// rparen: TokenIndex,
|
||
|
// };
|
||
|
//
|
||
|
// /// ArrayTypeStart <- LBRACKET Expr? RBRACKET
|
||
|
// fn parseArrayTypeStart(p: *Parser) !?*Node {
|
||
|
// const lbracket = p.eatToken(.LBracket) orelse return null;
|
||
|
// const expr = try p.parseExpr();
|
||
|
// const sentinel = if (p.eatToken(.Colon)) |_|
|
||
|
// try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// })
|
||
|
// else
|
||
|
// null;
|
||
|
// const rbracket = try p.expectToken(.RBracket);
|
||
|
//
|
||
|
// if (expr) |len_expr| {
|
||
|
// if (sentinel) |s| {
|
||
|
// const node = try p.arena.allocator.create(Node.ArrayTypeSentinel);
|
||
|
// node.* = .{
|
||
|
// .op_token = lbracket,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// .len_expr = len_expr,
|
||
|
// .sentinel = s,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// } else {
|
||
|
// const node = try p.arena.allocator.create(Node.ArrayType);
|
||
|
// node.* = .{
|
||
|
// .op_token = lbracket,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// .len_expr = len_expr,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.SliceType);
|
||
|
// node.* = .{
|
||
|
// .op_token = lbracket,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// .ptr_info = .{ .sentinel = sentinel },
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// PtrTypeStart
|
||
|
// /// <- ASTERISK
|
||
|
// /// / ASTERISK2
|
||
|
// /// / PTRUNKNOWN
|
||
|
// /// / PTRC
|
||
|
// fn parsePtrTypeStart(p: *Parser) !?*Node {
|
||
|
// if (p.eatToken(.Asterisk)) |asterisk| {
|
||
|
// const sentinel = if (p.eatToken(.Colon)) |_|
|
||
|
// try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// })
|
||
|
// else
|
||
|
// null;
|
||
|
// const node = try p.arena.allocator.create(Node.PtrType);
|
||
|
// node.* = .{
|
||
|
// .op_token = asterisk,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// .ptr_info = .{ .sentinel = sentinel },
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| {
|
||
|
// const node = try p.arena.allocator.create(Node.PtrType);
|
||
|
// node.* = .{
|
||
|
// .op_token = double_asterisk,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
//
|
||
|
// // Special case for **, which is its own token
|
||
|
// const child = try p.arena.allocator.create(Node.PtrType);
|
||
|
// child.* = .{
|
||
|
// .op_token = double_asterisk,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// node.rhs = &child.base;
|
||
|
//
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// if (p.eatToken(.LBracket)) |lbracket| {
|
||
|
// const asterisk = p.eatToken(.Asterisk) orelse {
|
||
|
// p.putBackToken(lbracket);
|
||
|
// return null;
|
||
|
// };
|
||
|
// if (p.eatToken(.Identifier)) |ident| {
|
||
|
// const token_loc = p.token_locs[ident];
|
||
|
// const token_slice = p.source[token_loc.start..token_loc.end];
|
||
|
// if (!std.mem.eql(u8, token_slice, "c")) {
|
||
|
// p.putBackToken(ident);
|
||
|
// } else {
|
||
|
// _ = try p.expectToken(.RBracket);
|
||
|
// const node = try p.arena.allocator.create(Node.PtrType);
|
||
|
// node.* = .{
|
||
|
// .op_token = lbracket,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// }
|
||
|
// const sentinel = if (p.eatToken(.Colon)) |_|
|
||
|
// try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// })
|
||
|
// else
|
||
|
// null;
|
||
|
// _ = try p.expectToken(.RBracket);
|
||
|
// const node = try p.arena.allocator.create(Node.PtrType);
|
||
|
// node.* = .{
|
||
|
// .op_token = lbracket,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// .ptr_info = .{ .sentinel = sentinel },
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
|
||
|
// fn parseContainerDeclAuto(p: *Parser) !?*Node {
|
||
|
// const container_decl_type = (try p.parseContainerDeclType()) orelse return null;
|
||
|
// const lbrace = try p.expectToken(.LBrace);
|
||
|
// const members = try p.parseContainerMembers(false);
|
||
|
// defer p.gpa.free(members);
|
||
|
// const rbrace = try p.expectToken(.RBrace);
|
||
|
//
|
||
|
// const members_len = @intCast(NodeIndex, members.len);
|
||
|
// const node = try Node.ContainerDecl.alloc(&p.arena.allocator, members_len);
|
||
|
// node.* = .{
|
||
|
// .layout_token = null,
|
||
|
// .kind_token = container_decl_type.kind_token,
|
||
|
// .init_arg_expr = container_decl_type.init_arg_expr,
|
||
|
// .fields_and_decls_len = members_len,
|
||
|
// .lbrace_token = lbrace,
|
||
|
// .rbrace_token = rbrace,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.fieldsAndDecls(), members);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// Holds temporary data until we are ready to construct the full ContainerDecl AST node.
|
||
|
// const ContainerDeclType = struct {
|
||
|
// kind_token: TokenIndex,
|
||
|
// init_arg_expr: Node.ContainerDecl.InitArg,
|
||
|
// };
|
||
|
//
|
||
|
// /// ContainerDeclType
|
||
|
// /// <- KEYWORD_struct
|
||
|
// /// / KEYWORD_enum (LPAREN Expr RPAREN)?
|
||
|
// /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
|
||
|
// fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {
|
||
|
// const kind_token = p.nextToken();
|
||
|
//
|
||
|
// const init_arg_expr = switch (p.token_ids[kind_token]) {
|
||
|
// .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
|
||
|
// .Keyword_enum => blk: {
|
||
|
// if (p.eatToken(.LParen) != null) {
|
||
|
// const expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// break :blk Node.ContainerDecl.InitArg{ .Type = expr };
|
||
|
// }
|
||
|
// break :blk Node.ContainerDecl.InitArg{ .None = {} };
|
||
|
// },
|
||
|
// .Keyword_union => blk: {
|
||
|
// if (p.eatToken(.LParen) != null) {
|
||
|
// if (p.eatToken(.Keyword_enum) != null) {
|
||
|
// if (p.eatToken(.LParen) != null) {
|
||
|
// const expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// break :blk Node.ContainerDecl.InitArg{ .Enum = expr };
|
||
|
// }
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// break :blk Node.ContainerDecl.InitArg{ .Enum = null };
|
||
|
// }
|
||
|
// const expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// break :blk Node.ContainerDecl.InitArg{ .Type = expr };
|
||
|
// }
|
||
|
// break :blk Node.ContainerDecl.InitArg{ .None = {} };
|
||
|
// },
|
||
|
// else => {
|
||
|
// p.putBackToken(kind_token);
|
||
|
// return null;
|
||
|
// },
|
||
|
// };
|
||
|
//
|
||
|
// return ContainerDeclType{
|
||
|
// .kind_token = kind_token,
|
||
|
// .init_arg_expr = init_arg_expr,
|
||
|
// };
|
||
|
// }
|
||
|
//
|
||
|
// /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
|
||
|
// fn parseByteAlign(p: *Parser) !?*Node {
|
||
|
// _ = p.eatToken(.Keyword_align) orelse return null;
|
||
|
// _ = try p.expectToken(.LParen);
|
||
|
// const expr = try p.expectNode(parseExpr, .{
|
||
|
// .ExpectedExpr = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// _ = try p.expectToken(.RParen);
|
||
|
// return expr;
|
||
|
// }
|
||
|
//
|
||
|
// /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
|
||
|
// /// Only ErrorSetDecl parses an IdentifierList
|
||
|
// fn parseErrorTagList(p: *Parser) ![]*Node {
|
||
|
// return ListParseFn(*Node, parseErrorTag)(p);
|
||
|
// }
|
||
|
//
|
||
|
// /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
|
||
|
// fn parseSwitchProngList(p: *Parser) ![]*Node {
|
||
|
// return ListParseFn(*Node, parseSwitchProng)(p);
|
||
|
// }
|
||
|
//
|
||
|
// /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
|
||
|
// fn parseAsmOutputList(p: *Parser) Error![]Node.Asm.Output {
|
||
|
// return ListParseFn(Node.Asm.Output, parseAsmOutputItem)(p);
|
||
|
// }
|
||
|
//
|
||
|
// /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
|
||
|
// fn parseAsmInputList(p: *Parser) Error![]Node.Asm.Input {
|
||
|
// return ListParseFn(Node.Asm.Input, parseAsmInputItem)(p);
|
||
|
// }
|
||
|
//
|
||
|
// /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
|
||
|
// fn parseParamDeclList(p: *Parser) ![]Node.FnProto.ParamDecl {
|
||
|
// return ListParseFn(Node.FnProto.ParamDecl, parseParamDecl)(p);
|
||
|
// }
|
||
|
//
|
||
|
// const NodeParseFn = fn (p: *Parser) Error!?*Node;
|
||
|
//
|
||
|
// fn ListParseFn(comptime E: type, comptime nodeParseFn: anytype) ParseFn([]E) {
|
||
|
// return struct {
|
||
|
// pub fn parse(p: *Parser) ![]E {
|
||
|
// var list = std.ArrayList(E).init(p.gpa);
|
||
|
// defer list.deinit();
|
||
|
//
|
||
|
// while (try nodeParseFn(p)) |item| {
|
||
|
// try list.append(item);
|
||
|
//
|
||
|
// switch (p.token_ids[p.tok_i]) {
|
||
|
// .Comma => _ = p.nextToken(),
|
||
|
// // all possible delimiters
|
||
|
// .Colon, .RParen, .RBrace, .RBracket => break,
|
||
|
// else => {
|
||
|
// // this is likely just a missing comma,
|
||
|
// // continue parsing this list and give an error
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
|
||
|
// });
|
||
|
// },
|
||
|
// }
|
||
|
// }
|
||
|
// return list.toOwnedSlice();
|
||
|
// }
|
||
|
// }.parse;
|
||
|
// }
|
||
|
//
|
||
|
// fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.Tag) NodeParseFn {
|
||
|
// return struct {
|
||
|
// pub fn parse(p: *Parser) Error!?*Node {
|
||
|
// const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) {
|
||
|
// .Keyword_and => p.nextToken(),
|
||
|
// .Invalid_ampersands => blk: {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .InvalidAnd = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// break :blk p.nextToken();
|
||
|
// },
|
||
|
// else => return null,
|
||
|
// } else p.eatToken(token) orelse return null;
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = op },
|
||
|
// .op_token = op_token,
|
||
|
// .lhs = undefined, // set by caller
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// }.parse;
|
||
|
// }
|
||
|
//
|
||
|
// // Helper parsers not included in the grammar
|
||
|
//
|
||
|
// fn parseBuiltinCall(p: *Parser) !?*Node {
|
||
|
// const token = p.eatToken(.Builtin) orelse return null;
|
||
|
// const params = (try p.parseFnCallArguments()) orelse {
|
||
|
// try p.errors.append(p.gpa, .{
|
||
|
// .ExpectedParamList = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// // lets pretend this was an identifier so we can continue parsing
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .Identifier },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// };
|
||
|
// defer p.gpa.free(params.list);
|
||
|
//
|
||
|
// const node = try Node.BuiltinCall.alloc(&p.arena.allocator, params.list.len);
|
||
|
// node.* = .{
|
||
|
// .builtin_token = token,
|
||
|
// .params_len = params.list.len,
|
||
|
// .rparen_token = params.rparen,
|
||
|
// };
|
||
|
// std.mem.copy(*Node, node.params(), params.list);
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// fn parseErrorTag(p: *Parser) !?*Node {
|
||
|
// const doc_comments = try p.parseDocComment(); // no need to rewind on failure
|
||
|
// const token = p.eatToken(.Identifier) orelse return null;
|
||
|
//
|
||
|
// const node = try p.arena.allocator.create(Node.ErrorTag);
|
||
|
// node.* = .{
|
||
|
// .doc_comments = doc_comments,
|
||
|
// .name_token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// fn parseIdentifier(p: *Parser) !?*Node {
|
||
|
// const token = p.eatToken(.Identifier) orelse return null;
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .Identifier },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// fn parseAnyType(p: *Parser) !?*Node {
|
||
|
// const token = p.eatToken(.Keyword_anytype) orelse
|
||
|
// p.eatToken(.Keyword_var) orelse return null; // TODO remove in next release cycle
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .AnyType },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// fn createLiteral(p: *Parser, tag: ast.Node.Tag, token: TokenIndex) !*Node {
|
||
|
// const result = try p.arena.allocator.create(Node.OneToken);
|
||
|
// result.* = .{
|
||
|
// .base = .{ .tag = tag },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &result.base;
|
||
|
// }
|
||
|
//
|
||
|
// fn parseStringLiteralSingle(p: *Parser) !?*Node {
|
||
|
// if (p.eatToken(.StringLiteral)) |token| {
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .StringLiteral },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// // string literal or multiline string literal
|
||
|
// fn parseStringLiteral(p: *Parser) !?*Node {
|
||
|
// if (try p.parseStringLiteralSingle()) |node| return node;
|
||
|
//
|
||
|
// if (p.eatToken(.MultilineStringLiteralLine)) |first_line| {
|
||
|
// const start_tok_i = p.tok_i;
|
||
|
// var tok_i = start_tok_i;
|
||
|
// var count: usize = 1; // including first_line
|
||
|
// while (true) : (tok_i += 1) {
|
||
|
// switch (p.token_ids[tok_i]) {
|
||
|
// .LineComment => continue,
|
||
|
// .MultilineStringLiteralLine => count += 1,
|
||
|
// else => break,
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// const node = try Node.MultilineStringLiteral.alloc(&p.arena.allocator, count);
|
||
|
// node.* = .{ .lines_len = count };
|
||
|
// const lines = node.lines();
|
||
|
// tok_i = start_tok_i;
|
||
|
// lines[0] = first_line;
|
||
|
// count = 1;
|
||
|
// while (true) : (tok_i += 1) {
|
||
|
// switch (p.token_ids[tok_i]) {
|
||
|
// .LineComment => continue,
|
||
|
// .MultilineStringLiteralLine => {
|
||
|
// lines[count] = tok_i;
|
||
|
// count += 1;
|
||
|
// },
|
||
|
// else => break,
|
||
|
// }
|
||
|
// }
|
||
|
// p.tok_i = tok_i;
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// fn parseIntegerLiteral(p: *Parser) !?*Node {
|
||
|
// const token = p.eatToken(.IntegerLiteral) orelse return null;
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .IntegerLiteral },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// fn parseFloatLiteral(p: *Parser) !?*Node {
|
||
|
// const token = p.eatToken(.FloatLiteral) orelse return null;
|
||
|
// const node = try p.arena.allocator.create(Node.OneToken);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .FloatLiteral },
|
||
|
// .token = token,
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// fn parseTry(p: *Parser) !?*Node {
|
||
|
// const token = p.eatToken(.Keyword_try) orelse return null;
|
||
|
// const node = try p.arena.allocator.create(Node.SimplePrefixOp);
|
||
|
// node.* = .{
|
||
|
// .base = .{ .tag = .Try },
|
||
|
// .op_token = token,
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
// /// IfPrefix Body (KEYWORD_else Payload? Body)?
|
||
|
// fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
|
||
|
// const node = (try p.parseIfPrefix()) orelse return null;
|
||
|
// const if_prefix = node.cast(Node.If).?;
|
||
|
//
|
||
|
// if_prefix.body = try p.expectNode(bodyParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
//
|
||
|
// const else_token = p.eatToken(.Keyword_else) orelse return node;
|
||
|
// const payload = try p.parsePayload();
|
||
|
// const else_expr = try p.expectNode(bodyParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const else_node = try p.arena.allocator.create(Node.Else);
|
||
|
// else_node.* = .{
|
||
|
// .else_token = else_token,
|
||
|
// .payload = payload,
|
||
|
// .body = else_expr,
|
||
|
// };
|
||
|
// if_prefix.@"else" = else_node;
|
||
|
//
|
||
|
// return node;
|
||
|
// }
|
||
|
//
|
||
|
// /// Eat a multiline doc comment
|
||
|
// fn parseDocComment(p: *Parser) !?*Node.DocComment {
|
||
|
// if (p.eatToken(.DocComment)) |first_line| {
|
||
|
// while (p.eatToken(.DocComment)) |_| {}
|
||
|
// const node = try p.arena.allocator.create(Node.DocComment);
|
||
|
// node.* = .{ .first_line = first_line };
|
||
|
// return node;
|
||
|
// }
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// fn tokensOnSameLine(p: *Parser, token1: TokenIndex, token2: TokenIndex) bool {
|
||
|
// return std.mem.indexOfScalar(u8, p.source[p.token_locs[token1].end..p.token_locs[token2].start], '\n') == null;
|
||
|
// }
|
||
|
//
|
||
|
// /// Eat a single-line doc comment on the same line as another node
|
||
|
// fn parseAppendedDocComment(p: *Parser, after_token: TokenIndex) !?*Node.DocComment {
|
||
|
// const comment_token = p.eatToken(.DocComment) orelse return null;
|
||
|
// if (p.tokensOnSameLine(after_token, comment_token)) {
|
||
|
// const node = try p.arena.allocator.create(Node.DocComment);
|
||
|
// node.* = .{ .first_line = comment_token };
|
||
|
// return node;
|
||
|
// }
|
||
|
// p.putBackToken(comment_token);
|
||
|
// return null;
|
||
|
// }
|
||
|
//
|
||
|
// /// Op* Child
|
||
|
// fn parsePrefixOpExpr(p: *Parser, comptime opParseFn: NodeParseFn, comptime childParseFn: NodeParseFn) Error!?*Node {
|
||
|
// if (try opParseFn(p)) |first_op| {
|
||
|
// var rightmost_op = first_op;
|
||
|
// while (true) {
|
||
|
// switch (rightmost_op.tag) {
|
||
|
// .AddressOf,
|
||
|
// .Await,
|
||
|
// .BitNot,
|
||
|
// .BoolNot,
|
||
|
// .OptionalType,
|
||
|
// .Negation,
|
||
|
// .NegationWrap,
|
||
|
// .Resume,
|
||
|
// .Try,
|
||
|
// => {
|
||
|
// if (try opParseFn(p)) |rhs| {
|
||
|
// rightmost_op.cast(Node.SimplePrefixOp).?.rhs = rhs;
|
||
|
// rightmost_op = rhs;
|
||
|
// } else break;
|
||
|
// },
|
||
|
// .ArrayType => {
|
||
|
// if (try opParseFn(p)) |rhs| {
|
||
|
// rightmost_op.cast(Node.ArrayType).?.rhs = rhs;
|
||
|
// rightmost_op = rhs;
|
||
|
// } else break;
|
||
|
// },
|
||
|
// .ArrayTypeSentinel => {
|
||
|
// if (try opParseFn(p)) |rhs| {
|
||
|
// rightmost_op.cast(Node.ArrayTypeSentinel).?.rhs = rhs;
|
||
|
// rightmost_op = rhs;
|
||
|
// } else break;
|
||
|
// },
|
||
|
// .SliceType => {
|
||
|
// if (try opParseFn(p)) |rhs| {
|
||
|
// rightmost_op.cast(Node.SliceType).?.rhs = rhs;
|
||
|
// rightmost_op = rhs;
|
||
|
// } else break;
|
||
|
// },
|
||
|
// .PtrType => {
|
||
|
// var ptr_type = rightmost_op.cast(Node.PtrType).?;
|
||
|
// // If the token encountered was **, there will be two nodes
|
||
|
// if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk) {
|
||
|
// rightmost_op = ptr_type.rhs;
|
||
|
// ptr_type = rightmost_op.cast(Node.PtrType).?;
|
||
|
// }
|
||
|
// if (try opParseFn(p)) |rhs| {
|
||
|
// ptr_type.rhs = rhs;
|
||
|
// rightmost_op = rhs;
|
||
|
// } else break;
|
||
|
// },
|
||
|
// .AnyFrameType => {
|
||
|
// const prom = rightmost_op.cast(Node.AnyFrameType).?;
|
||
|
// if (try opParseFn(p)) |rhs| {
|
||
|
// prom.result.?.return_type = rhs;
|
||
|
// rightmost_op = rhs;
|
||
|
// } else break;
|
||
|
// },
|
||
|
// else => unreachable,
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// // If any prefix op existed, a child node on the RHS is required
|
||
|
// switch (rightmost_op.tag) {
|
||
|
// .AddressOf,
|
||
|
// .Await,
|
||
|
// .BitNot,
|
||
|
// .BoolNot,
|
||
|
// .OptionalType,
|
||
|
// .Negation,
|
||
|
// .NegationWrap,
|
||
|
// .Resume,
|
||
|
// .Try,
|
||
|
// => {
|
||
|
// const prefix_op = rightmost_op.cast(Node.SimplePrefixOp).?;
|
||
|
// prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// },
|
||
|
// .ArrayType => {
|
||
|
// const prefix_op = rightmost_op.cast(Node.ArrayType).?;
|
||
|
// prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// },
|
||
|
// .ArrayTypeSentinel => {
|
||
|
// const prefix_op = rightmost_op.cast(Node.ArrayTypeSentinel).?;
|
||
|
// prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// },
|
||
|
// .PtrType => {
|
||
|
// const prefix_op = rightmost_op.cast(Node.PtrType).?;
|
||
|
// prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// },
|
||
|
// .SliceType => {
|
||
|
// const prefix_op = rightmost_op.cast(Node.SliceType).?;
|
||
|
// prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// },
|
||
|
// .AnyFrameType => {
|
||
|
// const prom = rightmost_op.cast(Node.AnyFrameType).?;
|
||
|
// prom.result.?.return_type = try p.expectNode(childParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// },
|
||
|
// else => unreachable,
|
||
|
// }
|
||
|
//
|
||
|
// return first_op;
|
||
|
// }
|
||
|
//
|
||
|
// // Otherwise, the child node is optional
|
||
|
// return childParseFn(p);
|
||
|
// }
|
||
|
//
|
||
|
// /// Child (Op Child)*
|
||
|
// /// Child (Op Child)?
|
||
|
// fn parseBinOpExpr(
|
||
|
// p: *Parser,
|
||
|
// opParseFn: NodeParseFn,
|
||
|
// childParseFn: NodeParseFn,
|
||
|
// chain: enum {
|
||
|
// Once,
|
||
|
// Infinitely,
|
||
|
// },
|
||
|
// ) Error!?*Node {
|
||
|
// var res = (try childParseFn(p)) orelse return null;
|
||
|
//
|
||
|
// while (try opParseFn(p)) |node| {
|
||
|
// const right = try p.expectNode(childParseFn, .{
|
||
|
// .InvalidToken = .{ .token = p.tok_i },
|
||
|
// });
|
||
|
// const left = res;
|
||
|
// res = node;
|
||
|
//
|
||
|
// if (node.castTag(.Catch)) |op| {
|
||
|
// op.lhs = left;
|
||
|
// op.rhs = right;
|
||
|
// } else if (node.cast(Node.SimpleInfixOp)) |op| {
|
||
|
// op.lhs = left;
|
||
|
// op.rhs = right;
|
||
|
// }
|
||
|
//
|
||
|
// switch (chain) {
|
||
|
// .Once => break,
|
||
|
// .Infinitely => continue,
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// return res;
|
||
|
// }
|
||
|
//
|
||
|
// fn createInfixOp(p: *Parser, op_token: TokenIndex, tag: Node.Tag) !*Node {
|
||
|
// const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||
|
// node.* = .{
|
||
|
// .base = Node{ .tag = tag },
|
||
|
// .op_token = op_token,
|
||
|
// .lhs = undefined, // set by caller
|
||
|
// .rhs = undefined, // set by caller
|
||
|
// };
|
||
|
// return &node.base;
|
||
|
// }
|
||
|
//
|
||
|
fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex {
|
||
|
return if (p.token_ids[p.tok_i] == id) p.nextToken() else null;
|
||
|
}
|
||
|
|
||
|
// expectToken: either returns the token or an error.
|
||
|
fn expectToken(p: *Parser, id: Token.Id) Error!TokenIndex {
|
||
|
return (try p.expectTokenRecoverable(id)) orelse error.ParseError;
|
||
|
}
|
||
|
|
||
|
// expectTokenRecoverable: either returns the token or null if not the one expected.
|
||
|
// Also, appends the error inside p.errors.
|
||
|
fn expectTokenRecoverable(p: *Parser, id: Token.Id) !?TokenIndex {
|
||
|
const token = p.nextToken();
|
||
|
if (p.token_ids[token] != id) {
|
||
|
try p.errors.append(p.gpa, .{
|
||
|
.ExpectedToken = .{ .token = token, .expected_id = id },
|
||
|
});
|
||
|
// go back so that we can recover properly
|
||
|
p.putBackToken(token);
|
||
|
return null;
|
||
|
}
|
||
|
return token;
|
||
|
}
|
||
|
|
||
|
// nextToken: provide the TokenIndex of the current token, but increases the tok_i
|
||
|
// inside the Parser structure.
|
||
|
fn nextToken(p: *Parser) TokenIndex {
|
||
|
const result = p.tok_i;
|
||
|
p.tok_i += 1;
|
||
|
assert(p.token_ids[result] != .LineComment);
|
||
|
if (p.tok_i >= p.token_ids.len) return result;
|
||
|
|
||
|
while (true) {
|
||
|
if (p.token_ids[p.tok_i] != .LineComment) return result;
|
||
|
p.tok_i += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// putBackToken: come back one token (except for comment lines which are ignored).
|
||
|
// Example: we have a function searching for a declaration,
|
||
|
// the function read a token "my-variable" so it returns after putting back the token.
|
||
|
// Caller now have the start of a declaration in its parsing structure.
|
||
|
fn putBackToken(p: *Parser, putting_back: TokenIndex) void {
|
||
|
while (p.tok_i > 0) {
|
||
|
p.tok_i -= 1;
|
||
|
if (p.token_ids[p.tok_i] == .LineComment) continue;
|
||
|
assert(putting_back == p.tok_i);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// TODO Delete this function. I don't like the inversion of control.
|
||
|
fn expectNode(
|
||
|
p: *Parser,
|
||
|
parseFn: NodeParseFn,
|
||
|
/// if parsing fails
|
||
|
err: AstError,
|
||
|
) Error!*Node {
|
||
|
return (try p.expectNodeRecoverable(parseFn, err)) orelse return error.ParseError;
|
||
|
}
|
||
|
|
||
|
/// TODO Delete this function. I don't like the inversion of control.
|
||
|
fn expectNodeRecoverable(
|
||
|
p: *Parser,
|
||
|
parseFn: NodeParseFn,
|
||
|
/// if parsing fails
|
||
|
err: AstError,
|
||
|
) !?*Node {
|
||
|
return (try parseFn(p)) orelse {
|
||
|
try p.errors.append(p.gpa, err);
|
||
|
return null;
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
fn ParseFn(comptime T: type) type {
|
||
|
return fn (p: *Parser) Error!T;
|
||
|
}
|
||
|
|
||
|
test "std.zig.parser" {
|
||
|
_ = @import("parser_test.zig");
|
||
|
}
|