diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-01-03 18:02:13 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-01-03 18:02:13 +0000 |
| commit | a86896e4d30b118287cf2111cd2fbec00ed2be70 (patch) | |
| tree | 15198095de38744739e239bfac3c160dfa936d58 | |
| parent | a3883a178c1e4e10058089a2832004a6ce1521e2 (diff) | |
Interval expressions in `range`
| -rw-r--r-- | code/demo.odin | 16 | ||||
| -rw-r--r-- | src/checker/expr.c | 5 | ||||
| -rw-r--r-- | src/checker/stmt.c | 132 | ||||
| -rw-r--r-- | src/parser.c | 52 | ||||
| -rw-r--r-- | src/ssa.c | 177 | ||||
| -rw-r--r-- | src/tokenizer.c | 53 |
6 files changed, 316 insertions, 119 deletions
diff --git a/code/demo.odin b/code/demo.odin index 05a9dfd50..05307c40f 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -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); } } diff --git a/src/checker/expr.c b/src/checker/expr.c index 3c7403143..bf1303e4c 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -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; diff --git a/src/checker/stmt.c b/src/checker/stmt.c index 60154855f..6113c519a 100644 --- a/src/checker/stmt.c +++ b/src/checker/stmt.c @@ -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); + Type *val = NULL; + Type *idx = NULL; + Entity *entities[2] = {0}; + isize entity_count = 0; - 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; + 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 (key == NULL) { - gbString s = expr_to_string(operand.expr); - error_node(operand.expr, "Cannot iterate over %s", s); - gb_string_free(s); + 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); + } } - 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) { diff --git a/src/parser.c b/src/parser.c index da87a6c7c..1332fd929 100644 --- a/src/parser.c +++ b/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) { @@ -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 (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 (key_) *key_ = idx; 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); - } - 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); + 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_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); diff --git a/src/tokenizer.c b/src/tokenizer.c index 5e0f31279..b5f46bcd7 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -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; |