diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-03-10 13:46:04 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-03-10 13:46:04 -0400 |
commit | 64ff51894b290452963c7fd72e012be24bbeab4c (patch) | |
tree | c6352a20e81dd7cc82db646152ad1115d514f18f | |
parent | eab6760e746527e88d05d507195c78a0197e8be5 (diff) |
non-const varargs seem to be working at runtime
-rw-r--r-- | cgen.c | 42 | ||||
-rw-r--r-- | eval.c | 4 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | test.toc | 9 | ||||
-rw-r--r-- | types.c | 101 | ||||
-rw-r--r-- | types.h | 2 |
6 files changed, 92 insertions, 67 deletions
@@ -1262,6 +1262,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { } break; case EXPR_BINARY_OP: { const char *s = ""; + Expression *lhs = e->binary.lhs, *rhs = e->binary.rhs; bool handled = false; switch (e->binary.op) { case BINARY_SUB: @@ -1275,7 +1276,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { case BINARY_MOD: s = "%"; break; case BINARY_SET: - cgen_set(g, e->binary.lhs, NULL, e->binary.rhs, NULL); + cgen_set(g, lhs, NULL, rhs, NULL); handled = true; break; case BINARY_GT: @@ -1300,13 +1301,14 @@ static void cgen_expr(CGenerator *g, Expression *e) { s = "/="; break; case BINARY_SET_MOD: s = "%="; break; - case BINARY_AT_INDEX: + case BINARY_AT_INDEX: { + Type *lhs_type = &lhs->type; cgen_write(g, "("); - switch (e->binary.lhs->type.kind) { + switch (lhs_type->kind) { case TYPE_ARR: - cgen_expr(g, e->binary.lhs); + cgen_expr(g, lhs); cgen_write(g, "["); - cgen_expr(g, e->binary.rhs); + cgen_expr(g, rhs); cgen_write(g, "]"); break; case TYPE_SLICE: @@ -1315,42 +1317,52 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, "(*)"); cgen_type_post(g, &e->type); cgen_write(g, ")("); - cgen_expr(g, e->binary.lhs); + cgen_expr(g, lhs); cgen_write(g, ".data))["); - cgen_expr(g, e->binary.rhs); + cgen_expr(g, rhs); cgen_write(g, "]"); break; + case TYPE_BUILTIN: + if (lhs_type->builtin == BUILTIN_VARARGS) { + assert(lhs->kind == EXPR_IDENT); + assert(rhs->kind == EXPR_VAL); + assert(type_is_builtin(&rhs->type, BUILTIN_I64)); + I64 i = rhs->val.i64; + cgen_ident(g, lhs->ident); + cgen_write(g, I64_FMT "_", i); + } else assert(0); + break; default: assert(0); break; } cgen_write(g, ")"); handled = true; - break; + } break; case BINARY_DOT: { - Type *struct_type = &e->binary.lhs->type; + Type *struct_type = &lhs->type; if (struct_type->kind == TYPE_PTR) struct_type = struct_type->ptr; if (struct_type->kind == TYPE_STRUCT) { cgen_write(g, "("); - cgen_expr(g, e->binary.lhs); - bool is_ptr = e->binary.lhs->type.kind == TYPE_PTR; + cgen_expr(g, lhs); + bool is_ptr = lhs->type.kind == TYPE_PTR; cgen_write(g, is_ptr ? "->" :"."); cgen_ident_simple(g, e->binary.dot.field->name); cgen_write(g, ")"); } else { assert(type_is_builtin(struct_type, BUILTIN_NMS)); - char *prefix = e->binary.lhs->val.nms->c.prefix; + char *prefix = lhs->val.nms->c.prefix; cgen_write(g, "%s", prefix); - cgen_ident_simple(g, e->binary.rhs->ident); + cgen_ident_simple(g, rhs->ident); } handled = true; } break; } if (handled) break; cgen_write(g, "("); - cgen_expr(g, e->binary.lhs); + cgen_expr(g, lhs); cgen_write(g, "%s", s); - cgen_expr(g, e->binary.rhs); + cgen_expr(g, rhs); cgen_write(g, ")"); } break; case EXPR_UNARY_OP: { @@ -668,8 +668,10 @@ static Value *ident_val(Identifier i) { else return valp; } else { + if (!(decl->flags & DECL_FOUND_VAL)) { + return NULL; + } /* struct parameter */ - assert(decl->flags & DECL_FOUND_VAL); if (arr_len(decl->idents) > 1) return &decl->val.tuple[idx]; else @@ -36,6 +36,7 @@ any odd number of "s for a string allow omission of trailing ; in foo ::= fn() {...} or foo ::= nms {...} or foo ::= struct { ... } consider- should #sizeof always take a Type? it would be more verbose, but we might not actually need #sizeof that much, given that we have new. + it probably should, because #sizeof(x[0]) can't be evaluated at compile time if x is not a constant */ @@ -1,10 +1,9 @@ #include "std/io.toc"; -f ::= fn(x :: ..) Type { - [#sizeof(x[0])]x[1] +f ::= fn(x : ..) int { + x[0] + x[1] }; main ::= fn() { - x: f(int,u8); -}; -main();
\ No newline at end of file + puti(f(1,2)); +};
\ No newline at end of file @@ -420,9 +420,13 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { size_t param_idx; FnExpr *prev_fn = tr->fn; FnExpr fn_copy = {0}; - - /* f has compile time params, but it's not an instance! */ - bool generic = !(flags & TYPE_OF_FN_IS_INSTANCE) && fn_has_any_const_params(f); + + Declaration *last_param = arr_last(f->params); + bool has_varargs = last_param && (last_param->flags & DECL_ANNOTATES_TYPE) && type_is_builtin(&last_param->type, BUILTIN_VARARGS); + if (has_varargs) + f->flags |= FN_EXPR_HAS_VARARGS; + /* f has compile time params/varargs, but it's not an instance! */ + bool generic = !(flags & TYPE_OF_FN_IS_INSTANCE) && (fn_has_any_const_params(f) || has_varargs); if (generic) { Copier cop = copier_create(tr->allocr, &f->body); copy_fn_expr(&cop, &fn_copy, f, COPY_FN_EXPR_DONT_COPY_BODY); @@ -449,7 +453,6 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { success = false; goto ret; } - f->flags |= FN_EXPR_HAS_VARARGS; } if (param->type.kind == TYPE_TUPLE) { @@ -1456,7 +1459,7 @@ static Status types_expr(Typer *tr, Expression *e) { if (!type_of_fn(tr, e->fn, &e->type, 0)) { return false; } - if (fn_has_any_const_params(e->fn)) { + if (fn_has_any_const_params(e->fn) || fn_type_has_varargs(&e->type.fn)) { HashTable z = {0}; e->fn->instances = z; } else { @@ -2014,9 +2017,9 @@ static Status types_expr(Typer *tr, Expression *e) { c->arg_exprs = arg_exprs; FnExpr *original_fn = NULL; FnExpr *fn_copy = NULL; - + if (fn_type->constness || has_varargs) { - /* evaluate compile-time arguments + add an instance */ + /* eval function, create copy */ /* the function had better be a compile time constant if it has constant params */ @@ -2030,6 +2033,22 @@ static Status types_expr(Typer *tr, Expression *e) { fn_copy = typer_malloc(tr, sizeof *fn_copy); Copier cop = copier_create(tr->allocr, fn->body.parent); copy_fn_expr(&cop, fn_copy, fn, 0); + + if (has_varargs) { + /* set value of varargs param decl */ + VarArg *varargs = NULL; + arr_set_lena(&varargs, nvarargs, tr->allocr); + Declaration *varargs_param = arr_last(fn_copy->params); + varargs_param->val.varargs = varargs; + for (int v = 0; v < (int)nvarargs; ++v) { + Expression *arg = &arg_exprs[v+order[nparams-1]]; + VarArg *vararg = &varargs[v]; + + if (varargs_param->flags & DECL_IS_CONST) + vararg->val = arg->val; + vararg->type = &arg->type; + } + } } if (fn_type->constness) { @@ -2117,25 +2136,11 @@ static Status types_expr(Typer *tr, Expression *e) { } - /* eval compile time arguments */ for (i = 0; i < nparams; ++i) { bool should_be_evald = arg_is_const(&arg_exprs[i], fn_type->constness[i]); if (i == nparams-1 && has_varargs) { - /* set value of varargs param decl */ - VarArg *varargs = NULL; - arr_set_lena(&varargs, nvarargs, tr->allocr); - Declaration *varargs_param = arr_last(fn_copy->params); - varargs_param->val.varargs = varargs; - - for (int v = 0; v < (int)nvarargs; ++v) { - Expression *arg = &arg_exprs[v+order[nparams-1]]; - VarArg *vararg = &varargs[v]; - - if (varargs_param->flags & DECL_IS_CONST) - vararg->val = arg->val; - vararg->type = &arg->type; - } + /* handled above */ } else if (should_be_evald) { if (!order || order[i] != -1) { Expression *expr = &arg_exprs[i]; @@ -2163,30 +2168,33 @@ static Status types_expr(Typer *tr, Expression *e) { ++param_decl; } } + } + if (fn_type->constness || has_varargs) { /* type params, return declarations, etc */ - if (!type_of_fn(tr, fn, &f->type, TYPE_OF_FN_IS_INSTANCE)) + if (!type_of_fn(tr, fn_copy, &f->type, TYPE_OF_FN_IS_INSTANCE)) return false; - - /* deal with default arguments */ - i = 0; - arr_foreach(fn->params, Declaration, param) { - arr_foreach(param->idents, Identifier, ident) { - if (order && order[i] == -1) { - if (param->flags & DECL_INFER) { - arg_exprs[i].kind = EXPR_VAL; - arg_exprs[i].flags = EXPR_FOUND_TYPE; - arg_exprs[i].type = param_types[i] = param->type; - arg_exprs[i].val = param->val; - } else { - assert(param->flags & DECL_HAS_EXPR); - assert(param->expr.kind == EXPR_VAL); /* this was done by type_of_fn */ - arg_exprs[i] = param->expr; - copy_val(tr->allocr, &arg_exprs[i].val, ¶m->expr.val, ¶m->expr.type); + + if (fn_type->constness) { + /* deal with default arguments */ + size_t i = 0; + arr_foreach(fn_copy->params, Declaration, param) { + arr_foreach(param->idents, Identifier, ident) { + if (order && order[i] == -1) { + if (param->flags & DECL_INFER) { + arg_exprs[i].kind = EXPR_VAL; + arg_exprs[i].flags = EXPR_FOUND_TYPE; + arg_exprs[i].type = param_types[i] = param->type; + arg_exprs[i].val = param->val; + } else { + assert(param->flags & DECL_HAS_EXPR); + assert(param->expr.kind == EXPR_VAL); /* this was done by type_of_fn */ + arg_exprs[i] = param->expr; + copy_val(tr->allocr, &arg_exprs[i].val, ¶m->expr.val, ¶m->expr.type); + } } - } - ++i; + ++i; + } } - } ret_type = f->type.fn.types; @@ -2671,15 +2679,18 @@ static Status types_expr(Typer *tr, Expression *e) { err_print(e->where, "Index out of bounds for varargs access (index = " I64_FMT ", length = %lu).", i, (unsigned long)arr_len(varargs)); return 0; } + VarArg *vararg = &varargs[i]; if (decl->flags & DECL_IS_CONST) { /* replace with value */ - VarArg *vararg = &varargs[i]; e->kind = EXPR_VAL; e->type = *vararg->type; copy_val(tr->allocr, &e->val, &vararg->val, &e->type); - } else { - /* TODO */ + /* just use vararg's type */ + rhs->kind = EXPR_VAL; + rhs->val.i64 = i; + rhs->type.builtin = BUILTIN_I64; + *t = *vararg->type; } break; } @@ -888,7 +888,7 @@ typedef struct Declaration { }; } foreign; }; - Value val; /* only for constant decls and non-constant globals. */ + Value val; /* only for constant decls, non-constant globals, and varargs. */ /* for eval, for non-constant local decls: */ /* the pointers to values need to be fixed, which is why this isn't just Value *. */ |