-Subproject commit 04b44ae194ffa5b2d20c963c92971f1acbab8ea0
+Subproject commit 95366beda5cdee923011fa5cf53269c74a1ec791
+++ /dev/null
-#ifndef __CURRY
-#define __CURRY
-ANN2(1,2,3) Type curry_type(const Env env, const Exp exp, const Exp func, const Exp args, const bool lambda);
-#endif
et_union,
et_auto,
et_none,
- et_apms,
et_dict,
MAX_TYPE
} type_enum;
ANN m_bool import_deep_equal(const Gwi gwi);
ANN m_bool import_dict(const Gwi gwi);
ANN m_bool import_gack(const Gwi gwi);
-ANN m_bool import_curry(const Gwi gwi);
#endif
--- /dev/null
+#ifndef __PARTIAL_APPLICATION
+#define __PARTIAL_APPLICATION
+
+ANN Type partial_type(const Env, Exp_Call *const);
+ANN void print_signature(const Func f);
+
+ANN static inline bool func_match_inner(const Env env, const Exp e,
+ const Type t, const bool implicit,
+ const bool specific) {
+ if (specific ? e->type == t : isa(e->type, t) > 0) // match
+ return true;
+ return !implicit ? false : check_implicit(env, e, t) > 0;
+}
+
+ANN static inline bool is_typed_hole(const Env env, const Exp exp) {
+ return exp->exp_type == ae_exp_cast && is_hole(env, exp->d.exp_cast.exp);
+}
+#endif
+++ /dev/null
-#include "gwion_util.h"
-#include "gwion_ast.h"
-#include "gwion_env.h"
-#include "vm.h"
-#include "instr.h"
-#include "emit.h"
-#include "gwion.h"
-#include "object.h"
-#include "operator.h"
-#include "import.h"
-#include "gwi.h"
-#include "traverse.h"
-#include "parse.h"
-#include "curry.h"
-
-ANN static Arg_List curry_arg_list(const Env env, const Arg_List base, const Exp e) {
- Arg_List args = new_mp_vector(env->gwion->mp, sizeof(Arg), 0);
- Exp next = e;
- uint32_t i = 0;
- while(next) {
- if(is_hole(env, next)) {
- char c[256];
- sprintf(c, "@%u\n", args->len);
- Type_Decl *td = cpy_type_decl(env->gwion->mp, mp_vector_at(base, Arg, i)->td);
- Arg arg = { .td = td, .var_decl = { .xid = insert_symbol(c) }};
- mp_vector_add(env->gwion->mp, &args, Arg, arg);
- }
- i++;
- next = next->next;
- }
- return args;
-}
-
-ANN2(1, 2) static inline Func_Base *curry_base(const Env env, const Func_Base *base, Exp earg, const loc_t loc) {
- Arg_List args = earg ? curry_arg_list(env, base->args, earg) : NULL;
- Func_Base *fb = new_func_base(env->gwion->mp, cpy_type_decl(env->gwion->mp, base->td), lambda_name(env->gwion->st, loc.first), args, ae_flag_none, loc);
- return fb;
-}
-
-ANN static Exp curry_call(const Env env, Exp e) {
- Exp base = NULL, arg;
- uint32_t i = 0;
- while(e) {
- if(is_hole(env, e)) {
- char c[256];
- sprintf(c, "@%u\n", i++);
- const Exp next = new_prim_id(env->gwion->mp, insert_symbol(c), e->pos);
- if(base) arg = arg->next = next;
- else arg = base = next;
- } else {
- const Exp next = cpy_exp(env->gwion->mp, e);
- if(base) arg = arg->next = next;
- else arg = base = next;
- }
- e = e->next;
- }
- return base;
-}
-
-ANN static Stmt curry_code(const Env env, const Exp efun, const Exp earg) {
- Stmt_List slist = new_mp_vector(env->gwion->mp, sizeof(struct Stmt_), 1);
- const Exp arg = curry_call(env, earg);
- const Exp exp = new_exp_call(env->gwion->mp, efun, arg, efun->pos);
- Stmt stmt = mp_vector_at(slist, struct Stmt_, 0);
- stmt->stmt_type = ae_stmt_return;
- stmt->d.stmt_exp.val = exp;
- return new_stmt_code(env->gwion->mp, slist, efun->pos);
-}
-
-ANN2(1,2,3) Type curry_type(const Env env, const Exp exp, const Exp func, const Exp args, const bool lambda) {
- Func_Base *const base = curry_base(env, func->type->info->func->def->base, args, exp->pos);
- const Stmt code = curry_code(env, func, args);
- if(lambda)base->fbflag |= fbflag_lambda; // rewritem
- exp->d.exp_lambda.def = new_func_def(env->gwion->mp, base, code);
- exp->exp_type = ae_exp_lambda;
- return check_exp(env, exp);
-}
-
-static OP_CHECK(opck_curry) {
- Exp_Call *call = (Exp_Call*)data;
- if(!call->args)
- ERR_N(exp_self(call)->pos, _("`curry` requires a function as first argument"));
- const Exp efun = call->args;
- const Exp earg = efun->next;
- efun->next = NULL;
- const Type ret = check_exp(env, efun)
- ? curry_type(env, exp_self(call), efun, earg, true)
- : env->gwion->type[et_error];
- mp_free(env->gwion->mp, Exp, earg);
- return ret;
-}
-
-GWION_IMPORT(curry) {
- GWI_BB(gwi_func_ini(gwi, "@function", "curry"));
- GWI_BB(gwi_func_end(gwi, (f_xfun)1, ae_flag_none));
-
- const Env env = gwi->gwion->env; // no need
- const Func f = (Func)map_at(&env->curr->info->func->map, map_size(&env->curr->info->func->map) - 1);
- const struct Op_Func opfunc = {.ck = opck_curry};
- const struct Op_Import opi = {
- .rhs = f->value_ref->type,
- .func = &opfunc,
- .data = (uintptr_t)f,
- .op = insert_symbol("@func_check")};
- CHECK_BB(add_op(gwi->gwion, &opi));
- return GW_OK;
-}
/*set_tflag(t_lambda, tflag_infer);*/
GWI_BB(gwi_set_global_type(gwi, t_lambda, et_lambda))
- gwidoc(gwi, "Mark function as apms.");
- const Type t_apms = gwi_mk_type(gwi, "@apms", 0, NULL);
- GWI_BB(gwi_set_global_type(gwi, t_apms, et_apms))
-
gwidoc(gwi, "type for internal pointer data.");
GWI_BB(gwi_typedef_ini(gwi, "int", "@internal"))
GWI_BB(gwi_typedef_end(gwi, ae_flag_none))
GWI_BB(import_gack(gwi));
- GWI_BB(import_curry(gwi));
-
gwi_func_ini(gwi, "float", "BasicLocale");
gwi_func_arg(gwi, "string", "str");
gwi_func_end(gwi, BasicLocale, ae_flag_none);
Exp_Call call = {.func = bin->rhs, .args = bin->lhs};
Exp e = exp_self(bin);
e->exp_type = ae_exp_call;
- call.apms = true;
memcpy(&e->d.exp_call, &call, sizeof(Exp_Call));
return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_error];
}
return ret;
}
-ANN static Exp order_apms(const Env env, Exp fn, const Exp _arg) {
- const MemPool mp = env->gwion->mp;
- Exp base = NULL;
- Exp next = NULL;
- Exp arg = _arg;
- do {
- const bool hole = is_hole(env, fn);
- const Exp curr = !hole ? fn : arg;
- if (hole) {
- if (!arg) {
- if (base) free_exp(mp, base);
- ERR_O(fn->pos, "not enough arguments for holes");
- }
- arg = arg->next;
- }
- if (!base)
- base = next = cpy_nonext(env, curr);
- else if(next) { // check me (added after a fuzzing session)
- next->next = cpy_nonext(env, curr);
- next = next->next;
- }
- } while ((fn = fn->next));
- assert(base);
- if (arg) {
- free_exp(mp, base);
- ERR_O(arg->pos, "too many arguments for holes");
- }
- return base;
-}
-
-static OP_CHECK(opck_apms) {
- Exp_Binary *bin = (Exp_Binary *)data;
- Exp lhs = bin->lhs;
- Exp_Call base = bin->rhs->d.exp_call;
- DECL_ON(const Exp, args, = order_apms(env, base.args, lhs));
- Exp_Call call = {.func = base.func, .args = args};
- Exp e = exp_self(bin);
- e->exp_type = ae_exp_call;
- e->type = NULL;
- memcpy(&e->d.exp_call, &call, sizeof(Exp_Call));
-
- const MemPool mp = env->gwion->mp;
- free_exp(mp, base.args);
- free_exp(mp, lhs);
-
- return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_error];
-}
-
static inline void fptr_instr(const Emitter emit, const Func f,
const m_uint i) {
const Instr set = emit_add_instr(emit, RegSetImm);
return check_lambda(env, actual_type(env->gwion, info->rhs->value_ref->type), l);
}
-ANN static Type curry2auto(const Env env, const Exp_Binary *bin) {
+ANN static Type partial2auto(const Env env, const Exp_Binary *bin) {
const Func_Def fdef = bin->lhs->d.exp_lambda.def;
unset_fbflag(fdef->base, fbflag_lambda);
CHECK_BN(traverse_func_def(env, fdef));
if (bin->lhs->exp_type == ae_exp_td)
ERR_N(bin->lhs->pos, "can't use {/}type decl expressions{0} in auto function pointer declarations");
if(!bin->lhs->type->info->func)
- return curry2auto(env, bin);
+ return partial2auto(env, bin);
// create a matching signature
// TODO: we could check first if there a matching existing one
Func_Base *const fbase =
GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "@function", NULL))
GWI_BB(gwi_oper_add(gwi, opck_func_call))
GWI_BB(gwi_oper_end(gwi, "=>", NULL))
- GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "@apms", NULL))
- GWI_BB(gwi_oper_add(gwi, opck_apms))
- GWI_BB(gwi_oper_end(gwi, "=>", NULL))
GWI_BB(gwi_oper_ini(gwi, NULL, "@func_ptr", "bool"))
GWI_BB(gwi_oper_end(gwi, "!", IntNot))
GWI_BB(gwi_oper_ini(gwi, "@function", "@func_ptr", NULL))
GWI_BB(gwi_oper_add(gwi, opck_fptr_at))
GWI_BB(gwi_oper_emi(gwi, opem_func_assign))
GWI_BB(gwi_oper_end(gwi, "@=>", NULL))
- // GWI_BB(gwi_oper_add(gwi, opck_fptr_cast))
- // GWI_BB(gwi_oper_emi(gwi, opem_fptr_cast))
- // GWI_BB(gwi_oper_end(gwi, "$", NULL))
GWI_BB(gwi_oper_add(gwi, opck_fptr_impl))
GWI_BB(gwi_oper_emi(gwi, opem_fptr_impl))
GWI_BB(gwi_oper_end(gwi, "@implicit", NULL))
#include "match.h"
#include "specialid.h"
#include "tmp_resolve.h"
-#include "curry.h"
+#include "partial.h"
ANN static m_bool check_stmt_list(const Env env, Stmt_List list);
ANN m_bool check_class_def(const Env env, const Class_Def class_def);
return type2td(env->gwion, t, pos);
}
-ANN static inline bool func_match_inner(const Env env, const Exp e,
- const Type t, const bool implicit,
- const bool specific) {
- if (specific ? e->type == t : isa(e->type, t) > 0) // match
- return true;
- return !implicit ? false : check_implicit(env, e, t) > 0;
-}
-
ANN2(1, 2)
static Func find_func_match_actual(const Env env, Func func, const Exp exp,
const bool implicit, const bool specific) {
e->cast_to = NULL;
if (!e->type) // investigate
return NULL;
-// rewrite
Arg *arg = i < args_len ? mp_vector_at(args, Arg, i++) : NULL;
if (!arg) {
if (fbflag(func->def->base, fbflag_variadic)) return func;
gw_err("\n");
}
-ANN static void print_arg(Arg_List args) {
- for(uint32_t i = 0; i < args->len; i++) {
- Arg *arg = mp_vector_at(args, Arg, i);
- gw_err("{G}%s{0} {/}%s{0}", arg->type ? arg->type->name : NULL,
- arg->var_decl.xid ? s_name(arg->var_decl.xid) : "");
- if(i < args->len - 1) gw_err(", ");
- }
-// while ((e = next_arg_Arg_List(e)));
-}
-
ANN2(1)
static void function_alternative(const Env env, const Type f, const Exp args,
const loc_t pos) {
gwerr_basic("Argument type mismatch", "call site",
"valid alternatives:", env->name, pos, 0);
Func up = f->info->func;
- do {
- gw_err(" {-}(%s){0} ", up->name);
- const Arg_List e = up->def->base->args;
- if (e)
- print_arg(e);
- else
- gw_err("{G}void{0}");
- gw_err("\n");
- } while ((up = up->next));
+ do print_signature(up);
+ while ((up = up->next));
if (args)
print_current_args(args);
else
}
exp->func->type = func->value_ref->type;
call_add_effect(env, func, exp->func->pos);
-// if (func == env->func) set_fflag(env->func, fflag_recurs);
return func->def->base->ret_type != env->gwion->type[et_auto] ?
func->def->base->ret_type : exp->func->d.exp_dot.base->type;
}
+ if(exp->func->exp_type == ae_exp_lambda) {
+ const Type tt = partial_type(env, exp);
+ if(tt) return tt;
+ }
function_alternative(env, exp->func->type, exp->args, exp->func->pos);
return NULL;
}
CHECK_OO(check_exp(env, bin->rhs));
if (is_auto) {
assert(bin->rhs->type == bin->lhs->type);
-// bin->rhs->type = bin->lhs->type;
set_vflag(mp_vector_at(bin->rhs->d.exp_decl.list, struct Var_Decl_, 0)->value, vflag_assigned);
}
struct Op_Import opi = {.op = bin->op,
return GW_ERROR;
}
-ANN2(1) static inline bool apms(const Env env, Exp exp) {
+ANN2(1) static inline bool is_partial(const Env env, Exp exp) {
while (exp) {
- if (is_hole(env, exp))
+ if (is_hole(env, exp) || is_typed_hole(env, exp))
return true;
exp = exp->next;
}
}
ANN static Type check_exp_call(const Env env, Exp_Call *exp) {
- if (exp->apms && apms(env, exp->args))
- return env->gwion->type[et_apms];
+ if (is_partial(env, exp->args)) {
+ CHECK_OO(check_exp(env, exp->func));
+ return partial_type(env, exp);
+ }
if (exp->tmpl) {
DECL_BO(const m_bool, ret, = func_check(env, exp));
if (!ret) return exp_self(exp)->type;
}
ANN static m_bool check_stmt_exp(const Env env, const Stmt_Exp stmt) {
+ if(stmt->val) {
+ CHECK_OB(check_exp(env, stmt->val));
+ if(!strncmp(stmt->val->type->name, "partial:", 8)) {
+ const loc_t loc = stmt->val->d.exp_lambda.def->base->pos;
+ env_warn(env, loc, "Partial application not used");
+ }
+ }
return stmt->val ? check_exp(env, stmt->val) ? 1 : -1 : 1;
}
const Exp call = new_exp_call(env->gwion->mp, id, arg, loc);
stmt->exp = call;
CHECK_BB(traverse_exp(env, id));
- CHECK_OB(curry_type(env, call, id, call->d.exp_call.args, false));
- CHECK_OB(traverse_func_def(env, call->d.exp_lambda.def));
+ CHECK_OB(partial_type(env, &call->d.exp_call));
}
return GW_OK;
}
if(fflag(func, fflag_valid))return GW_OK;
set_fflag(func, fflag_valid);
assert(func == fdef->base->func);
- if (env->class_def && !strstr(func->name, "lambda:"))
+ if (env->class_def && !fbflag(func->def->base, fbflag_lambda))
CHECK_BB(check_parent_match(env, fdef));
if (tmpl_base(fdef->base->tmpl)) return GW_OK;
Value override = NULL;
--- /dev/null
+#include "gwion_util.h"
+#include "gwion_ast.h"
+#include "gwion_env.h"
+#include "vm.h"
+#include "instr.h"
+#include "emit.h"
+#include "gwion.h"
+#include "object.h"
+#include "operator.h"
+#include "import.h"
+#include "gwi.h"
+#include "traverse.h"
+#include "parse.h"
+#include "partial.h"
+
+ANN static Arg_List partial_arg_list(const Env env, const Arg_List base, const Exp e) {
+ Arg_List args = new_mp_vector(env->gwion->mp, sizeof(Arg), 0);
+ Exp next = e;
+ uint32_t i = 0;
+ while(next) {
+ if(is_hole(env, next) || is_typed_hole(env, next)) {
+ char c[256];
+ sprintf(c, "@%u", args->len);
+ const Arg *src = mp_vector_at(base, Arg, i);
+ Type_Decl *td = src->td ? cpy_type_decl(env->gwion->mp, src->td) : NULL;
+ Arg arg = { .td = td, .var_decl = { .xid = insert_symbol(c) }};
+ mp_vector_add(env->gwion->mp, &args, Arg, arg);
+ }
+ i++;
+ next = next->next;
+ }
+ return args;
+}
+
+ANN static inline Symbol partial_name(const Env env, const pos_t pos) {
+ char c[7 + 1 + num_digit(pos.line) + num_digit(pos.column) + 2];
+ sprintf(c, "partial:%u:%u", pos.line, pos.column);
+ return insert_symbol(c);
+}
+
+ANN2(1, 2) static inline Func_Base *partial_base(const Env env, const Func_Base *base, Exp earg, const loc_t loc) {
+ Arg_List args = earg ? partial_arg_list(env, base->args, earg) : NULL;
+ Func_Base *fb = new_func_base(env->gwion->mp, cpy_type_decl(env->gwion->mp, base->td), partial_name(env, loc.first), args, ae_flag_none, loc);
+ return fb;
+}
+
+ANN static Exp partial_call(const Env env, Exp e) {
+ Exp base = NULL, arg;
+ uint32_t i = 0;
+ while(e) {
+ if(is_hole(env, e) || is_typed_hole(env, e)) {
+ char c[256];
+ sprintf(c, "@%u", i++);
+ const Exp next = new_prim_id(env->gwion->mp, insert_symbol(c), e->pos);
+ if(base) arg = arg->next = next;
+ else arg = base = next;
+ } else {
+ const Exp next = cpy_exp(env->gwion->mp, e);
+ if(base) arg = arg->next = next;
+ else arg = base = next;
+ }
+ e = e->next;
+ }
+ return base;
+}
+
+
+ANN Func find_match(const Env env, Func func, const Exp exp, const bool implicit,
+ const bool specific) {
+ do {
+ Exp e = exp;
+ uint32_t i = 0;
+ Arg_List args = func->def->base->args;
+ uint32_t len = args ? args->len : 0;
+ while(e) {
+ if (i >= len) break;
+ const Arg *arg = mp_vector_at(args, Arg, i++);
+ if(!is_hole(env, e)) {
+ if(!is_typed_hole(env, e)) {
+ const Exp next = e->next;
+ e->next = NULL;
+ check_exp(env, e);
+ e->next = next;
+ } else
+ CHECK_OO((e->type = known_type(env, e->d.exp_cast.td)));
+ if (!func_match_inner(env, e, arg->type, implicit, specific)) break;
+ }
+ e = e->next;
+ }
+ if (!e && len == i) return func;
+ } while ((func = func->next));
+ return NULL;
+}
+
+ANN Func find_match_actual(const Env env, const Func up, const Exp args) {
+ Func func;
+ if ((func = find_match(env, up, args, false, true)) ||
+ (func = find_match(env, up, args, true, true)) ||
+ (func = find_match(env, up, args, false, true)) ||
+ (func = find_match(env, up, args, true, false)))
+ return func;
+ return NULL;
+}
+
+ANN static Func partial_match(const Env env, const Func up, const Exp args, const loc_t loc);
+
+ANN static void print_arg(Arg_List args) {
+ for(uint32_t i = 0; i < args->len; i++) {
+ Arg *arg = mp_vector_at(args, Arg, i);
+ gw_err("{G}%s{0} {/}%s{0}", arg->type ? arg->type->name : NULL,
+ arg->var_decl.xid ? s_name(arg->var_decl.xid) : "");
+ if(i < args->len - 1) gw_err(", ");
+ }
+}
+
+ANN void print_signature(const Func f) {
+ gw_err(" {-}(%s){0} ", f->name);
+ const Arg_List args = f->def->base->args;
+ if (args)
+ print_arg(args);
+ else
+ gw_err("{G}void{0}");
+ gw_err("\n");
+}
+
+ANN void ambiguity(const Env env, Func f, const Exp args, const loc_t loc) {
+ print_signature(f);
+ while(f->next) {
+ const Func next = partial_match(env, f->next, args, loc);
+ if(next) print_signature(next);
+ f = f->next;
+ }
+}
+
+ANN static Func partial_match(const Env env, const Func up, const Exp args, const loc_t loc) {
+ const Func f = find_match_actual(env, up, args);
+ if(f) {
+ if(f->next) {
+ const Func next = partial_match(env, f->next, args, loc);
+ if(next) {
+ gwerr_basic("can't resolve ambiguity", "in this partial application", "use typed holes: _ $ type", env->name, loc, 0);
+ gw_err("\nthose functions could match:\n");
+ print_signature(f);
+ ambiguity(env, next, args, loc);
+ env->context->error = true;
+ return NULL;
+ }
+ }
+ return f;
+ }
+ return NULL;
+}
+
+ANN static Stmt partial_code(const Env env, const Exp efun, const Exp earg) {
+ Stmt_List slist = new_mp_vector(env->gwion->mp, sizeof(struct Stmt_), 1);
+ const Exp arg = partial_call(env, earg);
+ const Exp exp = new_exp_call(env->gwion->mp, efun, arg, efun->pos);
+ Stmt stmt = mp_vector_at(slist, struct Stmt_, 0);
+ stmt->stmt_type = ae_stmt_return;
+ stmt->d.stmt_exp.val = exp;
+ return new_stmt_code(env->gwion->mp, slist, efun->pos);
+}
+
+ANN static uint32_t count_args_exp(Exp args) {
+ uint32_t i = 0;
+ while(args && ++i) args = args->next;
+ return i;
+}
+
+ANN static uint32_t count_args_func(Func f, const uint32_t i) {
+ uint32_t max = 0;
+ while(f) {
+ const uint32_t len = f->def->base->args ? f->def->base->args->len : 0;
+ if(len > i && len > max) max = len;
+ f = f->next;
+ }
+ return max;
+}
+
+ANN static Exp expand(const Env env, const Func func, const Exp e, const loc_t loc) {
+ const uint32_t i = count_args_exp(e);
+ const uint32_t max = count_args_func(func, i);
+ if(max > i) {
+ Exp args = e;
+ if(args) {
+ while(args->next) args = args->next;
+ args->next = new_prim_id(env->gwion->mp, insert_symbol("_"), loc);
+ return e;
+ } else return new_prim_id(env->gwion->mp, insert_symbol("_"), loc);
+ }
+ return NULL;
+}
+
+ANN Type partial_type(const Env env, Exp_Call *const call) {
+ const Func f = partial_match(env, call->func->type->info->func, call->args, call->func->pos);
+ if(!f) {
+ const Exp e = expand(env, call->func->type->info->func, call->args, call->func->pos);
+ if(e) {
+ call->args = e;
+ return partial_type(env, call);
+ }
+ ERR_O(call->func->pos, "not match found for partial application");
+ }
+ Func_Base *const base = partial_base(env, f->def->base, call->args, call->func->pos);
+ const Stmt code = partial_code(env, call->func, call->args);
+ const Exp exp = exp_self(call);
+ exp->d.exp_lambda.def = new_func_def(env->gwion->mp, base, code);
+ exp->exp_type = ae_exp_lambda;
+ CHECK_OO(traverse_func_def(env, exp->d.exp_lambda.def));
+ return exp->d.exp_lambda.def->base->func->value_ref->type;
+}
Arg *arg = mp_vector_at(args, Arg, i);
const Value v = arg->var_decl.value;
v->from->offset = f->stack_depth;
- f->stack_depth += v->type->size;
+ //f->stack_depth += v->type->size;
+ f->stack_depth += v->type ? v->type->size : SZ_INT;
if (global) SET_FLAG(v, global);
}
return GW_OK;
const Exp_Binary *bin) {
CHECK_BB(scan2_exp(env, bin->lhs));
CHECK_BB(scan2_exp(env, bin->rhs));
- if(bin->rhs->exp_type == ae_exp_call)bin->rhs->d.exp_call.apms = true;
CHECK_BB(multi_decl(env, bin->lhs, bin->op));
return multi_decl(env, bin->rhs, bin->op);
}
+++ /dev/null
-#! [contains] 42
-
-fun void test(int i, int j) {
- <<< "The answer: ${ i + j}" >>>;
-}
-
-curry(test, 40, _)(2);
-
-curry(test, _, 2) @=> const (void(int)) func0;
-
-curry(test, 40, _) @=> const auto func1;
-
-func0(40);
-
-func1(2);