Add ..< operator for ranges; Add extra checking for bit set assignments

This commit is contained in:
gingerBill
2019-05-28 12:45:20 +01:00
parent 5697d6df74
commit 222941727f
8 changed files with 71 additions and 22 deletions

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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 {