diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/csx.c | 30 |
1 files changed, 23 insertions, 7 deletions
@@ -15,7 +15,8 @@ typedef enum csx_type { type_name, type_base, type_int, - type_fn + type_fn, + type_sx } csx_type; static csx_type type(void *p) @@ -222,6 +223,7 @@ static void *base_type(void *arg) case type_base: return csx_name("base"); case type_int: return csx_name("int"); case type_fn: return csx_name("fn"); + case type_sx: return csx_name("sx"); } return 0; } @@ -246,12 +248,20 @@ static void *base_fn(void *arg) return res; } +static void *base_sx(void *arg) +{ + fn_data *res = new(type_sx, sizeof(fn_data)); + res->params = head(arg); + res->body = tail(arg); + res->context = context; + return res; +} + static void *base_if(void *arg) { - void *saved = context; - void *res = csx_run(head(arg)); - context = saved; - return type(res) != type_null ? + if (type(arg) != type_pair) return null; + if (type(tail(arg)) != type_pair) return csx_run(head(arg)); + return type(csx_run(head(arg))) != type_null ? csx_run(head(tail(arg))) : csx_run(head(tail(tail(arg)))); } @@ -387,14 +397,19 @@ tailcall: return (*base)(ops); } } else if (type(fn) == type_fn) { - void *saved; void *res; + void *saved = context; ops = run_each(ops); - saved = context; context = new_pair(zip(fn->params, ops), fn->context); res = base_do(fn->body); context = saved; return res; + } else if (type(fn) == type_sx) { + void *saved = context; + context = new_pair(zip(fn->params, ops), fn->context); + arg = base_do(fn->body); + context = saved; + goto tailcall; } else if (type(fn) == type_pair) { pair_data *res = (void *)fn; int pos = *(int *)head(ops); @@ -425,6 +440,7 @@ static void new_context() base_set(csx_list(csx_name("type"), csx_base(base_type), 0)); base_set(csx_list(csx_name("do"), csx_base(base_do), 0)); base_set(csx_list(csx_name("fn"), csx_base(base_fn), 0)); + base_set(csx_list(csx_name("sx"), csx_base(base_sx), 0)); base_set(csx_list(csx_name("if"), csx_base(base_if), 0)); base_set(csx_list(csx_name("+"), csx_base(base_sum), 0)); base_set(csx_list(csx_name("*"), csx_base(base_prod), 0)); |