Teach the compiler to handle syntax objects as input
This commit is contained in:
parent
4b7d845757
commit
12509f65df
5 changed files with 178 additions and 98 deletions
|
@ -527,7 +527,9 @@ Result<Dict> Dict::create(const Array& arr) {
|
||||||
|
|
||||||
Result<Value> Dict::get(const Value& key) const {
|
Result<Value> Dict::get(const Value& key) const {
|
||||||
auto pos = TRY(find(key));
|
auto pos = TRY(find(key));
|
||||||
if (pos >= size()) return ERROR(KeyError);
|
if (pos >= size()) {
|
||||||
|
return ERROR(KeyError);
|
||||||
|
}
|
||||||
auto k = TRY(Value::create(_value->data[pos * 2].get()));
|
auto k = TRY(Value::create(_value->data[pos * 2].get()));
|
||||||
|
|
||||||
if (TRY(k.cmp(key)) != 0) {
|
if (TRY(k.cmp(key)) != 0) {
|
||||||
|
@ -751,3 +753,51 @@ Result<Value> Object::second() const { return ERROR(TypeMismatch); }
|
||||||
Result<Value> Object::third() const { return ERROR(TypeMismatch); }
|
Result<Value> Object::third() const { return ERROR(TypeMismatch); }
|
||||||
|
|
||||||
Result<Value> Object::rest() const { return ERROR(TypeMismatch); }
|
Result<Value> Object::rest() const { return ERROR(TypeMismatch); }
|
||||||
|
|
||||||
|
Result<bool> syntax_is_list(const Value& value) {
|
||||||
|
if (!value.is<Syntax>()) return value.is<Pair>();
|
||||||
|
|
||||||
|
auto val = TRY(value.to<Syntax>()->expression());
|
||||||
|
return val.is<Pair>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<bool> syntax_is_nil(const Value& value) {
|
||||||
|
if (!value.is<Syntax>()) return value.is<Nil>();
|
||||||
|
|
||||||
|
auto val = TRY(value.to<Syntax>()->expression());
|
||||||
|
return val.is<Nil>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> syntax_first(const Value& value) {
|
||||||
|
if (!value.is<Syntax>()) return value.first();
|
||||||
|
|
||||||
|
auto val = TRY(value.to<Syntax>()->expression());
|
||||||
|
return val.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> syntax_second(const Value& value) {
|
||||||
|
if (!value.is<Syntax>()) return value.second();
|
||||||
|
|
||||||
|
auto val = TRY(value.to<Syntax>()->expression());
|
||||||
|
return val.second();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> syntax_third(const Value& value) {
|
||||||
|
if (!value.is<Syntax>()) return value.third();
|
||||||
|
|
||||||
|
auto val = TRY(value.to<Syntax>()->expression());
|
||||||
|
return val.third();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> syntax_rest(const Value& value) {
|
||||||
|
if (!value.is<Syntax>()) return value.rest();
|
||||||
|
|
||||||
|
auto val = TRY(value.to<Syntax>()->expression());
|
||||||
|
return val.rest();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> syntax_unwrap(const Value& value) {
|
||||||
|
if (!value.is<Syntax>()) return value.copy();
|
||||||
|
|
||||||
|
return TRY(value.to<Syntax>()->expression());
|
||||||
|
}
|
||||||
|
|
|
@ -1243,3 +1243,11 @@ Result<Array> Array::append(const V& value) const {
|
||||||
Value v = TRY(Value::create(value));
|
Value v = TRY(Value::create(value));
|
||||||
return append(v);
|
return append(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<bool> syntax_is_list(const Value& value);
|
||||||
|
Result<bool> syntax_is_nil(const Value& value);
|
||||||
|
Result<Value> syntax_first(const Value& value);
|
||||||
|
Result<Value> syntax_second(const Value& value);
|
||||||
|
Result<Value> syntax_third(const Value& value);
|
||||||
|
Result<Value> syntax_rest(const Value& value);
|
||||||
|
Result<Value> syntax_unwrap(const Value& value);
|
||||||
|
|
187
src/compiler.cpp
187
src/compiler.cpp
|
@ -192,7 +192,7 @@ Result<Value> Compiler::compile(Value& expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise perform actual compilation of the expression
|
// Otherwise perform actual compilation of the expression
|
||||||
if (!expr.is<Pair>()) {
|
if (!TRY(syntax_is_list(expr))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,8 @@ Result<Value> Compiler::compile(Value& expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_expr(Context& context, const Value& expr) {
|
Result<Expression> Compiler::compile_expr(Context& context, const Value& expr) {
|
||||||
switch (expr.tag()) {
|
auto unwrapped = TRY(syntax_unwrap(expr));
|
||||||
|
switch (unwrapped.tag()) {
|
||||||
case Tag::Pair:
|
case Tag::Pair:
|
||||||
return compile_list(context, expr);
|
return compile_list(context, expr);
|
||||||
case Tag::Int64:
|
case Tag::Int64:
|
||||||
|
@ -244,7 +245,7 @@ Result<Expression> Compiler::compile_expr(Context& context, const Value& expr) {
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
Value cur = TRY(expr.rest());
|
Value cur = TRY(syntax_rest(expr));
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
|
|
||||||
Oc opcode = Oc::Unknown;
|
Oc opcode = Oc::Unknown;
|
||||||
|
@ -269,7 +270,7 @@ Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto subexpr = TRY(cur.first());
|
auto subexpr = TRY(syntax_first(cur));
|
||||||
|
|
||||||
auto comp = TRY(compile_expr(context, subexpr));
|
auto comp = TRY(compile_expr(context, subexpr));
|
||||||
|
|
||||||
|
@ -277,16 +278,16 @@ Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
||||||
uint64_t firstreg = comp.reg;
|
uint64_t firstreg = comp.reg;
|
||||||
uint64_t reg = firstreg;
|
uint64_t reg = firstreg;
|
||||||
|
|
||||||
cur = TRY(cur.rest());
|
cur = TRY(syntax_rest(cur));
|
||||||
|
|
||||||
while (!cur.is<Nil>()) {
|
while (!cur.is<Nil>()) {
|
||||||
auto subexpr = TRY(cur.first());
|
auto subexpr = TRY(syntax_first(cur));
|
||||||
|
|
||||||
auto comp = TRY(compile_expr(context, subexpr));
|
auto comp = TRY(compile_expr(context, subexpr));
|
||||||
|
|
||||||
ex.add_code(comp.code);
|
ex.add_code(comp.code);
|
||||||
|
|
||||||
auto rest = TRY(cur.rest());
|
auto rest = TRY(syntax_rest(cur));
|
||||||
|
|
||||||
uint64_t res = 0;
|
uint64_t res = 0;
|
||||||
if (rest.is<Nil>())
|
if (rest.is<Nil>())
|
||||||
|
@ -308,7 +309,7 @@ Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_comparison(Context& context, Symbol& op,
|
Result<Expression> Compiler::compile_comparison(Context& context, Symbol& op,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
Value cur = TRY(expr.rest());
|
Value cur = TRY(syntax_rest(expr));
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
|
|
||||||
Oc opcode = Oc::Unknown;
|
Oc opcode = Oc::Unknown;
|
||||||
|
@ -345,7 +346,7 @@ Result<Expression> Compiler::compile_comparison(Context& context, Symbol& op,
|
||||||
int64_t false_c = TRY(context.add_const(TRY(Bool::create(false))));
|
int64_t false_c = TRY(context.add_const(TRY(Bool::create(false))));
|
||||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)result}, {1, true_c}));
|
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)result}, {1, true_c}));
|
||||||
|
|
||||||
auto subexpr = TRY(cur.first());
|
auto subexpr = TRY(syntax_first(cur));
|
||||||
|
|
||||||
auto comp = TRY(compile_expr(context, subexpr));
|
auto comp = TRY(compile_expr(context, subexpr));
|
||||||
|
|
||||||
|
@ -353,16 +354,16 @@ Result<Expression> Compiler::compile_comparison(Context& context, Symbol& op,
|
||||||
uint64_t firstreg = comp.reg;
|
uint64_t firstreg = comp.reg;
|
||||||
uint64_t reg = firstreg;
|
uint64_t reg = firstreg;
|
||||||
|
|
||||||
cur = TRY(cur.rest());
|
cur = TRY(syntax_rest(cur));
|
||||||
|
|
||||||
while (!cur.is<Nil>()) {
|
while (!cur.is<Nil>()) {
|
||||||
auto subexpr = TRY(cur.first());
|
auto subexpr = TRY(syntax_first(cur));
|
||||||
|
|
||||||
auto comp = TRY(compile_expr(context, subexpr));
|
auto comp = TRY(compile_expr(context, subexpr));
|
||||||
|
|
||||||
ex.add_code(comp.code);
|
ex.add_code(comp.code);
|
||||||
|
|
||||||
auto rest = TRY(cur.rest());
|
auto rest = TRY(syntax_rest(cur));
|
||||||
|
|
||||||
TRY(ex.add_opcode(opcode, {0, (int64_t)reg}, {0, (int64_t)comp.reg},
|
TRY(ex.add_opcode(opcode, {0, (int64_t)reg}, {0, (int64_t)comp.reg},
|
||||||
{0, (int64_t)cmp_expected}));
|
{0, (int64_t)cmp_expected}));
|
||||||
|
@ -380,25 +381,25 @@ Result<Expression> Compiler::compile_comparison(Context& context, Symbol& op,
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_if(Context& context, Symbol& op,
|
Result<Expression> Compiler::compile_if(Context& context, Symbol& op,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
Value first = TRY(expr.rest());
|
Value first = TRY(syntax_rest(expr));
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
if (!first.is<Pair>()) {
|
if (!TRY(syntax_is_list(first))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value second = TRY(first.rest());
|
Value second = TRY(syntax_rest(first));
|
||||||
|
|
||||||
if (!second.is<Pair>()) {
|
if (!TRY(syntax_is_list(second))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value third = TRY(second.rest());
|
Value third = TRY(syntax_rest(second));
|
||||||
|
|
||||||
if (!third.is<Pair>()) {
|
if (!TRY(syntax_is_list(third))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto condition = TRY(first.first());
|
auto condition = TRY(syntax_first(first));
|
||||||
|
|
||||||
auto condition_comp = TRY(compile_expr(context, condition));
|
auto condition_comp = TRY(compile_expr(context, condition));
|
||||||
|
|
||||||
|
@ -406,14 +407,14 @@ Result<Expression> Compiler::compile_if(Context& context, Symbol& op,
|
||||||
uint64_t firstreg = condition_comp.reg;
|
uint64_t firstreg = condition_comp.reg;
|
||||||
uint64_t reg = firstreg;
|
uint64_t reg = firstreg;
|
||||||
|
|
||||||
auto option1 = TRY(second.first());
|
auto option1 = TRY(syntax_first(second));
|
||||||
auto option1_comp = TRY(compile_expr(context, option1));
|
auto option1_comp = TRY(compile_expr(context, option1));
|
||||||
|
|
||||||
uint64_t option1_reg = option1_comp.reg;
|
uint64_t option1_reg = option1_comp.reg;
|
||||||
|
|
||||||
context.maxreg = firstreg + 1;
|
context.maxreg = firstreg + 1;
|
||||||
|
|
||||||
auto option2 = TRY(third.first());
|
auto option2 = TRY(syntax_first(third));
|
||||||
auto option2_comp = TRY(compile_expr(context, option2));
|
auto option2_comp = TRY(compile_expr(context, option2));
|
||||||
|
|
||||||
int64_t true_const = TRY(context.add_const(TRY(Bool::create(true))));
|
int64_t true_const = TRY(context.add_const(TRY(Bool::create(true))));
|
||||||
|
@ -439,9 +440,9 @@ Result<Expression> Compiler::compile_if(Context& context, Symbol& op,
|
||||||
|
|
||||||
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(syntax_rest(expr));
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
if (param.is<Nil>() || !param.is<Pair>()) {
|
if (!TRY(syntax_is_list(param))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,12 +455,12 @@ Result<Expression> Compiler::compile_and(Context& context, Symbol& op,
|
||||||
bool is_first = true;
|
bool is_first = true;
|
||||||
|
|
||||||
while (!param.is<Nil>()) {
|
while (!param.is<Nil>()) {
|
||||||
if (!param.is<Pair>()) {
|
if (!TRY(syntax_is_list(param))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rest = TRY(param.rest());
|
auto rest = TRY(syntax_rest(param));
|
||||||
Value param_val = TRY(param.first());
|
Value param_val = TRY(syntax_first(param));
|
||||||
|
|
||||||
auto param_ex = TRY(compile_expr(context, param_val));
|
auto param_ex = TRY(compile_expr(context, param_val));
|
||||||
|
|
||||||
|
@ -486,9 +487,9 @@ Result<Expression> Compiler::compile_and(Context& context, Symbol& op,
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_or(Context& context, Symbol& op,
|
Result<Expression> Compiler::compile_or(Context& context, Symbol& op,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
Value param = TRY(expr.rest());
|
Value param = TRY(syntax_rest(expr));
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
if (param.is<Nil>() || !param.is<Pair>()) {
|
if (!TRY(syntax_is_list(param))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,12 +502,12 @@ Result<Expression> Compiler::compile_or(Context& context, Symbol& op,
|
||||||
bool is_first = true;
|
bool is_first = true;
|
||||||
|
|
||||||
while (!param.is<Nil>()) {
|
while (!param.is<Nil>()) {
|
||||||
if (!param.is<Pair>()) {
|
if (!TRY(syntax_is_list(param))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rest = TRY(param.rest());
|
auto rest = TRY(syntax_rest(param));
|
||||||
Value param_val = TRY(param.first());
|
Value param_val = TRY(syntax_first(param));
|
||||||
|
|
||||||
auto param_ex = TRY(compile_expr(context, param_val));
|
auto param_ex = TRY(compile_expr(context, param_val));
|
||||||
|
|
||||||
|
@ -533,13 +534,13 @@ Result<Expression> Compiler::compile_or(Context& context, Symbol& op,
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_not(Context& context, Symbol& op,
|
Result<Expression> Compiler::compile_not(Context& context, Symbol& op,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
Value first = TRY(expr.rest());
|
Value first = TRY(syntax_rest(expr));
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
if (first.is<Nil>() || !first.is<Pair>()) {
|
if (!TRY(syntax_is_list(first))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto first_expr = TRY(first.first());
|
auto first_expr = TRY(syntax_first(first));
|
||||||
|
|
||||||
uint64_t result = context.alloc_reg();
|
uint64_t result = context.alloc_reg();
|
||||||
int64_t true_c = TRY(context.add_const(TRY(Bool::create(true))));
|
int64_t true_c = TRY(context.add_const(TRY(Bool::create(true))));
|
||||||
|
@ -560,10 +561,11 @@ Result<Expression> Compiler::compile_not(Context& context, Symbol& op,
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_def(Context& context, Symbol& op,
|
Result<Expression> Compiler::compile_def(Context& context, Symbol& op,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
auto varname = TRY(expr.second());
|
auto varname = TRY(syntax_second(expr));
|
||||||
if (!varname.is<Symbol>()) return ERROR(CompilationError);
|
auto varname_unwrapped = TRY(syntax_unwrap(varname));
|
||||||
|
if (!varname_unwrapped.is<Symbol>()) return ERROR(CompilationError);
|
||||||
|
|
||||||
auto var_expr = TRY(expr.third());
|
auto var_expr = TRY(syntax_third(expr));
|
||||||
|
|
||||||
uint64_t maxreg = context.maxreg;
|
uint64_t maxreg = context.maxreg;
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
|
@ -571,7 +573,7 @@ Result<Expression> Compiler::compile_def(Context& context, Symbol& op,
|
||||||
auto comp = TRY(compile_expr(context, var_expr));
|
auto comp = TRY(compile_expr(context, var_expr));
|
||||||
ex.add_code(comp.code);
|
ex.add_code(comp.code);
|
||||||
|
|
||||||
int64_t gname = TRY(context.add_const(varname));
|
int64_t gname = TRY(context.add_const(varname_unwrapped));
|
||||||
TRY(ex.add_opcode(Oc::GlobalStore, {1, (int64_t)gname},
|
TRY(ex.add_opcode(Oc::GlobalStore, {1, (int64_t)gname},
|
||||||
{0, (int64_t)comp.reg}));
|
{0, (int64_t)comp.reg}));
|
||||||
|
|
||||||
|
@ -586,49 +588,51 @@ Result<Expression> Compiler::compile_fn(Context& context, Symbol& op,
|
||||||
Context ctx = TRY(Context::create(context));
|
Context ctx = TRY(Context::create(context));
|
||||||
ctx.maxreg = 1; // Reserve the slot for function itself
|
ctx.maxreg = 1; // Reserve the slot for function itself
|
||||||
|
|
||||||
auto first = TRY(expr.rest());
|
auto first = TRY(syntax_rest(expr));
|
||||||
|
|
||||||
if (!first.is<Pair>()) {
|
if (!TRY(syntax_is_list(first))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value name = TRY(Nil::create());
|
Value name = TRY(Nil::create());
|
||||||
|
|
||||||
auto maybe_name = TRY(first.first());
|
auto maybe_name = TRY(syntax_first(first));
|
||||||
|
auto maybe_name_unwrapped = TRY(syntax_unwrap(maybe_name));
|
||||||
|
|
||||||
if (maybe_name.is<Symbol>()) {
|
if (maybe_name_unwrapped.is<Symbol>()) {
|
||||||
name = TRY(maybe_name.copy());
|
name = TRY(maybe_name_unwrapped.copy());
|
||||||
ctx.fname = TRY(name.copy());
|
ctx.fname = TRY(name.copy());
|
||||||
|
|
||||||
first = TRY(first.rest());
|
first = TRY(syntax_rest(first));
|
||||||
|
|
||||||
if (first.is<Nil>() || !first.is<Pair>()) {
|
if (!TRY(syntax_is_list(first))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto param = TRY(first.first());
|
auto param = TRY(syntax_first(first));
|
||||||
|
|
||||||
uint64_t arity = 0;
|
uint64_t arity = 0;
|
||||||
while (!param.is<Nil>()) {
|
while (!TRY(syntax_is_nil(param))) {
|
||||||
if (!param.is<Pair>()) {
|
if (!TRY(syntax_is_list(param))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
auto param_name = TRY(param.first());
|
auto param_name = TRY(syntax_first(param));
|
||||||
|
auto param_name_unwrapped = TRY(syntax_unwrap(param_name));
|
||||||
|
|
||||||
if (!param_name.is<Symbol>()) {
|
if (!param_name_unwrapped.is<Symbol>()) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t reg = TRY(ctx.add_var(param_name));
|
int64_t reg = TRY(ctx.add_var(param_name_unwrapped));
|
||||||
|
|
||||||
param = TRY(param.rest());
|
param = TRY(syntax_rest(param));
|
||||||
arity++;
|
arity++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value second = TRY(first.rest());
|
Value second = TRY(syntax_rest(first));
|
||||||
|
|
||||||
if (second.is<Nil>() || !second.is<Pair>()) {
|
if (!TRY(syntax_is_list(second))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,43 +724,44 @@ Result<Expression> Compiler::compile_let(Context& context, Symbol& op,
|
||||||
// Save the variable bindings to restore it later
|
// Save the variable bindings to restore it later
|
||||||
Dict saved_vars = TRY(context.variables_dict.copy());
|
Dict saved_vars = TRY(context.variables_dict.copy());
|
||||||
|
|
||||||
auto first = TRY(expr.rest());
|
auto first = TRY(syntax_rest(expr));
|
||||||
|
|
||||||
if (first.is<Nil>() || !first.is<Pair>()) {
|
if (!TRY(syntax_is_list(first))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t maxreg = context.maxreg;
|
uint64_t maxreg = context.maxreg;
|
||||||
|
|
||||||
auto bindings = TRY(first.first());
|
auto bindings = TRY(syntax_first(first));
|
||||||
|
|
||||||
Expression ex_res = TRY(Expression::create());
|
Expression ex_res = TRY(Expression::create());
|
||||||
|
|
||||||
while (!bindings.is<Nil>()) {
|
while (!bindings.is<Nil>()) {
|
||||||
auto binding = TRY(bindings.first());
|
auto binding = TRY(syntax_first(bindings));
|
||||||
|
|
||||||
if (!binding.is<Pair>()) {
|
if (!TRY(syntax_is_list(binding))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto binding_name = TRY(binding.first());
|
auto binding_name = TRY(syntax_first(binding));
|
||||||
auto binding_expr = TRY(binding.second());
|
auto binding_name_unwrapped = TRY(syntax_unwrap(binding_name));
|
||||||
|
auto binding_expr = TRY(syntax_second(binding));
|
||||||
|
|
||||||
if (!binding_name.is<Symbol>()) return ERROR(CompilationError);
|
if (!binding_name_unwrapped.is<Symbol>()) return ERROR(CompilationError);
|
||||||
|
|
||||||
int64_t reg = TRY(context.update_var(binding_name));
|
int64_t reg = TRY(context.update_var(binding_name_unwrapped));
|
||||||
auto ex = TRY(compile_expr(context, binding_expr));
|
auto ex = TRY(compile_expr(context, binding_expr));
|
||||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {0, (int64_t)ex.reg}));
|
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {0, (int64_t)ex.reg}));
|
||||||
context.maxreg = reg + 1;
|
context.maxreg = reg + 1;
|
||||||
|
|
||||||
ex_res.add_code(ex.code);
|
ex_res.add_code(ex.code);
|
||||||
|
|
||||||
bindings = TRY(bindings.rest());
|
bindings = TRY(syntax_rest(bindings));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value second = TRY(first.rest());
|
Value second = TRY(syntax_rest(first));
|
||||||
|
|
||||||
if (!second.is<Pair>()) {
|
if (!TRY(syntax_is_list(second))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,10 +785,10 @@ Result<Expression> Compiler::compile_body(Context& context, const Value& expr) {
|
||||||
int64_t maxreg = context.maxreg;
|
int64_t maxreg = context.maxreg;
|
||||||
|
|
||||||
while (!cur.is<Nil>()) {
|
while (!cur.is<Nil>()) {
|
||||||
if (!cur.is<Pair>()) {
|
if (!TRY(syntax_is_list(cur))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
auto expr_val = TRY(cur.first());
|
auto expr_val = TRY(syntax_first(cur));
|
||||||
|
|
||||||
// debug_print(expr_val);
|
// debug_print(expr_val);
|
||||||
|
|
||||||
|
@ -791,7 +796,7 @@ Result<Expression> Compiler::compile_body(Context& context, const Value& expr) {
|
||||||
|
|
||||||
TRY(ex_res.add_code(expr.code));
|
TRY(ex_res.add_code(expr.code));
|
||||||
|
|
||||||
cur = TRY(cur.rest());
|
cur = TRY(syntax_rest(cur));
|
||||||
|
|
||||||
if (cur.is<Nil>()) {
|
if (cur.is<Nil>()) {
|
||||||
ex_res.reg = expr.reg;
|
ex_res.reg = expr.reg;
|
||||||
|
@ -807,12 +812,14 @@ Result<Expression> Compiler::compile_function_call(Context& context,
|
||||||
const Value& expr) {
|
const Value& expr) {
|
||||||
auto ex = TRY(Expression::create());
|
auto ex = TRY(Expression::create());
|
||||||
|
|
||||||
auto first = TRY(expr.first());
|
auto first = TRY(syntax_first(expr));
|
||||||
auto param = TRY(expr.rest());
|
auto first_unwrapped = TRY(syntax_unwrap(first));
|
||||||
|
auto param = TRY(syntax_rest(expr));
|
||||||
|
|
||||||
bool is_self_call = false;
|
bool is_self_call = false;
|
||||||
uint64_t firstreg = context.maxreg;
|
uint64_t firstreg = context.maxreg;
|
||||||
if (first.is<Symbol>() && TRY(first.cmp(context.fname)) == 0) {
|
if (first_unwrapped.is<Symbol>() &&
|
||||||
|
TRY(first_unwrapped.cmp(context.fname)) == 0) {
|
||||||
int64_t r = context.alloc_reg();
|
int64_t r = context.alloc_reg();
|
||||||
int64_t c = TRY(context.add_const(TRY(Nil::create())));
|
int64_t c = TRY(context.add_const(TRY(Nil::create())));
|
||||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)r}, {1, (int64_t)c}));
|
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)r}, {1, (int64_t)c}));
|
||||||
|
@ -824,15 +831,15 @@ Result<Expression> Compiler::compile_function_call(Context& context,
|
||||||
|
|
||||||
int64_t maxreg = context.maxreg;
|
int64_t maxreg = context.maxreg;
|
||||||
while (!param.is<Nil>()) {
|
while (!param.is<Nil>()) {
|
||||||
if (!param.is<Pair>()) {
|
if (!TRY(syntax_is_list(param))) {
|
||||||
return ERROR(CompilationError);
|
return ERROR(CompilationError);
|
||||||
}
|
}
|
||||||
Value param_val = TRY(param.first());
|
Value param_val = TRY(syntax_first(param));
|
||||||
|
|
||||||
auto param_ex = TRY(compile_expr(context, param_val));
|
auto param_ex = TRY(compile_expr(context, param_val));
|
||||||
TRY(ex.add_code(param_ex.code));
|
TRY(ex.add_code(param_ex.code));
|
||||||
|
|
||||||
param = TRY(param.rest());
|
param = TRY(syntax_rest(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_self_call) {
|
if (is_self_call) {
|
||||||
|
@ -849,10 +856,11 @@ Result<Expression> Compiler::compile_function_call(Context& context,
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expression> Compiler::compile_list(Context& context, const Value& expr) {
|
Result<Expression> Compiler::compile_list(Context& context, const Value& expr) {
|
||||||
auto first = TRY(expr.first());
|
auto first = TRY(syntax_first(expr));
|
||||||
|
auto unwrapped = TRY(syntax_unwrap(first));
|
||||||
|
|
||||||
if (first.is<Symbol>()) {
|
if (unwrapped.is<Symbol>()) {
|
||||||
Symbol& sym = *first.to<Symbol>();
|
Symbol& sym = *unwrapped.to<Symbol>();
|
||||||
if (TRY(is_primitive_op(sym))) {
|
if (TRY(is_primitive_op(sym))) {
|
||||||
return compile_primop(context, sym, expr);
|
return compile_primop(context, sym, expr);
|
||||||
} else if (TRY(is_comparison_op(sym))) {
|
} else if (TRY(is_comparison_op(sym))) {
|
||||||
|
@ -874,7 +882,7 @@ Result<Expression> Compiler::compile_list(Context& context, const Value& expr) {
|
||||||
} else {
|
} else {
|
||||||
return compile_function_call(context, expr);
|
return compile_function_call(context, expr);
|
||||||
}
|
}
|
||||||
} else if (first.is<Pair>()) {
|
} else if (TRY(syntax_is_list(first))) {
|
||||||
return compile_function_call(context, expr);
|
return compile_function_call(context, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,7 +894,8 @@ Result<Expression> Compiler::compile_constant(Context& context,
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
uint64_t reg = context.alloc_reg();
|
uint64_t reg = context.alloc_reg();
|
||||||
|
|
||||||
int64_t c = TRY(context.add_const(value));
|
auto unwrapped = TRY(syntax_unwrap(value));
|
||||||
|
int64_t c = TRY(context.add_const(unwrapped));
|
||||||
|
|
||||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
||||||
|
|
||||||
|
@ -898,14 +907,16 @@ Result<Expression> Compiler::compile_symbol(Context& context,
|
||||||
const Value& value) {
|
const Value& value) {
|
||||||
Expression ex = TRY(Expression::create());
|
Expression ex = TRY(Expression::create());
|
||||||
|
|
||||||
|
auto unwrapped = TRY(syntax_unwrap(value));
|
||||||
|
|
||||||
// Symbol may be self-evaluating (e.g. :foo), in which case we just use it as
|
// Symbol may be self-evaluating (e.g. :foo), in which case we just use it as
|
||||||
// its own value
|
// its own value
|
||||||
|
|
||||||
if (value.is<Symbol>()) {
|
if (unwrapped.is<Symbol>()) {
|
||||||
Symbol& sym = *value.to<Symbol>();
|
Symbol& sym = *unwrapped.to<Symbol>();
|
||||||
|
|
||||||
if (sym.size() > 0 && TRY(sym[0]) == ':') {
|
if (sym.size() > 0 && TRY(sym[0]) == ':') {
|
||||||
int64_t c = TRY(context.add_const(value));
|
int64_t c = TRY(context.add_const(unwrapped));
|
||||||
|
|
||||||
uint64_t reg = context.alloc_reg();
|
uint64_t reg = context.alloc_reg();
|
||||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
||||||
|
@ -915,7 +926,7 @@ Result<Expression> Compiler::compile_symbol(Context& context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto maybe_reg = context.get_var(TRY(value.copy()));
|
auto maybe_reg = context.get_var(TRY(unwrapped.copy()));
|
||||||
|
|
||||||
if (!maybe_reg.has_error()) {
|
if (!maybe_reg.has_error()) {
|
||||||
auto var_reg = maybe_reg.value();
|
auto var_reg = maybe_reg.value();
|
||||||
|
@ -927,7 +938,8 @@ Result<Expression> Compiler::compile_symbol(Context& context,
|
||||||
return std::move(ex);
|
return std::move(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto maybe_stdlib_fun = get_stdlib_function(*value.to<Symbol>());
|
if (unwrapped.is<Symbol>()) {
|
||||||
|
auto maybe_stdlib_fun = get_stdlib_function(*unwrapped.to<Symbol>());
|
||||||
|
|
||||||
if (!maybe_stdlib_fun.has_error()) {
|
if (!maybe_stdlib_fun.has_error()) {
|
||||||
auto stdlib_fun = TRY(StdlibFunction::create(maybe_stdlib_fun.value()));
|
auto stdlib_fun = TRY(StdlibFunction::create(maybe_stdlib_fun.value()));
|
||||||
|
@ -939,11 +951,12 @@ Result<Expression> Compiler::compile_symbol(Context& context,
|
||||||
ex.reg = reg;
|
ex.reg = reg;
|
||||||
return std::move(ex);
|
return std::move(ex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Most variable references in function bodies will fall back to loading the
|
// Most variable references in function bodies will fall back to loading the
|
||||||
// accessed variables from parent closures.
|
// accessed variables from parent closures.
|
||||||
if (!context.toplevel) {
|
if (!context.toplevel) {
|
||||||
auto maybe_closure = context.get_closure(TRY(value.copy()));
|
auto maybe_closure = context.get_closure(TRY(unwrapped.copy()));
|
||||||
|
|
||||||
if (!maybe_closure.has_error()) {
|
if (!maybe_closure.has_error()) {
|
||||||
auto var_closure = maybe_closure.value();
|
auto var_closure = maybe_closure.value();
|
||||||
|
@ -960,7 +973,7 @@ Result<Expression> Compiler::compile_symbol(Context& context,
|
||||||
// Otherwise treat unknown symbol as a global and try to load it from the
|
// Otherwise treat unknown symbol as a global and try to load it from the
|
||||||
// global scope. This usually happens in toplevel expressions.
|
// global scope. This usually happens in toplevel expressions.
|
||||||
|
|
||||||
int64_t c = TRY(context.add_const(TRY(value.copy())));
|
int64_t c = TRY(context.add_const(TRY(unwrapped.copy())));
|
||||||
|
|
||||||
uint64_t reg = context.alloc_reg();
|
uint64_t reg = context.alloc_reg();
|
||||||
TRY(ex.add_opcode(Oc::GlobalLoad, {0, (int64_t)reg}, {1, (int64_t)c}));
|
TRY(ex.add_opcode(Oc::GlobalLoad, {0, (int64_t)reg}, {1, (int64_t)c}));
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
StaticArena<64 * 1024 * 1024> arena;
|
StaticArena<64 * 1024 * 1024> arena;
|
||||||
|
|
||||||
Result<Value> run_string(const String& src) {
|
Result<Value> run_string(const String& src) {
|
||||||
auto parsed = TRY(read_multiple(src, false));
|
auto parsed = TRY(read_multiple(src));
|
||||||
|
|
||||||
TRY(arena_gc());
|
TRY(arena_gc());
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ Result<void> run_repl() {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto src = TRY(read_line("valeri> "));
|
auto src = TRY(read_line("valeri> "));
|
||||||
auto parsed = TRY(read_multiple(src, false));
|
auto parsed = TRY(read_multiple(src));
|
||||||
auto compiled = TRY(compile(parsed));
|
auto compiled = TRY(compile(parsed));
|
||||||
Module& mod = *compiled.to<Module>();
|
Module& mod = *compiled.to<Module>();
|
||||||
auto vm = TRY(VM::create());
|
auto vm = TRY(VM::create());
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "writer.hpp"
|
#include "writer.hpp"
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "opcode.hpp"
|
#include "opcode.hpp"
|
||||||
#include "sourcerange.hpp"
|
#include "sourcerange.hpp"
|
||||||
|
@ -196,7 +197,15 @@ Result<String> Writer::write_srcloc(const SrcLoc& val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> Writer::write_syntax(const Syntax& val) {
|
Result<String> Writer::write_syntax(const Syntax& val) {
|
||||||
return TRY(String::create("#<syntax>"));
|
auto res = TRY(String::create("#<syntax "));
|
||||||
|
|
||||||
|
auto unwrapped = TRY(syntax_unwrap(TRY(val.copy_value())));
|
||||||
|
auto str = TRY(write_one(unwrapped));
|
||||||
|
|
||||||
|
res = TRY(res.concat(str));
|
||||||
|
|
||||||
|
res = TRY(res.concat(">"));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> Writer::write_pair(const Pair& val) {
|
Result<String> Writer::write_pair(const Pair& val) {
|
||||||
|
|
Loading…
Reference in a new issue