summaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/eval.c b/eval.c
index b78ea45..65fb4c6 100644
--- a/eval.c
+++ b/eval.c
@@ -1529,6 +1529,10 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
}
/* NOTE: we're not calling fn_enter because we're manually entering the function */
+ Value *ret_val;
+ Value *arg_tuple = NULL;
+ Type *arg_type_tuple = NULL;
+
/* set parameter values */
Declaration *params = fn->params;
long arg = 0;
@@ -1545,11 +1549,35 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
Type *type = is_tuple ? &p->type.tuple[idx] : &p->type;
Value *ival = multiple_idents ? &pval->tuple[idx] : pval;
copy_val(NULL, ival, &arg_val, type);
+ if (fn->flags & FN_EXPR_CACHE) {
+ Value *arg_tuple_member = arr_add(&arg_tuple);
+ *(Type *)arr_add(&arg_type_tuple) = *type;
+ copy_val(ev->allocr, arg_tuple_member, &arg_val, type);
+ }
++arg;
++idx;
}
++arr_hdr(p->val_stack)->len;
}
+
+ if (fn->flags & FN_EXPR_CACHE) {
+ Value args;
+ args.tuple = arg_tuple;
+ Type args_type = {0};
+ args_type.flags = TYPE_IS_RESOLVED;
+ args_type.tuple = arg_type_tuple;
+ bool already_there;
+ Instance *i = instance_table_adda(ev->allocr, fn->cache, args, &args_type, &already_there);
+ arr_clear(&arg_tuple);
+ arr_clear(&arg_type_tuple);
+ if (already_there) {
+ *v = *i->ret_val;
+ return true;
+ } else {
+ ret_val = i->ret_val = evalr_calloc(ev, 1, sizeof *ret_val);
+ }
+
+ }
arr_foreach(fn->ret_decls, Declaration, d) {
int idx = 0;
@@ -1608,7 +1636,8 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
decl_remove_val(p);
arr_foreach(fn->ret_decls, Declaration, d)
decl_remove_val(d);
-
+ if (fn->flags & FN_EXPR_CACHE)
+ *ret_val = *v;
} break;
case EXPR_SLICE: {
SliceExpr *s = &e->slice;