diff options
| author | gingerBill <bill@gingerbill.org> | 2018-08-16 15:16:57 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2018-08-16 15:16:57 +0100 |
| commit | 884d5fed9f2894a91ede38fb073338b1fe94a483 (patch) | |
| tree | 41867331fdc096743e0072bf55067f77ebc306fb /src/check_type.cpp | |
| parent | ec84188597b6558970e66ec7918851f1267888df (diff) | |
bit_set['A'..'Z'], bit_set[0..8]
Diffstat (limited to 'src/check_type.cpp')
| -rw-r--r-- | src/check_type.cpp | 168 |
1 files changed, 137 insertions, 31 deletions
diff --git a/src/check_type.cpp b/src/check_type.cpp index 6b93fbd68..bbae12654 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -680,49 +680,157 @@ void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Ast *node) } } +bool is_type_valid_bit_set_range(Type *t) { + if (is_type_integer(t)) { + return true; + } + if (is_type_rune(t)) { + return true; + } + return false; +} -void check_bit_set_type(CheckerContext *ctx, Type *type, Ast *node) { +void check_bit_set_type(CheckerContext *c, Type *type, Ast *node) { ast_node(bs, BitSetType, node); GB_ASSERT(type->kind == Type_BitSet); - Type *bt = check_type_expr(ctx, bs->base, nullptr); + Ast *base = unparen_expr(bs->base); + if (is_ast_range(base)) { + ast_node(be, BinaryExpr, base); + Operand lhs = {}; + Operand rhs = {}; + check_expr(c, &lhs, be->left); + check_expr(c, &rhs, be->right); + if (lhs.mode == Addressing_Invalid) { + return; + } + if (rhs.mode == Addressing_Invalid) { + return; + } + convert_to_typed(c, &lhs, rhs.type); + if (lhs.mode == Addressing_Invalid) { + return; + } + convert_to_typed(c, &rhs, lhs.type); + if (rhs.mode == Addressing_Invalid) { + return; + } + if (!are_types_identical(lhs.type, rhs.type)) { + if (lhs.type != t_invalid && + rhs.type != t_invalid) { + gbString xt = type_to_string(lhs.type); + gbString yt = type_to_string(rhs.type); + gbString expr_str = expr_to_string(bs->base); + error(bs->base, "Mismatched types in range '%s' : '%s' vs '%s'", expr_str, xt, yt); + gb_string_free(expr_str); + gb_string_free(yt); + gb_string_free(xt); + } + return; + } - type->BitSet.base = bt; - if (!is_type_enum(bt)) { - error(bs->base, "Expected an enum type for a bit_set"); - } else { - Type *et = base_type(bt); - GB_ASSERT(et->kind == Type_Enum); - if (!is_type_integer(et->Enum.base_type)) { - error(bs->base, "Enum type for bit_set must be an integer"); + if (!is_type_valid_bit_set_range(lhs.type)) { + gbString str = type_to_string(lhs.type); + error(bs->base, "'%s' is invalid for an interval expression, expected an integer or rune", str); + gb_string_free(str); return; } - i64 min_value = 0; - i64 max_value = 0; - BigInt v64 = {}; big_int_from_i64(&v64, 64); - for_array(i, et->Enum.fields) { - Entity *e = et->Enum.fields[i]; - if (e->kind != Entity_Constant) { - continue; - } - ExactValue value = exact_value_to_integer(e->Constant.value); - GB_ASSERT(value.kind == ExactValue_Integer); - i64 x = big_int_to_i64(&value.value_integer); - min_value = gb_min(min_value, x); - max_value = gb_max(max_value, x); + if (lhs.mode != Addressing_Constant || rhs.mode != Addressing_Constant) { + error(bs->base, "Intervals must be constant values"); + return; } - GB_ASSERT(min_value <= max_value); + ExactValue iv = exact_value_to_integer(lhs.value); + ExactValue jv = exact_value_to_integer(rhs.value); + GB_ASSERT(iv.kind == ExactValue_Integer); + GB_ASSERT(jv.kind == ExactValue_Integer); - if (max_value - min_value > 64) { - error(bs->base, "bit_set range is greater than 64 bits"); + BigInt i = iv.value_integer; + BigInt j = jv.value_integer; + if (big_int_cmp(&i, &j) > 0) { + gbAllocator a = heap_allocator(); + String si = big_int_to_string(a, &i); + String sj = big_int_to_string(a, &j); + error(bs->base, "Lower interval bound larger than upper bound, %.*s .. %.*s", LIT(si), LIT(sj)); + gb_free(a, si.text); + gb_free(a, sj.text); + return; } - type->BitSet.min = min_value; - type->BitSet.max = max_value; - } + Type *t = default_type(lhs.type); + bool ok = true; + ok = check_representable_as_constant(c, iv, t, nullptr); + if (!ok) { + gbAllocator a = heap_allocator(); + String s = big_int_to_string(a, &i); + gbString ts = type_to_string(t); + error(bs->base, "%.*s is not representable by %s", LIT(s), ts); + gb_string_free(ts); + gb_free(a, s.text); + return; + } + ok = check_representable_as_constant(c, iv, t, nullptr); + if (!ok) { + gbAllocator a = heap_allocator(); + String s = big_int_to_string(a, &j); + gbString ts = type_to_string(t); + error(bs->base, "%.*s is not representable by %s", LIT(s), ts); + gb_string_free(ts); + gb_free(a, s.text); + return; + } + i64 lower = big_int_to_i64(&i); + i64 upper = big_int_to_i64(&j); + + if (upper - lower > 64) { + error(bs->base, "bit_set range is greater than 64 bits, %lld bits are required", (upper-lower+1)); + } + type->BitSet.base = t; + type->BitSet.lower = lower; + type->BitSet.upper = upper; + + } else { + Type *bt = check_type_expr(c, bs->base, nullptr); + + type->BitSet.base = bt; + if (!is_type_enum(bt)) { + error(bs->base, "Expected an enum type for a bit_set"); + } else { + Type *et = base_type(bt); + GB_ASSERT(et->kind == Type_Enum); + if (!is_type_integer(et->Enum.base_type)) { + error(bs->base, "Enum type for bit_set must be an integer"); + return; + } + i64 lower = 0; + i64 upper = 0; + BigInt v64 = {}; big_int_from_i64(&v64, 64); + + for_array(i, et->Enum.fields) { + Entity *e = et->Enum.fields[i]; + if (e->kind != Entity_Constant) { + continue; + } + ExactValue value = exact_value_to_integer(e->Constant.value); + GB_ASSERT(value.kind == ExactValue_Integer); + // NOTE(bill): enum types should be able to store i64 values + i64 x = big_int_to_i64(&value.value_integer); + lower = gb_min(lower, x); + upper = gb_max(upper, x); + } + + GB_ASSERT(lower <= upper); + + if (upper - lower > 64) { + error(bs->base, "bit_set range is greater than 64 bits, %lld bits are required", (upper-lower+1)); + } + + type->BitSet.lower = lower; + type->BitSet.upper = upper; + } + } } @@ -1951,9 +2059,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t case_ast_node(bs, BitSetType, e); *type = alloc_type_bit_set(); set_base_type(named_type, *type); - check_open_scope(ctx, e); check_bit_set_type(ctx, *type, e); - check_close_scope(ctx); return true; case_end; |