mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-17 11:22:22 -07:00
append :: proc(s: ^[]T, i: T) -> bool
This commit is contained in:
+74
-41
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+110
-23
@@ -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);
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -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);
|
||||
|
||||
+23
-16
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user