summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-10-20 11:39:21 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-10-20 11:39:21 -0400
commit89f00af3cf25d594f10aebaa7048a17bdd520c4b (patch)
treebbb22f3ffe808bca6849fd66693b094221a047fb
parentbfd0a7f6fbf22914631337b3871011f452d3fb94 (diff)
improved new; new slices
-rw-r--r--cgen.c141
-rw-r--r--eval.c3
-rw-r--r--main.c6
-rw-r--r--out.c35
-rw-r--r--parse.c25
-rwxr-xr-xrunv2
-rw-r--r--test.toc20
-rw-r--r--types.c78
-rw-r--r--types.h12
9 files changed, 191 insertions, 131 deletions
diff --git a/cgen.c b/cgen.c
index ff389e1..c733426 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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;
diff --git a/eval.c b/eval.c
index ba7712b..9f8209c 100644
--- a/eval.c
+++ b/eval.c
@@ -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));
diff --git a/main.c b/main.c
index ee75bc4..02309af 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/out.c b/out.c
index 450acad..d165db8 100644
--- a/out.c
+++ b/out.c
@@ -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__;}
+ }}
diff --git a/parse.c b/parse.c
index 58d53c2..5cf0381 100644
--- a/parse.c
+++ b/parse.c
@@ -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:
diff --git a/runv b/runv
index 698e83d..e892908 100755
--- a/runv
+++ b/runv
@@ -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
diff --git a/test.toc b/test.toc
index d21f355..3346b9e 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
+};
diff --git a/types.c b/types.c
index 387edef..fda1afa 100644
--- a/types.c
+++ b/types.c
@@ -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;
}
diff --git a/types.h b/types.h
index 1c5aaa4..59f1b4e 100644
--- a/types.h
+++ b/types.h
@@ -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;