[X] Procedures as arguments
- [ ] Deferred statements
+ [X] Deferred statements
[ ] Pointer math
[ ] Hex literals
+ [ ] #file_contents
+
+ [ ] #initialize structs
+
[ ] Start work on evaluating compile time known values.
- An expression marked COMPTIME will be reduced to its value in the parse tree.
typedef struct AstIf AstIf;
typedef struct AstFor AstFor;
typedef struct AstWhile AstWhile;
+typedef struct AstDefer AstDefer;
typedef struct AstType AstType;
typedef struct AstBasicType AstBasicType;
Ast_Kind_While,
Ast_Kind_Break,
Ast_Kind_Continue,
+ Ast_Kind_Defer,
Ast_Kind_Count
} AstKind;
// Structure Nodes
struct AstBlock { AstNode_base; AstNode *body; Scope *scope; };
struct AstWhile { AstNode_base; AstTyped *cond; AstNode *stmt; };
+struct AstDefer { AstNode_base; AstNode *stmt; };
struct AstFor {
AstNode_base;
Token_Type_Keyword_Continue,
Token_Type_Keyword_Sizeof,
Token_Type_Keyword_Alignof,
+ Token_Type_Keyword_Defer,
Token_Type_Right_Arrow,
Token_Type_Left_Arrow,
// NOTE: Used in type checking phase
Type* expected_return_type;
+
+ u32 defer_allowed : 1;
} SemState;
extern SemState semstate;
ptr data;
} WasmDatum;
+typedef struct DeferredStmt {
+ u64 depth;
+ AstNode *stmt;
+} DeferredStmt;
+
typedef struct OnyxWasmModule {
bh_allocator allocator;
// NOTE: Mapping ptrs to elements
bh_imap elem_map;
+ bh_arr(DeferredStmt) deferred_stmts;
+
// NOTE: Used internally as a map from strings that represent function types,
// 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 )
// to the function type index if it has been created.
# strings in YAML. When using single quoted strings, only single quotes
# need to be escaped: this is done by using two single quotes next to each
# other.
- - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|cast|sizeof|alignof)\b'
+ - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|cast|sizeof|alignof|defer)\b'
scope: keyword.control.onyx
- match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr)\b'
syn keyword onyxKeyword package struct proc use global
syn keyword onyxKeyword if elseif else
syn keyword onyxKeyword for while do
-syn keyword onyxKeyword break continue return
+syn keyword onyxKeyword break continue return defer
syn keyword onyxKeyword as cast sizeof alignof
syn keyword onyxType bool void
syn keyword onyxType f64
syn keyword onyxType rawptr
-syn keyword onyxConstant true false
+syn keyword onyxConstant true false null
syn keyword onyxCommentStart contained TODO NOTE BUG HACK
use "progs/intrinsics"
-use package printing { print }
-
use package intrinsics {
memory_size, memory_grow
}
alloc_proc :: #type proc (rawptr, AllocAction, u32, u32, rawptr) -> rawptr;
-alloc :: proc (a: ^Allocator, size: u32) -> rawptr {
- return a.func(a.data, AllocAction.Alloc, size, 16, null);
+alloc :: proc (use a: ^Allocator, size: u32) -> rawptr {
+ return func(data, AllocAction.Alloc, size, 16, null);
}
-free :: proc (a: ^Allocator, ptr: rawptr) {
- a.func(a.data, AllocAction.Free, 0, 0, ptr);
+free :: proc (use a: ^Allocator, ptr: rawptr) {
+ func(data, AllocAction.Free, 0, 0, ptr);
}
heap_state.next_alloc = __heap_start;
heap_state.remaining_space = (memory_size() << 16) - cast(u32) __heap_start;
- heap_allocator.data = null;
+ heap_allocator.data = ^heap_state;
heap_allocator.func = heap_alloc_proc;
}
heap_free :: proc (ptr: rawptr) {
hb_ptr := cast(^heap_block) (cast(u32) ptr - sizeof heap_block);
+
+ // DEBUGGING: Fills freed memory with 0's
+ for i: 0, hb_ptr.size {
+ (cast(^u8) ptr)[i] = cast(u8) 0;
+ }
+
hb_ptr.next = heap_state.free_list;
heap_state.free_list = hb_ptr;
}
use package memory
use package printing
+deferred_example :: proc -> i32 {
+ arr := cast([] i32) malloc(sizeof [8] i32);
+ defer if cast(rawptr) arr != null mfree(arr);
+
+ for i: 0, 8 arr[i] = i * i;
+ for i: 0, 8 print(arr[i]);
+
+ return arr[1] + arr[7];
+}
+
proc #export "main" {
- asdf :: "staring asdfkjasd asdflkjasdflkajsdflk";
- heap_init();
+ asdf :: "staring asdfkjasd asdflkjasdflkajsdflk";
+ heap_init();
+
+ print(deferred_example());
- first := cast([] i32) malloc(sizeof [4] i32);
- for i: 0, 4 first[i] = i * 2;
+ first := cast([] i32) malloc(sizeof [4] i32);
+ for i: 0, 4 first[i] = i * 2;
- second := cast([] f32) malloc(sizeof [24] f32);
- for i: 0, 24 second[i] = cast(f32) i;
+ second := cast([] f32) malloc(sizeof [24] f32);
+ for i: 0, 24 second[i] = cast(f32) i;
- print(cast(u32) first);
- print(cast(u32) second);
+ print(cast(u32) first);
+ print(cast(u32) second);
- for i: 0, 4 print(first[i]);
- for i: 0, 24 print(second[i]);
+ for i: 0, 4 print(first[i]);
+ for i: 0, 24 print(second[i]);
- mfree(first);
+ mfree(first);
- third := cast(^i32) malloc(sizeof i32);
+ third := cast(^i32) malloc(sizeof i32);
- print(cast(u32) third);
- *third = 1234;
- print(*third);
+ print(cast(u32) third);
+ *third = 1234;
+ print(*third);
- mfree(second);
+ mfree(second);
- fourth := cast([] i32) malloc(sizeof [128]i32);
- print(cast(u32) fourth);
+ fourth := cast([] i32) malloc(sizeof [128]i32);
+ print(cast(u32) fourth);
- fifth := cast(^i32) malloc(sizeof i32);
- print(cast(u32) fifth);
+ fifth := cast(^i32) malloc(sizeof i32);
+ print(cast(u32) fifth);
}
\ No newline at end of file
case Ast_Kind_While: return check_while((AstWhile *) stmt);
case Ast_Kind_For: return check_for((AstFor *) stmt);
case Ast_Kind_Block: return check_block((AstBlock *) stmt);
+ case Ast_Kind_Defer: {
+ if (!semstate.defer_allowed) {
+ onyx_message_add(Msg_Type_Literal,
+ stmt->token->pos,
+ "deferred statement not allowed in deferred block");
+ return 1;
+ }
+
+ semstate.defer_allowed = 0;
+ b32 state = check_statement(((AstDefer *) stmt)->stmt);
+ semstate.defer_allowed = 1;
+
+ return state;
+ }
+
case Ast_Kind_Binary_Op:
stmt->flags |= Ast_Flag_Expr_Ignored;
return check_binaryop((AstBinaryOp *) stmt, 1);
"continue",
"sizeof",
"alignof",
+ "defer",
"->",
"<-",
LITERAL_TOKEN("continue", 1, Token_Type_Keyword_Continue);
LITERAL_TOKEN("sizeof", 1, Token_Type_Keyword_Sizeof);
LITERAL_TOKEN("alignof", 1, Token_Type_Keyword_Alignof);
+ LITERAL_TOKEN("defer", 1, Token_Type_Keyword_Defer);
LITERAL_TOKEN("true", 1, Token_Type_Literal_True);
LITERAL_TOKEN("false", 1, Token_Type_Literal_False);
LITERAL_TOKEN("->", 0, Token_Type_Right_Arrow);
break;
}
+ case Token_Type_Keyword_Defer: {
+ needs_semicolon = 0;
+
+ AstDefer* defer = make_node(AstDefer, Ast_Kind_Defer);
+ defer->token = expect_token(parser, Token_Type_Keyword_Defer);
+ defer->stmt = parse_statement(parser);
+
+ retval = (AstNode *) defer;
+ break;
+ }
+
default:
break;
}
.global_scope = NULL,
.curr_scope = NULL,
+
+ .defer_allowed = 1,
};
}
case Ast_Kind_Call: symres_call((AstCall *) stmt); return 0;
case Ast_Kind_Argument: symres_expression((AstTyped **) &((AstArgument *)stmt)->value); return 0;
case Ast_Kind_Block: symres_block((AstBlock *) stmt); return 0;
+ case Ast_Kind_Defer: symres_statement(((AstDefer *) stmt)->stmt); return 0;
case Ast_Kind_Break: return 0;
case Ast_Kind_Continue: return 0;
"WHILE",
"BREAK",
"CONTINUE",
+ "DEFER",
"AST_NODE_KIND_COUNT",
};
COMPILE_FUNC(if, AstIf* if_node);
COMPILE_FUNC(while, AstWhile* while_node);
COMPILE_FUNC(for, AstFor* for_node);
+COMPILE_FUNC(defer, AstDefer* defer);
+COMPILE_FUNC(deferred_stmts, AstNode* node);
COMPILE_FUNC(binop, AstBinaryOp* binop);
COMPILE_FUNC(unaryop, AstUnaryOp* unop);
COMPILE_FUNC(call, AstCall* call);
compile_statement(mod, &code, stmt);
}
+ compile_deferred_stmts(mod, &code, (AstNode *) fd);
+
WI(WI_BLOCK_END);
*pcode = code;
compile_statement(mod, &code, stmt);
}
+ compile_deferred_stmts(mod, &code, (AstNode *) block);
+
WI(WI_BLOCK_END);
bh_arr_pop(mod->structured_jump_target);
case Ast_Kind_Break: compile_structured_jump(mod, &code, ((AstBreak *) stmt)->count); break;
case Ast_Kind_Continue: compile_structured_jump(mod, &code, -((AstContinue *) stmt)->count); break;
case Ast_Kind_Block: compile_block(mod, &code, (AstBlock *) stmt); break;
+ case Ast_Kind_Defer: compile_defer(mod, &code, (AstDefer *) stmt); break;
default: compile_expression(mod, &code, (AstTyped *) stmt); break;
}
}
}
+ compile_deferred_stmts(mod, &code, (AstNode *) if_node);
+
bh_arr_pop(mod->structured_jump_target);
WI(WI_IF_END);
bh_arr_pop(mod->structured_jump_target);
bh_arr_pop(mod->structured_jump_target);
+ compile_deferred_stmts(mod, &code, (AstNode *) while_node);
+
WID(WI_JUMP, 0x00);
WI(WI_LOOP_END);
WI(WI_I32_ADD);
WID(WI_LOCAL_SET, it_idx);
+ compile_deferred_stmts(mod, &code, (AstNode *) for_node);
+
bh_arr_pop(mod->structured_jump_target);
bh_arr_pop(mod->structured_jump_target);
*pcode = code;
}
+COMPILE_FUNC(defer, AstDefer* defer) {
+ bh_arr_push(mod->deferred_stmts, ((DeferredStmt) {
+ .depth = bh_arr_length(mod->structured_jump_target),
+ .stmt = defer->stmt,
+ }));
+}
+
+COMPILE_FUNC(deferred_stmts, AstNode* node) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ u64 depth = bh_arr_length(mod->structured_jump_target);
+
+ while (bh_arr_last(mod->deferred_stmts).depth == depth) {
+ compile_statement(mod, &code, bh_arr_last(mod->deferred_stmts).stmt);
+ bh_arr_pop(mod->deferred_stmts);
+ }
+
+ *pcode = code;
+}
+
// NOTE: These need to be in the same order as
// the OnyxBinaryOp enum
static const WasmInstructionType binop_map[][4] = {
compile_expression(mod, &code, ret->expr);
}
+ compile_deferred_stmts(mod, &code, (AstNode *) ret);
+
+ if (bh_arr_length(mod->deferred_stmts) != 0) {
+ i32 i = bh_arr_length(mod->deferred_stmts) - 1;
+ while (i >= 0) {
+ compile_statement(mod, &code, mod->deferred_stmts[i].stmt);
+ i--;
+ }
+ }
+
WI(WI_RETURN);
*pcode = code;
bh_imap_init(&module.local_map, global_heap_allocator, 16);
bh_imap_init(&module.elem_map, global_heap_allocator, 16);
+ bh_arr_new(global_heap_allocator, module.deferred_stmts, 4);
+
return module;
}