mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Allow ranges for array-like compound literals
This commit is contained in:
@@ -2391,6 +2391,9 @@ parse_value :: proc(p: ^Parser) -> ^ast.Expr {
|
|||||||
if p.curr_tok.kind == .Open_Brace {
|
if p.curr_tok.kind == .Open_Brace {
|
||||||
return parse_literal_value(p, nil);
|
return parse_literal_value(p, nil);
|
||||||
}
|
}
|
||||||
|
prev_allow_range = p.allow_range;
|
||||||
|
defer p.allow_range = prev_allow_range;
|
||||||
|
p.allow_range = true;
|
||||||
return parse_expr(p, false);
|
return parse_expr(p, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+187
-52
@@ -6635,6 +6635,98 @@ bool ternary_compare_types(Type *x, Type *y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_) {
|
||||||
|
if (!is_ast_range(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_node(ie, BinaryExpr, node);
|
||||||
|
|
||||||
|
check_expr(c, x, ie->left);
|
||||||
|
if (x->mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
check_expr(c, y, ie->right);
|
||||||
|
if (y->mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_to_typed(c, x, y->type);
|
||||||
|
if (x->mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
convert_to_typed(c, y, x->type);
|
||||||
|
if (y->mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_to_typed(c, x, default_type(y->type));
|
||||||
|
if (x->mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
convert_to_typed(c, y, default_type(x->type));
|
||||||
|
if (y->mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!are_types_identical(x->type, y->type)) {
|
||||||
|
if (x->type != t_invalid &&
|
||||||
|
y->type != t_invalid) {
|
||||||
|
gbString xt = type_to_string(x->type);
|
||||||
|
gbString yt = type_to_string(y->type);
|
||||||
|
gbString expr_str = expr_to_string(x->expr);
|
||||||
|
error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
gb_string_free(yt);
|
||||||
|
gb_string_free(xt);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *type = x->type;
|
||||||
|
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
|
||||||
|
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x->mode == Addressing_Constant &&
|
||||||
|
y->mode == Addressing_Constant) {
|
||||||
|
ExactValue a = x->value;
|
||||||
|
ExactValue b = y->value;
|
||||||
|
|
||||||
|
GB_ASSERT(are_types_identical(x->type, y->type));
|
||||||
|
|
||||||
|
TokenKind op = Token_Lt;
|
||||||
|
switch (ie->op.kind) {
|
||||||
|
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);
|
||||||
|
if (!ok) {
|
||||||
|
// TODO(bill): Better error message
|
||||||
|
error(ie->op, "Invalid interval range");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExactValue inline_for_depth = exact_value_sub(b, a);
|
||||||
|
if (ie->op.kind == Token_Ellipsis) {
|
||||||
|
inline_for_depth = exact_value_increment_one(inline_for_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inline_for_depth_) *inline_for_depth_ = inline_for_depth;
|
||||||
|
} else {
|
||||||
|
error(ie->op, "Interval expressions must be constant");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_type_and_value(&c->checker->info, ie->left, x->mode, x->type, x->value);
|
||||||
|
add_type_and_value(&c->checker->info, ie->right, y->mode, y->type, y->value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
||||||
ExprKind kind = Expr_Stmt;
|
ExprKind kind = Expr_Stmt;
|
||||||
@@ -6697,35 +6789,26 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
|
|
||||||
|
|
||||||
case_ast_node(bl, BasicLit, node);
|
case_ast_node(bl, BasicLit, node);
|
||||||
// NOTE(bill, 2018-06-17): Placing this in the parser is slower than
|
|
||||||
// placing it here for some reason. So don't move it to the parsing
|
|
||||||
// stage if you _think_ it will be faster, only do it if you _know_ it
|
|
||||||
// will be faster.
|
|
||||||
Type *t = t_invalid;
|
Type *t = t_invalid;
|
||||||
switch (bl->token.kind) {
|
switch (bl->value.kind) {
|
||||||
case Token_Integer: t = t_untyped_integer; break;
|
case ExactValue_String: t = t_untyped_string; break;
|
||||||
case Token_Float: t = t_untyped_float; break;
|
case ExactValue_Float: t = t_untyped_float; break;
|
||||||
case Token_String: t = t_untyped_string; break;
|
case ExactValue_Complex: t = t_untyped_complex; break;
|
||||||
case Token_Rune: t = t_untyped_rune; break;
|
case ExactValue_Quaternion: t = t_untyped_quaternion; break;
|
||||||
case Token_Imag: {
|
case ExactValue_Integer:
|
||||||
String s = bl->token.string;
|
t = t_untyped_integer;
|
||||||
Rune r = s[s.len-1];
|
if (bl->token.kind == Token_Rune) {
|
||||||
// NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers
|
t = t_untyped_rune;
|
||||||
switch (r) {
|
|
||||||
case 'i': t = t_untyped_complex; break;
|
|
||||||
case 'j': t = t_untyped_quaternion; break;
|
|
||||||
case 'k': t = t_untyped_quaternion; break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("Unknown literal");
|
GB_PANIC("Unhandled value type for basic literal");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
o->mode = Addressing_Constant;
|
o->mode = Addressing_Constant;
|
||||||
o->type = t;
|
o->type = t;
|
||||||
o->value = exact_value_from_basic_literal(bl->token);
|
o->value = bl->value;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(bd, BasicDirective, node);
|
case_ast_node(bd, BasicDirective, node);
|
||||||
@@ -7090,9 +7173,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
if (is_type_simd_vector(t)) {
|
if (is_type_simd_vector(t)) {
|
||||||
error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals");
|
error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals");
|
||||||
} else {
|
} else {
|
||||||
Map<bool> seen = {};
|
RangeCache rc = range_cache_make(heap_allocator());
|
||||||
map_init(&seen, heap_allocator());
|
defer (range_cache_destroy(&rc));
|
||||||
defer (map_destroy(&seen));
|
|
||||||
|
|
||||||
for_array(i, cl->elems) {
|
for_array(i, cl->elems) {
|
||||||
Ast *elem = cl->elems[i];
|
Ast *elem = cl->elems[i];
|
||||||
@@ -7102,36 +7184,89 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
}
|
}
|
||||||
ast_node(fv, FieldValue, elem);
|
ast_node(fv, FieldValue, elem);
|
||||||
|
|
||||||
Operand op_index = {};
|
if (is_ast_range(fv->field)) {
|
||||||
check_expr(c, &op_index, fv->field);
|
Token op = fv->field->BinaryExpr.op;
|
||||||
|
|
||||||
if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) {
|
Operand x = {};
|
||||||
error(elem, "Expected a constant integer as an array field");
|
Operand y = {};
|
||||||
continue;
|
bool ok = check_range(c, fv->field, &x, &y, nullptr);
|
||||||
|
if (!ok) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (x.mode != Addressing_Constant || !is_type_integer(core_type(x.type))) {
|
||||||
|
error(x.expr, "Expected a constant integer as an array field");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y.mode != Addressing_Constant || !is_type_integer(core_type(y.type))) {
|
||||||
|
error(y.expr, "Expected a constant integer as an array field");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 lo = exact_value_to_i64(x.value);
|
||||||
|
i64 hi = exact_value_to_i64(y.value);
|
||||||
|
if (op.kind == Token_RangeHalf) {
|
||||||
|
hi -= 1;
|
||||||
|
}
|
||||||
|
i64 max_index = hi;
|
||||||
|
|
||||||
|
bool new_range = range_cache_add_range(&rc, lo, hi);
|
||||||
|
if (!new_range) {
|
||||||
|
error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) {
|
||||||
|
error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) {
|
||||||
|
error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max < max_index) {
|
||||||
|
max = max_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand operand = {};
|
||||||
|
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
|
||||||
|
check_assignment(c, &operand, elem_type, context_name);
|
||||||
|
|
||||||
|
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||||
|
} else {
|
||||||
|
Operand op_index = {};
|
||||||
|
check_expr(c, &op_index, fv->field);
|
||||||
|
|
||||||
|
if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) {
|
||||||
|
error(elem, "Expected a constant integer as an array field");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 index = exact_value_to_i64(op_index.value);
|
||||||
|
|
||||||
|
if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) {
|
||||||
|
error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool new_index = range_cache_add_index(&rc, index);
|
||||||
|
if (!new_index) {
|
||||||
|
error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max < index) {
|
||||||
|
max = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand operand = {};
|
||||||
|
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
|
||||||
|
check_assignment(c, &operand, elem_type, context_name);
|
||||||
|
|
||||||
|
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 index = exact_value_to_i64(op_index.value);
|
|
||||||
|
|
||||||
if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) {
|
|
||||||
error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map_get(&seen, hash_integer(u64(index))) != nullptr) {
|
|
||||||
error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
map_set(&seen, hash_integer(u64(index)), true);
|
|
||||||
|
|
||||||
if (max < index) {
|
|
||||||
max = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand operand = {};
|
|
||||||
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
|
|
||||||
check_assignment(c, &operand, elem_type, context_name);
|
|
||||||
|
|
||||||
is_constant = is_constant && operand.mode == Addressing_Constant;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cl->max_index = max;
|
cl->max_index = max;
|
||||||
|
|||||||
+5
-79
@@ -605,89 +605,15 @@ void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
|
|
||||||
if (is_ast_range(expr)) {
|
if (is_ast_range(expr)) {
|
||||||
ast_node(ie, BinaryExpr, expr);
|
ast_node(ie, BinaryExpr, expr);
|
||||||
Operand x = {Addressing_Invalid};
|
Operand x = {};
|
||||||
Operand y = {Addressing_Invalid};
|
Operand y = {};
|
||||||
|
|
||||||
check_expr(ctx, &x, ie->left);
|
bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth);
|
||||||
if (x.mode == Addressing_Invalid) {
|
if (!ok) {
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
check_expr(ctx, &y, ie->right);
|
|
||||||
if (y.mode == Addressing_Invalid) {
|
|
||||||
goto skip_expr;
|
goto skip_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_to_typed(ctx, &x, y.type);
|
val0 = x.type;
|
||||||
if (x.mode == Addressing_Invalid) {
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
convert_to_typed(ctx, &y, x.type);
|
|
||||||
if (y.mode == Addressing_Invalid) {
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_to_typed(ctx, &x, default_type(y.type));
|
|
||||||
if (x.mode == Addressing_Invalid) {
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
convert_to_typed(ctx, &y, default_type(x.type));
|
|
||||||
if (y.mode == Addressing_Invalid) {
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!are_types_identical(x.type, y.type)) {
|
|
||||||
if (x.type != t_invalid &&
|
|
||||||
y.type != t_invalid) {
|
|
||||||
gbString xt = type_to_string(x.type);
|
|
||||||
gbString yt = type_to_string(y.type);
|
|
||||||
gbString expr_str = expr_to_string(x.expr);
|
|
||||||
error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
gb_string_free(yt);
|
|
||||||
gb_string_free(xt);
|
|
||||||
}
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *type = x.type;
|
|
||||||
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
|
|
||||||
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.mode == Addressing_Constant &&
|
|
||||||
y.mode == Addressing_Constant) {
|
|
||||||
ExactValue a = x.value;
|
|
||||||
ExactValue b = y.value;
|
|
||||||
|
|
||||||
GB_ASSERT(are_types_identical(x.type, y.type));
|
|
||||||
|
|
||||||
TokenKind op = Token_Lt;
|
|
||||||
switch (ie->op.kind) {
|
|
||||||
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);
|
|
||||||
if (!ok) {
|
|
||||||
// TODO(bill): Better error message
|
|
||||||
error(ie->op, "Invalid interval range");
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline_for_depth = exact_value_sub(b, a);
|
|
||||||
if (ie->op.kind == Token_Ellipsis) {
|
|
||||||
inline_for_depth = exact_value_increment_one(inline_for_depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
error(ie->op, "Interval expressions must be constant");
|
|
||||||
goto skip_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value);
|
|
||||||
add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
|
|
||||||
val0 = type;
|
|
||||||
val1 = t_int;
|
val1 = t_int;
|
||||||
} else {
|
} else {
|
||||||
Operand operand = {Addressing_Invalid};
|
Operand operand = {Addressing_Invalid};
|
||||||
|
|||||||
@@ -143,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
|||||||
|
|
||||||
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||||
|
|
||||||
|
#include "range_cache.cpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
u64 fnv64a(void const *data, isize len) {
|
u64 fnv64a(void const *data, isize len) {
|
||||||
u8 const *bytes = cast(u8 const *)data;
|
u8 const *bytes = cast(u8 const *)data;
|
||||||
|
|||||||
+1
-1
@@ -293,12 +293,12 @@ ExactValue exact_value_from_basic_literal(Token token) {
|
|||||||
case 'i': return exact_value_complex(0, imag);
|
case 'i': return exact_value_complex(0, imag);
|
||||||
case 'j': return exact_value_quaternion(0, 0, imag, 0);
|
case 'j': return exact_value_quaternion(0, 0, imag, 0);
|
||||||
case 'k': return exact_value_quaternion(0, 0, 0, imag);
|
case 'k': return exact_value_quaternion(0, 0, 0, imag);
|
||||||
|
default: GB_PANIC("Invalid imaginary basic literal");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Token_Rune: {
|
case Token_Rune: {
|
||||||
Rune r = GB_RUNE_INVALID;
|
Rune r = GB_RUNE_INVALID;
|
||||||
gb_utf8_decode(token.string.text, token.string.len, &r);
|
gb_utf8_decode(token.string.text, token.string.len, &r);
|
||||||
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
|
|
||||||
return exact_value_i64(r);
|
return exact_value_i64(r);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
+98
-26
@@ -7865,14 +7865,40 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
if (ir_is_elem_const(proc->module, fv->value, et)) {
|
if (ir_is_elem_const(proc->module, fv->value, et)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto tav = fv->field->tav;
|
if (is_ast_range(fv->field)) {
|
||||||
GB_ASSERT(tav.mode == Addressing_Constant);
|
ast_node(ie, BinaryExpr, fv->field);
|
||||||
i64 index = exact_value_to_i64(tav.value);
|
TypeAndValue lo_tav = ie->left->tav;
|
||||||
|
TypeAndValue hi_tav = ie->right->tav;
|
||||||
|
GB_ASSERT(lo_tav.mode == Addressing_Constant);
|
||||||
|
GB_ASSERT(hi_tav.mode == Addressing_Constant);
|
||||||
|
|
||||||
irCompoundLitElemTempData data = {};
|
TokenKind op = ie->op.kind;
|
||||||
data.expr = fv->value;
|
i64 lo = exact_value_to_i64(lo_tav.value);
|
||||||
data.elem_index = cast(i32)index;
|
i64 hi = exact_value_to_i64(hi_tav.value);
|
||||||
array_add(&temp_data, data);
|
if (op == Token_Ellipsis) {
|
||||||
|
hi += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
irValue *value = ir_build_expr(proc, fv->value);
|
||||||
|
|
||||||
|
for (i64 k = lo; k < hi; k++) {
|
||||||
|
irCompoundLitElemTempData data = {};
|
||||||
|
data.value = value;
|
||||||
|
data.elem_index = cast(i32)k;
|
||||||
|
array_add(&temp_data, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
auto tav = fv->field->tav;
|
||||||
|
GB_ASSERT(tav.mode == Addressing_Constant);
|
||||||
|
i64 index = exact_value_to_i64(tav.value);
|
||||||
|
|
||||||
|
irCompoundLitElemTempData data = {};
|
||||||
|
data.value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
|
||||||
|
data.expr = fv->value;
|
||||||
|
data.elem_index = cast(i32)index;
|
||||||
|
array_add(&temp_data, data);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (ir_is_elem_const(proc->module, elem, et)) {
|
if (ir_is_elem_const(proc->module, elem, et)) {
|
||||||
@@ -7897,15 +7923,15 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
defer (proc->return_ptr_hint_value = return_ptr_hint_value);
|
defer (proc->return_ptr_hint_value = return_ptr_hint_value);
|
||||||
defer (proc->return_ptr_hint_used = return_ptr_hint_used);
|
defer (proc->return_ptr_hint_used = return_ptr_hint_used);
|
||||||
|
|
||||||
|
irValue *field_expr = temp_data[i].value;
|
||||||
Ast *expr = temp_data[i].expr;
|
Ast *expr = temp_data[i].expr;
|
||||||
if (expr == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
proc->return_ptr_hint_value = temp_data[i].gep;
|
proc->return_ptr_hint_value = temp_data[i].gep;
|
||||||
proc->return_ptr_hint_ast = unparen_expr(expr);
|
proc->return_ptr_hint_ast = unparen_expr(expr);
|
||||||
|
|
||||||
irValue *field_expr = ir_build_expr(proc, expr);
|
if (field_expr == nullptr) {
|
||||||
|
field_expr = ir_build_expr(proc, expr);
|
||||||
|
}
|
||||||
Type *t = ir_type(field_expr);
|
Type *t = ir_type(field_expr);
|
||||||
GB_ASSERT(t->kind != Type_Tuple);
|
GB_ASSERT(t->kind != Type_Tuple);
|
||||||
irValue *ev = ir_emit_conv(proc, field_expr, et);
|
irValue *ev = ir_emit_conv(proc, field_expr, et);
|
||||||
@@ -7945,19 +7971,43 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_ast_range(fv->field)) {
|
||||||
|
ast_node(ie, BinaryExpr, fv->field);
|
||||||
|
TypeAndValue lo_tav = ie->left->tav;
|
||||||
|
TypeAndValue hi_tav = ie->right->tav;
|
||||||
|
GB_ASSERT(lo_tav.mode == Addressing_Constant);
|
||||||
|
GB_ASSERT(hi_tav.mode == Addressing_Constant);
|
||||||
|
|
||||||
GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
|
TokenKind op = ie->op.kind;
|
||||||
i64 index = exact_value_to_i64(fv->field->tav.value);
|
i64 lo = exact_value_to_i64(lo_tav.value);
|
||||||
|
i64 hi = exact_value_to_i64(hi_tav.value);
|
||||||
|
if (op == Token_Ellipsis) {
|
||||||
|
hi += 1;
|
||||||
|
}
|
||||||
|
|
||||||
irValue *field_expr = ir_build_expr(proc, fv->value);
|
irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
|
||||||
GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
|
|
||||||
|
|
||||||
irValue *ev = ir_emit_conv(proc, field_expr, et);
|
for (i64 k = lo; k < hi; k++) {
|
||||||
|
irCompoundLitElemTempData data = {};
|
||||||
|
data.value = value;
|
||||||
|
data.elem_index = cast(i32)k;
|
||||||
|
array_add(&temp_data, data);
|
||||||
|
}
|
||||||
|
|
||||||
irCompoundLitElemTempData data = {};
|
} else {
|
||||||
data.value = ev;
|
GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
|
||||||
data.elem_index = cast(i32)index;
|
i64 index = exact_value_to_i64(fv->field->tav.value);
|
||||||
array_add(&temp_data, data);
|
|
||||||
|
irValue *field_expr = ir_build_expr(proc, fv->value);
|
||||||
|
GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
|
||||||
|
|
||||||
|
irValue *ev = ir_emit_conv(proc, field_expr, et);
|
||||||
|
|
||||||
|
irCompoundLitElemTempData data = {};
|
||||||
|
data.value = ev;
|
||||||
|
data.elem_index = cast(i32)index;
|
||||||
|
array_add(&temp_data, data);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ir_is_elem_const(proc->module, elem, et)) {
|
if (ir_is_elem_const(proc->module, elem, et)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -8015,14 +8065,36 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
Ast *elem = cl->elems[i];
|
Ast *elem = cl->elems[i];
|
||||||
if (elem->kind == Ast_FieldValue) {
|
if (elem->kind == Ast_FieldValue) {
|
||||||
ast_node(fv, FieldValue, elem);
|
ast_node(fv, FieldValue, elem);
|
||||||
GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
|
if (is_ast_range(fv->field)) {
|
||||||
|
ast_node(ie, BinaryExpr, fv->field);
|
||||||
|
TypeAndValue lo_tav = ie->left->tav;
|
||||||
|
TypeAndValue hi_tav = ie->right->tav;
|
||||||
|
GB_ASSERT(lo_tav.mode == Addressing_Constant);
|
||||||
|
GB_ASSERT(hi_tav.mode == Addressing_Constant);
|
||||||
|
|
||||||
i64 field_index = exact_value_to_i64(fv->field->tav.value);
|
TokenKind op = ie->op.kind;
|
||||||
|
i64 lo = exact_value_to_i64(lo_tav.value);
|
||||||
|
i64 hi = exact_value_to_i64(hi_tav.value);
|
||||||
|
if (op == Token_Ellipsis) {
|
||||||
|
hi += 1;
|
||||||
|
}
|
||||||
|
|
||||||
irValue *ev = ir_build_expr(proc, fv->value);
|
irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
|
||||||
irValue *value = ir_emit_conv(proc, ev, et);
|
|
||||||
irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
|
for (i64 k = lo; k < hi; k++) {
|
||||||
ir_emit_store(proc, ep, value);
|
irValue *ep = ir_emit_array_epi(proc, items, cast(i32)k);
|
||||||
|
ir_emit_store(proc, ep, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
|
||||||
|
|
||||||
|
i64 field_index = exact_value_to_i64(fv->field->tav.value);
|
||||||
|
|
||||||
|
irValue *ev = ir_build_expr(proc, fv->value);
|
||||||
|
irValue *value = ir_emit_conv(proc, ev, et);
|
||||||
|
irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
|
||||||
|
ir_emit_store(proc, ep, value);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et);
|
irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et);
|
||||||
irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i);
|
irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i);
|
||||||
|
|||||||
+39
-9
@@ -887,17 +887,47 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
for (isize j = 0; j < elem_count; j++) {
|
for (isize j = 0; j < elem_count; j++) {
|
||||||
Ast *elem = cl->elems[j];
|
Ast *elem = cl->elems[j];
|
||||||
ast_node(fv, FieldValue, elem);
|
ast_node(fv, FieldValue, elem);
|
||||||
TypeAndValue index_tav = fv->field->tav;
|
if (is_ast_range(fv->field)) {
|
||||||
GB_ASSERT(index_tav.mode == Addressing_Constant);
|
ast_node(ie, BinaryExpr, fv->field);
|
||||||
i64 index = exact_value_to_i64(index_tav.value);
|
TypeAndValue lo_tav = ie->left->tav;
|
||||||
if (index == i) {
|
TypeAndValue hi_tav = ie->right->tav;
|
||||||
TypeAndValue tav = fv->value->tav;
|
GB_ASSERT(lo_tav.mode == Addressing_Constant);
|
||||||
if (tav.mode != Addressing_Constant) {
|
GB_ASSERT(hi_tav.mode == Addressing_Constant);
|
||||||
|
|
||||||
|
TokenKind op = ie->op.kind;
|
||||||
|
i64 lo = exact_value_to_i64(lo_tav.value);
|
||||||
|
i64 hi = exact_value_to_i64(hi_tav.value);
|
||||||
|
if (op == Token_Ellipsis) {
|
||||||
|
hi += 1;
|
||||||
|
}
|
||||||
|
if (lo == i) {
|
||||||
|
TypeAndValue tav = fv->value->tav;
|
||||||
|
if (tav.mode != Addressing_Constant) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (i64 k = lo; k < hi; k++) {
|
||||||
|
if (k > lo) ir_write_str_lit(f, ", ");
|
||||||
|
|
||||||
|
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
i += (hi-lo-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TypeAndValue index_tav = fv->field->tav;
|
||||||
|
GB_ASSERT(index_tav.mode == Addressing_Constant);
|
||||||
|
i64 index = exact_value_to_i64(index_tav.value);
|
||||||
|
if (index == i) {
|
||||||
|
TypeAndValue tav = fv->value->tav;
|
||||||
|
if (tav.mode != Addressing_Constant) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||||
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ir_print_compound_element(f, m, tav.value, elem_type);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -588,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) {
|
|||||||
Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
|
Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_BasicLit);
|
Ast *result = alloc_ast_node(f, Ast_BasicLit);
|
||||||
result->BasicLit.token = basic_lit;
|
result->BasicLit.token = basic_lit;
|
||||||
|
result->BasicLit.value = exact_value_from_basic_literal(basic_lit);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1509,8 +1510,11 @@ Ast *parse_value(AstFile *f) {
|
|||||||
if (f->curr_token.kind == Token_OpenBrace) {
|
if (f->curr_token.kind == Token_OpenBrace) {
|
||||||
return parse_literal_value(f, nullptr);
|
return parse_literal_value(f, nullptr);
|
||||||
}
|
}
|
||||||
|
Ast *value;
|
||||||
Ast *value = parse_expr(f, false);
|
bool prev_allow_range = f->allow_range;
|
||||||
|
f->allow_range = true;
|
||||||
|
value = parse_expr(f, false);
|
||||||
|
f->allow_range = prev_allow_range;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1735,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
operand = ast_bad_expr(f, token, f->curr_token);
|
operand = ast_bad_expr(f, token, f->curr_token);
|
||||||
}
|
}
|
||||||
operand->stmt_state_flags |= StmtStateFlag_no_deferred;
|
operand->stmt_state_flags |= StmtStateFlag_no_deferred;
|
||||||
} */ else if (name.string == "file") { return ast_basic_directive(f, token, name.string);
|
} */ else if (name.string == "file") {
|
||||||
|
return ast_basic_directive(f, token, name.string);
|
||||||
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
|
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
|
||||||
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
|
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
|
||||||
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
|
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ enum StmtAllowFlag {
|
|||||||
AST_KIND(Undef, "undef", Token) \
|
AST_KIND(Undef, "undef", Token) \
|
||||||
AST_KIND(BasicLit, "basic literal", struct { \
|
AST_KIND(BasicLit, "basic literal", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
|
ExactValue value; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(BasicDirective, "basic directive", struct { \
|
AST_KIND(BasicDirective, "basic directive", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
|
|||||||
Reference in New Issue
Block a user