From b44bc99b889bb07dfe4f843ddeefd7483e0fba82 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Aug 2016 15:31:11 +0100 Subject: append :: proc(s: ^[]T, i: T) -> bool --- src/checker/expr.cpp | 115 +++++++++++++++++++++++++++--------------- src/checker/type.cpp | 5 ++ src/codegen/ssa.cpp | 137 +++++++++++++++++++++++++++++++++++++++++---------- src/main.cpp | 2 + src/parser.cpp | 7 +-- src/tokenizer.cpp | 39 +++++++++------ 6 files changed, 218 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index a4931ed94..ced7402af 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -857,45 +857,6 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) { return false; } -void check_cast_expr(Checker *c, Operand *operand, Type *type) { - b32 is_const_expr = operand->mode == Addressing_Constant; - b32 can_convert = false; - - if (is_const_expr && is_type_constant_type(type)) { - Type *t = get_base_type(type); - if (t->kind == Type_Basic) { - if (check_value_is_expressible(c, operand->value, t, &operand->value)) { - can_convert = true; - } - } - } else if (check_castable_to(c, operand, type)) { - operand->mode = Addressing_Value; - can_convert = true; - } - - if (!can_convert) { - gbString expr_str = expr_to_string(operand->expr); - gbString type_str = type_to_string(type); - defer (gb_string_free(expr_str)); - defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(operand->expr), "Cannot cast `%s` to `%s`", expr_str, type_str); - - operand->mode = Addressing_Invalid; - return; - } - - if (is_type_untyped(operand->type)) { - Type *final_type = type; - if (is_const_expr && !is_type_constant_type(type)) { - final_type = default_type(operand->type); - } - update_expr_type(c, operand->expr, final_type, true); - } - - operand->type = type; -} - - void check_binary_expr(Checker *c, Operand *x, AstNode *node) { GB_ASSERT(node->kind == AstNode_BinaryExpr); Operand y_ = {}, *y = &y_; @@ -906,10 +867,82 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (be->op.kind == Token_as) { check_expr(c, x, be->left); - Type *cast_type = check_type(c, be->right); + Type *type = check_type(c, be->right); if (x->mode == Addressing_Invalid) return; - check_cast_expr(c, x, cast_type); + + b32 is_const_expr = x->mode == Addressing_Constant; + b32 can_convert = false; + + if (is_const_expr && is_type_constant_type(type)) { + Type *t = get_base_type(type); + if (t->kind == Type_Basic) { + if (check_value_is_expressible(c, x->value, t, &x->value)) { + can_convert = true; + } + } + } else if (check_castable_to(c, x, type)) { + x->mode = Addressing_Value; + can_convert = true; + } + + if (!can_convert) { + gbString expr_str = expr_to_string(x->expr); + gbString type_str = type_to_string(type); + defer (gb_string_free(expr_str)); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(x->expr), "Cannot cast `%s` to `%s`", expr_str, type_str); + + x->mode = Addressing_Invalid; + return; + } + + if (is_type_untyped(x->type)) { + Type *final_type = type; + if (is_const_expr && !is_type_constant_type(type)) { + final_type = default_type(x->type); + } + update_expr_type(c, x->expr, final_type, true); + } + + x->type = type; + return; + } else if (be->op.kind == Token_transmute) { + check_expr(c, x, be->left); + Type *type = check_type(c, be->right); + if (x->mode == Addressing_Invalid) + return; + + if (x->mode == Addressing_Constant) { + gbString expr_str = expr_to_string(x->expr); + defer (gb_string_free(expr_str)); + error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute constant expression: `%s`", expr_str); + x->mode = Addressing_Invalid; + return; + } + + if (is_type_untyped(x->type)) { + gbString expr_str = expr_to_string(x->expr); + defer (gb_string_free(expr_str)); + error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute untyped expression: `%s`", expr_str); + x->mode = Addressing_Invalid; + return; + } + + i64 otz = type_size_of(c->sizes, c->allocator, x->type); + i64 ttz = type_size_of(c->sizes, c->allocator, type); + if (otz != ttz) { + gbString expr_str = expr_to_string(x->expr); + gbString type_str = type_to_string(type); + defer (gb_string_free(expr_str)); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, otz, ttz); + x->mode = Addressing_Invalid; + return; + } + + x->type = type; + return; } diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 12a96e1a5..4504cd06f 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -438,6 +438,11 @@ b32 are_types_identical(Type *x, Type *y) { return (x->vector.count == y->vector.count) && are_types_identical(x->vector.elem, y->vector.elem); break; + case Type_Slice: + if (y->kind == Type_Slice) + return are_types_identical(x->slice.elem, y->slice.elem); + break; + case Type_Structure: if (y->kind == Type_Structure) { if (x->structure.field_count == y->structure.field_count) { diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 42e7046cf..1b70b2678 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -401,6 +401,7 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr); ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv); ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr); ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *a_type); +ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *a_type); void ssa_build_proc(ssaValue *value, ssaProcedure *parent); @@ -1077,7 +1078,7 @@ ssaValue *ssa_emit_slice(ssaProcedure *proc, Type *slice_type, ssaValue *base, s switch (base_type->kind) { case Type_Array: elem = ssa_array_elem(proc, base); break; case Type_Slice: elem = ssa_slice_elem(proc, base); break; - case Type_Pointer: elem = base; break; + case Type_Pointer: elem = ssa_emit_load(proc, base); break; } elem = ssa_emit_ptr_offset(proc, elem, low); @@ -1176,8 +1177,6 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) { if (are_types_identical(t, src_type)) return value; - - if (value->kind == ssaValue_Constant) { if (dst->kind == Type_Basic) { ExactValue ev = value->constant.value; @@ -1291,6 +1290,31 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) { } +ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) { + Type *src_type = ssa_value_type(value); + if (are_types_identical(t, src_type)) { + return value; + } + + Type *src = get_base_type(src_type); + Type *dst = get_base_type(t); + if (are_types_identical(t, src_type)) + return value; + + i64 sz = type_size_of(proc->module->sizes, proc->module->allocator, src); + i64 dz = type_size_of(proc->module->sizes, proc->module->allocator, dst); + + if (sz == dz) { + return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_bitcast, value, src, dst)); + } + + + GB_PANIC("Invalid transmute conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); + + return NULL; +} + + @@ -1392,6 +1416,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case Token_as: return ssa_emit_conv(proc, ssa_build_expr(proc, be->left), tv->type); + case Token_transmute: + return ssa_emit_transmute(proc, ssa_build_expr(proc, be->left), tv->type); + default: GB_PANIC("Invalid binary expression"); break; @@ -1583,8 +1610,44 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue return len; } break; case BuiltinProc_append: { - // copy :: proc(s: ^[]Type, value: Type) -> bool - GB_PANIC("TODO(bill): BuiltinProc_append"); + // append :: proc(s: ^[]Type, item: Type) -> bool + AstNode *sptr_node = ce->arg_list; + AstNode *item_node = ce->arg_list->next; + ssaValue *slice = ssa_build_addr(proc, sptr_node).address; + ssaValue *item = ssa_build_addr(proc, item_node).address; + Type *item_type = type_deref(ssa_value_type(item)); + + ssaValue *elem = ssa_slice_elem(proc, slice); + ssaValue *len = ssa_slice_len(proc, slice); + ssaValue *cap = ssa_slice_cap(proc, slice); + + // NOTE(bill): Check if can append is possible + Token lt = {Token_Lt}; + ssaValue *cond = ssa_emit_comp(proc, lt, len, cap); + ssaBlock *able = ssa_add_block(proc, NULL, make_string("builtin.append.able")); + ssaBlock *done = ssa__make_block(proc, NULL, make_string("builtin.append.done")); + + ssa_emit_if(proc, cond, able, done); + proc->curr_block = able; + + // Add new slice item + ssaValue *offset = ssa_emit_ptr_offset(proc, elem, len); + i64 item_size = type_size_of(proc->module->sizes, proc->module->allocator, item_type); + ssaValue *byte_count = ssa_make_value_constant(proc->module->allocator, t_int, + make_exact_value_integer(item_size)); + ssa_emit(proc, ssa_make_instr_copy_memory(proc, offset, item, byte_count, 1, false)); + + // Increment slice length + Token add = {Token_Add}; + ssaValue *new_len = ssa_emit_arith(proc, add, len, v_one, t_int); + ssaValue *gep = ssa_emit_struct_gep(proc, slice, v_one32, t_int); + ssa_emit_store(proc, gep, new_len); + + ssa_emit_jump(proc, done); + gb_array_append(proc->blocks, done); + proc->curr_block = done; + + return ssa_emit_conv(proc, cond, t_bool); } break; case BuiltinProc_print: { // print :: proc(...) @@ -1735,12 +1798,21 @@ ssaLvalue ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(be, BinaryExpr, expr); switch (be->op.kind) { case Token_as: { + // HACK(bill): Do have to make new variable to do this? // NOTE(bill): Needed for dereference of pointer conversion Type *type = type_of_expr(proc->module->info, expr); ssaValue *v = ssa_add_local_generated(proc, type); ssa_emit_store(proc, v, ssa_emit_conv(proc, ssa_build_expr(proc, be->left), type)); return ssa_make_lvalue(v, expr); } + case Token_transmute: { + // HACK(bill): Do have to make new variable to do this? + // NOTE(bill): Needed for dereference of pointer conversion + Type *type = type_of_expr(proc->module->info, expr); + ssaValue *v = ssa_add_local_generated(proc, type); + ssa_emit_store(proc, v, ssa_emit_transmute(proc, ssa_build_expr(proc, be->left), type)); + return ssa_make_lvalue(v, expr); + } default: GB_PANIC("Invalid binary expression for ssa_build_addr: %.*s\n", LIT(be->op.string)); break; @@ -1971,33 +2043,48 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { if (proc->children == NULL) { gb_array_init(proc->children, gb_heap_allocator()); } - // NOTE(bill): Generate a new name - // parent$name - String pd_name = pd->name->Ident.token.string; - isize name_len = proc->name.len + 1 + pd_name.len + 1; - u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); - name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%.*s", LIT(proc->name), LIT(pd_name)); - String name = make_string(name_text, name_len-1); - - Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name)); - GB_ASSERT(found != NULL); - Entity *e = *found; - ssaValue *value = ssa_make_value_procedure(proc->module->allocator, - proc->module, e->type, pd->type, pd->body, name); - - ssa_module_add_value(proc->module, e, value); - gb_array_append(proc->children, &value->proc); - ssa_build_proc(value, proc); + if (pd->body != NULL) { + // NOTE(bill): Generate a new name + // parent$name-guid + String pd_name = pd->name->Ident.token.string; + isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1; + u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); + i32 guid = cast(i32)gb_array_count(proc->children); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%.*s-%d", LIT(proc->name), LIT(pd_name), guid); + String name = make_string(name_text, name_len-1); + + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name)); + GB_ASSERT(found != NULL); + Entity *e = *found; + ssaValue *value = ssa_make_value_procedure(proc->module->allocator, + proc->module, e->type, pd->type, pd->body, name); + + ssa_module_add_value(proc->module, e, value); + gb_array_append(proc->children, &value->proc); + ssa_build_proc(value, proc); + } else { + String name = pd->name->Ident.token.string; + + Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name)); + GB_ASSERT(found != NULL); + Entity *e = *found; + ssaValue *value = ssa_make_value_procedure(proc->module->allocator, + proc->module, e->type, pd->type, pd->body, name); + ssa_module_add_value(proc->module, e, value); + gb_array_append(proc->children, &value->proc); + ssa_build_proc(value, proc); + } case_end; case_ast_node(td, TypeDecl, node); // NOTE(bill): Generate a new name - // parent_proc.name + // parent_proc.name-guid String td_name = td->name->Ident.token.string; - isize name_len = proc->name.len + 1 + td_name.len + 1; + isize name_len = proc->name.len + 1 + td_name.len + 1 + 10 + 1; u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); - name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s", LIT(proc->name), LIT(td_name)); + i32 guid = cast(i32)gb_array_count(proc->module->nested_type_names); + name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(td_name), guid); String name = make_string(name_text, name_len-1); Entity **found = map_get(&proc->module->info->definitions, hash_pointer(td->name)); diff --git a/src/main.cpp b/src/main.cpp index 85c5912fc..f8416a8c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,6 +39,8 @@ int main(int argc, char **argv) { ssa_gen_code(&ssa); success = 0; + } else { + gb_printf("Failed to build: %s\n", init_filename); } } } diff --git a/src/parser.cpp b/src/parser.cpp index 40a970fc6..9e9992fa5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1212,16 +1212,13 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { i32 op_prec = token_precedence(op); if (op_prec != prec) break; - if (op.kind != Token_as) { - expect_operator(f); // NOTE(bill): error checks too - } + expect_operator(f); // NOTE(bill): error checks too if (lhs) { // TODO(bill): error checking lhs = false; } - if (op.kind == Token_as) { - next_token(f); + if (op.kind == Token_as || op.kind == Token_transmute) { right = parse_type(f); } else { right = parse_binary_expr(f, false, prec+1); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d025d0879..848dd7ab6 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -54,7 +54,10 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ TOKEN_KIND(Token_AndNot, "&~"), \ TOKEN_KIND(Token_Shl, "<<"), \ TOKEN_KIND(Token_Shr, ">>"), \ +\ TOKEN_KIND(Token_as, "as"), \ + TOKEN_KIND(Token_transmute, "transmute"), \ +\ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token_AddEq, "+="), \ TOKEN_KIND(Token_SubEq, "-="), \ @@ -101,23 +104,23 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ - TOKEN_KIND(Token_type, "type"), \ - TOKEN_KIND(Token_alias, "alias"), \ - TOKEN_KIND(Token_proc, "proc"), \ - TOKEN_KIND(Token_match, "match"), \ - TOKEN_KIND(Token_break, "break"), \ - TOKEN_KIND(Token_continue, "continue"), \ + TOKEN_KIND(Token_type, "type"), \ + TOKEN_KIND(Token_alias, "alias"), \ + TOKEN_KIND(Token_proc, "proc"), \ + TOKEN_KIND(Token_match, "match"), \ + TOKEN_KIND(Token_break, "break"), \ + TOKEN_KIND(Token_continue, "continue"), \ TOKEN_KIND(Token_fallthrough, "fallthrough"), \ - TOKEN_KIND(Token_case, "case"), \ - TOKEN_KIND(Token_if, "if"), \ - TOKEN_KIND(Token_else, "else"), \ - TOKEN_KIND(Token_for, "for"), \ - TOKEN_KIND(Token_defer, "defer"), \ - TOKEN_KIND(Token_return, "return"), \ - TOKEN_KIND(Token_import, "import"), \ - TOKEN_KIND(Token_struct, "struct"), \ - TOKEN_KIND(Token_union, "union"), \ - TOKEN_KIND(Token_enum, "enum"), \ + TOKEN_KIND(Token_case, "case"), \ + TOKEN_KIND(Token_if, "if"), \ + TOKEN_KIND(Token_else, "else"), \ + TOKEN_KIND(Token_for, "for"), \ + TOKEN_KIND(Token_defer, "defer"), \ + TOKEN_KIND(Token_return, "return"), \ + TOKEN_KIND(Token_import, "import"), \ + TOKEN_KIND(Token_struct, "struct"), \ + TOKEN_KIND(Token_union, "union"), \ + TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token_Count, "") @@ -225,6 +228,7 @@ i32 token_precedence(Token t) { case Token_Shr: return 5; case Token_as: + case Token_transmute: return 6; } @@ -645,6 +649,8 @@ Token tokenizer_get_token(Tokenizer *t) { if (token.string.len > 1) { if (are_strings_equal(token.string, token_strings[Token_as])) { token.kind = Token_as; + } else if (are_strings_equal(token.string, token_strings[Token_transmute])) { + token.kind = Token_transmute; } else { for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) { if (are_strings_equal(token.string, token_strings[k])) { @@ -730,6 +736,7 @@ Token tokenizer_get_token(Tokenizer *t) { if (valid && len != 1) tokenizer_err(t, "Illegal rune literal"); token.string.len = t->curr - token.string.text; + i32 success = unquote_string(gb_heap_allocator(), &token.string); if (success > 0) { if (success == 2) { -- cgit v1.2.3