"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/onyx",
- "args": ["progs/alloc_test.onyx"],
+ "args": ["progs/stack_based.onyx"],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
-RELEASE=0
+RELEASE=1
OBJ_FILES=\
build/onyxlex.o \
[X] Be smart about when to use the stack versus use the wasm locals
- [ ] Array literals
+ [ ] Better numeric literals
+ - suffix 'f' for float32
+ - no suffix 'f', but has decimal for float64
+ - suffix 'l' for int64
+ - nothing special for i32 or below
+
+ [ ] Char literals
[ ] Properly checking binary operators
+ - Shouldn't be able to add two structs/arrays together
+
+ [ ] Array literals
[ ] Better checking for casts
+ - Checking which things are allowed to cast to/from should be checked in the checker,
+ not in the wasm generatation
+
+ [ ] Start work on evaluating compile time known values.
+ - An expression marked COMPTIME will be reduced to its value in the parse tree.
[ ] All code paths return correct value
[ ] #initialize structs
- [ ] Start work on evaluating compile time known values.
- - An expression marked COMPTIME will be reduced to its value in the parse tree.
+ [ ] Variadic arguments
[ ] Switch statements
static inline u64 log2_dumb(u64 n) {
switch (n) {
- case 1: return 0;
- case 2: return 1;
- case 4: return 2;
- case 8: return 3;
- case 16: return 4;
- case 32: return 5;
- case 64: return 6;
- case 128: return 7;
- case 256: return 8;
- case 512: return 9;
- case 1024: return 10;
- case 2048: return 11;
- case 4096: return 12;
- case 8192: return 13;
-
- // Don't need all of them right now
+ case 1 << 0: return 0;
+ case 1 << 1: return 1;
+ case 1 << 2: return 2;
+ case 1 << 3: return 3;
+ case 1 << 4: return 4;
+ case 1 << 5: return 5;
+ case 1 << 6: return 6;
+ case 1 << 7: return 7;
+ case 1 << 8: return 8;
+ case 1 << 9: return 9;
+ case 1 << 10: return 10;
+ case 1 << 11: return 11;
+ case 1 << 12: return 12;
+ case 1 << 13: return 13;
+ case 1 << 14: return 14;
+ case 1 << 15: return 15;
+ case 1 << 16: return 16;
+ case 1 << 17: return 17;
+ case 1 << 18: return 18;
+ case 1 << 19: return 19;
+ case 1 << 20: return 20;
+ case 1 << 21: return 21;
+ case 1 << 22: return 22;
+ case 1 << 23: return 23;
+ case 1 << 24: return 24;
+ case 1 << 25: return 25;
+ case 1 << 26: return 26;
+ case 1 << 27: return 27;
+ case 1 << 28: return 28;
+ case 1 << 29: return 29;
+ case 1 << 30: return 30;
+ case 1 << 31: return 31;
+
default: return 0;
}
}
+//-------------------------------------------------------------------------------------
+// Allocator based string functions
+//-------------------------------------------------------------------------------------
+
+char* bh_strdup(bh_allocator a, char* str);
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// STRING IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+char* bh_strdup(bh_allocator a, char* str) {
+ u32 len = strlen(str);
+ char* buf = bh_alloc(a, len + 1);
+ char* t = buf;
+ while (*t++ = *str++);
-
+ *t = 0;
+ return buf;
+}
bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file) {
bh_file_contents fc = {
.allocator = alloc,
- .filename = file->filename,
+ .filename = bh_strdup(alloc, (char *) file->filename),
.length = 0, .data = NULL
};
scope: constant.boolean.onyx
# Numbers
- - match: '\b(-)?[0-9.]+\b'
+ - match: '\b(-)?[0-9.]+(f|l)?\b'
scope: constant.numeric.onyx
- match: '\b0x[0-9A-Fa-f]+\b'
heap_allocator : Allocator;
+#private
heap_state : struct {
free_list : ^heap_block;
next_alloc : rawptr;
remaining_space : u32;
}
+#private
heap_block :: struct {
size : u32;
next : ^heap_block;
heap_allocator.func = heap_alloc_proc;
}
+#private
heap_alloc :: proc (size_: u32, align: u32) -> rawptr {
if size_ == 0 do return null;
return cast(rawptr) (cast(u32) ret + sizeof heap_block);
}
+#private
heap_free :: proc (ptr: rawptr) {
hb_ptr := cast(^heap_block) (cast(u32) ptr - sizeof heap_block);
heap_state.free_list = hb_ptr;
}
+#private
heap_alloc_proc :: proc (data: rawptr, aa: AllocAction, size: u32, align: u32, oldptr: rawptr) -> rawptr {
if aa == AllocAction.Alloc do return heap_alloc(size, align);
if aa == AllocAction.Free {
return null;
}
-malloc :: proc (size: u32) -> rawptr {
- return alloc(^heap_allocator, size);
-}
-
-mfree :: proc (ptr: rawptr) {
- free(^heap_allocator, ptr);
-}
\ No newline at end of file
+malloc :: proc (size: u32) -> rawptr do return alloc(^heap_allocator, size);
+mfree :: proc (ptr: rawptr) do free(^heap_allocator, ptr);
use package printing
deferred_example :: proc -> i32 {
- arr := cast([] i64) malloc(sizeof [8] i64);
+ arr := cast(^i64) malloc(sizeof [8] i64);
if cast(rawptr) arr == null do return 0;
defer mfree(arr);
walker := cast(^i64) arr;
for _: 0, 8 {
- print(*walker);
+ print_u64(cast(i64) *walker);
walker += 1;
}
return cast(i32) (arr[1] + arr[7]);
}
-proc #export "main" {
+proc #export "start" {
print(#file_contents "progs/filetest");
heap_init();
print(deferred_example());
- first := cast([] i32) malloc(sizeof [4] i32);
+ first: [4] i32;
for i: 0, 4 do first[i] = i * 2;
- second := cast([] f32) malloc(sizeof [24] f32);
+ second := cast(^f32) malloc(sizeof [24] f32);
for i: 0, 24 do second[i] = cast(f32) i;
print(cast(u32) first);
mfree(second);
- fourth := cast([] i32) malloc(sizeof [128]i32);
+ fourth := cast(^i32) malloc(sizeof [128]i32);
print(cast(u32) fourth);
fifth := cast(^i32) malloc(sizeof i32);
}
// NOTE: print null-terminated string
-print_str :: proc (str: ^u8) {
+print_str_by_byte :: proc (str: ^u8) {
c := str;
while *c != cast(u8) 0 {
print(cast(i32) (*c));
}
}
+print_str :: proc #foreign "host" "print_str" (str: ^u8) ---
+
print_str_len :: proc (str: [] u8, len: i32) {
for i: 0, len do print(cast(i32) str[i]);
}
+print_u64 :: proc (n_: u64) {
+ n := n_;
+ str: [128] u8;
+ c := cast(^u8) ^str[127];
+ *c = cast(u8) 0;
+ c -= 1;
+
+ if n == cast(u64) 0 {
+ *c = cast(u8) 0x30;
+ c -= 1;
+ } else {
+ while n > cast(u64) 0 {
+ m :: n % cast(u64) 10;
+
+ ch := cast(u8) 0;
+ if m == cast(u64) 0 do ch = cast(u8) 0x30;
+ if m == cast(u64) 1 do ch = cast(u8) 0x31;
+ if m == cast(u64) 2 do ch = cast(u8) 0x32;
+ if m == cast(u64) 3 do ch = cast(u8) 0x33;
+ if m == cast(u64) 4 do ch = cast(u8) 0x34;
+ if m == cast(u64) 5 do ch = cast(u8) 0x35;
+ if m == cast(u64) 6 do ch = cast(u8) 0x36;
+ if m == cast(u64) 7 do ch = cast(u8) 0x37;
+ if m == cast(u64) 8 do ch = cast(u8) 0x38;
+ if m == cast(u64) 9 do ch = cast(u8) 0x39;
+
+ *c = ch;
+ c -= 1;
+
+ n /= cast(u64) 10;
+ }
+ }
+
+ print(c + 1);
+}
+
print :: proc #overloaded {
print_bool,
print_i32,
summing :: proc (x: ^i32) -> i32 {
s := 0;
- for i: 0, N {
- tmp :: ^i;
- s += x[i];
- }
+ for i: 0, N do s += x[i];
return s;
}
return v.x * v.x + v.y * v.y + v.z * v.z;
}
-stuff :: #file_contents "Makefile"
+vec_add :: proc (v: Vec3, u: Vec3, use out: ^Vec3) {
+ x = v.x + u.x;
+ y = v.y + u.y;
+ z = v.z + u.z;
+}
-main :: proc #export {
+start :: proc #export {
heap_init();
print("Hello, World!");
print(cast(i32) __heap_start);
a := 12345;
- arr: [N] i32;
- arr[0] = 10;
- arr[1] = 20;
- arr[2] = 30;
- arr[3] = 40;
- arr[4] = 50;
- arr[9] = 123;
- print(sumN(arr));
- print(summing(cast(^i32) arr));
-
- v: Vec3;
- v.x = 2;
- v.y = 4;
- v.z = 10;
- print(mag_squared(v));
+ arr: [N][N] i32;
+ arr[1][0] = 10;
+ arr[1][1] = 20;
+ arr[1][2] = 30;
+ arr[1][3] = 40;
+ arr[1][4] = 50;
+ arr[1][9] = 123;
+ print(sumN(arr[1]));
+ print(summing(cast(^i32) arr[1]));
+
+ v1: Vec3;
+ v1.x = 2;
+ v1.y = 4;
+ v1.z = 10;
+
+ v2: Vec3;
+ v2.x = 4;
+ v2.y = 2;
+ v2.z = 1;
+
+ v3: Vec3;
+ vec_add(v1, v2, ^v3);
+ print(v3.x);
+ print(v3.y);
+ print(v3.z);
+ print(mag_squared(v3));
print(ret_val(10, 4));
- for i: 0, N do print(arr[i]);
+ for i: 0, N do print(arr[1][i]);
+
+ soa: struct { x: [5] i32; y: [5] i32; };
+ for i: 0, 5 {
+ soa.x[i] = i;
+ soa.y[i] = i * i;
+ }
+ print(soa.y[3]);
}
\ No newline at end of file
CHECK(for, AstFor* fornode) {
if (check_expression(&fornode->start)) return 1;
if (check_expression(&fornode->end)) return 1;
- if (fornode->step)
- if (check_expression(&fornode->step)) return 1;
+ if (check_expression(&fornode->step)) return 1;
+ fornode->var->type_node = fornode->start->type_node;
if (check_expression((AstTyped **) &fornode->var)) return 1;
- // HACK
- if (!types_are_compatible(fornode->start->type, &basic_types[Basic_Kind_I32])) {
+ if (!type_is_integer(fornode->start->type)) {
onyx_message_add(Msg_Type_Literal,
fornode->start->token->pos,
- "expected expression of type i32 for start");
+ "expected expression of integer type for start");
return 1;
}
- if (!types_are_compatible(fornode->end->type, &basic_types[Basic_Kind_I32])) {
+ if (!type_is_integer(fornode->end->type)) {
onyx_message_add(Msg_Type_Literal,
fornode->end->token->pos,
- "expected expression of type i32 for end");
+ "expected expression of integer type for end");
return 1;
}
- if (fornode->step)
- if (!types_are_compatible(fornode->step->type, &basic_types[Basic_Kind_I32])) {
- onyx_message_add(Msg_Type_Literal,
- fornode->start->token->pos,
- "expected expression of type i32 for step");
- return 1;
- }
+ if (!type_is_integer(fornode->step->type)) {
+ onyx_message_add(Msg_Type_Literal,
+ fornode->step->token->pos,
+ "expected expression of integer type for step");
+ return 1;
+ }
+
+ if (!types_are_compatible(fornode->end->type, fornode->start->type)) {
+ onyx_message_add(Msg_Type_Literal,
+ fornode->end->token->pos,
+ "type of end does not match type of start");
+ return 1;
+ }
+
+ if (!types_are_compatible(fornode->step->type, fornode->start->type)) {
+ onyx_message_add(Msg_Type_Literal,
+ fornode->start->token->pos,
+ "type of step does not match type of start");
+ return 1;
+ }
if (check_block(fornode->stmt)) return 1;
if (parser->curr->type == ',') {
consume_token(parser);
for_node->step = parse_expression(parser);
+ } else {
+ for_node->step = make_node(AstNumLit, Ast_Kind_NumLit);
+ for_node->step->type_node = (AstType *) &basic_type_i32;
+ ((AstNumLit *) for_node->step)->value.i = 1;
}
for_node->stmt = parse_block(parser);
symres_expression(&fornode->start);
symres_expression(&fornode->end);
- if (fornode->step) symres_expression(&fornode->step);
+ symres_expression(&fornode->step);
symres_block(fornode->stmt);
u32 it_idx = (u32) (tmp & ~LOCAL_IS_WASM);
u64 offset = 0;
+ WasmType var_type = onyx_type_to_wasm_type(for_node->var->type);
+ assert(var_type == WASM_TYPE_INT32 || var_type == WASM_TYPE_INT64);
+ WasmInstructionType add_instr = var_type == WASM_TYPE_INT32 ? WI_I32_ADD : WI_I64_ADD;
+ WasmInstructionType ge_instr = var_type == WASM_TYPE_INT32 ? WI_I32_GE_S : WI_I64_GE_S;
+
if (it_is_local) {
compile_expression(mod, &code, for_node->start);
WID(WI_LOCAL_SET, it_idx);
compile_load_instruction(mod, &code, var->type, offset);
}
compile_expression(mod, &code, for_node->end);
- WI(WI_I32_GE_S);
+ WI(ge_instr);
WID(WI_COND_JUMP, 0x01);
forll (AstNode, stmt, for_node->stmt->body, next) {
if (it_is_local) {
WID(WI_LOCAL_GET, it_idx);
- if (for_node->step == NULL)
- WID(WI_I32_CONST, 0x01);
- else
- compile_expression(mod, &code, for_node->step);
- WI(WI_I32_ADD);
+ compile_expression(mod, &code, for_node->step);
+ WI(add_instr);
WID(WI_LOCAL_SET, it_idx);
} else {
offset = 0;
offset = 0;
compile_local_location(mod, &code, var, &offset);
compile_load_instruction(mod, &code, var->type, offset);
- if (for_node->step == NULL)
- WID(WI_I32_CONST, 0x01);
- else
- compile_expression(mod, &code, for_node->step);
- WI(WI_I32_ADD);
+ compile_expression(mod, &code, for_node->step);
+ WI(add_instr);
compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
}
if (expr->type->kind != Type_Kind_Array) {
compile_load_instruction(mod, &code, expr->type, offset);
- } else {
+ } else if (offset != 0) {
WID(WI_I32_CONST, offset);
WI(WI_I32_ADD);
}