summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eval.c31
-rw-r--r--parse.c6
-rw-r--r--test.toc18
-rw-r--r--tokenizer.c2
-rw-r--r--types.h19
5 files changed, 57 insertions, 19 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;
diff --git a/parse.c b/parse.c
index b03a213..e258416 100644
--- a/parse.c
+++ b/parse.c
@@ -866,6 +866,11 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
/* only called when token is fn */
assert(token_is_kw(t->token, KW_FN));
++t->token;
+ if (token_is_direct(t->token, DIRECT_CACHE)) {
+ f->flags |= FN_EXPR_CACHE;
+ f->cache = parser_calloc(p, 1, sizeof *f->cache);
+ ++t->token;
+ }
if (!token_is_kw(t->token, KW_LPAREN)) {
tokr_err(t, "Expected '(' after 'fn'.");
return false;
@@ -1770,6 +1775,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
case DIRECT_FOREIGN:
case DIRECT_EXPORT:
case DIRECT_INCLUDE:
+ case DIRECT_CACHE:
tokr_err(t, "Unrecognized expression.");
return false;
case DIRECT_COUNT: assert(0); break;
diff --git a/test.toc b/test.toc
index 56b4092..56718ab 100644
--- a/test.toc
+++ b/test.toc
@@ -2,19 +2,13 @@ io ::= nms{
#include "std/io.toc";
};
-foo ::= fn(a: [3]int) {
- a[0] = 128;
+ll ::= fn() Type {
+ struct {
+ head : int;
+ tail : &ll();
+ }
};
-f ::= fn() int {
- a : [3]int;
- foo(a);
- a[0]
-};
main ::= fn() {
- a ::= f();
- b := f();
- io.puti(a);
- io.puti(b);
-
+ l : ll();
};
diff --git a/tokenizer.c b/tokenizer.c
index 5a7e272..36d9aa5 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -19,7 +19,7 @@ static const char *const keywords[KW_COUNT] =
static inline const char *kw_to_str(Keyword k) { return keywords[k]; }
static const char *directives[DIRECT_COUNT] =
- {"C", "sizeof", "alignof", "export", "foreign", "builtin", "include"};
+ {"C", "sizeof", "alignof", "export", "foreign", "builtin", "include", "cache"};
/* Returns KW_COUNT if it's not a keyword */
/* OPTIM: don't use strncmp so much */
diff --git a/types.h b/types.h
index 620451c..c4851c4 100644
--- a/types.h
+++ b/types.h
@@ -131,6 +131,7 @@ typedef struct BlockArr {
ArrBlock *blocks;
} BlockArr;
+/* initialize to 0 */
typedef struct HashTable {
void *data;
bool *occupied;
@@ -229,6 +230,7 @@ typedef enum {
DIRECT_FOREIGN,
DIRECT_BUILTIN,
DIRECT_INCLUDE,
+ DIRECT_CACHE,
DIRECT_COUNT
} Directive;
@@ -594,7 +596,8 @@ typedef struct ForExpr {
enum {
FN_EXPR_FOREIGN = 0x01,
- FN_EXPR_EXPORT = 0x02 /* set by sdecls_cgen.c */
+ FN_EXPR_EXPORT = 0x02, /* set by sdecls_cgen.c */
+ FN_EXPR_CACHE = 0x04
};
typedef struct FnExpr {
@@ -614,6 +617,7 @@ typedef struct FnExpr {
the first element is a u64 value whose ith bit (1<<i) is 1
if the ith semi-constant parameter is constant.
*/
+ HashTable *cache; /* only set for FN_EXPR_CACHE */
struct {
/* if name = NULL, this is an anonymous function, and id will be the ID of the fn. */
Identifier name;
@@ -624,10 +628,15 @@ typedef struct FnExpr {
typedef struct Instance {
Value val; /* key into hash table */
- FnExpr *fn; /* the typed function */
- struct {
- U64 id;
- } c;
+ union {
+ struct {
+ FnExpr *fn; /* the typed function */
+ struct {
+ U64 id;
+ } c;
+ };
+ Value *ret_val; /* return value (for #cached functions). pointer must stay fixed, so this is a Value * */
+ };
} Instance;
typedef struct CastExpr {