From 18f885efabb98fb91ab0c6e9586a8b66eab511d9 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 24 Jun 2017 20:39:37 +0100 Subject: [PATCH] `expand_to_tuple` --- src/check_expr.cpp | 43 ++++++++++++++++++++++++++++++++++--------- src/checker.cpp | 17 +++++++++++++++-- src/ir.cpp | 17 +++++++++++++++++ src/parser.cpp | 20 ++++++++++++++++++-- 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c8366422f..33e323644 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1516,6 +1516,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { type->Proc.result_count = result_count; type->Proc.variadic = variadic; type->Proc.calling_convention = pt->calling_convention; + type->Proc.is_generic = pt->generic; if (param_count > 0) { Entity *end = params->Tuple.variables[param_count-1]; @@ -1530,18 +1531,19 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { type->Proc.c_vararg = true; } } - - bool is_generic = false; - for (isize i = 0; i < param_count; i++) { - Entity *e = params->Tuple.variables[i]; - if (e->type->kind == Type_Generic) { - is_generic = true; - } - } - type->Proc.is_generic = is_generic; } + bool is_generic = false; + for (isize i = 0; i < param_count; i++) { + Entity *e = params->Tuple.variables[i]; + if (e->type->kind == Type_Generic) { + is_generic = true; + } + } + GB_ASSERT(type->Proc.is_generic == is_generic); + + type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count); for (isize i = 0; i < param_count; i++) { Type *original_type = type->Proc.params->Tuple.variables[i]->type; @@ -4490,6 +4492,29 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->mode = Addressing_Value; } break; + case BuiltinProc_expand_to_tuple: { + Type *type = base_type(operand->type); + if (!is_type_struct(type) & + !is_type_union(type)) { + gbString type_str = type_to_string(operand->type); + error(call, "Expected a struct or union type, got `%s`", type_str); + gb_string_free(type_str); + return false; + } + gbAllocator a = c->allocator; + + Type *tuple = make_type_tuple(a); + i32 variable_count = type->Record.field_count; + tuple->Tuple.variables = gb_alloc_array(a, Entity *, variable_count); + tuple->Tuple.variable_count = variable_count; + + // TODO(bill): Should I copy each of the entities or is this good enough? + gb_memcopy_array(tuple->Tuple.variables, type->Record.fields, variable_count); + + operand->type = tuple; + operand->mode = Addressing_Value; + } break; + case BuiltinProc_min: { // proc min(a, b: ordered) -> ordered Type *type = base_type(operand->type); diff --git a/src/checker.cpp b/src/checker.cpp index a912c6a59..66fcc1ab6 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -56,6 +56,8 @@ enum BuiltinProcId { BuiltinProc_slice_ptr, BuiltinProc_slice_to_bytes, + BuiltinProc_expand_to_tuple, + BuiltinProc_min, BuiltinProc_max, BuiltinProc_abs, @@ -99,8 +101,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("imag"), 1, false, Expr_Expr}, {STR_LIT("conj"), 1, false, Expr_Expr}, - {STR_LIT("slice_ptr"), 2, true, Expr_Expr}, - {STR_LIT("slice_to_bytes"), 1, false, Expr_Stmt}, + {STR_LIT("slice_ptr"), 2, true, Expr_Expr}, + {STR_LIT("slice_to_bytes"), 1, false, Expr_Stmt}, + + {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr}, {STR_LIT("min"), 2, false, Expr_Expr}, {STR_LIT("max"), 2, false, Expr_Expr}, @@ -328,6 +332,15 @@ void scope_lookup_parent_entity (Scope *s, String name, Scope **scope_, Entit Entity *scope_insert_entity (Scope *s, Entity *entity); +ExprInfo *check_get_expr_info(CheckerInfo *i, AstNode *expr); +void check_set_expr_info(CheckerInfo *i, AstNode *expr, ExprInfo info); +void check_remove_expr_info(CheckerInfo *i, AstNode *expr); +void add_untyped(CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value); +void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value); +void add_entity_use(Checker *c, AstNode *identifier, Entity *entity); +void add_implicit_entity(Checker *c, AstNode *node, Entity *e); +void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d); +void add_implicit_entity(Checker *c, AstNode *node, Entity *e); void init_declaration_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { diff --git a/src/ir.cpp b/src/ir.cpp index b2a6b9579..cd611ea44 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4283,6 +4283,23 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv return ir_emit_load(proc, slice); } break; + case BuiltinProc_expand_to_tuple: { + ir_emit_comment(proc, str_lit("expand_to_tuple")); + irValue *s = ir_build_expr(proc, ce->args[0]); + Type *t = base_type(ir_type(s)); + + GB_ASSERT(t->kind == Type_Record); + GB_ASSERT(is_type_tuple(tv.type)); + + irValue *tuple = ir_add_local_generated(proc, tv.type); + for (isize i = 0; i < t->Record.field_count; i++) { + irValue *f = ir_emit_struct_ev(proc, s, i); + irValue *ep = ir_emit_struct_ep(proc, tuple, i); + ir_emit_store(proc, ep, f); + } + return ir_emit_load(proc, tuple); + } break; + case BuiltinProc_min: { ir_emit_comment(proc, str_lit("min")); Type *t = type_of_expr(proc->module->info, expr); diff --git a/src/parser.cpp b/src/parser.cpp index a023bccd5..37f56d350 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -393,6 +393,7 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ AstNode *results; \ u64 tags; \ ProcCallingConvention calling_convention; \ + bool generic; \ }) \ AST_NODE_KIND(PointerType, "pointer type", struct { \ Token token; \ @@ -1370,16 +1371,18 @@ AstNode *ast_helper_type(AstFile *f, Token token) { } -AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention) { +AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention, bool generic) { AstNode *result = make_ast_node(f, AstNode_ProcType); result->ProcType.token = token; result->ProcType.params = params; result->ProcType.results = results; result->ProcType.tags = tags; result->ProcType.calling_convention = calling_convention; + result->ProcType.generic = generic; return result; } + AstNode *ast_pointer_type(AstFile *f, Token token, AstNode *type) { AstNode *result = make_ast_node(f, AstNode_PointerType); result->PointerType.token = token; @@ -3214,7 +3217,20 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) { if (link_name_) *link_name_ = link_name; - return ast_proc_type(f, proc_token, params, results, tags, cc); + bool is_generic = false; + + for_array(i, params->FieldList.list) { + AstNode *param = params->FieldList.list[i]; + ast_node(f, Field, param); + if (f->type != NULL && + f->type->kind == AstNode_HelperType) { + is_generic = true; + break; + } + } + + + return ast_proc_type(f, proc_token, params, results, tags, cc, is_generic); } AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) {