mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-28 01:03:56 +00:00
Add ..< operator for ranges; Add extra checking for bit set assignments
This commit is contained in:
@@ -60,8 +60,10 @@ general_stuff :: proc() {
|
||||
|
||||
{
|
||||
// .. open range
|
||||
// ..< half-closed range
|
||||
|
||||
for in 0..2 {} // 0, 1, 2
|
||||
for in 0..<2 {} // 0, 1
|
||||
}
|
||||
|
||||
{ // Multiple sized booleans
|
||||
@@ -480,7 +482,7 @@ parametric_polymorphism :: proc() {
|
||||
|
||||
get_hash :: proc(s: string) -> u32 { // fnv32a
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i in 0..len(s)-1 {
|
||||
for i in 0..<len(s) {
|
||||
h = (h ~ u32(s[i])) * 0x01000193;
|
||||
}
|
||||
return h;
|
||||
@@ -530,7 +532,7 @@ parametric_polymorphism :: proc() {
|
||||
// `T` is the type passed
|
||||
fmt.printf("Generating an array of type %v from the value %v of type %v\n",
|
||||
typeid_of(type_of(res)), N, typeid_of(I));
|
||||
for i in 0..N-1 {
|
||||
for i in 0..<N {
|
||||
res[i] = T(i*i);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -1057,7 +1057,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
continue;
|
||||
}
|
||||
bool is_immutable = e->Variable.is_immutable;
|
||||
bool is_value = (e->flags & EntityFlag_Value) != 0;
|
||||
bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (t->kind == Type_Struct) {
|
||||
|
||||
@@ -6383,6 +6383,17 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
}
|
||||
|
||||
check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal"));
|
||||
if (o->mode == Addressing_Constant) {
|
||||
i64 lower = t->BitSet.lower;
|
||||
i64 upper = t->BitSet.upper;
|
||||
i64 v = exact_value_to_i64(o->value);
|
||||
if (lower <= v && v <= upper) {
|
||||
// okay
|
||||
} else {
|
||||
error(elem, "Bit field value out of bounds, %lld not in the range %lld .. %lld", v, lower, upper);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -693,17 +693,17 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
Ast *expr = unparen_expr(cc->list[j]);
|
||||
|
||||
if (is_ast_range(expr)) {
|
||||
ast_node(ie, BinaryExpr, expr);
|
||||
ast_node(be, BinaryExpr, expr);
|
||||
Operand lhs = {};
|
||||
Operand rhs = {};
|
||||
check_expr_with_type_hint(ctx, &lhs, ie->left, x.type);
|
||||
check_expr_with_type_hint(ctx, &lhs, be->left, x.type);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
continue;
|
||||
}
|
||||
if (lhs.mode == Addressing_Invalid) {
|
||||
continue;
|
||||
}
|
||||
check_expr_with_type_hint(ctx, &rhs, ie->right, x.type);
|
||||
check_expr_with_type_hint(ctx, &rhs, be->right, x.type);
|
||||
if (rhs.mode == Addressing_Invalid) {
|
||||
continue;
|
||||
}
|
||||
@@ -715,6 +715,13 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TokenKind upper_op = Token_Invalid;
|
||||
switch (be->op.kind) {
|
||||
case Token_Ellipsis: upper_op = Token_GtEq; break;
|
||||
case Token_RangeHalf: upper_op = Token_Gt; break;
|
||||
default: GB_PANIC("Invalid range operator"); break;
|
||||
}
|
||||
|
||||
|
||||
Operand a = lhs;
|
||||
Operand b = rhs;
|
||||
@@ -723,7 +730,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
check_comparison(ctx, &b, &x, Token_GtEq);
|
||||
check_comparison(ctx, &b, &x, upper_op);
|
||||
if (b.mode == Addressing_Invalid) {
|
||||
continue;
|
||||
}
|
||||
@@ -736,7 +743,9 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
}
|
||||
|
||||
add_constant_switch_case(ctx, &seen, lhs);
|
||||
add_constant_switch_case(ctx, &seen, rhs);
|
||||
if (upper_op == Token_GtEq) {
|
||||
add_constant_switch_case(ctx, &seen, rhs);
|
||||
}
|
||||
} else {
|
||||
Operand y = {};
|
||||
if (is_type_typeid(x.type)) {
|
||||
@@ -1380,7 +1389,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
|
||||
TokenKind op = Token_Lt;
|
||||
switch (ie->op.kind) {
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_RangeHalf: op = Token_Lt; break;
|
||||
default: error(ie->op, "Invalid range operator"); break;
|
||||
}
|
||||
bool ok = compare_exact_values(op, a, b);
|
||||
|
||||
@@ -1044,8 +1044,18 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no
|
||||
bits = 8*type_size_of(type->BitSet.underlying);
|
||||
}
|
||||
|
||||
if (upper - lower >= bits) {
|
||||
error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, (upper-lower+1));
|
||||
switch (be->op.kind) {
|
||||
case Token_Ellipsis:
|
||||
if (upper - lower >= bits) {
|
||||
error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, (upper-lower+1));
|
||||
}
|
||||
break;
|
||||
case Token_RangeHalf:
|
||||
if (upper - lower > bits) {
|
||||
error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, (upper-lower));
|
||||
}
|
||||
upper -= 1;
|
||||
break;
|
||||
}
|
||||
type->BitSet.elem = t;
|
||||
type->BitSet.lower = lower;
|
||||
|
||||
@@ -8156,7 +8156,8 @@ void ir_build_range_interval(irProcedure *proc, AstBinaryExpr *node, Type *val_t
|
||||
|
||||
TokenKind op = Token_Lt;
|
||||
switch (node->op.kind) {
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_RangeHalf: op = Token_Lt; break;
|
||||
default: GB_PANIC("Invalid interval operator"); break;
|
||||
}
|
||||
|
||||
@@ -8832,7 +8833,8 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
|
||||
ast_node(ie, BinaryExpr, expr);
|
||||
TokenKind op = Token_Invalid;
|
||||
switch (ie->op.kind) {
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_RangeHalf: op = Token_Lt; break;
|
||||
default: GB_PANIC("Invalid interval operator"); break;
|
||||
}
|
||||
irValue *lhs = ir_build_expr(proc, ie->left);
|
||||
|
||||
@@ -1146,6 +1146,19 @@ Token expect_token_after(AstFile *f, TokenKind kind, char *msg) {
|
||||
}
|
||||
|
||||
|
||||
bool is_token_range(TokenKind kind) {
|
||||
switch (kind) {
|
||||
case Token_Ellipsis:
|
||||
case Token_RangeHalf:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_token_range(Token tok) {
|
||||
return is_token_range(tok.kind);
|
||||
}
|
||||
|
||||
|
||||
Token expect_operator(AstFile *f) {
|
||||
Token prev = f->curr_token;
|
||||
if ((prev.kind == Token_in || prev.kind == Token_notin) && (f->expr_level >= 0 || f->allow_in_expr)) {
|
||||
@@ -1153,7 +1166,7 @@ Token expect_operator(AstFile *f) {
|
||||
} else if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
|
||||
syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
|
||||
LIT(token_strings[prev.kind]));
|
||||
} else if (!f->allow_range && (prev.kind == Token_Ellipsis)) {
|
||||
} else if (!f->allow_range && is_token_range(prev)) {
|
||||
syntax_error(f->curr_token, "Expected an non-range operator, got '%.*s'",
|
||||
LIT(token_strings[prev.kind]));
|
||||
}
|
||||
@@ -2131,9 +2144,9 @@ Ast *parse_call_expr(AstFile *f, Ast *operand) {
|
||||
}
|
||||
|
||||
bool prefix_ellipsis = false;
|
||||
if (f->curr_token.kind == Token_Ellipsis) {
|
||||
if (is_token_range(f->curr_token)) {
|
||||
prefix_ellipsis = true;
|
||||
ellipsis = expect_token(f, Token_Ellipsis);
|
||||
ellipsis = expect_token(f, f->curr_token.kind);
|
||||
}
|
||||
|
||||
Ast *arg = parse_expr(f, false);
|
||||
@@ -2320,12 +2333,7 @@ bool is_ast_range(Ast *expr) {
|
||||
if (expr->kind != Ast_BinaryExpr) {
|
||||
return false;
|
||||
}
|
||||
TokenKind op = expr->BinaryExpr.op.kind;
|
||||
switch (op) {
|
||||
case Token_Ellipsis:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return is_token_range(expr->BinaryExpr.op.kind);
|
||||
}
|
||||
|
||||
// NOTE(bill): result == priority
|
||||
@@ -2334,6 +2342,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
|
||||
case Token_Question:
|
||||
return 1;
|
||||
case Token_Ellipsis:
|
||||
case Token_RangeHalf:
|
||||
if (!f->allow_range) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ TOKEN_KIND(Token__ComparisonEnd, ""), \
|
||||
TOKEN_KIND(Token_Period, "."), \
|
||||
TOKEN_KIND(Token_Comma, ","), \
|
||||
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||
TOKEN_KIND(Token_RangeHalf, "..<"), \
|
||||
TOKEN_KIND(Token_BackSlash, "\\"), \
|
||||
TOKEN_KIND(Token__OperatorEnd, ""), \
|
||||
\
|
||||
@@ -985,6 +986,10 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
if (t->curr_rune == '.') { // Could be an ellipsis
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_Ellipsis;
|
||||
if (t->curr_rune == '<') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_RangeHalf;
|
||||
}
|
||||
} else if ('0' <= t->curr_rune && t->curr_rune <= '9') {
|
||||
token = scan_number_to_token(t, true);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user