diff --git a/code/demo.odin b/code/demo.odin index 9fb3e9aad..4b4781323 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -10,46 +10,45 @@ #import "utf8.odin"; main :: proc() { - foo :: proc(x: ^i32) -> (int, int) { - fmt.println("^int"); - return 123, int(x^); - } - foo :: proc(x: rawptr) { - fmt.println("rawptr"); - } + // foo :: proc(x: ^i32) -> (int, int) { + // fmt.println("^int"); + // return 123, int(x^); + // } + // foo :: proc(x: rawptr) { + // fmt.println("rawptr"); + // } + // THINGI :: 14451; + // THINGF :: 14451.1; - THINGI :: 14451; - THINGF :: 14451.1; + // a: i32 = 111111; + // b: f32; + // c: rawptr; + // fmt.println(foo(^a)); + // foo(^b); + // foo(c); + // // foo(nil); + // atomic.store(^a, 1); - a: i32 = 111111; - b: f32; - c: rawptr; - fmt.println(foo(^a)); - foo(^b); - foo(c); - // foo(nil); - atomic.store(^a, 1); + // foo :: proc() { + // fmt.printf("Zero args\n"); + // } + // foo :: proc(i: int) { + // fmt.printf("int arg, i=%d\n", i); + // } + // foo :: proc(f: f64) { + // i := int(f); + // fmt.printf("f64 arg, f=%d\n", i); + // } - foo :: proc() { - fmt.printf("Zero args\n"); - } - foo :: proc(i: int) { - fmt.printf("int arg, i=%d\n", i); - } - foo :: proc(f: f64) { - i := int(f); - fmt.printf("f64 arg, f=%d\n", i); - } + // foo(); + // // foo(THINGI); + // foo(THINGF); + // foo(int(THINGI)); + // fmt.println(THINGI); + // fmt.println(THINGF); - foo(); - foo(int(THINGI)); - // foo(THINGI); - foo(THINGF); - fmt.println(THINGI); - fmt.println(THINGF); - - f: proc(); - f = foo; - f(); + // f: proc(); + // f = foo; + // f(); } diff --git a/core/fmt.odin b/core/fmt.odin index 91b83cc3a..d23fca9ce 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -890,7 +890,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, verb: rune, prec, bit_size: int) -> } - return buf[:0]; + return buf[:i]; } fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) { diff --git a/src/check_expr.c b/src/check_expr.c index 9ba5f4db2..06ba49d9d 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -26,6 +26,23 @@ gb_inline Type *check_type(Checker *c, AstNode *expression) { } +void error_operand_not_expression(Operand *o) { + if (o->mode == Addressing_Type) { + gbString err = expr_to_string(o->expr); + error_node(o->expr, "`%s` is not an expression", err); + gb_string_free(err); + o->mode = Addressing_Invalid; + } +} + +void error_operand_no_value(Operand *o) { + if (o->mode == Addressing_NoValue) { + gbString err = expr_to_string(o->expr); + error_node(o->expr, "`%s` used as value", err); + gb_string_free(err); + o->mode = Addressing_Invalid; + } +} void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size) { @@ -1547,8 +1564,19 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { } void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) { - gbString err_str = NULL; + if (x->mode == Addressing_Type && y->mode == Addressing_Type) { + bool comp = are_types_identical(x->type, y->type); + switch (op) { + case Token_CmpEq: comp = comp; break; + case Token_NotEq: comp = !comp; break; + } + x->mode = Addressing_Constant; + x->type = t_untyped_bool; + x->value = make_exact_value_bool(comp); + return; + } + gbString err_str = NULL; gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); if (check_is_assignable_to(c, x, y->type) || check_is_assignable_to(c, y, x->type)) { @@ -1905,208 +1933,36 @@ void check_conversion(Checker *c, Operand *x, Type *type) { x->type = type; } + + void check_binary_expr(Checker *c, Operand *x, AstNode *node) { GB_ASSERT(node->kind == AstNode_BinaryExpr); Operand y_ = {0}, *y = &y_; ast_node(be, BinaryExpr, node); -#if 0 - switch (be->op.kind) { - case Token_as: { - check_expr(c, x, be->left); - Type *type = check_type(c, be->right); - if (x->mode == Addressing_Invalid) { - return; + Token op = be->op; + switch (op.kind) { + case Token_CmpEq: + case Token_NotEq: { + // NOTE(bill): Allow comparisons between types + check_expr_or_type(c, x, be->left); + check_expr_or_type(c, y, be->right); + bool xt = x->mode == Addressing_Type; + bool yt = y->mode == Addressing_Type; + // If only one is a type, this is an error + if (xt ^ yt) { + GB_ASSERT(xt != yt); + if (xt) error_operand_not_expression(x); + if (yt) error_operand_not_expression(y); } - check_conversion(c, x, type); - return; } break; - case Token_transmute: { + + default: 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); - error_node(x->expr, "Cannot transmute constant expression: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - if (is_type_untyped(x->type)) { - gbString expr_str = expr_to_string(x->expr); - error_node(x->expr, "Cannot transmute untyped expression: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - i64 srcz = type_size_of(c->sizes, c->allocator, x->type); - i64 dstz = type_size_of(c->sizes, c->allocator, type); - if (srcz != dstz) { - gbString expr_str = expr_to_string(x->expr); - gbString type_str = type_to_string(type); - error_node(x->expr, "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, srcz, dstz); - gb_string_free(type_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - x->type = type; - - return; - } break; - case Token_down_cast: { - 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(node); - error_node(node, "Cannot `down_cast` a constant expression: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - if (is_type_untyped(x->type)) { - gbString expr_str = expr_to_string(node); - error_node(node, "Cannot `down_cast` an untyped expression: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - if (!(is_type_pointer(x->type) && is_type_pointer(type))) { - gbString expr_str = expr_to_string(node); - error_node(node, "Can only `down_cast` pointers: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - Type *src = type_deref(x->type); - Type *dst = type_deref(type); - Type *bsrc = base_type(src); - Type *bdst = base_type(dst); - - if (!(is_type_struct(bsrc) || is_type_raw_union(bsrc))) { - gbString expr_str = expr_to_string(node); - error_node(node, "Can only `down_cast` pointer from structs or unions: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - if (!(is_type_struct(bdst) || is_type_raw_union(bdst))) { - gbString expr_str = expr_to_string(node); - error_node(node, "Can only `down_cast` pointer to structs or unions: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - String param_name = check_down_cast_name(dst, src); - if (param_name.len == 0) { - gbString expr_str = expr_to_string(node); - error_node(node, "Illegal `down_cast`: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - x->mode = Addressing_Value; - x->type = type; - return; - } break; - case Token_union_cast: { - 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(node); - error_node(node, "Cannot `union_cast` a constant expression: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - if (is_type_untyped(x->type)) { - gbString expr_str = expr_to_string(node); - error_node(node, "Cannot `union_cast` an untyped expression: `%s`", expr_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - bool src_is_ptr = is_type_pointer(x->type); - bool dst_is_ptr = is_type_pointer(type); - Type *src = type_deref(x->type); - Type *dst = type_deref(type); - Type *bsrc = base_type(src); - Type *bdst = base_type(dst); - - if (src_is_ptr != dst_is_ptr) { - gbString src_type_str = type_to_string(x->type); - gbString dst_type_str = type_to_string(type); - error_node(node, "Invalid `union_cast` types: `%s` and `%s`", src_type_str, dst_type_str); - gb_string_free(dst_type_str); - gb_string_free(src_type_str); - x->mode = Addressing_Invalid; - return; - } - - if (!is_type_union(src)) { - error_node(node, "`union_cast` can only operate on unions"); - x->mode = Addressing_Invalid; - return; - } - - bool ok = false; - for (isize i = 1; i < bsrc->Record.field_count; i++) { - Entity *f = bsrc->Record.fields[i]; - if (are_types_identical(f->type, dst)) { - ok = true; - break; - } - } - - if (!ok) { - gbString expr_str = expr_to_string(node); - gbString dst_type_str = type_to_string(type); - error_node(node, "Cannot `union_cast` `%s` to `%s`", expr_str, dst_type_str); - gb_string_free(dst_type_str); - gb_string_free(expr_str); - x->mode = Addressing_Invalid; - return; - } - - Entity **variables = gb_alloc_array(c->allocator, Entity *, 2); - variables[0] = make_entity_param(c->allocator, NULL, empty_token, type, false); - variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false); - - Type *tuple = make_type_tuple(c->allocator); - tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = 2; - - x->type = tuple; - x->mode = Addressing_Value; - return; - } break; + check_expr(c, y, be->right); + break; } -#endif - check_expr(c, x, be->left); - check_expr(c, y, be->right); if (x->mode == Addressing_Invalid) { return; } @@ -2116,8 +1972,6 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { return; } - Token op = be->op; - if (token_is_shift(op)) { check_shift(c, x, y, node); return; @@ -2339,6 +2193,7 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level) { GB_ASSERT_NOT_NULL(target_type); if (operand->mode == Addressing_Invalid || + operand->mode == Addressing_Type || is_type_typed(operand->type) || target_type == t_invalid) { return; @@ -2441,7 +2296,7 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val } if (operand.mode == Addressing_Constant && - (c->context.stmt_state_flags & StmtStateFlag_bounds_check) != 0) { + (c->context.stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) { i64 i = exact_value_to_integer(operand.value).value_integer; if (i < 0) { gbString expr_str = expr_to_string(operand.expr); @@ -4958,23 +4813,19 @@ ExprKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) } + void check_multi_expr(Checker *c, Operand *o, AstNode *e) { - gbString err_str = NULL; check_expr_base(c, o, e, NULL); switch (o->mode) { default: return; // NOTE(bill): Valid - case Addressing_NoValue: - err_str = expr_to_string(e); - error_node(e, "`%s` used as value", err_str); + error_operand_no_value(o); break; case Addressing_Type: - err_str = expr_to_string(e); - error_node(e, "`%s` is not an expression", err_str); + error_operand_not_expression(o); break; } - gb_string_free(err_str); o->mode = Addressing_Invalid; } @@ -5000,12 +4851,7 @@ void check_expr(Checker *c, Operand *o, AstNode *e) { void check_expr_or_type(Checker *c, Operand *o, AstNode *e) { check_expr_base(c, o, e, NULL); check_not_tuple(c, o); - if (o->mode == Addressing_NoValue) { - gbString str = expr_to_string(o->expr); - error_node(o->expr, "`%s` used as value or type", str); - gb_string_free(str); - o->mode = Addressing_Invalid; - } + error_operand_no_value(o); } diff --git a/src/check_stmt.c b/src/check_stmt.c index b1f2a6d97..f9315c321 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -310,12 +310,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { u32 in = node->stmt_state_flags; u32 out = c->context.stmt_state_flags; - if (in & StmtStateFlag_bounds_check) { - out |= StmtStateFlag_bounds_check; - out &= ~StmtStateFlag_no_bounds_check; - } else if (in & StmtStateFlag_no_bounds_check) { + if (in & StmtStateFlag_no_bounds_check) { out |= StmtStateFlag_no_bounds_check; out &= ~StmtStateFlag_bounds_check; + } else { + // if (in & StmtStateFlag_bounds_check) { + out |= StmtStateFlag_bounds_check; + out &= ~StmtStateFlag_no_bounds_check; } c->context.stmt_state_flags = out; @@ -648,6 +649,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { GB_ASSERT(are_types_identical(x.type, y.type)); + TokenKind op = Token_Lt; + switch (ie->op.kind) { + case Token_HalfOpenRange: op = Token_Lt; break; + case Token_Ellipsis: op = Token_LtEq; break; + default: error(ie->op, "Invalid range operator"); break; + } bool ok = compare_exact_values(Token_Lt, a, b); if (!ok) { // TODO(bill): Better error message diff --git a/src/ir.c b/src/ir.c index eb4506ce7..b7d41817c 100644 --- a/src/ir.c +++ b/src/ir.c @@ -4115,7 +4115,13 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type upper = ir_build_expr(proc, node->right); - irValue *cond = ir_emit_comp(proc, Token_Lt, ir_emit_load(proc, value), upper); + TokenKind op = Token_Lt; + switch (node->op.kind) { + case Token_HalfOpenRange: op = Token_Lt; break; + case Token_Ellipsis: op = Token_LtEq; break; + default: GB_PANIC("Invalid interval operator"); break; + } + irValue *cond = ir_emit_comp(proc, op, ir_emit_load(proc, value), upper); ir_emit_if(proc, cond, body, done); proc->curr_block = body; diff --git a/src/parser.c b/src/parser.c index 53173eb4b..f083c2c8f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2848,10 +2848,14 @@ AstNode *parse_for_stmt(AstFile *f) { isize prev_level = f->expr_level; f->expr_level = -1; AstNode *expr = parse_expr(f, false); - if (f->curr_token.kind == Token_Interval) { - Token op = expect_token(f, Token_Interval); + switch (f->curr_token.kind) { + case Token_HalfOpenRange: + case Token_Ellipsis: { + Token op = f->curr_token; + next_token(f); AstNode *right = parse_expr(f, false); expr = make_interval_expr(f, op, expr, right); + } break; } f->expr_level = prev_level; diff --git a/src/tokenizer.c b/src/tokenizer.c index d9a258a31..f4dbb9fff 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -65,18 +65,18 @@ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token_GtEq, ">="), \ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \ \ - TOKEN_KIND(Token_OpenParen, "("), \ - TOKEN_KIND(Token_CloseParen, ")"), \ - TOKEN_KIND(Token_OpenBracket, "["), \ - TOKEN_KIND(Token_CloseBracket, "]"), \ - TOKEN_KIND(Token_OpenBrace, "{"), \ - TOKEN_KIND(Token_CloseBrace, "}"), \ - TOKEN_KIND(Token_Colon, ":"), \ - TOKEN_KIND(Token_Semicolon, ";"), \ - TOKEN_KIND(Token_Period, "."), \ - TOKEN_KIND(Token_Comma, ","), \ - TOKEN_KIND(Token_Ellipsis, "..."), \ - TOKEN_KIND(Token_Interval, "..<"), \ + TOKEN_KIND(Token_OpenParen, "("), \ + TOKEN_KIND(Token_CloseParen, ")"), \ + TOKEN_KIND(Token_OpenBracket, "["), \ + TOKEN_KIND(Token_CloseBracket, "]"), \ + TOKEN_KIND(Token_OpenBrace, "{"), \ + TOKEN_KIND(Token_CloseBrace, "}"), \ + TOKEN_KIND(Token_Colon, ":"), \ + TOKEN_KIND(Token_Semicolon, ";"), \ + TOKEN_KIND(Token_Period, "."), \ + TOKEN_KIND(Token_Comma, ","), \ + TOKEN_KIND(Token_Ellipsis, "..."), \ + TOKEN_KIND(Token_HalfOpenRange, "..<"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ @@ -846,7 +846,7 @@ Token tokenizer_get_token(Tokenizer *t) { token.kind = Token_Ellipsis; } else if (t->curr_rune == '<') { advance_to_next_rune(t); - token.kind = Token_Interval; + token.kind = Token_HalfOpenRange; } } break;