Przeglądaj źródła

Closed range `...` (both inclusive); Type comparisons with == and !=

Ginger Bill 8 lat temu
rodzic
commit
4603d2525e
7 zmienionych plików z 128 dodań i 266 usunięć
  1. 36 37
      code/demo.odin
  2. 1 1
      core/fmt.odin
  3. 54 208
      src/check_expr.c
  4. 11 4
      src/check_stmt.c
  5. 7 1
      src/ir.c
  6. 6 2
      src/parser.c
  7. 13 13
      src/tokenizer.c

+ 36 - 37
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();
 }

+ 1 - 1
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) {

+ 54 - 208
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;
-		}
-		check_conversion(c, x, type);
-		return;
-	} break;
-	case 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);
-			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;
+	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);
 		}
-
-		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: {
+	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(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);
 }
 
 

+ 11 - 4
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

+ 7 - 1
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;
 

+ 6 - 2
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;
 

+ 13 - 13
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;