typedef struct AstBasicType AstBasicType;
typedef struct AstPointerType AstPointerType;
typedef struct AstFunctionType AstFunctionType;
+typedef struct AstArrayType AstArrayType;
typedef struct AstStructType AstStructType;
typedef struct AstStructMember AstStructMember;
Ast_Kind_Basic_Type,
Ast_Kind_Pointer_Type,
Ast_Kind_Function_Type,
+ Ast_Kind_Array_Type,
Ast_Kind_Struct_Type,
Ast_Kind_Type_End,
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 AstArrayType { AstType_base; AstType* elem; AstTyped *count_expr; };
struct AstStructType {
AstType_base;
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(Struct, struct { char* name; u32 size; u32 mem_count; bh_table(StructMember) members; })
+ TYPE_KIND(Struct, struct { char* name; u32 size; u32 mem_count; bh_table(StructMember) members; }) \
+ TYPE_KIND(Array, struct { u32 size; u32 count; Type *elem; })
typedef enum TypeKind {
Type_Kind_Invalid,
print_i64 :: proc #foreign "host" "print" (value: i64) ---
print_f64 :: proc #foreign "host" "print" (value: f64) ---
-print_i32arr :: proc (arr: ^i32, len: i32) {
+print_i32arr :: proc (arr: [] i32, len: i32) {
for i: 0, len print(arr[i]);
}
-print_i64arr :: proc (arr: ^i64, len: i32) {
+print_i64arr :: proc (arr: [] i64, len: i32) {
for i: 0, len print(arr[i]);
}
-print_f32arr :: proc (arr: ^f32, len: i32) {
+print_f32arr :: proc (arr: [] f32, len: i32) {
for i: 0, len print(arr[i]);
}
-print_f64arr :: proc (arr: ^f64, len: i32) {
+print_f64arr :: proc (arr: [] f64, len: i32) {
for i: 0, len print(arr[i]);
}
}
}
-print_str_len :: proc (str: ^u8, len: i32) {
+print_str_len :: proc (str: [] u8, len: i32) {
for i: 0, len print(str[i] as i32);
}
use "progs/print_funcs"
use "progs/intrinsics"
+N :: 5
+
Vec3 :: struct {
x : f32;
y : f32;
return alloc(sizeof Foo) as ^Foo;
}
-foo_get :: proc (fooarr: ^Foo, i: i32) -> ^Foo {
+foo_get :: proc (fooarr: []Foo, i: i32) -> ^Foo {
return ^fooarr[i];
}
foo1.v.y = 123.0f;
print(foo1.v.y);
- foo := alloc(sizeof Foo * 5) as ^Foo;
+ foo := alloc(sizeof [N]Foo) as [N]Foo;
for i: 1, 6 {
foo[i - 1].v.x = (i + 3) as f32;
foo[i - 1].f = (i * 100) as f32;
foo[i - 1].d = (i * 1000) as f64;
- foo[i - 1].foo = foo;
+ foo[i - 1].foo = foo as ^Foo;
}
print(foo[3].v.x); // 7
print(1000000000000);
link_test();
+
+ 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
}
Mut1 :: struct {
link_create(4, node_head);
link_print(*node_head);
-}
\ No newline at end of file
+}
+
+
+
+// TODO: Make everything below this comment work
+// SOA :: struct {
+// x : [3]i32;
+// y : [3]i32;
+// }
+
+// soa_test :: proc #export "main" {
+// m_arr := alloc(sizeof [5][5]i32) as [5][5]i32;
+
+// for y: 0, 5 {
+// for x: 0, 5 {
+// m_arr[y][x] = x + y * 5;
+// }
+// }
+
+// print(m_arr[2][4]); // 14
+
+// print(sizeof SOA);
+// }
\ No newline at end of file
if (!type_is_pointer(aa->addr->type)) {
onyx_message_add(Msg_Type_Literal,
aa->token->pos,
- "expected pointer type for left of array access");
+ "expected pointer or array type for left of array access");
return 1;
}
return 1;
}
- aa->type = aa->addr->type->Pointer.elem;
+ if (aa->addr->type->kind == Type_Kind_Pointer)
+ aa->type = aa->addr->type->Pointer.elem;
+ else if (aa->addr->type->kind == Type_Kind_Array)
+ aa->type = aa->addr->type->Array.elem;
+ else {
+ onyx_message_add(Msg_Type_Literal,
+ aa->token->pos,
+ "invalid type for left of array access");
+ return 1;
+ }
+
aa->elem_size = type_size_of(aa->type);
return 0;
"for",
"break",
"continue",
+ "sizeof",
"->",
"<-",
tk.type = Token_Type_Comment;
tk.text = tokenizer->curr;
- while (*tokenizer->curr != '\n') {
+ while (*tokenizer->curr != '\n' && tokenizer->curr != tokenizer->end) {
INCREMENT_CURR_TOKEN(tokenizer);
}
next_insertion = &new->elem;
}
+ else if (parser->curr->type == '[') {
+ AstArrayType* new = make_node(AstArrayType, Ast_Kind_Array_Type);
+ new->token = expect_token(parser, '[');
+
+ if (parser->curr->type != ']')
+ new->count_expr = parse_expression(parser);
+
+ expect_token(parser, ']');
+ *next_insertion = (AstType *) new;
+ next_insertion = &new->elem;
+ }
+
else if (parser->curr->type == Token_Type_Symbol) {
AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol);
symbol_node->token = expect_token(parser, Token_Type_Symbol);
next_insertion = NULL;
}
+ else if (parser->curr->type == Token_Type_Keyword_Struct) {
+ AstStructType* s_node = parse_struct(parser);
+ *next_insertion = (AstType *) s_node;
+ next_insertion = NULL;
+ }
+
else {
token_toggle_end(parser->curr);
onyx_message_add(Msg_Type_Unexpected_Token,
bh_arr_push(s_node->members, mem);
}
+ expect_token(parser, '}');
+
return s_node;
}
return type;
}
+ if (type->kind == Ast_Kind_Array_Type) {
+ AstArrayType* a_node = (AstArrayType *) type;
+
+ if (a_node->count_expr) symres_expression(&a_node->count_expr);
+ a_node->elem = symres_type(a_node->elem);
+
+ return type;
+ }
+
assert(("Bad type node", 0));
return NULL;
}
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;
+ if (t1->Struct.name && t2->Struct.name)
+ if (strcmp(t1->Struct.name, t2->Struct.name) == 0) return 1;
b32 works = 1;
bh_table_each_start(StructMember, t1->Struct.members);
}
break;
- case Type_Kind_Pointer:
+ case Type_Kind_Pointer: {
if (t2->kind == Type_Kind_Pointer) {
return types_are_compatible(t1->Pointer.elem, t2->Pointer.elem);
}
break;
+ }
+
+ case Type_Kind_Array: {
+ if (t2->kind != Type_Kind_Array) return 0;
+
+ if (t1->Array.count != 0)
+ if (t1->Array.count != t2->Array.count) return 0;
+
+ return types_are_compatible(t1->Array.elem, t2->Array.elem);
+ }
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;
+ if (t1->Struct.name && t2->Struct.name)
+ if (strcmp(t1->Struct.name, t2->Struct.name) == 0) return 1;
b32 works = 1;
bh_table_each_start(StructMember, t1->Struct.members);
case Type_Kind_Basic: return type->Basic.size;
case Type_Kind_Pointer: return 4;
case Type_Kind_Function: return 0;
+ case Type_Kind_Array: return type->Array.size;
case Type_Kind_Struct: return type->Struct.size;
default: return 0;
}
return func_type;
}
+ case Ast_Kind_Array_Type: {
+ AstArrayType* a_node = (AstArrayType *) type_node;
+
+ Type* a_type = bh_alloc(alloc, sizeof(Type));
+ a_type->kind = Type_Kind_Array;
+ a_type->Array.elem = type_build_from_ast(alloc, a_node->elem);
+
+ u32 count = 0;
+ if (a_node->count_expr) {
+ a_node->count_expr->type = type_build_from_ast(alloc, a_node->count_expr->type_node);
+
+ // NOTE: Currently, the count_expr has to be an I32 literal
+ if (a_node->count_expr->kind != Ast_Kind_NumLit
+ || a_node->count_expr->type->kind != Type_Kind_Basic
+ || a_node->count_expr->type->Basic.kind != Basic_Kind_I32) {
+ return NULL;
+ }
+
+ count = ((AstNumLit *) a_node->count_expr)->value.i;
+ }
+
+ a_type->Array.count = count;
+ a_type->Array.size = type_size_of(a_type->Array.elem) * count;
+
+ return a_type;
+ }
+
case Ast_Kind_Struct_Type: {
AstStructType* s_node = (AstStructType *) type_node;
if (s_node->stcache != NULL) return s_node->stcache;
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;
+ case Type_Kind_Array: return bh_aprintf(global_scratch_allocator, "[%d] %s", type->Array.count, type_get_name(type->Array.elem));
+ case Type_Kind_Struct:
+ if (type->Struct.name)
+ return type->Struct.name;
+ else
+ return "<anonymous struct>";
default: return "unknown";
}
}
}
b32 type_is_pointer(Type* type) {
- return type->kind == Type_Kind_Pointer || (type->Basic.flags & Basic_Flag_Pointer) != 0;
+ return (type->kind == Type_Kind_Pointer)
+ || (type->kind == Type_Kind_Array);
}
b32 type_is_struct(Type* type) {
"TYPE",
"POINTER_TYPE",
"FUNCTION_TYPE",
+ "ARRAY TYPE",
"STRUCT TYPE",
"TYPE_END (BAD)",
return WASM_TYPE_INT32;
}
+ if (type->kind == Type_Kind_Array) {
+ return WASM_TYPE_INT32;
+ }
+
if (type->kind == Type_Kind_Basic) {
TypeBasic* basic = &type->Basic;
if (basic->flags & Basic_Flag_Boolean) return WASM_TYPE_INT32;
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(array_access_location, AstArrayAccess* aa, u64* offset_return);
COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return);
COMPILE_FUNC(expression, AstTyped* expr);
COMPILE_FUNC(cast, AstUnaryOp* cast);
} else if (lval->kind == Ast_Kind_Array_Access) {
AstArrayAccess* aa = (AstArrayAccess *) lval;
- compile_array_access_location(mod, &code, aa);
+
+ u64 offset = 0;
+ compile_array_access_location(mod, &code, aa, &offset);
compile_expression(mod, &code, assign->right);
compile_store_instruction(mod, &code,
aa->type,
type_get_alignment_log2(aa->type),
- 0);
+ offset);
} else if (lval->kind == Ast_Kind_Field_Access) {
AstFieldAccess* field = (AstFieldAccess *) lval;
*pcode = code;
}
-COMPILE_FUNC(array_access_location, AstArrayAccess* aa) {
+COMPILE_FUNC(array_access_location, AstArrayAccess* aa, u64* offset_return) {
bh_arr(WasmInstruction) code = *pcode;
+ *offset_return = 0;
+
compile_expression(mod, &code, aa->expr);
if (aa->elem_size != 1) {
WID(WI_I32_CONST, aa->elem_size);
}
if (source_expr->kind == Ast_Kind_Array_Access) {
- compile_array_access_location(mod, &code, (AstArrayAccess *) source_expr);
+ u64 o2 = 0;
+ compile_array_access_location(mod, &code, (AstArrayAccess *) source_expr, &o2);
+ offset += o2;
} else {
compile_expression(mod, &code, source_expr);
}
case Ast_Kind_Array_Access: {
AstArrayAccess* aa = (AstArrayAccess *) aof->expr;
- compile_array_access_location(mod, &code, aa);
+ u64 offset = 0;
+ compile_array_access_location(mod, &code, aa, &offset);
+ if (offset != 0) {
+ WID(WI_I32_CONST, offset);
+ WI(WI_I32_ADD);
+ }
break;
}
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);
+ if (offset != 0) {
+ WID(WI_I32_CONST, offset);
+ WI(WI_I32_ADD);
+ }
break;
}
case Ast_Kind_Array_Access: {
AstArrayAccess* aa = (AstArrayAccess *) expr;
- compile_array_access_location(mod, &code, aa);
- compile_load_instruction(mod, &code, aa->type, 0);
+ u64 offset = 0;
+ compile_array_access_location(mod, &code, aa, &offset);
+ compile_load_instruction(mod, &code, aa->type, offset);
break;
}
return;
}
+ if (to->kind == Type_Kind_Basic && to->Basic.kind == Basic_Kind_Void) {
+ WI(WI_DROP);
+ return;
+ }
+
i32 fromidx = -1, toidx = -1;
if (from->Basic.flags & Basic_Flag_Pointer) {
fromidx = 8;