2455 lines
69 KiB
Zig
2455 lines
69 KiB
Zig
const std = @import("std");
|
|||
|
|
|
||
|
|
const Location = @import("Location.zig").Location;
|
||
|
|
|
||
|
|
const Variant = @import("../Common/Variant.zig").Variant;
|
||
|
|
|
||
|
|
const cpp_std = @import("../cpp_std.zig");
|
||
|
|
|
||
|
|
const Ast = @This();
|
||
|
|
|
||
|
|
pub const Name = extern struct {
|
||
|
|
value: [*:0]const u8,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const Local = extern struct {
|
||
|
|
name: Name,
|
||
|
|
location: Location,
|
||
|
|
shadow: ?*Local,
|
||
|
|
functionDepth: usize,
|
||
|
|
loopDepth: usize,
|
||
|
|
isConst: bool,
|
||
|
|
/// exported is only a property set after construction
|
||
|
|
isExported: bool = false,
|
||
|
|
|
||
|
|
annotation: ?*Type,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub fn Array(comptime T: type) type {
|
||
|
|
return extern struct {
|
||
|
|
data: ?[*]T = null,
|
||
|
|
size: usize = 0,
|
||
|
|
|
||
|
|
const This = @This();
|
||
|
|
|
||
|
|
pub fn slice(self: This) []T {
|
||
|
|
return if (self.data) |d| d[0..self.size] else &.{};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
pub const TypeList = extern struct {
|
||
|
|
types: Array(*Type),
|
||
|
|
/// Null indicates no tail, not an untyped tail.
|
||
|
|
tailType: ?*TypePack = null,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const Node = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const Kind = enum(u32) {
|
||
|
|
unknown,
|
||
|
|
attr,
|
||
|
|
generic_type,
|
||
|
|
generic_type_pack,
|
||
|
|
expr_group,
|
||
|
|
expr_constant_nil,
|
||
|
|
expr_constant_bool,
|
||
|
|
expr_constant_number,
|
||
|
|
expr_constant_integer,
|
||
|
|
expr_constant_string,
|
||
|
|
expr_local,
|
||
|
|
expr_global,
|
||
|
|
expr_varargs,
|
||
|
|
expr_call,
|
||
|
|
expr_index_name,
|
||
|
|
expr_index_expr,
|
||
|
|
expr_function,
|
||
|
|
expr_table,
|
||
|
|
expr_unary,
|
||
|
|
expr_binary,
|
||
|
|
expr_type_assertion,
|
||
|
|
expr_if_else,
|
||
|
|
expr_interp_string,
|
||
|
|
expr_instantiate,
|
||
|
|
stat_block,
|
||
|
|
stat_if,
|
||
|
|
stat_while,
|
||
|
|
stat_repeat,
|
||
|
|
stat_break,
|
||
|
|
stat_continue,
|
||
|
|
stat_return,
|
||
|
|
stat_expr,
|
||
|
|
stat_local,
|
||
|
|
stat_for,
|
||
|
|
stat_for_in,
|
||
|
|
stat_assign,
|
||
|
|
stat_compound_assign,
|
||
|
|
stat_function,
|
||
|
|
stat_local_function,
|
||
|
|
stat_type_alias,
|
||
|
|
stat_type_function,
|
||
|
|
stat_declare_global,
|
||
|
|
stat_declare_function,
|
||
|
|
stat_class,
|
||
|
|
stat_declare_extern_type,
|
||
|
|
type_reference,
|
||
|
|
type_table,
|
||
|
|
type_function,
|
||
|
|
type_typeof,
|
||
|
|
type_optional,
|
||
|
|
type_union,
|
||
|
|
type_intersection,
|
||
|
|
expr_error,
|
||
|
|
stat_error,
|
||
|
|
type_error,
|
||
|
|
type_singleton_bool,
|
||
|
|
type_singleton_string,
|
||
|
|
type_group,
|
||
|
|
type_pack_explicit,
|
||
|
|
type_pack_variadic,
|
||
|
|
type_pack_generic,
|
||
|
|
|
||
|
|
pub fn Type(self: Kind) type {
|
||
|
|
return switch (self) {
|
||
|
|
.unknown => Node,
|
||
|
|
.attr => Attr,
|
||
|
|
.generic_type => GenericType,
|
||
|
|
.generic_type_pack => GenericTypePack,
|
||
|
|
.expr_group => ExprGroup,
|
||
|
|
.expr_constant_nil => ExprConstantNil,
|
||
|
|
.expr_constant_bool => ExprConstantBool,
|
||
|
|
.expr_constant_number => ExprConstantNumber,
|
||
|
|
.expr_constant_integer => ExprConstantInteger,
|
||
|
|
.expr_constant_string => ExprConstantString,
|
||
|
|
.expr_local => ExprLocal,
|
||
|
|
.expr_global => ExprGlobal,
|
||
|
|
.expr_varargs => ExprVarargs,
|
||
|
|
.expr_call => ExprCall,
|
||
|
|
.expr_index_name => ExprIndexName,
|
||
|
|
.expr_index_expr => ExprIndexExpr,
|
||
|
|
.expr_function => ExprFunction,
|
||
|
|
.expr_table => ExprTable,
|
||
|
|
.expr_unary => ExprUnary,
|
||
|
|
.expr_binary => ExprBinary,
|
||
|
|
.expr_type_assertion => ExprTypeAssertion,
|
||
|
|
.expr_if_else => ExprIfElse,
|
||
|
|
.expr_interp_string => ExprInterpString,
|
||
|
|
.expr_instantiate => ExprInstantiate,
|
||
|
|
.stat_block => StatBlock,
|
||
|
|
.stat_if => StatIf,
|
||
|
|
.stat_while => StatWhile,
|
||
|
|
.stat_repeat => StatRepeat,
|
||
|
|
.stat_break => StatBreak,
|
||
|
|
.stat_continue => StatContinue,
|
||
|
|
.stat_return => StatReturn,
|
||
|
|
.stat_expr => StatExpr,
|
||
|
|
.stat_local => StatLocal,
|
||
|
|
.stat_for => StatFor,
|
||
|
|
.stat_for_in => StatForIn,
|
||
|
|
.stat_assign => StatAssign,
|
||
|
|
.stat_compound_assign => StatCompoundAssign,
|
||
|
|
.stat_function => StatFunction,
|
||
|
|
.stat_local_function => StatLocalFunction,
|
||
|
|
.stat_type_alias => StatTypeAlias,
|
||
|
|
.stat_type_function => StatTypeFunction,
|
||
|
|
.stat_declare_global => StatDeclareGlobal,
|
||
|
|
.stat_declare_function => StatDeclareFunction,
|
||
|
|
.stat_class => StatClass,
|
||
|
|
.stat_declare_extern_type => StatDeclareExternType,
|
||
|
|
.type_reference => TypeReference,
|
||
|
|
.type_table => TypeTable,
|
||
|
|
.type_function => TypeFunction,
|
||
|
|
.type_typeof => TypeTypeof,
|
||
|
|
.type_optional => TypeOptional,
|
||
|
|
.type_union => TypeUnion,
|
||
|
|
.type_intersection => TypeIntersection,
|
||
|
|
.expr_error => ExprError,
|
||
|
|
.stat_error => StatError,
|
||
|
|
.type_error => TypeError,
|
||
|
|
.type_singleton_bool => TypeSingletonBool,
|
||
|
|
.type_singleton_string => TypeSingletonString,
|
||
|
|
.type_group => TypeGroup,
|
||
|
|
.type_pack_explicit => TypePackExplicit,
|
||
|
|
.type_pack_variadic => TypePackVariadic,
|
||
|
|
.type_pack_generic => TypePackGeneric,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn Parent(self: Kind) type {
|
||
|
|
return switch (self) {
|
||
|
|
.unknown => Node,
|
||
|
|
.attr,
|
||
|
|
.generic_type,
|
||
|
|
.generic_type_pack,
|
||
|
|
=> Node,
|
||
|
|
.expr_group,
|
||
|
|
.expr_constant_nil,
|
||
|
|
.expr_constant_bool,
|
||
|
|
.expr_constant_number,
|
||
|
|
.expr_constant_string,
|
||
|
|
.expr_local,
|
||
|
|
.expr_global,
|
||
|
|
.expr_varargs,
|
||
|
|
.expr_call,
|
||
|
|
.expr_index_name,
|
||
|
|
.expr_index_expr,
|
||
|
|
.expr_function,
|
||
|
|
.expr_table,
|
||
|
|
.expr_unary,
|
||
|
|
.expr_binary,
|
||
|
|
.expr_type_assertion,
|
||
|
|
.expr_if_else,
|
||
|
|
.expr_interp_string,
|
||
|
|
.expr_instantiate,
|
||
|
|
.expr_error,
|
||
|
|
=> Expr,
|
||
|
|
.stat_block,
|
||
|
|
.stat_if,
|
||
|
|
.stat_while,
|
||
|
|
.stat_repeat,
|
||
|
|
.stat_break,
|
||
|
|
.stat_continue,
|
||
|
|
.stat_return,
|
||
|
|
.stat_expr,
|
||
|
|
.stat_local,
|
||
|
|
.stat_for,
|
||
|
|
.stat_for_in,
|
||
|
|
.stat_assign,
|
||
|
|
.stat_compound_assign,
|
||
|
|
.stat_function,
|
||
|
|
.stat_local_function,
|
||
|
|
.stat_type_alias,
|
||
|
|
.stat_type_function,
|
||
|
|
.stat_declare_global,
|
||
|
|
.stat_declare_function,
|
||
|
|
.stat_class,
|
||
|
|
.stat_declare_extern_type,
|
||
|
|
.stat_error,
|
||
|
|
=> Stat,
|
||
|
|
.type_reference,
|
||
|
|
.type_table,
|
||
|
|
.type_function,
|
||
|
|
.type_typeof,
|
||
|
|
.type_optional,
|
||
|
|
.type_union,
|
||
|
|
.type_intersection,
|
||
|
|
.type_error,
|
||
|
|
.type_singleton_bool,
|
||
|
|
.type_singleton_string,
|
||
|
|
.type_group,
|
||
|
|
=> Ast.Type,
|
||
|
|
.type_pack_explicit,
|
||
|
|
.type_pack_variadic,
|
||
|
|
.type_pack_generic,
|
||
|
|
=> Ast.TypePack,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
};
|
||
|
|
|
||
|
|
pub fn IsFn(base: anytype, comptime to: Node.Kind) bool {
|
||
|
|
return base.classIndex == to;
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn AsCastFn(base: anytype, comptime to: Node.Kind) ?*to.Type() {
|
||
|
|
return if (base.classIndex == to) @ptrCast(@alignCast(base)) else null;
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn AsStatCastFn(base: anytype) *Stat {
|
||
|
|
return @ptrCast(@alignCast(base));
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn AsExprCastFn(base: anytype) *Expr {
|
||
|
|
return @ptrCast(@alignCast(base));
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn AsTypeCastFn(base: anytype) *Type {
|
||
|
|
return @ptrCast(@alignCast(base));
|
||
|
|
}
|
||
|
|
|
||
|
|
pub const Attr = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .attr,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
type: Attr.Type,
|
||
|
|
args: Array(*Expr),
|
||
|
|
name: Name,
|
||
|
|
|
||
|
|
pub const Type = enum(c_int) {
|
||
|
|
Checked = 0,
|
||
|
|
Native = 1,
|
||
|
|
Deprecated = 2,
|
||
|
|
DebugNoinline = 3,
|
||
|
|
Unknown = 4,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const Expr = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
return Visitor.selfVisit(visitor, self);
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn isLValue(expr: *const Expr) bool {
|
||
|
|
return switch (expr.classIndex) {
|
||
|
|
.expr_local, .expr_global, .expr_index_name, .expr_index_expr => true,
|
||
|
|
else => false,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn getIdentifier(node: *Expr) ?Name {
|
||
|
|
if (node.as(.expr_global)) |expr|
|
||
|
|
return expr.name;
|
||
|
|
|
||
|
|
if (node.as(.expr_local)) |expr|
|
||
|
|
return expr.local.name;
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const Stat = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
hasSemicolon: bool,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
return Visitor.selfVisit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const GenericType = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .generic_type,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
defaultValue: ?*Type = null,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
if (self.defaultValue) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const GenericTypePack = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .generic_type_pack,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
defaultValue: ?*TypePack = null,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
if (self.defaultValue) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprGroup = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_group,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
expr: *Expr,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprConstantNil = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_constant_nil,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprConstantBool = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_constant_bool,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
value: bool,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ConstantNumberParseResult = enum(c_int) {
|
||
|
|
Ok = 0,
|
||
|
|
Imprecise = 1,
|
||
|
|
Malformed = 2,
|
||
|
|
BinOverflow = 3,
|
||
|
|
HexOverflow = 4,
|
||
|
|
IntOverflow = 5,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprConstantNumber = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_constant_number,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
value: f64,
|
||
|
|
parseResult: ConstantNumberParseResult,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprConstantInteger = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_constant_integer,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
value: i64,
|
||
|
|
parseResult: ConstantNumberParseResult,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprConstantString = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_constant_string,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
value: Array(u8),
|
||
|
|
quoteStyle: QuoteStyle,
|
||
|
|
|
||
|
|
pub const QuoteStyle = enum(c_int) {
|
||
|
|
/// A string created using double quotes or an interpolated string,
|
||
|
|
/// as in:
|
||
|
|
///
|
||
|
|
/// "foo", `My name is {protagonist}! / And I'm {antagonist}!`
|
||
|
|
///
|
||
|
|
QuotedSimple = 0,
|
||
|
|
/// A string created using single quotes, as in:
|
||
|
|
///
|
||
|
|
/// 'bar'
|
||
|
|
///
|
||
|
|
QuotedSingle = 1,
|
||
|
|
/// A string created using `[[ ... ]]` as in:
|
||
|
|
///
|
||
|
|
/// [[ Gee, this sure is a long string.
|
||
|
|
/// it even has a new line in it! ]]
|
||
|
|
///
|
||
|
|
QuotedRaw = 2,
|
||
|
|
/// A "string" in the context of a table literal, as in:
|
||
|
|
///
|
||
|
|
/// { foo = 42 } -- `foo` here is a "constant string"
|
||
|
|
///
|
||
|
|
Unquoted = 3,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprLocal = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_local,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
local: ?*Local,
|
||
|
|
upvalue: bool,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprGlobal = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_global,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprVarargs = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_varargs,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprCall = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_call,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
func: *Expr,
|
||
|
|
/// These will only be filled in specifically `t:f<<A, B>>()`.
|
||
|
|
/// In `f<<A, B>>()`, this is parsed as `f<<A, B>>` as an expression,
|
||
|
|
/// which is then called.
|
||
|
|
typeArguments: Array(TypeOrPack),
|
||
|
|
args: Array(*Expr),
|
||
|
|
self: bool,
|
||
|
|
argLocation: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.func.visit(visitor);
|
||
|
|
|
||
|
|
for (self.args.slice()) |arg|
|
||
|
|
try arg.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprIndexName = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_index_name,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
expr: *Expr,
|
||
|
|
index: Name,
|
||
|
|
indexLocation: Location,
|
||
|
|
opPosition: Location.Position,
|
||
|
|
op: u8 = '.',
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprIndexExpr = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_index_expr,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
expr: *Expr,
|
||
|
|
index: *Expr,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
try self.index.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprFunction = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_function,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
attributes: Array(*Attr),
|
||
|
|
generics: Array(*GenericType),
|
||
|
|
genericPacks: Array(*GenericTypePack),
|
||
|
|
self: ?*Local,
|
||
|
|
args: Array(*Local),
|
||
|
|
returnAnnotation: ?*TypePack,
|
||
|
|
vararg: bool = false,
|
||
|
|
varargLocation: Location,
|
||
|
|
varargAnnotation: ?*TypePack,
|
||
|
|
body: *StatBlock,
|
||
|
|
functionDepth: usize,
|
||
|
|
debugname: Name,
|
||
|
|
argLocation: cpp_std.Optional(Location),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.args.slice()) |arg|
|
||
|
|
if (arg.annotation) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
|
||
|
|
if (self.varargAnnotation) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
|
||
|
|
if (self.returnAnnotation) |annotation|
|
||
|
|
try annotation.visit(visitor);
|
||
|
|
|
||
|
|
try self.body.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn hasNativeAttribute(self: *ExprFunction) bool {
|
||
|
|
for (self.attributes.slice()) |attr| {
|
||
|
|
if (attr.type == .Native)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn hasAttribute(self: *ExprFunction, attrType: Attr.Type) bool {
|
||
|
|
for (self.attributes.slice()) |attr| {
|
||
|
|
if (attr.type == attrType)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprTable = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_table,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
items: Array(Item),
|
||
|
|
|
||
|
|
pub const Item = extern struct {
|
||
|
|
pub const Kind = enum(c_int) {
|
||
|
|
List, // foo, in which case key is a nullptr
|
||
|
|
Record, // foo=bar, in which case key is a AstExprConstantString
|
||
|
|
General, // [foo]=bar
|
||
|
|
};
|
||
|
|
|
||
|
|
kind: Kind,
|
||
|
|
/// can be nullptr!
|
||
|
|
key: ?*Expr,
|
||
|
|
value: *Expr,
|
||
|
|
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.items.slice()) |item| {
|
||
|
|
if (item.key) |key|
|
||
|
|
try key.visit(visitor);
|
||
|
|
|
||
|
|
try item.value.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprUnary = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_unary,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
op: Op,
|
||
|
|
expr: *Expr,
|
||
|
|
|
||
|
|
pub const Op = enum(c_int) {
|
||
|
|
Not = 0,
|
||
|
|
Minus = 1,
|
||
|
|
Len = 2,
|
||
|
|
|
||
|
|
pub fn toString(self: Op) []const u8 {
|
||
|
|
return switch (self) {
|
||
|
|
.Not => "not",
|
||
|
|
.Minus => "-",
|
||
|
|
.Len => "#",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprBinary = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_binary,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
op: Op,
|
||
|
|
left: *Expr,
|
||
|
|
right: *Expr,
|
||
|
|
|
||
|
|
pub const Op = enum(c_int) {
|
||
|
|
Add = 0,
|
||
|
|
Sub = 1,
|
||
|
|
Mul = 2,
|
||
|
|
Div = 3,
|
||
|
|
FloorDiv = 4,
|
||
|
|
Mod = 5,
|
||
|
|
Pow = 6,
|
||
|
|
Concat = 7,
|
||
|
|
CompareNe = 8,
|
||
|
|
CompareEq = 9,
|
||
|
|
CompareLt = 10,
|
||
|
|
CompareLe = 11,
|
||
|
|
CompareGt = 12,
|
||
|
|
CompareGe = 13,
|
||
|
|
And = 14,
|
||
|
|
Or = 15,
|
||
|
|
__Count = 16,
|
||
|
|
|
||
|
|
pub fn toString(self: Op) []const u8 {
|
||
|
|
return switch (self) {
|
||
|
|
.Add => "+",
|
||
|
|
.Sub => "-",
|
||
|
|
.Mul => "*",
|
||
|
|
.Div => "/",
|
||
|
|
.FloorDiv => "//",
|
||
|
|
.Mod => "%",
|
||
|
|
.Pow => "^",
|
||
|
|
.Concat => "..",
|
||
|
|
.CompareNe => "~=",
|
||
|
|
.CompareEq => "==",
|
||
|
|
.CompareLt => "<",
|
||
|
|
.CompareLe => "<=",
|
||
|
|
.CompareGt => ">",
|
||
|
|
.CompareGe => ">=",
|
||
|
|
.And => "and",
|
||
|
|
.Or => "or",
|
||
|
|
.__Count => unreachable,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.left.visit(visitor);
|
||
|
|
try self.right.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprTypeAssertion = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_type_assertion,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
expr: *Expr,
|
||
|
|
annotation: *Type,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
try self.annotation.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprIfElse = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_if_else,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
condition: *Expr,
|
||
|
|
hasThen: bool,
|
||
|
|
trueExpr: *Expr,
|
||
|
|
hasElse: bool,
|
||
|
|
falseExpr: *Expr,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.condition.visit(visitor);
|
||
|
|
try self.trueExpr.visit(visitor);
|
||
|
|
try self.falseExpr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprInterpString = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_interp_string,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
/// An interpolated string such as `foo{bar}baz` is represented as
|
||
|
|
/// an array of strings for "foo" and "bar", and an array of expressions for "baz".
|
||
|
|
/// `strings` will always have one more element than `expressions`.
|
||
|
|
strings: Array(Array(u8)),
|
||
|
|
expressions: Array(*Expr),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.expressions.slice()) |expr|
|
||
|
|
try expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/// f<<T>>
|
||
|
|
pub const ExprInstantiate = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_instantiate,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
expr: *Expr,
|
||
|
|
typeArguments: Array(TypeOrPack),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
try TypeOrPack.visitArray(self.typeArguments, visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatBlock = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_block,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
body: Array(*Stat),
|
||
|
|
/// Indicates whether or not this block has been terminated in a
|
||
|
|
/// syntactically valid way.
|
||
|
|
///
|
||
|
|
/// This is usually but not always done with the 'end' keyword. StatIf
|
||
|
|
/// and StatRepeat are the two main exceptions to this.
|
||
|
|
///
|
||
|
|
/// The 'then' clause of an if statement can properly be closed by the
|
||
|
|
/// keywords 'else' or 'elseif'. A 'repeat' loop's body is closed with the
|
||
|
|
/// 'until' keyword.
|
||
|
|
hasEnd: bool = false,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self))
|
||
|
|
for (self.body.slice()) |stat|
|
||
|
|
try stat.visit(visitor);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatIf = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_if,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
condition: *Expr,
|
||
|
|
thenbody: *StatBlock,
|
||
|
|
elsebody: ?*Stat,
|
||
|
|
thenLocation: cpp_std.Optional(Location),
|
||
|
|
/// Active for 'elseif' as well
|
||
|
|
elseLocation: cpp_std.Optional(Location),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.condition.visit(visitor);
|
||
|
|
try self.thenbody.visit(visitor);
|
||
|
|
|
||
|
|
if (self.elsebody) |elsebody|
|
||
|
|
try elsebody.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatWhile = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_while,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
condition: *Expr,
|
||
|
|
body: *StatBlock,
|
||
|
|
hasDo: bool = false,
|
||
|
|
doLocation: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.condition.visit(visitor);
|
||
|
|
try self.body.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatRepeat = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_repeat,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
condition: *Expr,
|
||
|
|
body: *StatBlock,
|
||
|
|
DEPRECATED_hasUntil: bool = false,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.body.visit(visitor);
|
||
|
|
try self.condition.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatBreak = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_break,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatContinue = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_continue,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatReturn = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_return,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
list: Array(*Expr),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.list.slice()) |expr|
|
||
|
|
try expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatExpr = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_expr,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
expr: *Expr,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self))
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatLocal = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_local,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
vars: Array(*Local),
|
||
|
|
values: Array(*Expr),
|
||
|
|
|
||
|
|
isConst: bool = false,
|
||
|
|
isExported: bool = false,
|
||
|
|
|
||
|
|
keywordLocation: cpp_std.Optional(Location),
|
||
|
|
equalsSignLocation: cpp_std.Optional(Location),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.vars.slice()) |@"var"|
|
||
|
|
if (@"var".annotation) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
|
||
|
|
for (self.values.slice()) |expr|
|
||
|
|
try expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatFor = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_for,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
variable: *Local,
|
||
|
|
from: *Expr,
|
||
|
|
to: *Expr,
|
||
|
|
step: ?*Expr,
|
||
|
|
body: *StatBlock,
|
||
|
|
hasDo: bool = false,
|
||
|
|
doLocation: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
if (self.variable.annotation) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
|
||
|
|
try self.from.visit(visitor);
|
||
|
|
try self.to.visit(visitor);
|
||
|
|
|
||
|
|
if (self.step) |step|
|
||
|
|
try step.visit(visitor);
|
||
|
|
|
||
|
|
try self.body.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatForIn = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_for_in,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
vars: Array(*Local),
|
||
|
|
values: Array(*Expr),
|
||
|
|
body: *StatBlock,
|
||
|
|
hasIn: bool = false,
|
||
|
|
inLocation: Location,
|
||
|
|
hasDo: bool = false,
|
||
|
|
doLocation: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.vars.slice()) |@"var"|
|
||
|
|
if (@"var".annotation) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
|
||
|
|
for (self.values.slice()) |expr|
|
||
|
|
try expr.visit(visitor);
|
||
|
|
|
||
|
|
try self.body.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatAssign = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_assign,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
vars: Array(*Expr),
|
||
|
|
values: Array(*Expr),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.vars.slice()) |lvalue|
|
||
|
|
try lvalue.visit(visitor);
|
||
|
|
|
||
|
|
for (self.values.slice()) |expr|
|
||
|
|
try expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatCompoundAssign = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_compound_assign,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
op: ExprBinary.Op,
|
||
|
|
variable: *Expr,
|
||
|
|
value: *Expr,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.variable.visit(visitor);
|
||
|
|
try self.value.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatFunction = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_function,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
name: *Expr,
|
||
|
|
func: *ExprFunction,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.name.visit(visitor);
|
||
|
|
try self.func.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatLocalFunction = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_local_function,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
name: *Local,
|
||
|
|
func: *ExprFunction,
|
||
|
|
isConst: bool = false,
|
||
|
|
/// Position of the `const` keyword; Position::missing() when isConst is false.
|
||
|
|
constKeywordBegin: Location.Position,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.func.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatTypeAlias = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_type_alias,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
generics: Array(*GenericType),
|
||
|
|
genericPacks: Array(*GenericTypePack),
|
||
|
|
type: *Type,
|
||
|
|
exported: bool,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.generics.slice()) |el|
|
||
|
|
try el.visit(visitor);
|
||
|
|
|
||
|
|
for (self.genericPacks.slice()) |el|
|
||
|
|
try el.visit(visitor);
|
||
|
|
|
||
|
|
try self.type.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatTypeFunction = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_type_function,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
body: *ExprFunction = undefined,
|
||
|
|
exported: bool = false,
|
||
|
|
hasErrors: bool = false,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.body.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatDeclareGlobal = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_declare_global,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
type: *Type,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.type.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ArgumentName = extern struct {
|
||
|
|
name: Name,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatDeclareFunction = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_declare_function,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
attributes: Array(*Attr),
|
||
|
|
name: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
generics: Array(*GenericType),
|
||
|
|
genericPacks: Array(*GenericTypePack),
|
||
|
|
params: TypeList,
|
||
|
|
paramNames: Array(ArgumentName),
|
||
|
|
vararg: bool = false,
|
||
|
|
varargLocation: Location,
|
||
|
|
retTypes: *TypePack,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try Visitor.visitTypeList(visitor, self.params);
|
||
|
|
try self.retTypes.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn isCheckedFunction(self: *StatDeclareFunction) bool {
|
||
|
|
for (self.attributes.slice()) |attr| {
|
||
|
|
if (attr.type == .Checked)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn hasAttribute(self: *StatDeclareFunction, attrType: Attr.Type) bool {
|
||
|
|
for (self.attributes.slice()) |attr| {
|
||
|
|
if (attr.type == attrType)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TableAccess = enum(c_int) {
|
||
|
|
Read = 1,
|
||
|
|
Write = 2,
|
||
|
|
ReadWrite = 3,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const DeclaredExternTypeProperty = extern struct {
|
||
|
|
name: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
ty: *Type = undefined,
|
||
|
|
isMethod: bool = false,
|
||
|
|
location: Location,
|
||
|
|
access: TableAccess = .ReadWrite,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ClassProperty = extern struct {
|
||
|
|
qualifierLocation: Location,
|
||
|
|
name: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
typeColonLocation: cpp_std.Optional(Location) = .nullopt,
|
||
|
|
ty: ?*Type = null,
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ClassMethod = extern struct {
|
||
|
|
qualifierLocation: cpp_std.Optional(Location),
|
||
|
|
keywordLocation: Location,
|
||
|
|
functionName: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
function: *ExprFunction,
|
||
|
|
};
|
||
|
|
|
||
|
|
const ClassMember = Variant(&.{ ClassProperty, ClassMethod });
|
||
|
|
|
||
|
|
pub const StatClass = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_class,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
members: Array(ClassMember),
|
||
|
|
exported: bool,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.members.slice()) |member| {
|
||
|
|
switch (member.typeId) {
|
||
|
|
0 => if (member.@"union"().@"0".ty) |ty|
|
||
|
|
try ty.visit(visitor),
|
||
|
|
1 => try member.@"union"().@"1".function.visit(visitor),
|
||
|
|
else => unreachable,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TableIndexer = extern struct {
|
||
|
|
indexType: *Type,
|
||
|
|
resultType: *Type,
|
||
|
|
location: Location,
|
||
|
|
access: TableAccess = .ReadWrite,
|
||
|
|
accessLocation: cpp_std.Optional(Location),
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatDeclareExternType = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_declare_extern_type,
|
||
|
|
location: Location,
|
||
|
|
hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
name: Name,
|
||
|
|
superName: cpp_std.Optional(Name),
|
||
|
|
props: Array(DeclaredExternTypeProperty),
|
||
|
|
indexer: *TableIndexer,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.props.slice()) |prop|
|
||
|
|
try prop.ty.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const Type = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
return Visitor.selfVisit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/// Don't have Luau::Variant available, it's a bit of an overhead, but a plain struct is nice to use
|
||
|
|
pub const TypeOrPack = extern struct {
|
||
|
|
type: ?*Type = null,
|
||
|
|
typePack: ?*TypePack = null,
|
||
|
|
|
||
|
|
pub fn visitArray(self: Array(TypeOrPack), visitor: anytype) !void {
|
||
|
|
for (self.slice()) |param| {
|
||
|
|
if (param.type) |node|
|
||
|
|
try node.visit(visitor)
|
||
|
|
else
|
||
|
|
try param.typePack.?.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeReference = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_reference,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
hasParameterList: bool,
|
||
|
|
prefix: cpp_std.Optional(Name),
|
||
|
|
prefixLocation: cpp_std.Optional(Location),
|
||
|
|
prefixLocal: ?*Local = null,
|
||
|
|
name: Name,
|
||
|
|
nameLocation: Location,
|
||
|
|
parameters: Array(TypeOrPack),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try TypeOrPack.visitArray(self.parameters, visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TableProp = extern struct {
|
||
|
|
name: Name,
|
||
|
|
location: Location,
|
||
|
|
type: *Type,
|
||
|
|
access: TableAccess = .ReadWrite,
|
||
|
|
accessLocation: cpp_std.Optional(Location),
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeTable = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_table,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
props: Array(TableProp),
|
||
|
|
indexer: ?*TableIndexer,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.props.slice()) |node|
|
||
|
|
try node.type.visit(visitor);
|
||
|
|
|
||
|
|
if (self.indexer) |indexer| {
|
||
|
|
try indexer.indexType.visit(visitor);
|
||
|
|
try indexer.resultType.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeFunction = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_function,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
attributes: Array(*Attr),
|
||
|
|
generics: Array(*GenericType),
|
||
|
|
genericPacks: Array(*GenericTypePack),
|
||
|
|
argTypes: TypeList,
|
||
|
|
argNames: Array(cpp_std.Optional(ArgumentName)),
|
||
|
|
returnTypes: *TypePack,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try Visitor.visitTypeList(visitor, self.argTypes);
|
||
|
|
try self.returnTypes.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn isCheckedFunction(self: *TypeFunction) bool {
|
||
|
|
for (self.attributes.slice()) |attr| {
|
||
|
|
if (attr.type == .Checked)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn hasAttribute(self: *TypeFunction, attrType: Attr.Type) bool {
|
||
|
|
for (self.attributes.slice()) |attr| {
|
||
|
|
if (attr.type == attrType)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeTypeof = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_typeof,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
expr: *Expr,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.expr.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeOptional = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_optional,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeUnion = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_union,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
types: Array(*Type),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.types.slice()) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeIntersection = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_intersection,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
types: Array(*Type),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.types.slice()) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const ExprError = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .expr_error,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
expressions: Array(*Expr),
|
||
|
|
messageIndex: c_uint,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.expressions.slice()) |expression|
|
||
|
|
try expression.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const StatError = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .stat_error,
|
||
|
|
location: Location,
|
||
|
|
MAYBE_hasSemicolon: bool = false,
|
||
|
|
|
||
|
|
expressions: Array(*Expr),
|
||
|
|
statements: Array(*Stat),
|
||
|
|
messageIndex: c_uint,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.expressions.slice()) |expression|
|
||
|
|
try expression.visit(visitor);
|
||
|
|
|
||
|
|
for (self.statements.slice()) |statement|
|
||
|
|
try statement.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeError = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_error,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
types: Array(*Type),
|
||
|
|
isMissing: bool,
|
||
|
|
messageIndex: c_uint,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.types.slice()) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeSingletonBool = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_singleton_bool,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
value: bool,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeSingletonString = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_singleton_string,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
value: Array(u8),
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypeGroup = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_group,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
type: *Type,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
try self.type.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypePack = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
return Visitor.selfVisit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypePackExplicit = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_pack_explicit,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
typeList: TypeList,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self)) {
|
||
|
|
for (self.typeList.types.slice()) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
|
||
|
|
if (self.typeList.tailType) |node|
|
||
|
|
try node.visit(visitor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypePackVariadic = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_pack_variadic,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
variadicType: *Type,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
if (try Visitor.visit(visitor, self))
|
||
|
|
try self.variadicType.visit(visitor);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const TypePackGeneric = extern struct {
|
||
|
|
vtable: *const anyopaque,
|
||
|
|
|
||
|
|
classIndex: Node.Kind = .type_pack_generic,
|
||
|
|
location: Location,
|
||
|
|
|
||
|
|
genericName: Name,
|
||
|
|
|
||
|
|
pub const is = IsFn;
|
||
|
|
pub const as = AsCastFn;
|
||
|
|
pub const asExpr = AsExprCastFn;
|
||
|
|
pub const asStat = AsStatCastFn;
|
||
|
|
pub const asType = AsTypeCastFn;
|
||
|
|
|
||
|
|
pub fn visit(self: *@This(), visitor: anytype) !void {
|
||
|
|
_ = try Visitor.visit(visitor, self);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
pub const Visitor = struct {
|
||
|
|
pub fn visitTypeList(self: anytype, this: TypeList) !void {
|
||
|
|
for (this.types.slice()) |node|
|
||
|
|
try node.visit(self);
|
||
|
|
|
||
|
|
if (this.tailType) |node|
|
||
|
|
try node.visit(self);
|
||
|
|
}
|
||
|
|
|
||
|
|
fn getVisitorStruct(comptime self: type) type {
|
||
|
|
return switch (@typeInfo(self)) {
|
||
|
|
.pointer => |ptr| ptr.child,
|
||
|
|
.@"struct" => |s| s,
|
||
|
|
else => |t| @compileError("Visitor type unsupported: " ++ @typeName(t)),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
fn hasVistDecl(comptime self: type, comptime name: [:0]const u8) bool {
|
||
|
|
return @hasDecl(getVisitorStruct(self), name);
|
||
|
|
}
|
||
|
|
|
||
|
|
fn callVisitorDecl(self: anytype, comptime name: [:0]const u8, this: anytype) !bool {
|
||
|
|
const visitor_type = @TypeOf(self);
|
||
|
|
const visitor_struct = getVisitorStruct(visitor_type);
|
||
|
|
const visitor_fn = @field(visitor_struct, name);
|
||
|
|
return switch (@typeInfo(visitor_type)) {
|
||
|
|
.type => visitor_fn(@ptrCast(@alignCast(this))),
|
||
|
|
.pointer, .@"struct" => visitor_fn(self, @ptrCast(@alignCast(this))),
|
||
|
|
else => unreachable,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
fn visitByName(self: anytype, comptime name: [:0]const u8, this: anytype) ?bool {
|
||
|
|
const namespace = @typeName(Ast);
|
||
|
|
const ast_name = name[namespace.len + 1 ..];
|
||
|
|
const fn_name = "visit" ++ ast_name;
|
||
|
|
|
||
|
|
if (comptime hasVistDecl(@TypeOf(self), fn_name))
|
||
|
|
return callVisitorDecl(self, fn_name, this);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
fn getParent(comptime ast: type) type {
|
||
|
|
const namespace = @typeName(Ast);
|
||
|
|
const ast_name = @typeName(ast)[namespace.len + 1 ..];
|
||
|
|
if (std.mem.eql(u8, ast_name, "Attr") or
|
||
|
|
std.mem.eql(u8, ast_name, "GenericType") or
|
||
|
|
std.mem.eql(u8, ast_name, "GenericTypePack") or
|
||
|
|
std.mem.eql(u8, ast_name, "Expr") or
|
||
|
|
std.mem.eql(u8, ast_name, "Stat"))
|
||
|
|
return Ast.Node
|
||
|
|
else if (std.mem.startsWith(u8, ast_name, "Expr"))
|
||
|
|
return Ast.Expr
|
||
|
|
else if (std.mem.startsWith(u8, ast_name, "Stat"))
|
||
|
|
return Ast.Stat
|
||
|
|
else if (std.mem.startsWith(u8, ast_name, "TypePack"))
|
||
|
|
return Ast.TypePack
|
||
|
|
else if (std.mem.startsWith(u8, ast_name, "Type"))
|
||
|
|
return Ast.Type;
|
||
|
|
@compileError("Invalid Ast type");
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn selfVisit(self: anytype, this: anytype) anyerror!void {
|
||
|
|
switch (this.classIndex) {
|
||
|
|
inline else => |kind| {
|
||
|
|
const kind_type = kind.Type();
|
||
|
|
if (@hasDecl(kind_type, "visit"))
|
||
|
|
try kind_type.visit(@ptrCast(@alignCast(this)), self);
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn visit(self: anytype, this: anytype) anyerror!bool {
|
||
|
|
const node_type = @typeInfo(@TypeOf(this));
|
||
|
|
const ast_type = node_type.pointer.child;
|
||
|
|
comptime if (node_type != .pointer)
|
||
|
|
@compileError("Invalid Ast type");
|
||
|
|
comptime if (!std.mem.startsWith(u8, @typeName(ast_type), @typeName(Ast)))
|
||
|
|
@compileError("Invalid Ast type");
|
||
|
|
|
||
|
|
const namespace = @typeName(Ast);
|
||
|
|
if (ast_type == Ast.Node) {
|
||
|
|
if (comptime hasVistDecl(@TypeOf(self), "visit"))
|
||
|
|
return callVisitorDecl(self, "visit", this);
|
||
|
|
return true;
|
||
|
|
} else if (ast_type == Ast.Type or ast_type == Ast.TypePack) {
|
||
|
|
const ast_name = @typeName(ast_type)[namespace.len + 1 ..];
|
||
|
|
if (comptime hasVistDecl(@TypeOf(self), "visit" ++ ast_name))
|
||
|
|
return callVisitorDecl(self, "visit" ++ ast_name, this);
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
const ast_name = @typeName(ast_type)[namespace.len + 1 ..];
|
||
|
|
const fn_name = "visit" ++ ast_name;
|
||
|
|
|
||
|
|
if (comptime hasVistDecl(@TypeOf(self), fn_name))
|
||
|
|
return callVisitorDecl(self, fn_name, this);
|
||
|
|
|
||
|
|
const parent = comptime getParent(ast_type);
|
||
|
|
return Visitor.visit(self, @as(*parent, @ptrCast(@alignCast(this))));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
test Node {
|
||
|
|
const Lexer = @import("Lexer.zig");
|
||
|
|
const Parser = @import("Parser.zig");
|
||
|
|
const Allocator = @import("Allocator.zig");
|
||
|
|
|
||
|
|
{
|
||
|
|
const allocator = Allocator.init();
|
||
|
|
defer allocator.deinit();
|
||
|
|
|
||
|
|
const table = Lexer.AstNameTable.init(allocator);
|
||
|
|
defer table.deinit();
|
||
|
|
const source =
|
||
|
|
\\local x = 1;
|
||
|
|
\\local x = 2
|
||
|
|
\\local x = 3
|
||
|
|
\\
|
||
|
|
;
|
||
|
|
|
||
|
|
var parse_result = Parser.parse(source, table, allocator, .{});
|
||
|
|
defer parse_result.deinit();
|
||
|
|
|
||
|
|
const root = parse_result.root;
|
||
|
|
|
||
|
|
try std.testing.expectEqual(Node.Kind.stat_block, root.classIndex);
|
||
|
|
|
||
|
|
const stats = root.body.slice();
|
||
|
|
try std.testing.expectEqual(3, stats.len);
|
||
|
|
|
||
|
|
for (stats, 1..) |node, order| {
|
||
|
|
switch (node.classIndex) {
|
||
|
|
.stat_local => {
|
||
|
|
const local: *StatLocal = node.as(.stat_local).?;
|
||
|
|
try std.testing.expectEqualStrings("x", std.mem.span(local.vars.slice()[0].name.value));
|
||
|
|
try std.testing.expect(@as(f64, @floatFromInt(order)) == local.values.slice()[0].as(.expr_constant_number).?.value);
|
||
|
|
},
|
||
|
|
else => {},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
const allocator = Allocator.init();
|
||
|
|
defer allocator.deinit();
|
||
|
|
|
||
|
|
const astNameTable = Lexer.AstNameTable.init(allocator);
|
||
|
|
defer astNameTable.deinit();
|
||
|
|
const source =
|
||
|
|
\\@native
|
||
|
|
\\function test()
|
||
|
|
\\end
|
||
|
|
\\
|
||
|
|
;
|
||
|
|
|
||
|
|
const parseResult = Parser.parse(source, astNameTable, allocator, .{});
|
||
|
|
defer parseResult.deinit();
|
||
|
|
|
||
|
|
{
|
||
|
|
const FunctionVisitor = struct {
|
||
|
|
hasNativeFunction: bool = false,
|
||
|
|
|
||
|
|
pub fn visitExprFunction(self: *@This(), node: *Ast.ExprFunction) !bool {
|
||
|
|
errdefer unreachable;
|
||
|
|
try node.body.visit(self);
|
||
|
|
|
||
|
|
if (!self.hasNativeFunction and node.hasNativeAttribute())
|
||
|
|
self.hasNativeFunction = true;
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var visitor: FunctionVisitor = .{};
|
||
|
|
|
||
|
|
parseResult.root.visit(&visitor) catch unreachable;
|
||
|
|
// no errors expected, since none of the visitor method does error
|
||
|
|
|
||
|
|
try std.testing.expect(visitor.hasNativeFunction);
|
||
|
|
}
|
||
|
|
{
|
||
|
|
const FunctionVisitor = struct {
|
||
|
|
hasNativeFunction: bool = false,
|
||
|
|
|
||
|
|
pub fn visitExprFunction(self: *@This(), node: *Ast.ExprFunction) !bool {
|
||
|
|
try node.body.visit(self);
|
||
|
|
|
||
|
|
if (!self.hasNativeFunction and node.hasNativeAttribute()) {
|
||
|
|
self.hasNativeFunction = true;
|
||
|
|
return error.Done;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var visitor: FunctionVisitor = .{};
|
||
|
|
|
||
|
|
parseResult.root.visit(&visitor) catch |err| switch (err) {
|
||
|
|
error.Done => {}, // this error is defined in the visitor
|
||
|
|
else => unreachable,
|
||
|
|
};
|
||
|
|
|
||
|
|
try std.testing.expect(visitor.hasNativeFunction);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
test "AstValuesCheck" {
|
||
|
|
if (@import("builtin").cpu.arch.isWasm() or @import("builtin").os.tag == .windows)
|
||
|
|
return error.SkipZigTest;
|
||
|
|
const AstValues = struct {
|
||
|
|
pub extern "c" const AstAttrIndex: u8;
|
||
|
|
pub extern "c" const AstGenericTypeIndex: u8;
|
||
|
|
pub extern "c" const AstGenericTypePackIndex: u8;
|
||
|
|
pub extern "c" const AstExprGroupIndex: u8;
|
||
|
|
pub extern "c" const AstExprConstantNilIndex: u8;
|
||
|
|
pub extern "c" const AstExprConstantBoolIndex: u8;
|
||
|
|
pub extern "c" const AstExprConstantNumberIndex: u8;
|
||
|
|
pub extern "c" const AstExprConstantIntegerIndex: u8;
|
||
|
|
pub extern "c" const AstExprConstantStringIndex: u8;
|
||
|
|
pub extern "c" const AstExprLocalIndex: u8;
|
||
|
|
pub extern "c" const AstExprGlobalIndex: u8;
|
||
|
|
pub extern "c" const AstExprVarargsIndex: u8;
|
||
|
|
pub extern "c" const AstExprCallIndex: u8;
|
||
|
|
pub extern "c" const AstExprIndexNameIndex: u8;
|
||
|
|
pub extern "c" const AstExprIndexExprIndex: u8;
|
||
|
|
pub extern "c" const AstExprFunctionIndex: u8;
|
||
|
|
pub extern "c" const AstExprTableIndex: u8;
|
||
|
|
pub extern "c" const AstExprUnaryIndex: u8;
|
||
|
|
pub extern "c" const AstExprBinaryIndex: u8;
|
||
|
|
pub extern "c" const AstExprTypeAssertionIndex: u8;
|
||
|
|
pub extern "c" const AstExprIfElseIndex: u8;
|
||
|
|
pub extern "c" const AstExprInterpStringIndex: u8;
|
||
|
|
pub extern "c" const AstExprInstantiateIndex: u8;
|
||
|
|
pub extern "c" const AstStatBlockIndex: u8;
|
||
|
|
pub extern "c" const AstStatIfIndex: u8;
|
||
|
|
pub extern "c" const AstStatWhileIndex: u8;
|
||
|
|
pub extern "c" const AstStatRepeatIndex: u8;
|
||
|
|
pub extern "c" const AstStatBreakIndex: u8;
|
||
|
|
pub extern "c" const AstStatContinueIndex: u8;
|
||
|
|
pub extern "c" const AstStatReturnIndex: u8;
|
||
|
|
pub extern "c" const AstStatExprIndex: u8;
|
||
|
|
pub extern "c" const AstStatLocalIndex: u8;
|
||
|
|
pub extern "c" const AstStatForIndex: u8;
|
||
|
|
pub extern "c" const AstStatForInIndex: u8;
|
||
|
|
pub extern "c" const AstStatAssignIndex: u8;
|
||
|
|
pub extern "c" const AstStatCompoundAssignIndex: u8;
|
||
|
|
pub extern "c" const AstStatFunctionIndex: u8;
|
||
|
|
pub extern "c" const AstStatLocalFunctionIndex: u8;
|
||
|
|
pub extern "c" const AstStatTypeAliasIndex: u8;
|
||
|
|
pub extern "c" const AstStatTypeFunctionIndex: u8;
|
||
|
|
pub extern "c" const AstStatDeclareFunctionIndex: u8;
|
||
|
|
pub extern "c" const AstStatDeclareGlobalIndex: u8;
|
||
|
|
pub extern "c" const AstStatClassIndex: u8;
|
||
|
|
pub extern "c" const AstStatDeclareExternTypeIndex: u8;
|
||
|
|
pub extern "c" const AstTypeReferenceIndex: u8;
|
||
|
|
pub extern "c" const AstTypeTableIndex: u8;
|
||
|
|
pub extern "c" const AstTypeFunctionIndex: u8;
|
||
|
|
pub extern "c" const AstTypeTypeofIndex: u8;
|
||
|
|
pub extern "c" const AstTypeOptionalIndex: u8;
|
||
|
|
pub extern "c" const AstTypeUnionIndex: u8;
|
||
|
|
pub extern "c" const AstTypeIntersectionIndex: u8;
|
||
|
|
pub extern "c" const AstExprErrorIndex: u8;
|
||
|
|
pub extern "c" const AstStatErrorIndex: u8;
|
||
|
|
pub extern "c" const AstTypeErrorIndex: u8;
|
||
|
|
pub extern "c" const AstTypeSingletonBoolIndex: u8;
|
||
|
|
pub extern "c" const AstTypeSingletonStringIndex: u8;
|
||
|
|
pub extern "c" const AstTypeGroupIndex: u8;
|
||
|
|
pub extern "c" const AstTypePackExplicitIndex: u8;
|
||
|
|
pub extern "c" const AstTypePackVariadicIndex: u8;
|
||
|
|
pub extern "c" const AstTypePackGenericIndex: u8;
|
||
|
|
|
||
|
|
pub extern "c" const AstAttrSize: usize;
|
||
|
|
pub extern "c" const AstGenericTypeSize: usize;
|
||
|
|
pub extern "c" const AstGenericTypePackSize: usize;
|
||
|
|
pub extern "c" const AstExprGroupSize: usize;
|
||
|
|
pub extern "c" const AstExprConstantNilSize: usize;
|
||
|
|
pub extern "c" const AstExprConstantBoolSize: usize;
|
||
|
|
pub extern "c" const AstExprConstantNumberSize: usize;
|
||
|
|
pub extern "c" const AstExprConstantIntegerSize: usize;
|
||
|
|
pub extern "c" const AstExprConstantStringSize: usize;
|
||
|
|
pub extern "c" const AstExprLocalSize: usize;
|
||
|
|
pub extern "c" const AstExprGlobalSize: usize;
|
||
|
|
pub extern "c" const AstExprVarargsSize: usize;
|
||
|
|
pub extern "c" const AstExprCallSize: usize;
|
||
|
|
pub extern "c" const AstExprIndexNameSize: usize;
|
||
|
|
pub extern "c" const AstExprIndexExprSize: usize;
|
||
|
|
pub extern "c" const AstExprFunctionSize: usize;
|
||
|
|
pub extern "c" const AstExprTableSize: usize;
|
||
|
|
pub extern "c" const AstExprUnarySize: usize;
|
||
|
|
pub extern "c" const AstExprBinarySize: usize;
|
||
|
|
pub extern "c" const AstExprTypeAssertionSize: usize;
|
||
|
|
pub extern "c" const AstExprIfElseSize: usize;
|
||
|
|
pub extern "c" const AstExprInterpStringSize: usize;
|
||
|
|
pub extern "c" const AstExprInstantiateSize: usize;
|
||
|
|
pub extern "c" const AstStatBlockSize: usize;
|
||
|
|
pub extern "c" const AstStatIfSize: usize;
|
||
|
|
pub extern "c" const AstStatWhileSize: usize;
|
||
|
|
pub extern "c" const AstStatRepeatSize: usize;
|
||
|
|
pub extern "c" const AstStatBreakSize: usize;
|
||
|
|
pub extern "c" const AstStatContinueSize: usize;
|
||
|
|
pub extern "c" const AstStatReturnSize: usize;
|
||
|
|
pub extern "c" const AstStatExprSize: usize;
|
||
|
|
pub extern "c" const AstStatLocalSize: usize;
|
||
|
|
pub extern "c" const AstStatForSize: usize;
|
||
|
|
pub extern "c" const AstStatForInSize: usize;
|
||
|
|
pub extern "c" const AstStatAssignSize: usize;
|
||
|
|
pub extern "c" const AstStatCompoundAssignSize: usize;
|
||
|
|
pub extern "c" const AstStatFunctionSize: usize;
|
||
|
|
pub extern "c" const AstStatLocalFunctionSize: usize;
|
||
|
|
pub extern "c" const AstStatTypeAliasSize: usize;
|
||
|
|
pub extern "c" const AstStatTypeFunctionSize: usize;
|
||
|
|
pub extern "c" const AstStatDeclareFunctionSize: usize;
|
||
|
|
pub extern "c" const AstStatDeclareGlobalSize: usize;
|
||
|
|
pub extern "c" const AstStatClassSize: usize;
|
||
|
|
pub extern "c" const AstStatDeclareExternTypeSize: usize;
|
||
|
|
pub extern "c" const AstTypeReferenceSize: usize;
|
||
|
|
pub extern "c" const AstTypeTableSize: usize;
|
||
|
|
pub extern "c" const AstTypeFunctionSize: usize;
|
||
|
|
pub extern "c" const AstTypeTypeofSize: usize;
|
||
|
|
pub extern "c" const AstTypeOptionalSize: usize;
|
||
|
|
pub extern "c" const AstTypeUnionSize: usize;
|
||
|
|
pub extern "c" const AstTypeIntersectionSize: usize;
|
||
|
|
pub extern "c" const AstExprErrorSize: usize;
|
||
|
|
pub extern "c" const AstStatErrorSize: usize;
|
||
|
|
pub extern "c" const AstTypeErrorSize: usize;
|
||
|
|
pub extern "c" const AstTypeSingletonBoolSize: usize;
|
||
|
|
pub extern "c" const AstTypeSingletonStringSize: usize;
|
||
|
|
pub extern "c" const AstTypeGroupSize: usize;
|
||
|
|
pub extern "c" const AstTypePackExplicitSize: usize;
|
||
|
|
pub extern "c" const AstTypePackVariadicSize: usize;
|
||
|
|
pub extern "c" const AstTypePackGenericSize: usize;
|
||
|
|
};
|
||
|
|
|
||
|
|
@setEvalBranchQuota(2000);
|
||
|
|
inline for (@typeInfo(AstValues).@"struct".decls) |decl| {
|
||
|
|
if (comptime std.mem.endsWith(u8, decl.name, "Index")) {
|
||
|
|
const name = decl.name[3 .. decl.name.len - 5];
|
||
|
|
|
||
|
|
const ast_node_type = @field(Ast, name);
|
||
|
|
const info = @typeInfo(ast_node_type).@"struct";
|
||
|
|
|
||
|
|
comptime var field: ?std.builtin.Type.StructField = null;
|
||
|
|
inline for (info.fields) |f| {
|
||
|
|
if (comptime std.mem.eql(u8, f.name, "classIndex")) {
|
||
|
|
field = f;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (field == null)
|
||
|
|
@compileError("classIndex field not found");
|
||
|
|
const default_value_ptr = field.?.default_value_ptr orelse @compileError("classIndex field does not have a default value");
|
||
|
|
const enum_value = @as(*const Ast.Node.Kind, @ptrCast(@alignCast(default_value_ptr))).*;
|
||
|
|
|
||
|
|
std.testing.expectEqual(@field(AstValues, decl.name), @intFromEnum(enum_value)) catch |err| {
|
||
|
|
std.debug.print("index error for {s}\n", .{name});
|
||
|
|
return err;
|
||
|
|
};
|
||
|
|
} else if (comptime std.mem.endsWith(u8, decl.name, "Size")) {
|
||
|
|
const name = decl.name[3 .. decl.name.len - 4];
|
||
|
|
|
||
|
|
const ast_node_type = @field(Ast, name);
|
||
|
|
|
||
|
|
std.testing.expectEqual(@field(AstValues, decl.name), @sizeOf(ast_node_type)) catch |err| {
|
||
|
|
std.debug.print("size error for {s}\n", .{name});
|
||
|
|
return err;
|
||
|
|
};
|
||
|
|
} else @compileError("unknown exported constant");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// sources:
|
||
|
|
// https://github.com/luau-lang/luau/blob/40d4815888f63362a6cb79b3e74c4aafa0b2cbf4/Ast/include/Luau/Ast.h
|
||
|
|
// https://github.com/luau-lang/luau/blob/40d4815888f63362a6cb79b3e74c4aafa0b2cbf4/Ast/src/Ast.cpp
|