diff --git a/src/compiler.cpp b/src/compiler.cpp index 1357346..4fdc2db 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -433,6 +433,49 @@ Result Compiler::compile_if(Context& context, Symbol& op, return std::move(ex); } +Result Compiler::compile_when(Context& context, Symbol& op, + const Value& expr) { + Value rest = TRY(expr.rest()); + Expression ex = TRY(Expression::create()); + + auto num_params = TRY(rest.size()); + if (num_params < 2) { + return syntax_error(TRY(expr.first()), + "\"when\" form must have at least 2 arguments"); + } + + auto condition = TRY(rest.first()); + auto body = TRY(rest.rest()); + + auto condition_comp = TRY(compile_expr(context, condition)); + + ex.add_code(condition_comp.code); + uint64_t firstreg = condition_comp.reg; + uint64_t reg = firstreg; + + auto body_comp = TRY(compile_body(context, body)); + uint64_t body_reg = body_comp.reg; + + context.maxreg = firstreg + 1; + + int64_t true_const = TRY(context.add_const(TRY(Bool::create(true)))); + int64_t nil_const = TRY(context.add_const(TRY(Nil::create()))); + + TRY(ex.add_opcode(Oc::Equal, {0, (int64_t)firstreg}, {1, (int64_t)true_const}, + {0, (int64_t)1})); + + TRY(ex.add_opcode(Oc::Jump, {0, (int64_t)3})); + TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)firstreg}, {1, (int64_t)nil_const})); + TRY(ex.add_opcode(Oc::Jump, {0, (int64_t)TRY(body_comp.code.size()) + 2})); + + ex.add_code(body_comp.code); + + TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)firstreg}, {0, (int64_t)body_reg})); + + context.maxreg = firstreg + 1; + ex.reg = firstreg; + return std::move(ex); +} Result Compiler::compile_and(Context& context, Symbol& op, const Value& expr) { Value param = TRY(expr.rest()); @@ -918,6 +961,8 @@ Result Compiler::compile_list(Context& context, const Value& expr) { return compile_comparison(context, sym, expr); } else if (TRY(sym.cmp("if")) == 0) { return compile_if(context, sym, expr); + } else if (TRY(sym.cmp("when")) == 0) { + return compile_when(context, sym, expr); } else if (TRY(sym.cmp("and")) == 0) { return compile_and(context, sym, expr); } else if (TRY(sym.cmp("or")) == 0) { diff --git a/src/compiler.hpp b/src/compiler.hpp index 2c8ff74..3329171 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -42,6 +42,8 @@ class Compiler { Result compile_symbol(Context& context, const Value& value); Result compile_if(Context& context, Symbol& op, const Value& expr); + Result compile_when(Context& context, Symbol& op, + const Value& expr); Result compile_and(Context& context, Symbol& op, const Value& expr); Result compile_or(Context& context, Symbol& op,