diff --git a/src/compiler.cpp b/src/compiler.cpp index b2564c3..602469c 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -820,16 +820,42 @@ Result Compiler::compile_fn(Context& context, Symbol& op, Oc::MakeClosure, {0, (int64_t)reg}, {0, (int64_t)reg + (int64_t)TRY(ctx.closures.size()) + 1})); - if (context.toplevel && !name.is()) { - int64_t gname = TRY(context.add_const(name)); - TRY(ex_res.add_opcode(Oc::GlobalStore, {1, (int64_t)gname}, - {0, (int64_t)reg})); + if (!name.is()) { + if (context.toplevel) { + int64_t gname = TRY(context.add_const(name)); + TRY(ex_res.add_opcode(Oc::GlobalStore, {1, (int64_t)gname}, + {0, (int64_t)reg})); + context.maxreg = reg + 1; + ex_res.reg = reg; + + return ex_res; + } else { + auto maybe_binding = context.get_var(name); + + if (maybe_binding.has_value()) { + auto breg = maybe_binding.value(); + TRY(ex_res.add_opcode(Oc::Mov, {0, (int64_t)breg}, {0, (int64_t)reg})); + ex_res.reg = reg; + + context.maxreg = reg + 1; + return std::move(ex_res); + } else { + context.maxreg = reg + 1; + auto breg = TRY(context.add_var(name)); + + TRY(ex_res.add_opcode(Oc::Mov, {0, (int64_t)breg}, {0, (int64_t)reg})); + ex_res.reg = breg; + context.maxreg = breg + 1; + + return std::move(ex_res); + } + } + } else { + context.maxreg = reg + 1; + ex_res.reg = reg; + + return ex_res; } - - context.maxreg = reg + 1; - ex_res.reg = reg; - - return ex_res; } Result Compiler::compile_let(Context& context, Symbol& op, @@ -924,6 +950,7 @@ Result Compiler::compile_body(Context& context, const Value& expr) { if (cur.is()) { ex_res.reg = expr.reg; } else { + // TODO: commenting this out means we waste registers // context.maxreg = maxreg; } } diff --git a/test/function.vli b/test/function.vli index 34d70ba..8716147 100644 --- a/test/function.vli +++ b/test/function.vli @@ -65,3 +65,13 @@ (+ x y)) (assert (= (def-redef) 6)) + +;; allow redefenition of variables with "fn" + +(fn def-redef-fn () + (def x 2) + (fn x (y) (+ x y)) + (x 3) + ) + +(assert (= (def-redef-fn) 5))