diff options
| author | Zac Pierson <zacpiersonhehe@gmail.com> | 2017-02-15 10:21:38 -0600 |
|---|---|---|
| committer | Zac Pierson <zacpiersonhehe@gmail.com> | 2017-02-15 10:21:38 -0600 |
| commit | aaa4dd5c363f2cb4643cd6489108d5be7c9d17de (patch) | |
| tree | cb6b93596135d2a7f868acc73fcea1536e3d7ab9 /src | |
| parent | 9d19ee7e4c285d5d881570be3328d81bdff40368 (diff) | |
| parent | 71100ed427ee2eec8d8a9d4d9616102738097e80 (diff) | |
Merge https://github.com/gingerBill/odin
Diffstat (limited to 'src')
| -rw-r--r-- | src/build_settings.c | 8 | ||||
| -rw-r--r-- | src/check_decl.c | 11 | ||||
| -rw-r--r-- | src/check_expr.c | 477 | ||||
| -rw-r--r-- | src/check_stmt.c | 134 | ||||
| -rw-r--r-- | src/checker.c | 73 | ||||
| -rw-r--r-- | src/common.c | 3 | ||||
| -rw-r--r-- | src/entity.c | 9 | ||||
| -rw-r--r-- | src/ir.c | 125 | ||||
| -rw-r--r-- | src/map.c | 3 | ||||
| -rw-r--r-- | src/parser.c | 292 | ||||
| -rw-r--r-- | src/string.c | 1 | ||||
| -rw-r--r-- | src/tokenizer.c | 3 | ||||
| -rw-r--r-- | src/types.c | 17 |
13 files changed, 493 insertions, 663 deletions
diff --git a/src/build_settings.c b/src/build_settings.c index 2409db9aa..c50150827 100644 --- a/src/build_settings.c +++ b/src/build_settings.c @@ -1,4 +1,6 @@ +// This stores the information for the specify architecture of this build typedef struct BuildContext { + // Constants String ODIN_OS; // target operating system String ODIN_ARCH; // target architecture String ODIN_ENDIAN; // target endian @@ -6,8 +8,10 @@ typedef struct BuildContext { String ODIN_VERSION; // compiler version String ODIN_ROOT; // Odin ROOT - i64 word_size; - i64 max_align; + // In bytes + i64 word_size; // Size of a pointer, must be >= 4 + i64 max_align; // max alignment, must be >= 1 (and typically >= word_size) + String llc_flags; String link_flags; bool is_dll; diff --git a/src/check_decl.c b/src/check_decl.c index ebee92b5e..bc49e36c1 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -72,25 +72,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra } } - isize max = gb_min(lhs_count, rhs_count); for (isize i = 0; i < max; i++) { check_init_variable(c, lhs[i], &operands.e[i], context_name); } - if (rhs_count > 0 && lhs_count != rhs_count) { error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); } -#if 0 - 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); - } - } -#endif - gb_temp_arena_memory_end(tmp); } diff --git a/src/check_expr.c b/src/check_expr.c index 3b58dc904..687f4ebea 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -265,8 +265,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n } - - if (type == NULL) { return; } @@ -1030,7 +1028,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ } o->mode = Addressing_Variable; if (e->Variable.is_immutable) { - o->mode = Addressing_Value; + o->mode = Addressing_Immutable; } break; @@ -1073,7 +1071,7 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) { } Operand o = {0}; if (e->kind == AstNode_UnaryExpr && - e->UnaryExpr.op.kind == Token_Question) { + e->UnaryExpr.op.kind == Token_Ellipsis) { return -1; } @@ -1115,12 +1113,13 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) { return 0; } -Type *make_map_tuple_type(gbAllocator a, Type *value) { +Type *make_optional_ok_type(gbAllocator a, Type *value) { + bool typed = true; Type *t = make_type_tuple(a); t->Tuple.variables = gb_alloc_array(a, Entity *, 2); t->Tuple.variable_count = 2; t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value, false, 0); - t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, t_bool, false, 1); + t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, typed ? t_bool : t_untyped_bool, false, 1); return t; } @@ -1221,7 +1220,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { type->Map.generated_struct_type = generated_struct_type; } - type->Map.lookup_result_type = make_map_tuple_type(a, value); + type->Map.lookup_result_type = make_optional_ok_type(a, value); // error_node(node, "`map` types are not yet implemented"); } @@ -1929,6 +1928,76 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { x->mode = Addressing_Value; } + +String check_down_cast_name(Type *dst_, Type *src_) { + String result = {0}; + Type *dst = type_deref(dst_); + Type *src = type_deref(src_); + Type *dst_s = base_type(dst); + GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s)); + for (isize i = 0; i < dst_s->Record.field_count; i++) { + Entity *f = dst_s->Record.fields[i]; + GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); + if (f->flags & EntityFlag_Anonymous) { + if (are_types_identical(f->type, src_)) { + return f->token.string; + } + if (are_types_identical(type_deref(f->type), src_)) { + return f->token.string; + } + + if (!is_type_pointer(f->type)) { + result = check_down_cast_name(f->type, src_); + if (result.len > 0) { + return result; + } + } + } + } + + return result; +} + +Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) { + GB_ASSERT(node->kind == AstNode_BinaryExpr); + ast_node(be, BinaryExpr, node); + GB_ASSERT(is_type_pointer(ptr->type)); + GB_ASSERT(is_type_integer(offset->type)); + GB_ASSERT(op == Token_Add || op == Token_Sub); + + Operand operand = {0}; + operand.mode = Addressing_Value; + operand.type = ptr->type; + operand.expr = node; + + if (base_type(ptr->type) == t_rawptr) { + gbString str = type_to_string(ptr->type); + error_node(node, "Invalid pointer type for pointer arithmetic: `%s`", str); + gb_string_free(str); + operand.mode = Addressing_Invalid; + return operand; + } + + + if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) { + i64 elem_size = type_size_of(c->allocator, ptr->type); + i64 ptr_val = ptr->value.value_pointer; + i64 offset_val = exact_value_to_integer(offset->value).value_integer; + i64 new_ptr_val = ptr_val; + if (op == Token_Add) { + new_ptr_val += elem_size*offset_val; + } else { + new_ptr_val -= elem_size*offset_val; + } + operand.mode = Addressing_Constant; + operand.value = make_exact_value_pointer(new_ptr_val); + } + + return operand; +} + + + bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { if (check_is_assignable_to(c, operand, y)) { return true; @@ -1968,10 +2037,21 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { // Cast between pointers if (is_type_pointer(src) && is_type_pointer(dst)) { + Type *s = base_type(type_deref(src)); + if (is_type_union(s)) { + // NOTE(bill): Should the error be here?! + // NOTE(bill): This error should suppress the next casting error as it's at the same position + gbString xs = type_to_string(x); + gbString ys = type_to_string(y); + error_node(operand->expr, "Cannot cast from a union pointer `%s` to `%s`, try using `union_cast` or cast to a `rawptr`", xs, ys); + gb_string_free(ys); + gb_string_free(xs); + return false; + } return true; } - // (u)int <-> pointer + // (u)int <-> rawptr if (is_type_int_or_uint(src) && is_type_rawptr(dst)) { return true; } @@ -2006,75 +2086,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { return false; } -String check_down_cast_name(Type *dst_, Type *src_) { - String result = {0}; - Type *dst = type_deref(dst_); - Type *src = type_deref(src_); - Type *dst_s = base_type(dst); - GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s)); - for (isize i = 0; i < dst_s->Record.field_count; i++) { - Entity *f = dst_s->Record.fields[i]; - GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); - if (f->flags & EntityFlag_Anonymous) { - if (are_types_identical(f->type, src_)) { - return f->token.string; - } - if (are_types_identical(type_deref(f->type), src_)) { - return f->token.string; - } - - if (!is_type_pointer(f->type)) { - result = check_down_cast_name(f->type, src_); - if (result.len > 0) { - return result; - } - } - } - } - - return result; -} - -Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) { - GB_ASSERT(node->kind == AstNode_BinaryExpr); - ast_node(be, BinaryExpr, node); - GB_ASSERT(is_type_pointer(ptr->type)); - GB_ASSERT(is_type_integer(offset->type)); - GB_ASSERT(op == Token_Add || op == Token_Sub); - - Operand operand = {0}; - operand.mode = Addressing_Value; - operand.type = ptr->type; - operand.expr = node; - - if (base_type(ptr->type) == t_rawptr) { - gbString str = type_to_string(ptr->type); - error_node(node, "Invalid pointer type for pointer arithmetic: `%s`", str); - gb_string_free(str); - operand.mode = Addressing_Invalid; - return operand; - } - - - if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) { - i64 elem_size = type_size_of(c->allocator, ptr->type); - i64 ptr_val = ptr->value.value_pointer; - i64 offset_val = exact_value_to_integer(offset->value).value_integer; - i64 new_ptr_val = ptr_val; - if (op == Token_Add) { - new_ptr_val += elem_size*offset_val; - } else { - new_ptr_val -= elem_size*offset_val; - } - operand.mode = Addressing_Constant; - operand.value = make_exact_value_pointer(new_ptr_val); - } - - return operand; -} - - -void check_conversion(Checker *c, Operand *x, Type *type) { +void check_cast(Checker *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; bool can_convert = false; @@ -2714,7 +2726,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h break; case Entity_Variable: // TODO(bill): This is the rule I need? - if (sel.indirect || operand->mode != Addressing_Value) { + if (operand->mode == Addressing_Immutable) { + // Okay + } else if (sel.indirect || operand->mode != Addressing_Value) { operand->mode = Addressing_Variable; } else { operand->mode = Addressing_Value; @@ -3819,17 +3833,16 @@ int valid_proc_and_score_cmp(void const *a, void const *b) { typedef Array(Operand) ArrayOperand; -void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) { - for_array(i, args) { +bool check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray rhs, bool allow_ok) { + bool optional_ok = false; + for_array(i, rhs) { Operand o = {0}; - check_multi_expr(c, &o, args.e[i]); + check_multi_expr(c, &o, rhs.e[i]); if (o.type == NULL || o.type->kind != Type_Tuple) { - if (o.mode == Addressing_MapIndex && - allow_map_ok && - lhs_count == 2 && - args.count == 1) { - Type *tuple = make_map_tuple_type(c->allocator, o.type); + if (allow_ok && lhs_count == 2 && rhs.count == 1 && + (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) { + Type *tuple = make_optional_ok_type(c->allocator, o.type); add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value); Operand val = o; @@ -3839,9 +3852,11 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, ok.type = t_bool; array_add(operands, val); array_add(operands, ok); - continue; + + optional_ok = true; + } else { + array_add(operands, o); } - array_add(operands, o); } else { TypeTuple *tuple = &o.type->Tuple; for (isize j = 0; j < tuple->variable_count; j++) { @@ -3850,6 +3865,8 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, } } } + + return optional_ok; } Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { @@ -3998,7 +4015,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { case 1: check_expr(c, operand, ce->args.e[0]); if (operand->mode != Addressing_Invalid) { - check_conversion(c, operand, t); + check_cast(c, operand, t); } break; } @@ -4097,8 +4114,19 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) { } } -bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { - t = base_type(type_deref(t)); +void check_set_mode_with_indirection(Operand *o, bool indirection) { + if (o->mode != Addressing_Immutable) { + if (indirection) { + o->mode = Addressing_Variable; + } else if (o->mode != Addressing_Variable && + o->mode != Addressing_Constant) { + o->mode = Addressing_Value; + } + } +} + +bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_count) { + Type *t = base_type(type_deref(type)); switch (t->kind) { case Type_Basic: @@ -4106,9 +4134,7 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { if (o->mode == Addressing_Constant) { *max_count = o->value.value_string.len; } - if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t_u8; return true; } @@ -4116,69 +4142,33 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { case Type_Array: *max_count = t->Array.count; - if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t->Array.elem; return true; case Type_Vector: *max_count = t->Vector.count; - if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t->Vector.elem; return true; case Type_Slice: o->type = t->Slice.elem; - o->mode = Addressing_Variable; + if (o->mode != Addressing_Immutable) { + o->mode = Addressing_Variable; + } return true; case Type_DynamicArray: o->type = t->DynamicArray.elem; - o->mode = Addressing_Variable; + check_set_mode_with_indirection(o, indirection); return true; } return false; } - -bool check_is_giving(AstNode *node, AstNode **give_expr) { - switch (node->kind) { - case_ast_node(es, ExprStmt, node); - if (es->expr->kind == AstNode_GiveExpr) { - if (give_expr) *give_expr = es->expr; - return true; - } - case_end; - - case_ast_node(ge, GiveExpr, node); - if (give_expr) *give_expr = node; - return true; - case_end; - - case_ast_node(be, BlockExpr, node); - // Iterate backwards - for (isize n = be->stmts.count-1; n >= 0; n--) { - AstNode *stmt = be->stmts.e[n]; - if (stmt->kind == AstNode_EmptyStmt) { - continue; - } - if (stmt->kind == AstNode_ExprStmt && stmt->ExprStmt.expr->kind == AstNode_GiveExpr) { - if (give_expr) *give_expr = stmt->ExprStmt.expr; - return true; - } - } - 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; @@ -4280,177 +4270,30 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->type = type; case_end; - case_ast_node(ge, GiveExpr, node); - if (c->proc_stack.count == 0) { - error_node(node, "A give expression is only allowed within a procedure"); - goto error; - } - - if (ge->results.count == 0) { - error_node(node, "`give` has no results"); - goto error; - } - - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - - Array(Operand) operands; - array_init_reserve(&operands, c->tmp_allocator, 2*ge->results.count); - - for_array(i, ge->results) { - AstNode *rhs = ge->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); - } - } - } - - if (operands.count == 0) { - error_node(node, "`give` has no value"); - gb_temp_arena_memory_end(tmp); - goto error; - } else if (operands.count == 1) { - Operand operand = operands.e[0]; - Type *th = type_hint != NULL ? type_hint : c->context.type_hint; - if (th != NULL) { - convert_to_typed(c, &operand, th, 0); - } - // IMPORTANT NOTE(bill): This type could be untyped!!! - o->type = default_type(operand.type); - o->mode = Addressing_Value; - } 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) { - Operand operand = operands.e[i]; - // Type *type = default_type(operand.type); - Type *type = operand.type; - switch (operand.mode) { - case Addressing_Constant: - variables[variable_index++] = make_entity_constant(c->allocator, NULL, empty_token, type, operand.value); - break; - default: - variables[variable_index++] = make_entity_param(c->allocator, NULL, empty_token, type, false, true); - break; - } - } - tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = operands.count; - - o->type = tuple; - o->mode = Addressing_Value; - } - gb_temp_arena_memory_end(tmp); - case_end; - - case_ast_node(be, BlockExpr, node); + case_ast_node(te, TernaryExpr, node); if (c->proc_stack.count == 0) { - error_node(node, "A block expression is only allowed within a procedure"); + error_node(node, "A ternary expression is only allowed within 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--; - } - - if (be->stmts.count == 0) { - error_node(node, "Empty block expression"); - goto error; - } - - CheckerContext prev_context = c->context; - c->context.type_hint = type_hint; - check_open_scope(c, node); - check_stmt_list(c, be->stmts, Stmt_GiveAllowed); - check_close_scope(c); - - c->context = prev_context; - - AstNode *give_node = NULL; - if (!check_is_giving(node, &give_node) || give_node == NULL) { - error_node(node, "Missing give statement at end of block expression"); - goto error; - } - - GB_ASSERT(give_node != NULL && give_node->kind == AstNode_GiveExpr); - be->give_node = give_node; - - Type *type = type_of_expr(&c->info, give_node); - if (type == NULL) { - goto error; - } else if (type == t_invalid) { - o->type = t_invalid; - o->mode = Addressing_Invalid; - } else { - o->type = type; - o->mode = Addressing_Value; - } - case_end; - - case_ast_node(ie, IfExpr, node); - if (c->proc_stack.count == 0) { - error_node(node, "An if expression is only allowed within a procedure"); - goto error; - } - - check_open_scope(c, node); - - if (ie->init != NULL) { - check_stmt(c, ie->init, 0); - } - Operand operand = {Addressing_Invalid}; - check_expr(c, &operand, ie->cond); + check_expr(c, &operand, te->cond); if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) { - error_node(ie->cond, "Non-boolean condition in if expression"); + error_node(te->cond, "Non-boolean condition in if expression"); } Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; - Type *if_type = NULL; - Type *else_type = NULL; - if (type_hint) { - gb_printf_err("here\n"); - } - check_expr_with_type_hint(c, &x, ie->body, type_hint); - if_type = x.type; - - if (ie->else_expr != NULL) { - switch (ie->else_expr->kind) { - case AstNode_IfExpr: - case AstNode_BlockExpr: - check_expr_with_type_hint(c, &y, ie->else_expr, if_type); - else_type = y.type; - break; - default: - error_node(ie->else_expr, "Invalid else expression in if expression"); - break; - } + check_expr_with_type_hint(c, &x, te->x, type_hint); + + if (te->y != NULL) { + check_expr_with_type_hint(c, &y, te->y, type_hint); } else { - error_node(ie->else_expr, "An if expression must have an else expression"); - check_close_scope(c); + error_node(node, "A ternary expression must have an else clause"); goto error; } - check_close_scope(c); - - if (if_type == NULL || if_type == t_invalid || - else_type == NULL || else_type == t_invalid) { + if (x.type == NULL || x.type == t_invalid || + y.type == NULL || y.type == t_invalid) { goto error; } @@ -4465,16 +4308,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } - if (!are_types_identical(if_type, else_type)) { - gbString its = type_to_string(if_type); - gbString ets = type_to_string(else_type); - error_node(node, "Mismatched types in if expression, %s vs %s", its, ets); + if (!are_types_identical(x.type, y.type)) { + gbString its = type_to_string(x.type); + gbString ets = type_to_string(y.type); + error_node(node, "Mismatched types in ternary expression, %s vs %s", its, ets); gb_string_free(ets); gb_string_free(its); goto error; } - o->type = if_type; + o->type = x.type; o->mode = Addressing_Value; case_end; @@ -4489,7 +4332,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) { AstNode *count = cl->type->ArrayType.count; if (count->kind == AstNode_UnaryExpr && - count->UnaryExpr.op.kind == Token_Question) { + count->UnaryExpr.op.kind == Token_Ellipsis) { type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1); is_to_be_determined_array_count = true; } @@ -4820,7 +4663,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } switch (ce->token.kind) { case Token_cast: - check_conversion(c, o, t); + check_cast(c, o, t); break; case Token_transmute: { if (o->mode == Addressing_Constant) { @@ -4913,16 +4756,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } - Entity **variables = gb_alloc_array(c->allocator, Entity *, 2); - variables[0] = make_entity_param(c->allocator, NULL, empty_token, t, false, true); - variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true); - - Type *tuple = make_type_tuple(c->allocator); - tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = 2; + add_type_info_type(c, o->type); + add_type_info_type(c, t); - o->type = tuple; - o->mode = Addressing_Value; + o->type = t; + o->mode = Addressing_OptionalOk; } break; case Token_down_cast: { if (o->mode == Addressing_Constant) { @@ -5023,6 +4861,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } Type *t = base_type(type_deref(o->type)); + bool is_ptr = is_type_pointer(o->type); bool is_const = o->mode == Addressing_Constant; if (is_type_map(t)) { @@ -5039,7 +4878,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } i64 max_count = -1; - bool valid = check_set_index_data(o, t, &max_count); + bool valid = check_set_index_data(o, t, is_ptr, &max_count); if (is_const) { valid = false; @@ -5048,7 +4887,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (!valid && (is_type_struct(t) || is_type_raw_union(t))) { Entity *found = find_using_index_expr(t); if (found != NULL) { - valid = check_set_index_data(o, found->type, &max_count); + valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count); } } @@ -5125,7 +4964,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } - o->mode = Addressing_Value; + if (o->mode != Addressing_Immutable) { + o->mode = Addressing_Value; + } i64 indices[2] = {0}; AstNode *nodes[2] = {se->low, se->high}; @@ -5173,7 +5014,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } else { Type *t = base_type(o->type); if (t->kind == Type_Pointer) { - o->mode = Addressing_Variable; + if (o->mode != Addressing_Immutable) { + o->mode = Addressing_Variable; + } o->type = t->Pointer.elem; } else { gbString str = expr_to_string(o->expr); @@ -5354,12 +5197,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "}"); case_end; - case_ast_node(be, BlockExpr, node); - str = gb_string_appendc(str, "block expression"); - case_end; - case_ast_node(ie, IfExpr, node); - str = gb_string_appendc(str, "if expression"); - case_end; case_ast_node(te, TagExpr, node); str = gb_string_appendc(str, "#"); diff --git a/src/check_stmt.c b/src/check_stmt.c index bbe254615..7315f80ee 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -30,11 +30,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { case AstNode_ReturnStmt: error_node(n, "Statements after this `return` are never executed"); break; - case AstNode_ExprStmt: - if (n->ExprStmt.expr->kind == AstNode_GiveExpr) { - error_node(n, "A `give` must be the last statement in a block"); - } - break; } } @@ -182,40 +177,40 @@ bool check_is_terminating(AstNode *node) { return false; } -Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { - if (op_a->mode == Addressing_Invalid || - (op_a->type == t_invalid && op_a->mode != Addressing_Overload)) { +Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { + if (rhs->mode == Addressing_Invalid || + (rhs->type == t_invalid && rhs->mode != Addressing_Overload)) { return NULL; } - AstNode *node = unparen_expr(lhs); + AstNode *node = unparen_expr(lhs_node); // NOTE(bill): Ignore assignments to `_` if (node->kind == AstNode_Ident && str_eq(node->Ident.string, str_lit("_"))) { add_entity_definition(&c->info, node, NULL); - check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier")); - if (op_a->mode == Addressing_Invalid) { + check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier")); + if (rhs->mode == Addressing_Invalid) { return NULL; } - return op_a->type; + return rhs->type; } Entity *e = NULL; bool used = false; - Operand op_b = {Addressing_Invalid}; + Operand lhs = {Addressing_Invalid}; - check_expr(c, &op_b, lhs); - if (op_b.mode == Addressing_Invalid || - op_b.type == t_invalid) { + check_expr(c, &lhs, lhs_node); + if (lhs.mode == Addressing_Invalid || + lhs.type == t_invalid) { return NULL; } - if (op_a->mode == Addressing_Overload) { - isize overload_count = op_a->overload_count; - Entity **procs = op_a->overload_entities; + if (rhs->mode == Addressing_Overload) { + isize overload_count = rhs->overload_count; + Entity **procs = rhs->overload_entities; GB_ASSERT(procs != NULL && overload_count > 0); // NOTE(bill): These should be done @@ -227,19 +222,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { Operand x = {0}; x.mode = Addressing_Value; x.type = t; - if (check_is_assignable_to(c, &x, op_b.type)) { + if (check_is_assignable_to(c, &x, lhs.type)) { e = procs[i]; - add_entity_use(c, op_a->expr, e); + add_entity_use(c, rhs->expr, e); break; } } if (e != NULL) { // HACK TODO(bill): Should the entities be freed as it's technically a leak - op_a->mode = Addressing_Value; - op_a->type = e->type; - op_a->overload_count = 0; - op_a->overload_entities = NULL; + rhs->mode = Addressing_Value; + rhs->type = e->type; + rhs->overload_count = 0; + rhs->overload_entities = NULL; } } else { if (node->kind == AstNode_Ident) { @@ -256,43 +251,60 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { e->flags |= EntityFlag_Used; } - Type *assignment_type = op_b.type; - switch (op_b.mode) { + Type *assignment_type = lhs.type; + switch (lhs.mode) { case Addressing_Invalid: return NULL; + case Addressing_Variable: - case Addressing_MapIndex: break; + case Addressing_MapIndex: { + AstNode *ln = unparen_expr(lhs_node); + if (ln->kind == AstNode_IndexExpr) { + AstNode *x = ln->IndexExpr.expr; + TypeAndValue *tav = type_and_value_of_expression(&c->info, x); + GB_ASSERT(tav != NULL); + if (tav->mode != Addressing_Variable) { + if (!is_type_pointer(tav->type)) { + gbString str = expr_to_string(lhs.expr); + error_node(lhs.expr, "Cannot assign to the value of a map `%s`", str); + gb_string_free(str); + return NULL; + } + } + } + } break; + default: { - if (op_b.expr->kind == AstNode_SelectorExpr) { + if (lhs.expr->kind == AstNode_SelectorExpr) { // NOTE(bill): Extra error checks Operand op_c = {Addressing_Invalid}; - ast_node(se, SelectorExpr, op_b.expr); + ast_node(se, SelectorExpr, lhs.expr); check_expr(c, &op_c, se->expr); if (op_c.mode == Addressing_MapIndex) { - gbString str = expr_to_string(op_b.expr); - error_node(op_b.expr, "Cannot assign to record field `%s` in map", str); + gbString str = expr_to_string(lhs.expr); + error_node(lhs.expr, "Cannot assign to record field `%s` in map", str); gb_string_free(str); return NULL; } } - gbString str = expr_to_string(op_b.expr); - if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) { - error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str); + gbString str = expr_to_string(lhs.expr); + if (lhs.mode == Addressing_Immutable) { + error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str); } else { - error_node(op_b.expr, "Cannot assign to `%s`", str); + error_node(lhs.expr, "Cannot assign to `%s`", str); } gb_string_free(str); } break; } - check_assignment(c, op_a, assignment_type, str_lit("assignment")); - if (op_a->mode == Addressing_Invalid) { + check_assignment(c, rhs, assignment_type, str_lit("assignment")); + if (rhs->mode == Addressing_Invalid) { return NULL; } - return op_a->type; + return rhs->type; } bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) { @@ -396,12 +408,6 @@ 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); @@ -419,40 +425,34 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { switch (as->op.kind) { case Token_Eq: { // a, b, c = 1, 2, 3; // Multisided - if (as->lhs.count == 0) { + + isize lhs_count = as->lhs.count; + if (lhs_count == 0) { error(as->op, "Missing lhs in assignment statement"); return; } + // TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just + // leave it? + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation - Array(Operand) operands; - array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count); + ArrayOperand operands = {0}; + array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count); + check_unpack_arguments(c, lhs_count, &operands, as->rhs, true); - for_array(i, as->rhs) { - AstNode *rhs = as->rhs.e[i]; - Operand o = {0}; - check_multi_expr(c, &o, rhs); - 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); - } + isize rhs_count = operands.count; + for_array(i, operands) { + if (operands.e[i].mode == Addressing_Invalid) { + rhs_count--; } } - isize lhs_count = as->lhs.count; - isize rhs_count = operands.count; - - isize operand_count = gb_min(as->lhs.count, operands.count); - for (isize i = 0; i < operand_count; i++) { - AstNode *lhs = as->lhs.e[i]; - check_assignment_variable(c, &operands.e[i], lhs); + isize max = gb_min(lhs_count, rhs_count); + for (isize i = 0; i < max; i++) { + check_assignment_variable(c, &operands.e[i], as->lhs.e[i]); } if (lhs_count != rhs_count) { error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); diff --git a/src/checker.c b/src/checker.c index 7c37f0601..3bb76245f 100644 --- a/src/checker.c +++ b/src/checker.c @@ -106,29 +106,29 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { }; +#include "types.c" typedef enum AddressingMode { - Addressing_Invalid, - - Addressing_NoValue, - Addressing_Value, - Addressing_Variable, - Addressing_Constant, - Addressing_Type, - Addressing_Builtin, - Addressing_Overload, - Addressing_MapIndex, - - Addressing_Count, + Addressing_Invalid, // invalid addressing mode + Addressing_NoValue, // no value (void in C) + Addressing_Value, // computed value (rvalue) + Addressing_Immutable, // immutable computed value (const rvalue) + Addressing_Variable, // addressable variable (lvalue) + Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named) + Addressing_Type, // type + Addressing_Builtin, // built in procedure + Addressing_Overload, // overloaded procedure + Addressing_MapIndex, // map index expression - + // lhs: acts like a Variable + // rhs: acts like OptionalOk + Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check) } AddressingMode; -#include "types.c" - -#define MAP_TYPE Entity * -#define MAP_PROC map_entity_ -#define MAP_NAME MapEntity -#include "map.c" - +// Operand is used as an intermediate value whilst checking +// Operands store an addressing mode, the expression being evaluated, +// its type and node, and other specific information for certain +// addressing modes +// Its zero-value is a valid "invalid operand" typedef struct Operand { AddressingMode mode; Type * type; @@ -149,7 +149,9 @@ bool is_operand_value(Operand o) { switch (o.mode) { case Addressing_Value: case Addressing_Variable: + case Addressing_Immutable: case Addressing_Constant: + case Addressing_MapIndex: return true; } return false; @@ -159,7 +161,7 @@ bool is_operand_nil(Operand o) { } - +// DeclInfo is used to store information of certain declarations to allow for "any order" usage typedef struct DeclInfo { Scope *scope; @@ -173,6 +175,17 @@ typedef struct DeclInfo { MapBool deps; // Key: Entity * } DeclInfo; +// ProcedureInfo stores the information needed for checking a procedure +typedef struct ProcedureInfo { + AstFile * file; + Token token; + DeclInfo *decl; + Type * type; // Type_Procedure + AstNode * body; // AstNode_BlockStmt + u32 tags; +} ProcedureInfo; + +// ExprInfo stores information used for "untyped" expressions typedef struct ExprInfo { bool is_lhs; // Debug info AddressingMode mode; @@ -185,14 +198,12 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue return ei; } -typedef struct ProcedureInfo { - AstFile * file; - Token token; - DeclInfo *decl; - Type * type; // Type_Procedure - AstNode * body; // AstNode_BlockStmt - u32 tags; -} ProcedureInfo; + + +#define MAP_TYPE Entity * +#define MAP_PROC map_entity_ +#define MAP_NAME MapEntity +#include "map.c" typedef struct Scope { Scope * parent; @@ -256,7 +267,7 @@ typedef struct CheckerContext { Type * type_hint; } CheckerContext; -// NOTE(bill): Symbol tables +// CheckerInfo stores all the symbol information for a type-checked program typedef struct CheckerInfo { MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value) MapEntity definitions; // Key: AstNode * | Identifier -> Entity @@ -389,9 +400,7 @@ void check_open_scope(Checker *c, AstNode *node) { node = unparen_expr(node); GB_ASSERT(node->kind == AstNode_Invalid || is_ast_node_stmt(node) || - is_ast_node_type(node) || - node->kind == AstNode_BlockExpr || - node->kind == AstNode_IfExpr ); + is_ast_node_type(node)); Scope *scope = make_scope(c->context.scope, c->allocator); add_scope(c, node, scope); if (node->kind == AstNode_ProcType) { diff --git a/src/common.c b/src/common.c index f09282b5a..2c40e22ed 100644 --- a/src/common.c +++ b/src/common.c @@ -131,6 +131,9 @@ i16 f32_to_f16(f32 value) { // //////////////////////////////////////////////////////////////// +typedef Array(i32) Array_i32; +typedef Array(isize) Array_isize; + #define MAP_TYPE String #define MAP_PROC map_string_ diff --git a/src/entity.c b/src/entity.c index 04ef323a1..99acef870 100644 --- a/src/entity.c +++ b/src/entity.c @@ -40,12 +40,15 @@ typedef enum EntityFlag { EntityFlag_TypeField = 1<<8, } EntityFlag; +// Zero value means the overloading process is not yet done typedef enum OverloadKind { - Overload_No = -1, - Overload_Unknown = 0, - Overload_Yes = +1, + Overload_Unknown, + Overload_No, + Overload_Yes, } OverloadKind; + +// An Entity is a named "thing" in the language typedef struct Entity Entity; struct Entity { EntityKind kind; @@ -2462,13 +2462,19 @@ irValue *ir_emit_down_cast(irProcedure *proc, irValue *value, Type *t) { return ir_emit_conv(proc, head, t); } -irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) { - GB_ASSERT(tuple->kind == Type_Tuple); +irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) { gbAllocator a = proc->module->allocator; Type *src_type = ir_type(value); bool is_ptr = is_type_pointer(src_type); + bool is_tuple = true; + Type *tuple = type; + if (type->kind != Type_Tuple) { + is_tuple = false; + tuple = make_optional_ok_type(a, type); + } + irValue *v = ir_add_local_generated(proc, tuple); if (is_ptr) { @@ -2541,6 +2547,25 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) { ir_start_block(proc, end_block); } + + if (!is_tuple) { + // NOTE(bill): Panic on invalid conversion + Type *dst_type = tuple->Tuple.variables[0]->type; + + irValue *ok = ir_emit_load(proc, ir_emit_struct_ep(proc, v, 1)); + irValue **args = gb_alloc_array(a, irValue *, 6); + args[0] = ok; + + args[1] = ir_make_const_string(a, pos.file); + args[2] = ir_make_const_int(a, pos.line); + args[3] = ir_make_const_int(a, pos.column); + + args[4] = ir_type_info(proc, src_type); + args[5] = ir_type_info(proc, dst_type); + ir_emit_global_call(proc, "__union_cast_check", args, 6); + + return ir_emit_load(proc, ir_emit_struct_ep(proc, v, 0)); + } return ir_emit_load(proc, v); } @@ -2826,25 +2851,40 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; - case_ast_node(be, BlockExpr, expr); - ir_emit_comment(proc, str_lit("BlockExpr")); - ir_open_scope(proc); + case_ast_node(te, TernaryExpr, expr); + ir_emit_comment(proc, str_lit("TernaryExpr")); + + irValueArray edges = {0}; + array_init_reserve(&edges, proc->module->allocator, 2); - AstNodeArray stmts = be->stmts; - stmts.count--; - ir_build_stmt_list(proc, stmts); + GB_ASSERT(te->y != NULL); + irBlock *then = ir_new_block(proc, NULL, "if.then"); + irBlock *done = ir_new_block(proc, NULL, "if.done"); // NOTE(bill): Append later + irBlock *else_ = ir_new_block(proc, NULL, "if.else"); - 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); - irValue *value = ir_build_expr(proc, give_expr); + irValue *cond = ir_build_cond(proc, te->cond, then, else_); + ir_start_block(proc, then); + ir_open_scope(proc); + array_add(&edges, ir_build_expr(proc, te->x)); ir_close_scope(proc, irDeferExit_Default, NULL); - return value; + ir_emit_jump(proc, done); + ir_start_block(proc, else_); + + ir_open_scope(proc); + array_add(&edges, ir_build_expr(proc, te->y)); + ir_close_scope(proc, irDeferExit_Default, NULL); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + + Type *type = type_of_expr(proc->module->info, expr); + + return ir_emit(proc, ir_make_instr_phi(proc, edges, type)); case_end; +#if 0 case_ast_node(ie, IfExpr, expr); ir_emit_comment(proc, str_lit("IfExpr")); if (ie->init != NULL) { @@ -2883,70 +2923,27 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv return ir_emit(proc, ir_make_instr_phi(proc, edges, type)); case_end; - - case_ast_node(ge, GiveExpr, expr); - ir_emit_comment(proc, str_lit("GiveExpr")); - - irValue *v = NULL; - Type *give_type = type_of_expr(proc->module->info, expr); - GB_ASSERT(give_type != NULL); - if (give_type->kind != Type_Tuple) { - v = ir_emit_conv(proc, ir_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); - - irValueArray results; - array_init_reserve(&results, proc->module->tmp_allocator, tuple->variable_count); - - for_array(res_index, ge->results) { - irValue *res = ir_build_expr(proc, ge->results.e[res_index]); - Type *t = ir_type(res); - if (t->kind == Type_Tuple) { - for (isize i = 0; i < t->Tuple.variable_count; i++) { - Entity *e = t->Tuple.variables[i]; - irValue *v = ir_emit_struct_ev(proc, res, i); - array_add(&results, v); - } - } else { - array_add(&results, res); - } - } - - v = ir_add_local_generated(proc, give_type); - for_array(i, results) { - Entity *e = tuple->variables[i]; - irValue *res = ir_emit_conv(proc, results.e[i], e->type); - irValue *field = ir_emit_struct_ep(proc, v, i); - ir_emit_store(proc, field, res); - } - v = ir_emit_load(proc, v); - - gb_temp_arena_memory_end(tmp); - } - - return v; - case_end; +#endif case_ast_node(ce, CastExpr, expr); Type *type = tv->type; - irValue *expr = ir_build_expr(proc, ce->expr); + irValue *e = ir_build_expr(proc, ce->expr); switch (ce->token.kind) { case Token_cast: ir_emit_comment(proc, str_lit("cast - cast")); - return ir_emit_conv(proc, expr, type); + return ir_emit_conv(proc, e, type); case Token_transmute: ir_emit_comment(proc, str_lit("cast - transmute")); - return ir_emit_transmute(proc, expr, type); + return ir_emit_transmute(proc, e, type); case Token_down_cast: ir_emit_comment(proc, str_lit("cast - down_cast")); - return ir_emit_down_cast(proc, expr, type); + return ir_emit_down_cast(proc, e, type); case Token_union_cast: ir_emit_comment(proc, str_lit("cast - union_cast")); - return ir_emit_union_cast(proc, expr, type); + return ir_emit_union_cast(proc, e, type, ast_node_token(expr).pos); default: GB_PANIC("Unknown cast expression"); @@ -3384,7 +3381,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv args[1] = ir_make_const_int(proc->module->allocator, pos.line); args[2] = ir_make_const_int(proc->module->allocator, pos.column); args[3] = msg; - ir_emit_global_call(proc, "__assert", args, 4); + ir_emit_global_call(proc, "__panic", args, 4); return NULL; } break; @@ -6,6 +6,9 @@ #define MAP_NAME MapString #include "map.c" */ +// A `Map` is an unordered hash table which can allow for a key to point to multiple values +// with the use of the `multi_*` procedures. +// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out #ifndef MAP_UTIL_STUFF #define MAP_UTIL_STUFF diff --git a/src/parser.c b/src/parser.c index b5d8f442b..52343b649 100644 --- a/src/parser.c +++ b/src/parser.c @@ -111,7 +111,9 @@ AstNodeArray make_ast_node_array(AstFile *f) { } - +// NOTE(bill): This massive define is so it is possible to create a discriminated union (and extra debug info) +// for the AstNode. I personally prefer discriminated unions over subtype polymorphism as I can preallocate +// all the nodes and even memcpy in a different kind of node #define AST_NODE_KINDS \ AST_NODE_KIND(Ident, "identifier", Token) \ AST_NODE_KIND(Implicit, "implicit", Token) \ @@ -166,24 +168,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \ Token open; \ Token close; \ }) \ - AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \ - 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(IfExpr, "if expression", struct { \ - Token token; \ - AstNode *init; \ - AstNode *cond; \ - AstNode *body; \ - AstNode *else_expr; \ - }) \ + AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \ + AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \ + AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \ AST_NODE_KIND(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \ AST_NODE_KIND(_ExprEnd, "", i32) \ AST_NODE_KIND(_StmtBegin, "", i32) \ @@ -463,9 +450,7 @@ Token ast_node_token(AstNode *node) { case AstNode_CastExpr: return node->CastExpr.token; case AstNode_FieldValue: return node->FieldValue.eq; case AstNode_DerefExpr: return node->DerefExpr.op; - case AstNode_BlockExpr: return node->BlockExpr.open; - case AstNode_GiveExpr: return node->GiveExpr.token; - case AstNode_IfExpr: return node->IfExpr.token; + case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond); case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left); case AstNode_BadStmt: return node->BadStmt.begin; @@ -766,29 +751,11 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o return result; } - -AstNode *ast_block_expr(AstFile *f, AstNodeArray stmts, Token open, Token close) { - AstNode *result = make_ast_node(f, AstNode_BlockExpr); - result->BlockExpr.stmts = stmts; - result->BlockExpr.open = open; - result->BlockExpr.close = close; - return result; -} - -AstNode *ast_give_expr(AstFile *f, Token token, AstNodeArray results) { - AstNode *result = make_ast_node(f, AstNode_GiveExpr); - result->GiveExpr.token = token; - result->GiveExpr.results = results; - return result; -} - -AstNode *ast_if_expr(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body, AstNode *else_expr) { - AstNode *result = make_ast_node(f, AstNode_IfExpr); - result->IfExpr.token = token; - result->IfExpr.init = init; - result->IfExpr.cond = cond; - result->IfExpr.body = body; - result->IfExpr.else_expr = else_expr; +AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) { + AstNode *result = make_ast_node(f, AstNode_TernaryExpr); + result->TernaryExpr.cond = cond; + result->TernaryExpr.x = x; + result->TernaryExpr.y = y; return result; } @@ -1319,13 +1286,13 @@ void expect_semicolon(AstFile *f, AstNode *s) { return; } } else { - switch (s->kind) { - case AstNode_GiveExpr: - if (f->curr_token.kind == Token_CloseBrace) { - return; - } - break; - } + // switch (s->kind) { + // case AstNode_GiveExpr: + // if (f->curr_token.kind == Token_CloseBrace) { + // return; + // } + // break; + // } } syntax_error(prev_token, "Expected `;` after %.*s, got %.*s", LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind])); @@ -1610,72 +1577,72 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { -AstNode *parse_block_expr(AstFile *f) { - 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 ast_block_expr(f, stmts, open, close); -} - -AstNode *parse_if_expr(AstFile *f) { - if (f->curr_proc == NULL) { - syntax_error(f->curr_token, "You cannot use an if expression in the file scope"); - return ast_bad_stmt(f, f->curr_token, f->curr_token); - } - - Token token = expect_token(f, Token_if); - AstNode *init = NULL; - AstNode *cond = NULL; - AstNode *body = NULL; - AstNode *else_expr = NULL; - - isize prev_level = f->expr_level; - f->expr_level = -1; - - if (allow_token(f, Token_Semicolon)) { - cond = parse_expr(f, false); - } else { - init = parse_simple_stmt(f, false); - if (allow_token(f, Token_Semicolon)) { - cond = parse_expr(f, false); - } else { - cond = convert_stmt_to_expr(f, init, str_lit("boolean expression")); - init = NULL; - } - } - - f->expr_level = prev_level; - - if (cond == NULL) { - syntax_error(f->curr_token, "Expected condition for if statement"); - } - - body = parse_block_expr(f); - - if (allow_token(f, Token_else)) { - switch (f->curr_token.kind) { - case Token_if: - else_expr = parse_if_expr(f); - break; - case Token_OpenBrace: - else_expr = parse_block_expr(f); - break; - default: - syntax_error(f->curr_token, "Expected if expression block statement"); - else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); - break; - } - } else { - syntax_error(f->curr_token, "An if expression must have an else clause"); - return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); - } - - return ast_if_expr(f, token, init, cond, body, else_expr); -} +// AstNode *parse_block_expr(AstFile *f) { +// 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 ast_block_expr(f, stmts, open, close); +// } + +// AstNode *parse_if_expr(AstFile *f) { +// if (f->curr_proc == NULL) { +// syntax_error(f->curr_token, "You cannot use an if expression in the file scope"); +// return ast_bad_stmt(f, f->curr_token, f->curr_token); +// } + +// Token token = expect_token(f, Token_if); +// AstNode *init = NULL; +// AstNode *cond = NULL; +// AstNode *body = NULL; +// AstNode *else_expr = NULL; + +// isize prev_level = f->expr_level; +// f->expr_level = -1; + +// if (allow_token(f, Token_Semicolon)) { +// cond = parse_expr(f, false); +// } else { +// init = parse_simple_stmt(f, false); +// if (allow_token(f, Token_Semicolon)) { +// cond = parse_expr(f, false); +// } else { +// cond = convert_stmt_to_expr(f, init, str_lit("boolean expression")); +// init = NULL; +// } +// } + +// f->expr_level = prev_level; + +// if (cond == NULL) { +// syntax_error(f->curr_token, "Expected condition for if statement"); +// } + +// body = parse_block_expr(f); + +// if (allow_token(f, Token_else)) { +// switch (f->curr_token.kind) { +// case Token_if: +// else_expr = parse_if_expr(f); +// break; +// case Token_OpenBrace: +// else_expr = parse_block_expr(f); +// break; +// default: +// syntax_error(f->curr_token, "Expected if expression block statement"); +// else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); +// break; +// } +// } else { +// syntax_error(f->curr_token, "An if expression must have an else clause"); +// return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); +// } + +// return ast_if_expr(f, token, init, cond, body, else_expr); +// } AstNode *parse_operand(AstFile *f, bool lhs) { AstNode *operand = NULL; // Operand @@ -1789,16 +1756,16 @@ AstNode *parse_operand(AstFile *f, bool lhs) { return type; } - case Token_if: - if (!lhs && f->expr_level >= 0) { - return parse_if_expr(f); - } - break; - case Token_OpenBrace: - if (!lhs && f->expr_level >= 0) { - return parse_block_expr(f); - } - break; + // case Token_if: + // if (!lhs && f->expr_level >= 0) { + // return parse_if_expr(f); + // } + // break; + // case Token_OpenBrace: + // if (!lhs && f->expr_level >= 0) { + // return parse_block_expr(f); + // } + // break; default: { AstNode *type = parse_type_or_ident(f); @@ -1982,6 +1949,19 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { } break; + case Token_Question: + if (!lhs && operand != NULL && f->expr_level >= 0) { + AstNode *cond = operand; + Token token_q = expect_token(f, Token_Question); + AstNode *x = parse_expr(f, false); + Token token_c = expect_token(f, Token_Colon); + AstNode *y = parse_expr(f, false); + operand = ast_ternary_expr(f, cond, x, y); + } else { + loop = false; + } + break; + default: loop = false; break; @@ -2358,7 +2338,7 @@ bool is_token_field_prefix(TokenKind kind) { switch (kind) { case Token_using: case Token_no_alias: - // case Token_immutable: + case Token_immutable: return true; } return false; @@ -2374,7 +2354,7 @@ u32 parse_field_prefixes(AstFile *f) { switch (f->curr_token.kind) { case Token_using: using_count += 1; next_token(f); break; case Token_no_alias: no_alias_count += 1; next_token(f); break; - // case Token_immutable: immutable_count += 1; next_token(f); break; + case Token_immutable: immutable_count += 1; next_token(f); break; } } if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list"); @@ -2572,8 +2552,8 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *count_expr = NULL; bool is_vector = false; - if (f->curr_token.kind == Token_Question) { - count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL); + if (f->curr_token.kind == Token_Ellipsis) { + count_expr = ast_unary_expr(f, expect_token(f, Token_Ellipsis), NULL); } else if (f->curr_token.kind == Token_vector) { next_token(f); if (f->curr_token.kind != Token_CloseBracket) { @@ -2584,7 +2564,7 @@ AstNode *parse_type_or_ident(AstFile *f) { syntax_error(f->curr_token, "Vector type missing count"); } is_vector = true; - } else if (f->curr_token.kind == Token_Ellipsis) { + } else if (f->curr_token.kind == Token_dynamic) { next_token(f); expect_token(f, Token_CloseBracket); return ast_dynamic_array_type(f, token, parse_type(f)); @@ -2923,27 +2903,27 @@ AstNode *parse_return_stmt(AstFile *f) { } -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 ast_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 ast_bad_stmt(f, f->curr_token, f->curr_token); - } - - Token token = expect_token(f, Token_give); - AstNodeArray results; - if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { - results = parse_rhs_expr_list(f); - } else { - results = make_ast_node_array(f); - } - AstNode *ge = ast_give_expr(f, token, results); - expect_semicolon(f, ge); - return ast_expr_stmt(f, ge); -} +// 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 ast_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 ast_bad_stmt(f, f->curr_token, f->curr_token); +// } + +// Token token = expect_token(f, Token_give); +// AstNodeArray results; +// if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { +// results = parse_rhs_expr_list(f); +// } else { +// results = make_ast_node_array(f); +// } +// AstNode *ge = ast_give_expr(f, token, results); +// expect_semicolon(f, ge); +// return ast_expr_stmt(f, ge); +// } AstNode *parse_for_stmt(AstFile *f) { if (f->curr_proc == NULL) { @@ -3225,7 +3205,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_give: return parse_give_stmt(f); case Token_break: case Token_continue: @@ -3272,7 +3252,7 @@ AstNode *parse_stmt(AstFile *f) { return ast_bad_stmt(f, token, f->curr_token); } break; -#if 0 +#if 1 case Token_immutable: { Token token = expect_token(f, Token_immutable); AstNode *node = parse_stmt(f); diff --git a/src/string.c b/src/string.c index 38874a7d5..19161de93 100644 --- a/src/string.c +++ b/src/string.c @@ -19,6 +19,7 @@ typedef struct String { #define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1} +// NOTE(bill): String16 is only used for Windows due to its file directories typedef struct String16 { wchar_t *text; isize len; diff --git a/src/tokenizer.c b/src/tokenizer.c index f2cabfb02..68ab270be 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -99,9 +99,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_raw_union, "raw_union"), \ TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_vector, "vector"), \ + TOKEN_KIND(Token_static, "static"), \ + TOKEN_KIND(Token_dynamic, "dynamic"), \ TOKEN_KIND(Token_map, "map"), \ TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_no_alias, "no_alias"), \ + TOKEN_KIND(Token_immutable, "immutable"), \ TOKEN_KIND(Token_cast, "cast"), \ TOKEN_KIND(Token_transmute, "transmute"), \ TOKEN_KIND(Token_down_cast, "down_cast"), \ diff --git a/src/types.c b/src/types.c index 6c0524955..06a407576 100644 --- a/src/types.c +++ b/src/types.c @@ -178,8 +178,9 @@ typedef struct Type { bool failure; } Type; -typedef Array(i32) Array_i32; +// TODO(bill): Should I add extra information here specifying the kind of selection? +// e.g. field, constant, vector field, type field, etc. typedef struct Selection { Entity * entity; Array_i32 index; @@ -195,6 +196,7 @@ Selection make_selection(Entity *entity, Array_i32 index, bool indirect) { void selection_add_index(Selection *s, isize index) { // IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form // of heap allocation + // TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3 if (s->index.e == NULL) { array_init(&s->index, heap_allocator()); } @@ -277,6 +279,7 @@ gb_global Type *t_byte_slice = NULL; gb_global Type *t_string_slice = NULL; +// Type generated for the "preload" file gb_global Type *t_type_info = NULL; gb_global Type *t_type_info_record = NULL; gb_global Type *t_type_info_enum_value = NULL; @@ -303,7 +306,6 @@ gb_global Type *t_type_info_raw_union = NULL; gb_global Type *t_type_info_enum = NULL; gb_global Type *t_type_info_map = NULL; - gb_global Type *t_type_info_named_ptr = NULL; gb_global Type *t_type_info_integer_ptr = NULL; gb_global Type *t_type_info_float_ptr = NULL; @@ -323,8 +325,6 @@ gb_global Type *t_type_info_raw_union_ptr = NULL; gb_global Type *t_type_info_enum_ptr = NULL; gb_global Type *t_type_info_map_ptr = NULL; - - gb_global Type *t_allocator = NULL; gb_global Type *t_allocator_ptr = NULL; gb_global Type *t_context = NULL; @@ -337,14 +337,15 @@ gb_global Type *t_map_header = NULL; -i64 type_size_of (gbAllocator allocator, Type *t); -i64 type_align_of (gbAllocator allocator, Type *t); -i64 type_offset_of(gbAllocator allocator, Type *t, i32 index); - +i64 type_size_of (gbAllocator allocator, Type *t); +i64 type_align_of (gbAllocator allocator, Type *t); +i64 type_offset_of (gbAllocator allocator, Type *t, i32 index); gbString type_to_string(Type *type); + + Type *base_type(Type *t) { for (;;) { if (t == NULL) { |