package odin_parser

This commit is contained in:
gingerBill
2019-01-26 20:17:03 +00:00
parent c72427fd1e
commit 5f840ea2fc
4 changed files with 3736 additions and 0 deletions

607
core/odin/ast/ast.odin Normal file
View File

@@ -0,0 +1,607 @@
package odin_ast
import "core:odin/token"
Proc_Tag :: enum {
Bounds_Check,
No_Bounds_Check,
Require_Results,
No_Context,
}
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
Proc_Inlining :: enum u32 {
None = 0,
Inline = 1,
No_Inline = 2,
}
Proc_Calling_Convention :: enum i32 {
Invalid = 0,
Odin,
Contextless,
C_Decl,
Std_Call,
Fast_Call,
Foreign_Block_Default = -1,
}
Comment_Group :: struct {
list: []token.Token,
}
Node :: struct {
pos: token.Pos,
end: token.Pos,
derived: any,
}
Expr :: struct {
using expr_base: Node,
}
Stmt :: struct {
using stmt_base: Node,
}
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: token.Token,
}
Undef :: struct {
using node: Expr,
tok: token.Kind,
}
Basic_Lit :: struct {
using node: Expr,
tok: token.Token,
}
Basic_Directive :: struct {
using node: Expr,
tok: token.Token,
name: string,
}
Ellipsis :: struct {
using node: Expr,
tok: token.Kind,
expr: ^Expr,
}
Proc_Lit :: struct {
using node: Expr,
type: ^Proc_Type,
body: ^Stmt,
tags: Proc_Tags,
inlining: Proc_Inlining,
}
Comp_Lit :: struct {
using node: Expr,
type: ^Expr,
open: token.Pos,
elems: []^Expr,
close: token.Pos,
}
Tag_Expr :: struct {
using node: Expr,
op: token.Token,
name: string,
expr: ^Expr,
}
Unary_Expr :: struct {
using node: Expr,
op: token.Token,
expr: ^Expr,
}
Binary_Expr :: struct {
using node: Expr,
left: ^Expr,
op: token.Token,
right: ^Expr,
}
Paren_Expr :: struct {
using node: Expr,
open: token.Pos,
expr: ^Expr,
close: token.Pos,
}
Selector_Expr :: struct {
using node: Expr,
expr: ^Expr,
field: ^Ident,
}
Index_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: token.Pos,
index: ^Expr,
close: token.Pos,
}
Deref_Expr :: struct {
using node: Expr,
expr: ^Expr,
op: token.Token,
}
Slice_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: token.Pos,
low: ^Expr,
interval: token.Token,
high: ^Expr,
close: token.Pos,
}
Call_Expr :: struct {
using node: Expr,
inlining: Proc_Inlining,
expr: ^Expr,
open: token.Pos,
args: []^Expr,
ellipsis: token.Token,
close: token.Pos,
}
Field_Value :: struct {
using node: Expr,
field: ^Expr,
sep: token.Pos,
value: ^Expr,
}
Ternary_Expr :: struct {
using node: Expr,
cond: ^Expr,
op1: token.Token,
x: ^Expr,
op2: token.Token,
y: ^Expr,
}
Type_Assertion :: struct {
using node: Expr,
expr: ^Expr,
dot: token.Pos,
open: token.Pos,
type: ^Expr,
close: token.Pos,
}
Type_Cast :: struct {
using node: Expr,
tok: token.Token,
open: token.Pos,
type: ^Expr,
close: token.Pos,
expr: ^Expr,
}
Auto_Cast :: struct {
using node: Expr,
op: token.Token,
expr: ^Expr,
}
// Statements
Bad_Stmt :: struct {
using node: Stmt,
}
Empty_Stmt :: struct {
using node: Stmt,
semicolon: token.Pos, // Position of the following ';'
}
Expr_Stmt :: struct {
using node: Stmt,
expr: ^Expr,
}
Tag_Stmt :: struct {
using node: Stmt,
op: token.Token,
name: string,
stmt: ^Stmt,
}
Assign_Stmt :: struct {
using node: Stmt,
lhs: []^Expr,
op: token.Token,
rhs: []^Expr,
}
Block_Stmt :: struct {
using node: Stmt,
label: ^Expr,
open: token.Pos,
stmts: []^Stmt,
close: token.Pos,
}
If_Stmt :: struct {
using node: Stmt,
label: ^Expr,
if_pos: token.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
else_stmt: ^Stmt,
}
When_Stmt :: struct {
using node: Stmt,
when_pos: token.Pos,
cond: ^Expr,
body: ^Stmt,
else_stmt: ^Stmt,
}
Return_Stmt :: struct {
using node: Stmt,
results: []^Expr,
}
Defer_Stmt :: struct {
using node: Stmt,
stmt: ^Stmt,
}
For_Stmt :: struct {
using node: Stmt,
label: ^Expr,
for_pos: token.Pos,
init: ^Stmt,
cond: ^Expr,
post: ^Stmt,
body: ^Stmt,
}
Range_Stmt :: struct {
using node: Stmt,
label: ^Expr,
for_pos: token.Pos,
val0: ^Expr,
val1: ^Expr,
in_pos: token.Pos,
expr: ^Expr,
body: ^Stmt,
}
Case_Clause :: struct {
using node: Stmt,
case_pos: token.Pos,
list: []^Expr,
terminator: token.Token,
body: []^Stmt,
}
Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
switch_pos: token.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
complete: bool,
}
Type_Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
switch_pos: token.Pos,
tag: ^Stmt,
expr: ^Expr,
body: ^Stmt,
complete: bool,
}
Branch_Stmt :: struct {
using node: Stmt,
tok: token.Token,
label: ^Ident,
}
Using_Stmt :: struct {
using node: Stmt,
list: []^Expr,
}
// Declarations
Bad_Decl :: struct {
using node: Decl,
}
Value_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
names: []^Expr,
type: ^Expr,
values: []^Expr,
comment: ^Comment_Group,
is_static: bool,
is_using: bool,
is_mutable: bool,
}
Package_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
token: token.Token,
name: string,
comment: ^Comment_Group,
}
Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
is_using: bool,
import_tok: token.Token,
name: token.Token,
relpath: token.Token,
fullpath: string,
comment: ^Comment_Group,
}
Foreign_Block_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
tok: token.Token,
foreign_library: ^Expr,
body: ^Stmt,
}
Foreign_Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
foreign_tok: token.Token,
import_tok: token.Token,
name: ^Ident,
collection_name: string,
fullpaths: []string,
comment: ^Comment_Group,
}
// Other things
unparen_expr :: proc(expr: ^Expr) -> ^Expr {
if expr == nil {
return nil;
}
for {
e, ok := expr.derived.(Paren_Expr);
if !ok do break;
expr = e.expr;
}
return expr;
}
Field_Flag :: enum {
Ellipsis,
Using,
No_Alias,
C_Vararg,
Auto_Cast,
In,
Results,
Default_Parameters,
Typeid_Token,
}
Field_Flags :: distinct bit_set[Field_Flag];
Field_Flags_Struct :: Field_Flags{
Field_Flag.Using,
};
Field_Flags_Record_Poly_Params :: Field_Flags{
Field_Flag.Typeid_Token,
};
Field_Flags_Signature :: Field_Flags{
Field_Flag.Ellipsis,
Field_Flag.Using,
Field_Flag.No_Alias,
Field_Flag.C_Vararg,
Field_Flag.Auto_Cast,
Field_Flag.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: token.Token,
open: token.Pos,
args: []^Expr,
close: token.Pos,
}
Attribute :: struct {
using node: Node,
tok: token.Kind,
open: token.Pos,
elems: []^Expr,
close: token.Pos,
}
Field :: struct {
using node: Node,
docs: ^Comment_Group,
names: []^Expr, // Could be polymorphic
type: ^Expr,
default_value: ^Expr,
flags: Field_Flags,
comment: ^Comment_Group,
}
Field_List :: struct {
using node: Node,
open: token.Pos,
list: []^Field,
close: token.Pos,
}
// Types
Typeid_Type :: struct {
using node: Expr,
tok: token.Kind,
specialization: ^Expr,
}
Helper_Type :: struct {
using node: Expr,
tok: token.Kind,
type: ^Expr,
}
Distinct_Type :: struct {
using node: Expr,
tok: token.Kind,
type: ^Expr,
}
Opaque_Type :: struct {
using node: Expr,
tok: token.Kind,
type: ^Expr,
}
Poly_Type :: struct {
using node: Expr,
dollar: token.Pos,
type: ^Ident,
specialization: ^Expr,
}
Proc_Type :: struct {
using node: Expr,
tok: token.Token,
calling_convention: Proc_Calling_Convention,
params: ^Field_List,
arrow: token.Pos,
results: ^Field_List,
tags: Proc_Tags,
generic: bool,
diverging: bool,
}
Pointer_Type :: struct {
using node: Expr,
pointer: token.Pos,
elem: ^Expr,
}
Array_Type :: struct {
using node: Expr,
open: token.Pos,
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
close: token.Pos,
elem: ^Expr,
}
Dynamic_Array_Type :: struct {
using node: Expr,
open: token.Pos,
dynamic_pos: token.Pos,
close: token.Pos,
elem: ^Expr,
}
Struct_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
poly_params: ^Field_List,
align: ^Expr,
is_packed: bool,
is_raw_union: bool,
fields: ^Field_List,
name_count: int,
}
Union_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
poly_params: ^Field_List,
align: ^Expr,
variants: []^Expr,
}
Enum_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
base_type: ^Expr,
open: token.Pos,
fields: []^Expr,
close: token.Pos,
is_using: bool,
}
Bit_Field_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
align: ^Expr,
open: token.Pos,
fields: []^Field_Value, // Field_Value with ':' rather than '='
close: token.Pos,
}
Bit_Set_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
open: token.Pos,
elem: ^Expr,
underlying: ^Expr,
close: token.Pos,
}
Map_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
key: ^Expr,
value: ^Expr,
}

