Iterator :: struct (Iter_Type: type_expr) {
- data: rawptr;
- next: (data: rawptr) -> (Iter_Type, bool);
- close: (data: rawptr) -> void = null_proc;
+ data: rawptr;
+ next: (data: rawptr) -> (Iter_Type, bool);
+ close: (data: rawptr) -> void = null_proc;
+ remove: (data: rawptr) -> void = null_proc;
}
};
}
+#match as_iterator (x: ^[..] $T) -> Iterator(^T) {
+ Context :: struct (T: type_expr) {
+ arr: ^[..] T;
+ current: u32;
+ }
+
+ c := make(Context(T));
+ c.arr = x;
+ c.current = 0;
+
+ next :: (use _: ^Context($T)) -> (^T, bool) {
+ if current < arr.count {
+ defer current += 1;
+ return ^arr.data[current], true;
+
+ } else {
+ return null, false;
+ }
+ }
+
+ close :: (data: rawptr) {
+ cfree(data);
+ }
+
+ remove :: (use _: ^Context($T)) {
+ //
+ // This is current - 1 because current will have already
+ // been incremented by the time this element calls #remove.
+ array :: package core.array
+ array.delete(arr, current - 1);
+ }
+
+ return .{
+ data = c,
+ next = #solidify next { T = T },
+ close = close,
+ remove = #solidify remove { T = T },
+ };
+}
+
#match as_iterator (r: range) -> Iterator(i32) {
Context :: struct {
r: range;
NODE(DirectiveTag) \
NODE(DirectiveInit) \
NODE(DirectiveLibrary) \
+ NODE(DirectiveRemove) \
\
NODE(Return) \
NODE(Jump) \
Ast_Kind_Directive_Tag,
Ast_Kind_Directive_Init,
Ast_Kind_Directive_Library,
+ Ast_Kind_Directive_Remove,
Ast_Kind_Call_Site,
Ast_Kind_Code_Block,
AstTyped* tag;
};
+struct AstDirectiveRemove {
+ AstNode_base;
+};
+
struct AstNote {
AstNode_base;
};
u32 instruction_index;
} PatchInfo;
+typedef struct ForRemoveInfo {
+ // These are WASM locals
+ u64 iterator_remove_func;
+ u64 iterator_data_ptr;
+
+ i32 remove_func_type_idx;
+} ForRemoveInfo;
+
typedef struct OnyxWasmModule {
bh_allocator allocator;
bh_arr(PatchInfo) stack_leave_patches;
+ bh_arr(ForRemoveInfo) for_remove_info;
+
// 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.
"TAG",
"INIT",
"LIBRARY",
+ "REMOVE",
"CALL SITE",
"CODE BLOCK",
// HACK HACK HACK
b32 expression_types_must_be_known = 0;
b32 all_checks_are_final = 1;
+b32 inside_for_iterator = 0;
#define STATEMENT_LEVEL 1
#define EXPRESSION_LEVEL 2
fornode->flags |= Ast_Flag_Has_Been_Checked;
fornode_expr_checked:
+ b32 old_inside_for_iterator = inside_for_iterator;
+ inside_for_iterator = 0;
+ iter_type = fornode->iter->type;
+ if (type_struct_constructed_from_poly_struct(iter_type, builtin_iterator_type)) {
+ inside_for_iterator = 1;
+ }
CHECK(block, fornode->stmt);
+ inside_for_iterator = old_inside_for_iterator;
return Check_Success;
}
return Check_Success;
}
+CheckStatus check_remove_directive(AstDirectiveRemove *remove) {
+ if (!inside_for_iterator) {
+ ERROR(remove->token->pos, "#remove is only allowed in the body of a for-loop over an iterator.");
+ }
+
+ return Check_Success;
+}
+
CheckStatus check_statement(AstNode** pstmt) {
AstNode* stmt = *pstmt;
case Ast_Kind_Switch: return check_switch((AstSwitch *) stmt);
case Ast_Kind_Block: return check_block((AstBlock *) stmt);
case Ast_Kind_Defer: return check_statement(&((AstDefer *) stmt)->stmt);
+ case Ast_Kind_Directive_Remove: return check_remove_directive((AstDirectiveRemove *) stmt);
case Ast_Kind_Call: {
CHECK(call, (AstCall **) pstmt);
(*pstmt)->flags |= Ast_Flag_Expr_Ignored;
case Ast_Kind_Directive_Defined: return sizeof(AstDirectiveDefined);
case Ast_Kind_Do_Block: return sizeof(AstDoBlock);
case Ast_Kind_Constraint: return sizeof(AstConstraint);
+ case Ast_Kind_Directive_Remove: return sizeof(AstDirectiveRemove);
case Ast_Kind_Count: return 0;
}
break;
}
+ if (parse_possible_directive(parser, "remove")) {
+ // :LinearTokenDependent
+ AstDirectiveRemove *remove = make_node(AstDirectiveRemove, Ast_Kind_Directive_Remove);
+ remove->token = parser->curr - 2;
+ retval = (AstNode *) remove;
+ break;
+ }
+
if (next_tokens_are(parser, 2, '#', Token_Type_Symbol)) {
retval = (AstNode *) parse_factor(parser);
break;
case Ast_Kind_Defer: SYMRES(statement, &((AstDefer *) *stmt)->stmt, NULL); break;
case Ast_Kind_Switch_Case: SYMRES(case, (AstSwitchCase *) *stmt); break;
case Ast_Kind_Jump: break;
+ case Ast_Kind_Directive_Remove: break;
case Ast_Kind_Local:
// if (remove) *remove = 1;
EMIT_FUNC(defer_code, WasmInstruction* deferred_code, u32 code_count);
EMIT_FUNC(deferred_stmt, DeferredStmt deferred_stmt);
EMIT_FUNC_NO_ARGS(deferred_stmts);
+EMIT_FUNC(remove_directive, AstDirectiveRemove* remove);
EMIT_FUNC(binop, AstBinaryOp* binop);
EMIT_FUNC(unaryop, AstUnaryOp* unop);
EMIT_FUNC(call, AstCall* call);
case Ast_Kind_Defer: emit_defer(mod, &code, (AstDefer *) stmt); break;
case Ast_Kind_Local: emit_local_allocation(mod, &code, (AstTyped *) stmt); break;
+ case Ast_Kind_Directive_Remove: emit_remove_directive(mod, &code, (AstDirectiveRemove *) stmt); break;
case Ast_Kind_Directive_Insert: break;
default: emit_expression(mod, &code, (AstTyped *) stmt); break;
bh_arr(WasmInstruction) code = *pcode;
// Allocate temporaries for iterator contents
- u64 iterator_data_ptr = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR);
- u64 iterator_next_func = local_raw_allocate(mod->local_alloc, WASM_TYPE_FUNC);
- u64 iterator_close_func = local_raw_allocate(mod->local_alloc, WASM_TYPE_FUNC);
- u64 iterator_done_bool = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+ u64 iterator_data_ptr = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR);
+ u64 iterator_next_func = local_raw_allocate(mod->local_alloc, WASM_TYPE_FUNC);
+ u64 iterator_close_func = local_raw_allocate(mod->local_alloc, WASM_TYPE_FUNC);
+ u64 iterator_remove_func = local_raw_allocate(mod->local_alloc, WASM_TYPE_FUNC);
+ u64 iterator_done_bool = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+ WIL(WI_LOCAL_SET, iterator_remove_func);
WIL(WI_LOCAL_SET, iterator_close_func);
WIL(WI_LOCAL_SET, iterator_next_func);
WIL(WI_LOCAL_SET, iterator_data_ptr);
+
+ {
+ //
+ // This pushes an entry onto the stack of for loops that have
+ // are iterator that can have a '#remove' directive in them.
+ ForRemoveInfo remove_info;
+ remove_info.iterator_data_ptr = iterator_data_ptr;
+ remove_info.iterator_remove_func = iterator_remove_func;
+
+ TypeWithOffset remove_func_type;
+ type_linear_member_lookup(for_node->iter->type, 3, &remove_func_type);
+ remove_info.remove_func_type_idx = generate_type_idx(mod, remove_func_type.type);
+
+ bh_arr_push(mod->for_remove_info, remove_info);
+ }
+
AstLocal* var = for_node->var;
b32 it_is_local = (b32) ((iter_local & LOCAL_IS_WASM) != 0);
u64 offset = 0;
emit_deferred_stmts(mod, &code);
emit_leave_structured_block(mod, &code);
+ bh_arr_pop(mod->for_remove_info);
+
local_raw_free(mod->local_alloc, WASM_TYPE_PTR);
local_raw_free(mod->local_alloc, WASM_TYPE_FUNC);
local_raw_free(mod->local_alloc, WASM_TYPE_FUNC);
}
}
+EMIT_FUNC(remove_directive, AstDirectiveRemove* remove) {
+ assert(bh_arr_length(mod->for_remove_info) > 0);
+
+ bh_arr(WasmInstruction) code = *pcode;
+
+ ForRemoveInfo remove_info = bh_arr_last(mod->for_remove_info);
+
+ WIL(WI_LOCAL_GET, remove_info.iterator_remove_func);
+ WIL(WI_I32_CONST, mod->null_proc_func_idx);
+ WI(WI_I32_NE);
+ WID(WI_IF_START, 0x40);
+ WIL(WI_LOCAL_GET, remove_info.iterator_data_ptr);
+ WIL(WI_LOCAL_GET, remove_info.iterator_remove_func);
+ WIL(WI_CALL_INDIRECT, remove_info.remove_func_type_idx);
+ WI(WI_IF_END);
+
+ *pcode = code;
+}
+
// NOTE: These need to be in the same order as
// the OnyxBinaryOp enum
static const WasmInstructionType binop_map[][4] = {