Implement "when" form

This commit is contained in:
Konstantin Nazarov 2024-09-28 20:03:38 +01:00
parent 52eae6b3e3
commit 4945a86c2e
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
2 changed files with 47 additions and 0 deletions

View file

@ -433,6 +433,49 @@ Result<Expression> Compiler::compile_if(Context& context, Symbol& op,
return std::move(ex); return std::move(ex);
} }
Result<Expression> 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<Expression> Compiler::compile_and(Context& context, Symbol& op, Result<Expression> Compiler::compile_and(Context& context, Symbol& op,
const Value& expr) { const Value& expr) {
Value param = TRY(expr.rest()); Value param = TRY(expr.rest());
@ -918,6 +961,8 @@ Result<Expression> Compiler::compile_list(Context& context, const Value& expr) {
return compile_comparison(context, sym, expr); return compile_comparison(context, sym, expr);
} else if (TRY(sym.cmp("if")) == 0) { } else if (TRY(sym.cmp("if")) == 0) {
return compile_if(context, sym, expr); 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) { } else if (TRY(sym.cmp("and")) == 0) {
return compile_and(context, sym, expr); return compile_and(context, sym, expr);
} else if (TRY(sym.cmp("or")) == 0) { } else if (TRY(sym.cmp("or")) == 0) {

View file

@ -42,6 +42,8 @@ class Compiler {
Result<Expression> compile_symbol(Context& context, const Value& value); Result<Expression> compile_symbol(Context& context, const Value& value);
Result<Expression> compile_if(Context& context, Symbol& op, Result<Expression> compile_if(Context& context, Symbol& op,
const Value& expr); const Value& expr);
Result<Expression> compile_when(Context& context, Symbol& op,
const Value& expr);
Result<Expression> compile_and(Context& context, Symbol& op, Result<Expression> compile_and(Context& context, Symbol& op,
const Value& expr); const Value& expr);
Result<Expression> compile_or(Context& context, Symbol& op, Result<Expression> compile_or(Context& context, Symbol& op,