test.c
test
*.wasm
+*.html
at once would be overwhelming and unsatisfying. The current progress of each stage:
Stage 1 (MVP):
- [ ] Can declare procedures
- [ ] Procedures have params and returns of the following types:
+ [X] Can declare procedures
+ [X] Procedures have params and returns of the following types:
- i32, u32
- i64, u64
- f32, f64
- [ ] Procedures have locals of the same set of types
- [ ] Locals are declared in the following way
- local : (const) (type) (= initial value);
+ [X] Procedures have locals of the same set of types
+ [X] Locals are declared in the following way
+ local : (type) ((= or :) initial value);
- if const is specified, the value is unmodifiable
+ if : is used, the value is unmodifiable
if type is specified, that is assumed to be the correct type
if type is not specified, the type of initial value is used as the type
- [ ] Five basic math operations are legal:
+ [X] Five basic math operations are legal:
+ - * / %
- [ ] Math operations are sign aware and only operate on operands of the same type
- [ ] All casts are explicit using this syntax:
+ [X] Math operations are sign aware and only operate on operands of the same type
+ [X] All casts are explicit using this syntax:
X as T
casts X to type T
+ [ ] Numeric literals are parsed and minimum type detected
+ [ ] Comparison operators
+ [ ] Proper boolean type
[ ] Conditional branching works as expected
[ ] Curly braces are required for all bodies of blocks
[ ] Simple while loop is functioning as expected
[ ] break and continue semantics
+ [ ] Function calling works for the builtin types
+ [ ] Function return values are type checked
+
+ Stage 2:
+ [ ] Order of symbol declaration is irrelevant
+ Either:
+ make a graph of symbol dependencies and produce a schedule on the graph
+ that would allow for all symbols to be resolved
+
+ OR
+
+ Do as many passes on the parse tree as needed to resolve all symbols.
+ This could be slow but it would be easier than creating a graph
+ scheduling algorithm.
+
+ [ ] Devise and implement a simple set of implicit type casting rules.
+ - Numeric literals always type cast to whatever type is needed (very flexible).
+
+ [ ] Start work on evaluating compile time known values.
+ - An expression marked COMPTIME will be reduced to its value in the parse tree.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
return (c * d) as i32;
}
-export dummy :: proc () { }
+export main :: proc () {
+
+}
bh_allocator alloc = bh_heap_allocator();
+ // NOTE: 1st: Read file contents
bh_file_contents fc = bh_file_read_contents(alloc, &source_file);
bh_file_close(&source_file);
+ // NOTE: 2nd: Tokenize the contents
OnyxTokenizer tokenizer = onyx_tokenizer_create(alloc, &fc);
onyx_lex_tokens(&tokenizer);
bh_arr(OnyxToken) token_arr = tokenizer.tokens;
-#if 0
- bh_printf("There are %d tokens (Allocated space for %d tokens)\n", bh_arr_length(token_arr), bh_arr_capacity(token_arr));
-
- bh_arr_each(OnyxToken, it, token_arr) {
- onyx_token_null_toggle(*it);
- bh_printf("%s (%s:%l:%l)\n", onyx_get_token_type_name(it->type), it->pos.filename, it->pos.line, it->pos.column);
- onyx_token_null_toggle(*it);
- }
-#endif
-
+ // NOTE: Create the buffer for where compiler messages will be written
bh_arena msg_arena;
bh_arena_init(&msg_arena, alloc, 4096);
bh_allocator msg_alloc = bh_arena_allocator(&msg_arena);
OnyxMessages msgs;
onyx_message_create(msg_alloc, &msgs);
+ // NOTE: Create the arena where AST nodes will exist
+ // Prevents nodes from being scattered across memory due to fragmentation
bh_arena ast_arena;
bh_arena_init(&ast_arena, alloc, 16 * 1024 * 1024); // 16MB
bh_allocator ast_alloc = bh_arena_allocator(&ast_arena);
+ // NOTE: 3rd: parse the tokens to an AST
OnyxParser parser = onyx_parser_create(ast_alloc, &tokenizer, &msgs);
OnyxAstNode* program = onyx_parse(&parser);
onyx_message_print(&msgs);
goto main_exit;
} else {
- onyx_ast_print(program, 0);
+ // onyx_ast_print(program, 0);
bh_printf("\nNo errors.\n");
}
+ // NOTE: 4th: Generate a WASM module from the parse tree and
+ // write it to a file.
OnyxWasmModule wasm_mod = onyx_wasm_generate_module(alloc, program);
-#if 1
+ bh_file out_file;
+ bh_file_create(&out_file, "out.wasm");
+ onyx_wasm_module_write_to_file(&wasm_mod, out_file);
+ bh_file_close(&out_file);
+
+ onyx_wasm_module_free(&wasm_mod);
+main_exit: // NOTE: Cleanup, since C doesn't have defer
+ bh_arena_free(&msg_arena);
+ bh_arena_free(&ast_arena);
+ onyx_parser_free(&parser);
+ onyx_tokenizer_free(&tokenizer);
+ bh_file_contents_free(&fc);
+
+ return 0;
+}
+
+// NOTE: Old bits of code that may be useful again at some point.
+#if 0
+ bh_printf("There are %d tokens (Allocated space for %d tokens)\n", bh_arr_length(token_arr), bh_arr_capacity(token_arr));
+
+ bh_arr_each(OnyxToken, it, token_arr) {
+ onyx_token_null_toggle(*it);
+ bh_printf("%s (%s:%l:%l)\n", onyx_get_token_type_name(it->type), it->pos.filename, it->pos.line, it->pos.column);
+ onyx_token_null_toggle(*it);
+ }
+#endif
+
+#if 0
// NOTE: Ensure type table made correctly
bh_printf("Type map:\n");
}
#endif
-#if 1
+#if 0
// NOTE: Ensure the export table was built correctly
bh_printf("Function types:\n");
bh_printf("%s: %d %d\n", key, value.kind, value.idx);
bh_hash_each_end;
#endif
-
- bh_file out_file;
- bh_file_create(&out_file, "out.wasm");
- onyx_wasm_module_write_to_file(&wasm_mod, out_file);
- bh_file_close(&out_file);
-
- onyx_wasm_module_free(&wasm_mod);
-main_exit: // NOTE: Cleanup, since C doesn't have defer
- bh_arena_free(&msg_arena);
- bh_arena_free(&ast_arena);
- onyx_parser_free(&parser);
- onyx_tokenizer_free(&tokenizer);
- bh_file_contents_free(&fc);
-
- return 0;
-}
}
case ONYX_AST_NODE_KIND_RETURN: {
- if (node->next) {
- onyx_ast_print(node->next, indent + 1);
+ if (node->left) {
+ onyx_ast_print(node->left, indent + 1);
}
break;
count++;
}
-
- bh_printf("\nLocals for function: %b\n", fd->token->token, fd->token->length);
- bh_printf("\tI32 count: %d\n", wasm_func.locals.i32_count);
- bh_printf("\tI64 count: %d\n", wasm_func.locals.i64_count);
- bh_printf("\tF32 count: %d\n", wasm_func.locals.f32_count);
- bh_printf("\tF64 count: %d\n", wasm_func.locals.f64_count);
- bh_hash_each_start(i32, mod->local_map);
- bh_printf("\t%s -> %d\n", key, value);
- bh_hash_each_end;
-
// Generate code
process_function_body(mod, &wasm_func, fd);
- bh_printf("Code for function:\n");
- bh_arr_each(WasmInstruction, instr, wasm_func.code) {
- bh_printf("\t%s\t%xd\n", wi_string(instr->type), instr->data.i1);
- }
-
bh_arr_push(mod->funcs, wasm_func);
// NOTE: Clear the local map on exit of generating this function
return buff->length - prev_len;
}
+static i32 output_startsection(OnyxWasmModule* module, bh_buffer* buff) {
+ i32 prev_len = buff->length;
+
+ i32 start_idx = -1;
+ bh_hash_each_start(WasmExport, module->exports) {
+ if (value.kind == WASM_EXPORT_FUNCTION) {
+ if (strncmp("main", key, 5) == 0) {
+ start_idx = value.idx;
+ break;
+ }
+ }
+ } bh_hash_each_end;
+
+ if (start_idx != -1) {
+ bh_buffer_write_byte(buff, WASM_SECTION_ID_START);
+
+ i32 start_leb_len, section_leb_len;
+ u8* start_leb = uint_to_uleb128((u64) start_idx, &start_leb_len);
+ u8* section_leb = uint_to_uleb128((u64) start_leb_len, §ion_leb_len);
+ bh_buffer_append(buff, section_leb, section_leb_len);
+
+ start_leb = uint_to_uleb128((u64) start_idx, &start_leb_len);
+ bh_buffer_append(buff, start_leb, start_leb_len);
+ }
+
+ return buff->length - prev_len;
+}
+
static i32 output_locals(WasmFunc* func, bh_buffer* buff) {
i32 prev_len = buff->length;
output_typesection(module, &master_buffer);
output_funcsection(module, &master_buffer);
output_exportsection(module, &master_buffer);
+ output_startsection(module, &master_buffer);
output_codesection(module, &master_buffer);
-
bh_file_write(&file, master_buffer.data, master_buffer.length);
}