mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +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
|
// .. open range
|
||||||
|
// ..< half-closed range
|
||||||
|
|
||||||
for in 0..2 {} // 0, 1, 2
|
for in 0..2 {} // 0, 1, 2
|
||||||
|
for in 0..<2 {} // 0, 1
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Multiple sized booleans
|
{ // Multiple sized booleans
|
||||||
@@ -480,7 +482,7 @@ parametric_polymorphism :: proc() {
|
|||||||
|
|
||||||
get_hash :: proc(s: string) -> u32 { // fnv32a
|
get_hash :: proc(s: string) -> u32 { // fnv32a
|
||||||
h: u32 = 0x811c9dc5;
|
h: u32 = 0x811c9dc5;
|
||||||
for i in 0..len(s)-1 {
|
for i in 0..<len(s) {
|
||||||
h = (h ~ u32(s[i])) * 0x01000193;
|
h = (h ~ u32(s[i])) * 0x01000193;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
@@ -530,7 +532,7 @@ parametric_polymorphism :: proc() {
|
|||||||
// `T` is the type passed
|
// `T` is the type passed
|
||||||
fmt.printf("Generating an array of type %v from the value %v of type %v\n",
|
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));
|
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);
|
res[i] = T(i*i);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
+1
-1
@@ -1057,7 +1057,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bool is_immutable = e->Variable.is_immutable;
|
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;
|
String name = e->token.string;
|
||||||
Type *t = base_type(type_deref(e->type));
|
Type *t = base_type(type_deref(e->type));
|
||||||
if (t->kind == Type_Struct) {
|
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"));
|
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;
|
break;
|
||||||
|
|||||||
+14
-4
@@ -693,17 +693,17 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
Ast *expr = unparen_expr(cc->list[j]);
|
Ast *expr = unparen_expr(cc->list[j]);
|
||||||
|
|
||||||
if (is_ast_range(expr)) {
|
if (is_ast_range(expr)) {
|
||||||
ast_node(ie, BinaryExpr, expr);
|
ast_node(be, BinaryExpr, expr);
|
||||||
Operand lhs = {};
|
Operand lhs = {};
|
||||||
Operand rhs = {};
|
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) {
|
if (x.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (lhs.mode == Addressing_Invalid) {
|
if (lhs.mode == Addressing_Invalid) {
|
||||||
continue;
|
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) {
|
if (rhs.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -715,6 +715,13 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
continue;
|
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 a = lhs;
|
||||||
Operand b = rhs;
|
Operand b = rhs;
|
||||||
@@ -723,7 +730,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_comparison(ctx, &b, &x, Token_GtEq);
|
check_comparison(ctx, &b, &x, upper_op);
|
||||||
if (b.mode == Addressing_Invalid) {
|
if (b.mode == Addressing_Invalid) {
|
||||||
continue;
|
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, lhs);
|
||||||
|
if (upper_op == Token_GtEq) {
|
||||||
add_constant_switch_case(ctx, &seen, rhs);
|
add_constant_switch_case(ctx, &seen, rhs);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Operand y = {};
|
Operand y = {};
|
||||||
if (is_type_typeid(x.type)) {
|
if (is_type_typeid(x.type)) {
|
||||||
@@ -1381,6 +1390,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
TokenKind op = Token_Lt;
|
TokenKind op = Token_Lt;
|
||||||
switch (ie->op.kind) {
|
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;
|
default: error(ie->op, "Invalid range operator"); break;
|
||||||
}
|
}
|
||||||
bool ok = compare_exact_values(op, a, b);
|
bool ok = compare_exact_values(op, a, b);
|
||||||
|
|||||||
@@ -1044,9 +1044,19 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no
|
|||||||
bits = 8*type_size_of(type->BitSet.underlying);
|
bits = 8*type_size_of(type->BitSet.underlying);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (be->op.kind) {
|
||||||
|
case Token_Ellipsis:
|
||||||
if (upper - lower >= bits) {
|
if (upper - lower >= bits) {
|
||||||
error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, (upper-lower+1));
|
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.elem = t;
|
||||||
type->BitSet.lower = lower;
|
type->BitSet.lower = lower;
|
||||||
type->BitSet.upper = upper;
|
type->BitSet.upper = upper;
|
||||||
|
|||||||
@@ -8157,6 +8157,7 @@ void ir_build_range_interval(irProcedure *proc, AstBinaryExpr *node, Type *val_t
|
|||||||
TokenKind op = Token_Lt;
|
TokenKind op = Token_Lt;
|
||||||
switch (node->op.kind) {
|
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;
|
default: GB_PANIC("Invalid interval operator"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8833,6 +8834,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
|
|||||||
TokenKind op = Token_Invalid;
|
TokenKind op = Token_Invalid;
|
||||||
switch (ie->op.kind) {
|
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;
|
default: GB_PANIC("Invalid interval operator"); break;
|
||||||
}
|
}
|
||||||
irValue *lhs = ir_build_expr(proc, ie->left);
|
irValue *lhs = ir_build_expr(proc, ie->left);
|
||||||
|
|||||||
+18
-9
@@ -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 expect_operator(AstFile *f) {
|
||||||
Token prev = f->curr_token;
|
Token prev = f->curr_token;
|
||||||
if ((prev.kind == Token_in || prev.kind == Token_notin) && (f->expr_level >= 0 || f->allow_in_expr)) {
|
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)) {
|
} else if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
|
||||||
syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
|
syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
|
||||||
LIT(token_strings[prev.kind]));
|
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'",
|
syntax_error(f->curr_token, "Expected an non-range operator, got '%.*s'",
|
||||||
LIT(token_strings[prev.kind]));
|
LIT(token_strings[prev.kind]));
|
||||||
}
|
}
|
||||||
@@ -2131,9 +2144,9 @@ Ast *parse_call_expr(AstFile *f, Ast *operand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool prefix_ellipsis = false;
|
bool prefix_ellipsis = false;
|
||||||
if (f->curr_token.kind == Token_Ellipsis) {
|
if (is_token_range(f->curr_token)) {
|
||||||
prefix_ellipsis = true;
|
prefix_ellipsis = true;
|
||||||
ellipsis = expect_token(f, Token_Ellipsis);
|
ellipsis = expect_token(f, f->curr_token.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *arg = parse_expr(f, false);
|
Ast *arg = parse_expr(f, false);
|
||||||
@@ -2320,12 +2333,7 @@ bool is_ast_range(Ast *expr) {
|
|||||||
if (expr->kind != Ast_BinaryExpr) {
|
if (expr->kind != Ast_BinaryExpr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TokenKind op = expr->BinaryExpr.op.kind;
|
return is_token_range(expr->BinaryExpr.op.kind);
|
||||||
switch (op) {
|
|
||||||
case Token_Ellipsis:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): result == priority
|
// NOTE(bill): result == priority
|
||||||
@@ -2334,6 +2342,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
|
|||||||
case Token_Question:
|
case Token_Question:
|
||||||
return 1;
|
return 1;
|
||||||
case Token_Ellipsis:
|
case Token_Ellipsis:
|
||||||
|
case Token_RangeHalf:
|
||||||
if (!f->allow_range) {
|
if (!f->allow_range) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ TOKEN_KIND(Token__ComparisonEnd, ""), \
|
|||||||
TOKEN_KIND(Token_Period, "."), \
|
TOKEN_KIND(Token_Period, "."), \
|
||||||
TOKEN_KIND(Token_Comma, ","), \
|
TOKEN_KIND(Token_Comma, ","), \
|
||||||
TOKEN_KIND(Token_Ellipsis, ".."), \
|
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||||
|
TOKEN_KIND(Token_RangeHalf, "..<"), \
|
||||||
TOKEN_KIND(Token_BackSlash, "\\"), \
|
TOKEN_KIND(Token_BackSlash, "\\"), \
|
||||||
TOKEN_KIND(Token__OperatorEnd, ""), \
|
TOKEN_KIND(Token__OperatorEnd, ""), \
|
||||||
\
|
\
|
||||||
@@ -985,6 +986,10 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
if (t->curr_rune == '.') { // Could be an ellipsis
|
if (t->curr_rune == '.') { // Could be an ellipsis
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
token.kind = Token_Ellipsis;
|
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') {
|
} else if ('0' <= t->curr_rune && t->curr_rune <= '9') {
|
||||||
token = scan_number_to_token(t, true);
|
token = scan_number_to_token(t, true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user