mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-18 20:40:28 +00:00
Interval expressions in range
This commit is contained in:
@@ -18,12 +18,16 @@ Thing :: enum f64 {
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
msg := "Hello";
|
||||
range index, value : msg {
|
||||
fmt.println(index, value);
|
||||
}
|
||||
msg := "Hellope";
|
||||
list := []int{1, 4, 7, 3, 7, 2, 1};
|
||||
range index, value : list {
|
||||
fmt.println(index, value);
|
||||
|
||||
range value : msg {
|
||||
fmt.println(value);
|
||||
}
|
||||
range value : list {
|
||||
fmt.println(value);
|
||||
}
|
||||
range x : 0 ..< 5 {
|
||||
fmt.println(x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3790,6 +3790,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
goto error;
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, IntervalExpr, node);
|
||||
error_node(node, "Invalid use of an interval expression");
|
||||
goto error;
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Ident, node);
|
||||
check_identifier(c, o, node, type_hint);
|
||||
case_end;
|
||||
|
||||
@@ -594,42 +594,116 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
||||
check_open_scope(c, node);
|
||||
|
||||
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr(c, &operand, rs->expr);
|
||||
|
||||
Type *key = NULL;
|
||||
Type *val = NULL;
|
||||
if (operand.mode != Addressing_Invalid) {
|
||||
Type *t = base_type(type_deref(operand.type));
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (is_type_string(t)) {
|
||||
key = t_int;
|
||||
val = t_rune;
|
||||
Type *idx = NULL;
|
||||
Entity *entities[2] = {0};
|
||||
isize entity_count = 0;
|
||||
|
||||
|
||||
if (rs->expr != NULL && rs->expr->kind == AstNode_IntervalExpr) {
|
||||
ast_node(ie, IntervalExpr, rs->expr);
|
||||
Operand x = {Addressing_Invalid};
|
||||
Operand y = {Addressing_Invalid};
|
||||
|
||||
check_expr(c, &x, ie->left);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
check_expr(c, &y, ie->right);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
convert_to_typed(c, &x, y.type, 0);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
convert_to_typed(c, &y, x.type, 0);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
convert_to_typed(c, &x, default_type(y.type), 0);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
convert_to_typed(c, &y, default_type(x.type), 0);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case Type_Array:
|
||||
key = t_int;
|
||||
val = t->Array.elem;
|
||||
break;
|
||||
case Type_Slice:
|
||||
key = t_int;
|
||||
val = t->Array.elem;
|
||||
break;
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
if (!is_type_integer(x.type) && !is_type_float(x.type)) {
|
||||
error(ie->op, "Only numerical 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));
|
||||
|
||||
bool ok = compare_exact_values(Token_Lt, a, b);
|
||||
if (!ok) {
|
||||
// TODO(bill): Better error message
|
||||
error(ie->op, "Invalid interval expression");
|
||||
goto skip_expr;
|
||||
}
|
||||
}
|
||||
|
||||
add_type_and_value(&c->info, ie->left, x.mode, x.type, x.value);
|
||||
add_type_and_value(&c->info, ie->right, y.mode, y.type, y.value);
|
||||
val = x.type;
|
||||
idx = t_int;
|
||||
} else {
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr(c, &operand, rs->expr);
|
||||
|
||||
if (operand.mode != Addressing_Invalid) {
|
||||
Type *t = base_type(type_deref(operand.type));
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (is_type_string(t)) {
|
||||
val = t_rune;
|
||||
idx = t_int;
|
||||
}
|
||||
break;
|
||||
case Type_Array:
|
||||
val = t->Array.elem;
|
||||
idx = t_int;
|
||||
break;
|
||||
case Type_Slice:
|
||||
val = t->Array.elem;
|
||||
idx = t_int;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (val == NULL) {
|
||||
gbString s = expr_to_string(operand.expr);
|
||||
error_node(node, "Cannot iterate over %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (key == NULL) {
|
||||
gbString s = expr_to_string(operand.expr);
|
||||
error_node(operand.expr, "Cannot iterate over %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
Entity *entities[2] = {0};
|
||||
isize entity_count = 0;
|
||||
AstNode *lhs[2] = {rs->key, rs->value};
|
||||
Type * rhs[2] = {key, val};
|
||||
skip_expr:
|
||||
AstNode *lhs[2] = {rs->value, rs->index};
|
||||
Type * rhs[2] = {val, idx};
|
||||
|
||||
for (isize i = 0; i < 2; i++) {
|
||||
if (lhs[i] == NULL) {
|
||||
|
||||
52
src/parser.c
52
src/parser.c
@@ -160,6 +160,7 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
|
||||
AstNode *body; \
|
||||
AstNode *else_expr; \
|
||||
}) \
|
||||
AST_NODE_KIND(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \
|
||||
AST_NODE_KIND(_ExprEnd, "", i32) \
|
||||
AST_NODE_KIND(_StmtBegin, "", i32) \
|
||||
AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
|
||||
@@ -205,11 +206,11 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
|
||||
AstNode *body; \
|
||||
}) \
|
||||
AST_NODE_KIND(RangeStmt, "range statement", struct { \
|
||||
Token token; \
|
||||
AstNode * key; \
|
||||
AstNode * value; \
|
||||
AstNode * expr; \
|
||||
AstNode * body; \
|
||||
Token token; \
|
||||
AstNode *value; \
|
||||
AstNode *index; \
|
||||
AstNode *expr; \
|
||||
AstNode *body; \
|
||||
}) \
|
||||
AST_NODE_KIND(CaseClause, "case clause", struct { \
|
||||
Token token; \
|
||||
@@ -451,6 +452,8 @@ Token ast_node_token(AstNode *node) {
|
||||
return node->GiveExpr.token;
|
||||
case AstNode_IfExpr:
|
||||
return node->IfExpr.token;
|
||||
case AstNode_IntervalExpr:
|
||||
return ast_node_token(node->IntervalExpr.left);
|
||||
|
||||
case AstNode_BadStmt:
|
||||
return node->BadStmt.begin;
|
||||
@@ -700,6 +703,18 @@ AstNode *make_demaybe_expr(AstFile *f, AstNode *expr, Token op) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_interval_expr(AstFile *f, Token op, AstNode *left, AstNode *right) {
|
||||
AstNode *result = make_node(f, AstNode_IntervalExpr);
|
||||
|
||||
result->IntervalExpr.op = op;
|
||||
result->IntervalExpr.left = left;
|
||||
result->IntervalExpr.right = right;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
AstNode *make_basic_lit(AstFile *f, Token basic_lit) {
|
||||
AstNode *result = make_node(f, AstNode_BasicLit);
|
||||
@@ -854,12 +869,12 @@ AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, As
|
||||
result->ForStmt.body = body;
|
||||
return result;
|
||||
}
|
||||
AstNode *make_range_stmt(AstFile *f, Token token, AstNode *key, AstNode *value, AstNode *expr, AstNode *body) {
|
||||
AstNode *make_range_stmt(AstFile *f, Token token, AstNode *value, AstNode *index, AstNode *expr, AstNode *body) {
|
||||
AstNode *result = make_node(f, AstNode_RangeStmt);
|
||||
result->RangeStmt.token = token;
|
||||
result->RangeStmt.key = key;
|
||||
result->RangeStmt.value = value;
|
||||
result->RangeStmt.expr = expr;
|
||||
result->RangeStmt.index = index;
|
||||
result->RangeStmt.expr = expr;
|
||||
result->RangeStmt.body = body;
|
||||
return result;
|
||||
}
|
||||
@@ -2791,28 +2806,31 @@ AstNode *parse_range_stmt(AstFile *f) {
|
||||
isize prev_level = f->expr_level;
|
||||
f->expr_level = -1;
|
||||
AstNode *expr = parse_expr(f, false);
|
||||
if (f->curr_token.kind == Token_Interval) {
|
||||
Token op = expect_token(f, Token_Interval);
|
||||
AstNode *right = parse_expr(f, false);
|
||||
expr = make_interval_expr(f, op, expr, right);
|
||||
}
|
||||
f->expr_level = prev_level;
|
||||
|
||||
AstNode *key = NULL;
|
||||
AstNode *value = NULL;
|
||||
AstNode *body = parse_block_stmt(f, false);
|
||||
AstNode *index = NULL;
|
||||
AstNode *body = parse_block_stmt(f, false);
|
||||
|
||||
switch (names.count) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
key = names.e[0];
|
||||
value = names.e[0];
|
||||
break;
|
||||
case 2:
|
||||
key = names.e[0];
|
||||
value = names.e[1];
|
||||
value = names.e[0];
|
||||
index = names.e[1];
|
||||
break;
|
||||
default:
|
||||
error_node(names.e[names.count-1], "Expected at most 2 expressions");
|
||||
error(token, "Expected at 1 or 2 identifiers");
|
||||
return make_bad_stmt(f, token, f->curr_token);
|
||||
}
|
||||
|
||||
return make_range_stmt(f, token, key, value, expr, body);
|
||||
return make_range_stmt(f, token, value, index, expr, body);
|
||||
}
|
||||
|
||||
AstNode *parse_case_clause(AstFile *f) {
|
||||
|
||||
177
src/ssa.c
177
src/ssa.c
@@ -3908,8 +3908,15 @@ void ssa_build_when_stmt(ssaProcedure *proc, AstNodeWhenStmt *ws) {
|
||||
}
|
||||
}
|
||||
|
||||
void ssa_emit_increment(ssaProcedure *proc, ssaValue *addr) {
|
||||
GB_ASSERT(is_type_pointer(ssa_type(addr)));
|
||||
Type *type = type_deref(ssa_type(addr));
|
||||
ssa_emit_store(proc, addr, ssa_emit_arith(proc, Token_Add, ssa_emit_load(proc, addr), v_one, type));
|
||||
|
||||
}
|
||||
|
||||
void ssa_build_range_indexed(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
ssaValue **key_, ssaValue **val_, ssaBlock **loop_, ssaBlock **done_) {
|
||||
ssaValue **val_, ssaValue **idx_, ssaBlock **loop_, ssaBlock **done_) {
|
||||
ssaValue *count = NULL;
|
||||
Type *expr_type = base_type(ssa_type(expr));
|
||||
switch (expr_type->kind) {
|
||||
@@ -3924,8 +3931,8 @@ void ssa_build_range_indexed(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
break;
|
||||
}
|
||||
|
||||
ssaValue *idx = NULL;
|
||||
ssaValue *val = NULL;
|
||||
ssaValue *idx = NULL;
|
||||
ssaBlock *loop = NULL;
|
||||
ssaBlock *done = NULL;
|
||||
ssaBlock *body = NULL;
|
||||
@@ -3933,15 +3940,15 @@ void ssa_build_range_indexed(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
ssaValue *index = ssa_add_local_generated(proc, t_int);
|
||||
ssa_emit_store(proc, index, ssa_make_const_int(proc->module->allocator, -1));
|
||||
|
||||
loop = ssa_add_block(proc, NULL, "rangeindex.loop");
|
||||
loop = ssa_add_block(proc, NULL, "range.index.loop");
|
||||
ssa_emit_jump(proc, loop);
|
||||
proc->curr_block = loop;
|
||||
|
||||
ssaValue *incr = ssa_emit_arith(proc, Token_Add, ssa_emit_load(proc, index), v_one, t_int);
|
||||
ssa_emit_store(proc, index, incr);
|
||||
|
||||
body = ssa_add_block(proc, NULL, "rangeindex.body");
|
||||
done = ssa_add_block(proc, NULL, "rangeindex.done");
|
||||
body = ssa_add_block(proc, NULL, "range.index.body");
|
||||
done = ssa_add_block(proc, NULL, "range.index.done");
|
||||
ssaValue *cond = ssa_emit_comp(proc, Token_Lt, incr, count);
|
||||
ssa_emit_if(proc, cond, body, done);
|
||||
proc->curr_block = body;
|
||||
@@ -3962,15 +3969,15 @@ void ssa_build_range_indexed(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
}
|
||||
}
|
||||
|
||||
if (key_) *key_ = idx;
|
||||
if (val_) *val_ = val;
|
||||
if (idx_) *idx_ = idx;
|
||||
if (loop_) *loop_ = loop;
|
||||
if (done_) *done_ = done;
|
||||
}
|
||||
|
||||
|
||||
void ssa_build_range_string(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
ssaValue **key_, ssaValue **val_, ssaBlock **loop_, ssaBlock **done_) {
|
||||
ssaValue **val_, ssaValue **idx_, ssaBlock **loop_, ssaBlock **done_) {
|
||||
ssaValue *count = v_zero;
|
||||
Type *expr_type = base_type(ssa_type(expr));
|
||||
switch (expr_type->kind) {
|
||||
@@ -3982,8 +3989,8 @@ void ssa_build_range_string(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
break;
|
||||
}
|
||||
|
||||
ssaValue *idx = NULL;
|
||||
ssaValue *val = NULL;
|
||||
ssaValue *idx = NULL;
|
||||
ssaBlock *loop = NULL;
|
||||
ssaBlock *done = NULL;
|
||||
ssaBlock *body = NULL;
|
||||
@@ -3994,14 +4001,14 @@ void ssa_build_range_string(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
ssaValue *offset_ = ssa_add_local_generated(proc, t_int);
|
||||
ssa_emit_store(proc, index, v_zero);
|
||||
|
||||
loop = ssa_add_block(proc, NULL, "rangestring.loop");
|
||||
loop = ssa_add_block(proc, NULL, "range.string.loop");
|
||||
ssa_emit_jump(proc, loop);
|
||||
proc->curr_block = loop;
|
||||
|
||||
|
||||
|
||||
body = ssa_add_block(proc, NULL, "rangestring.body");
|
||||
done = ssa_add_block(proc, NULL, "rangestring.done");
|
||||
body = ssa_add_block(proc, NULL, "range.string.body");
|
||||
done = ssa_add_block(proc, NULL, "range.string.done");
|
||||
|
||||
ssaValue *offset = ssa_emit_load(proc, offset_);
|
||||
|
||||
@@ -4023,14 +4030,61 @@ void ssa_build_range_string(ssaProcedure *proc, ssaValue *expr, Type *val_type,
|
||||
if (val_type != NULL) {
|
||||
val = ssa_emit_struct_ev(proc, rune_and_len, 0);
|
||||
}
|
||||
ssa_emit_store(proc, index, ssa_emit_arith(proc, Token_Add, ssa_emit_load(proc, index), v_one, t_int));
|
||||
ssa_emit_increment(proc, index);
|
||||
|
||||
if (key_) *key_ = idx;
|
||||
if (val_) *val_ = val;
|
||||
if (idx_) *idx_ = idx;
|
||||
if (loop_) *loop_ = loop;
|
||||
if (done_) *done_ = done;
|
||||
}
|
||||
|
||||
void ssa_build_range_interval(ssaProcedure *proc, AstNodeIntervalExpr *node, Type *val_type,
|
||||
ssaValue **val_, ssaValue **idx_, ssaBlock **loop_, ssaBlock **done_) {
|
||||
|
||||
ssaValue *lower = ssa_build_expr(proc, node->left);
|
||||
ssaValue *upper = ssa_build_expr(proc, node->right);
|
||||
|
||||
ssaValue *val = NULL;
|
||||
ssaValue *idx = NULL;
|
||||
ssaBlock *loop = NULL;
|
||||
ssaBlock *done = NULL;
|
||||
ssaBlock *body = NULL;
|
||||
|
||||
if (val_type == NULL) {
|
||||
val_type = ssa_type(lower);
|
||||
}
|
||||
ssaValue *value = ssa_add_local_generated(proc, val_type);
|
||||
ssa_emit_store(proc, value, lower);
|
||||
|
||||
ssaValue *index = ssa_add_local_generated(proc, t_int);
|
||||
ssa_emit_store(proc, index, ssa_make_const_int(proc->module->allocator, 0));
|
||||
|
||||
loop = ssa_add_block(proc, NULL, "range.interval.loop");
|
||||
ssa_emit_jump(proc, loop);
|
||||
proc->curr_block = loop;
|
||||
|
||||
body = ssa_add_block(proc, NULL, "range.interval.body");
|
||||
done = ssa_add_block(proc, NULL, "range.interval.done");
|
||||
|
||||
ssaValue *cond = ssa_emit_comp(proc, Token_Lt, ssa_emit_load(proc, value), upper);
|
||||
ssa_emit_if(proc, cond, body, done);
|
||||
proc->curr_block = body;
|
||||
|
||||
if (value != NULL) {
|
||||
val = ssa_emit_load(proc, value);
|
||||
}
|
||||
idx = ssa_emit_load(proc, index);
|
||||
|
||||
ssa_emit_increment(proc, value);
|
||||
ssa_emit_increment(proc, index);
|
||||
|
||||
if (val_) *val_ = val;
|
||||
if (idx_) *idx_ = idx;
|
||||
if (loop_) *loop_ = loop;
|
||||
if (done_) *done_ = done;
|
||||
}
|
||||
|
||||
|
||||
void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
|
||||
switch (node->kind) {
|
||||
case_ast_node(bs, EmptyStmt, node);
|
||||
@@ -4441,77 +4495,80 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
|
||||
case_ast_node(rs, RangeStmt, node);
|
||||
ssa_emit_comment(proc, str_lit("RangeStmt"));
|
||||
|
||||
Type *key_type = NULL;
|
||||
Type *val_type = NULL;
|
||||
if (rs->key != NULL && !ssa_is_blank_ident(rs->key)) {
|
||||
key_type = type_of_expr(proc->module->info, rs->key);
|
||||
}
|
||||
Type *idx_type = NULL;
|
||||
if (rs->value != NULL && !ssa_is_blank_ident(rs->value)) {
|
||||
val_type = type_of_expr(proc->module->info, rs->value);
|
||||
}
|
||||
|
||||
if (key_type != NULL) {
|
||||
ssa_add_local_for_identifier(proc, rs->key, true);
|
||||
if (rs->index != NULL && !ssa_is_blank_ident(rs->index)) {
|
||||
idx_type = type_of_expr(proc->module->info, rs->index);
|
||||
}
|
||||
|
||||
if (val_type != NULL) {
|
||||
ssa_add_local_for_identifier(proc, rs->value, true);
|
||||
}
|
||||
if (idx_type != NULL) {
|
||||
ssa_add_local_for_identifier(proc, rs->index, true);
|
||||
}
|
||||
|
||||
ssaValue *key = NULL;
|
||||
ssaValue *val = NULL;
|
||||
ssaValue *index = NULL;
|
||||
ssaBlock *loop = NULL;
|
||||
ssaBlock *done = NULL;
|
||||
|
||||
Type *expr_type = type_of_expr(proc->module->info, rs->expr);
|
||||
Type *et = base_type(type_deref(expr_type));
|
||||
bool deref = is_type_pointer(expr_type);
|
||||
switch (et->kind) {
|
||||
case Type_Array: {
|
||||
ssaValue *array = ssa_build_addr(proc, rs->expr).addr;
|
||||
if (deref) {
|
||||
array = ssa_emit_load(proc, array);
|
||||
if (rs->expr->kind == AstNode_IntervalExpr) {
|
||||
ssa_build_range_interval(proc, &rs->expr->IntervalExpr, val_type, &val, &index, &loop, &done);
|
||||
} else {
|
||||
Type *expr_type = type_of_expr(proc->module->info, rs->expr);
|
||||
Type *et = base_type(type_deref(expr_type));
|
||||
bool deref = is_type_pointer(expr_type);
|
||||
switch (et->kind) {
|
||||
case Type_Array: {
|
||||
ssaValue *array = ssa_build_addr(proc, rs->expr).addr;
|
||||
if (deref) {
|
||||
array = ssa_emit_load(proc, array);
|
||||
}
|
||||
ssa_build_range_indexed(proc, array, val_type, &val, &index, &loop, &done);
|
||||
} break;
|
||||
case Type_Slice: {
|
||||
ssaValue *slice = ssa_build_expr(proc, rs->expr);
|
||||
if (deref) {
|
||||
slice = ssa_emit_load(proc, slice);
|
||||
}
|
||||
ssa_build_range_indexed(proc, slice, val_type, &val, &index, &loop, &done);
|
||||
} break;
|
||||
case Type_Basic: {
|
||||
ssaValue *string = ssa_build_expr(proc, rs->expr);
|
||||
if (deref) {
|
||||
string = ssa_emit_load(proc, string);
|
||||
}
|
||||
if (is_type_untyped(expr_type)) {
|
||||
ssaValue *s = ssa_add_local_generated(proc, t_string);
|
||||
ssa_emit_store(proc, s, string);
|
||||
string = ssa_emit_load(proc, s);
|
||||
}
|
||||
ssa_build_range_string(proc, string, val_type, &val, &index, &loop, &done);
|
||||
} break;
|
||||
default:
|
||||
GB_PANIC("Cannot range over %s", type_to_string(expr_type));
|
||||
break;
|
||||
}
|
||||
ssa_build_range_indexed(proc, array, val_type, &key, &val, &loop, &done);
|
||||
} break;
|
||||
case Type_Slice: {
|
||||
ssaValue *slice = ssa_build_expr(proc, rs->expr);
|
||||
if (deref) {
|
||||
slice = ssa_emit_load(proc, slice);
|
||||
}
|
||||
ssa_build_range_indexed(proc, slice, val_type, &key, &val, &loop, &done);
|
||||
} break;
|
||||
case Type_Basic: {
|
||||
ssaValue *string = ssa_build_expr(proc, rs->expr);
|
||||
if (deref) {
|
||||
string = ssa_emit_load(proc, string);
|
||||
}
|
||||
if (is_type_untyped(expr_type)) {
|
||||
ssaValue *s = ssa_add_local_generated(proc, t_string);
|
||||
ssa_emit_store(proc, s, string);
|
||||
string = ssa_emit_load(proc, s);
|
||||
}
|
||||
ssa_build_range_string(proc, string, val_type, &key, &val, &loop, &done);
|
||||
} break;
|
||||
default:
|
||||
GB_PANIC("Cannot range over %s", type_to_string(expr_type));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
ssaAddr key_addr = {0};
|
||||
ssaAddr val_addr = {0};
|
||||
if (key_type != NULL) {
|
||||
key_addr = ssa_build_addr(proc, rs->key);
|
||||
}
|
||||
ssaAddr idx_addr = {0};
|
||||
if (val_type != NULL) {
|
||||
val_addr = ssa_build_addr(proc, rs->value);
|
||||
}
|
||||
if (key_type != NULL) {
|
||||
ssa_addr_store(proc, key_addr, key);
|
||||
if (idx_type != NULL) {
|
||||
idx_addr = ssa_build_addr(proc, rs->index);
|
||||
}
|
||||
if (val_type != NULL) {
|
||||
ssa_addr_store(proc, val_addr, val);
|
||||
}
|
||||
if (idx_type != NULL) {
|
||||
ssa_addr_store(proc, idx_addr, index);
|
||||
}
|
||||
|
||||
ssa_push_target_list(proc, done, loop, NULL);
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
||||
TOKEN_KIND(Token_Period, "."), \
|
||||
TOKEN_KIND(Token_Comma, ","), \
|
||||
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||
TOKEN_KIND(Token_RangeExclusive, "..<"), \
|
||||
TOKEN_KIND(Token_Interval, "..<"), \
|
||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||
\
|
||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
@@ -286,6 +286,14 @@ typedef enum TokenizerInitError {
|
||||
} TokenizerInitError;
|
||||
|
||||
|
||||
typedef struct TokenizerState {
|
||||
Rune curr_rune; // current character
|
||||
u8 * curr; // character pos
|
||||
u8 * read_curr; // pos from start
|
||||
u8 * line; // current line pos
|
||||
isize line_count;
|
||||
} TokenizerState;
|
||||
|
||||
typedef struct Tokenizer {
|
||||
String fullpath;
|
||||
u8 *start;
|
||||
@@ -302,6 +310,25 @@ typedef struct Tokenizer {
|
||||
} Tokenizer;
|
||||
|
||||
|
||||
TokenizerState save_tokenizer_state(Tokenizer *t) {
|
||||
TokenizerState state = {0};
|
||||
state.curr_rune = t->curr_rune;
|
||||
state.curr = t->curr;
|
||||
state.read_curr = t->read_curr;
|
||||
state.line = t->line;
|
||||
state.line_count = t->line_count;
|
||||
return state;
|
||||
}
|
||||
|
||||
void restore_tokenizer_state(Tokenizer *t, TokenizerState *state) {
|
||||
t->curr_rune = state->curr_rune;
|
||||
t->curr = state->curr;
|
||||
t->read_curr = state->read_curr;
|
||||
t->line = state->line;
|
||||
t->line_count = state->line_count;
|
||||
}
|
||||
|
||||
|
||||
void tokenizer_err(Tokenizer *t, char *msg, ...) {
|
||||
va_list va;
|
||||
isize column = t->read_curr - t->line+1;
|
||||
@@ -456,23 +483,27 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||
if (t->curr_rune == 'b') { // Binary
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 2);
|
||||
if (t->curr - prev <= 2)
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else if (t->curr_rune == 'o') { // Octal
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 8);
|
||||
if (t->curr - prev <= 2)
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else if (t->curr_rune == 'd') { // Decimal
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 10);
|
||||
if (t->curr - prev <= 2)
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else if (t->curr_rune == 'x') { // Hexadecimal
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 16);
|
||||
if (t->curr - prev <= 2)
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else {
|
||||
seen_decimal_point = false;
|
||||
scan_mantissa(t, 10);
|
||||
@@ -491,8 +522,15 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||
|
||||
fraction:
|
||||
if (t->curr_rune == '.') {
|
||||
token.kind = Token_Float;
|
||||
// HACK(bill): This may be inefficient
|
||||
TokenizerState state = save_tokenizer_state(t);
|
||||
advance_to_next_rune(t);
|
||||
if (t->curr_rune == '.') {
|
||||
// TODO(bill): Clean up this shit
|
||||
restore_tokenizer_state(t, &state);
|
||||
goto end;
|
||||
}
|
||||
token.kind = Token_Float;
|
||||
scan_mantissa(t, 10);
|
||||
}
|
||||
|
||||
@@ -506,6 +544,7 @@ exponent:
|
||||
scan_mantissa(t, 10);
|
||||
}
|
||||
|
||||
end:
|
||||
token.string.len = t->curr - token.string.text;
|
||||
return token;
|
||||
}
|
||||
@@ -801,7 +840,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.kind = Token_Ellipsis;
|
||||
if (t->curr_rune == '<') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_RangeExclusive;
|
||||
token.kind = Token_Interval;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user