313
core/odin/ast/clone.odin Normal file
View File

@@ -0,0 +1,313 @@
package odin_ast
import "core:mem"
import "core:fmt"
import "core:odin/token"
new :: proc($T: typeid, pos, end: token.Pos) -> ^T {
n := mem.new(T);
n.pos = pos;
n.end = end;
n.derived = n^;
base: ^Node = n; // dummy check
return n;
}
clone :: proc{
clone_node,
clone_expr,
clone_stmt,
clone_decl,
clone_array,
clone_dynamic_array,
};
clone_array :: proc(array: $A/[]^$T) -> A {
if len(array) == 0 {
return nil;
}
res := make(A, len(array));
for elem, i in array {
res[i] = auto_cast clone(elem);
}
return res;
}
clone_dynamic_array :: proc(array: $A/[dynamic]^$T) -> A {
if len(array) == 0 {
return nil;
}
res := make(A, len(array));
for elem, i in array {
res[i] = auto_cast clone(elem);
}
return res;
}
clone_expr :: proc(node: ^Expr) -> ^Expr {
return cast(^Expr)clone_node(node);
}
clone_stmt :: proc(node: ^Stmt) -> ^Stmt {
return cast(^Stmt)clone_node(node);
}
clone_decl :: proc(node: ^Decl) -> ^Decl {
return cast(^Decl)clone_node(node);
}
clone_node :: proc(node: ^Node) -> ^Node {
if node == nil {
return nil;
}
size := size_of(Node);
align := align_of(Node);
ti := type_info_of(node.derived.id);
if ti != nil {
size = ti.size;
align = ti.align;
}
res := cast(^Node)mem.alloc(size, align);
src: rawptr = node;
if node.derived != nil {
src = node.derived.data;
}
mem.copy(res, src, size);
res.derived.data = rawptr(res);
switch n in node.derived {
case Bad_Expr:
case Ident:
case Implicit:
case Undef:
case Basic_Lit:
case Ellipsis:
r := cast(^Ellipsis)res;
r.expr = clone(r.expr);
case Proc_Lit:
r := cast(^Proc_Lit)res;
r.type = auto_cast clone(r.type);
r.body = clone(r.body);
case Comp_Lit:
r := cast(^Comp_Lit)res;
r.type = clone(r.type);
r.elems = clone(r.elems);
case Tag_Expr:
r := cast(^Tag_Expr)res;
r.expr = clone(r.expr);
case Unary_Expr:
r := cast(^Unary_Expr)res;
r.expr = clone(r.expr);
case Binary_Expr:
r := cast(^Binary_Expr)res;
r.left = clone(r.left);
r.right = clone(r.right);
case Paren_Expr:
r := cast(^Paren_Expr)res;
r.expr = clone(r.expr);
case Selector_Expr:
r := cast(^Selector_Expr)res;
r.expr = clone(r.expr);
r.field = auto_cast clone(r.field);
case Index_Expr:
r := cast(^Index_Expr)res;
r.expr = clone(r.expr);
r.index = clone(r.index);
case Deref_Expr:
r := cast(^Deref_Expr)res;
r.expr = clone(r.expr);
case Slice_Expr:
r := cast(^Slice_Expr)res;
r.expr = clone(r.expr);
r.low = clone(r.low);
r.high = clone(r.high);
case Call_Expr:
r := cast(^Call_Expr)res;
r.expr = clone(r.expr);
r.args = clone(r.args);
case Field_Value:
r := cast(^Field_Value)res;
r.field = clone(r.field);
r.value = clone(r.value);
case Ternary_Expr:
r := cast(^Ternary_Expr)res;
r.cond = clone(r.cond);
r.x = clone(r.x);
r.y = clone(r.y);
case Type_Assertion:
r := cast(^Type_Assertion)res;
r.expr = clone(r.expr);
r.type = clone(r.type);
case Type_Cast:
r := cast(^Type_Cast)res;
r.type = clone(r.type);
r.expr = clone(r.expr);
case Auto_Cast:
r := cast(^Auto_Cast)res;
r.expr = clone(r.expr);
case Bad_Stmt:
case Empty_Stmt:
case Expr_Stmt:
r := cast(^Expr_Stmt)res;
r.expr = clone(r.expr);
case Tag_Stmt:
r := cast(^Expr_Stmt)res;
r.expr = clone(r.expr);
case Assign_Stmt:
r := cast(^Assign_Stmt)res;
r.lhs = clone(r.lhs);
r.rhs = clone(r.rhs);
case Block_Stmt:
r := cast(^Block_Stmt)res;
r.label = auto_cast clone(r.label);
r.stmts = clone(r.stmts);
case If_Stmt:
r := cast(^If_Stmt)res;
r.label = auto_cast clone(r.label);
r.init = clone(r.init);
r.cond = clone(r.cond);
r.body = clone(r.body);
r.else_stmt = clone(r.else_stmt);
case When_Stmt:
r := cast(^When_Stmt)res;
r.cond = clone(r.cond);
r.body = clone(r.body);
r.else_stmt = clone(r.else_stmt);
case Return_Stmt:
r := cast(^Return_Stmt)res;
r.results = clone(r.results);
case Defer_Stmt:
r := cast(^Defer_Stmt)res;
r.stmt = clone(r.stmt);
case For_Stmt:
r := cast(^For_Stmt)res;
r.label = auto_cast clone(r.label);
r.init = clone(r.init);
r.cond = clone(r.cond);
r.post = clone(r.post);
r.body = clone(r.body);
case Range_Stmt:
r := cast(^Range_Stmt)res;
r.label = auto_cast clone(r.label);
r.val0 = clone(r.val0);
r.val1 = clone(r.val1);
r.expr = clone(r.expr);
r.body = clone(r.body);
case Case_Clause:
r := cast(^Case_Clause)res;
r.list = clone(r.list);
r.body = clone(r.body);
case Switch_Stmt:
r := cast(^Switch_Stmt)res;
r.label = auto_cast clone(r.label);
r.init = clone(r.init);
r.cond = clone(r.cond);
r.body = clone(r.body);
case Type_Switch_Stmt:
r := cast(^Type_Switch_Stmt)res;
r.label = auto_cast clone(r.label);
r.tag = clone(r.tag);
r.expr = clone(r.expr);
r.body = clone(r.body);
case Branch_Stmt:
r := cast(^Branch_Stmt)res;
r.label = auto_cast clone(r.label);
case Using_Stmt:
r := cast(^Using_Stmt)res;
r.list = clone(r.list);
case Bad_Decl:
case Value_Decl:
r := cast(^Value_Decl)res;
r.attributes = clone(r.attributes);
r.names = clone(r.names);
r.type = clone(r.type);
r.values = clone(r.values);
case Package_Decl:
case Import_Decl:
case Foreign_Block_Decl:
r := cast(^Foreign_Block_Decl)res;
r.attributes = clone(r.attributes);
r.foreign_library = clone(r.foreign_library);
r.body = clone(r.body);
case Foreign_Import_Decl:
r := cast(^Foreign_Import_Decl)res;
r.name = auto_cast clone(r.name);
case Proc_Group:
r := cast(^Proc_Group)res;
r.args = clone(r.args);
case Attribute:
r := cast(^Attribute)res;
r.elems = clone(r.elems);
case Field:
r := cast(^Field)res;
r.names = clone(r.names);
r.type = clone(r.type);
r.default_value = clone(r.default_value);
case Field_List:
r := cast(^Field_List)res;
r.list = clone(r.list);
case Typeid_Type:
r := cast(^Typeid_Type)res;
r.specialization = clone(r.specialization);
case Helper_Type:
r := cast(^Helper_Type)res;
r.type = clone(r.type);
case Distinct_Type:
r := cast(^Distinct_Type)res;
r.type = clone(r.type);
case Opaque_Type:
r := cast(^Opaque_Type)res;
r.type = clone(r.type);
case Poly_Type:
r := cast(^Poly_Type)res;
r.type = auto_cast clone(r.type);
r.specialization = clone(r.specialization);
case Proc_Type:
r := cast(^Proc_Type)res;
r.params = auto_cast clone(r.params);
r.results = auto_cast clone(r.results);
case Pointer_Type:
r := cast(^Pointer_Type)res;
r.elem = clone(r.elem);
case Array_Type:
r := cast(^Array_Type)res;
r.len = clone(r.len);
r.elem = clone(r.elem);
case Dynamic_Array_Type:
r := cast(^Dynamic_Array_Type)res;
r.elem = clone(r.elem);
case Struct_Type:
r := cast(^Struct_Type)res;
r.poly_params = auto_cast clone(r.poly_params);
r.align = clone(r.align);
r.fields = auto_cast clone(r.fields);
case Union_Type:
r := cast(^Union_Type)res;
r.poly_params = auto_cast clone(r.poly_params);
r.align = clone(r.align);
r.variants = clone(r.variants);
case Enum_Type:
r := cast(^Enum_Type)res;
r.base_type = clone(r.base_type);
r.fields = clone(r.fields);
case Bit_Field_Type:
r := cast(^Bit_Field_Type)res;
r.fields = clone(r.fields);
case Bit_Set_Type:
r := cast(^Bit_Set_Type)res;
r.elem = clone(r.elem);
r.underlying = clone(r.underlying);
case Map_Type:
r := cast(^Map_Type)res;
r.key = clone(r.key);
r.value = clone(r.value);
case:
fmt.panicf("Unhandled node kind: %T", n);
}
return res;
}

40
core/odin/ast/file.odin Normal file
View File

@@ -0,0 +1,40 @@
package odin_ast
import "core:odin/token"
Package_Kind :: enum {
Normal,
Runtime,
Init,
}
Package :: struct {
kind: Package_Kind,
id: int,
name: string,
fullpath: string,
files: []^File,
user_data: rawptr,
}
File :: struct {
id: int,
pkg: ^Package,
fullpath: string,
src: []byte,
pkg_decl: ^Package_Decl,
pkg_token: token.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,
}

2776
core/odin/parser/parser.odin Normal file

File diff suppressed because it is too large Load Diff