2024-07-30 22:52:23 +00:00
|
|
|
#include "compiler.hpp"
|
|
|
|
|
2024-08-10 20:47:07 +00:00
|
|
|
#include "common.hpp"
|
|
|
|
|
2024-08-04 19:38:56 +00:00
|
|
|
struct Context {
|
|
|
|
Context() {}
|
2024-08-10 17:46:20 +00:00
|
|
|
Context(Value&& env, Array&& constants, Dict&& constants_dict)
|
2024-08-04 19:38:56 +00:00
|
|
|
: env(std::move(env)),
|
|
|
|
constants(std::move(constants)),
|
2024-08-10 17:46:20 +00:00
|
|
|
constants_dict(std::move(constants_dict)),
|
|
|
|
maxreg(0) {}
|
2024-08-04 19:38:56 +00:00
|
|
|
|
2024-08-09 22:45:06 +00:00
|
|
|
static Result<Context> create() {
|
|
|
|
auto env = TRY(Nil::create());
|
|
|
|
auto constants = TRY(Array::create());
|
2024-08-10 17:46:20 +00:00
|
|
|
auto constants_dict = TRY(Dict::create());
|
2024-08-04 19:38:56 +00:00
|
|
|
|
2024-08-10 17:46:20 +00:00
|
|
|
return Context(std::move(env), std::move(constants),
|
|
|
|
std::move(constants_dict));
|
2024-08-04 19:38:56 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 17:24:16 +00:00
|
|
|
uint64_t alloc_reg() {
|
|
|
|
uint64_t reg = maxreg;
|
|
|
|
++maxreg;
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
2024-08-10 17:56:42 +00:00
|
|
|
Result<int64_t> add_const(const Value& val) {
|
2024-08-10 17:46:20 +00:00
|
|
|
auto idx = constants_dict.get(val);
|
|
|
|
|
|
|
|
if (idx.has_value()) {
|
|
|
|
if (!idx.value().is<Int64>()) return ERROR(TypeMismatch);
|
|
|
|
|
|
|
|
return idx.value().to<Int64>()->value();
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t i = constants.size();
|
|
|
|
|
|
|
|
constants = TRY(constants.append(val));
|
|
|
|
constants_dict = TRY(constants_dict.insert(val, TRY(Value::create(i))));
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2024-08-04 19:38:56 +00:00
|
|
|
Value env;
|
|
|
|
Array constants;
|
2024-08-10 17:46:20 +00:00
|
|
|
Dict constants_dict;
|
2024-08-04 19:38:56 +00:00
|
|
|
uint64_t maxreg;
|
|
|
|
};
|
2024-07-30 22:52:23 +00:00
|
|
|
|
2024-08-10 20:47:07 +00:00
|
|
|
Result<void> Expression::add_opcode(Oc opcode, OpArg arg1, OpArg arg2,
|
|
|
|
OpArg arg3, OpArg arg4) {
|
2024-08-10 17:24:16 +00:00
|
|
|
Value oc = Value(TRY(Opcode::create(opcode, arg1, arg2, arg3, arg4)));
|
2024-08-10 20:47:07 +00:00
|
|
|
code = TRY(code.append(oc));
|
|
|
|
return Result<void>();
|
2024-08-10 17:24:16 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 10:17:20 +00:00
|
|
|
Result<bool> is_primitive_op(Symbol& sym) {
|
|
|
|
return TRY(sym.cmp("+")) == 0 || TRY(sym.cmp("-")) == 0 ||
|
|
|
|
TRY(sym.cmp("*")) == 0 || TRY(sym.cmp("/")) == 0;
|
2024-08-04 19:38:56 +00:00
|
|
|
return false;
|
2024-07-30 22:52:23 +00:00
|
|
|
}
|
|
|
|
|
2024-08-04 19:38:56 +00:00
|
|
|
Result<Value> Compiler::compile(Value& expr) {
|
2024-08-09 22:45:06 +00:00
|
|
|
auto context = TRY(Context::create());
|
2024-08-04 19:38:56 +00:00
|
|
|
|
2024-08-10 20:47:07 +00:00
|
|
|
auto ex = TRY(compile_expr(context, expr));
|
2024-08-11 20:37:37 +00:00
|
|
|
TRY(ex.add_opcode(Oc::Ret, {0, (int64_t)ex.reg}));
|
2024-08-10 20:47:07 +00:00
|
|
|
|
2024-08-11 20:37:37 +00:00
|
|
|
Value name = TRY(Nil::create());
|
2024-08-10 20:47:07 +00:00
|
|
|
Value constants = TRY(context.constants.copy());
|
|
|
|
Value code = TRY(ex.code.copy());
|
2024-08-11 20:37:37 +00:00
|
|
|
// TRY(debug_print(constants));
|
|
|
|
// TRY(debug_print(code));
|
|
|
|
|
|
|
|
auto fun = TRY(Function::create(name, 0, constants, code));
|
|
|
|
return Value(std::move(fun));
|
2024-08-04 19:38:56 +00:00
|
|
|
}
|
2024-08-10 17:56:42 +00:00
|
|
|
|
2024-08-04 19:38:56 +00:00
|
|
|
Result<Expression> Compiler::compile_expr(Context& context, Value& expr) {
|
2024-07-30 22:52:23 +00:00
|
|
|
switch (expr.tag()) {
|
|
|
|
case Tag::Pair:
|
2024-08-04 19:38:56 +00:00
|
|
|
return compile_list(context, *expr.to<Pair>());
|
2024-08-10 17:24:16 +00:00
|
|
|
case Tag::Int64:
|
|
|
|
return compile_int64(context, *expr.to<Int64>());
|
2024-07-30 22:52:23 +00:00
|
|
|
case Tag::Nil:
|
|
|
|
case Tag::Bool:
|
|
|
|
case Tag::Float:
|
|
|
|
case Tag::String:
|
|
|
|
case Tag::Symbol:
|
|
|
|
case Tag::Syntax:
|
|
|
|
case Tag::Array:
|
|
|
|
case Tag::ByteArray:
|
2024-08-01 17:56:38 +00:00
|
|
|
case Tag::Dict:
|
2024-08-10 17:24:16 +00:00
|
|
|
case Tag::Opcode:
|
2024-08-11 20:37:37 +00:00
|
|
|
case Tag::Function:
|
2024-08-12 22:05:40 +00:00
|
|
|
case Tag::Stack:
|
2024-08-10 10:17:20 +00:00
|
|
|
return ERROR(TypeMismatch);
|
2024-07-30 22:52:23 +00:00
|
|
|
}
|
2024-08-10 10:17:20 +00:00
|
|
|
return ERROR(TypeMismatch);
|
2024-07-30 22:52:23 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 10:17:20 +00:00
|
|
|
Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
|
|
|
Pair& expr) {
|
|
|
|
Value cur = TRY(expr.rest());
|
2024-08-10 20:47:07 +00:00
|
|
|
Expression ex = TRY(Expression::create());
|
2024-08-10 10:17:20 +00:00
|
|
|
|
2024-08-11 18:25:37 +00:00
|
|
|
Oc opcode = Oc::Unknown;
|
|
|
|
|
|
|
|
if (TRY(op.cmp("+")) == 0) {
|
|
|
|
opcode = Oc::Add;
|
|
|
|
} else if (TRY(op.cmp("*")) == 0) {
|
|
|
|
opcode = Oc::Mul;
|
|
|
|
} else {
|
|
|
|
return ERROR(NotImplemented);
|
|
|
|
}
|
|
|
|
|
2024-08-11 11:37:00 +00:00
|
|
|
if (cur.is<Nil>()) {
|
|
|
|
uint64_t reg = context.alloc_reg();
|
|
|
|
int64_t zero = TRY(context.add_const(TRY(Value::create((int64_t)0))));
|
|
|
|
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, zero}));
|
|
|
|
|
|
|
|
return ex;
|
|
|
|
}
|
|
|
|
|
|
|
|
Pair& pair = *cur.to<Pair>();
|
|
|
|
auto subexpr = TRY(pair.first());
|
|
|
|
|
|
|
|
auto comp = TRY(compile_expr(context, subexpr));
|
|
|
|
|
|
|
|
ex.add_code(comp.code);
|
2024-08-11 18:25:37 +00:00
|
|
|
uint64_t firstreg = comp.reg;
|
|
|
|
uint64_t reg = firstreg;
|
2024-08-11 11:37:00 +00:00
|
|
|
|
|
|
|
cur = TRY(pair.rest());
|
2024-08-10 17:24:16 +00:00
|
|
|
|
2024-08-10 10:17:20 +00:00
|
|
|
while (!cur.is<Nil>()) {
|
|
|
|
Pair& pair = *cur.to<Pair>();
|
|
|
|
auto subexpr = TRY(pair.first());
|
|
|
|
|
|
|
|
auto comp = TRY(compile_expr(context, subexpr));
|
|
|
|
|
2024-08-10 20:47:07 +00:00
|
|
|
ex.add_code(comp.code);
|
|
|
|
|
2024-08-11 18:25:37 +00:00
|
|
|
auto rest = TRY(pair.rest());
|
|
|
|
|
|
|
|
uint64_t res = 0;
|
|
|
|
if (rest.is<Nil>())
|
|
|
|
res = firstreg;
|
|
|
|
else
|
|
|
|
res = context.alloc_reg();
|
|
|
|
|
|
|
|
TRY(ex.add_opcode(opcode, {0, (int64_t)res}, {0, (int64_t)reg},
|
2024-08-10 20:47:07 +00:00
|
|
|
{0, (int64_t)comp.reg}));
|
2024-08-10 17:24:16 +00:00
|
|
|
|
|
|
|
reg = res;
|
2024-08-11 18:25:37 +00:00
|
|
|
cur = std::move(rest);
|
2024-08-10 10:17:20 +00:00
|
|
|
}
|
2024-08-10 17:24:16 +00:00
|
|
|
|
2024-08-11 18:25:37 +00:00
|
|
|
context.maxreg = firstreg + 1;
|
2024-08-10 20:47:07 +00:00
|
|
|
ex.reg = reg;
|
|
|
|
return std::move(ex);
|
2024-08-10 10:17:20 +00:00
|
|
|
}
|
2024-08-10 17:24:16 +00:00
|
|
|
|
2024-08-04 19:38:56 +00:00
|
|
|
Result<Expression> Compiler::compile_list(Context& context, Pair& expr) {
|
2024-08-09 22:45:06 +00:00
|
|
|
auto first = TRY(expr.first());
|
2024-08-04 19:38:56 +00:00
|
|
|
|
|
|
|
if (first.is<Symbol>()) {
|
|
|
|
Symbol& sym = *first.to<Symbol>();
|
2024-08-10 10:17:20 +00:00
|
|
|
if (TRY(is_primitive_op(sym))) {
|
|
|
|
return compile_primop(context, sym, expr);
|
|
|
|
}
|
2024-08-04 19:38:56 +00:00
|
|
|
}
|
2024-08-10 10:17:20 +00:00
|
|
|
return ERROR(TypeMismatch);
|
2024-07-30 22:52:23 +00:00
|
|
|
}
|
2024-08-10 17:24:16 +00:00
|
|
|
|
|
|
|
Result<Expression> Compiler::compile_int64(Context& context, Int64& value) {
|
2024-08-10 20:47:07 +00:00
|
|
|
Expression ex = TRY(Expression::create());
|
2024-08-10 17:24:16 +00:00
|
|
|
uint64_t reg = context.alloc_reg();
|
2024-08-10 20:47:07 +00:00
|
|
|
|
|
|
|
int64_t c = TRY(context.add_const(TRY(value.copy())));
|
|
|
|
|
|
|
|
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
2024-08-10 17:24:16 +00:00
|
|
|
|
2024-08-10 20:47:07 +00:00
|
|
|
ex.reg = reg;
|
|
|
|
return std::move(ex);
|
2024-08-10 17:24:16 +00:00
|
|
|
}
|
2024-08-11 20:37:37 +00:00
|
|
|
|
|
|
|
Result<Value> compile(Value& expr) {
|
|
|
|
Compiler c = Compiler();
|
|
|
|
return c.compile(expr);
|
|
|
|
}
|