Files
Odin/core/odin/ast/ast.odin

1070 lines
18 KiB
Odin

// Abstract Syntax Tree for the `Odin` parser packages.
package odin_ast
import "core:odin/tokenizer"
Proc_Tag :: enum {
Bounds_Check,
No_Bounds_Check,
Optional_Ok,
Optional_Allocator_Error,
}
Proc_Tags :: distinct bit_set[Proc_Tag; u32]
Proc_Inlining :: enum u32 {
None = 0,
Inline = 1,
No_Inline = 2,
}
Proc_Tailing :: enum u32 {
None = 0,
Must_Tail = 1,
}
Proc_Calling_Convention_Extra :: enum i32 {
Foreign_Block_Default,
}
Proc_Calling_Convention :: union {
string,
Proc_Calling_Convention_Extra,
}
Node_State_Flag :: enum {
Bounds_Check,
No_Bounds_Check,
Type_Assert,
No_Type_Assert,
}
Node_State_Flags :: distinct bit_set[Node_State_Flag]
Node :: struct {
pos: tokenizer.Pos,
end: tokenizer.Pos,
state_flags: Node_State_Flags,
derived: Any_Node,
}
Comment_Group :: struct {
using node: Node,
list: []tokenizer.Token,
}
Package_Kind :: enum {
Normal,
Runtime,
Init,
}
Package :: struct {
using node: Node,
kind: Package_Kind,
id: int,
name: string,
fullpath: string,
files: map[string]^File,
user_data: rawptr,
}
File :: struct {
using node: Node,
id: int,
pkg: ^Package,
fullpath: string,
src: string,
tags: [dynamic]tokenizer.Token,
docs: ^Comment_Group, // possibly nil
pkg_decl: ^Package_Decl,
pkg_token: tokenizer.Token,
pkg_name: string,
decls: [dynamic]^Stmt,
imports: [dynamic]^Import_Decl,
directive_count: int,
comments: [dynamic]^Comment_Group,
syntax_warning_count: int,
syntax_error_count: int,
}
// Base Types
Expr :: struct {
using expr_base: Node,
derived_expr: Any_Expr,
}
Stmt :: struct {
using stmt_base: Node,
derived_stmt: Any_Stmt,
}
Decl :: struct {
using decl_base: Stmt,
}
// Expressions
Bad_Expr :: struct {
using node: Expr,
}
Ident :: struct {
using node: Expr,
name: string,
}
Implicit :: struct {
using node: Expr,
tok: tokenizer.Token,
}
Undef :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
}
Basic_Lit :: struct {
using node: Expr,
tok: tokenizer.Token,
}
Basic_Directive :: struct {
using node: Expr,
tok: tokenizer.Token,
name: string,
}
Ellipsis :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
expr: ^Expr, // possibly nil
}
Proc_Lit :: struct {
using node: Expr,
type: ^Proc_Type,
body: ^Stmt, // nil when it represents a foreign procedure
tags: Proc_Tags,
inlining: Proc_Inlining,
tailing: Proc_Tailing,
where_token: tokenizer.Token,
where_clauses: []^Expr,
}
Comp_Lit :: struct {
using node: Expr,
type: ^Expr, // nil when type is inferred
open: tokenizer.Pos,
elems: []^Expr,
close: tokenizer.Pos,
tag: ^Expr, // possibly nil
}
Tag_Expr :: struct {
using node: Expr,
op: tokenizer.Token,
name: string,
expr: ^Expr,
}
Unary_Expr :: struct {
using node: Expr,
op: tokenizer.Token,
expr: ^Expr, // nil in the case of `[?]T` or `x.?`
}
Binary_Expr :: struct {
using node: Expr,
left: ^Expr,
op: tokenizer.Token,
right: ^Expr,
}
Paren_Expr :: struct {
using node: Expr,
open: tokenizer.Pos,
expr: ^Expr,
close: tokenizer.Pos,
}
Selector_Expr :: struct {
using node: Expr,
expr: ^Expr,
op: tokenizer.Token,
field: ^Ident,
}
Implicit_Selector_Expr :: struct {
using node: Expr,
field: ^Ident,
}
Selector_Call_Expr :: struct {
using node: Expr,
expr: ^Expr,
call: ^Call_Expr,
modified_call: bool,
}
Index_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: tokenizer.Pos,
index: ^Expr,
close: tokenizer.Pos,
}
Deref_Expr :: struct {
using node: Expr,
expr: ^Expr,
op: tokenizer.Token,
}
Slice_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: tokenizer.Pos,
low: ^Expr, // possibly nil
interval: tokenizer.Token,
high: ^Expr, // possibly nil
close: tokenizer.Pos,
}
Matrix_Index_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: tokenizer.Pos,
row_index: ^Expr,
column_index: ^Expr,
close: tokenizer.Pos,
}
Call_Expr :: struct {
using node: Expr,
inlining: Proc_Inlining,
tailing: Proc_Tailing,
expr: ^Expr,
open: tokenizer.Pos,
args: []^Expr,
ellipsis: tokenizer.Token,
close: tokenizer.Pos,
}
Field_Value :: struct {
using node: Expr,
field: ^Expr,
sep: tokenizer.Pos,
value: ^Expr,
}
Ternary_If_Expr :: struct {
using node: Expr,
x: ^Expr,
op1: tokenizer.Token,
cond: ^Expr,
op2: tokenizer.Token,
y: ^Expr,
}
Ternary_When_Expr :: struct {
using node: Expr,
x: ^Expr,
op1: tokenizer.Token,
cond: ^Expr,
op2: tokenizer.Token,
y: ^Expr,
}
Or_Else_Expr :: struct {
using node: Expr,
x: ^Expr,
token: tokenizer.Token,
y: ^Expr,
}
Or_Return_Expr :: struct {
using node: Expr,
expr: ^Expr,
token: tokenizer.Token,
}
Or_Branch_Expr :: struct {
using node: Expr,
expr: ^Expr,
token: tokenizer.Token,
label: ^Expr, // possibly nil when not used
}
Type_Assertion :: struct {
using node: Expr,
expr: ^Expr,
dot: tokenizer.Pos,
open: tokenizer.Pos,
type: ^Expr,
close: tokenizer.Pos,
}
Type_Cast :: struct {
using node: Expr,
tok: tokenizer.Token,
open: tokenizer.Pos,
type: ^Expr,
close: tokenizer.Pos,
expr: ^Expr,
}
Auto_Cast :: struct {
using node: Expr,
op: tokenizer.Token,
expr: ^Expr,
}
Inline_Asm_Dialect :: enum u8 {
Default = 0,
ATT = 1,
Intel = 2,
}
Inline_Asm_Expr :: struct {
using node: Expr,
tok: tokenizer.Token,
param_types: []^Expr,
return_type: ^Expr,
has_side_effects: bool,
is_align_stack: bool,
dialect: Inline_Asm_Dialect,
open: tokenizer.Pos,
constraints_string: ^Expr,
asm_string: ^Expr,
close: tokenizer.Pos,
}
// Statements
Bad_Stmt :: struct {
using node: Stmt,
}
Empty_Stmt :: struct {
using node: Stmt,
semicolon: tokenizer.Pos, // Position of the following ';'
}
Expr_Stmt :: struct {
using node: Stmt,
expr: ^Expr,
}
Tag_Stmt :: struct {
using node: Stmt,
op: tokenizer.Token,
name: string,
stmt: ^Stmt,
}
Assign_Stmt :: struct {
using node: Stmt,
lhs: []^Expr,
op: tokenizer.Token,
rhs: []^Expr,
}
Block_Stmt :: struct {
using node: Stmt,
label: ^Expr,
open: tokenizer.Pos,
stmts: []^Stmt,
close: tokenizer.Pos,
uses_do: bool,
}
If_Stmt :: struct {
using node: Stmt,
label: ^Expr, // possibly nil
if_pos: tokenizer.Pos,
init: ^Stmt, // possibly nil
cond: ^Expr,
body: ^Stmt,
else_pos: tokenizer.Pos,
else_stmt: ^Stmt, // possibly nil
}
When_Stmt :: struct {
using node: Stmt,
when_pos: tokenizer.Pos,
cond: ^Expr,
body: ^Stmt,
else_stmt: ^Stmt, // possibly nil
}
Return_Stmt :: struct {
using node: Stmt,
results: []^Expr,
}
Defer_Stmt :: struct {
using node: Stmt,
stmt: ^Stmt,
}
For_Stmt :: struct {
using node: Stmt,
label: ^Expr, // possibly nil
for_pos: tokenizer.Pos,
init: ^Stmt, // possibly nil
cond: ^Expr, // possibly nil
post: ^Stmt, // possibly nil
body: ^Stmt,
}
Range_Stmt :: struct {
using node: Stmt,
label: ^Expr, // possibly nil
init: ^Stmt,
for_pos: tokenizer.Pos,
vals: []^Expr,
in_pos: tokenizer.Pos,
expr: ^Expr,
body: ^Stmt,
reverse: bool,
}
Inline_Range_Stmt :: Unroll_Range_Stmt
Unroll_Range_Stmt :: struct {
using node: Stmt,
label: ^Expr, // possibly nil
unroll_pos: tokenizer.Pos,
args: []^Expr,
for_pos: tokenizer.Pos,
val0: ^Expr,
val1: ^Expr, // possibly nil
in_pos: tokenizer.Pos,
expr: ^Expr,
body: ^Stmt,
}
Case_Clause :: struct {
using node: Stmt,
case_pos: tokenizer.Pos,
list: []^Expr,
terminator: tokenizer.Token,
body: []^Stmt,
}
Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr, // possibly nil
switch_pos: tokenizer.Pos,
init: ^Stmt, // possibly nil
cond: ^Expr,
body: ^Stmt,
partial: bool,
}
Type_Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr, // possibly nil
switch_pos: tokenizer.Pos,
tag: ^Stmt,
expr: ^Expr,
body: ^Stmt,
partial: bool,
}
Branch_Stmt :: struct {
using node: Stmt,
tok: tokenizer.Token,
label: ^Ident, // possibly nil
}
Using_Stmt :: struct {
using node: Stmt,
list: []^Expr,
}
// Declarations
Bad_Decl :: struct {
using node: Decl,
}
Value_Decl :: struct {
using node: Decl,
docs: ^Comment_Group, // possibly nil
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
names: []^Expr,
type: ^Expr, // possibly nil
values: []^Expr,
comment: ^Comment_Group, // possibly nil
is_using: bool,
is_mutable: bool,
}
Package_Decl :: struct {
using node: Decl,
docs: ^Comment_Group, // possibly nil
token: tokenizer.Token,
name: string,
comment: ^Comment_Group, // possibly nil
}
Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group, // possibly nil
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
is_using: bool,
import_tok: tokenizer.Token,
name: tokenizer.Token,
relpath: tokenizer.Token,
fullpath: string,
comment: ^Comment_Group, // possibly nil
}
Foreign_Block_Decl :: struct {
using node: Decl,
docs: ^Comment_Group, // possibly nil
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
tok: tokenizer.Token,
foreign_library: ^Expr, // possibly nil
body: ^Stmt, // possibly nil
}
Foreign_Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group, // possibly nil
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
foreign_tok: tokenizer.Token,
import_tok: tokenizer.Token,
name: ^Ident, // possibly nil
collection_name: string,
fullpaths: []^Expr,
comment: ^Comment_Group, // possibly nil
}
// Other things
unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
val = expr
if expr == nil {
return
}
for {
e := val.derived.(^Paren_Expr) or_break
if e.expr == nil {
break
}
val = e.expr
}
return
}
strip_or_return_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
val = expr
if expr == nil {
return
}
for {
inner: ^Expr
#partial switch e in val.derived {
case ^Or_Return_Expr:
inner = e.expr
case ^Or_Branch_Expr:
inner = e.expr
case ^Paren_Expr:
inner = e.expr
}
if inner == nil {
break
}
val = inner
}
return
}
Field_Flags :: distinct bit_set[Field_Flag]
Field_Flag :: enum {
Invalid,
Unknown,
Ellipsis,
Using,
No_Alias,
C_Vararg,
Const,
Any_Int,
Subtype,
By_Ptr,
No_Broadcast,
No_Capture,
Results,
Tags,
Default_Parameters,
Typeid_Token,
}
field_flag_strings := [Field_Flag]string{
.Invalid = "",
.Unknown = "",
.Ellipsis = "..",
.Using = "using",
.No_Alias = "#no_alias",
.C_Vararg = "#c_vararg",
.Const = "#const",
.Any_Int = "#any_int",
.Subtype = "#subtype",
.By_Ptr = "#by_ptr",
.No_Broadcast = "#no_broadcast",
.No_Capture = "#no_capture",
.Results = "results",
.Tags = "field tag",
.Default_Parameters = "default parameters",
.Typeid_Token = "typeid",
}
field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{
{"no_alias", .No_Alias},
{"c_vararg", .C_Vararg},
{"const", .Const},
{"any_int", .Any_Int},
{"subtype", .Subtype},
{"by_ptr", .By_Ptr},
{"no_broadcast", .No_Broadcast},
{"no_capture", .No_Capture},
}
Field_Flags_Struct :: Field_Flags{
.Using,
.Tags,
.Subtype,
}
Field_Flags_Record_Poly_Params :: Field_Flags{
.Typeid_Token,
.Default_Parameters,
}
Field_Flags_Signature :: Field_Flags{
.Ellipsis,
.Using,
.No_Alias,
.C_Vararg,
.Const,
.Any_Int,
.By_Ptr,
.No_Broadcast,
.Default_Parameters,
}
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token}
Field_Flags_Signature_Results :: Field_Flags_Signature
Proc_Group :: struct {
using node: Expr,
tok: tokenizer.Token,
open: tokenizer.Pos,
args: []^Expr,
close: tokenizer.Pos,
}
Attribute :: struct {
using node: Node,
tok: tokenizer.Token_Kind,
open: tokenizer.Pos,
elems: []^Expr,
close: tokenizer.Pos,
}
Field :: struct {
using node: Node,
docs: ^Comment_Group, // possibly nil
names: []^Expr, // Could be polymorphic
type: ^Expr,
default_value: ^Expr, // possibly nil
tag: tokenizer.Token,
flags: Field_Flags,
comment: ^Comment_Group, // possibly nil
}
Field_List :: struct {
using node: Node,
open: tokenizer.Pos,
list: []^Field,
close: tokenizer.Pos,
}
// Types
Typeid_Type :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
specialization: ^Expr, // possibly nil
}
Helper_Type :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Distinct_Type :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Poly_Type :: struct {
using node: Expr,
dollar: tokenizer.Pos,
type: ^Ident,
specialization: ^Expr, // possibly nil
}
Proc_Type :: struct {
using node: Expr,
tok: tokenizer.Token,
calling_convention: Proc_Calling_Convention,
params: ^Field_List,
arrow: tokenizer.Pos,
results: ^Field_List,
tags: Proc_Tags,
generic: bool,
diverging: bool,
}
Pointer_Type :: struct {
using node: Expr,
tag: ^Expr, // possibly nil
pointer: tokenizer.Pos,
elem: ^Expr,
}
Multi_Pointer_Type :: struct {
using node: Expr,
open: tokenizer.Pos,
pointer: tokenizer.Pos,
close: tokenizer.Pos,
elem: ^Expr,
}
Array_Type :: struct {
using node: Expr,
open: tokenizer.Pos,
tag: ^Expr, // possibly nil
len: ^Expr, // Unary_Expr node for [?]T array types, nil for slice types
close: tokenizer.Pos,
elem: ^Expr,
}
Dynamic_Array_Type :: struct {
using node: Expr,
tag: ^Expr, // possibly nil
open: tokenizer.Pos,
dynamic_pos: tokenizer.Pos,
close: tokenizer.Pos,
elem: ^Expr,
}
Fixed_Capacity_Dynamic_Array_Type :: struct {
using node: Expr,
tag: ^Expr, // possibly nil
open: tokenizer.Pos,
dynamic_pos: tokenizer.Pos,
capacity: ^Expr,
close: tokenizer.Pos,
elem: ^Expr,
}
Struct_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
poly_params: ^Field_List, // possibly nil
align: ^Expr, // possibly nil
min_field_align: ^Expr, // possibly nil
max_field_align: ^Expr, // possibly nil
where_token: tokenizer.Token,
where_clauses: []^Expr,
is_packed: bool,
is_raw_union: bool,
is_no_copy: bool,
is_all_or_none: bool,
is_simple: bool,
fields: ^Field_List,
name_count: int,
}
Union_Type_Kind :: enum u8 {
Normal,
maybe,
no_nil,
shared_nil,
}
Union_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
poly_params: ^Field_List, // possibly nil
align: ^Expr, // possibly nil
kind: Union_Type_Kind,
where_token: tokenizer.Token,
where_clauses: []^Expr,
variants: []^Expr,
}
Enum_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
base_type: ^Expr, // possibly nil
open: tokenizer.Pos,
fields: []^Expr,
close: tokenizer.Pos,
is_using: bool,
}
Bit_Set_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
open: tokenizer.Pos,
elem: ^Expr,
underlying: ^Expr, // possibly nil
close: tokenizer.Pos,
}
Map_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
key: ^Expr,
value: ^Expr,
}
Relative_Type :: struct {
using node: Expr,
tag: ^Expr,
type: ^Expr,
}
Matrix_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
row_count: ^Expr,
column_count: ^Expr,
elem: ^Expr,
}
Bit_Field_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
backing_type: ^Expr,
open: tokenizer.Pos,
fields: []^Bit_Field_Field,
close: tokenizer.Pos,
}
Bit_Field_Field :: struct {
using node: Node,
docs: ^Comment_Group, // possibly nil
name: ^Expr,
type: ^Expr,
bit_size: ^Expr,
tag: tokenizer.Token,
comments: ^Comment_Group, // possibly nil
}
Any_Node :: union {
^Package,
^File,
^Comment_Group,
^Bad_Expr,
^Ident,
^Implicit,
^Undef,
^Basic_Lit,
^Basic_Directive,
^Ellipsis,
^Proc_Lit,
^Comp_Lit,
^Tag_Expr,
^Unary_Expr,
^Binary_Expr,
^Paren_Expr,
^Selector_Expr,
^Implicit_Selector_Expr,
^Selector_Call_Expr,
^Index_Expr,
^Deref_Expr,
^Slice_Expr,
^Matrix_Index_Expr,
^Call_Expr,
^Field_Value,
^Ternary_If_Expr,
^Ternary_When_Expr,
^Or_Else_Expr,
^Or_Return_Expr,
^Or_Branch_Expr,
^Type_Assertion,
^Type_Cast,
^Auto_Cast,
^Inline_Asm_Expr,
^Proc_Group,
^Typeid_Type,
^Helper_Type,
^Distinct_Type,
^Poly_Type,
^Proc_Type,
^Pointer_Type,
^Multi_Pointer_Type,
^Array_Type,
^Dynamic_Array_Type,
^Fixed_Capacity_Dynamic_Array_Type,
^Struct_Type,
^Union_Type,
^Enum_Type,
^Bit_Set_Type,
^Map_Type,
^Relative_Type,
^Matrix_Type,
^Bit_Field_Type,
^Bad_Stmt,
^Empty_Stmt,
^Expr_Stmt,
^Tag_Stmt,
^Assign_Stmt,
^Block_Stmt,
^If_Stmt,
^When_Stmt,
^Return_Stmt,
^Defer_Stmt,
^For_Stmt,
^Range_Stmt,
^Inline_Range_Stmt,
^Case_Clause,
^Switch_Stmt,
^Type_Switch_Stmt,
^Branch_Stmt,
^Using_Stmt,
^Bad_Decl,
^Value_Decl,
^Package_Decl,
^Import_Decl,
^Foreign_Block_Decl,
^Foreign_Import_Decl,
^Attribute,
^Field,
^Field_List,
^Bit_Field_Field,
}
Any_Expr :: union {
^Bad_Expr,
^Ident,
^Implicit,
^Undef,
^Basic_Lit,
^Basic_Directive,
^Ellipsis,
^Proc_Lit,
^Comp_Lit,
^Tag_Expr,
^Unary_Expr,
^Binary_Expr,
^Paren_Expr,
^Selector_Expr,
^Implicit_Selector_Expr,
^Selector_Call_Expr,
^Index_Expr,
^Deref_Expr,
^Slice_Expr,
^Matrix_Index_Expr,
^Call_Expr,
^Field_Value,
^Ternary_If_Expr,
^Ternary_When_Expr,
^Or_Else_Expr,
^Or_Return_Expr,
^Or_Branch_Expr,
^Type_Assertion,
^Type_Cast,
^Auto_Cast,
^Inline_Asm_Expr,
^Proc_Group,
^Typeid_Type,
^Helper_Type,
^Distinct_Type,
^Poly_Type,
^Proc_Type,
^Pointer_Type,
^Multi_Pointer_Type,
^Array_Type,
^Dynamic_Array_Type,
^Fixed_Capacity_Dynamic_Array_Type,
^Struct_Type,
^Union_Type,
^Enum_Type,
^Bit_Set_Type,
^Map_Type,
^Relative_Type,
^Matrix_Type,
^Bit_Field_Type,
}
Any_Stmt :: union {
^Bad_Stmt,
^Empty_Stmt,
^Expr_Stmt,
^Tag_Stmt,
^Assign_Stmt,
^Block_Stmt,
^If_Stmt,
^When_Stmt,
^Return_Stmt,
^Defer_Stmt,
^For_Stmt,
^Range_Stmt,
^Inline_Range_Stmt,
^Case_Clause,
^Switch_Stmt,
^Type_Switch_Stmt,
^Branch_Stmt,
^Using_Stmt,
^Bad_Decl,
^Value_Decl,
^Package_Decl,
^Import_Decl,
^Foreign_Block_Decl,
^Foreign_Import_Decl,
}