"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/onyx",
- "args": ["progs/arrays.onyx"],
+ "args": ["progs/structs.onyx"],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
typedef struct AstAddressOf AstAddressOf;
typedef struct AstDereference AstDereference;
typedef struct AstArrayAccess AstArrayAccess;
+typedef struct AstFieldAccess AstFieldAccess;
typedef struct AstAssign AstAssign;
typedef struct AstReturn AstReturn;
typedef struct AstBasicType AstBasicType;
typedef struct AstPointerType AstPointerType;
typedef struct AstFunctionType AstFunctionType;
+typedef struct AstStructType AstStructType;
+typedef struct AstStructMember AstStructMember;
typedef struct AstBinding AstBinding;
typedef struct AstUse AstUse;
Ast_Kind_Basic_Type,
Ast_Kind_Pointer_Type,
Ast_Kind_Function_Type,
+ Ast_Kind_Struct_Type,
Ast_Kind_Type_End,
+ Ast_Kind_Struct_Member,
+
Ast_Kind_NumLit,
Ast_Kind_StrLit,
Ast_Kind_Param,
Ast_Kind_Address_Of,
Ast_Kind_Dereference,
Ast_Kind_Array_Access,
+ Ast_Kind_Field_Access,
Ast_Kind_If,
Ast_Kind_For,
// only 32-bits of flags to play with
typedef enum AstFlags {
// Top-level flags
- Ast_Flag_Exported = BH_BIT(0),
- Ast_Flag_Foreign = BH_BIT(1),
- Ast_Flag_Const = BH_BIT(2),
- Ast_Flag_Comptime = BH_BIT(3),
+ Ast_Flag_Exported = BH_BIT(0),
+ Ast_Flag_Foreign = BH_BIT(1),
+ Ast_Flag_Const = BH_BIT(2),
+ Ast_Flag_Comptime = BH_BIT(3),
// Function flags
- Ast_Flag_Inline = BH_BIT(8),
- Ast_Flag_Intrinsic = BH_BIT(9),
+ Ast_Flag_Inline = BH_BIT(8),
+ Ast_Flag_Intrinsic = BH_BIT(9),
// Expression flags
- Ast_Flag_Expr_Ignored = BH_BIT(8),
+ Ast_Flag_Expr_Ignored = BH_BIT(8),
+
+ // Type flags
+ Ast_Flag_Type_Is_Resolved = BH_BIT(8),
} AstFlags;
typedef enum UnaryOp {
struct AstAddressOf { AstTyped_base; AstTyped *expr; };
struct AstDereference { AstTyped_base; AstTyped *expr; };
struct AstArrayAccess { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
+struct AstFieldAccess { AstTyped_base; AstTyped *expr; u64 offset; };
// Intruction Node
struct AstReturn { AstNode_base; AstTyped* expr; };
// without the 'next' member. This is because types
// can't be in expressions so a 'next' thing
// doesn't make sense.
-#define AstType_members { AstKind kind; u32 flags; char* name; }
+#define AstType_members { AstKind kind; u32 flags; OnyxToken* token; char* name; }
#define AstType_base struct AstType_members;
struct AstType AstType_members;
struct AstBasicType { AstType_base; Type* type; };
struct AstPointerType { AstType_base; AstType* elem; };
struct AstFunctionType { AstType_base; AstType* return_type; u64 param_count; AstType* params[]; };
+struct AstStructType {
+ AstType_base;
+
+ bh_arr(AstStructMember *) members;
+
+ // NOTE: Used to cache the actual type, since building
+ // a struct type is kind of complicated and should
+ // only happen once.
+ Type *stcache;
+};
+struct AstStructMember { AstTyped_base; u64 offset; };
// Top level nodes
struct AstBinding { AstTyped_base; AstNode* node; };
// processed later down the pipeline.
typedef enum EntityType {
Entity_Type_Unknown,
- Entity_Type_Function,
- Entity_Type_Overloaded_Function,
- Entity_Type_Global,
+ Entity_Type_Function_Header,
+ Entity_Type_Global_Header,
+ Entity_Type_Expression,
Entity_Type_String_Literal,
- Entity_Type_Expression
+ Entity_Type_Struct,
+ Entity_Type_Global,
+ Entity_Type_Overloaded_Function,
+ Entity_Type_Function,
} EntityType;
typedef struct Entity {
AstGlobal *global;
AstTyped *expr;
AstStrLit *strlit;
+ AstStructType *struct_type;
};
} Entity;
return (node->kind == Ast_Kind_Local)
|| (node->kind == Ast_Kind_Global)
|| (node->kind == Ast_Kind_Dereference)
- || (node->kind == Ast_Kind_Array_Access);
+ || (node->kind == Ast_Kind_Array_Access)
+ || (node->kind == Ast_Kind_Field_Access);
}
static inline b32 binop_is_assignment(AstBinaryOp* binop) {
Msg_Type_Function_Return_Mismatch,
Msg_Type_Function_Param_Mismatch,
+ Msg_Type_Duplicate_Member,
+
Msg_Type_Unresolved_Type,
Msg_Type_Unresolved_Symbol,
// NOTE: Forward declaration for some of the types below
typedef struct Type Type;
+typedef struct StructMember {
+ u64 offset;
+ Type *type;
+} StructMember;
+
#define TYPE_KINDS \
TYPE_KIND(Basic, TypeBasic) \
TYPE_KIND(Pointer, struct { TypeBasic base; Type *elem; }) \
- TYPE_KIND(Function, struct { Type *return_type; u64 param_count; Type* params[]; })
+ TYPE_KIND(Function, struct { Type *return_type; u64 param_count; Type* params[]; }) \
+ TYPE_KIND(Struct, struct { char* name; u32 size; u32 mem_count; bh_table(StructMember) members; })
typedef enum TypeKind {
Type_Kind_Invalid,
struct AstType;
b32 types_are_compatible(Type* t1, Type* t2);
+u32 type_size_of(Type* type);
Type* type_build_from_ast(bh_allocator alloc, struct AstType* type_node);
Type* type_make_pointer(bh_allocator alloc, Type* to);
const char* type_get_name(Type* type);
+u32 type_get_alignment_log2(Type* type);
+
+StructMember type_struct_lookup_member(Type* type, char* member);
b32 type_is_pointer(Type* type);
+b32 type_is_struct(Type* type);
b32 type_is_bool(Type* type);
#endif // #ifndef ONYX_TYPES
--- /dev/null
+use "progs/print_funcs"
+use "progs/intrinsics"
+
+Vec3 :: struct {
+ x : f32;
+ y : f32;
+ z : f32;
+}
+
+Foo :: struct {
+ v : Vec3;
+ i : i32;
+ l : i64;
+ f : f32;
+ d : f64;
+ foo : ^Foo;
+}
+
+alloc :: proc (size: u32) -> rawptr {
+ heap_u32 :: __heap_start as ^u32;
+
+ curr_offset := *heap_u32;
+ if curr_offset == 0 curr_offset = 8;
+
+ *heap_u32 = curr_offset + size;
+
+ return ((__heap_start as u32) + curr_offset) as rawptr;
+}
+
+foo_make :: proc -> ^Foo {
+ return alloc(40) as ^Foo;
+}
+
+foo_get :: proc (fooarr: ^Foo, i: i32) -> ^Foo {
+ return ^fooarr[i];
+}
+
+proc #export "main" {
+ // foo := foo_make();
+ // other_foo := foo_make();
+ // other_foo.i = 1234;
+
+ // foo.foo = other_foo;
+ // print(foo.foo.i);
+
+ foo1 := foo_make();
+ foo1.v.y = 123.0f;
+ print(foo1.v.y);
+
+ foo := alloc(40* 5) as ^Foo;
+
+ for i: 1, 6 {
+ foo[i - 1].v.x = (i + 3) as f32;
+ foo[i - 1].v.y = (i + 4) as f32;
+
+ foo[i - 1].i = i;
+ foo[i - 1].l = (i * 10) as i64;
+ foo[i - 1].f = (i * 100) as f32;
+ foo[i - 1].d = (i * 1000) as f64;
+
+ foo[i - 1].foo = foo;
+ }
+
+ print(foo[3].v.x); // 7
+ print(foo[4].i); // 5
+ print(foo[2].d); // 3000.0
+ print(foo[3].f); // 400.0
+ print(foo[0].l); // 10
+
+ print(foo as i32);
+ print((^(foo[3].l)) as i32); // 84
+
+ print(foo[2].foo[4].foo[3].f); // 400.0
+
+ foo_get(foo, 2).f = 1234.5f;
+ print(foo[2].f);
+
+ print(1000000000000);
+ link_test();
+}
+
+Mut1 :: struct {
+ bar : i32;
+ other : Mut2;
+}
+
+Mut2 :: struct {
+ foo : i32;
+ other : ^Foo;
+}
+
+mut_func :: proc #export (mut: ^Mut1) -> ^Foo {
+ return mut.other.other;
+}
+
+
+Link :: struct {
+ data : i32;
+ other_data : i32;
+ next : ^Link;
+}
+
+link_create :: proc (data: i32, parent: ^Link) -> ^Link {
+ link := alloc(12) as ^Link;
+ link.data = data;
+ link.other_data = 1234;
+ link.next = parent;
+ return link;
+}
+
+link_print :: proc (start: ^Link) {
+ walker := start;
+ while (walker as i32) != 0 {
+ print(walker.next.data);
+ walker = walker.next;
+ }
+}
+
+link_test :: proc #export "main2" {
+ dummy :: "H";
+
+ node1 := link_create(1, 0 as ^Link);
+ node2 := link_create(2, node1);
+ node3 := link_create(3, node2);
+ node4 := link_create(4, node3);
+ node5 := link_create(5, node4);
+
+ link_print(node5);
+}
\ No newline at end of file
return onyx_parse(&parser);
}
+static i32 sort_entities(const void* e1, const void* e2) {
+ return ((Entity *)e1)->type - ((Entity *)e2)->type;
+}
+
static void merge_parse_results(CompilerState* compiler_state, ParseResults* results) {
bh_arr_each(AstUse *, use_node, results->uses) {
char* formatted_name = bh_aprintf(
bh_arr_each(AstBinding *, binding_node, results->bindings)
bh_arr_push(compiler_state->prog_info.bindings, *binding_node);
+ Entity ent;
bh_arr_each(AstNode *, node, results->nodes_to_process) {
- Entity ent = { Entity_Type_Unknown };
-
AstKind nkind = (*node)->kind;
switch (nkind) {
- case Ast_Kind_Function:
+ case Ast_Kind_Function: {
+ ent.type = Entity_Type_Function_Header;
+ ent.function = (AstFunction *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
+
ent.type = Entity_Type_Function;
ent.function = (AstFunction *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
break;
+ }
- case Ast_Kind_Overloaded_Function:
+ case Ast_Kind_Overloaded_Function: {
ent.type = Entity_Type_Overloaded_Function;
ent.overloaded_function = (AstOverloadedFunction *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
break;
+ }
+
+ case Ast_Kind_Global: {
+ ent.type = Entity_Type_Global_Header;
+ ent.global = (AstGlobal *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
- case Ast_Kind_Global:
ent.type = Entity_Type_Global;
ent.global = (AstGlobal *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
break;
+ }
- case Ast_Kind_StrLit:
+ case Ast_Kind_StrLit: {
ent.type = Entity_Type_String_Literal;
ent.strlit = (AstStrLit *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
+ break;
+ }
+
+ case Ast_Kind_Struct_Type: {
+ ent.type = Entity_Type_Struct;
+ ent.struct_type = (AstStructType *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
break;
+ }
- default:
+ default: {
ent.type = Entity_Type_Expression;
ent.expr = (AstTyped *) *node;
+ bh_arr_push(compiler_state->prog_info.entities, ent);
break;
+ }
}
-
- bh_arr_push(compiler_state->prog_info.entities, ent);
}
+
+ qsort(compiler_state->prog_info.entities,
+ bh_arr_length(compiler_state->prog_info.entities),
+ sizeof(Entity),
+ sort_entities);
}
static CompilerProgress process_source_file(CompilerState* compiler_state, char* filename) {
#define BH_DEBUG
#include "onyxsempass.h"
#include "onyxparser.h"
+#include "onyxutils.h"
#define CHECK(kind, ...) static b32 check_ ## kind (__VA_ARGS__)
CHECK(address_of, AstAddressOf* aof);
CHECK(dereference, AstDereference* deref);
CHECK(array_access, AstArrayAccess* expr);
+CHECK(field_access, AstFieldAccess* field);
CHECK(global, AstGlobal* global);
CHECK(function, AstFunction* func);
CHECK(overloaded_function, AstOverloadedFunction* func);
+CHECK(struct, AstStructType* s_node);
static inline void fill_in_type(AstTyped* node) {
if (node->type == NULL)
if (check_expression(aof->expr)) return 1;
if (aof->expr->kind != Ast_Kind_Array_Access
- && aof->expr->kind != Ast_Kind_Dereference) {
+ && aof->expr->kind != Ast_Kind_Dereference
+ && aof->expr->kind != Ast_Kind_Field_Access) {
onyx_message_add(Msg_Type_Literal,
aof->token->pos,
"cannot take the address of this");
}
aa->type = aa->addr->type->Pointer.elem;
- aa->elem_size = aa->type->Basic.size;
+ aa->elem_size = type_size_of(aa->type);
+
+ return 0;
+}
+
+CHECK(field_access, AstFieldAccess* field) {
+ if (check_expression(field->expr)) return 1;
+
+ if (!type_is_struct(field->expr->type)) {
+ onyx_message_add(Msg_Type_Literal,
+ field->token->pos,
+ "expected expression of kind struct or pointer to struct");
+ return 1;
+ }
+
+ token_toggle_end(field->token);
+ StructMember smem = type_struct_lookup_member(field->expr->type, field->token->text);
+ field->offset = smem.offset;
+ field->type = smem.type;
+ token_toggle_end(field->token);
return 0;
}
case Ast_Kind_Address_Of: retval = check_address_of((AstAddressOf *) expr); break;
case Ast_Kind_Dereference: retval = check_dereference((AstDereference *) expr); break;
case Ast_Kind_Array_Access: retval = check_array_access((AstArrayAccess *) expr); break;
+ case Ast_Kind_Field_Access: retval = check_field_access((AstFieldAccess *) expr); break;
case Ast_Kind_Global:
if (expr->type == NULL) {
return 0;
}
+CHECK(struct, AstStructType* s_node) {
+ bh_table(i32) mem_set;
+ bh_table_init(global_heap_allocator, mem_set, bh_arr_length(s_node->members));
+
+ bh_arr_each(AstStructMember *, member, s_node->members) {
+ token_toggle_end((*member)->token);
+
+ if (bh_table_has(i32, mem_set, (*member)->token->text)) {
+ onyx_message_add(Msg_Type_Duplicate_Member,
+ (*member)->token->pos,
+ (*member)->token->text);
+
+ token_toggle_end((*member)->token);
+ return 1;
+ }
+
+ bh_table_put(i32, mem_set, (*member)->token->text, 1);
+ token_toggle_end((*member)->token);
+ }
+
+ bh_table_free(mem_set);
+
+ // NOTE: fills in the stcache
+ type_build_from_ast(semstate.allocator, (AstType *) s_node);
+
+ return 0;
+}
+
CHECK(node, AstNode* node) {
switch (node->kind) {
case Ast_Kind_Function: return check_function((AstFunction *) node);
if (check_expression(entity->expr)) return;
break;
+ case Entity_Type_Struct:
+ if (check_struct(entity->struct_type)) return;
+ break;
+
case Entity_Type_String_Literal: break;
+ case Entity_Type_Function_Header: break;
+ case Entity_Type_Global_Header: break;
+
default: DEBUG_HERE; break;
}
}
"returning '%s' from function that returns '%s'",
"function '%b' expected type '%s' in position '%d', got '%s'",
+ "duplicate declaration of struct member '%s'",
+
"unable to resolve type for symbol '%b'",
"unable to resolve symbol '%b'",
};
static b32 is_terminating_token(TokenType token_type);
static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type);
-static AstNumLit* parse_numeric_literal(OnyxParser* parser);
-static AstTyped* parse_factor(OnyxParser* parser);
-static AstTyped* parse_expression(OnyxParser* parser);
-static AstIf* parse_if_stmt(OnyxParser* parser);
-static AstWhile* parse_while_stmt(OnyxParser* parser);
-static AstFor* parse_for_stmt(OnyxParser* parser);
-static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret);
-static AstReturn* parse_return_statement(OnyxParser* parser);
-static AstBlock* parse_block(OnyxParser* parser);
-static AstNode* parse_statement(OnyxParser* parser);
-static AstType* parse_type(OnyxParser* parser);
-static AstLocal* parse_function_params(OnyxParser* parser);
-static AstFunction* parse_function_definition(OnyxParser* parser);
-static AstTyped* parse_global_declaration(OnyxParser* parser);
-static AstTyped* parse_top_level_expression(OnyxParser* parser);
-static AstNode* parse_top_level_statement(OnyxParser* parser);
+static AstNumLit* parse_numeric_literal(OnyxParser* parser);
+static AstTyped* parse_factor(OnyxParser* parser);
+static AstTyped* parse_expression(OnyxParser* parser);
+static AstIf* parse_if_stmt(OnyxParser* parser);
+static AstWhile* parse_while_stmt(OnyxParser* parser);
+static AstFor* parse_for_stmt(OnyxParser* parser);
+static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret);
+static AstReturn* parse_return_statement(OnyxParser* parser);
+static AstBlock* parse_block(OnyxParser* parser);
+static AstNode* parse_statement(OnyxParser* parser);
+static AstType* parse_type(OnyxParser* parser);
+static AstStructType* parse_struct(OnyxParser* parser);
+static AstLocal* parse_function_params(OnyxParser* parser);
+static AstFunction* parse_function_definition(OnyxParser* parser);
+static AstTyped* parse_global_declaration(OnyxParser* parser);
+static AstTyped* parse_top_level_expression(OnyxParser* parser);
+static AstNode* parse_top_level_statement(OnyxParser* parser);
static void consume_token(OnyxParser* parser) {
parser->prev = parser->curr;
return NULL;
}
- while (parser->curr->type == '[') {
- AstArrayAccess* aa_node = make_node(AstArrayAccess, Ast_Kind_Array_Access);
- aa_node->token = expect_token(parser, '[');
- aa_node->addr = retval;
- aa_node->expr = parse_expression(parser);
+ while (parser->curr->type == '[' || parser->curr->type == Token_Type_Keyword_Cast
+ || parser->curr->type == '.') {
- expect_token(parser, ']');
+ switch ((u16) parser->curr->type) {
+ case '[': {
+ AstArrayAccess* aa_node = make_node(AstArrayAccess, Ast_Kind_Array_Access);
+ aa_node->token = expect_token(parser, '[');
+ aa_node->addr = retval;
+ aa_node->expr = parse_expression(parser);
- retval = (AstTyped *) aa_node;
- }
+ expect_token(parser, ']');
- while (parser->curr->type == Token_Type_Keyword_Cast) {
+ retval = (AstTyped *) aa_node;
+ break;
+ }
- AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
- cast_node->token = expect_token(parser, Token_Type_Keyword_Cast);
- cast_node->type_node = parse_type(parser);
- cast_node->operation = Unary_Op_Cast;
- cast_node->expr = retval;
- retval = (AstTyped *) cast_node;
- }
+ case '.': {
+ consume_token(parser);
+ AstFieldAccess* field = make_node(AstFieldAccess, Ast_Kind_Field_Access);
+ field->token = expect_token(parser, Token_Type_Symbol);
+ field->expr = retval;
+ retval = (AstTyped *) field;
+ break;
+ }
+
+ case Token_Type_Keyword_Cast: {
+ AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
+ cast_node->token = expect_token(parser, Token_Type_Keyword_Cast);
+ cast_node->type_node = parse_type(parser);
+ cast_node->operation = Unary_Op_Cast;
+ cast_node->expr = retval;
+
+ retval = (AstTyped *) cast_node;
+ break;
+ }
+ }
+ }
return retval;
}
while (1) {
if (parser->curr->type == '^') {
- consume_token(parser);
AstPointerType* new = make_node(AstPointerType, Ast_Kind_Pointer_Type);
new->flags |= Basic_Flag_Pointer;
+ new->token = expect_token(parser, '^');
*next_insertion = (AstType *) new;
next_insertion = &new->elem;
}
return root;
}
+static AstStructType* parse_struct(OnyxParser* parser) {
+ AstStructType* s_node = make_node(AstStructType, Ast_Kind_Struct_Type);
+ s_node->token = expect_token(parser, Token_Type_Keyword_Struct);
+
+ bh_arr_new(global_heap_allocator, s_node->members, 4);
+
+ expect_token(parser, '{');
+ while (parser->curr->type != '}') {
+ AstStructMember* mem = make_node(AstStructMember, Ast_Kind_Struct_Member);
+ mem->offset = 0;
+
+ mem->token = expect_token(parser, Token_Type_Symbol);
+ expect_token(parser, ':');
+ mem->type_node = parse_type(parser);
+ expect_token(parser, ';');
+
+ bh_arr_push(s_node->members, mem);
+ }
+
+ return s_node;
+}
+
// e
// '(' (<symbol>: <type>,?)* ')'
static AstLocal* parse_function_params(OnyxParser* parser) {
else if (parser->curr->type == Token_Type_Keyword_Global) {
return parse_global_declaration(parser);
}
+ else if (parser->curr->type == Token_Type_Keyword_Struct) {
+ return (AstTyped *) parse_struct(parser);
+ }
else {
return parse_expression(parser);
}
// <symbol> :: <expr>
static AstNode* parse_top_level_statement(OnyxParser* parser) {
switch (parser->curr->type) {
- case Token_Type_Keyword_Use:
- {
- AstUse* use_node = make_node(AstUse, Ast_Kind_Use);
- use_node->token = expect_token(parser, Token_Type_Keyword_Use);
- use_node->filename = expect_token(parser, Token_Type_Literal_String);
+ case Token_Type_Keyword_Use: {
+ AstUse* use_node = make_node(AstUse, Ast_Kind_Use);
+ use_node->token = expect_token(parser, Token_Type_Keyword_Use);
+ use_node->filename = expect_token(parser, Token_Type_Literal_String);
- return (AstNode *) use_node;
- }
+ return (AstNode *) use_node;
+ }
case Token_Type_Keyword_Proc:
parse_top_level_expression(parser);
return NULL;
- case Token_Type_Symbol:
- {
- OnyxToken* symbol = parser->curr;
- consume_token(parser);
+ case Token_Type_Symbol: {
+ OnyxToken* symbol = parser->curr;
+ consume_token(parser);
- expect_token(parser, ':');
- expect_token(parser, ':');
+ expect_token(parser, ':');
+ expect_token(parser, ':');
- AstTyped* node = parse_top_level_expression(parser);
+ AstTyped* node = parse_top_level_expression(parser);
- if (node->kind == Ast_Kind_Function) {
- AstFunction* func = (AstFunction *) node;
+ if (node->kind == Ast_Kind_Function) {
+ AstFunction* func = (AstFunction *) node;
- if (func->exported_name == NULL)
- func->exported_name = symbol;
+ if (func->exported_name == NULL)
+ func->exported_name = symbol;
- } else if (node->kind == Ast_Kind_Global) {
- AstGlobal* global = (AstGlobal *) node;
+ } else if (node->kind == Ast_Kind_Global) {
+ AstGlobal* global = (AstGlobal *) node;
- if (global->exported_name == NULL)
- global->exported_name = symbol;
+ if (global->exported_name == NULL)
+ global->exported_name = symbol;
- } else if (node->kind != Ast_Kind_Overloaded_Function
- && node->kind != Ast_Kind_StrLit) {
- // HACK
- bh_arr_push(parser->results.nodes_to_process, (AstNode *) node);
- }
+ } else if (node->kind != Ast_Kind_Overloaded_Function
+ && node->kind != Ast_Kind_StrLit) {
- AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
- binding->token = symbol;
- binding->node = (AstNode *) node;
+ if (node->kind == Ast_Kind_Struct_Type) {
+ ((AstStructType *)node)->name = bh_aprintf(global_heap_allocator,
+ "%b", symbol->text, symbol->length);
+ }
- return (AstNode *) binding;
+ // HACK
+ bh_arr_push(parser->results.nodes_to_process, (AstNode *) node);
}
+ AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
+ binding->token = symbol;
+ binding->node = (AstNode *) node;
+
+ return (AstNode *) binding;
+ }
+
default: break;
}
#define BH_DEBUG
#include "onyxsempass.h"
-AstBasicType basic_type_void = { { Ast_Kind_Basic_Type, 0, "void" }, &basic_types[Basic_Kind_Void] };
-AstBasicType basic_type_bool = { { Ast_Kind_Basic_Type, 0, "bool" }, &basic_types[Basic_Kind_Bool] };
-AstBasicType basic_type_i8 = { { Ast_Kind_Basic_Type, 0, "i8" }, &basic_types[Basic_Kind_I8] };
-AstBasicType basic_type_u8 = { { Ast_Kind_Basic_Type, 0, "u8" }, &basic_types[Basic_Kind_U8] };
-AstBasicType basic_type_i16 = { { Ast_Kind_Basic_Type, 0, "i16" }, &basic_types[Basic_Kind_I16] };
-AstBasicType basic_type_u16 = { { Ast_Kind_Basic_Type, 0, "u16" }, &basic_types[Basic_Kind_U16] };
-AstBasicType basic_type_i32 = { { Ast_Kind_Basic_Type, 0, "i32" }, &basic_types[Basic_Kind_I32] };
-AstBasicType basic_type_u32 = { { Ast_Kind_Basic_Type, 0, "u32" }, &basic_types[Basic_Kind_U32] };
-AstBasicType basic_type_i64 = { { Ast_Kind_Basic_Type, 0, "i64" }, &basic_types[Basic_Kind_I64] };
-AstBasicType basic_type_u64 = { { Ast_Kind_Basic_Type, 0, "u64" }, &basic_types[Basic_Kind_U64] };
-AstBasicType basic_type_f32 = { { Ast_Kind_Basic_Type, 0, "f32" }, &basic_types[Basic_Kind_F32] };
-AstBasicType basic_type_f64 = { { Ast_Kind_Basic_Type, 0, "f64" }, &basic_types[Basic_Kind_F64] };
-AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
+AstBasicType basic_type_void = { { Ast_Kind_Basic_Type, 0, NULL, "void" }, &basic_types[Basic_Kind_Void] };
+AstBasicType basic_type_bool = { { Ast_Kind_Basic_Type, 0, NULL, "bool" }, &basic_types[Basic_Kind_Bool] };
+AstBasicType basic_type_i8 = { { Ast_Kind_Basic_Type, 0, NULL, "i8" }, &basic_types[Basic_Kind_I8] };
+AstBasicType basic_type_u8 = { { Ast_Kind_Basic_Type, 0, NULL, "u8" }, &basic_types[Basic_Kind_U8] };
+AstBasicType basic_type_i16 = { { Ast_Kind_Basic_Type, 0, NULL, "i16" }, &basic_types[Basic_Kind_I16] };
+AstBasicType basic_type_u16 = { { Ast_Kind_Basic_Type, 0, NULL, "u16" }, &basic_types[Basic_Kind_U16] };
+AstBasicType basic_type_i32 = { { Ast_Kind_Basic_Type, 0, NULL, "i32" }, &basic_types[Basic_Kind_I32] };
+AstBasicType basic_type_u32 = { { Ast_Kind_Basic_Type, 0, NULL, "u32" }, &basic_types[Basic_Kind_U32] };
+AstBasicType basic_type_i64 = { { Ast_Kind_Basic_Type, 0, NULL, "i64" }, &basic_types[Basic_Kind_I64] };
+AstBasicType basic_type_u64 = { { Ast_Kind_Basic_Type, 0, NULL, "u64" }, &basic_types[Basic_Kind_U64] };
+AstBasicType basic_type_f32 = { { Ast_Kind_Basic_Type, 0, NULL, "f32" }, &basic_types[Basic_Kind_F32] };
+AstBasicType basic_type_f64 = { { Ast_Kind_Basic_Type, 0, NULL, "f64" }, &basic_types[Basic_Kind_F64] };
+AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, NULL, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
return type;
}
+ if (type->kind == Ast_Kind_Struct_Type) {
+ AstStructType* s_node = (AstStructType *) type;
+ if (s_node->flags & Ast_Flag_Type_Is_Resolved) return type;
+
+ s_node->flags |= Ast_Flag_Type_Is_Resolved;
+
+ bh_arr_each(AstStructMember *, member, s_node->members) {
+ (*member)->type_node = symres_type((*member)->type_node);
+ }
+
+ return type;
+ }
+
assert(("Bad type node", 0));
return NULL;
}
symres_expression(&((AstArrayAccess *)(*expr))->expr);
break;
+ case Ast_Kind_Field_Access:
+ symres_expression(&((AstFieldAccess *)(*expr))->expr);
+ break;
+
default:
DEBUG_HERE;
break;
case Entity_Type_Overloaded_Function: symres_overloaded_function(entity->overloaded_function); break;
case Entity_Type_Global: symres_global(entity->global); break;
case Entity_Type_Expression: symres_expression(&entity->expr); break;
+ case Entity_Type_Struct: symres_type((AstType *) entity->struct_type); break;
default: break;
}
{ Type_Kind_Basic, 0, { Basic_Kind_Rawptr, Basic_Flag_Pointer, 4, "rawptr" } },
};
+b32 types_are_surface_compatible(Type* t1, Type* t2) {
+ // NOTE: If they are pointing to the same thing,
+ // it is safe to assume they are the same type
+ if (t1 == t2) return 1;
+ if (t1 == NULL || t2 == NULL) return 0;
+
+ switch (t1->kind) {
+ case Type_Kind_Basic:
+ if (t2->kind == Type_Kind_Basic) {
+ // HACK: Not sure if this is right way to check this?
+ if (t1 == t2) return 1;
+
+ if ((t1->Basic.flags & Basic_Flag_Integer) && (t2->Basic.flags & Basic_Flag_Integer)) {
+ return t1->Basic.size == t2->Basic.size;
+ }
+ }
+ break;
+
+ case Type_Kind_Pointer:
+ if (t2->kind == Type_Kind_Pointer) return 1;
+ break;
+
+ case Type_Kind_Struct: {
+ if (t2->kind != Type_Kind_Struct) return 0;
+ if (t1->Struct.mem_count != t2->Struct.mem_count) return 0;
+ if (strcmp(t1->Struct.name, t2->Struct.name) == 0) return 1;
+
+ b32 works = 1;
+ bh_table_each_start(StructMember, t1->Struct.members);
+ if (!bh_table_has(StructMember, t2->Struct.members, (char *) key)) return 0;
+ StructMember other = bh_table_get(StructMember, t2->Struct.members, (char *) key);
+ if (other.offset != value.offset) return 0;
+
+ if (!types_are_compatible(value.type, other.type)) {
+ works = 0;
+ break;
+ }
+ bh_table_each_end;
+
+ return works;
+ }
+
+ default:
+ assert(("Invalid type", 0));
+ break;
+ }
+
+ return 0;
+}
+
b32 types_are_compatible(Type* t1, Type* t2) {
// NOTE: If they are pointing to the same thing,
// it is safe to assume they are the same type
}
break;
+ case Type_Kind_Struct: {
+ if (t2->kind != Type_Kind_Struct) return 0;
+ if (t1->Struct.mem_count != t2->Struct.mem_count) return 0;
+ if (strcmp(t1->Struct.name, t2->Struct.name) == 0) return 1;
+
+ b32 works = 1;
+ bh_table_each_start(StructMember, t1->Struct.members);
+ if (!bh_table_has(StructMember, t2->Struct.members, (char *) key)) return 0;
+ StructMember other = bh_table_get(StructMember, t2->Struct.members, (char *) key);
+ if (other.offset != value.offset) return 0;
+
+ if (!types_are_surface_compatible(value.type, other.type)) {
+ works = 0;
+ break;
+ }
+ bh_table_each_end;
+
+ return works;
+ }
+
default:
assert(("Invalid type", 0));
break;
return 0;
}
+u32 type_size_of(Type* type) {
+ if (type == NULL) return 0;
+
+ switch (type->kind) {
+ case Type_Kind_Basic: return type->Basic.size;
+ case Type_Kind_Pointer: return 4;
+ case Type_Kind_Function: return 0;
+ case Type_Kind_Struct: return type->Struct.size;
+ default: return 0;
+ }
+}
+
Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
if (type_node == NULL) return NULL;
return func_type;
}
+ case Ast_Kind_Struct_Type: {
+ AstStructType* s_node = (AstStructType *) type_node;
+ if (s_node->stcache != NULL) return s_node->stcache;
+
+ Type* s_type = bh_alloc(alloc, sizeof(Type));
+ s_node->stcache = s_type;
+ s_type->kind = Type_Kind_Struct;
+
+ s_type->Struct.name = s_node->name;
+ s_type->Struct.mem_count = bh_arr_length(s_node->members);
+ bh_table_init(global_heap_allocator, s_type->Struct.members, s_type->Struct.mem_count);
+
+ u32 offset = 0;
+ u32 min_alignment = 1;
+ bh_arr_each(AstStructMember *, member, s_node->members) {
+ (*member)->type = type_build_from_ast(alloc, (*member)->type_node);
+
+ // TODO: Add alignment checking here
+
+ StructMember smem = {
+ .offset = offset,
+ .type = (*member)->type
+ };
+
+ token_toggle_end((*member)->token);
+ bh_table_put(StructMember, s_type->Struct.members, (*member)->token->text, smem);
+ token_toggle_end((*member)->token);
+
+ offset += type_size_of((*member)->type);
+ }
+
+ // TODO: Again, add alignment
+ s_type->Struct.size = offset;
+
+ return s_type;
+ }
+
case Ast_Kind_Basic_Type:
return ((AstBasicType *) type_node)->type;
+ case Ast_Kind_Symbol:
+ assert(("symbol node in type expression", 0));
+ return NULL;
+
default:
assert(("Node is not a type node", 0));
return NULL;
switch (type->kind) {
case Type_Kind_Basic: return type->Basic.name;
case Type_Kind_Pointer: return bh_aprintf(global_scratch_allocator, "^%s", type_get_name(type->Pointer.elem));
+ case Type_Kind_Struct: return type->Struct.name;
default: return "unknown";
}
}
+u32 type_get_alignment_log2(Type* type) {
+ i32 store_size = type_size_of(type);
+ i32 is_integer = (type->Basic.flags & Basic_Flag_Integer)
+ || (type->Basic.flags & Basic_Flag_Pointer);
+
+ if (is_integer) {
+ if (store_size == 1) return 0;
+ else if (store_size == 2) return 1;
+ else if (store_size == 4) return 2;
+ else if (store_size == 8) return 3;
+ } else {
+ if (store_size == 4) return 2;
+ else if (store_size == 8) return 3;
+ }
+
+ return 2;
+}
+
+StructMember type_struct_lookup_member(Type* type, char* member) {
+ if (!type_is_struct(type)) return (StructMember) { 0 };
+ if (type->kind == Type_Kind_Pointer) type = type->Pointer.elem;
+
+ TypeStruct* stype = &type->Struct;
+
+ if (!bh_table_has(StructMember, stype->members, member)) return (StructMember) { 0 };
+ StructMember smem = bh_table_get(StructMember, stype->members, member);
+ return smem;
+}
+
b32 type_is_pointer(Type* type) {
return type->kind == Type_Kind_Pointer || (type->Basic.flags & Basic_Flag_Pointer) != 0;
}
+b32 type_is_struct(Type* type) {
+ if (type->kind == Type_Kind_Struct) return 1;
+ if (type->kind == Type_Kind_Pointer && type->Pointer.elem->kind == Type_Kind_Struct) return 1;
+ return 0;
+}
+
b32 type_is_bool(Type* type) {
return type != NULL && type->kind == Type_Kind_Basic && type->Basic.kind == Basic_Kind_Bool;
}
"UN_OP",
"BIN_OP",
- "TYPE_START (BAD)"
+ "TYPE_START (BAD)",
"TYPE",
"POINTER_TYPE",
"FUNCTION_TYPE",
- "TYPE_END (BAD)"
+ "STRUCT TYPE",
+ "TYPE_END (BAD)",
+
+ "STRUCT MEMBER",
"NUMERIC LITERAL",
"STRING LITERAL",
"ADDRESS OF",
"DEREFERENCE",
"ARRAY_ACCESS",
+ "FIELD_ACCESS",
"IF",
"FOR",
#define WID(instr, data) bh_arr_push(code, ((WasmInstruction){ instr, data }))
#define COMPILE_FUNC(kind, ...) static void compile_ ## kind (OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, __VA_ARGS__)
-COMPILE_FUNC(function_body, AstFunction* fd);
-COMPILE_FUNC(block, AstBlock* block);
-COMPILE_FUNC(statement, AstNode* stmt);
-COMPILE_FUNC(assignment, AstBinaryOp* assign);
-COMPILE_FUNC(if, AstIf* if_node);
-COMPILE_FUNC(while, AstWhile* while_node);
-COMPILE_FUNC(for, AstFor* for_node);
-COMPILE_FUNC(binop, AstBinaryOp* binop);
-COMPILE_FUNC(unaryop, AstUnaryOp* unop);
-COMPILE_FUNC(call, AstCall* call);
-COMPILE_FUNC(intrinsic_call, AstIntrinsicCall* call);
-COMPILE_FUNC(expression, AstTyped* expr);
-COMPILE_FUNC(cast, AstUnaryOp* cast);
-COMPILE_FUNC(return, AstReturn* ret);
+COMPILE_FUNC(function_body, AstFunction* fd);
+COMPILE_FUNC(block, AstBlock* block);
+COMPILE_FUNC(statement, AstNode* stmt);
+COMPILE_FUNC(assignment, AstBinaryOp* assign);
+COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset);
+COMPILE_FUNC(load_instruction, Type* type, u32 offset);
+COMPILE_FUNC(if, AstIf* if_node);
+COMPILE_FUNC(while, AstWhile* while_node);
+COMPILE_FUNC(for, AstFor* for_node);
+COMPILE_FUNC(binop, AstBinaryOp* binop);
+COMPILE_FUNC(unaryop, AstUnaryOp* unop);
+COMPILE_FUNC(call, AstCall* call);
+COMPILE_FUNC(intrinsic_call, AstIntrinsicCall* call);
+COMPILE_FUNC(array_access_location, AstArrayAccess* aa);
+COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return);
+COMPILE_FUNC(expression, AstTyped* expr);
+COMPILE_FUNC(cast, AstUnaryOp* cast);
+COMPILE_FUNC(return, AstReturn* ret);
COMPILE_FUNC(function_body, AstFunction* fd) {
if (fd->body == NULL) return;
compile_expression(mod, &code, deref->expr);
compile_expression(mod, &code, assign->right);
- i32 store_size = deref->type->Basic.size;
- i32 is_integer = (deref->type->Basic.flags & Basic_Flag_Integer)
- || (deref->type->Basic.flags & Basic_Flag_Pointer);
-
- if (is_integer) {
- if (store_size == 1) WID(WI_I32_STORE_8, ((WasmInstructionData) { 0, 0 }));
- else if (store_size == 2) WID(WI_I32_STORE_16, ((WasmInstructionData) { 1, 0 }));
- else if (store_size == 4) WID(WI_I32_STORE, ((WasmInstructionData) { 2, 0 }));
- else if (store_size == 8) WID(WI_I64_STORE, ((WasmInstructionData) { 3, 0 }));
- } else {
- if (store_size == 4) WID(WI_F32_STORE, ((WasmInstructionData) { 2, 0 }));
- else if (store_size == 8) WID(WI_F64_STORE, ((WasmInstructionData) { 3, 0 }));
- }
+ compile_store_instruction(mod, &code,
+ deref->type,
+ type_get_alignment_log2(deref->type),
+ 0);
} else if (lval->kind == Ast_Kind_Array_Access) {
AstArrayAccess* aa = (AstArrayAccess *) lval;
- compile_expression(mod, &code, aa->expr);
- if (aa->elem_size != 1) {
- WID(WI_I32_CONST, aa->elem_size);
- WI(WI_I32_MUL);
- }
- compile_expression(mod, &code, aa->addr);
- WI(WI_I32_ADD);
-
+ compile_array_access_location(mod, &code, aa);
compile_expression(mod, &code, assign->right);
- i32 store_size = aa->type->Basic.size;
- i32 is_integer = (aa->type->Basic.flags & Basic_Flag_Integer)
- || (aa->type->Basic.flags & Basic_Flag_Pointer);
+ compile_store_instruction(mod, &code,
+ aa->type,
+ type_get_alignment_log2(aa->type),
+ 0);
- if (is_integer) {
- if (store_size == 1) WID(WI_I32_STORE_8, ((WasmInstructionData) { 0, 0 }));
- else if (store_size == 2) WID(WI_I32_STORE_16, ((WasmInstructionData) { 1, 0 }));
- else if (store_size == 4) WID(WI_I32_STORE, ((WasmInstructionData) { 2, 0 }));
- else if (store_size == 8) WID(WI_I64_STORE, ((WasmInstructionData) { 3, 0 }));
- } else {
- if (store_size == 4) WID(WI_F32_STORE, ((WasmInstructionData) { 2, 0 }));
- else if (store_size == 8) WID(WI_F64_STORE, ((WasmInstructionData) { 3, 0 }));
- }
+ } else if (lval->kind == Ast_Kind_Field_Access) {
+ AstFieldAccess* field = (AstFieldAccess *) lval;
+ u64 offset = 0;
+ compile_field_access_location(mod, &code, field, &offset);
+ compile_expression(mod, &code, assign->right);
+
+ compile_store_instruction(mod, &code,
+ field->type,
+ type_get_alignment_log2(field->type),
+ offset);
} else {
assert(("Invalid lval", 0));
}
*pcode = code;
}
+COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ i32 store_size = type_size_of(type);
+ i32 is_integer = (type->Basic.flags & Basic_Flag_Integer)
+ || (type->Basic.flags & Basic_Flag_Pointer);
+
+ if (is_integer) {
+ if (store_size == 1) WID(WI_I32_STORE_8, ((WasmInstructionData) { alignment, offset }));
+ else if (store_size == 2) WID(WI_I32_STORE_16, ((WasmInstructionData) { alignment, offset }));
+ else if (store_size == 4) WID(WI_I32_STORE, ((WasmInstructionData) { alignment, offset }));
+ else if (store_size == 8) WID(WI_I64_STORE, ((WasmInstructionData) { alignment, offset }));
+ } else {
+ if (store_size == 4) WID(WI_F32_STORE, ((WasmInstructionData) { alignment, offset }));
+ else if (store_size == 8) WID(WI_F64_STORE, ((WasmInstructionData) { alignment, offset }));
+ }
+
+ *pcode = code;
+}
+
+COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ i32 load_size = type_size_of(type);
+ i32 is_integer = (type->Basic.flags & Basic_Flag_Integer)
+ || (type->Basic.flags & Basic_Flag_Pointer);
+ i32 is_unsigned = type->Basic.flags & Basic_Flag_Unsigned;
+
+ WasmInstructionType instr = WI_NOP;
+ i32 alignment = type_get_alignment_log2(type);
+
+ if (is_integer) {
+ if (load_size == 1) instr = WI_I32_LOAD_8_S;
+ else if (load_size == 2) instr = WI_I32_LOAD_16_S;
+ else if (load_size == 4) instr = WI_I32_LOAD;
+ else if (load_size == 8) instr = WI_I64_LOAD;
+
+ if (load_size < 4 && is_unsigned) instr += 1;
+ } else {
+ if (load_size == 4) instr = WI_F32_LOAD;
+ else if (load_size == 8) instr = WI_F64_LOAD;
+ }
+
+ WID(instr, ((WasmInstructionData) { alignment, offset }));
+
+ if (instr == WI_NOP) {
+ onyx_message_add(Msg_Type_Literal,
+ (OnyxFilePos) { 0 },
+ "failed to generate load instruction");
+ }
+
+ *pcode = code;
+}
+
COMPILE_FUNC(if, AstIf* if_node) {
bh_arr(WasmInstruction) code = *pcode;
*pcode = code;
}
+COMPILE_FUNC(array_access_location, AstArrayAccess* aa) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ compile_expression(mod, &code, aa->expr);
+ if (aa->elem_size != 1) {
+ WID(WI_I32_CONST, aa->elem_size);
+ WI(WI_I32_MUL);
+ }
+ compile_expression(mod, &code, aa->addr);
+ WI(WI_I32_ADD);
+
+ *pcode = code;
+}
+
+COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ u64 offset = field->offset;
+ AstTyped* source_expr = field->expr;
+ while (source_expr->kind == Ast_Kind_Field_Access
+ && (source_expr->type->kind == Type_Kind_Struct)) {
+ offset += ((AstFieldAccess *) source_expr)->offset;
+ source_expr = (AstTyped *) ((AstFieldAccess *) source_expr)->expr;
+ }
+
+ if (source_expr->kind == Ast_Kind_Array_Access) {
+ compile_array_access_location(mod, &code, (AstArrayAccess *) source_expr);
+ } else {
+ compile_expression(mod, &code, source_expr);
+ }
+
+ *offset_return = offset;
+
+ *pcode = code;
+}
+
COMPILE_FUNC(expression, AstTyped* expr) {
bh_arr(WasmInstruction) code = *pcode;
case Ast_Kind_Array_Access: {
AstArrayAccess* aa = (AstArrayAccess *) aof->expr;
+ compile_array_access_location(mod, &code, aa);
+ break;
+ }
- compile_expression(mod, &code, aa->expr);
- if (aa->elem_size != 1) {
- WID(WI_I32_CONST, aa->elem_size);
- WI(WI_I32_MUL);
- }
- compile_expression(mod, &code, aa->addr);
+ case Ast_Kind_Field_Access: {
+ AstFieldAccess* field = (AstFieldAccess *) aof->expr;
+ u64 offset = 0;
+ compile_field_access_location(mod, &code, field, &offset);
+ WID(WI_I32_CONST, offset);
WI(WI_I32_ADD);
break;
}
case Ast_Kind_Dereference: {
AstDereference* deref = (AstDereference *) expr;
compile_expression(mod, &code, deref->expr);
-
- i32 load_size = deref->type->Basic.size;
- i32 is_integer = (deref->type->Basic.flags & Basic_Flag_Integer)
- || (deref->type->Basic.flags & Basic_Flag_Pointer);
- i32 is_unsigned = deref->type->Basic.flags & Basic_Flag_Unsigned;
-
- WasmInstructionType instr = WI_NOP;
- i32 alignment = log2_dumb(load_size);
-
- if (is_integer) {
- if (load_size == 1) instr = WI_I32_LOAD_8_S;
- else if (load_size == 2) instr = WI_I32_LOAD_16_S;
- else if (load_size == 4) instr = WI_I32_LOAD;
- else if (load_size == 8) instr = WI_I64_LOAD;
-
- if (load_size < 4 && is_unsigned) instr += 1;
- } else {
- if (load_size == 4) instr = WI_F32_LOAD;
- else if (load_size == 8) instr = WI_F64_LOAD;
- }
-
- if (instr != WI_NOP) {
- WID(instr, ((WasmInstructionData) { alignment, 0 }));
- } else {
- DEBUG_HERE;
- }
-
+ compile_load_instruction(mod, &code, deref->type, 0);
break;
}
case Ast_Kind_Array_Access: {
AstArrayAccess* aa = (AstArrayAccess *) expr;
- compile_expression(mod, &code, aa->expr);
- if (aa->elem_size != 1) {
- WID(WI_I32_CONST, aa->elem_size);
- WI(WI_I32_MUL);
- }
- compile_expression(mod, &code, aa->addr);
- WI(WI_I32_ADD);
-
- i32 load_size = aa->type->Basic.size;
- i32 is_integer = (aa->type->Basic.flags & Basic_Flag_Integer)
- || (aa->type->Basic.flags & Basic_Flag_Pointer);
- i32 is_unsigned = aa->type->Basic.flags & Basic_Flag_Unsigned;
-
- WasmInstructionType instr = WI_NOP;
- i32 alignment = log2_dumb(load_size);
-
- if (is_integer) {
- if (load_size == 1) instr = WI_I32_LOAD_8_S;
- else if (load_size == 2) instr = WI_I32_LOAD_16_S;
- else if (load_size == 4) instr = WI_I32_LOAD;
- else if (load_size == 8) instr = WI_I64_LOAD;
-
- if (load_size < 4 && is_unsigned) instr += 1;
- } else {
- if (load_size == 4) instr = WI_F32_LOAD;
- else if (load_size == 8) instr = WI_F64_LOAD;
- }
+ compile_array_access_location(mod, &code, aa);
+ compile_load_instruction(mod, &code, aa->type, 0);
+ break;
+ }
- if (instr != WI_NOP) {
- WID(instr, ((WasmInstructionData) { alignment, 0 }));
- } else {
- DEBUG_HERE;
- }
+ case Ast_Kind_Field_Access: {
+ AstFieldAccess* field = (AstFieldAccess* ) expr;
+ u64 offset = 0;
+ compile_field_access_location(mod, &code, field, &offset);
+ compile_load_instruction(mod, &code, field->type, offset);
break;
}
module->next_func_idx = program->foreign_func_count;
module->next_global_idx = program->foreign_global_count;
- // NOTE: First, assign indicies to all functions / globals
bh_arr_each(Entity, entity, program->entities) {
switch (entity->type) {
- case Entity_Type_Function: {
+ case Entity_Type_Function_Header: {
if (entity->function->flags & Ast_Flag_Intrinsic) break;
u64 func_idx;
break;
}
- case Entity_Type_Global: {
+ case Entity_Type_Global_Header: {
u64 global_idx;
if ((entity->global->flags & Ast_Flag_Foreign) != 0)
global_idx = module->next_foreign_global_idx++;
case Entity_Type_String_Literal: {
compile_string_literal(module, (AstStrLit *) entity->strlit);
- }
- default: break;
- }
- }
-
- // NOTE: Round up to the nearest multiple of 16
- builtin_heap_start.value.i =
- (module->next_datum_offset & 15)
- ? ((module->next_datum_offset >> 4) + 1) << 4
- : module->next_datum_offset;
+ // HACK: To put this here
+ // NOTE: Round up to the nearest multiple of 16
+ builtin_heap_start.value.i =
+ (module->next_datum_offset & 15)
+ ? ((module->next_datum_offset >> 4) + 1) << 4
+ : module->next_datum_offset;
+ break;
+ }
- // NOTE: Then, compile everything
- bh_arr_each(Entity, entity, program->entities) {
- switch (entity->type) {
case Entity_Type_Function: compile_function(module, entity->function); break;
case Entity_Type_Global: compile_global(module, entity->global); break;
+
default: break;
}
}