511 lines
12 KiB
Zig
511 lines
12 KiB
Zig
const std = @import("std");
|
|
|
|
pub const Span = struct {
|
|
start: u32,
|
|
end: u32,
|
|
};
|
|
|
|
pub const Node = struct {
|
|
span: Span,
|
|
data: Data,
|
|
source_file: ?[]const u8 = null,
|
|
|
|
pub const Data = union(enum) {
|
|
root: Root,
|
|
fn_decl: FnDecl,
|
|
block: Block,
|
|
int_literal: IntLiteral,
|
|
float_literal: FloatLiteral,
|
|
bool_literal: BoolLiteral,
|
|
string_literal: StringLiteral,
|
|
identifier: Identifier,
|
|
enum_literal: EnumLiteral,
|
|
binary_op: BinaryOp,
|
|
chained_comparison: ChainedComparison,
|
|
unary_op: UnaryOp,
|
|
call: Call,
|
|
field_access: FieldAccess,
|
|
if_expr: IfExpr,
|
|
match_expr: MatchExpr,
|
|
match_arm: MatchArm,
|
|
const_decl: ConstDecl,
|
|
var_decl: VarDecl,
|
|
assignment: Assignment,
|
|
multi_assign: MultiAssign,
|
|
destructure_decl: DestructureDecl,
|
|
enum_decl: EnumDecl,
|
|
struct_decl: StructDecl,
|
|
struct_literal: StructLiteral,
|
|
union_decl: UnionDecl,
|
|
lambda: Lambda,
|
|
type_expr: TypeExpr,
|
|
param: Param,
|
|
defer_stmt: DeferStmt,
|
|
push_stmt: PushStmt,
|
|
comptime_expr: ComptimeExpr,
|
|
insert_expr: InsertExpr,
|
|
return_stmt: ReturnStmt,
|
|
import_decl: ImportDecl,
|
|
namespace_decl: NamespaceDecl,
|
|
array_type_expr: ArrayTypeExpr,
|
|
slice_type_expr: SliceTypeExpr,
|
|
array_literal: ArrayLiteral,
|
|
parameterized_type_expr: ParameterizedTypeExpr,
|
|
index_expr: IndexExpr,
|
|
slice_expr: SliceExpr,
|
|
pointer_type_expr: PointerTypeExpr,
|
|
many_pointer_type_expr: ManyPointerTypeExpr,
|
|
optional_type_expr: OptionalTypeExpr,
|
|
force_unwrap: ForceUnwrap,
|
|
null_coalesce: NullCoalesce,
|
|
deref_expr: DerefExpr,
|
|
null_literal: void,
|
|
while_expr: WhileExpr,
|
|
for_expr: ForExpr,
|
|
spread_expr: SpreadExpr,
|
|
break_expr: void,
|
|
continue_expr: void,
|
|
undef_literal: void,
|
|
inferred_type: void,
|
|
builtin_expr: void,
|
|
compiler_expr: void,
|
|
foreign_expr: ForeignExpr,
|
|
library_decl: LibraryDecl,
|
|
function_type_expr: FunctionTypeExpr,
|
|
closure_type_expr: ClosureTypeExpr,
|
|
tuple_type_expr: TupleTypeExpr,
|
|
tuple_literal: TupleLiteral,
|
|
ufcs_alias: UfcsAlias,
|
|
c_import_decl: CImportDecl,
|
|
protocol_decl: ProtocolDecl,
|
|
impl_block: ImplBlock,
|
|
|
|
pub fn declName(self: Data) ?[]const u8 {
|
|
return switch (self) {
|
|
.fn_decl => |d| d.name,
|
|
.const_decl => |d| d.name,
|
|
.var_decl => |d| d.name,
|
|
.enum_decl => |d| d.name,
|
|
.struct_decl => |d| d.name,
|
|
.union_decl => |d| d.name,
|
|
.namespace_decl => |d| d.name,
|
|
.ufcs_alias => |d| d.name,
|
|
.c_import_decl => |d| d.name,
|
|
.protocol_decl => |d| d.name,
|
|
else => null,
|
|
};
|
|
}
|
|
};
|
|
};
|
|
|
|
pub const Root = struct {
|
|
decls: []const *Node,
|
|
};
|
|
|
|
pub const CallingConvention = enum { default, c };
|
|
|
|
pub const FnDecl = struct {
|
|
name: []const u8,
|
|
params: []const Param,
|
|
return_type: ?*Node,
|
|
body: *Node,
|
|
type_params: []const StructTypeParam = &.{},
|
|
is_arrow: bool = false,
|
|
call_conv: CallingConvention = .default,
|
|
};
|
|
|
|
pub const Param = struct {
|
|
name: []const u8,
|
|
name_span: Span,
|
|
type_expr: *Node,
|
|
is_variadic: bool = false,
|
|
is_comptime: bool = false,
|
|
};
|
|
|
|
pub const Block = struct {
|
|
stmts: []const *Node,
|
|
};
|
|
|
|
pub const IntLiteral = struct {
|
|
value: i64,
|
|
};
|
|
|
|
pub const FloatLiteral = struct {
|
|
value: f64,
|
|
};
|
|
|
|
pub const BoolLiteral = struct {
|
|
value: bool,
|
|
};
|
|
|
|
pub const StringLiteral = struct {
|
|
raw: []const u8,
|
|
is_raw: bool = false,
|
|
};
|
|
|
|
pub const Identifier = struct {
|
|
name: []const u8,
|
|
};
|
|
|
|
pub const EnumLiteral = struct {
|
|
name: []const u8, // without the leading dot
|
|
};
|
|
|
|
pub const BinaryOp = struct {
|
|
op: Op,
|
|
lhs: *Node,
|
|
rhs: *Node,
|
|
|
|
pub const Op = enum {
|
|
add,
|
|
sub,
|
|
mul,
|
|
div,
|
|
mod,
|
|
eq,
|
|
neq,
|
|
lt,
|
|
lte,
|
|
gt,
|
|
gte,
|
|
and_op,
|
|
or_op,
|
|
bit_and,
|
|
bit_or,
|
|
bit_xor,
|
|
shl,
|
|
shr,
|
|
in_op,
|
|
};
|
|
};
|
|
|
|
pub const ChainedComparison = struct {
|
|
operands: []const *Node,
|
|
ops: []const BinaryOp.Op,
|
|
};
|
|
|
|
pub const UnaryOp = struct {
|
|
op: Op,
|
|
operand: *Node,
|
|
|
|
pub const Op = enum {
|
|
negate,
|
|
not,
|
|
bit_not,
|
|
xx,
|
|
address_of,
|
|
};
|
|
};
|
|
|
|
pub const Call = struct {
|
|
callee: *Node,
|
|
args: []const *Node,
|
|
};
|
|
|
|
pub const FieldAccess = struct {
|
|
object: *Node,
|
|
field: []const u8,
|
|
is_optional: bool = false,
|
|
};
|
|
|
|
pub const IfExpr = struct {
|
|
condition: *Node,
|
|
then_branch: *Node,
|
|
else_branch: ?*Node,
|
|
is_inline: bool, // true for `if cond then a else b`
|
|
is_comptime: bool = false, // true for `inline if` — compile-time branch elimination
|
|
binding_name: ?[]const u8 = null, // for `if val := expr { ... }` optional binding
|
|
};
|
|
|
|
pub const MatchExpr = struct {
|
|
subject: *Node,
|
|
arms: []const MatchArm,
|
|
is_comptime: bool = false,
|
|
};
|
|
|
|
pub const MatchArm = struct {
|
|
pattern: ?*Node, // null = else (default) arm
|
|
body: *Node,
|
|
is_break: bool,
|
|
capture: ?[]const u8 = null, // payload binding name: case .variant: (name) { ... }
|
|
};
|
|
|
|
pub const ConstDecl = struct {
|
|
name: []const u8,
|
|
type_annotation: ?*Node,
|
|
value: *Node,
|
|
};
|
|
|
|
pub const VarDecl = struct {
|
|
name: []const u8,
|
|
type_annotation: ?*Node,
|
|
value: ?*Node,
|
|
};
|
|
|
|
pub const Assignment = struct {
|
|
target: *Node,
|
|
op: Op,
|
|
value: *Node,
|
|
|
|
pub const Op = enum {
|
|
assign,
|
|
add_assign,
|
|
sub_assign,
|
|
mul_assign,
|
|
div_assign,
|
|
mod_assign,
|
|
and_assign,
|
|
or_assign,
|
|
xor_assign,
|
|
shl_assign,
|
|
shr_assign,
|
|
};
|
|
};
|
|
|
|
pub const MultiAssign = struct {
|
|
targets: []const *Node,
|
|
values: []const *Node,
|
|
};
|
|
|
|
pub const DestructureDecl = struct {
|
|
names: []const []const u8,
|
|
value: *Node,
|
|
};
|
|
|
|
pub const EnumDecl = struct {
|
|
name: []const u8,
|
|
variant_names: []const []const u8,
|
|
variant_types: []const ?*Node = &.{}, // null entries = no payload; empty = payload-less enum
|
|
is_flags: bool = false,
|
|
variant_values: []const ?*Node = &.{}, // explicit value per variant (null = auto), empty = all auto
|
|
backing_type: ?*Node = null, // optional backing type: enum u8 { ... }
|
|
};
|
|
|
|
pub const UnionDecl = struct {
|
|
name: []const u8,
|
|
field_names: []const []const u8,
|
|
field_types: []const *Node,
|
|
};
|
|
|
|
pub const StructTypeParam = struct {
|
|
name: []const u8, // e.g. "N" or "T" (without $)
|
|
constraint: *Node, // type_expr: "u32" for value param, "Type" for type param
|
|
protocol_constraints: []const []const u8 = &.{}, // e.g. ["Eq", "Hashable"] for $T/Eq/Hashable
|
|
};
|
|
|
|
pub const UsingEntry = struct {
|
|
insert_index: u32, // position in field_names where used fields are spliced
|
|
type_name: []const u8, // struct type to inline
|
|
};
|
|
|
|
pub const StructDecl = struct {
|
|
name: []const u8,
|
|
field_names: []const []const u8,
|
|
field_types: []const *Node, // type_expr nodes
|
|
field_defaults: []const ?*Node, // default value per field, null if none
|
|
type_params: []const StructTypeParam = &.{},
|
|
using_entries: []const UsingEntry = &.{},
|
|
methods: []const *Node = &.{}, // fn_decl nodes for struct methods
|
|
constants: []const *Node = &.{}, // const_decl nodes for struct-level constants
|
|
};
|
|
|
|
pub const StructFieldInit = struct {
|
|
name: ?[]const u8, // null for positional, non-null for named/shorthand
|
|
value: *Node,
|
|
};
|
|
|
|
pub const StructLiteral = struct {
|
|
struct_name: ?[]const u8, // null for anonymous `.{ ... }`
|
|
type_expr: ?*Node = null, // for GenericType(args).{ ... }
|
|
field_inits: []const StructFieldInit,
|
|
init_block: ?*Node = null, // optional `{ stmts }` block after struct literal
|
|
};
|
|
|
|
pub const Lambda = struct {
|
|
params: []const Param,
|
|
return_type: ?*Node,
|
|
body: *Node,
|
|
type_params: []const StructTypeParam = &.{},
|
|
call_conv: CallingConvention = .default,
|
|
};
|
|
|
|
pub const TypeExpr = struct {
|
|
name: []const u8,
|
|
is_generic: bool = false,
|
|
protocol_constraints: []const []const u8 = &.{}, // e.g. ["Eq", "Hashable"] for $T/Eq/Hashable
|
|
};
|
|
|
|
pub const DeferStmt = struct {
|
|
expr: *Node,
|
|
};
|
|
|
|
pub const PushStmt = struct {
|
|
context_expr: *Node,
|
|
body: *Node,
|
|
};
|
|
|
|
pub const ComptimeExpr = struct {
|
|
expr: *Node,
|
|
};
|
|
|
|
pub const InsertExpr = struct {
|
|
expr: *Node,
|
|
};
|
|
|
|
pub const ReturnStmt = struct {
|
|
value: ?*Node,
|
|
};
|
|
|
|
pub const ImportDecl = struct {
|
|
path: []const u8,
|
|
name: ?[]const u8,
|
|
};
|
|
|
|
pub const ArrayTypeExpr = struct {
|
|
length: *Node, // int_literal for the size
|
|
element_type: *Node, // type_expr for the element type
|
|
};
|
|
|
|
pub const SliceTypeExpr = struct {
|
|
element_type: *Node, // type_expr for the element type
|
|
};
|
|
|
|
pub const ArrayLiteral = struct {
|
|
elements: []const *Node,
|
|
type_expr: ?*Node = null,
|
|
};
|
|
|
|
pub const ParameterizedTypeExpr = struct {
|
|
name: []const u8, // e.g. "Vector", or later generic struct names
|
|
args: []const *Node, // e.g. [int_literal(3), type_expr("f32")]
|
|
};
|
|
|
|
pub const IndexExpr = struct {
|
|
object: *Node,
|
|
index: *Node,
|
|
};
|
|
|
|
pub const SliceExpr = struct {
|
|
object: *Node,
|
|
start: ?*Node = null,
|
|
end: ?*Node = null,
|
|
};
|
|
|
|
pub const PointerTypeExpr = struct {
|
|
pointee_type: *Node,
|
|
};
|
|
|
|
pub const ManyPointerTypeExpr = struct {
|
|
element_type: *Node,
|
|
};
|
|
|
|
pub const OptionalTypeExpr = struct {
|
|
inner_type: *Node,
|
|
};
|
|
|
|
pub const ForceUnwrap = struct {
|
|
operand: *Node,
|
|
};
|
|
|
|
pub const NullCoalesce = struct {
|
|
lhs: *Node,
|
|
rhs: *Node,
|
|
};
|
|
|
|
pub const DerefExpr = struct {
|
|
operand: *Node,
|
|
};
|
|
|
|
pub const WhileExpr = struct {
|
|
condition: *Node,
|
|
body: *Node,
|
|
binding_name: ?[]const u8 = null, // for `while val := expr { ... }` optional binding
|
|
};
|
|
|
|
pub const ForExpr = struct {
|
|
iterable: *Node,
|
|
body: *Node,
|
|
capture_name: []const u8,
|
|
index_name: ?[]const u8 = null,
|
|
};
|
|
|
|
pub const SpreadExpr = struct {
|
|
operand: *Node,
|
|
};
|
|
|
|
pub const NamespaceDecl = struct {
|
|
name: []const u8,
|
|
decls: []const *Node,
|
|
};
|
|
|
|
pub const ForeignExpr = struct {
|
|
library_ref: ?[]const u8 = null, // identifier name of library constant
|
|
c_name: ?[]const u8 = null, // C symbol name override
|
|
};
|
|
|
|
pub const LibraryDecl = struct {
|
|
lib_name: []const u8,
|
|
name: []const u8, // sx-side constant name
|
|
};
|
|
|
|
pub const FunctionTypeExpr = struct {
|
|
param_types: []const *Node,
|
|
param_names: ?[]const ?[]const u8 = null, // optional documentation names
|
|
return_type: ?*Node, // null = void return
|
|
};
|
|
|
|
pub const ClosureTypeExpr = struct {
|
|
param_types: []const *Node,
|
|
param_names: ?[]const ?[]const u8 = null, // optional documentation names
|
|
return_type: ?*Node, // null = void return
|
|
};
|
|
|
|
pub const TupleTypeExpr = struct {
|
|
field_types: []const *Node,
|
|
field_names: ?[]const []const u8, // null for positional
|
|
};
|
|
|
|
pub const TupleLiteral = struct {
|
|
elements: []const TupleElement,
|
|
};
|
|
|
|
pub const TupleElement = struct {
|
|
name: ?[]const u8, // null for positional
|
|
value: *Node,
|
|
};
|
|
|
|
pub const UfcsAlias = struct {
|
|
name: []const u8,
|
|
target: []const u8,
|
|
};
|
|
|
|
pub const CImportDecl = struct {
|
|
includes: []const []const u8,
|
|
sources: []const []const u8,
|
|
defines: []const []const u8,
|
|
flags: []const []const u8,
|
|
name: ?[]const u8 = null,
|
|
bitcode_paths: []const []const u8 = &.{}, // populated during import resolution
|
|
};
|
|
|
|
pub const ProtocolMethodDecl = struct {
|
|
name: []const u8,
|
|
params: []const *Node, // type_expr nodes for parameter types (excluding implicit self)
|
|
param_names: []const []const u8, // parameter names (excluding implicit self)
|
|
return_type: ?*Node, // null = void return
|
|
default_body: ?*Node, // null = required method, non-null = default implementation
|
|
};
|
|
|
|
pub const ProtocolDecl = struct {
|
|
name: []const u8,
|
|
methods: []const ProtocolMethodDecl,
|
|
is_inline: bool = false, // #inline — embedded fn ptrs instead of vtable pointer
|
|
};
|
|
|
|
pub const ImplBlock = struct {
|
|
protocol_name: []const u8,
|
|
target_type: []const u8,
|
|
target_type_params: []const StructTypeParam = &.{}, // for `impl P for List($T)`
|
|
methods: []const *Node, // fn_decl nodes
|
|
};
|