summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c42
-rw-r--r--eval.c4
-rw-r--r--main.c1
-rw-r--r--test.toc9
-rw-r--r--types.c101
-rw-r--r--types.h2
6 files changed, 92 insertions, 67 deletions
diff --git a/cgen.c b/cgen.c
index dd03cc9..dcfc240 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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: {
diff --git a/eval.c b/eval.c
index 796894e..8e6b765 100644
--- a/eval.c
+++ b/eval.c
@@ -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
diff --git a/main.c b/main.c
index 8ebe7cb..e47bf36 100644
--- a/main.c
+++ b/main.c
@@ -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
*/
diff --git a/test.toc b/test.toc
index d37489e..da377c8 100644
--- a/test.toc
+++ b/test.toc
@@ -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
diff --git a/types.c b/types.c
index 423ac2a..26a4015 100644
--- a/types.c
+++ b/types.c
@@ -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, &param->expr.val, &param->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, &param->expr.val, &param->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;
}
diff --git a/types.h b/types.h
index 38614d1..ceea98b 100644
--- a/types.h
+++ b/types.h
@@ -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 *. */