mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-18 03:42:23 -07:00
Block Expressions and give
This commit is contained in:
+21
-1
@@ -32,6 +32,16 @@ typedef struct TypeAndValue {
|
||||
ExactValue value;
|
||||
} TypeAndValue;
|
||||
|
||||
bool is_operand_value(Operand o) {
|
||||
switch (o.mode) {
|
||||
case Addressing_Value:
|
||||
case Addressing_Variable:
|
||||
case Addressing_Constant:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct DeclInfo {
|
||||
@@ -92,6 +102,14 @@ typedef enum ExprKind {
|
||||
Expr_Stmt,
|
||||
} ExprKind;
|
||||
|
||||
// Statements and Declarations
|
||||
typedef enum StmtFlag {
|
||||
Stmt_BreakAllowed = 1<<0,
|
||||
Stmt_ContinueAllowed = 1<<1,
|
||||
Stmt_FallthroughAllowed = 1<<2,
|
||||
Stmt_GiveAllowed = 1<<3,
|
||||
} StmtFlag;
|
||||
|
||||
typedef enum BuiltinProcId {
|
||||
BuiltinProc_Invalid,
|
||||
|
||||
@@ -357,9 +375,11 @@ void add_scope(Checker *c, AstNode *node, Scope *scope) {
|
||||
|
||||
void check_open_scope(Checker *c, AstNode *node) {
|
||||
GB_ASSERT(node != NULL);
|
||||
node = unparen_expr(node);
|
||||
GB_ASSERT(node->kind == AstNode_Invalid ||
|
||||
is_ast_node_stmt(node) ||
|
||||
is_ast_node_type(node));
|
||||
is_ast_node_type(node) ||
|
||||
node->kind == AstNode_BlockExpr);
|
||||
Scope *scope = make_scope(c->context.scope, c->allocator);
|
||||
add_scope(c, node, scope);
|
||||
if (node->kind == AstNode_ProcType) {
|
||||
|
||||
+13
-1
@@ -92,7 +92,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
||||
}
|
||||
|
||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||
error(lhs[0]->token, "Assignment count mismatch `%td` := `%td`", lhs_count, rhs_count);
|
||||
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
}
|
||||
|
||||
if (lhs[0]->kind == Entity_Variable &&
|
||||
lhs[0]->Variable.is_let) {
|
||||
if (lhs_count != rhs_count) {
|
||||
error(lhs[0]->token, "`let` variables must be initialized, `%td` = `%td`", lhs_count, rhs_count);
|
||||
}
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
@@ -350,6 +357,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
|
||||
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
|
||||
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
|
||||
proc_type->Proc.calling_convention = ProcCC_Odin;
|
||||
}
|
||||
|
||||
d->scope = c->context.scope;
|
||||
|
||||
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
||||
|
||||
@@ -14,6 +14,10 @@ void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type
|
||||
void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type);
|
||||
void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body);
|
||||
void update_expr_type (Checker *c, AstNode *e, Type *type, bool final);
|
||||
bool check_is_terminating (AstNode *node);
|
||||
bool check_has_break (AstNode *stmt, bool implicit);
|
||||
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
||||
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
|
||||
|
||||
|
||||
gb_inline Type *check_type(Checker *c, AstNode *expression) {
|
||||
@@ -3652,6 +3656,42 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool check_is_giving(AstNode *node, AstNode **give_expr);
|
||||
|
||||
bool check_giving_list(AstNodeArray stmts, AstNode **give_expr) {
|
||||
// Iterate backwards
|
||||
for (isize n = stmts.count-1; n >= 0; n--) {
|
||||
AstNode *stmt = stmts.e[n];
|
||||
if (stmt->kind != AstNode_EmptyStmt) {
|
||||
return check_is_giving(stmt, give_expr);
|
||||
}
|
||||
}
|
||||
|
||||
if (give_expr) *give_expr = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_is_giving(AstNode *node, AstNode **give_expr) {
|
||||
switch (node->kind) {
|
||||
case_ast_node(es, ExprStmt, node);
|
||||
return check_is_giving(es->expr, give_expr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ye, GiveExpr, node);
|
||||
if (give_expr) *give_expr = node;
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(be, BlockExpr, node);
|
||||
return check_giving_list(be->stmts, give_expr);
|
||||
case_end;
|
||||
}
|
||||
|
||||
if (give_expr) *give_expr = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
|
||||
ExprKind kind = Expr_Stmt;
|
||||
|
||||
@@ -3700,7 +3740,105 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
|
||||
o->mode = Addressing_Value;
|
||||
o->type = proc_type;
|
||||
case_end;
|
||||
|
||||
case_ast_node(be, BlockExpr, node);
|
||||
if (c->proc_stack.count == 0) {
|
||||
error_node(node, "A block expression is only allowed withing a procedure");
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (isize i = be->stmts.count-1; i >= 0; i--) {
|
||||
if (be->stmts.e[i]->kind != AstNode_EmptyStmt) {
|
||||
break;
|
||||
}
|
||||
be->stmts.count--;
|
||||
}
|
||||
|
||||
check_open_scope(c, node);
|
||||
check_stmt_list(c, be->stmts, Stmt_GiveAllowed);
|
||||
check_close_scope(c);
|
||||
|
||||
|
||||
if (be->stmts.count == 0) {
|
||||
error_node(node, "Empty block expression");
|
||||
goto error;
|
||||
}
|
||||
AstNode *give_node = NULL;
|
||||
if (!check_is_giving(node, &give_node) || give_node == NULL) {
|
||||
error_node(node, "Missing give statement at");
|
||||
goto error;
|
||||
}
|
||||
|
||||
GB_ASSERT(give_node != NULL && give_node->kind == AstNode_GiveExpr);
|
||||
be->give_node = give_node;
|
||||
|
||||
o->type = type_of_expr(&c->info, give_node);
|
||||
o->mode = Addressing_Value;
|
||||
case_end;
|
||||
|
||||
case_ast_node(ye, GiveExpr, node);
|
||||
if (c->proc_stack.count == 0) {
|
||||
error_node(node, "A give expression is only allowed withing a procedure");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ye->results.count == 0) {
|
||||
error_node(node, "No give values");
|
||||
goto error;
|
||||
}
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
|
||||
Array(Operand) operands;
|
||||
array_init_reserve(&operands, c->tmp_allocator, 2*ye->results.count);
|
||||
|
||||
for_array(i, ye->results) {
|
||||
AstNode *rhs = ye->results.e[i];
|
||||
Operand o = {0};
|
||||
check_multi_expr(c, &o, rhs);
|
||||
if (!is_operand_value(o)) {
|
||||
error_node(rhs, "Expected a value for a `give`");
|
||||
continue;
|
||||
}
|
||||
if (o.type->kind != Type_Tuple) {
|
||||
array_add(&operands, o);
|
||||
} else {
|
||||
TypeTuple *tuple = &o.type->Tuple;
|
||||
for (isize j = 0; j < tuple->variable_count; j++) {
|
||||
o.type = tuple->variables[j]->type;
|
||||
array_add(&operands, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Type *give_type = NULL;
|
||||
|
||||
if (operands.count == 0) {
|
||||
error_node(node, "`give` has no type");
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
goto error;
|
||||
} else if (operands.count == 1) {
|
||||
give_type = default_type(operands.e[0].type);
|
||||
} else {
|
||||
Type *tuple = make_type_tuple(c->allocator);
|
||||
|
||||
Entity **variables = gb_alloc_array(c->allocator, Entity *, operands.count);
|
||||
isize variable_index = 0;
|
||||
for_array(i, operands) {
|
||||
Type *type = default_type(operands.e[i].type);
|
||||
variables[variable_index++] = make_entity_param(c->allocator, NULL, empty_token, type, false);
|
||||
}
|
||||
tuple->Tuple.variables = variables;
|
||||
tuple->Tuple.variable_count = operands.count;
|
||||
|
||||
give_type = tuple;
|
||||
}
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
|
||||
o->type = give_type;
|
||||
o->mode = Addressing_Value;
|
||||
case_end;
|
||||
|
||||
case_ast_node(cl, CompoundLit, node);
|
||||
|
||||
+10
-14
@@ -1,16 +1,3 @@
|
||||
bool check_is_terminating(AstNode *node);
|
||||
bool check_has_break (AstNode *stmt, bool implicit);
|
||||
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
||||
|
||||
|
||||
// Statements and Declarations
|
||||
typedef enum StmtFlag {
|
||||
Stmt_BreakAllowed = GB_BIT(0),
|
||||
Stmt_ContinueAllowed = GB_BIT(1),
|
||||
Stmt_FallthroughAllowed = GB_BIT(2), // TODO(bill): fallthrough
|
||||
} StmtFlag;
|
||||
|
||||
|
||||
void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
if (stmts.count == 0) {
|
||||
return;
|
||||
@@ -40,6 +27,10 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
|
||||
if (n->kind == AstNode_ReturnStmt && i+1 < max) {
|
||||
error_node(n, "Statements after this `return` are never executed");
|
||||
} else if (n->kind == AstNode_ExprStmt && i+1 < max) {
|
||||
if (n->ExprStmt.expr->kind == AstNode_GiveExpr) {
|
||||
error_node(n, "A `give` must be the last statement in a block");
|
||||
}
|
||||
}
|
||||
|
||||
check_stmt(c, n, new_flags);
|
||||
@@ -48,7 +39,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
}
|
||||
|
||||
bool check_is_terminating_list(AstNodeArray stmts) {
|
||||
|
||||
// Iterate backwards
|
||||
for (isize n = stmts.count-1; n >= 0; n--) {
|
||||
AstNode *stmt = stmts.e[n];
|
||||
@@ -355,6 +345,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
if (operand.expr->kind == AstNode_CallExpr) {
|
||||
return;
|
||||
}
|
||||
if (operand.expr->kind == AstNode_GiveExpr) {
|
||||
if ((flags&Stmt_GiveAllowed) != 0) {
|
||||
return;
|
||||
}
|
||||
error_node(node, "Illegal use of `give`");
|
||||
}
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error_node(node, "Expression is not used: `%s`", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
|
||||
@@ -775,6 +775,65 @@ Type *default_type(Type *type) {
|
||||
return type;
|
||||
}
|
||||
|
||||
// NOTE(bill): Valid Compile time execution #run type
|
||||
bool is_type_cte_safe(Type *type) {
|
||||
type = default_type(base_type(type));
|
||||
switch (type->kind) {
|
||||
case Type_Basic:
|
||||
switch (type->Basic.kind) {
|
||||
case Basic_rawptr:
|
||||
case Basic_any:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_Pointer:
|
||||
return false;
|
||||
|
||||
case Type_Array:
|
||||
return is_type_cte_safe(type->Array.elem);
|
||||
|
||||
case Type_Vector: // NOTE(bill): This should always to be true but this is for sanity reasons
|
||||
return is_type_cte_safe(type->Vector.elem);
|
||||
|
||||
case Type_Slice:
|
||||
return false;
|
||||
|
||||
case Type_Maybe:
|
||||
return is_type_cte_safe(type->Maybe.elem);
|
||||
|
||||
case Type_Record: {
|
||||
if (type->Record.kind != TypeRecord_Struct) {
|
||||
return false;
|
||||
}
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *v = type->Record.fields[i];
|
||||
if (!is_type_cte_safe(v->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case Type_Tuple: {
|
||||
for (isize i = 0; i < type->Tuple.variable_count; i++) {
|
||||
Entity *v = type->Tuple.variables[i];
|
||||
if (!is_type_cte_safe(v->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case Type_Proc:
|
||||
// TODO(bill): How should I handle procedures in the CTE stage?
|
||||
// return type->Proc.calling_convention == ProcCC_Odin;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+68
-3
@@ -144,6 +144,15 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
|
||||
bool triple_indexed; \
|
||||
}) \
|
||||
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
|
||||
AST_NODE_KIND(BlockExpr, "block expr", struct { \
|
||||
AstNodeArray stmts; \
|
||||
Token open, close; \
|
||||
AstNode *give_node; \
|
||||
}) \
|
||||
AST_NODE_KIND(GiveExpr, "give expression", struct { \
|
||||
Token token; \
|
||||
AstNodeArray results; \
|
||||
}) \
|
||||
AST_NODE_KIND(_ExprEnd, "", i32) \
|
||||
AST_NODE_KIND(_StmtBegin, "", i32) \
|
||||
AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
|
||||
@@ -432,6 +441,10 @@ Token ast_node_token(AstNode *node) {
|
||||
return node->DerefExpr.op;
|
||||
case AstNode_DemaybeExpr:
|
||||
return node->DemaybeExpr.op;
|
||||
case AstNode_BlockExpr:
|
||||
return node->BlockExpr.open;
|
||||
case AstNode_GiveExpr:
|
||||
return node->GiveExpr.token;
|
||||
case AstNode_BadStmt:
|
||||
return node->BadStmt.begin;
|
||||
case AstNode_EmptyStmt:
|
||||
@@ -729,6 +742,24 @@ AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *make_block_expr(AstFile *f, AstNodeArray stmts, Token open, Token close) {
|
||||
AstNode *result = make_node(f, AstNode_BlockExpr);
|
||||
result->BlockExpr.stmts = stmts;
|
||||
result->BlockExpr.open = open;
|
||||
result->BlockExpr.close = close;
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_give_expr(AstFile *f, Token token, AstNodeArray results) {
|
||||
AstNode *result = make_node(f, AstNode_GiveExpr);
|
||||
result->GiveExpr.token = token;
|
||||
result->GiveExpr.results = results;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AstNode *make_bad_stmt(AstFile *f, Token begin, Token end) {
|
||||
AstNode *result = make_node(f, AstNode_BadStmt);
|
||||
result->BadStmt.begin = begin;
|
||||
@@ -1508,6 +1539,9 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeArray parse_lhs_expr_list(AstFile *f);
|
||||
AstNodeArray parse_rhs_expr_list(AstFile *f);
|
||||
|
||||
AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
AstNode *operand = NULL; // Operand
|
||||
switch (f->curr_token.kind) {
|
||||
@@ -1623,6 +1657,17 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
return type;
|
||||
}
|
||||
|
||||
case Token_OpenBrace: {
|
||||
AstNodeArray stmts = {0};
|
||||
Token open, close;
|
||||
open = expect_token(f, Token_OpenBrace);
|
||||
f->expr_level++;
|
||||
stmts = parse_stmt_list(f);
|
||||
f->expr_level--;
|
||||
close = expect_token(f, Token_CloseBrace);
|
||||
return make_block_expr(f, stmts, open, close);
|
||||
}
|
||||
|
||||
default: {
|
||||
AstNode *type = parse_identifier_or_type(f);
|
||||
if (type != NULL) {
|
||||
@@ -2619,12 +2664,15 @@ AstNode *parse_return_stmt(AstFile *f) {
|
||||
syntax_error(f->curr_token, "You cannot use a return statement in the file scope");
|
||||
return make_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
}
|
||||
if (f->expr_level > 0) {
|
||||
syntax_error(f->curr_token, "You cannot use a return statement within an expression");
|
||||
return make_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
}
|
||||
|
||||
Token token = expect_token(f, Token_return);
|
||||
AstNodeArray results = make_ast_node_array(f);
|
||||
|
||||
if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace &&
|
||||
f->curr_token.pos.line == token.pos.line) {
|
||||
if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
|
||||
results = parse_rhs_expr_list(f);
|
||||
}
|
||||
|
||||
@@ -2632,6 +2680,23 @@ AstNode *parse_return_stmt(AstFile *f) {
|
||||
return make_return_stmt(f, token, results);
|
||||
}
|
||||
|
||||
|
||||
AstNode *parse_give_stmt(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
|
||||
return make_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
}
|
||||
if (f->expr_level == 0) {
|
||||
syntax_error(f->curr_token, "A give statement must be used within an expression");
|
||||
return make_bad_stmt(f, f->curr_token, f->curr_token);
|
||||
}
|
||||
|
||||
Token token = expect_token(f, Token_give);
|
||||
AstNodeArray results = parse_rhs_expr_list(f);
|
||||
expect_semicolon(f, results.e[0]);
|
||||
return make_expr_stmt(f, make_give_expr(f, token, results));
|
||||
}
|
||||
|
||||
AstNode *parse_for_stmt(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
syntax_error(f->curr_token, "You cannot use a for statement in the file scope");
|
||||
@@ -2861,7 +2926,6 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
expect_semicolon(f, s);
|
||||
return s;
|
||||
|
||||
// TODO(bill): other keywords
|
||||
case Token_if: return parse_if_stmt(f);
|
||||
case Token_when: return parse_when_stmt(f);
|
||||
case Token_for: return parse_for_stmt(f);
|
||||
@@ -2869,6 +2933,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
case Token_defer: return parse_defer_stmt(f);
|
||||
case Token_asm: return parse_asm_stmt(f);
|
||||
case Token_return: return parse_return_stmt(f);
|
||||
case Token_give: return parse_give_stmt(f);
|
||||
|
||||
case Token_break:
|
||||
case Token_continue:
|
||||
|
||||
@@ -2571,7 +2571,7 @@ ssaValue *ssa_find_implicit_value_backing(ssaProcedure *proc, ImplicitValueId id
|
||||
return *value;
|
||||
}
|
||||
|
||||
|
||||
void ssa_build_stmt_list(ssaProcedure *proc, AstNodeArray stmts);
|
||||
|
||||
ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
|
||||
expr = unparen_expr(expr);
|
||||
@@ -2626,6 +2626,70 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
return ssa_addr_load(proc, ssa_build_addr(proc, expr));
|
||||
case_end;
|
||||
|
||||
case_ast_node(be, BlockExpr, expr);
|
||||
ssa_emit_comment(proc, str_lit("BlockExpr"));
|
||||
ssa_open_scope(proc);
|
||||
|
||||
AstNodeArray stmts = be->stmts;
|
||||
stmts.count--;
|
||||
ssa_build_stmt_list(proc, stmts);
|
||||
|
||||
AstNode *give_stmt = be->stmts.e[be->stmts.count-1];
|
||||
GB_ASSERT(give_stmt->kind == AstNode_ExprStmt);
|
||||
AstNode *give_expr = give_stmt->ExprStmt.expr;
|
||||
GB_ASSERT(give_expr->kind == AstNode_GiveExpr);
|
||||
ssaValue *value = ssa_build_expr(proc, give_expr);
|
||||
|
||||
ssa_close_scope(proc, ssaDeferExit_Default, NULL);
|
||||
|
||||
return value;
|
||||
case_end;
|
||||
|
||||
case_ast_node(ge, GiveExpr, expr);
|
||||
ssa_emit_comment(proc, str_lit("GiveExpr"));
|
||||
|
||||
ssaValue *v = NULL;
|
||||
Type *give_type = type_of_expr(proc->module->info, expr);
|
||||
GB_ASSERT(give_type != NULL);
|
||||
if (give_type->kind != Type_Tuple) {
|
||||
v = ssa_emit_conv(proc, ssa_build_expr(proc, ge->results.e[0]), give_type);
|
||||
} else {
|
||||
TypeTuple *tuple = &give_type->Tuple;
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||
|
||||
ssaValueArray results;
|
||||
array_init_reserve(&results, proc->module->tmp_allocator, tuple->variable_count);
|
||||
|
||||
for_array(res_index, ge->results) {
|
||||
ssaValue *res = ssa_build_expr(proc, ge->results.e[res_index]);
|
||||
Type *t = ssa_type(res);
|
||||
if (t->kind == Type_Tuple) {
|
||||
for (isize i = 0; i < t->Tuple.variable_count; i++) {
|
||||
Entity *e = t->Tuple.variables[i];
|
||||
ssaValue *v = ssa_emit_struct_ev(proc, res, i);
|
||||
array_add(&results, v);
|
||||
}
|
||||
} else {
|
||||
array_add(&results, res);
|
||||
}
|
||||
}
|
||||
|
||||
v = ssa_add_local_generated(proc, give_type);
|
||||
for_array(i, results) {
|
||||
Entity *e = tuple->variables[i];
|
||||
ssaValue *res = ssa_emit_conv(proc, results.e[i], e->type);
|
||||
ssaValue *field = ssa_emit_struct_ep(proc, v, i);
|
||||
ssa_emit_store(proc, field, res);
|
||||
}
|
||||
|
||||
v = ssa_emit_load(proc, v);
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
return v;
|
||||
case_end;
|
||||
|
||||
case_ast_node(ue, UnaryExpr, expr);
|
||||
switch (ue->op.kind) {
|
||||
case Token_Pointer:
|
||||
|
||||
@@ -104,6 +104,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_range, "range"), \
|
||||
TOKEN_KIND(Token_defer, "defer"), \
|
||||
TOKEN_KIND(Token_return, "return"), \
|
||||
TOKEN_KIND(Token_give, "give"), \
|
||||
TOKEN_KIND(Token_struct, "struct"), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||
|
||||
Reference in New Issue
Block a user