zig/std/zig/ast.zig
2018-03-29 23:40:46 +02:00

636 lines
18 KiB
Zig

const std = @import("../index.zig");
const assert = std.debug.assert;
const ArrayList = std.ArrayList;
const Token = std.zig.Token;
const mem = std.mem;
pub const Node = struct {
id: Id,
comment: ?&NodeLineComment,
pub const Id = enum {
Root,
VarDecl,
Identifier,
FnProto,
ParamDecl,
Block,
InfixOp,
PrefixOp,
IntegerLiteral,
FloatLiteral,
StringLiteral,
UndefinedLiteral,
BuiltinCall,
Call,
LineComment,
TestDecl,
};
pub fn iterate(base: &Node, index: usize) ?&Node {
return switch (base.id) {
Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),
Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),
Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index),
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
Id.Call => @fieldParentPtr(NodeCall, "base", base).iterate(index),
Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
};
}
pub fn firstToken(base: &Node) Token {
return switch (base.id) {
Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),
Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),
Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).firstToken(),
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),
Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),
Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),
Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
Id.Call => @fieldParentPtr(NodeCall, "base", base).firstToken(),
Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
};
}
pub fn lastToken(base: &Node) Token {
return switch (base.id) {
Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),
Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),
Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).lastToken(),
Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),
Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),
Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),
Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),
Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
Id.Call => @fieldParentPtr(NodeCall, "base", base).lastToken(),
Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),
Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(),
};
}
};
pub const NodeRoot = struct {
base: Node,
decls: ArrayList(&Node),
eof_token: Token,
pub fn iterate(self: &NodeRoot, index: usize) ?&Node {
if (index < self.decls.len) {
return self.decls.items[self.decls.len - index - 1];
}
return null;
}
pub fn firstToken(self: &NodeRoot) Token {
return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();
}
pub fn lastToken(self: &NodeRoot) Token {
return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();
}
};
pub const NodeVarDecl = struct {
base: Node,
visib_token: ?Token,
name_token: Token,
eq_token: Token,
mut_token: Token,
comptime_token: ?Token,
extern_token: ?Token,
lib_name: ?&Node,
type_node: ?&Node,
align_node: ?&Node,
init_node: ?&Node,
semicolon_token: Token,
pub fn iterate(self: &NodeVarDecl, 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.init_node) |init_node| {
if (i < 1) return init_node;
i -= 1;
}
return null;
}
pub fn firstToken(self: &NodeVarDecl) Token {
if (self.visib_token) |visib_token| return visib_token;
if (self.comptime_token) |comptime_token| return comptime_token;
if (self.extern_token) |extern_token| return extern_token;
assert(self.lib_name == null);
return self.mut_token;
}
pub fn lastToken(self: &NodeVarDecl) Token {
return self.semicolon_token;
}
};
pub const NodeIdentifier = struct {
base: Node,
name_token: Token,
pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
return null;
}
pub fn firstToken(self: &NodeIdentifier) Token {
return self.name_token;
}
pub fn lastToken(self: &NodeIdentifier) Token {
return self.name_token;
}
};
pub const NodeFnProto = struct {
base: Node,
visib_token: ?Token,
fn_token: Token,
name_token: ?Token,
params: ArrayList(&Node),
return_type: ReturnType,
var_args_token: ?Token,
extern_token: ?Token,
inline_token: ?Token,
cc_token: ?Token,
body_node: ?&Node,
lib_name: ?&Node, // populated if this is an extern declaration
align_expr: ?&Node, // populated if align(A) is present
pub const ReturnType = union(enum) {
Explicit: &Node,
Infer: Token,
InferErrorSet: &Node,
};
pub fn iterate(self: &NodeFnProto, index: usize) ?&Node {
var i = index;
if (self.body_node) |body_node| {
if (i < 1) return body_node;
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;
},
ReturnType.Infer => {},
}
if (self.align_expr) |align_expr| {
if (i < 1) return align_expr;
i -= 1;
}
if (i < self.params.len) return self.params.items[self.params.len - i - 1];
i -= self.params.len;
if (self.lib_name) |lib_name| {
if (i < 1) return lib_name;
i -= 1;
}
return null;
}
pub fn firstToken(self: &NodeFnProto) Token {
if (self.visib_token) |visib_token| return visib_token;
if (self.extern_token) |extern_token| return extern_token;
assert(self.lib_name == null);
if (self.inline_token) |inline_token| return inline_token;
if (self.cc_token) |cc_token| return cc_token;
return self.fn_token;
}
pub fn lastToken(self: &NodeFnProto) Token {
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(),
ReturnType.Infer => |token| return token,
}
}
};
pub const NodeParamDecl = struct {
base: Node,
comptime_token: ?Token,
noalias_token: ?Token,
name_token: ?Token,
type_node: &Node,
var_args_token: ?Token,
pub fn iterate(self: &NodeParamDecl, index: usize) ?&Node {
var i = index;
if (i < 1) return self.type_node;
i -= 1;
return null;
}
pub fn firstToken(self: &NodeParamDecl) Token {
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: &NodeParamDecl) Token {
if (self.var_args_token) |var_args_token| return var_args_token;
return self.type_node.lastToken();
}
};
pub const NodeBlock = struct {
base: Node,
begin_token: Token,
end_token: Token,
statements: ArrayList(&Node),
pub fn iterate(self: &NodeBlock, index: usize) ?&Node {
var i = index;
if (i < self.statements.len) return self.statements.items[i];
i -= self.statements.len;
return null;
}
pub fn firstToken(self: &NodeBlock) Token {
return self.begin_token;
}
pub fn lastToken(self: &NodeBlock) Token {
return self.end_token;
}
};
pub const NodeInfixOp = struct {
base: Node,
op_token: Token,
lhs: &Node,
op: InfixOp,
rhs: &Node,
const InfixOp = enum {
Add,
AddWrap,
ArrayCat,
ArrayMult,
Assign,
AssignBitAnd,
AssignBitOr,
AssignBitShiftLeft,
AssignBitShiftRight,
AssignBitXor,
AssignDiv,
AssignMinus,
AssignMinusWrap,
AssignMod,
AssignPlus,
AssignPlusWrap,
AssignTimes,
AssignTimesWarp,
BangEqual,
BitAnd,
BitOr,
BitShiftLeft,
BitShiftRight,
BitXor,
BoolAnd,
BoolOr,
Div,
EqualEqual,
ErrorUnion,
GreaterOrEqual,
GreaterThan,
LessOrEqual,
LessThan,
MergeErrorSets,
Mod,
Mult,
MultWrap,
Period,
Sub,
SubWrap,
UnwrapMaybe,
};
pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
var i = index;
if (i < 1) return self.lhs;
i -= 1;
switch (self.op) {
InfixOp.Add,
InfixOp.AddWrap,
InfixOp.ArrayCat,
InfixOp.ArrayMult,
InfixOp.Assign,
InfixOp.AssignBitAnd,
InfixOp.AssignBitOr,
InfixOp.AssignBitShiftLeft,
InfixOp.AssignBitShiftRight,
InfixOp.AssignBitXor,
InfixOp.AssignDiv,
InfixOp.AssignMinus,
InfixOp.AssignMinusWrap,
InfixOp.AssignMod,
InfixOp.AssignPlus,
InfixOp.AssignPlusWrap,
InfixOp.AssignTimes,
InfixOp.AssignTimesWarp,
InfixOp.BangEqual,
InfixOp.BitAnd,
InfixOp.BitOr,
InfixOp.BitShiftLeft,
InfixOp.BitShiftRight,
InfixOp.BitXor,
InfixOp.BoolAnd,
InfixOp.BoolOr,
InfixOp.Div,
InfixOp.EqualEqual,
InfixOp.ErrorUnion,
InfixOp.GreaterOrEqual,
InfixOp.GreaterThan,
InfixOp.LessOrEqual,
InfixOp.LessThan,
InfixOp.MergeErrorSets,
InfixOp.Mod,
InfixOp.Mult,
InfixOp.MultWrap,
InfixOp.Period,
InfixOp.Sub,
InfixOp.SubWrap,
InfixOp.UnwrapMaybe => {},
}
if (i < 1) return self.rhs;
i -= 1;
return null;
}
pub fn firstToken(self: &NodeInfixOp) Token {
return self.lhs.firstToken();
}
pub fn lastToken(self: &NodeInfixOp) Token {
return self.rhs.lastToken();
}
};
pub const NodePrefixOp = struct {
base: Node,
op_token: Token,
op: PrefixOp,
rhs: &Node,
const PrefixOp = union(enum) {
Return,
Try,
AddrOf: AddrOfInfo,
};
const AddrOfInfo = struct {
align_expr: ?&Node,
bit_offset_start_token: ?Token,
bit_offset_end_token: ?Token,
const_token: ?Token,
volatile_token: ?Token,
};
pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {
var i = index;
switch (self.op) {
PrefixOp.Return,
PrefixOp.Try => {},
PrefixOp.AddrOf => |addr_of_info| {
if (addr_of_info.align_expr) |align_expr| {
if (i < 1) return align_expr;
i -= 1;
}
},
}
if (i < 1) return self.rhs;
i -= 1;
return null;
}
pub fn firstToken(self: &NodePrefixOp) Token {
return self.op_token;
}
pub fn lastToken(self: &NodePrefixOp) Token {
return self.rhs.lastToken();
}
};
pub const NodeIntegerLiteral = struct {
base: Node,
token: Token,
pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node {
return null;
}
pub fn firstToken(self: &NodeIntegerLiteral) Token {
return self.token;
}
pub fn lastToken(self: &NodeIntegerLiteral) Token {
return self.token;
}
};
pub const NodeFloatLiteral = struct {
base: Node,
token: Token,
pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node {
return null;
}
pub fn firstToken(self: &NodeFloatLiteral) Token {
return self.token;
}
pub fn lastToken(self: &NodeFloatLiteral) Token {
return self.token;
}
};
pub const NodeBuiltinCall = struct {
base: Node,
builtin_token: Token,
params: ArrayList(&Node),
rparen_token: Token,
pub fn iterate(self: &NodeBuiltinCall, 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: &NodeBuiltinCall) Token {
return self.builtin_token;
}
pub fn lastToken(self: &NodeBuiltinCall) Token {
return self.rparen_token;
}
};
pub const NodeCall = struct {
base: Node,
callee: &Node,
params: ArrayList(&Node),
rparen_token: Token,
pub fn iterate(self: &NodeCall, index: usize) ?&Node {
var i = index;
if (i < 1) return self.callee;
i -= 1;
if (i < self.params.len) return self.params.at(i);
i -= self.params.len;
return null;
}
pub fn firstToken(self: &NodeCall) Token {
return self.callee.firstToken();
}
pub fn lastToken(self: &NodeCall) Token {
return self.rparen_token;
}
};
pub const NodeStringLiteral = struct {
base: Node,
token: Token,
pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {
return null;
}
pub fn firstToken(self: &NodeStringLiteral) Token {
return self.token;
}
pub fn lastToken(self: &NodeStringLiteral) Token {
return self.token;
}
};
pub const NodeUndefinedLiteral = struct {
base: Node,
token: Token,
pub fn iterate(self: &NodeUndefinedLiteral, index: usize) ?&Node {
return null;
}
pub fn firstToken(self: &NodeUndefinedLiteral) Token {
return self.token;
}
pub fn lastToken(self: &NodeUndefinedLiteral) Token {
return self.token;
}
};
pub const NodeLineComment = struct {
base: Node,
lines: ArrayList(Token),
pub fn iterate(self: &NodeLineComment, index: usize) ?&Node {
return null;
}
pub fn firstToken(self: &NodeLineComment) Token {
return self.lines.at(0);
}
pub fn lastToken(self: &NodeLineComment) Token {
return self.lines.at(self.lines.len - 1);
}
};
pub const NodeTestDecl = struct {
base: Node,
test_token: Token,
name_token: Token,
body_node: &Node,
pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {
var i = index;
if (i < 1) return self.body_node;
i -= 1;
return null;
}
pub fn firstToken(self: &NodeTestDecl) Token {
return self.test_token;
}
pub fn lastToken(self: &NodeTestDecl) Token {
return self.body_node.lastToken();
}
};