diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fad3a4df0..d6ca524f5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2364,6 +2364,11 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint ast_node(be, BinaryExpr, node); + defer({ + node->viral_state_flags |= be->left->viral_state_flags; + node->viral_state_flags |= be->right->viral_state_flags; + }); + Token op = be->op; switch (op.kind) { case Token_CmpEq: @@ -2605,6 +2610,18 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint return; } } + break; + + case Token_CmpAnd: + case Token_CmpOr: + if (be->left->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) { + error(be->left, "Procedure calls that have an associated deferred procedure are not allowed within logical binary expressions"); + } + if (be->right->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) { + error(be->right, "Procedure calls that have an associated deferred procedure are not allowed within logical binary expressions"); + } + break; + } if (x->mode == Addressing_Constant && @@ -5440,6 +5457,8 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { Entity *e = sig_params[operand_index]; Type *t = e->type; Operand o = operands[operand_index]; + call->viral_state_flags |= o.expr->viral_state_flags; + if (e->kind == Entity_TypeName) { // GB_ASSERT(!variadic); if (o.mode == Addressing_Invalid) { @@ -5596,6 +5615,12 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { defer (gb_free(c->allocator, visited)); auto ordered_operands = array_make(c->allocator, param_count); defer (array_free(&ordered_operands)); + defer ({ + for_array(i, ordered_operands) { + Operand const &o = ordered_operands[i]; + call->viral_state_flags |= o.expr->viral_state_flags; + } + }); for_array(i, ce->args) { Ast *arg = ce->args[i]; @@ -6668,6 +6693,14 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *t return builtin_procs[id].kind; } + Entity *e = entity_of_ident(operand->expr); + + if (e != nullptr && e->kind == Entity_Procedure) { + if (e->Procedure.deferred_procedure.entity != nullptr) { + call->viral_state_flags |= ViralStateFlag_ContainsDeferredProcedure; + } + } + Type *proc_type = base_type(operand->type); if (operand->mode != Addressing_ProcGroup) { bool valid_type = (proc_type != nullptr) && is_type_proc(proc_type); @@ -7097,6 +7130,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(te, TernaryExpr, node); Operand cond = {Addressing_Invalid}; check_expr(c, &cond, te->cond); + node->viral_state_flags |= te->cond->viral_state_flags; + if (cond.mode != Addressing_Invalid && !is_type_boolean(cond.type)) { error(te->cond, "Non-boolean condition in if expression"); } @@ -7104,9 +7139,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; check_expr_or_type(c, &x, te->x, type_hint); + node->viral_state_flags |= te->x->viral_state_flags; if (te->y != nullptr) { check_expr_or_type(c, &y, te->y, type_hint); + node->viral_state_flags |= te->y->viral_state_flags; } else { error(node, "A ternary expression must have an else clause"); return kind; @@ -7761,6 +7798,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(pe, ParenExpr, node); kind = check_expr_base(c, o, pe->expr, type_hint); + node->viral_state_flags |= pe->expr->viral_state_flags; o->expr = node; case_end; @@ -7769,18 +7807,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type error(node, "Unknown tag expression, #%.*s", LIT(name)); if (te->expr) { kind = check_expr_base(c, o, te->expr, type_hint); + node->viral_state_flags |= te->expr->viral_state_flags; } o->expr = node; case_end; - case_ast_node(re, RunExpr, node); - // TODO(bill): Tag expressions - kind = check_expr_base(c, o, re->expr, type_hint); - o->expr = node; - case_end; - case_ast_node(ta, TypeAssertion, node); check_expr(c, o, ta->expr); + node->viral_state_flags |= ta->expr->viral_state_flags; + if (o->mode == Addressing_Invalid) { o->expr = node; return kind; @@ -7874,6 +7909,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } Type *type = o->type; check_expr_base(c, o, tc->expr, type); + node->viral_state_flags |= tc->expr->viral_state_flags; + if (o->mode != Addressing_Invalid) { switch (tc->token.kind) { case Token_transmute: @@ -7893,6 +7930,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(ac, AutoCast, node); check_expr_base(c, o, ac->expr, type_hint); + node->viral_state_flags |= ac->expr->viral_state_flags; + if (o->mode == Addressing_Invalid) { o->expr = node; return kind; @@ -7906,6 +7945,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(ue, UnaryExpr, node); check_expr_base(c, o, ue->expr, type_hint); + node->viral_state_flags |= ue->expr->viral_state_flags; + if (o->mode == Addressing_Invalid) { o->expr = node; return kind; @@ -7930,6 +7971,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(se, SelectorExpr, node); check_selector(c, o, node, type_hint); + node->viral_state_flags |= se->expr->viral_state_flags; case_end; @@ -8000,6 +8042,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(ie, IndexExpr, node); check_expr(c, o, ie->expr); + node->viral_state_flags |= ie->expr->viral_state_flags; if (o->mode == Addressing_Invalid) { o->expr = node; return kind; @@ -8061,12 +8104,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type i64 index = 0; bool ok = check_index_value(c, false, ie->index, max_count, &index); + node->viral_state_flags |= ie->index->viral_state_flags; case_end; case_ast_node(se, SliceExpr, node); check_expr(c, o, se->expr); + node->viral_state_flags |= se->expr->viral_state_flags; + if (o->mode == Addressing_Invalid) { o->mode = Addressing_Invalid; o->expr = node; @@ -8148,6 +8194,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (check_index_value(c, false, nodes[i], capacity, &j)) { index = j; } + + node->viral_state_flags |= nodes[i]->viral_state_flags; } else if (i == 0) { index = 0; } @@ -8173,6 +8221,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(de, DerefExpr, node); check_expr_or_type(c, o, de->expr); + node->viral_state_flags |= de->expr->viral_state_flags; + if (o->mode == Addressing_Invalid) { o->mode = Addressing_Invalid; o->expr = node; diff --git a/src/common.cpp b/src/common.cpp index 779554ecc..78782704c 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -443,7 +443,7 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) { ptr = arena_alloc(arena, size, alignment); break; case gbAllocation_Free: - GB_PANIC("gbAllocation_Free not supported"); + // GB_PANIC("gbAllocation_Free not supported"); break; case gbAllocation_Resize: GB_PANIC("gbAllocation_Resize: not supported"); diff --git a/src/ir.cpp b/src/ir.cpp index 6a9835636..19fa94485 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -91,6 +91,7 @@ enum irDeferExitKind { enum irDeferKind { irDefer_Node, irDefer_Instr, + irDefer_Proc, }; struct irDefer { @@ -102,6 +103,10 @@ struct irDefer { Ast *stmt; // NOTE(bill): 'instr' will be copied every time to create a new one irValue *instr; + struct { + irValue *deferred; + Array result_as_args; + } proc; }; }; @@ -1554,6 +1559,17 @@ irDefer ir_add_defer_instr(irProcedure *proc, isize scope_index, irValue *instr) return d; } +irDefer ir_add_defer_proc(irProcedure *proc, isize scope_index, irValue *deferred, Array const &result_as_args) { + irDefer d = {irDefer_Proc}; + d.scope_index = proc->scope_index; + d.block = proc->curr_block; + d.proc.deferred = deferred; + d.proc.result_as_args = result_as_args; + array_add(&proc->defer_stmts, d); + return d; +} + + irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) { @@ -3202,8 +3218,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar break; } - irValue *deferred_call = ir_de_emit(p, ir_emit_call(p, deferred, result_as_args)); - ir_add_defer_instr(p, p->scope_index, deferred_call); + ir_add_defer_proc(p, p->scope_index, deferred, result_as_args); } } @@ -3271,21 +3286,34 @@ void ir_open_scope(irProcedure *proc) { proc->scope_index++; } -void ir_close_scope(irProcedure *proc, irDeferExitKind kind, irBlock *block) { +void ir_close_scope(irProcedure *proc, irDeferExitKind kind, irBlock *block, bool pop_stack=true) { ir_emit_defer_stmts(proc, kind, block); GB_ASSERT(proc->scope_index > 0); // NOTE(bill): Remove `context`s made in that scope + + isize end_idx = proc->context_stack.count-1; + isize pop_count = 0; + for (;;) { - irContextData *end = array_end_ptr(&proc->context_stack); + if (end_idx < 0) { + break; + } + irContextData *end = &proc->context_stack[end_idx]; if (end == nullptr) { break; } if (end->scope_index != proc->scope_index) { break; } - array_pop(&proc->context_stack); + end_idx -= 1; + pop_count += 1; + } + if (pop_stack) { + for (isize i = 0; i < pop_count; i++) { + array_pop(&proc->context_stack); + } } @@ -6256,6 +6284,8 @@ void ir_build_defer_stmt(irProcedure *proc, irDefer d) { // NOTE(bill): Need to make a new copy irValue *instr = cast(irValue *)gb_alloc_copy(ir_allocator(), d.instr, gb_size_of(irValue)); ir_emit(proc, instr); + } else if (d.kind == irDefer_Proc) { + ir_emit_call(proc, d.proc.deferred, d.proc.result_as_args); } } @@ -6959,11 +6989,6 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { return nullptr; case_end; - case_ast_node(re, RunExpr, expr); - // TODO(bill): Run Expression - return ir_build_expr(proc, re->expr); - case_end; - case_ast_node(de, DerefExpr, expr); return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; @@ -9499,7 +9524,6 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { case_ast_node(is, IfStmt, node); ir_emit_comment(proc, str_lit("IfStmt")); ir_open_scope(proc); // Scope #1 - defer (ir_close_scope(proc, irDeferExit_Default, nullptr)); if (is->init != nullptr) { // TODO(bill): Should this have a separate block to begin with? @@ -9525,7 +9549,9 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { tl->is_block = true; } + // ir_open_scope(proc); ir_build_stmt(proc, is->body); + // ir_close_scope(proc, irDeferExit_Default, nullptr); ir_emit_jump(proc, done); @@ -9539,7 +9565,10 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { ir_emit_jump(proc, done); } + ir_start_block(proc, done); + ir_close_scope(proc, irDeferExit_Default, nullptr); + case_end; case_ast_node(fs, ForStmt, node); diff --git a/src/parser.cpp b/src/parser.cpp index be3991add..bf049f037 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -14,7 +14,6 @@ Token ast_token(Ast *node) { return node->CompoundLit.open; case Ast_TagExpr: return node->TagExpr.token; - case Ast_RunExpr: return node->RunExpr.token; case Ast_BadExpr: return node->BadExpr.begin; case Ast_UnaryExpr: return node->UnaryExpr.op; case Ast_BinaryExpr: return ast_token(node->BinaryExpr.left); @@ -155,9 +154,6 @@ Ast *clone_ast(Ast *node) { case Ast_TagExpr: n->TagExpr.expr = clone_ast(n->TagExpr.expr); break; - case Ast_RunExpr: - n->RunExpr.expr = clone_ast(n->RunExpr.expr); - break; case Ast_UnaryExpr: n->UnaryExpr.expr = clone_ast(n->UnaryExpr.expr); break; @@ -458,15 +454,6 @@ Ast *ast_tag_expr(AstFile *f, Token token, Token name, Ast *expr) { return result; } -Ast *ast_run_expr(AstFile *f, Token token, Token name, Ast *expr) { - Ast *result = alloc_ast_node(f, Ast_RunExpr); - result->RunExpr.token = token; - result->RunExpr.name = name; - result->RunExpr.expr = expr; - return result; -} - - Ast *ast_tag_stmt(AstFile *f, Token token, Token name, Ast *stmt) { Ast *result = alloc_ast_node(f, Ast_TagStmt); result->TagStmt.token = token; diff --git a/src/parser.hpp b/src/parser.hpp index 13c66d8d1..c8f1a683c 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -191,6 +191,11 @@ enum StmtStateFlag { StmtStateFlag_no_deferred = 1<<5, }; +enum ViralStateFlag { + ViralStateFlag_ContainsDeferredProcedure = 1<<0, +}; + + enum FieldFlag { FieldFlag_NONE = 0, FieldFlag_ellipsis = 1<<0, @@ -255,7 +260,6 @@ enum StmtAllowFlag { AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ AST_KIND(TagExpr, "tag expression", struct { Token token, name; Ast *expr; }) \ - AST_KIND(RunExpr, "run expression", struct { Token token, name; Ast *expr; }) \ AST_KIND(UnaryExpr, "unary expression", struct { Token op; Ast *expr; }) \ AST_KIND(BinaryExpr, "binary expression", struct { Token op; Ast *left, *right; } ) \ AST_KIND(ParenExpr, "parentheses expression", struct { Ast *expr; Token open, close; }) \ @@ -570,9 +574,10 @@ isize const ast_variant_sizes[] = { struct Ast { AstKind kind; u32 stmt_state_flags; + u32 viral_state_flags; + bool been_handled; AstFile * file; Scope * scope; - bool been_handled; TypeAndValue tav; union {