zig/lib/std/zig/ast.zig

2294 lines
69 KiB
Zig

const std = @import("../std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const SegmentedList = std.SegmentedList;
const mem = std.mem;
const Token = std.zig.Token;
pub const TokenIndex = usize;
pub const Tree = struct {
source: []const u8,
tokens: TokenList,
root_node: *Node.Root,
arena_allocator: std.heap.ArenaAllocator,
errors: ErrorList,
generated: bool = false,
pub const TokenList = SegmentedList(Token, 64);
pub const ErrorList = SegmentedList(Error, 0);
pub fn deinit(self: *Tree) void {
// Here we copy the arena allocator into stack memory, because
// otherwise it would destroy itself while it was still working.
var arena_allocator = self.arena_allocator;
arena_allocator.deinit();
// self is destroyed
}
pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void {
return parse_error.render(&self.tokens, stream);
}
pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 {
return self.tokenSlicePtr(self.tokens.at(token_index));
}
pub fn tokenSlicePtr(self: *Tree, token: *const Token) []const u8 {
return self.source[token.start..token.end];
}
pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 {
const first_token = self.tokens.at(node.firstToken());
const last_token = self.tokens.at(node.lastToken());
return self.source[first_token.start..last_token.end];
}
pub const Location = struct {
line: usize,
column: usize,
line_start: usize,
line_end: usize,
};
/// Return the Location of the token relative to the offset specified by `start_index`.
pub fn tokenLocationPtr(self: *Tree, start_index: usize, token: *const Token) Location {
var loc = Location{
.line = 0,
.column = 0,
.line_start = start_index,
.line_end = self.source.len,
};
if (self.generated)
return loc;
const token_start = token.start;
for (self.source[start_index..]) |c, i| {
if (i + start_index == token_start) {
loc.line_end = i + start_index;
while (loc.line_end < self.source.len and self.source[loc.line_end] != '\n') : (loc.line_end += 1) {}
return loc;
}
if (c == '\n') {
loc.line += 1;
loc.column = 0;
loc.line_start = i + 1;
} else {
loc.column += 1;
}
}
return loc;
}
pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location {
return self.tokenLocationPtr(start_index, self.tokens.at(token_index));
}
pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool {
return self.tokensOnSameLinePtr(self.tokens.at(token1_index), self.tokens.at(token2_index));
}
pub fn tokensOnSameLinePtr(self: *Tree, token1: *const Token, token2: *const Token) bool {
return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null;
}
pub fn dump(self: *Tree) void {
self.root_node.base.dump(0);
}
/// Skips over comments
pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex {
var index = token_index - 1;
while (self.tokens.at(index).id == Token.Id.LineComment) {
index -= 1;
}
return index;
}
/// Skips over comments
pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex {
var index = token_index + 1;
while (self.tokens.at(index).id == Token.Id.LineComment) {
index += 1;
}
return index;
}
};
pub const Error = union(enum) {
InvalidToken: InvalidToken,
ExpectedContainerMembers: ExpectedContainerMembers,
ExpectedStringLiteral: ExpectedStringLiteral,
ExpectedIntegerLiteral: ExpectedIntegerLiteral,
ExpectedPubItem: ExpectedPubItem,
ExpectedIdentifier: ExpectedIdentifier,
ExpectedStatement: ExpectedStatement,
ExpectedVarDeclOrFn: ExpectedVarDeclOrFn,
ExpectedVarDecl: ExpectedVarDecl,
ExpectedReturnType: ExpectedReturnType,
ExpectedAggregateKw: ExpectedAggregateKw,
UnattachedDocComment: UnattachedDocComment,
ExpectedEqOrSemi: ExpectedEqOrSemi,
ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,
ExpectedSemiOrElse: ExpectedSemiOrElse,
ExpectedLabelOrLBrace: ExpectedLabelOrLBrace,
ExpectedLBrace: ExpectedLBrace,
ExpectedColonOrRParen: ExpectedColonOrRParen,
ExpectedLabelable: ExpectedLabelable,
ExpectedInlinable: ExpectedInlinable,
ExpectedAsmOutputReturnOrType: ExpectedAsmOutputReturnOrType,
ExpectedCall: ExpectedCall,
ExpectedCallOrFnProto: ExpectedCallOrFnProto,
ExpectedSliceOrRBracket: ExpectedSliceOrRBracket,
ExtraAlignQualifier: ExtraAlignQualifier,
ExtraConstQualifier: ExtraConstQualifier,
ExtraVolatileQualifier: ExtraVolatileQualifier,
ExtraAllowZeroQualifier: ExtraAllowZeroQualifier,
ExpectedTypeExpr: ExpectedTypeExpr,
ExpectedPrimaryTypeExpr: ExpectedPrimaryTypeExpr,
ExpectedParamType: ExpectedParamType,
ExpectedExpr: ExpectedExpr,
ExpectedPrimaryExpr: ExpectedPrimaryExpr,
ExpectedToken: ExpectedToken,
ExpectedCommaOrEnd: ExpectedCommaOrEnd,
ExpectedParamList: ExpectedParamList,
ExpectedPayload: ExpectedPayload,
ExpectedBlockOrAssignment: ExpectedBlockOrAssignment,
ExpectedBlockOrExpression: ExpectedBlockOrExpression,
ExpectedExprOrAssignment: ExpectedExprOrAssignment,
ExpectedPrefixExpr: ExpectedPrefixExpr,
ExpectedLoopExpr: ExpectedLoopExpr,
ExpectedDerefOrUnwrap: ExpectedDerefOrUnwrap,
ExpectedSuffixOp: ExpectedSuffixOp,
pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
switch (self.*) {
.InvalidToken => |*x| return x.render(tokens, stream),
.ExpectedContainerMembers => |*x| return x.render(tokens, stream),
.ExpectedStringLiteral => |*x| return x.render(tokens, stream),
.ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
.ExpectedPubItem => |*x| return x.render(tokens, stream),
.ExpectedIdentifier => |*x| return x.render(tokens, stream),
.ExpectedStatement => |*x| return x.render(tokens, stream),
.ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
.ExpectedVarDecl => |*x| return x.render(tokens, stream),
.ExpectedReturnType => |*x| return x.render(tokens, stream),
.ExpectedAggregateKw => |*x| return x.render(tokens, stream),
.UnattachedDocComment => |*x| return x.render(tokens, stream),
.ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
.ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
.ExpectedSemiOrElse => |*x| return x.render(tokens, stream),
.ExpectedLabelOrLBrace => |*x| return x.render(tokens, stream),
.ExpectedLBrace => |*x| return x.render(tokens, stream),
.ExpectedColonOrRParen => |*x| return x.render(tokens, stream),
.ExpectedLabelable => |*x| return x.render(tokens, stream),
.ExpectedInlinable => |*x| return x.render(tokens, stream),
.ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
.ExpectedCall => |*x| return x.render(tokens, stream),
.ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
.ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
.ExtraAlignQualifier => |*x| return x.render(tokens, stream),
.ExtraConstQualifier => |*x| return x.render(tokens, stream),
.ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
.ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
.ExpectedTypeExpr => |*x| return x.render(tokens, stream),
.ExpectedPrimaryTypeExpr => |*x| return x.render(tokens, stream),
.ExpectedParamType => |*x| return x.render(tokens, stream),
.ExpectedExpr => |*x| return x.render(tokens, stream),
.ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
.ExpectedToken => |*x| return x.render(tokens, stream),
.ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
.ExpectedParamList => |*x| return x.render(tokens, stream),
.ExpectedPayload => |*x| return x.render(tokens, stream),
.ExpectedBlockOrAssignment => |*x| return x.render(tokens, stream),
.ExpectedBlockOrExpression => |*x| return x.render(tokens, stream),
.ExpectedExprOrAssignment => |*x| return x.render(tokens, stream),
.ExpectedPrefixExpr => |*x| return x.render(tokens, stream),
.ExpectedLoopExpr => |*x| return x.render(tokens, stream),
.ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
.ExpectedSuffixOp => |*x| return x.render(tokens, stream),
}
}
pub fn loc(self: *const Error) TokenIndex {
switch (self.*) {
.InvalidToken => |x| return x.token,
.ExpectedContainerMembers => |x| return x.token,
.ExpectedStringLiteral => |x| return x.token,
.ExpectedIntegerLiteral => |x| return x.token,
.ExpectedPubItem => |x| return x.token,
.ExpectedIdentifier => |x| return x.token,
.ExpectedStatement => |x| return x.token,
.ExpectedVarDeclOrFn => |x| return x.token,
.ExpectedVarDecl => |x| return x.token,
.ExpectedReturnType => |x| return x.token,
.ExpectedAggregateKw => |x| return x.token,
.UnattachedDocComment => |x| return x.token,
.ExpectedEqOrSemi => |x| return x.token,
.ExpectedSemiOrLBrace => |x| return x.token,
.ExpectedSemiOrElse => |x| return x.token,
.ExpectedLabelOrLBrace => |x| return x.token,
.ExpectedLBrace => |x| return x.token,
.ExpectedColonOrRParen => |x| return x.token,
.ExpectedLabelable => |x| return x.token,
.ExpectedInlinable => |x| return x.token,
.ExpectedAsmOutputReturnOrType => |x| return x.token,
.ExpectedCall => |x| return x.node.firstToken(),
.ExpectedCallOrFnProto => |x| return x.node.firstToken(),
.ExpectedSliceOrRBracket => |x| return x.token,
.ExtraAlignQualifier => |x| return x.token,
.ExtraConstQualifier => |x| return x.token,
.ExtraVolatileQualifier => |x| return x.token,
.ExtraAllowZeroQualifier => |x| return x.token,
.ExpectedTypeExpr => |x| return x.token,
.ExpectedPrimaryTypeExpr => |x| return x.token,
.ExpectedParamType => |x| return x.token,
.ExpectedExpr => |x| return x.token,
.ExpectedPrimaryExpr => |x| return x.token,
.ExpectedToken => |x| return x.token,
.ExpectedCommaOrEnd => |x| return x.token,
.ExpectedParamList => |x| return x.token,
.ExpectedPayload => |x| return x.token,
.ExpectedBlockOrAssignment => |x| return x.token,
.ExpectedBlockOrExpression => |x| return x.token,
.ExpectedExprOrAssignment => |x| return x.token,
.ExpectedPrefixExpr => |x| return x.token,
.ExpectedLoopExpr => |x| return x.token,
.ExpectedDerefOrUnwrap => |x| return x.token,
.ExpectedSuffixOp => |x| return x.token,
}
}
pub const InvalidToken = SingleTokenError("Invalid token '{}'");
pub const ExpectedContainerMembers = SingleTokenError("Expected test, comptime, var decl, or container field, found '{}'");
pub const ExpectedStringLiteral = SingleTokenError("Expected string literal, found '{}'");
pub const ExpectedIntegerLiteral = SingleTokenError("Expected integer literal, found '{}'");
pub const ExpectedIdentifier = SingleTokenError("Expected identifier, found '{}'");
pub const ExpectedStatement = SingleTokenError("Expected statement, found '{}'");
pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found '{}'");
pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");
pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");
pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', or '" ++ Token.Id.Keyword_enum.symbol() ++ "', found '{}'");
pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");
pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'");
pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'");
pub const ExpectedLBrace = SingleTokenError("Expected '{{', found '{}'");
pub const ExpectedLabelOrLBrace = SingleTokenError("Expected label or '{{', found '{}'");
pub const ExpectedColonOrRParen = SingleTokenError("Expected ':' or ')', found '{}'");
pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found '{}'");
pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found '{}'");
pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or '" ++ Token.Id.Identifier.symbol() ++ "', found '{}'");
pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found '{}'");
pub const ExpectedTypeExpr = SingleTokenError("Expected type expression, found '{}'");
pub const ExpectedPrimaryTypeExpr = SingleTokenError("Expected primary type expression, found '{}'");
pub const ExpectedExpr = SingleTokenError("Expected expression, found '{}'");
pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found '{}'");
pub const ExpectedParamList = SingleTokenError("Expected parameter list, found '{}'");
pub const ExpectedPayload = SingleTokenError("Expected loop payload, found '{}'");
pub const ExpectedBlockOrAssignment = SingleTokenError("Expected block or assignment, found '{}'");
pub const ExpectedBlockOrExpression = SingleTokenError("Expected block or expression, found '{}'");
pub const ExpectedExprOrAssignment = SingleTokenError("Expected expression or assignment, found '{}'");
pub const ExpectedPrefixExpr = SingleTokenError("Expected prefix expression, found '{}'");
pub const ExpectedLoopExpr = SingleTokenError("Expected loop expression, found '{}'");
pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found '{}'");
pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found '{}'");
pub const ExpectedParamType = SimpleError("Expected parameter type");
pub const ExpectedPubItem = SimpleError("Expected function or variable declaration after pub");
pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
pub const ExpectedCall = struct {
node: *Node,
pub fn render(self: *const ExpectedCall, tokens: *Tree.TokenList, stream: var) !void {
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{
@tagName(self.node.id),
});
}
};
pub const ExpectedCallOrFnProto = struct {
node: *Node,
pub fn render(self: *const ExpectedCallOrFnProto, tokens: *Tree.TokenList, stream: var) !void {
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
@tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
}
};
pub const ExpectedToken = struct {
token: TokenIndex,
expected_id: Token.Id,
pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
const found_token = tokens.at(self.token);
switch (found_token.id) {
.Invalid_ampersands => {
return stream.print("`&&` is invalid. Note that `and` is boolean AND.", .{});
},
.Invalid => {
return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
},
else => {
const token_name = found_token.id.symbol();
return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name });
},
}
}
};
pub const ExpectedCommaOrEnd = struct {
token: TokenIndex,
end_id: Token.Id,
pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void {
const actual_token = tokens.at(self.token);
return stream.print("expected ',' or '{}', found '{}'", .{
self.end_id.symbol(),
actual_token.id.symbol(),
});
}
};
fn SingleTokenError(comptime msg: []const u8) type {
return struct {
const ThisError = @This();
token: TokenIndex,
pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
const actual_token = tokens.at(self.token);
return stream.print(msg, .{actual_token.id.symbol()});
}
};
}
fn SimpleError(comptime msg: []const u8) type {
return struct {
const ThisError = @This();
token: TokenIndex,
pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
return stream.write(msg);
}
};
}
};
pub const Node = struct {
id: Id,
pub const Id = enum {
// Top level
Root,
Use,
TestDecl,
// Statements
VarDecl,
Defer,
// Operators
InfixOp,
PrefixOp,
SuffixOp,
// Control flow
Switch,
While,
For,
If,
ControlFlowExpression,
Suspend,
// Type expressions
VarType,
ErrorType,
FnProto,
AnyFrameType,
// Primary expressions
IntegerLiteral,
FloatLiteral,
EnumLiteral,
StringLiteral,
MultilineStringLiteral,
CharLiteral,
BoolLiteral,
NullLiteral,
UndefinedLiteral,
Unreachable,
Identifier,
GroupedExpression,
BuiltinCall,
ErrorSetDecl,
ContainerDecl,
Asm,
Comptime,
Block,
// Misc
DocComment,
SwitchCase,
SwitchElse,
Else,
Payload,
PointerPayload,
PointerIndexPayload,
ContainerField,
ErrorTag,
AsmInput,
AsmOutput,
ParamDecl,
FieldInitializer,
};
pub fn cast(base: *Node, comptime T: type) ?*T {
if (base.id == comptime typeToId(T)) {
return @fieldParentPtr(T, "base", base);
}
return null;
}
pub fn iterate(base: *Node, index: usize) ?*Node {
comptime var i = 0;
inline while (i < @memberCount(Id)) : (i += 1) {
if (base.id == @field(Id, @memberName(Id, i))) {
const T = @field(Node, @memberName(Id, i));
return @fieldParentPtr(T, "base", base).iterate(index);
}
}
unreachable;
}
pub fn firstToken(base: *const Node) TokenIndex {
comptime var i = 0;
inline while (i < @memberCount(Id)) : (i += 1) {
if (base.id == @field(Id, @memberName(Id, i))) {
const T = @field(Node, @memberName(Id, i));
return @fieldParentPtr(T, "base", base).firstToken();
}
}
unreachable;
}
pub fn lastToken(base: *const Node) TokenIndex {
comptime var i = 0;
inline while (i < @memberCount(Id)) : (i += 1) {
if (base.id == @field(Id, @memberName(Id, i))) {
const T = @field(Node, @memberName(Id, i));
return @fieldParentPtr(T, "base", base).lastToken();
}
}
unreachable;
}
pub fn typeToId(comptime T: type) Id {
comptime var i = 0;
inline while (i < @memberCount(Id)) : (i += 1) {
if (T == @field(Node, @memberName(Id, i))) {
return @field(Id, @memberName(Id, i));
}
}
unreachable;
}
pub fn requireSemiColon(base: *const Node) bool {
var n = base;
while (true) {
switch (n.id) {
Id.Root,
Id.ContainerField,
Id.ParamDecl,
Id.Block,
Id.Payload,
Id.PointerPayload,
Id.PointerIndexPayload,
Id.Switch,
Id.SwitchCase,
Id.SwitchElse,
Id.FieldInitializer,
Id.DocComment,
Id.TestDecl,
=> return false,
Id.While => {
const while_node = @fieldParentPtr(While, "base", n);
if (while_node.@"else") |@"else"| {
n = &@"else".base;
continue;
}
return while_node.body.id != Id.Block;
},
Id.For => {
const for_node = @fieldParentPtr(For, "base", n);
if (for_node.@"else") |@"else"| {
n = &@"else".base;
continue;
}
return for_node.body.id != Id.Block;
},
Id.If => {
const if_node = @fieldParentPtr(If, "base", n);
if (if_node.@"else") |@"else"| {
n = &@"else".base;
continue;
}
return if_node.body.id != Id.Block;
},
Id.Else => {
const else_node = @fieldParentPtr(Else, "base", n);
n = else_node.body;
continue;
},
Id.Defer => {
const defer_node = @fieldParentPtr(Defer, "base", n);
return defer_node.expr.id != Id.Block;
},
Id.Comptime => {
const comptime_node = @fieldParentPtr(Comptime, "base", n);
return comptime_node.expr.id != Id.Block;
},
Id.Suspend => {
const suspend_node = @fieldParentPtr(Suspend, "base", n);
if (suspend_node.body) |body| {
return body.id != Id.Block;
}
return true;
},
else => return true,
}
}
}
pub fn dump(self: *Node, indent: usize) void {
{
var i: usize = 0;
while (i < indent) : (i += 1) {
std.debug.warn(" ", .{});
}
}
std.debug.warn("{}\n", .{@tagName(self.id)});
var child_i: usize = 0;
while (self.iterate(child_i)) |child| : (child_i += 1) {
child.dump(indent + 2);
}
}
pub const Root = struct {
base: Node = Node{ .id = .Root },
decls: DeclList,
eof_token: TokenIndex,
pub const DeclList = SegmentedList(*Node, 4);
pub fn iterate(self: *Root, index: usize) ?*Node {
if (index < self.decls.len) {
return self.decls.at(index).*;
}
return null;
}
pub fn firstToken(self: *const Root) TokenIndex {
return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken();
}
pub fn lastToken(self: *const Root) TokenIndex {
return if (self.decls.len == 0) self.eof_token else (self.decls.at(self.decls.len - 1).*).lastToken();
}
};
pub const VarDecl = struct {
base: Node = Node{ .id = .VarDecl },
doc_comments: ?*DocComment,
visib_token: ?TokenIndex,
thread_local_token: ?TokenIndex,
name_token: TokenIndex,
eq_token: TokenIndex,
mut_token: TokenIndex,
comptime_token: ?TokenIndex,
extern_export_token: ?TokenIndex,
lib_name: ?*Node,
type_node: ?*Node,
align_node: ?*Node,
section_node: ?*Node,
init_node: ?*Node,
semicolon_token: TokenIndex,
pub fn iterate(self: *VarDecl, index: usize) ?*Node {
var i = index;
if (self.type_node) |type_node| {
if (i < 1) return type_node;
i -= 1;
}
if (self.align_node) |align_node| {
if (i < 1) return align_node;
i -= 1;
}
if (self.section_node) |section_node| {
if (i < 1) return section_node;
i -= 1;
}
if (self.init_node) |init_node| {
if (i < 1) return init_node;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const VarDecl) TokenIndex {
if (self.visib_token) |visib_token| return visib_token;
if (self.thread_local_token) |thread_local_token| return thread_local_token;
if (self.comptime_token) |comptime_token| return comptime_token;
if (self.extern_export_token) |extern_export_token| return extern_export_token;
assert(self.lib_name == null);
return self.mut_token;
}
pub fn lastToken(self: *const VarDecl) TokenIndex {
return self.semicolon_token;
}
};
pub const Use = struct {
base: Node = Node{ .id = .Use },
doc_comments: ?*DocComment,
visib_token: ?TokenIndex,
use_token: TokenIndex,
expr: *Node,
semicolon_token: TokenIndex,
pub fn iterate(self: *Use, index: usize) ?*Node {
var i = index;
if (i < 1) return self.expr;
i -= 1;
return null;
}
pub fn firstToken(self: *const Use) TokenIndex {
if (self.visib_token) |visib_token| return visib_token;
return self.use_token;
}
pub fn lastToken(self: *const Use) TokenIndex {
return self.semicolon_token;
}
};
pub const ErrorSetDecl = struct {
base: Node = Node{ .id = .ErrorSetDecl },
error_token: TokenIndex,
decls: DeclList,
rbrace_token: TokenIndex,
pub const DeclList = SegmentedList(*Node, 2);
pub fn iterate(self: *ErrorSetDecl, index: usize) ?*Node {
var i = index;
if (i < self.decls.len) return self.decls.at(i).*;
i -= self.decls.len;
return null;
}
pub fn firstToken(self: *const ErrorSetDecl) TokenIndex {
return self.error_token;
}
pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {
return self.rbrace_token;
}
};
pub const ContainerDecl = struct {
base: Node = Node{ .id = .ContainerDecl },
layout_token: ?TokenIndex,
kind_token: TokenIndex,
init_arg_expr: InitArg,
fields_and_decls: DeclList,
lbrace_token: TokenIndex,
rbrace_token: TokenIndex,
pub const DeclList = Root.DeclList;
pub const InitArg = union(enum) {
None,
Enum: ?*Node,
Type: *Node,
};
pub fn iterate(self: *ContainerDecl, index: usize) ?*Node {
var i = index;
switch (self.init_arg_expr) {
InitArg.Type => |t| {
if (i < 1) return t;
i -= 1;
},
InitArg.None, InitArg.Enum => {},
}
if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;
i -= self.fields_and_decls.len;
return null;
}
pub fn firstToken(self: *const ContainerDecl) TokenIndex {
if (self.layout_token) |layout_token| {
return layout_token;
}
return self.kind_token;
}
pub fn lastToken(self: *const ContainerDecl) TokenIndex {
return self.rbrace_token;
}
};
pub const ContainerField = struct {
base: Node = Node{ .id = .ContainerField },
doc_comments: ?*DocComment,
comptime_token: ?TokenIndex,
name_token: TokenIndex,
type_expr: ?*Node,
value_expr: ?*Node,
align_expr: ?*Node,
pub fn iterate(self: *ContainerField, index: usize) ?*Node {
var i = index;
if (self.type_expr) |type_expr| {
if (i < 1) return type_expr;
i -= 1;
}
if (self.value_expr) |value_expr| {
if (i < 1) return value_expr;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const ContainerField) TokenIndex {
return self.comptime_token orelse self.name_token;
}
pub fn lastToken(self: *const ContainerField) TokenIndex {
if (self.value_expr) |value_expr| {
return value_expr.lastToken();
}
if (self.type_expr) |type_expr| {
return type_expr.lastToken();
}
return self.name_token;
}
};
pub const ErrorTag = struct {
base: Node = Node{ .id = .ErrorTag },
doc_comments: ?*DocComment,
name_token: TokenIndex,
pub fn iterate(self: *ErrorTag, index: usize) ?*Node {
var i = index;
if (self.doc_comments) |comments| {
if (i < 1) return &comments.base;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const ErrorTag) TokenIndex {
return self.name_token;
}
pub fn lastToken(self: *const ErrorTag) TokenIndex {
return self.name_token;
}
};
pub const Identifier = struct {
base: Node = Node{ .id = .Identifier },
token: TokenIndex,
pub fn iterate(self: *Identifier, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const Identifier) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const Identifier) TokenIndex {
return self.token;
}
};
pub const FnProto = struct {
base: Node = Node{ .id = .FnProto },
doc_comments: ?*DocComment,
visib_token: ?TokenIndex,
fn_token: TokenIndex,
name_token: ?TokenIndex,
params: ParamList,
return_type: ReturnType,
var_args_token: ?TokenIndex,
extern_export_inline_token: ?TokenIndex,
cc_token: ?TokenIndex,
body_node: ?*Node,
lib_name: ?*Node, // populated if this is an extern declaration
align_expr: ?*Node, // populated if align(A) is present
section_expr: ?*Node, // populated if linksection(A) is present
pub const ParamList = SegmentedList(*Node, 2);
pub const ReturnType = union(enum) {
Explicit: *Node,
InferErrorSet: *Node,
};
pub fn iterate(self: *FnProto, index: usize) ?*Node {
var i = index;
if (self.lib_name) |lib_name| {
if (i < 1) return lib_name;
i -= 1;
}
if (i < self.params.len) return self.params.at(self.params.len - i - 1).*;
i -= self.params.len;
if (self.align_expr) |align_expr| {
if (i < 1) return align_expr;
i -= 1;
}
if (self.section_expr) |section_expr| {
if (i < 1) return section_expr;
i -= 1;
}
switch (self.return_type) {
// TODO allow this and next prong to share bodies since the types are the same
ReturnType.Explicit => |node| {
if (i < 1) return node;
i -= 1;
},
ReturnType.InferErrorSet => |node| {
if (i < 1) return node;
i -= 1;
},
}
if (self.body_node) |body_node| {
if (i < 1) return body_node;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const FnProto) TokenIndex {
if (self.visib_token) |visib_token| return visib_token;
if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
assert(self.lib_name == null);
if (self.cc_token) |cc_token| return cc_token;
return self.fn_token;
}
pub fn lastToken(self: *const FnProto) TokenIndex {
if (self.body_node) |body_node| return body_node.lastToken();
switch (self.return_type) {
// TODO allow this and next prong to share bodies since the types are the same
ReturnType.Explicit => |node| return node.lastToken(),
ReturnType.InferErrorSet => |node| return node.lastToken(),
}
}
};
pub const AnyFrameType = struct {
base: Node = Node{ .id = .AnyFrameType },
anyframe_token: TokenIndex,
result: ?Result,
pub const Result = struct {
arrow_token: TokenIndex,
return_type: *Node,
};
pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {
var i = index;
if (self.result) |result| {
if (i < 1) return result.return_type;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const AnyFrameType) TokenIndex {
return self.anyframe_token;
}
pub fn lastToken(self: *const AnyFrameType) TokenIndex {
if (self.result) |result| return result.return_type.lastToken();
return self.anyframe_token;
}
};
pub const ParamDecl = struct {
base: Node = Node{ .id = .ParamDecl },
doc_comments: ?*DocComment,
comptime_token: ?TokenIndex,
noalias_token: ?TokenIndex,
name_token: ?TokenIndex,
type_node: *Node,
var_args_token: ?TokenIndex,
pub fn iterate(self: *ParamDecl, index: usize) ?*Node {
var i = index;
if (i < 1) {
return if (self.var_args_token == null) self.type_node else null;
}
i -= 1;
return null;
}
pub fn firstToken(self: *const ParamDecl) TokenIndex {
if (self.comptime_token) |comptime_token| return comptime_token;
if (self.noalias_token) |noalias_token| return noalias_token;
if (self.name_token) |name_token| return name_token;
return self.type_node.firstToken();
}
pub fn lastToken(self: *const ParamDecl) TokenIndex {
if (self.var_args_token) |var_args_token| return var_args_token;
return self.type_node.lastToken();
}
};
pub const Block = struct {
base: Node = Node{ .id = .Block },
label: ?TokenIndex,
lbrace: TokenIndex,
statements: StatementList,
rbrace: TokenIndex,
pub const StatementList = Root.DeclList;
pub fn iterate(self: *Block, index: usize) ?*Node {
var i = index;
if (i < self.statements.len) return self.statements.at(i).*;
i -= self.statements.len;
return null;
}
pub fn firstToken(self: *const Block) TokenIndex {
if (self.label) |label| {
return label;
}
return self.lbrace;
}
pub fn lastToken(self: *const Block) TokenIndex {
return self.rbrace;
}
};
pub const Defer = struct {
base: Node = Node{ .id = .Defer },
defer_token: TokenIndex,
expr: *Node,
pub fn iterate(self: *Defer, index: usize) ?*Node {
var i = index;
if (i < 1) return self.expr;
i -= 1;
return null;
}
pub fn firstToken(self: *const Defer) TokenIndex {
return self.defer_token;
}
pub fn lastToken(self: *const Defer) TokenIndex {
return self.expr.lastToken();
}
};
pub const Comptime = struct {
base: Node = Node{ .id = .Comptime },
doc_comments: ?*DocComment,
comptime_token: TokenIndex,
expr: *Node,
pub fn iterate(self: *Comptime, index: usize) ?*Node {
var i = index;
if (i < 1) return self.expr;
i -= 1;
return null;
}
pub fn firstToken(self: *const Comptime) TokenIndex {
return self.comptime_token;
}
pub fn lastToken(self: *const Comptime) TokenIndex {
return self.expr.lastToken();
}
};
pub const Payload = struct {
base: Node = Node{ .id = .Payload },
lpipe: TokenIndex,
error_symbol: *Node,
rpipe: TokenIndex,
pub fn iterate(self: *Payload, index: usize) ?*Node {
var i = index;
if (i < 1) return self.error_symbol;
i -= 1;
return null;
}
pub fn firstToken(self: *const Payload) TokenIndex {
return self.lpipe;
}
pub fn lastToken(self: *const Payload) TokenIndex {
return self.rpipe;
}
};
pub const PointerPayload = struct {
base: Node = Node{ .id = .PointerPayload },
lpipe: TokenIndex,
ptr_token: ?TokenIndex,
value_symbol: *Node,
rpipe: TokenIndex,
pub fn iterate(self: *PointerPayload, index: usize) ?*Node {
var i = index;
if (i < 1) return self.value_symbol;
i -= 1;
return null;
}
pub fn firstToken(self: *const PointerPayload) TokenIndex {
return self.lpipe;
}
pub fn lastToken(self: *const PointerPayload) TokenIndex {
return self.rpipe;
}
};
pub const PointerIndexPayload = struct {
base: Node = Node{ .id = .PointerIndexPayload },
lpipe: TokenIndex,
ptr_token: ?TokenIndex,
value_symbol: *Node,
index_symbol: ?*Node,
rpipe: TokenIndex,
pub fn iterate(self: *PointerIndexPayload, index: usize) ?*Node {
var i = index;
if (i < 1) return self.value_symbol;
i -= 1;
if (self.index_symbol) |index_symbol| {
if (i < 1) return index_symbol;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const PointerIndexPayload) TokenIndex {
return self.lpipe;
}
pub fn lastToken(self: *const PointerIndexPayload) TokenIndex {
return self.rpipe;
}
};
pub const Else = struct {
base: Node = Node{ .id = .Else },
else_token: TokenIndex,
payload: ?*Node,
body: *Node,
pub fn iterate(self: *Else, index: usize) ?*Node {
var i = index;
if (self.payload) |payload| {
if (i < 1) return payload;
i -= 1;
}
if (i < 1) return self.body;
i -= 1;
return null;
}
pub fn firstToken(self: *const Else) TokenIndex {
return self.else_token;
}
pub fn lastToken(self: *const Else) TokenIndex {
return self.body.lastToken();
}
};
pub const Switch = struct {
base: Node = Node{ .id = .Switch },
switch_token: TokenIndex,
expr: *Node,
/// these must be SwitchCase nodes
cases: CaseList,
rbrace: TokenIndex,
pub const CaseList = SegmentedList(*Node, 2);
pub fn iterate(self: *Switch, index: usize) ?*Node {
var i = index;
if (i < 1) return self.expr;
i -= 1;
if (i < self.cases.len) return self.cases.at(i).*;
i -= self.cases.len;
return null;
}
pub fn firstToken(self: *const Switch) TokenIndex {
return self.switch_token;
}
pub fn lastToken(self: *const Switch) TokenIndex {
return self.rbrace;
}
};
pub const SwitchCase = struct {
base: Node = Node{ .id = .SwitchCase },
items: ItemList,
arrow_token: TokenIndex,
payload: ?*Node,
expr: *Node,
pub const ItemList = SegmentedList(*Node, 1);
pub fn iterate(self: *SwitchCase, index: usize) ?*Node {
var i = index;
if (i < self.items.len) return self.items.at(i).*;
i -= self.items.len;
if (self.payload) |payload| {
if (i < 1) return payload;
i -= 1;
}
if (i < 1) return self.expr;
i -= 1;
return null;
}
pub fn firstToken(self: *const SwitchCase) TokenIndex {
return (self.items.at(0).*).firstToken();
}
pub fn lastToken(self: *const SwitchCase) TokenIndex {
return self.expr.lastToken();
}
};
pub const SwitchElse = struct {
base: Node = Node{ .id = .SwitchElse },
token: TokenIndex,
pub fn iterate(self: *SwitchElse, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const SwitchElse) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const SwitchElse) TokenIndex {
return self.token;
}
};
pub const While = struct {
base: Node = Node{ .id = .While },
label: ?TokenIndex,
inline_token: ?TokenIndex,
while_token: TokenIndex,
condition: *Node,
payload: ?*Node,
continue_expr: ?*Node,
body: *Node,
@"else": ?*Else,
pub fn iterate(self: *While, index: usize) ?*Node {
var i = index;
if (i < 1) return self.condition;
i -= 1;
if (self.payload) |payload| {
if (i < 1) return payload;
i -= 1;
}
if (self.continue_expr) |continue_expr| {
if (i < 1) return continue_expr;
i -= 1;
}
if (i < 1) return self.body;
i -= 1;
if (self.@"else") |@"else"| {
if (i < 1) return &@"else".base;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const While) TokenIndex {
if (self.label) |label| {
return label;
}
if (self.inline_token) |inline_token| {
return inline_token;
}
return self.while_token;
}
pub fn lastToken(self: *const While) TokenIndex {
if (self.@"else") |@"else"| {
return @"else".body.lastToken();
}
return self.body.lastToken();
}
};
pub const For = struct {
base: Node = Node{ .id = .For },
label: ?TokenIndex,
inline_token: ?TokenIndex,
for_token: TokenIndex,
array_expr: *Node,
payload: *Node,
body: *Node,
@"else": ?*Else,
pub fn iterate(self: *For, index: usize) ?*Node {
var i = index;
if (i < 1) return self.array_expr;
i -= 1;
if (i < 1) return self.payload;
i -= 1;
if (i < 1) return self.body;
i -= 1;
if (self.@"else") |@"else"| {
if (i < 1) return &@"else".base;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const For) TokenIndex {
if (self.label) |label| {
return label;
}
if (self.inline_token) |inline_token| {
return inline_token;
}
return self.for_token;
}
pub fn lastToken(self: *const For) TokenIndex {
if (self.@"else") |@"else"| {
return @"else".body.lastToken();
}
return self.body.lastToken();
}
};
pub const If = struct {
base: Node = Node{ .id = .If },
if_token: TokenIndex,
condition: *Node,
payload: ?*Node,
body: *Node,
@"else": ?*Else,
pub fn iterate(self: *If, index: usize) ?*Node {
var i = index;
if (i < 1) return self.condition;
i -= 1;
if (self.payload) |payload| {
if (i < 1) return payload;
i -= 1;
}
if (i < 1) return self.body;
i -= 1;
if (self.@"else") |@"else"| {
if (i < 1) return &@"else".base;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const If) TokenIndex {
return self.if_token;
}
pub fn lastToken(self: *const If) TokenIndex {
if (self.@"else") |@"else"| {
return @"else".body.lastToken();
}
return self.body.lastToken();
}
};
pub const InfixOp = struct {
base: Node = Node{ .id = .InfixOp },
op_token: TokenIndex,
lhs: *Node,
op: Op,
rhs: *Node,
pub const Op = union(enum) {
Add,
AddWrap,
ArrayCat,
ArrayMult,
Assign,
AssignBitAnd,
AssignBitOr,
AssignBitShiftLeft,
AssignBitShiftRight,
AssignBitXor,
AssignDiv,
AssignSub,
AssignSubWrap,
AssignMod,
AssignAdd,
AssignAddWrap,
AssignMul,
AssignMulWrap,
BangEqual,
BitAnd,
BitOr,
BitShiftLeft,
BitShiftRight,
BitXor,
BoolAnd,
BoolOr,
Catch: ?*Node,
Div,
EqualEqual,
ErrorUnion,
GreaterOrEqual,
GreaterThan,
LessOrEqual,
LessThan,
MergeErrorSets,
Mod,
Mul,
MulWrap,
Period,
Range,
Sub,
SubWrap,
UnwrapOptional,
};
pub fn iterate(self: *InfixOp, index: usize) ?*Node {
var i = index;
if (i < 1) return self.lhs;
i -= 1;
switch (self.op) {
Op.Catch => |maybe_payload| {
if (maybe_payload) |payload| {
if (i < 1) return payload;
i -= 1;
}
},
Op.Add,
Op.AddWrap,
Op.ArrayCat,
Op.ArrayMult,
Op.Assign,
Op.AssignBitAnd,
Op.AssignBitOr,
Op.AssignBitShiftLeft,
Op.AssignBitShiftRight,
Op.AssignBitXor,
Op.AssignDiv,
Op.AssignSub,
Op.AssignSubWrap,
Op.AssignMod,
Op.AssignAdd,
Op.AssignAddWrap,
Op.AssignMul,
Op.AssignMulWrap,
Op.BangEqual,
Op.BitAnd,
Op.BitOr,
Op.BitShiftLeft,
Op.BitShiftRight,
Op.BitXor,
Op.BoolAnd,
Op.BoolOr,
Op.Div,
Op.EqualEqual,
Op.ErrorUnion,
Op.GreaterOrEqual,
Op.GreaterThan,
Op.LessOrEqual,
Op.LessThan,
Op.MergeErrorSets,
Op.Mod,
Op.Mul,
Op.MulWrap,
Op.Period,
Op.Range,
Op.Sub,
Op.SubWrap,
Op.UnwrapOptional,
=> {},
}
if (i < 1) return self.rhs;
i -= 1;
return null;
}
pub fn firstToken(self: *const InfixOp) TokenIndex {
return self.lhs.firstToken();
}
pub fn lastToken(self: *const InfixOp) TokenIndex {
return self.rhs.lastToken();
}
};
pub const PrefixOp = struct {
base: Node = Node{ .id = .PrefixOp },
op_token: TokenIndex,
op: Op,
rhs: *Node,
pub const Op = union(enum) {
AddressOf,
ArrayType: ArrayInfo,
Await,
BitNot,
BoolNot,
Cancel,
OptionalType,
Negation,
NegationWrap,
Resume,
PtrType: PtrInfo,
SliceType: PtrInfo,
Try,
};
pub const ArrayInfo = struct {
len_expr: *Node,
sentinel: ?*Node,
};
pub const PtrInfo = struct {
allowzero_token: ?TokenIndex = null,
align_info: ?Align = null,
const_token: ?TokenIndex = null,
volatile_token: ?TokenIndex = null,
sentinel: ?*Node = null,
pub const Align = struct {
node: *Node,
bit_range: ?BitRange,
pub const BitRange = struct {
start: *Node,
end: *Node,
};
};
};
pub fn iterate(self: *PrefixOp, index: usize) ?*Node {
var i = index;
switch (self.op) {
// TODO https://github.com/ziglang/zig/issues/1107
Op.SliceType => |addr_of_info| {
if (addr_of_info.sentinel) |sentinel| {
if (i < 1) return sentinel;
i -= 1;
}
if (addr_of_info.align_info) |align_info| {
if (i < 1) return align_info.node;
i -= 1;
}
},
Op.PtrType => |addr_of_info| {
if (addr_of_info.align_info) |align_info| {
if (i < 1) return align_info.node;
i -= 1;
}
},
Op.ArrayType => |array_info| {
if (i < 1) return array_info.len_expr;
i -= 1;
if (array_info.sentinel) |sentinel| {
if (i < 1) return sentinel;
i -= 1;
}
},
Op.AddressOf,
Op.Await,
Op.BitNot,
Op.BoolNot,
Op.Cancel,
Op.OptionalType,
Op.Negation,
Op.NegationWrap,
Op.Try,
Op.Resume,
=> {},
}
if (i < 1) return self.rhs;
i -= 1;
return null;
}
pub fn firstToken(self: *const PrefixOp) TokenIndex {
return self.op_token;
}
pub fn lastToken(self: *const PrefixOp) TokenIndex {
return self.rhs.lastToken();
}
};
pub const FieldInitializer = struct {
base: Node = Node{ .id = .FieldInitializer },
period_token: TokenIndex,
name_token: TokenIndex,
expr: *Node,
pub fn iterate(self: *FieldInitializer, index: usize) ?*Node {
var i = index;
if (i < 1) return self.expr;
i -= 1;
return null;
}
pub fn firstToken(self: *const FieldInitializer) TokenIndex {
return self.period_token;
}
pub fn lastToken(self: *const FieldInitializer) TokenIndex {
return self.expr.lastToken();
}
};
pub const SuffixOp = struct {
base: Node = Node{ .id = .SuffixOp },
lhs: Lhs,
op: Op,
rtoken: TokenIndex,
pub const Lhs = union(enum) {
node: *Node,
dot: TokenIndex,
};
pub const Op = union(enum) {
Call: Call,
ArrayAccess: *Node,
Slice: Slice,
ArrayInitializer: InitList,
StructInitializer: InitList,
Deref,
UnwrapOptional,
pub const InitList = SegmentedList(*Node, 2);
pub const Call = struct {
params: ParamList,
async_token: ?TokenIndex,
pub const ParamList = SegmentedList(*Node, 2);
};
pub const Slice = struct {
start: *Node,
end: ?*Node,
sentinel: ?*Node,
};
};
pub fn iterate(self: *SuffixOp, index: usize) ?*Node {
var i = index;
switch (self.lhs) {
.node => |node| {
if (i == 0) return node;
i -= 1;
},
.dot => {},
}
switch (self.op) {
.Call => |*call_info| {
if (i < call_info.params.len) return call_info.params.at(i).*;
i -= call_info.params.len;
},
.ArrayAccess => |index_expr| {
if (i < 1) return index_expr;
i -= 1;
},
.Slice => |range| {
if (i < 1) return range.start;
i -= 1;
if (range.end) |end| {
if (i < 1) return end;
i -= 1;
}
if (range.sentinel) |sentinel| {
if (i < 1) return sentinel;
i -= 1;
}
},
.ArrayInitializer => |*exprs| {
if (i < exprs.len) return exprs.at(i).*;
i -= exprs.len;
},
.StructInitializer => |*fields| {
if (i < fields.len) return fields.at(i).*;
i -= fields.len;
},
.UnwrapOptional,
.Deref,
=> {},
}
return null;
}
pub fn firstToken(self: *const SuffixOp) TokenIndex {
switch (self.op) {
.Call => |*call_info| if (call_info.async_token) |async_token| return async_token,
else => {},
}
switch (self.lhs) {
.node => |node| return node.firstToken(),
.dot => |dot| return dot,
}
}
pub fn lastToken(self: *const SuffixOp) TokenIndex {
return self.rtoken;
}
};
pub const GroupedExpression = struct {
base: Node = Node{ .id = .GroupedExpression },
lparen: TokenIndex,
expr: *Node,
rparen: TokenIndex,
pub fn iterate(self: *GroupedExpression, index: usize) ?*Node {
var i = index;
if (i < 1) return self.expr;
i -= 1;
return null;
}
pub fn firstToken(self: *const GroupedExpression) TokenIndex {
return self.lparen;
}
pub fn lastToken(self: *const GroupedExpression) TokenIndex {
return self.rparen;
}
};
pub const ControlFlowExpression = struct {
base: Node = Node{ .id = .ControlFlowExpression },
ltoken: TokenIndex,
kind: Kind,
rhs: ?*Node,
pub const Kind = union(enum) {
Break: ?*Node,
Continue: ?*Node,
Return,
};
pub fn iterate(self: *ControlFlowExpression, index: usize) ?*Node {
var i = index;
switch (self.kind) {
Kind.Break => |maybe_label| {
if (maybe_label) |label| {
if (i < 1) return label;
i -= 1;
}
},
Kind.Continue => |maybe_label| {
if (maybe_label) |label| {
if (i < 1) return label;
i -= 1;
}
},
Kind.Return => {},
}
if (self.rhs) |rhs| {
if (i < 1) return rhs;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const ControlFlowExpression) TokenIndex {
return self.ltoken;
}
pub fn lastToken(self: *const ControlFlowExpression) TokenIndex {
if (self.rhs) |rhs| {
return rhs.lastToken();
}
switch (self.kind) {
Kind.Break => |maybe_label| {
if (maybe_label) |label| {
return label.lastToken();
}
},
Kind.Continue => |maybe_label| {
if (maybe_label) |label| {
return label.lastToken();
}
},
Kind.Return => return self.ltoken,
}
return self.ltoken;
}
};
pub const Suspend = struct {
base: Node = Node{ .id = .Suspend },
suspend_token: TokenIndex,
body: ?*Node,
pub fn iterate(self: *Suspend, index: usize) ?*Node {
var i = index;
if (self.body) |body| {
if (i < 1) return body;
i -= 1;
}
return null;
}
pub fn firstToken(self: *const Suspend) TokenIndex {
return self.suspend_token;
}
pub fn lastToken(self: *const Suspend) TokenIndex {
if (self.body) |body| {
return body.lastToken();
}
return self.suspend_token;
}
};
pub const IntegerLiteral = struct {
base: Node = Node{ .id = .IntegerLiteral },
token: TokenIndex,
pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const IntegerLiteral) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const IntegerLiteral) TokenIndex {
return self.token;
}
};
pub const EnumLiteral = struct {
base: Node = Node{ .id = .EnumLiteral },
dot: TokenIndex,
name: TokenIndex,
pub fn iterate(self: *EnumLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const EnumLiteral) TokenIndex {
return self.dot;
}
pub fn lastToken(self: *const EnumLiteral) TokenIndex {
return self.name;
}
};
pub const FloatLiteral = struct {
base: Node = Node{ .id = .FloatLiteral },
token: TokenIndex,
pub fn iterate(self: *FloatLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const FloatLiteral) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const FloatLiteral) TokenIndex {
return self.token;
}
};
pub const BuiltinCall = struct {
base: Node = Node{ .id = .BuiltinCall },
builtin_token: TokenIndex,
params: ParamList,
rparen_token: TokenIndex,
pub const ParamList = SegmentedList(*Node, 2);
pub fn iterate(self: *BuiltinCall, index: usize) ?*Node {
var i = index;
if (i < self.params.len) return self.params.at(i).*;
i -= self.params.len;
return null;
}
pub fn firstToken(self: *const BuiltinCall) TokenIndex {
return self.builtin_token;
}
pub fn lastToken(self: *const BuiltinCall) TokenIndex {
return self.rparen_token;
}
};
pub const StringLiteral = struct {
base: Node = Node{ .id = .StringLiteral },
token: TokenIndex,
pub fn iterate(self: *StringLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const StringLiteral) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const StringLiteral) TokenIndex {
return self.token;
}
};
pub const MultilineStringLiteral = struct {
base: Node = Node{ .id = .MultilineStringLiteral },
lines: LineList,
pub const LineList = SegmentedList(TokenIndex, 4);
pub fn iterate(self: *MultilineStringLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex {
return self.lines.at(0).*;
}
pub fn lastToken(self: *const MultilineStringLiteral) TokenIndex {
return self.lines.at(self.lines.len - 1).*;
}
};
pub const CharLiteral = struct {
base: Node = Node{ .id = .CharLiteral },
token: TokenIndex,
pub fn iterate(self: *CharLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const CharLiteral) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const CharLiteral) TokenIndex {
return self.token;
}
};
pub const BoolLiteral = struct {
base: Node = Node{ .id = .BoolLiteral },
token: TokenIndex,
pub fn iterate(self: *BoolLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const BoolLiteral) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const BoolLiteral) TokenIndex {
return self.token;
}
};
pub const NullLiteral = struct {
base: Node = Node{ .id = .NullLiteral },
token: TokenIndex,
pub fn iterate(self: *NullLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const NullLiteral) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const NullLiteral) TokenIndex {
return self.token;
}
};
pub const UndefinedLiteral = struct {
base: Node = Node{ .id = .UndefinedLiteral },
token: TokenIndex,
pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const UndefinedLiteral) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const UndefinedLiteral) TokenIndex {
return self.token;
}
};
pub const AsmOutput = struct {
base: Node = Node{ .id = .AsmOutput },
lbracket: TokenIndex,
symbolic_name: *Node,
constraint: *Node,
kind: Kind,
rparen: TokenIndex,
pub const Kind = union(enum) {
Variable: *Identifier,
Return: *Node,
};
pub fn iterate(self: *AsmOutput, index: usize) ?*Node {
var i = index;
if (i < 1) return self.symbolic_name;
i -= 1;
if (i < 1) return self.constraint;
i -= 1;
switch (self.kind) {
Kind.Variable => |variable_name| {
if (i < 1) return &variable_name.base;
i -= 1;
},
Kind.Return => |return_type| {
if (i < 1) return return_type;
i -= 1;
},
}
return null;
}
pub fn firstToken(self: *const AsmOutput) TokenIndex {
return self.lbracket;
}
pub fn lastToken(self: *const AsmOutput) TokenIndex {
return self.rparen;
}
};
pub const AsmInput = struct {
base: Node = Node{ .id = .AsmInput },
lbracket: TokenIndex,
symbolic_name: *Node,
constraint: *Node,
expr: *Node,
rparen: TokenIndex,
pub fn iterate(self: *AsmInput, index: usize) ?*Node {
var i = index;
if (i < 1) return self.symbolic_name;
i -= 1;
if (i < 1) return self.constraint;
i -= 1;
if (i < 1) return self.expr;
i -= 1;
return null;
}
pub fn firstToken(self: *const AsmInput) TokenIndex {
return self.lbracket;
}
pub fn lastToken(self: *const AsmInput) TokenIndex {
return self.rparen;
}
};
pub const Asm = struct {
base: Node = Node{ .id = .Asm },
asm_token: TokenIndex,
volatile_token: ?TokenIndex,
template: *Node,
outputs: OutputList,
inputs: InputList,
clobbers: ClobberList,
rparen: TokenIndex,
pub const OutputList = SegmentedList(*AsmOutput, 2);
pub const InputList = SegmentedList(*AsmInput, 2);
pub const ClobberList = SegmentedList(*Node, 2);
pub fn iterate(self: *Asm, index: usize) ?*Node {
var i = index;
if (i < self.outputs.len) return &self.outputs.at(index).*.base;
i -= self.outputs.len;
if (i < self.inputs.len) return &self.inputs.at(index).*.base;
i -= self.inputs.len;
return null;
}
pub fn firstToken(self: *const Asm) TokenIndex {
return self.asm_token;
}
pub fn lastToken(self: *const Asm) TokenIndex {
return self.rparen;
}
};
pub const Unreachable = struct {
base: Node = Node{ .id = .Unreachable },
token: TokenIndex,
pub fn iterate(self: *Unreachable, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const Unreachable) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const Unreachable) TokenIndex {
return self.token;
}
};
pub const ErrorType = struct {
base: Node = Node{ .id = .ErrorType },
token: TokenIndex,
pub fn iterate(self: *ErrorType, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const ErrorType) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const ErrorType) TokenIndex {
return self.token;
}
};
pub const VarType = struct {
base: Node = Node{ .id = .VarType },
token: TokenIndex,
pub fn iterate(self: *VarType, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const VarType) TokenIndex {
return self.token;
}
pub fn lastToken(self: *const VarType) TokenIndex {
return self.token;
}
};
pub const DocComment = struct {
base: Node = Node{ .id = .DocComment },
lines: LineList,
pub const LineList = SegmentedList(TokenIndex, 4);
pub fn iterate(self: *DocComment, index: usize) ?*Node {
return null;
}
pub fn firstToken(self: *const DocComment) TokenIndex {
return self.lines.at(0).*;
}
pub fn lastToken(self: *const DocComment) TokenIndex {
return self.lines.at(self.lines.len - 1).*;
}
};
pub const TestDecl = struct {
base: Node = Node{ .id = .TestDecl },
doc_comments: ?*DocComment,
test_token: TokenIndex,
name: *Node,
body_node: *Node,
pub fn iterate(self: *TestDecl, index: usize) ?*Node {
var i = index;
if (i < 1) return self.body_node;
i -= 1;
return null;
}
pub fn firstToken(self: *const TestDecl) TokenIndex {
return self.test_token;
}
pub fn lastToken(self: *const TestDecl) TokenIndex {
return self.body_node.lastToken();
}
};
};
test "iterate" {
var root = Node.Root{
.base = Node{ .id = Node.Id.Root },
.decls = Node.Root.DeclList.init(std.debug.global_allocator),
.eof_token = 0,
};
var base = &root.base;
testing.expect(base.iterate(0) == null);
}