diff options
-rw-r--r-- | cgen.c | 91 | ||||
-rw-r--r-- | eval.c | 113 | ||||
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | parse.c | 25 | ||||
-rwxr-xr-x | runv | 4 | ||||
-rw-r--r-- | test.toc | 23 | ||||
-rw-r--r-- | tokenizer.c | 4 | ||||
-rw-r--r-- | types.c | 12 | ||||
-rw-r--r-- | types.h | 16 |
9 files changed, 153 insertions, 138 deletions
@@ -1661,14 +1661,15 @@ static void cgen_stmt(CGenerator *g, Statement *s) { } break; case STMT_FOR: { For *fo = s->for_; - int is_range = fo->flags & FOR_IS_RANGE; + ForFlags flags = fo->flags; + U32 is_range = flags & FOR_IS_RANGE; Declaration *header_decl = &fo->header; Identifier val_ident = header_decl->idents[0]; Identifier index_ident = header_decl->idents[1]; Type *fo_type = &header_decl->type; assert(fo_type->kind == TYPE_TUPLE && arr_len(fo_type->tuple) == 2); Type *val_type = &fo_type->tuple[0]; - Type *index_type = &fo_type->tuple[1]; + assert(type_is_builtin(&fo_type->tuple[1], BUILTIN_I64)); /* index type is always int */ bool has_val = !ident_eq_str(val_ident, "_"); bool has_index = !ident_eq_str(index_ident, "_"); @@ -1746,16 +1747,50 @@ static void cgen_stmt(CGenerator *g, Statement *s) { } if (has_index) { - cgen_type_pre(g, index_type); - cgen_write(g, " "); + cgen_write(g, "i64 "); cgen_ident(g, index_ident); - cgen_type_post(g, index_type); /* not needed yet, but keeping it here to prevent potential future problems */ cgen_write(g, " = 0; "); } cgen_write(g, "for ("); - - if (!is_range) { + if (is_range) { + bool positive_step + = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, val_type); + if (!(flags & FOR_INCLUDES_FROM)) { + if (has_val) + cgen_ident(g, val_ident); + else + cgen_write(g, "val_"); + cgen_write(g, " += "); + if (fo->range.stepval) { + cgen_val(g, fo->range.stepval, val_type); + } else { + cgen_write(g, "1"); + } + } + cgen_write(g, "; "); + if (fo->range.to) { /* if finite */ + if (has_val) + cgen_ident(g, val_ident); + else + cgen_write(g, "val_"); + cgen_write(g, " %c%s to_; ", positive_step ? '<' : '>', (flags & FOR_INCLUDES_TO) ? "=" : ""); + } + if (fo->range.stepval) { + cgen_val_pre(g, fo->range.stepval, val_type); + } + if (has_val) + cgen_ident(g, val_ident); + else + cgen_write(g, "val_"); + cgen_write(g, " += "); + if (fo->range.stepval) { + cgen_val(g, fo->range.stepval, val_type); + } else { + cgen_write(g, "1"); + } + if (has_index) { cgen_write(g, ", ++"); cgen_ident(g, index_ident); } + } else { cgen_type_pre(g, val_type); cgen_write(g, "(%sp_)", uses_ptr ? "" : "*"); cgen_type_post(g, val_type); @@ -1779,46 +1814,10 @@ static void cgen_stmt(CGenerator *g, Statement *s) { break; default: assert(0); break; } + cgen_write(g, "; p_ != end_; ++p_"); + if (has_index) { cgen_write(g, ", ++"); cgen_ident(g, index_ident); } } - - cgen_write(g, "; "); - if (!(is_range && !fo->range.to)) { /* if it's finite */ - if (is_range) { - if (has_val) - cgen_ident(g, val_ident); - else - cgen_write(g, "val_"); - bool positive_step - = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, val_type); - cgen_write(g, " %c= to_", positive_step ? '<' : '>'); - } else { - cgen_write(g, "p_ != end_"); - } - } - cgen_write(g, "; "); - if (is_range) { - if (fo->range.stepval) { - cgen_val_pre(g, fo->range.stepval, val_type); - } - if (has_val) - cgen_ident(g, val_ident); - else - cgen_write(g, "val_"); - cgen_write(g, " += "); - if (fo->range.stepval) { - cgen_val(g, fo->range.stepval, val_type); - } else { - cgen_write(g, "1"); - } - if (has_index) cgen_write(g, ", "); - } else { - cgen_write(g, "++p_"); - if (has_index) cgen_write(g, ", "); - } - if (has_index) { - cgen_write(g, "++"); - cgen_ident(g, index_ident); - } + cgen_write(g, ") {"); cgen_nl(g); if (has_val) { @@ -300,35 +300,35 @@ static inline void val_free_ptr(Value *v, Type *t) { #define builtin_casts_to_int(x) \ case BUILTIN_I8: \ - vout->i8 = (I8)(I64)vin->x; break; \ + vout->i8 = (I8)(I64)vin.x; break; \ case BUILTIN_I16: \ - vout->i16 = (I16)(I64)vin->x; break; \ + vout->i16 = (I16)(I64)vin.x; break; \ case BUILTIN_I32: \ - vout->i32 = (I32)(I64)vin->x; break; \ + vout->i32 = (I32)(I64)vin.x; break; \ case BUILTIN_I64: \ - vout->i64 = (I64)vin->x; break; \ + vout->i64 = (I64)vin.x; break; \ case BUILTIN_U8: \ - vout->u8 = (U8)(U64)vin->x; break; \ + vout->u8 = (U8)(U64)vin.x; break; \ case BUILTIN_U16: \ - vout->u16 = (U16)(U64)vin->x; break; \ + vout->u16 = (U16)(U64)vin.x; break; \ case BUILTIN_U32: \ - vout->u32 = (U32)(U64)vin->x; break; \ + vout->u32 = (U32)(U64)vin.x; break; \ case BUILTIN_U64: \ - vout->u64 = (U64)vin->x; break + vout->u64 = (U64)vin.x; break #define builtin_casts_to_num(x) \ builtin_casts_to_int(x); \ case BUILTIN_F32: \ - vout->f32 = (F32)vin->x; break; \ + vout->f32 = (F32)vin.x; break; \ case BUILTIN_F64: \ - vout->f64 = (F64)vin->x; break + vout->f64 = (F64)vin.x; break #define builtin_int_casts(low, up) \ case BUILTIN_##up: \ switch (to) { \ builtin_casts_to_num(low); \ - case BUILTIN_CHAR: vout->charv = (char)vin->low; break; \ - case BUILTIN_BOOL: vout->boolv = vin->low != 0; break; \ + case BUILTIN_CHAR: vout->charv = (char)vin.low; break; \ + case BUILTIN_BOOL: vout->boolv = vin.low != 0; break; \ case BUILTIN_NMS: \ case BUILTIN_VOID: \ case BUILTIN_TYPE: \ @@ -340,7 +340,7 @@ static inline void val_free_ptr(Value *v, Type *t) { case BUILTIN_##up: \ switch (to) { \ builtin_casts_to_num(low); \ - case BUILTIN_BOOL: vout->boolv = vin->low != 0.0f; break; \ + case BUILTIN_BOOL: vout->boolv = vin.low != 0.0f; break; \ case BUILTIN_CHAR: \ case BUILTIN_TYPE: \ case BUILTIN_NMS: \ @@ -349,9 +349,9 @@ static inline void val_free_ptr(Value *v, Type *t) { assert(0); break; \ } break -static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinType to) { +static void val_builtin_cast(Value vin, BuiltinType from, Value *vout, BuiltinType to) { if (from == to) { - *vout = *vin; + *vout = vin; return; } switch (from) { @@ -366,7 +366,7 @@ static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinT builtin_float_casts(f32, F32); builtin_float_casts(f64, F64); - case BUILTIN_BOOL: vout->boolv = builtin_truthiness(*vin, from); break; + case BUILTIN_BOOL: vout->boolv = builtin_truthiness(vin, from); break; case BUILTIN_CHAR: switch (to) { builtin_casts_to_int(charv); @@ -390,12 +390,12 @@ static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinT } } -static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { +static void val_cast(Value vin, Type *from, Value *vout, Type *to) { assert(from->flags & TYPE_IS_RESOLVED); assert(to->flags & TYPE_IS_RESOLVED); if (to->kind == TYPE_BUILTIN && to->builtin == BUILTIN_BOOL) { - vout->boolv = val_truthiness(*vin, from); + vout->boolv = val_truthiness(vin, from); return; } @@ -412,14 +412,14 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { break; case TYPE_PTR: switch (from->builtin) { - case BUILTIN_I8: vout->ptr = (void *)(U64)vin->i8; break; - case BUILTIN_I16: vout->ptr = (void *)(U64)vin->i16; break; - case BUILTIN_I32: vout->ptr = (void *)(U64)vin->i32; break; - case BUILTIN_I64: vout->ptr = (void *)(U64)vin->i64; break; - case BUILTIN_U8: vout->ptr = (void *)(U64)vin->u8; break; - case BUILTIN_U16: vout->ptr = (void *)(U64)vin->u16; break; - case BUILTIN_U32: vout->ptr = (void *)(U64)vin->u32; break; - case BUILTIN_U64: vout->ptr = (void *)(U64)vin->u64; break; + case BUILTIN_I8: vout->ptr = (void *)(U64)vin.i8; break; + case BUILTIN_I16: vout->ptr = (void *)(U64)vin.i16; break; + case BUILTIN_I32: vout->ptr = (void *)(U64)vin.i32; break; + case BUILTIN_I64: vout->ptr = (void *)(U64)vin.i64; break; + case BUILTIN_U8: vout->ptr = (void *)(U64)vin.u8; break; + case BUILTIN_U16: vout->ptr = (void *)(U64)vin.u16; break; + case BUILTIN_U32: vout->ptr = (void *)(U64)vin.u32; break; + case BUILTIN_U64: vout->ptr = (void *)(U64)vin.u64; break; default: assert(0); break; } break; @@ -438,10 +438,10 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_FN: switch (to->kind) { case TYPE_PTR: - vout->ptr = (void *)vin->fn; + vout->ptr = (void *)vin.fn; break; case TYPE_FN: - vout->fn = vin->fn; + vout->fn = vin.fn; break; default: assert(0); break; @@ -465,13 +465,13 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { } break; case TYPE_ARR: - vout->arr = vin->ptr; + vout->arr = vin.ptr; break; case TYPE_PTR: - vout->ptr = vin->ptr; + vout->ptr = vin.ptr; break; case TYPE_FN: - vout->fn = vin->ptr; + vout->fn = vin.ptr; break; default: assert(0); @@ -482,10 +482,10 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_ARR: switch (to->kind) { case TYPE_PTR: - vout->ptr = vin->arr; + vout->ptr = vin.arr; break; case TYPE_ARR: - vout->arr = vin->arr; + vout->arr = vin.arr; break; default: assert(0); break; @@ -494,13 +494,13 @@ static void val_cast(Value *vin, Type *from, Value *vout, Type *to) { case TYPE_SLICE: switch (to->kind) { case TYPE_PTR: - vout->ptr = vin->slice.data; + vout->ptr = vin.slice.data; break; case TYPE_ARR: - vout->arr = vin->slice.data; + vout->arr = vin.slice.data; break; case TYPE_SLICE: - vout->slice = vin->slice; + vout->slice = vin.slice; break; default: assert(0); break; @@ -858,6 +858,7 @@ static Status eval_set(Evaluator *ev, Expression *set, Value *to) { return true; } +/* @TODO(eventually): this could probably be made better */ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value rhs, Type *rhs_type, Value *out, Type *out_type) { /* WARNING: macros ahead */ @@ -888,8 +889,8 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value #define eval_binary_op_nums_only(op) \ - val_cast(&lhs, lhs_type, &lhs, out_type); \ - val_cast(&rhs, rhs_type, &rhs, out_type); \ + val_cast(lhs, lhs_type, &lhs, out_type); \ + val_cast(rhs, rhs_type, &rhs, out_type); \ assert(out_type->kind == TYPE_BUILTIN); \ switch (builtin) { \ eval_binary_op_nums(builtin, op); \ @@ -897,8 +898,8 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value } #define eval_binary_op_ints_only(op) \ - val_cast(&lhs, lhs_type, &lhs, out_type); \ - val_cast(&rhs, rhs_type, &rhs, out_type); \ + val_cast(lhs, lhs_type, &lhs, out_type); \ + val_cast(rhs, rhs_type, &rhs, out_type); \ assert(out_type->kind == TYPE_BUILTIN); \ switch (builtin) { \ eval_binary_op_ints(builtin, op); \ @@ -927,8 +928,8 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value #define eval_binary_bool_op_nums_only(op) \ {Type *cast_to = lhs_type->flags & TYPE_IS_FLEXIBLE ? \ rhs_type : lhs_type; \ - val_cast(&lhs, lhs_type, &lhs, cast_to); \ - val_cast(&rhs, rhs_type, &rhs, cast_to); \ + val_cast(lhs, lhs_type, &lhs, cast_to); \ + val_cast(rhs, rhs_type, &rhs, cast_to); \ assert(lhs_type->kind == TYPE_BUILTIN); \ switch (cast_to->builtin) { \ eval_binary_bool_op_nums(builtin, op); \ @@ -954,11 +955,11 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value case BINARY_SUB: if (lhs_type->kind == TYPE_PTR) { if (rhs_type->kind == TYPE_PTR) { - out->i64 = (I64)((char *)rhs.ptr - (char *)lhs.ptr) / (I64)compiler_sizeof(lhs_type); - + out->i64 = (I64)((char *)lhs.ptr - (char *)rhs.ptr) / (I64)compiler_sizeof(lhs_type->ptr); + } else { + out->ptr = (char *)lhs.ptr - val_to_i64(rhs, rhs_type->builtin) + * (I64)compiler_sizeof(lhs_type->ptr); } - out->ptr = (char *)lhs.ptr - val_to_i64(rhs, rhs_type->builtin) - * (I64)compiler_sizeof(lhs_type->ptr); } else { eval_binary_op_nums_only(-); } @@ -1235,7 +1236,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { case EXPR_CAST: { Value casted; if (!eval_expr(ev, e->cast.expr, &casted)) return false; - val_cast(&casted, &e->cast.expr->type, v, &e->cast.type); + val_cast(casted, &e->cast.expr->type, v, &e->cast.type); } break; case EXPR_FN: v->fn = e->fn; @@ -1609,7 +1610,9 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) { Value *value_val = &for_val_tuple[0]; Value *index_val = &for_val_tuple[1]; Type *value_type = &header->type.tuple[0]; - if (fo->flags & FOR_IS_RANGE) { + ForFlags flags = fo->flags; + + if (flags & FOR_IS_RANGE) { assert(value_type->kind == TYPE_BUILTIN); Value from, to; Value stepval; @@ -1618,9 +1621,19 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) { if (fo->range.to && !eval_expr(ev, fo->range.to, &to)) return false; if (fo->range.stepval) stepval = *fo->range.stepval; - Value x = from; + Value x; + val_cast(from, &fo->range.from->type, &x, value_type); bool step_is_negative = fo->range.stepval && !val_is_nonnegative(stepval, value_type); if (index_val) index_val->i64 = 0; + BinaryOp compare_binop; + if (flags & FOR_INCLUDES_TO) { + compare_binop = step_is_negative ? BINARY_GE : BINARY_LE; + } else { + compare_binop = step_is_negative ? BINARY_GT : BINARY_LT; + } + if (!(flags & FOR_INCLUDES_FROM)) { + eval_numerical_bin_op(x, value_type, BINARY_ADD, stepval, value_type, &x, value_type); + } while (1) { if (fo->range.to) { /* check if loop has ended */ @@ -1632,7 +1645,7 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) { boolt.builtin = BUILTIN_BOOL; Value cont; - eval_numerical_bin_op(lhs, value_type, step_is_negative ? BINARY_GE : BINARY_LE, rhs, &fo->range.to->type, &cont, &boolt); + eval_numerical_bin_op(lhs, value_type, compare_binop, rhs, &fo->range.to->type, &cont, &boolt); if (!cont.boolv) break; } if (value_val) *value_val = x; @@ -8,11 +8,10 @@ /* @TODO: -a..b should probably only go up to b-1 figure out how printf is gonna work if we do #include "foo.toc", bar; and foo.toc fails, bar should be declared as TYPE_UNKNOWN (right now it's undeclared) fix #foreign not at global scope - right now the cgen'd definition doesn't use the proper type -find out why file output is really slow at compile time; try to improve it +find out why loop with file output is really slow at compile time; try to improve it improve type_to_str: Foo ::= struct(t::Type) {} type_to_str(Foo(int)) @@ -430,6 +430,9 @@ static Token *expr_find_end(Parser *p, ExprEndFlags flags) { return token; break; case KW_DOTDOT: + case KW_DOTCOMMA: + case KW_COMMADOT: + case KW_COMMACOMMA: if (all_levels_0 && (flags & EXPR_CAN_END_WITH_DOTDOT)) return token; break; @@ -2212,6 +2215,10 @@ static bool is_decl(Tokenizer *t) { } } +static bool is_for_range_separator(Keyword kw) { + return kw == KW_DOTDOT || kw == KW_DOTCOMMA || kw == KW_COMMADOT || kw == KW_COMMACOMMA; +} + /* sets *was_a_statement to false if s was not filled, but the token was advanced */ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { Tokenizer *t = p->tokr; @@ -2417,7 +2424,8 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { goto for_fail; if (token_is_kw(first_end, KW_LBRACE)) { fo->of = first; - } else if (token_is_kw(first_end, KW_DOTDOT) || token_is_kw(first_end, KW_COMMA)) { + } else if (first_end->kind == TOKEN_KW && + (is_for_range_separator(first_end->kw) || first_end->kw == KW_COMMA)) { fo->flags |= FOR_IS_RANGE; fo->range.from = first; if (token_is_kw(first_end, KW_COMMA)) { @@ -2425,16 +2433,23 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { ++t->token; fo->range.step = parser_new_expr(p); Token *step_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE|EXPR_CAN_END_WITH_DOTDOT); - if (!parse_expr(p, fo->range.step, step_end)) - goto for_fail; - if (!token_is_kw(step_end, KW_DOTDOT)) { - err_print(token_location(p->file, step_end), "Expected .. to follow step in for statement."); + if (step_end->kind != TOKEN_KW || !is_for_range_separator(step_end->kw)) { + err_print(token_location(p->file, step_end), "Expected .. / ., / ,. / ,, to follow step in for statement."); tokr_skip_to_eof(t); goto for_fail; } + if (!parse_expr(p, fo->range.step, step_end)) + goto for_fail; } else { fo->range.step = NULL; } + { + Keyword separator = t->token->kw; + if (separator == KW_DOTDOT || separator == KW_DOTCOMMA) + fo->flags |= FOR_INCLUDES_FROM; + if (separator == KW_DOTDOT || separator == KW_COMMADOT) + fo->flags |= FOR_INCLUDES_TO; + } ++t->token; /* move past .. */ if (token_is_kw(t->token, KW_LBRACE)) { fo->range.to = NULL; /* infinite loop! */ @@ -12,8 +12,8 @@ fi valgrind $FLAGS --track-origins=yes --exit-on-first-error=yes --error-exitcode=1 --malloc-fill=0xcd --free-fill=0xef --num-callers=100 ./toc $tocf || exit 1 if [ "$1" = "c" ]; then - gcc out.c -g -Wno-builtin-declaration-mismatch && ./a.out + ./test elif [ "$1" = "pc" ]; then - cat out.c + cat test.c fi rm vgcore* 2> /dev/null @@ -2,25 +2,8 @@ #include "std/mem.toc"; main ::= fn() { - n := 100000000; - sieve := news(bool, n); - sieve[0] = true; - sieve[1] = true; - i := 0; - while i*i <= n { - defer i += 1; - if sieve[i] { continue; } - j := 2*i; - while j < n { - sieve[j] = true; - j += i; - } + for i, v : (float, int) = 10,-1,.0 { + io.puti(i as int); } - total := 0; - for is_composite, i := sieve { - if !is_composite { - total += i; - } - } - io.puti(total); } +main(); diff --git a/tokenizer.c b/tokenizer.c index 3f83e6f..d384da2 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -387,8 +387,8 @@ static Status tokenize_file(Tokenizer *t, File *file) { } while (1) { if (*t->s == '.') { - if (t->s[1] == '.') { - /* .. (not a decimal point; end the number here) */ + if (!isdigit(t->s[1])) { + /* not a decimal point; end the number here (could be .. or .,) */ break; } if (token->kind == TOKEN_LITERAL_FLOAT) { @@ -8,7 +8,7 @@ static Status types_block(Typer *tr, Block *b); static Status types_decl(Typer *tr, Declaration *d); static Status type_resolve(Typer *tr, Type *t, Location where); static Status eval_expr(Evaluator *ev, Expression *e, Value *v); -static void val_cast(Value *vin, Type *from, Value *vout, Type *to); +static void val_cast(Value vin, Type *from, Value *vout, Type *to); static U64 val_to_u64(Value v, BuiltinType v_type); static I64 val_to_i64(Value v, BuiltinType v_type); static bool val_truthiness(Value v, Type *t); @@ -660,7 +660,7 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { if (param->expr.type.flags & TYPE_IS_FLEXIBLE) { /* cast to the annotated type, if one exists */ if (param->flags & DECL_ANNOTATES_TYPE) { - val_cast(¶m->expr.val, ¶m->expr.type, ¶m->expr.val, ¶m->type); + val_cast(param->expr.val, ¶m->expr.type, ¶m->expr.val, ¶m->type); param->expr.type = param->type; } } @@ -3384,10 +3384,10 @@ top: index_type = &fo_type_tuple[1]; assert(val_type->flags & TYPE_IS_RESOLVED); assert(index_type->flags & TYPE_IS_RESOLVED); - if (!type_is_int(index_type)) { + if (!type_is_builtin(index_type, BUILTIN_I64)) { char *str = type_to_str(index_type); - err_print(header->where, "Expected index type of for loop to be a builtin integer type, but it's %s.", str); - free(s); + err_print(header->where, "Expected index type of for loop to be type int, but it's %s.", str); + free(str); goto for_fail; } } else { @@ -3485,7 +3485,7 @@ top: info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant."); goto for_fail; } - val_cast(stepval, &fo->range.step->type, stepval, val_type); + val_cast(*stepval, &fo->range.step->type, stepval, val_type); fo->range.stepval = stepval; } } else { @@ -250,7 +250,6 @@ static const char *directives[DIRECT_COUNT] = { typedef enum { KW_SEMICOLON, KW_COLON, - KW_COMMA, KW_LPAREN, KW_RPAREN, KW_LBRACE, @@ -278,6 +277,10 @@ typedef enum { KW_SLASH, KW_PERCENT, KW_DOTDOT, + KW_DOTCOMMA, + KW_COMMADOT, + KW_COMMACOMMA, + KW_COMMA, KW_DOT, KW_EQ, KW_LAST_SYMBOL = KW_EQ, /* last one entirely consisting of symbols */ @@ -322,10 +325,10 @@ typedef enum { } Keyword; static const char *const keywords[KW_COUNT] = { - ";", ":", ",", "(", ")", "{", "}", "[", "]", "==", + ";", ":", "(", ")", "{", "}", "[", "]", "==", "+=", "-=", "*=", "/=", "%=", "!=", "<=", "<", ">=", ">", "&&", "||", - "+", "-", "*", "!", "&", "/", "%", "..", ".", + "+", "-", "*", "!", "&", "/", "%", "..", ".,", ",.", ",,", ",", ".", "=", "if", "elif", "else", "while", "for", "return", "break", "continue", "defer", "fn", "as", "struct", @@ -864,10 +867,13 @@ typedef struct While { } While; enum { - FOR_IS_RANGE = 0x01 + FOR_IS_RANGE = 0x01, + FOR_INCLUDES_FROM = 0x02, + FOR_INCLUDES_TO = 0x04 }; +typedef U8 ForFlags; typedef struct For { - U8 flags; + ForFlags flags; Declaration header; Block body; union { |