diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-03-09 18:21:14 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-03-09 18:21:14 -0400 |
commit | f7375a3534eeab4200ec8ed15b4d9acca5e1913f (patch) | |
tree | 13935a4f343baac65ebe8111c471aae48a45b004 | |
parent | 5edaca6cf2ea681c01c7ee0ef5daa041ed185640 (diff) |
more varargs
-rw-r--r-- | cgen.c | 23 | ||||
-rw-r--r-- | decls_cgen.c | 2 | ||||
-rw-r--r-- | eval.c | 44 | ||||
-rw-r--r-- | test.toc | 55 | ||||
-rw-r--r-- | types.c | 122 |
5 files changed, 115 insertions, 131 deletions
@@ -121,7 +121,7 @@ static void cgen_defs_decl(CGenerator *g, Declaration *d); break; \ case EXPR_FN: { \ FnExpr *fn = e->fn; \ - if (fn->instances.data) { \ + if (fn_has_instances(fn)) { \ Instance **data = fn->instances.data; \ for (U64 i = 0; i < fn->instances.cap; ++i) { \ if (fn->instances.occupied[i]) { \ @@ -250,6 +250,12 @@ static bool cgen_fn_is_direct(CGenerator *g, Declaration *d) { return (g->block == NULL || (g->block->flags & BLOCK_IS_NMS)) && (d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_FN && arr_len(d->idents) == 1; } +static bool fn_has_instances(FnExpr *f) { + if (fn_has_any_const_params(f)) return true; + if (!arr_len(f->params)) return false; + return type_is_builtin(&((Declaration *)arr_last(f->params))->type, BUILTIN_VARARGS); +} + static bool cgen_uses_ptr(Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { @@ -901,7 +907,7 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { else cgen_write(g, "val_"); bool positive_step - = fo->range.stepval == NULL || val_is_nonnegative(fo->range.stepval, &fo->type); + = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, &fo->type); cgen_write(g, " %c= to_", positive_step ? '<' : '>'); } else { if (fo->index) @@ -1011,11 +1017,13 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { cgen_expr_pre(g, e->call.fn); size_t i = 0; Constness *constness = e->call.fn->type.fn.constness; + size_t nparams = arr_len(e->call.fn->type.fn.types)-1; arr_foreach(e->call.arg_exprs, Expression, arg) { if (!constness || !arg_is_const(arg, constness[i])) { cgen_arg_pre(g, arg); } - ++i; + if (i < nparams-1) + ++i; } if (e->type.kind == TYPE_TUPLE) { Type *t = &e->type; @@ -1198,6 +1206,7 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { } static void cgen_expr(CGenerator *g, Expression *e) { + assert(e->flags & EXPR_FOUND_TYPE); switch (e->kind) { case EXPR_LITERAL_FLOAT: cgen_write(g, "%.16Lf", (long double)e->floatl); @@ -1611,8 +1620,8 @@ static void cgen_fn(CGenerator *g, FnExpr *f, U64 instance, Value *compile_time_ Type *type = param->type.kind == TYPE_TUPLE ? ¶m->type.tuple[i] : ¶m->type; Value arg = compile_time_args[carg_idx]; - if (type_is_builtin(type, BUILTIN_TYPE)) { - /* don't need to do anything; we'll just use the type's id */ + if (type_is_builtin(type, BUILTIN_TYPE) || type_is_builtin(type, BUILTIN_VARARGS)) { + /* don't need to do anything */ } else { cgen_val_pre(g, arg, type); cgen_type_pre(g, type); @@ -1942,8 +1951,8 @@ static void cgen_stmt(CGenerator *g, Statement *s) { } static void cgen_defs_fn(CGenerator *g, FnExpr *f) { - HashTable *instances = &f->instances; - if (instances->data) { + if (fn_has_instances(f)) { + HashTable *instances = &f->instances; /* generate each instance */ Instance **is = instances->data; for (U64 i = 0; i < instances->cap; ++i) { diff --git a/decls_cgen.c b/decls_cgen.c index bd97756..84bab0a 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -164,7 +164,7 @@ static void cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) { cgen_nl(g); return; } - if (f->instances.data) { + if (fn_has_instances(f)) { cgen_decls_fn_instances(g, f); } else { cgen_single_fn_decl(g, f, 0, 0); @@ -69,16 +69,16 @@ static bool val_truthiness(Value v, Type *t) { -static I64 val_to_i64(Value *v, BuiltinType v_type) { +static I64 val_to_i64(Value v, BuiltinType v_type) { switch (v_type) { - case BUILTIN_I8: return (I64)v->i8; - case BUILTIN_I16: return (I64)v->i16; - case BUILTIN_I32: return (I64)v->i32; - case BUILTIN_I64: return (I64)v->i64; - case BUILTIN_U8: return (I64)v->u8; - case BUILTIN_U16: return (I64)v->u16; - case BUILTIN_U32: return (I64)v->u32; - case BUILTIN_U64: return (I64)v->u64; + case BUILTIN_I8: return (I64)v.i8; + case BUILTIN_I16: return (I64)v.i16; + case BUILTIN_I32: return (I64)v.i32; + case BUILTIN_I64: return (I64)v.i64; + case BUILTIN_U8: return (I64)v.u8; + case BUILTIN_U16: return (I64)v.u16; + case BUILTIN_U32: return (I64)v.u32; + case BUILTIN_U64: return (I64)v.u64; default: break; } assert(0); @@ -87,8 +87,8 @@ static I64 val_to_i64(Value *v, BuiltinType v_type) { -static U64 val_to_u64(Value *v, BuiltinType v_type) { - if (v_type == BUILTIN_U64) return v->u64; +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); } @@ -628,7 +628,7 @@ static Status eval_expr_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, T if (rtype->builtin == BUILTIN_U64) { i = index.u64; } else { - I64 signed_index = val_to_i64(&index, rtype->builtin); + I64 signed_index = val_to_i64(index, rtype->builtin); if (signed_index < 0) { err_print(e->where, "Array or slice out of bounds (index = %ld)\n", (long)signed_index); return false; @@ -936,7 +936,7 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value switch (op) { case BINARY_ADD: if (lhs_type->kind == TYPE_PTR) { - out->ptr = (char *)lhs.ptr + val_to_i64(&rhs, rhs_type->builtin) + out->ptr = (char *)lhs.ptr + val_to_i64(rhs, rhs_type->builtin) * (I64)compiler_sizeof(lhs_type->ptr); } else { eval_binary_op_nums_only(+); @@ -944,7 +944,7 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value break; case BINARY_SUB: if (lhs_type->kind == TYPE_PTR) { - out->ptr = (char *)lhs.ptr - val_to_i64(&rhs, rhs_type->builtin) + out->ptr = (char *)lhs.ptr - val_to_i64(rhs, rhs_type->builtin) * (I64)compiler_sizeof(lhs_type->ptr); } else { eval_binary_op_nums_only(-); @@ -987,12 +987,12 @@ static Value val_zero(Type *t) { return val; } -static bool val_is_nonnegative(Value *v, Type *t) { +static bool val_is_nonnegative(Value v, Type *t) { switch (t->builtin) { case BUILTIN_BOOL: assert(0); return false; - case BUILTIN_CHAR: return v->charv >= 0; - case BUILTIN_F32: return v->f32 >= 0; - case BUILTIN_F64: return v->f64 >= 0; + case BUILTIN_CHAR: return v.charv >= 0; + case BUILTIN_F32: return v.f32 >= 0; + case BUILTIN_F64: return v.f64 >= 0; default: break; } if (!type_builtin_is_signed(t->builtin)) @@ -1271,7 +1271,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { if (fo->range.stepval) stepval = *fo->range.stepval; Value x = from; - bool step_is_negative = fo->range.stepval && !val_is_nonnegative(&stepval, &fo->type); + bool step_is_negative = fo->range.stepval && !val_is_nonnegative(stepval, &fo->type); if (index_val) index_val->i64 = 0; while (1) { if (fo->range.to) { @@ -1391,7 +1391,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { Value n; if (!eval_expr(ev, e->new.n, &n)) return false; - U64 n64 = val_to_u64(&n, e->new.n->type.builtin); + U64 n64 = val_to_u64(n, e->new.n->type.builtin); v->slice.data = err_calloc(n64, compiler_sizeof(&e->new.type)); v->slice.n = (I64)n64; } else { @@ -1521,7 +1521,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { if (!eval_expr(ev, s->from, &fromv)) return false; assert(s->from->type.kind == TYPE_BUILTIN); - from = val_to_u64(&fromv, s->from->type.builtin); + from = val_to_u64(fromv, s->from->type.builtin); } else { from = 0; } @@ -1530,7 +1530,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { if (!eval_expr(ev, s->to, &tov)) return false; assert(s->to->type.kind == TYPE_BUILTIN); - to = val_to_u64(&tov, s->to->type.builtin); + to = val_to_u64(tov, s->to->type.builtin); } else { to = n; } @@ -1,54 +1,9 @@ -#include "io.toc"; +// #include "std/io.toc"; -Arr ::= struct (t :: Type) { - data: []t; - len, cap: int; -}; - - -arr_add ::= fn(t ::=, a : &Arr(t), x : t) { - if a.len >= a.cap { - a.cap = a.cap * 2 + 2; - new_data := new(t, a.cap); - for i := 0..a.len-1 { - new_data[i] = a.data[i]; - } - a.data = new_data; - } - a.data[a.len] = x; - a.len += 1; -}; - -square ::= fn(t ::=, x : t) t { - a : Arr(t); - for i := 1,2..2*x-1 { - arr_add(&a, i); - }; - sum := 0 as t; - for i := 0..a.len-1 { - sum += a.data[i]; - }; - sum -}; - - -// ArrInt ::= Arr(int); - -inc ::= fn(t ::=, x : t) t { - x + 1 +f ::= fn(x :: ..) int { + x[0] }; main ::= fn() { - arr : Arr(int); - farr : Arr(float); - for i := 1..100 { - arr_add(&arr, inc(square(i))); - arr_add(&farr, inc(square(i as float))); - } - for i := 0..arr.len - 1 { - puti(arr.data[i]); - } - for i := 0..farr.len - 1 { - puti(farr.data[i] as int); - } -}; + f(1,2,3); +};
\ No newline at end of file @@ -755,14 +755,14 @@ static Status type_resolve(Typer *tr, Type *t, Location where) { U64 size; if (type_builtin_is_signed(n_expr->type.builtin)) { - I64 ssize = val_to_i64(&val, n_expr->type.builtin); + I64 ssize = val_to_i64(val, n_expr->type.builtin); if (ssize < 0) { err_print(t->arr.n_expr->where, "Negative array length (" I64_FMT ")", ssize); return false; } size = (U64)ssize; } else { - size = val_to_u64(&val, n_expr->type.builtin); + size = val_to_u64(val, n_expr->type.builtin); } t->arr.n = (U64)size; if (!type_resolve(tr, t->arr.of, where)) @@ -1935,6 +1935,7 @@ static Status types_expr(Typer *tr, Expression *e) { goto ret; } fn_decl = val.fn; + if (has_varargs) fn_decl->flags |= FN_EXPR_HAS_VARARGS; } @@ -2028,7 +2029,7 @@ static Status types_expr(Typer *tr, Expression *e) { original_fn = fn; fn_copy = typer_malloc(tr, sizeof *fn_copy); Copier cop = copier_create(tr->allocr, fn->body.parent); - copy_fn_expr(&cop, fn_copy, fn, has_varargs ? COPY_FN_EXPR_DONT_COPY_HEADER : 0); + copy_fn_expr(&cop, fn_copy, fn, 0); } if (fn_type->constness) { @@ -2121,10 +2122,19 @@ static Status types_expr(Typer *tr, Expression *e) { 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) { - param_decl->val.varargs = NULL; - - if (should_be_evald) { - /* TODO */ + /* 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; } } else if (should_be_evald) { if (!order || order[i] != -1) { @@ -2291,25 +2301,6 @@ static Status types_expr(Typer *tr, Expression *e) { arr_remove_lasta(&err_ctx->instance_stack, tr->allocr); if (!success) return false; arr_cleara(&table_index_type.tuple, tr->allocr); - - 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 i = 0; i < (int)nvarargs; ++i) { - Expression *arg = &arg_exprs[i+order[nparams-1]]; - VarArg *vararg = &varargs[i]; - - if (varargs_param->flags & DECL_IS_CONST) - vararg->val = arg->val; - vararg->type = &arg->type; - - } - - } } } free(order); @@ -2592,7 +2583,7 @@ static Status types_expr(Typer *tr, Expression *e) { break; } case BINARY_AT_INDEX: - if ((lhs_type->kind == TYPE_ARR || lhs_type->kind == TYPE_SLICE) && + if ((lhs_type->kind == TYPE_ARR || lhs_type->kind == TYPE_SLICE || type_is_builtin(lhs_type, BUILTIN_VARARGS)) && (rhs_type->kind != TYPE_BUILTIN || !type_builtin_is_numerical(rhs_type->builtin))) { err_print(e->where, "The index of an array must be a builtin numerical type."); return false; @@ -2642,34 +2633,63 @@ static Status types_expr(Typer *tr, Expression *e) { } break; case TYPE_BUILTIN: if (lhs_type->builtin == BUILTIN_NMS) { - if (!type_is_slicechar(rhs_type)) + /* allow accessing namespace members with a string */ + if (!type_is_slicechar(rhs_type)) { + char *s = type_to_str(rhs_type); + err_print(e->where, "Expected a string for namsepace member access with [], but got type %s.", s); + return false; + } + + Value nms_val; + if (!eval_expr(tr->evalr, lhs, &nms_val)) + return false; + Namespace *nms = nms_val.nms; + lhs->kind = EXPR_VAL; + lhs->val.nms = nms; + + Value member_name; + if (!eval_expr(tr->evalr, rhs, &member_name)) return false; + e->binary.op = BINARY_DOT; + e->binary.rhs->kind = EXPR_IDENT; + e->binary.rhs->ident = ident_get_with_len(&nms->body.idents, member_name.slice.data, (size_t)member_name.slice.n); + if (!type_of_ident(tr, rhs->where, &e->binary.rhs->ident, t)) { + return false; + } + break; + } else if (lhs_type->builtin == BUILTIN_VARARGS) { + assert(lhs->kind == EXPR_IDENT); + assert(lhs->ident->decl_kind == IDECL_DECL); + Declaration *decl = lhs->ident->decl; + assert(decl->flags & DECL_IS_PARAM); + Value index_val; + if (!eval_expr(tr->evalr, rhs, &index_val)) + return false; + /* NOTE: rhs->type was checked above */ + I64 i = val_to_i64(index_val, rhs->type.builtin); + VarArg *varargs = decl->val.varargs; + if (i < 0 || i >= (I64)arr_len(varargs)) { + err_print(e->where, "Index out of bounds for varargs access (index = " I64_FMT ", length = %lu).", i, (unsigned long)arr_len(varargs)); + return 0; + } + 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 */ + } break; } /* fallthrough */ default: { - /* allow accessing namespace members with a string */ - if (!type_is_slicechar(rhs_type)) { - char *s = type_to_str(rhs_type); - err_print(e->where, "Expected a string for namsepace member access with [], but got type %s.", s); - return false; - } - - Value nms_val; - if (!eval_expr(tr->evalr, lhs, &nms_val)) - return false; - Namespace *nms = nms_val.nms; - lhs->kind = EXPR_VAL; - lhs->val.nms = nms; - - Value member_name; - if (!eval_expr(tr->evalr, rhs, &member_name)) return false; - e->binary.op = BINARY_DOT; - e->binary.rhs->kind = EXPR_IDENT; - e->binary.rhs->ident = ident_get_with_len(&nms->body.idents, member_name.slice.data, (size_t)member_name.slice.n); - if (!type_of_ident(tr, rhs->where, &e->binary.rhs->ident, t)) { - return false; - } - } break; + char *s = type_to_str(lhs_type); + err_print(e->where, "Cannot subscript type %s", s); + free(s); + return false; + } } break; case BINARY_DOT: { |