diff options
-rw-r--r-- | cgen.c | 152 | ||||
-rw-r--r-- | decls_cgen.c | 13 | ||||
-rw-r--r-- | eval.c | 122 | ||||
-rw-r--r-- | identifiers.c | 14 | ||||
-rw-r--r-- | main.c | 8 | ||||
-rw-r--r-- | parse.c | 143 | ||||
-rw-r--r-- | scope.c | 45 | ||||
-rw-r--r-- | test.toc | 53 | ||||
-rw-r--r-- | tokenizer.c | 10 | ||||
-rw-r--r-- | typedefs_cgen.c | 13 | ||||
-rw-r--r-- | types.c | 284 | ||||
-rw-r--r-- | types.h | 48 |
12 files changed, 757 insertions, 148 deletions
@@ -1,6 +1,6 @@ static bool cgen_stmt(CGenerator *g, Statement *s); -#define CGEN_BLOCK_FLAG_NOENTER 0x01 /* should cgen_block actually enter and exit the block? */ -#define CGEN_BLOCK_FLAG_NOBRACES 0x02 /* should it use braces? */ +#define CGEN_BLOCK_NOENTER 0x01 /* should cgen_block actually enter and exit the block? */ +#define CGEN_BLOCK_NOBRACES 0x02 /* should it use braces? */ static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, uint16_t flags); static bool cgen_expr_pre(CGenerator *g, Expression *e); static bool cgen_expr(CGenerator *g, Expression *e); @@ -9,6 +9,7 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where); static bool cgen_type_post(CGenerator *g, Type *t, Location where); static bool cgen_decl(CGenerator *g, Declaration *d); static bool cgen_ret(CGenerator *g, Expression *ret); +static bool cgen_val(CGenerator *g, Value *v, Type *t, Location where); static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where); static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *ev) { @@ -19,6 +20,7 @@ static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *e g->will_indent = true; g->indent_lvl = 0; g->anon_fns = NULL; + g->idents = ids; } static bool cgen_block_enter(CGenerator *g, Block *b) { @@ -121,6 +123,7 @@ static void cgen_ident(CGenerator *g, Identifier i) { } } + static char *cgen_ident_to_str(Identifier i) { return ident_to_str(i); } @@ -131,6 +134,12 @@ static inline void cgen_ident_id_to_str(char *buffer, IdentID id) { snprintf(buffer, 32, "a%lu_", (unsigned long)id); } +static inline Identifier cgen_ident_id_to_ident(CGenerator *g, IdentID id) { + char s[32]; + cgen_ident_id_to_str(s, id); + return ident_get(g->idents, s); +} + static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { assert(t->flags & TYPE_FLAG_RESOLVED); switch (t->kind) { @@ -500,6 +509,9 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, case EXPR_WHILE: prefix_id = to->while_.c.id; goto prefixed; + case EXPR_EACH: + prefix_id = to->each.c.id; + goto prefixed; prefixed: for (unsigned long i = 0; i < (unsigned long)arr_len(to->type.tuple); i++) { cgen_write(g, "("); @@ -596,6 +608,7 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { switch (e->kind) { case EXPR_IF: case EXPR_WHILE: + case EXPR_EACH: case EXPR_BLOCK: { id = g->ident_counter++; @@ -658,6 +671,125 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { if (!cgen_block(g, &w->body, ret_name, 0)) return false; } break; + case EXPR_EACH: { + EachExpr *ea = &e->each; + int is_range = ea->flags & EACH_IS_RANGE; + IdentID slice_id; + IdentID from_id; + if (!is_range && ea->of->type.kind == TYPE_SLICE) { + /* pre-generate the slice */ + slice_id = g->ident_counter++; + cgen_write(g, "slice_ "); + cgen_ident_id(g, slice_id); + cgen_write(g, " = "); + if (!cgen_expr(g, ea->of)) return false; + cgen_write(g, "; "); + } else if (is_range) { + /* pre-generate from */ + from_id = g->ident_counter++; + if (!cgen_type_pre(g, &ea->type, e->where)) return false; + cgen_write(g, " "); + cgen_ident_id(g, from_id); + if (!cgen_type_post(g, &ea->type, e->where)) return false; + cgen_write(g, " = "); + if (!cgen_expr(g, ea->range.from)) + return false; + cgen_write(g, "; "); + } + ea->c.id = id; + if (ea->index == NULL) + ea->c.index_id = g->ident_counter++; + if (!each_enter(e, 0)) return false; + cgen_write(g, "for (i64 "); + if (ea->index) + cgen_ident(g, ea->index); + else + cgen_ident_id(g, ea->c.index_id); + cgen_write(g, " = 0; "); + if (!(is_range && !ea->range.to)) { + if (ea->index) + cgen_ident(g, ea->index); + else + cgen_ident_id(g, ea->c.index_id); + if (is_range) { + bool positive_step + = ea->range.stepval == NULL || val_is_nonnegative(ea->range.stepval, &ea->type); + cgen_write(g, " %c= ", positive_step ? '<' : '>'); + if (!cgen_expr(g, ea->range.to)) + return false; + cgen_write(g, "-"); + cgen_ident_id(g, from_id); + } else { + cgen_write(g, " < "); + switch (ea->of->type.kind) { + case TYPE_ARR: + cgen_write(g, "%lu", (unsigned long)ea->of->type.arr.n); + break; + case TYPE_SLICE: + cgen_ident_id(g, slice_id); + cgen_write(g, ".len"); + break; + default: assert(0); break; + } + } + } + cgen_write(g, "; "); + if (ea->index) + cgen_ident(g, ea->index); + else + cgen_ident_id(g, ea->c.index_id); + cgen_write(g, " += "); + if (is_range && ea->range.stepval) { + if (!cgen_val(g, ea->range.stepval, &ea->type, e->where)) + return false; + } else { + cgen_write(g, "1"); + } + cgen_write(g, ") {"); + cgen_nl(g); + if (ea->value) { + if (is_range) { + if (!cgen_type_pre(g, &ea->type, e->where)) return false; + cgen_write(g, " "); + cgen_ident(g, ea->value); + if (!cgen_type_post(g, &ea->type, e->where)) return false; + cgen_write(g, " = "); + cgen_ident_id(g, from_id); + cgen_write(g, " + "); + if (ea->index) + cgen_ident(g, ea->index); + else + cgen_ident_id(g, ea->c.index_id); + cgen_write(g, ";"); + cgen_nl(g); + } else { + /* necessary for iterating over, e.g., an array of arrays */ + Expression set; + set.flags = 0; + set.kind = EXPR_IDENT; + set.ident = ea->value; + + Expression to; + to.flags = 0; + to.kind = EXPR_BINARY_OP; + to.binary.op = BINARY_AT_INDEX; + to.binary.lhs = ea->of; + to.binary.rhs = err_malloc(sizeof(Expression)); + to.binary.rhs->flags = 0; + to.binary.rhs->kind = EXPR_IDENT; + if (ea->index) + to.binary.rhs->ident = ea->index; + else + to.binary.rhs->ident = cgen_ident_id_to_ident(g, ea->c.id); + if (!cgen_set(g, &set, NULL, &to, NULL)) + return false; + } + } + if (!cgen_block(g, &ea->body, ret_name, CGEN_BLOCK_NOBRACES)) + return false; + cgen_write(g, "}"); + each_exit(e); + } break; case EXPR_BLOCK: e->block_ret_id = id; if (!cgen_block(g, &e->block, ret_name, 0)) @@ -969,6 +1101,10 @@ static bool cgen_expr(CGenerator *g, Expression *e) { if (e->type.kind != TYPE_VOID) cgen_ident_id(g, e->block_ret_id); break; + case EXPR_EACH: + if (e->type.kind != TYPE_VOID) + cgen_ident_id(g, e->each.c.id); + break; case EXPR_CALL: if (cgen_uses_ptr(&e->type)) { cgen_ident_id(g, e->call.c.id); @@ -1047,11 +1183,11 @@ static bool cgen_expr(CGenerator *g, Expression *e) { functions always call with NULL as ret_name, even if they use out params, for now at least. */ -static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, uint16_t flags) { +static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags) { Block *prev = g->block; - if (!(flags & CGEN_BLOCK_FLAG_NOBRACES)) + if (!(flags & CGEN_BLOCK_NOBRACES)) cgen_write(g, "{"); - if (!(flags & CGEN_BLOCK_FLAG_NOENTER)) + if (!(flags & CGEN_BLOCK_NOENTER)) if (!cgen_block_enter(g, b)) return false; cgen_nl(g); @@ -1068,9 +1204,9 @@ static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, uint16_t f } cgen_nl(g); } - if (!(flags & CGEN_BLOCK_FLAG_NOENTER)) + if (!(flags & CGEN_BLOCK_NOENTER)) cgen_block_exit(g, prev); - if (!(flags & CGEN_BLOCK_FLAG_NOBRACES)) + if (!(flags & CGEN_BLOCK_NOBRACES)) cgen_write(g, "}"); return true; } @@ -1118,7 +1254,7 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) { return false; } if (!cgen_block_enter(g, &f->body)) return false; - if (!cgen_block(g, &f->body, NULL, CGEN_BLOCK_FLAG_NOENTER | CGEN_BLOCK_FLAG_NOBRACES)) + if (!cgen_block(g, &f->body, NULL, CGEN_BLOCK_NOENTER | CGEN_BLOCK_NOBRACES)) return false; if (f->ret_decls) { if (cgen_uses_ptr(&f->ret_type)) { diff --git a/decls_cgen.c b/decls_cgen.c index 6a3a635..86ca5f8 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -47,6 +47,19 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) { if (!cgen_decls_block(g, &e->while_.body)) return false; break; + case EXPR_EACH: { + EachExpr *ea = &e->each; + if (ea->flags & EACH_IS_RANGE) { + if (!cgen_decls_expr(g, ea->range.from)) + return false; + if (ea->range.to && !cgen_decls_expr(g, ea->range.to)) + return false; + /* step is a value, not an expression */ + } else { + if (!cgen_decls_expr(g, ea->of)) + return false; + } + } break; case EXPR_TUPLE: arr_foreach(e->tuple, Expression, x) if (!cgen_decls_expr(g, x)) @@ -179,6 +179,8 @@ static bool val_truthiness(Value *v, Type *t) { return false; } + + static I64 val_to_i64(Value *v, BuiltinType v_type) { switch (v_type) { case BUILTIN_I8: return (I64)v->i8; @@ -195,6 +197,8 @@ static I64 val_to_i64(Value *v, BuiltinType v_type) { return 0; } + + static U64 val_to_u64(Value *v, BuiltinType v_type) { if (v_type == BUILTIN_U64) return v->u64; return (U64)val_to_i64(v, v_type); @@ -229,6 +233,106 @@ static void u64_to_val(Value *v, BuiltinType v_type, U64 x) { i64_to_val(v, v_type, (I64)x); } + +static bool val_is_nonnegative(Value *v, Type *t) { + assert(t->kind == TYPE_BUILTIN); + if (!type_builtin_is_signed(t->builtin)) + return true; + return val_to_i64(v, t->builtin) >= 0; +} + +static void fprint_val_ptr(FILE *f, void *p, Type *t) { + switch (t->kind) { + case TYPE_VOID: + fprintf(f, "(void)"); + break; + case TYPE_UNKNOWN: + fprintf(f, "???"); + break; + case TYPE_BUILTIN: + switch (t->builtin) { + case BUILTIN_I8: fprintf(f, "%"PRId8, *(I8 *)p); break; + case BUILTIN_U8: fprintf(f, "%"PRIu8, *(U8 *)p); break; + case BUILTIN_I16: fprintf(f, "%"PRId16, *(I16 *)p); break; + case BUILTIN_U16: fprintf(f, "%"PRIu16, *(U16 *)p); break; + case BUILTIN_I32: fprintf(f, "%"PRId32, *(I32 *)p); break; + case BUILTIN_U32: fprintf(f, "%"PRIu32, *(U32 *)p); break; + case BUILTIN_I64: fprintf(f, "%"PRId64, *(I64 *)p); break; + case BUILTIN_U64: fprintf(f, "%"PRIu64, *(U64 *)p); break; + case BUILTIN_F32: fprintf(f, F32_FMT, *(F32 *)p); break; + case BUILTIN_F64: fprintf(f, F64_FMT, *(F64 *)p); break; + case BUILTIN_CHAR: fprintf(f, "'%c'", *(char *)p); break; + case BUILTIN_BOOL: fprintf(f, "%s", *(bool *)p ? "true" : "false"); break; + } + break; + case TYPE_FN: + fprintf(f, "<function @ %p>", (void *)*(FnExpr **)p); + break; + case TYPE_TUPLE: + fprintf(f, "<tuple>"); + break; + case TYPE_ARR: { + fprintf(f, "["); /* TODO: change? when array initializers are added */ + size_t n = t->arr.n; + if (n > 5) n = 5; + for (size_t i = 0; i < n; i++) { + if (i) fprintf(f, ", "); + fprint_val_ptr(f, *(char **)p + i * compiler_sizeof(t->arr.of), t->arr.of); + } + if (t->arr.n > n) { + fprintf(f, ", ..."); + } + fprintf(f, "]"); + } break; + case TYPE_PTR: + fprintf(f, "<pointer: %p>", *(void **)p); + break; + case TYPE_SLICE: { + fprintf(f, "["); /* TODO: change? when slice initializers are added */ + Slice slice = *(Slice *)p; + I64 n = slice.n; + if (n > 5) n = 5; + for (I64 i = 0; i < n; i++) { + if (i) fprintf(f, ", "); + fprint_val_ptr(f, (char *)slice.data + i * (I64)compiler_sizeof(t->arr.of), t->arr.of); + } + if (slice.n > n) { + fprintf(f, ", ..."); + } + fprintf(f, "]"); + } break; + case TYPE_TYPE: + fprint_type(f, *(Type **)p); + break; + case TYPE_USER: + fprint_val_ptr(f, p, type_user_underlying(t)); + break; + case TYPE_STRUCT: + fprintf(f, "["); /* TODO: change? when struct initializers are added */ + arr_foreach(t->struc.fields, Field, fi) { + if (fi != t->struc.fields) + fprintf(f, ", "); + fprint_ident(f, fi->name); + fprintf(f, ": "); + fprint_val_ptr(f, *(char **)p + fi->offset, fi->type); + } + fprintf(f, "]"); + break; + } +} + +static void fprint_val(FILE *f, Value *v, Type *t) { + if (t->kind == TYPE_TUPLE) { + fprintf(f, "("); + for (size_t i = 0; i < arr_len(t->tuple); i++) { + fprint_val(f, &v->tuple[i], &t->tuple[i]); + } + fprintf(f, ")"); + } else { + fprint_val_ptr(f, v, t); + } +} + /* IMPORTANT: Only pass an evaluator if you want it to use its allocator. Otherwise, pass NULL. @@ -680,7 +784,7 @@ static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) { switch (e->kind) { case EXPR_IDENT: { IdentDecl *id = ident_decl(e->ident); - if (!(id->flags & IDECL_FLAG_HAS_VAL)) { + if (!(id->flags & IDECL_HAS_VAL)) { err_print(e->where, "Cannot take address of run time variable at compile time."); return false; } @@ -735,7 +839,7 @@ static bool eval_set(Evaluator *ev, Expression *set, Value *to) { switch (set->kind) { case EXPR_IDENT: { IdentDecl *id = ident_decl(set->ident); - if (!(id->flags & IDECL_FLAG_HAS_VAL)) { + if (!(id->flags & IDECL_HAS_VAL)) { err_print(set->where, "Cannot set value of run time variable at compile time."); return false; } @@ -1043,6 +1147,14 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { if (!eval_block(ev, &w->body, &e->type, v)) return false; } } break; + case EXPR_EACH: { + EachExpr *ea = &e->each; + /* TODO: ASDF */ + if (ea->flags & EACH_IS_RANGE) { + + } else { + } + } break; case EXPR_BLOCK: if (!eval_block(ev, &e->block, &e->type, v)) return false; break; @@ -1069,7 +1181,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { Declaration *d = idecl->decl; if (!types_decl(ev->typer, d)) return false; assert(d->type.flags & TYPE_FLAG_RESOLVED); - if (idecl->flags & IDECL_FLAG_HAS_VAL) { + if (idecl->flags & IDECL_HAS_VAL) { *v = idecl->val; } else if (d->flags & DECL_FLAG_CONST) { if (!(d->flags & DECL_FLAG_FOUND_VAL)) { @@ -1166,7 +1278,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { Type *type = p->type.kind == TYPE_TUPLE ? &p->type.tuple[idx++] : &p->type; IdentDecl *id = ident_decl(*i); val_copy(NULL, &id->val, &args[arg], type); - id->flags |= IDECL_FLAG_HAS_VAL; + id->flags |= IDECL_HAS_VAL; arg++; } } @@ -1270,7 +1382,7 @@ static bool eval_decl(Evaluator *ev, Declaration *d) { } } index++; - id->flags |= IDECL_FLAG_HAS_VAL; + id->flags |= IDECL_HAS_VAL; } } return true; diff --git a/identifiers.c b/identifiers.c index 030ec76..3cce0d1 100644 --- a/identifiers.c +++ b/identifiers.c @@ -149,6 +149,7 @@ static void ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) id_decl->decl = d; id_decl->scope = b; id_decl->flags = 0; + id_decl->kind = IDECL_DECL; } static IdentDecl *ident_decl(Identifier i) { @@ -225,3 +226,16 @@ static bool ident_eq_str(Identifier i, const char *s) { if (i->parent) return false; /* not at root */ return true; } + +static Location idecl_where(IdentDecl *id) { + + switch (id->kind) { + case IDECL_DECL: + return id->decl->where; + case IDECL_EXPR: + return id->expr->where; + } + assert(0); + Location def = {0}; + return def; +} @@ -1,7 +1,10 @@ /* TODO: -make sure futurely/currently-declared types are *only* used by pointer -for +each +compile-time each +each pointer +compile-time each pointer +prevent each x := x +=, -=, *=, /= compile-time arguments don't allow while {3; 5} (once break is added) @@ -9,6 +12,7 @@ any odd number of "s for a string modifiable strings: s := ["sakjdfhkjh ksjdahfkjsd ahs ahdf hsdaf khsadkjfh"]; unicode variable names (cgen support) +make sure futurely/currently-declared types are only used by pointer/slice allow omission of trailing ; in foo @= fn() {}? */ #include "toc.c" @@ -12,6 +12,7 @@ static const char *expr_kind_to_str(ExprKind k) { case EXPR_LITERAL_CHAR: return "character literal"; case EXPR_IF: return "if expression"; case EXPR_WHILE: return "while expression"; + case EXPR_EACH: return "each expression"; case EXPR_CALL: return "function call"; case EXPR_C: return "c code"; case EXPR_DSIZEOF: return "#sizeof"; @@ -255,11 +256,14 @@ static inline Expression *parser_new_expr(Parser *p) { return parser_malloc(p, sizeof(Expression)); } -#define EXPR_CAN_END_WITH_COMMA 0x01 /* a comma could end the expression */ -#define EXPR_CAN_END_WITH_LBRACE 0x02 -#define EXPR_CAN_END_WITH_COLON 0x04 +typedef enum { + EXPR_CAN_END_WITH_COMMA = 0x01, /* a comma could end the expression */ + EXPR_CAN_END_WITH_LBRACE = 0x02, + EXPR_CAN_END_WITH_COLON = 0x04, + EXPR_CAN_END_WITH_DOTDOT = 0x08 +} ExprEndFlags; /* is_vbs can be NULL */ -static Token *expr_find_end(Parser *p, U16 flags, bool *is_vbs) { +static Token *expr_find_end(Parser *p, ExprEndFlags flags, bool *is_vbs) { Tokenizer *t = p->tokr; int paren_level = 0; int brace_level = 0; @@ -313,6 +317,10 @@ static Token *expr_find_end(Parser *p, U16 flags, bool *is_vbs) { return token; could_be_vbs = true; break; + case KW_DOTDOT: + if (brace_level == 0 && square_level == 0 && paren_level == 0 && (flags & EXPR_CAN_END_WITH_DOTDOT)) + return token; + break; case KW_COLON: if ((flags & EXPR_CAN_END_WITH_COLON) && brace_level == 0 && square_level == 0 && paren_level == 0) @@ -1050,6 +1058,94 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { if (!parse_block(p, &w->body)) return false; return true; } + case KW_EACH: { + e->kind = EXPR_EACH; + EachExpr *ea = &e->each; + ea->flags = 0; + ea->value = NULL; + ea->index = NULL; + t->token++; + if (t->token->kind == TOKEN_IDENT) { + ea->value = t->token->ident; + if (ident_eq_str(ea->value, "_")) /* ignore value */ + ea->value = NULL; + t->token++; + if (token_is_kw(t->token, KW_COMMA)) { + t->token++; + if (t->token->kind == TOKEN_IDENT) { + ea->index = t->token->ident; + if (ident_eq_str(ea->index, "_")) /* ignore index */ + ea->index = NULL; + } else { + tokr_err(t, "Expected identifier after , in each statement."); + return false; + } + } + } + if (token_is_kw(t->token, KW_AT)) { + tokr_err(t, "The variable(s) in a for loop cannot be constant."); + return false; + } + if (!token_is_kw(t->token, KW_COLON)) { + tokr_err(t, "Expected : following identifiers in for statement."); + return false; + } + t->token++; + if (!token_is_kw(t->token, KW_EQ)) { + ea->flags |= EACH_ANNOTATED_TYPE; + if (!parse_type(p, &ea->type)) + return false; + if (!token_is_kw(t->token, KW_EQ)) { + tokr_err(t, "Expected = in for statement."); + return false; + } + } + t->token++; + Token *first_end = expr_find_end(p, EXPR_CAN_END_WITH_COMMA|EXPR_CAN_END_WITH_DOTDOT|EXPR_CAN_END_WITH_LBRACE, NULL); + Expression *first = parser_new_expr(p); + if (!parse_expr(p, first, first_end)) + return false; + if (token_is_kw(first_end, KW_LBRACE)) { + ea->of = first; + } else if (token_is_kw(first_end, KW_DOTDOT) || token_is_kw(first_end, KW_COMMA)) { + ea->flags |= EACH_IS_RANGE; + ea->range.from = first; + if (token_is_kw(first_end, KW_COMMA)) { + /* step */ + t->token++; + ea->range.step = parser_new_expr(p); + Token *step_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE|EXPR_CAN_END_WITH_DOTDOT, NULL); + if (!parse_expr(p, ea->range.step, step_end)) + return false; + if (!token_is_kw(step_end, KW_DOTDOT)) { + err_print(step_end->where, "Expected .. to follow step in for statement."); + return false; + } + } else { + ea->range.step = NULL; + } + t->token++; /* move past .. */ + if (token_is_kw(t->token, KW_LBRACE)) { + ea->range.to = NULL; /* infinite loop! */ + } else { + ea->range.to = parser_new_expr(p); + Token *to_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE, NULL); + if (!parse_expr(p, ea->range.to, to_end)) + return false; + if (!token_is_kw(t->token, KW_LBRACE)) { + tokr_err(t, "Expected { to open body of for statement."); + return false; + } + } + } else { + err_print(first_end->where, "Expected { or .. to follow expression in for statement."); + return false; + } + + if (!parse_block(p, &ea->body)) + return false; + return true; + } default: break; } @@ -1831,6 +1927,8 @@ static void fprint_arg_exprs(FILE *out, Expression *args) { fprintf(out, ")"); } +static void fprint_val(FILE *f, Value *v, Type *t); + static void fprint_expr(FILE *out, Expression *e) { PARSE_PRINT_LOCATION(e->where); switch (e->kind) { @@ -1902,6 +2000,43 @@ static void fprint_expr(FILE *out, Expression *e) { if (e->while_.cond) fprint_expr(out, e->while_.cond); fprint_block(out, &e->while_.body); break; + case EXPR_EACH: { + EachExpr *ea = &e->each; + fprintf(out, "each "); + if (ea->index) { + fprint_ident(out, ea->index); + } else fprintf(out, "_"); + fprintf(out, ", "); + if (ea->value) { + fprint_ident(out, ea->value); + } else fprintf(out, "_"); + fprintf(out, " :"); + if (ea->flags & EACH_ANNOTATED_TYPE) + fprint_type(out, &ea->type); + fprintf(out, "= "); + if (ea->flags & EACH_IS_RANGE) { + fprint_expr(out, ea->range.from); + if (parse_printing_after_types) { + if (ea->range.stepval) { + fprintf(out, ","); + fprint_val(out, ea->range.stepval, &ea->type); + } + } else { + if (ea->range.step) { + fprintf(out, ","); + fprint_expr(out, ea->range.step); + } + } + fprintf(out, ".."); + if (ea->range.to) { + fprint_expr(out, ea->range.to); + } + fprintf(out, " "); + } else { + fprint_expr(out, ea->of); + } + fprint_block(out, &ea->body); + } break; case EXPR_CALL: fprint_expr(out, e->call.fn); if (parse_printing_after_types) { @@ -6,10 +6,10 @@ static void val_free(Value *v, Type *t); static bool add_ident_decls(Block *b, Declaration *d, U32 flags) { bool ret = true; arr_foreach(d->idents, Identifier, ident) { - IdentDecl **decls = &(*ident)->decls; - if ((flags & SCOPE_FLAG_CHECK_REDECL) && arr_len(*decls)) { + IdentDecl *decls = (*ident)->decls; + if ((flags & SCOPE_FLAG_CHECK_REDECL) && arr_len(decls)) { /* check that it hasn't been declared in this block */ - IdentDecl *prev = arr_last(*decls); + IdentDecl *prev = arr_last(decls); if (prev->scope == b) { err_print(d->where, "Re-declaration of identifier in the same block."); info_print(prev->decl->where, "Previous declaration was here."); @@ -30,7 +30,7 @@ static void remove_ident_decls(Block *b, Declaration *d) { IdentDecl **decls = &id_info->decls; IdentDecl *last_decl = arr_last(*decls); if (last_decl && last_decl->scope == b) { - if ((last_decl->flags & IDECL_FLAG_HAS_VAL) + if ((last_decl->flags & IDECL_HAS_VAL) /* don't free const vals (there's only one per decl) */ && !(last_decl->decl->flags & DECL_FLAG_CONST)) { val_free(&last_decl->val, is_tuple ? &d->type.tuple[i++] : &d->type); @@ -63,11 +63,14 @@ static void block_exit(Block *b, Statement *stmts) { } /* does NOT enter function's block body */ -static void fn_enter(FnExpr *f, U32 flags) { +static bool fn_enter(FnExpr *f, U32 flags) { arr_foreach(f->params, Declaration, decl) - add_ident_decls(&f->body, decl, flags); + if (!add_ident_decls(&f->body, decl, flags)) + return false; arr_foreach(f->ret_decls, Declaration, decl) - add_ident_decls(&f->body, decl, flags); + if (!add_ident_decls(&f->body, decl, flags)) + return false; + return true; } static void fn_exit(FnExpr *f) { @@ -76,3 +79,31 @@ static void fn_exit(FnExpr *f) { arr_foreach(f->ret_decls, Declaration, decl) remove_ident_decls(&f->body, decl); } + +static bool each_enter(Expression *e, U32 flags) { + assert(e->kind == EXPR_EACH); + EachExpr *ea = &e->each; + if (ea->index && ea->index == ea->value) { + err_print(e->where, "The identifier for the index of an each loop must be different from the identifier for the value."); + return false; + } + if (ea->index) { + IdentDecl *id = arr_add(&ea->index->decls); + id->flags = 0; + id->kind = IDECL_EXPR; + id->scope = &ea->body; + id->expr = e; + } + if (ea->value) { + IdentDecl *id = arr_add(&ea->value->decls); + id->flags = 0; + id->kind = IDECL_EXPR; + id->scope = &ea->body; + id->expr = e; + } + return true; +} + +static void each_exit(Expression *e) { + assert(e->kind == EXPR_EACH); +} @@ -1,55 +1,16 @@ + puti @= fn(x: int) { #C("printf(\"%ld\\n\", (long)x); "); }; -total @= fn() int { - t := 0; - x := new(int,10); - i := 0; - while i < x.len { - x[i] = i; - i = i + 1; - } - - x.len = 5; - i = 0; - while i < x.len { - t = t + x[i]; - i = i + 1; - } - t -}; - -Foo @= struct { - x: &Bar; -}; - -Bar @= struct { - y : &Foo; -}; main @= fn() { - f: Foo; - b: Bar; - f.x = &b; - b.y = &f; - - Baz @= struct { a : &Quux; }; - Quux @= struct { b: &Baz; }; - B : Baz; - q : Quux; - B.a = &q; - q.b = &B; - - Wow @= struct { w: &Wow; }; - w: Wow; - w.w = &w; - - puti(total()); - X @= total(); - puti(X); - puti(#sizeof(int)); - puti(#alignof(int)); + each i := 1..10 { + puti(i); + } + each i := 10,-1..1 { + puti(i); + } }; diff --git a/tokenizer.c b/tokenizer.c index a5eb3ce..828b3d4 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -1,8 +1,8 @@ static const char *keywords[KW_COUNT] = {";", ":", "@", ",", "(", ")", "{", "}", "[", "]", "==", "!=", "<=", "<", ">=", ">", - "+", "-", "*", "!", "&", "/", ".", + "+", "-", "*", "!", "&", "/", "..", ".", "=", - "if", "elif", "else", "while", "return", "fn", "as", + "if", "elif", "else", "while", "each", "return", "fn", "as", "new", "del", "struct", "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "f32", "f64", @@ -273,7 +273,6 @@ static bool tokenize_string(Tokenizer *t, char *str) { } /* check if it's a number */ - if (isdigit(*t->s)) { /* it's a numeric literal */ int base = 10; @@ -308,6 +307,10 @@ static bool tokenize_string(Tokenizer *t, char *str) { while (1) { if (*t->s == '.') { + if (t->s[1] == '.') { + /* .. (not a decimal point; end the number here) */ + break; + } if (n.kind == NUM_LITERAL_FLOAT) { tokenization_err(t, "Double . in number."); goto err; @@ -389,6 +392,7 @@ static bool tokenize_string(Tokenizer *t, char *str) { } tokr_nextchar(t); } + token->kind = TOKEN_LITERAL_NUM; token->num = n; continue; diff --git a/typedefs_cgen.c b/typedefs_cgen.c index 2051acb..937be4a 100644 --- a/typedefs_cgen.c +++ b/typedefs_cgen.c @@ -56,6 +56,19 @@ static bool typedefs_expr(CGenerator *g, Expression *e) { if (!typedefs_block(g, &e->while_.body)) return false; break; + case EXPR_EACH: { + EachExpr *ea = &e->each; + if (ea->flags & EACH_IS_RANGE) { + if (!typedefs_expr(g, ea->range.from)) + return false; + if (ea->range.to && !typedefs_expr(g, ea->range.to)) + return false; + /* step is a value, not an expression */ + } else { + if (!typedefs_expr(g, ea->of)) + return false; + } + } break; case EXPR_TUPLE: arr_foreach(e->tuple, Expression, x) if (!typedefs_expr(g, x)) @@ -102,12 +102,15 @@ static bool expr_arr_must_mut(Expression *e) { switch (e->kind) { case EXPR_IDENT: { IdentDecl *idecl = ident_decl(e->ident); - Declaration *d = idecl->decl; - if (d->flags & DECL_FLAG_CONST) { - err_print(e->where, "Cannot modify a constant array."); - return false; + if (idecl->kind == IDECL_DECL) { + Declaration *d = idecl->decl; + if (d->flags & DECL_FLAG_CONST) { + err_print(e->where, "Cannot modify a constant array."); + return false; + } } - } return true; + return true; + } case EXPR_CAST: case EXPR_CALL: case EXPR_NEW: @@ -119,6 +122,8 @@ static bool expr_arr_must_mut(Expression *e) { case EXPR_WHILE: assert(e->while_.body.ret_expr); return expr_arr_must_mut(e->while_.body.ret_expr); + case EXPR_EACH: + return expr_arr_must_mut(e->each.body.ret_expr); case EXPR_IF: for (IfExpr *i = &e->if_; i; i->next_elif ? i = &i->next_elif->if_ : (i = NULL)) { assert(i->body.ret_expr); @@ -155,12 +160,15 @@ static bool expr_must_lval(Expression *e) { case EXPR_IDENT: { IdentDecl *id_decl = ident_decl(e->ident); assert(id_decl); - Declaration *d = id_decl->decl; - if (d->flags & DECL_FLAG_CONST) { - char *istr = ident_to_str(e->ident); - err_print(e->where, "Use of constant %s as a non-constant expression.", istr); - info_print(d->where, "%s was declared here.", istr); - return false; + if (id_decl->kind == IDECL_DECL) { + Declaration *d = id_decl->decl; + if (d->flags & DECL_FLAG_CONST) { + char *istr = ident_to_str(e->ident); + err_print(e->where, "Use of constant %s as a non-constant expression.", istr); + info_print(d->where, "%s was declared here.", istr); + return false; + } + } return true; } @@ -203,6 +211,7 @@ static bool expr_must_lval(Expression *e) { case EXPR_LITERAL_BOOL: case EXPR_IF: case EXPR_WHILE: + case EXPR_EACH: case EXPR_CALL: case EXPR_C: case EXPR_DALIGNOF: @@ -243,6 +252,7 @@ static bool type_of_fn(Typer *tr, Expression *e, Type *t) { } static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { + t->flags = 0; IdentDecl *decl = ident_decl(i); if (!decl) { char *s = ident_to_str(i); @@ -250,73 +260,93 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { free(s); return false; } - Declaration *d = decl->decl; - bool captured = false; - if (decl->scope != NULL) - for (Block *block = tr->block; block != decl->scope; block = block->parent) { - if (block->flags & BLOCK_FLAG_FN) { - captured = true; - break; + switch (decl->kind) { + case IDECL_DECL: { + Declaration *d = decl->decl; + bool captured = false; + if (decl->scope != NULL) + for (Block *block = tr->block; block != decl->scope; block = block->parent) { + if (block->flags & BLOCK_FLAG_FN) { + captured = true; + break; + } } + if (captured && !(d->flags & DECL_FLAG_CONST)) { + err_print(where, "Variables cannot be captured into inner functions (but constants can)."); + return false; } - if (captured && !(d->flags & DECL_FLAG_CONST)) { - err_print(where, "Variables cannot be captured into inner functions (but constants can)."); - return false; - } - /* are we inside this declaration? */ - typedef Declaration *DeclarationPtr; - arr_foreach(tr->in_decls, DeclarationPtr, in_decl) { - if (d == *in_decl) { - assert(d->flags & DECL_FLAG_HAS_EXPR); /* we can only be in decls with an expr */ - if (d->expr.kind != EXPR_FN) { /* it's okay if a function references itself */ - /* if we've complained about it before when we were figuring out the type, don't complain again */ - if (!(d->flags & DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE)) { - char *s = ident_to_str(i); - err_print(where, "Use of identifier %s within its own declaration.", s); - free(s); - info_print(d->where, "Declaration was here."); - d->flags |= DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE; + /* are we inside this declaration? */ + typedef Declaration *DeclarationPtr; + arr_foreach(tr->in_decls, DeclarationPtr, in_decl) { + if (d == *in_decl) { + assert(d->flags & DECL_FLAG_HAS_EXPR); /* we can only be in decls with an expr */ + if (d->expr.kind != EXPR_FN) { /* it's okay if a function references itself */ + /* if we've complained about it before when we were figuring out the type, don't complain again */ + if (!(d->flags & DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE)) { + char *s = ident_to_str(i); + err_print(where, "Use of identifier %s within its own declaration.", s); + free(s); + info_print(d->where, "Declaration was here."); + d->flags |= DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE; + } + return false; } - return false; } } - } - if (d->flags & DECL_FLAG_FOUND_TYPE) { - if (d->type.kind == TYPE_TUPLE) { - /* get correct item in tuple */ - long index = 0; - arr_foreach(d->idents, Identifier, decl_i) { - if (*decl_i == i) { - break; + if (d->flags & DECL_FLAG_FOUND_TYPE) { + if (d->type.kind == TYPE_TUPLE) { + /* get correct item in tuple */ + long index = 0; + arr_foreach(d->idents, Identifier, decl_i) { + if (*decl_i == i) { + break; + } + index++; + assert(index < (long)arr_len(d->idents)); /* identifier got its declaration set to here, but it's not here */ } - index++; - assert(index < (long)arr_len(d->idents)); /* identifier got its declaration set to here, but it's not here */ + *t = d->type.tuple[index]; + } else { + *t = d->type; } - *t = d->type.tuple[index]; - } else { - *t = d->type; - } - return true; - } else { - if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->expr.kind == EXPR_FN)) { - /* allow using a function before declaring it */ - if (!type_of_fn(tr, &d->expr, t)) return false; return true; } else { - if (location_after(d->where, where)) { - char *s = ident_to_str(i); - err_print(where, "Use of identifier %s before its declaration.\nNote that it is only possible to use a constant function before it is directly declared (e.g. x @= fn() {}).", s); - info_print(d->where, "%s will be declared here.", s); - free(s); + if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->expr.kind == EXPR_FN)) { + /* allow using a function before declaring it */ + if (!type_of_fn(tr, &d->expr, t)) return false; + return true; } else { - /* let's type the declaration, and redo this (for evaling future functions) */ - if (!types_decl(tr, d)) return false; - return type_of_ident(tr, where, i, t); + if (location_after(d->where, where)) { + char *s = ident_to_str(i); + err_print(where, "Use of identifier %s before its declaration.\nNote that it is only possible to use a constant function before it is directly declared (e.g. x @= fn() {}).", s); + info_print(d->where, "%s will be declared here.", s); + free(s); + } else { + /* let's type the declaration, and redo this (for evaling future functions) */ + if (!types_decl(tr, d)) return false; + return type_of_ident(tr, where, i, t); + } + return false; } - return false; } + } break; + case IDECL_EXPR: { + Expression *e = decl->expr; + switch (e->kind) { + case EXPR_EACH: + if (i == e->each.index) { + t->kind = TYPE_BUILTIN; + t->builtin = BUILTIN_I64; + } else { + assert(i == e->each.value); + *t = e->each.type; + } + break; + default: assert(0); return false; + } + } break; } + return true; } /* fixes the type (replaces [5+3]int with [8]int, etc.) */ @@ -389,6 +419,7 @@ static bool type_resolve(Typer *tr, Type *t, Location where) { free(s); return false; } + assert(idecl->kind == IDECL_DECL); Declaration *decl = idecl->decl; /* now, type the declaration (in case we are using it before its declaration) */ if (!types_decl(tr, decl)) @@ -558,7 +589,8 @@ static bool types_expr(Typer *tr, Expression *e) { tr->ret_type = t->fn.types[0]; } tr->can_ret = true; - fn_enter(f, SCOPE_FLAG_CHECK_REDECL); + if (!fn_enter(f, SCOPE_FLAG_CHECK_REDECL)) + return false; bool block_success = true; block_success = types_block(tr, &e->fn.body); fn_exit(f); @@ -634,6 +666,116 @@ static bool types_expr(Typer *tr, Expression *e) { t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_CHAR; break; + case EXPR_EACH: { + EachExpr *ea = &e->each; + if (ea->flags & EACH_IS_RANGE) { + /* TODO: allow user-defined numerical types */ + if (!types_expr(tr, ea->range.from)) return false; + { + Type *ft = &ea->range.from->type; + if (ft->kind != TYPE_BUILTIN || !type_builtin_is_numerical(ft->builtin)) { + char *s = type_to_str(ft); + err_print(e->where, "from expression of each must be a builtin numerical type, not %s", s); + free(s); + } + } + if (ea->range.step) { + if (!types_expr(tr, ea->range.step)) return false; + Type *st = &ea->range.step->type; + if (st->kind != TYPE_BUILTIN || !type_builtin_is_numerical(st->builtin)) { + char *s = type_to_str(st); + err_print(e->where, "step expression of each must be a builtin numerical type, not %s", s); + free(s); + } + } + if (ea->range.to) { + if (!types_expr(tr, ea->range.to)) return false; + Type *tt = &ea->range.to->type; + if (tt->kind != TYPE_BUILTIN || !type_builtin_is_numerical(tt->builtin)) { + char *s = type_to_str(tt); + err_print(e->where, "to expression of each must be a builtin numerical type, not %s", s); + free(s); + } + } + + if (!(ea->flags & EACH_ANNOTATED_TYPE)) { + ea->type = ea->range.from->type; + } + + if (!type_eq(&ea->type, &ea->range.from->type)) { + char *exp = type_to_str(&ea->type); + char *got = type_to_str(&ea->range.from->type); + err_print(e->where, "Type of each does not match the type of the from expression. Expected %s, but got %s.", exp, got); + free(exp); free(got); + return false; + } + + if (ea->range.step && !type_eq(&ea->type, &ea->range.step->type)) { + char *exp = type_to_str(&ea->type); + char *got = type_to_str(&ea->range.step->type); + err_print(e->where, "Type of each does not match the type of the step expression. Expected %s, but got %s.", exp, got); + free(exp); free(got); + return false; + } + + if ((ea->type.flags & TYPE_FLAG_FLEXIBLE) && ea->range.step) + ea->type = ea->range.step->type; + + if (ea->range.to && !type_eq(&ea->type, &ea->range.to->type)) { + char *exp = type_to_str(&ea->type); + char *got = type_to_str(&ea->range.to->type); + err_print(e->where, "Type of each does not match the type of the to expression. Expected %s, but got %s.", exp, got); + free(exp); free(got); + return false; + } + + if ((ea->type.flags & TYPE_FLAG_FLEXIBLE) && ea->range.to) + ea->type = ea->range.to->type; + + } else { + if (!types_expr(tr, ea->of)) + return false; + Type *of_type = NULL; + switch (ea->of->type.kind) { + case TYPE_SLICE: + of_type = ea->of->type.slice; + break; + case TYPE_ARR: + of_type = ea->of->type.arr.of; + break; + default: { + char *s = type_to_str(&ea->of->type); + err_print(e->where, "Cannot iterate over non-array non-slice type %s.", s); + free(s); + return false; + } + } + if (ea->flags & EACH_ANNOTATED_TYPE) { + if (!type_eq(of_type, &ea->type)) { + char *exp = type_to_str(of_type); + char *got = type_to_str(&ea->type); + err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s."); + free(exp); free(got); + return false; + } + } else ea->type = *of_type; + } + if ((ea->flags & EACH_IS_RANGE) && ea->range.step) { + Value *stepval = typer_malloc(tr, sizeof *ea->range.stepval); + if (!eval_expr(tr->evalr, ea->range.step, stepval)) { + info_print(ea->range.step->where, "Note that the step of an each loop must be a compile-time constant."); + return false; + } + ea->range.stepval = stepval; + } + if (!each_enter(e, SCOPE_FLAG_CHECK_REDECL)) return false; + if (!types_block(tr, &ea->body)) return false; + each_exit(e); + if (ea->body.ret_expr) + *t = ea->body.ret_expr->type; + else + t->kind = TYPE_VOID; + } break; case EXPR_IDENT: { if (!type_of_ident(tr, e->where, e->ident, t)) return false; } break; @@ -785,10 +927,12 @@ static bool types_expr(Typer *tr, Expression *e) { if (f->kind == EXPR_IDENT) { IdentDecl *decl = ident_decl(f->ident); assert(decl); - if (decl->decl->flags & DECL_FLAG_HAS_EXPR) { - Expression *expr = &decl->decl->expr; - if (expr->kind == EXPR_FN) - fn_decl = &decl->decl->expr.fn; + if (decl->kind == IDECL_DECL) { + if (decl->decl->flags & DECL_FLAG_HAS_EXPR) { + Expression *expr = &decl->decl->expr; + if (expr->kind == EXPR_FN) + fn_decl = &decl->decl->expr.fn; + } } } if (!fn_decl && nargs != nparams) { @@ -819,7 +963,7 @@ static bool types_expr(Typer *tr, Expression *e) { char *s = ident_to_str(args[p].name); err_print(args[p].where, "Argument '%s' does not appear in declaration of function.", s); free(s); - info_print(ident_decl(f->ident)->decl->where, "Declaration is here."); + info_print(idecl_where(ident_decl(f->ident)), "Declaration is here."); return false; } new_args[arg_index] = args[p].val; @@ -94,12 +94,22 @@ typedef union Value { struct Type *type; } Value; -#define IDECL_FLAG_HAS_VAL 0x01 +#define IDECL_HAS_VAL 0x01 + +typedef enum { + IDECL_DECL, + IDECL_EXPR +} IdentDeclKind; + typedef struct { - struct Declaration *decl; + union { + struct Declaration *decl; + struct Expression *expr; /* for example, this identifier is declared in an each expression */ + }; struct Block *scope; /* NULL for file scope */ Value val; - uint16_t flags; + IdentDeclKind kind; + U16 flags; } IdentDecl; /* @@ -166,6 +176,7 @@ typedef enum { KW_EXCLAMATION, KW_AMPERSAND, KW_SLASH, + KW_DOTDOT, KW_DOT, KW_EQ, KW_LAST_SYMBOL = KW_EQ, /* last one entirely consisting of symbols */ @@ -173,6 +184,7 @@ typedef enum { KW_ELIF, KW_ELSE, KW_WHILE, + KW_EACH, KW_RETURN, KW_FN, KW_AS, @@ -340,6 +352,7 @@ typedef enum { EXPR_UNARY_OP, EXPR_IF, EXPR_WHILE, + EXPR_EACH, EXPR_FN, EXPR_CAST, EXPR_NEW, @@ -406,6 +419,33 @@ typedef struct { Block body; } WhileExpr; + +#define EACH_IS_RANGE 0x01 +#define EACH_ANNOTATED_TYPE 0x02 + +typedef struct EachExpr { + U16 flags; + struct { + IdentID id; + IdentID index_id; /* only set if index is NULL */ + } c; + Type type; + Identifier index; /* NULL = no index */ + Identifier value; /* NULL = no value */ + Block body; + union { + struct { + struct Expression *from; + struct Expression *to; + union { + struct Expression *step; + Value *stepval; + }; + } range; + struct Expression *of; + }; +} EachExpr; + typedef struct FnExpr { struct Declaration *params; /* declarations of the parameters to this function */ struct Declaration *ret_decls; /* array of decls, if this has named return values. otherwise, NULL */ @@ -478,6 +518,7 @@ typedef struct Expression { } del; IfExpr if_; WhileExpr while_; + EachExpr each; FnExpr fn; CastExpr cast; SliceExpr slice; @@ -587,4 +628,5 @@ typedef struct { Expression **anon_fns; /* array of pointers to expressions of anonymous functions */ Evaluator *evalr; Identifier main_ident; + Identifiers *idents; } CGenerator; |