diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-10-20 11:39:21 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-10-20 11:39:21 -0400 |
commit | 89f00af3cf25d594f10aebaa7048a17bdd520c4b (patch) | |
tree | bbb22f3ffe808bca6849fd66693b094221a047fb | |
parent | bfd0a7f6fbf22914631337b3871011f452d3fb94 (diff) |
improved new; new slices
-rw-r--r-- | cgen.c | 141 | ||||
-rw-r--r-- | eval.c | 3 | ||||
-rw-r--r-- | main.c | 6 | ||||
-rw-r--r-- | out.c | 35 | ||||
-rw-r--r-- | parse.c | 25 | ||||
-rwxr-xr-x | runv | 2 | ||||
-rw-r--r-- | test.toc | 20 | ||||
-rw-r--r-- | types.c | 78 | ||||
-rw-r--r-- | types.h | 12 |
9 files changed, 191 insertions, 131 deletions
@@ -1,5 +1,5 @@ static bool cgen_stmt(CGenerator *g, Statement *s); -static bool cgen_block(CGenerator *g, Block *b, const char *ret_name); +static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, bool enter_and_exit); static bool cgen_expr_pre(CGenerator *g, Expression *e); static bool cgen_expr(CGenerator *g, Expression *e); static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, const char *prefix, Expression *to); @@ -194,7 +194,7 @@ static bool cgen_type_post(CGenerator *g, Type *t, Location where) { cgen_write(g, "["); if (!cgen_expr(g, t->arr.n_expr)) return false; - cgen_write(g, "]"); + cgen_write(g, "])"); } if (!cgen_type_post(g, t->arr.of, where)) return false; @@ -501,6 +501,57 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, return true; } +/* generates the C code for new'ing a slice of array type t (e.g. [5]int) and putting it in the given ident id. */ +static bool cgen_new_slice(CGenerator *g, Type *t, IdentID id, Location where) { + Expression *n_expr = t->arr.n_expr; + assert(!(t->flags & TYPE_FLAG_RESOLVED)); /* we don't want this to be resolved, because the size might only be known at runtime. */ + if (!cgen_expr_pre(g, n_expr)) return false; + cgen_write(g, "size_t s"); + cgen_ident_id(g, id); + cgen_write(g, " = "); + if (!cgen_expr(g, n_expr)) return false; + cgen_write(g, "; slice_ "); + cgen_ident_id(g, id); + cgen_write(g, ";"); + cgen_ident_id(g, id); + cgen_write(g, ".data = calloc(s"); + cgen_ident_id(g, id); + cgen_write(g, ", sizeof("); + if (t->arr.of->kind == TYPE_ARR) { + cgen_write(g, "slice_"); + } else { + if (!cgen_type_pre(g, t->arr.of, where)) + return false; + if (!cgen_type_post(g, t->arr.of, where)) + return false; + } + cgen_write(g, ")); "); + cgen_ident_id(g, id); + cgen_write(g, ".n = s"); + cgen_ident_id(g, id); + cgen_write(g, ";"); + if (t->arr.of->kind == TYPE_ARR) { + /* slice of slices. initialize the inner slices. */ + IdentID child_id = g->ident_counter++; + cgen_write(g, "for (u64 i_ = 0; i_ < s"); + cgen_ident_id(g, id); + cgen_write(g, "; i_++) {"); + cgen_nl(g); + g->indent_lvl++; + if (!cgen_new_slice(g, t->arr.of, child_id, where)) + return false; + cgen_write(g, " ((slice_*)"); + cgen_ident_id(g, id); + cgen_write(g, ".data)[i_] = "); + cgen_ident_id(g, child_id); + cgen_write(g, ";"); + cgen_nl(g); + g->indent_lvl--; + cgen_write(g, "}"); + } + return true; +} + static bool cgen_expr_pre(CGenerator *g, Expression *e) { IdentID id; char ret_name[64]; @@ -547,7 +598,7 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { return false; cgen_write(g, ") "); } - if (!cgen_block(g, &curr->body, ret_name)) + if (!cgen_block(g, &curr->body, ret_name, false)) return false; if (curr->next_elif) { cgen_write(g, " else "); @@ -566,12 +617,12 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { cgen_write(g, "true"); } cgen_write(g, ") "); - if (!cgen_block(g, &w->body, ret_name)) + if (!cgen_block(g, &w->body, ret_name, false)) return false; } break; case EXPR_BLOCK: e->block_ret_id = id; - if (!cgen_block(g, &e->block, ret_name)) + if (!cgen_block(g, &e->block, ret_name, false)) return false; break; case EXPR_CALL: @@ -590,7 +641,25 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { if (!cgen_expr_pre(g, e->cast.expr)) return false; break; case EXPR_NEW: - /* TODO */ + if (e->new.n) { + if (!cgen_expr_pre(g, e->new.n)) + return false; + IdentID n_id = e->new.c.id = g->ident_counter++; + cgen_write(g, "slice_ "); + cgen_ident_id(g, n_id); + cgen_write(g, "; "); + cgen_ident_id(g, n_id); + cgen_write(g, ".data = calloc("); + if (!cgen_expr(g, e->new.n)) return false; + cgen_write(g, ", sizeof("); + if (!cgen_type_pre(g, &e->new.type, e->where)) return false; + if (!cgen_type_post(g, &e->new.type, e->where)) return false; + cgen_write(g, ")); "); + cgen_ident_id(g, n_id); + cgen_write(g, ".n = "); + if (!cgen_expr(g, e->new.n)) return false; + cgen_write(g, ";"); + } break; case EXPR_LITERAL_INT: case EXPR_LITERAL_FLOAT: @@ -696,19 +765,24 @@ static bool cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, ")"); cgen_write(g, ")"); } break; - case EXPR_NEW: - cgen_write(g, "(("); - if (!cgen_type_pre(g, &e->type, e->where)) - return false; - if (!cgen_type_post(g, &e->type, e->where)) - return false; - cgen_write(g, ")calloc(1, sizeof("); - if (!cgen_type_pre(g, &e->new.type, e->where)) - return false; - if (!cgen_type_post(g, &e->new.type, e->where)) - return false; - cgen_write(g, ")))"); - break; + case EXPR_NEW: { + if (e->new.n) { + cgen_ident_id(g, e->new.c.id); + } else { + Type *t = &e->new.type; + cgen_write(g, "(("); + if (!cgen_type_pre(g, &e->type, e->where)) + return false; + if (!cgen_type_post(g, &e->type, e->where)) + return false; + cgen_write(g, ")calloc(1, sizeof("); + if (!cgen_type_pre(g, t, e->where)) + return false; + if (!cgen_type_post(g, t, e->where)) + return false; + cgen_write(g, ")))"); + } + } break; case EXPR_IF: cgen_ident_id(g, e->if_.c.id); break; @@ -779,11 +853,12 @@ 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) { +static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, bool enter_and_exit) { Block *prev = g->block; cgen_write(g, "{"); - if (!cgen_block_enter(g, b)) - return false; + if (enter_and_exit) + if (!cgen_block_enter(g, b)) + return false; cgen_nl(g); arr_foreach(b->stmts, Statement, s) if (!cgen_stmt(g, s)) @@ -799,7 +874,8 @@ static bool cgen_block(CGenerator *g, Block *b, const char *ret_name) { } cgen_nl(g); } - cgen_block_exit(g, prev); + if (enter_and_exit) + cgen_block_exit(g, prev); cgen_write(g, "}"); return true; } @@ -830,11 +906,12 @@ static void cgen_zero_value(CGenerator *g, Type *t) { } static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) { + FnExpr *prev_fn = g->fn; + Block *prev_block = g->block; fn_enter(f); if (!cgen_fn_header(g, f, where)) return false; cgen_write(g, " "); - FnExpr *prev_fn = g->fn; g->fn = f; cgen_write(g, "{"); cgen_nl(g); @@ -842,8 +919,10 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) { if (!cgen_decl(g, d)) return false; } - if (!cgen_block(g, &f->body, NULL)) + if (!cgen_block_enter(g, &f->body)) return false; + if (!cgen_block(g, &f->body, NULL, false)) return false; + if (f->ret_decls) { if (cgen_uses_ptr(&f->ret_type)) { } else { @@ -854,6 +933,7 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) { } else if (f->body.ret_expr) { if (!cgen_ret(g, f->body.ret_expr)) return false; } + cgen_block_exit(g, prev_block); cgen_write(g, "}"); fn_exit(f); @@ -870,12 +950,7 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { } else if (d->flags & DECL_FLAG_CONST) { /* TODO? */ } else { - /* TODO: Globals just cgen val */ - if (g->block != NULL && (d->flags & DECL_FLAG_HAS_EXPR)) { - if (!cgen_expr_pre(g, &d->expr)) - return false; - } - + /* TODO: Globals just cgen val */ for (size_t idx = 0; idx < arr_len(d->idents); idx++) { Identifier *i = &d->idents[idx]; Type *t = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx] : &d->type; @@ -998,10 +1073,10 @@ static bool cgen_file(CGenerator *g, ParsedFile *f) { cgen_write(g, "/* code */\n"); cgen_write(g, "int main() {\n\tmain__();\n\treturn 0;\n}\n\n"); - arr_foreach(f->stmts, Statement, s) + arr_foreach(f->stmts, Statement, s) { if (!cgen_stmt(g, s)) return false; - + } typedef Expression *ExprPtr; arr_foreach(g->anon_fns, ExprPtr, eptr) { Expression *e = *eptr; @@ -1,6 +1,5 @@ static bool eval_block(Evaluator *ev, Block *b, Value *v); static bool eval_expr(Evaluator *ev, Expression *e, Value *v); -static bool type_resolve(Evaluator *ev, Type *t); static bool block_enter(Block *b, Statement *stmts); static void block_exit(Block *b, Statement *stmts); @@ -787,8 +786,6 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { } } break; case EXPR_NEW: - if (!type_resolve(ev, &e->new.type)) - return false; /* it's not strictly necessary to do the if here */ if (e->new.type.kind == TYPE_ARR) v->arr = err_calloc(1, compiler_sizeof(&e->new.type)); @@ -1,6 +1,10 @@ /* TODO: -new returns a *slice* +fix compile time new +arr => slice casting +del slices +slice at index +bf interpreter unicode variable names make sure initializers for global variables are compile-time constants structs @@ -18,7 +18,6 @@ typedef struct { void *data; u64 n; } slice_; /* declarations */ void puti(i64 x); -void asdf(i64( (*x)[3]), i64 y, i64(*ret0_), i64((*ret1_)[3])); void main__(void); /* code */ int main() { @@ -26,35 +25,17 @@ int main() { return 0; } -#include <stdio.h> -; void puti(i64 x) { -{ - printf("%ld\n", (long)x); -}} - - -void asdf(i64( (*x)[3]), i64 y, i64(*ret0_), i64((*ret1_)[3])) { -{ -}(*ret0_) = y;{ -size_t i;i64(*arr__in) = (*x); i64(*arr__out) = (*ret1_); -for (i = 0; i < 3; i++) arr__out[i] = arr__in[i]; -}return; -} + { + }} void main__(void) { -{ - i64( a[3]) = {0}; - i64 b = 0; - (a[0]) = 17;; - b = 5489;; - i64 c; i64( d[3]); asdf(&a, b, &c, &d); - - (puti(c)); - (puti((d[0]))); - void (* asdfasdf)(i64((*)[3]), i64, i64(*), i64((*)[3])); { - void (* expr__)(i64((*)[3]), i64, i64(*), i64((*)[3])); expr__ = asdf;asdfasdf = expr__;} -}} + { + i64((* Ar)[5]); { + i64((* expr__)[5]); expr__ = ((i64((*)[5]))calloc(1, sizeof(i64([5]))));Ar = expr__;} + slice_ A; { + slice_ expr__; slice_ a0_; a0_.data = calloc(100, sizeof(i64)); a0_.n = 100;expr__ = a0_;A = expr__;} + }} @@ -235,6 +235,7 @@ static inline Expression *parser_new_expr(Parser *p) { #define EXPR_CAN_END_WITH_COMMA 0x01 /* a comma could end the expression */ #define EXPR_CAN_END_WITH_LBRACE 0x02 +/* is_vbs can be NULL */ static Token *expr_find_end(Parser *p, uint16_t flags, bool *is_vbs) { Tokenizer *t = p->tokr; int paren_level = 0; @@ -951,15 +952,37 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { op = UNARY_NOT; break; case KW_NEW: - t->token++; e->kind = EXPR_NEW; + t->token++; + if (!token_is_kw(t->token, KW_LPAREN)) { + err_print(t->token->where, "Expected ( to follow new."); + } + t->token++; if (!parse_type(p, &e->new.type)) return false; + if (token_is_kw(t->token, KW_COMMA)) { + /* new(int, 5) */ + t->token++; + Token *n_end = expr_find_end(p, 0, NULL); + e->new.n = parser_new_expr(p); + if (!parse_expr(p, e->new.n, n_end)) + return false; + } else e->new.n = NULL; + if (!token_is_kw(t->token, KW_RPAREN)) { + err_print(t->token->where, "Expected )."); + return false; + } + t->token++; if (e->new.type.kind == TYPE_TUPLE) { err_print(e->where, "You cannot new a tuple."); return false; } return true; case KW_DEL: + if (!token_is_kw(t->token + 1, KW_LPAREN)) { + /* for the future, when del could be a function */ + err_print(e->where, "Expected ( after del."); + return false; + } op = UNARY_DEL; break; default: @@ -2,4 +2,6 @@ valgrind -q --track-origins=yes ./toc test.toc || exit 1 if [ "$1" = "c" ]; then gcc out.c && ./a.out +elif [ "$1" = "pc" ]; then + cat out.c fi @@ -1,19 +1,11 @@ -#C("#include <stdio.h>\n"); +// #C("#include <stdio.h> +// #define kasfdhkjasdfhjk "); puti @= fn(x: int) { - #C("printf(\"%ld\\n\", (long)x)"); -}; - -asdf @= fn(x: [3]int, y : int) (int, [3]int) { - y, x + // #C("printf(\"%ld\\n\", (long)x)"); }; main @= fn() { - a : [3]int; - b : int; - a[0] = 17; - b = 5489; - c, d := asdf(a, b); - puti(c); puti(d[0]); - asdfasdf := asdf; -};
\ No newline at end of file + Ar := new([5]int); + A:=new(int, 100); +}; @@ -2,7 +2,7 @@ static bool types_stmt(Typer *tr, Statement *s); static bool types_decl(Typer *tr, Declaration *d); static bool types_expr(Typer *tr, Expression *e); static bool types_block(Typer *tr, Block *b); -static bool types_type(Typer *tr, Type *t); +static bool type_resolve(Typer *tr, Type *t); static inline void *typer_malloc(Typer *tr, size_t bytes) { return allocr_malloc(&tr->allocr, bytes); @@ -200,12 +200,12 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Type *t) { t->kind = TYPE_FN; t->fn.types = NULL; Type *ret_type = typer_arr_add(tr, &t->fn.types); - if (!types_type(tr, &f->ret_type) || !type_resolve(tr->evalr, &f->ret_type)) + if (!type_resolve(tr, &f->ret_type)) return false; *ret_type = f->ret_type; arr_foreach(f->params, Declaration, decl) { if (!types_decl(tr, decl)) return false; - if (!types_type(tr, &decl->type) || !type_resolve(tr->evalr, &decl->type)) + if (!type_resolve(tr, &decl->type)) return false; for (size_t i = 0; i < arr_len(decl->idents); i++) { Type *param_type = typer_arr_add(tr, &t->fn.types); @@ -294,13 +294,16 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { } /* fixes the type (replaces [5+3]int with [8]int, etc.) */ -static bool type_resolve(Evaluator *ev, Type *t) { +static bool type_resolve(Typer *tr, Type *t) { + Evaluator *ev = tr->evalr; if (t->flags & TYPE_FLAG_RESOLVED) return true; switch (t->kind) { case TYPE_ARR: { /* it's an array */ Value val; Expression *n_expr = t->arr.n_expr; + if (!types_expr(tr, n_expr)) return false; + if (n_expr->type.kind == TYPE_UNKNOWN) { err_print(n_expr->where, "Cannot determine type of array size at compile time."); return false; @@ -326,27 +329,27 @@ static bool type_resolve(Evaluator *ev, Type *t) { size = val_to_u64(&val, n_expr->type.builtin); } t->arr.n = (UInteger)size; - if (!type_resolve(ev, t->arr.of)) + if (!type_resolve(tr, t->arr.of)) return false; } break; case TYPE_FN: arr_foreach(t->fn.types, Type, child_type) { - if (!type_resolve(ev, child_type)) + if (!type_resolve(tr, child_type)) return false; } break; case TYPE_TUPLE: arr_foreach(t->tuple, Type, child_type) { - if (!type_resolve(ev, child_type)) + if (!type_resolve(tr, child_type)) return false; } break; case TYPE_PTR: - if (!type_resolve(ev, t->ptr)) + if (!type_resolve(tr, t->ptr)) return false; break; case TYPE_SLICE: - if (!type_resolve(ev, t->slice)) + if (!type_resolve(tr, t->slice)) return false; break; case TYPE_UNKNOWN: @@ -358,37 +361,6 @@ static bool type_resolve(Evaluator *ev, Type *t) { return true; } -static bool types_type(Typer *tr, Type *t) { - if (t->flags & TYPE_FLAG_RESOLVED) return true; - switch (t->kind) { - case TYPE_ARR: - if (!types_expr(tr, t->arr.n_expr)) return false; - if (!types_type(tr, t->arr.of)) return false; - break; - case TYPE_PTR: - if (!types_type(tr, t->ptr)) return false; - break; - case TYPE_SLICE: - if (!types_type(tr, t->slice)) return false; - break; - case TYPE_TUPLE: { - arr_foreach(t->tuple, Type, x) - if (!types_type(tr, x)) - return false; - } break; - case TYPE_FN: - arr_foreach(t->fn.types, Type, x) - if (!types_type(tr, x)) - return false; - break; - case TYPE_UNKNOWN: - case TYPE_BUILTIN: - case TYPE_VOID: - break; - } - return true; -} - static bool type_can_be_truthy(Type *t) { switch (t->kind) { case TYPE_VOID: @@ -596,7 +568,7 @@ static bool types_expr(Typer *tr, Expression *e) { CastExpr *c = &e->cast; if (!types_expr(tr, c->expr)) return false; - if (!types_type(tr, &c->type) || !type_resolve(tr->evalr, &c->type)) + if (!type_resolve(tr, &c->type)) return false; Status status = type_cast_status(&c->expr->type, &c->type); if (status != STATUS_NONE) { @@ -614,14 +586,20 @@ static bool types_expr(Typer *tr, Expression *e) { *t = c->type; } break; case EXPR_NEW: - t->kind = TYPE_PTR; - /* type the type, but don't resolve it (e.g. fn(x:int)int{(new [x]int)[0]}) */ - if (!types_type(tr, &e->new.type)) + if (!type_resolve(tr, &e->new.type)) return false; - if (e->new.type.kind == TYPE_ARR) { - *t = e->new.type; + if (e->new.n) { + if (!types_expr(tr, e->new.n)) return false; + if (e->new.n->type.kind != TYPE_BUILTIN || !type_builtin_is_int(e->new.n->type.builtin)) { + char *got = type_to_str(&e->new.n->type); + err_print(e->where, "Expected integer as second argument to new, but got %s.", got); + free(got); + return false; + } + t->kind = TYPE_SLICE; + t->slice = &e->new.type; } else { - t->ptr = typer_malloc(tr, sizeof *t->ptr); + t->kind = TYPE_PTR; t->ptr = &e->new.type; } break; @@ -1003,7 +981,9 @@ static bool types_expr(Typer *tr, Expression *e) { return false; } if (lhs_type->kind != TYPE_ARR) { - err_print(e->where, "Trying to take index of non-array."); + char *s = type_to_str(lhs_type); + err_print(e->where, "Trying to take index of non-array type %s.", s); + free(s); return false; } *t = *lhs_type->arr.of; @@ -1054,7 +1034,7 @@ static bool types_decl(Typer *tr, Declaration *d) { if (d->flags & DECL_FLAG_ANNOTATES_TYPE) { /* type supplied */ assert(d->type.kind != TYPE_VOID); /* there's no way to annotate void */ - if (!types_type(tr, &d->type) || !type_resolve(tr->evalr, &d->type)) { + if (!type_resolve(tr, &d->type)) { success = false; goto ret; } @@ -382,6 +382,14 @@ typedef struct { struct Expression *expr; } CastExpr; +typedef struct { + Type type; + struct Expression *n; /* e.g. for new(int, 5) */ + struct { + IdentID id; + } c; +} NewExpr; + #define EXPR_FLAG_FOUND_TYPE 0x01 typedef struct Expression { @@ -408,9 +416,7 @@ typedef struct Expression { CallExpr call; DirectExpr direct; Identifier ident; - struct { - Type type; - } new; + NewExpr new; struct { Type type; } del; |