Implement basic stdlib and a simple "println" function callable from lisp
This commit is contained in:
parent
48163e9251
commit
c7a3e820e0
16 changed files with 310 additions and 17 deletions
|
@ -21,6 +21,7 @@ target_sources(vm_lib
|
|||
src/compiler.cpp
|
||||
src/opcode.cpp
|
||||
src/fio.cpp
|
||||
src/stdlib.cpp
|
||||
|
||||
PUBLIC
|
||||
FILE_SET HEADERS
|
||||
|
@ -39,6 +40,7 @@ target_sources(vm_lib
|
|||
src/compiler.hpp
|
||||
src/opcode.hpp
|
||||
src/fio.hpp
|
||||
src/stdlib.hpp
|
||||
)
|
||||
|
||||
add_executable(vli src/vli.cpp)
|
||||
|
|
|
@ -11,4 +11,5 @@
|
|||
1
|
||||
(* n (fact (- n 1)))))
|
||||
|
||||
(fact 12)
|
||||
|
||||
(println "12! =" (fact 12))
|
|
@ -83,6 +83,8 @@ Result<PodObject*> Arena::gc_pod(PodObject* obj) {
|
|||
return gc_opcode((PodOpcode*)obj);
|
||||
case Tag::Function:
|
||||
return gc_function((PodFunction*)obj);
|
||||
case Tag::StdlibFunction:
|
||||
return gc_stdlib_function((PodStdlibFunction*)obj);
|
||||
case Tag::Module:
|
||||
return gc_module((PodModule*)obj);
|
||||
case Tag::Stack:
|
||||
|
@ -210,9 +212,17 @@ Result<PodObject*> Arena::gc_function(PodFunction* obj) {
|
|||
return nobj;
|
||||
}
|
||||
|
||||
Result<PodObject*> Arena::gc_stdlib_function(PodStdlibFunction* obj) {
|
||||
auto nobj = TRY(alloc<PodStdlibFunction>());
|
||||
nobj->header.tag = Tag::StdlibFunction;
|
||||
nobj->fun_id = obj->fun_id;
|
||||
|
||||
return nobj;
|
||||
}
|
||||
|
||||
Result<PodObject*> Arena::gc_module(PodModule* obj) {
|
||||
auto nobj = TRY(alloc<PodModule>());
|
||||
nobj->header.tag = Tag::Function;
|
||||
nobj->header.tag = Tag::Module;
|
||||
nobj->name = TRY(gc_pod(obj->name.get()));
|
||||
nobj->globals = TRY(gc_pod(obj->globals.get()));
|
||||
nobj->fun = TRY(gc_pod(obj->fun.get()));
|
||||
|
|
|
@ -156,6 +156,7 @@ class Arena {
|
|||
Result<PodObject*> gc_dict(PodDict* obj);
|
||||
Result<PodObject*> gc_opcode(PodOpcode* obj);
|
||||
Result<PodObject*> gc_function(PodFunction* obj);
|
||||
Result<PodObject*> gc_stdlib_function(PodStdlibFunction* obj);
|
||||
Result<PodObject*> gc_module(PodModule* obj);
|
||||
Result<PodObject*> gc_stack(PodStack* obj);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "arena.hpp"
|
||||
#include "error.hpp"
|
||||
#include "pod.hpp"
|
||||
#include "stdlib.hpp"
|
||||
#include "utf8.hpp"
|
||||
#include "writer.hpp"
|
||||
|
||||
|
@ -40,6 +41,8 @@ Result<Value> Value::create(PodObject* obj) {
|
|||
return Value(TRY(Opcode::create((PodOpcode*)obj)));
|
||||
case Tag::Function:
|
||||
return Value(TRY(Function::create((PodFunction*)obj)));
|
||||
case Tag::StdlibFunction:
|
||||
return Value(TRY(StdlibFunction::create((PodStdlibFunction*)obj)));
|
||||
case Tag::Module:
|
||||
return Value(TRY(Module::create((PodModule*)obj)));
|
||||
case Tag::Stack:
|
||||
|
@ -86,7 +89,7 @@ Result<Value> syntax_unwrap(Value& val) {
|
|||
return syntax->get_value();
|
||||
}
|
||||
|
||||
Result<Value> Nil::copy_value() const { return Value(Nil()); }
|
||||
Result<Value> Nil::copy_value() const { return Value(Nil(TRY(_value.copy()))); }
|
||||
|
||||
Result<Value> Int64::copy_value() const {
|
||||
return Value(Int64(TRY(_value.copy())));
|
||||
|
@ -162,6 +165,18 @@ Result<short> Function::cmp(const Function& rhs) const {
|
|||
return res;
|
||||
}
|
||||
|
||||
Result<Value> StdlibFunction::copy_value() const {
|
||||
return Value(StdlibFunction(TRY(_value.copy())));
|
||||
}
|
||||
Result<StdlibFunction> StdlibFunction::copy() const {
|
||||
return StdlibFunction(TRY(_value.copy()));
|
||||
}
|
||||
|
||||
Result<short> StdlibFunction::cmp(const StdlibFunction& rhs) const {
|
||||
short res = (fun_id() > rhs.fun_id()) - (fun_id() < rhs.fun_id());
|
||||
return res;
|
||||
}
|
||||
|
||||
Result<Value> Module::copy_value() const {
|
||||
return Value(Module(TRY(_value.copy())));
|
||||
}
|
||||
|
@ -276,6 +291,24 @@ Result<Array> Function::closure() const {
|
|||
return Array::create((PodArray*)_value->closure.get());
|
||||
}
|
||||
|
||||
Result<StdlibFunction> StdlibFunction::create(StdlibFunctionId fun_id) {
|
||||
auto pod = TRY(arena_alloc<PodStdlibFunction>());
|
||||
pod->header.tag = Tag::StdlibFunction;
|
||||
pod->fun_id = (uint64_t)fun_id;
|
||||
|
||||
return StdlibFunction(TRY(MkGcRoot(pod)));
|
||||
}
|
||||
|
||||
Result<Symbol> StdlibFunction::name() const {
|
||||
const char* fun_name =
|
||||
TRY(get_stdlib_function_name(StdlibFunctionId(_value->fun_id)));
|
||||
return Symbol::create(fun_name);
|
||||
}
|
||||
|
||||
StdlibFunctionId StdlibFunction::fun_id() const {
|
||||
return StdlibFunctionId(_value->fun_id);
|
||||
}
|
||||
|
||||
Result<Module> Module::create(const Value& name, const Function& fun,
|
||||
const Dict& globals) {
|
||||
auto pod = TRY(arena_alloc<PodModule>());
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "error.hpp"
|
||||
#include "opcode.hpp"
|
||||
#include "pod.hpp"
|
||||
#include "stdlib.hpp"
|
||||
#include "utf8.hpp"
|
||||
|
||||
// Forward declarations
|
||||
|
@ -29,6 +30,7 @@ class Writer;
|
|||
class Opcode;
|
||||
class Stack;
|
||||
class Function;
|
||||
class StdlibFunction;
|
||||
class Module;
|
||||
|
||||
short cmp_tag(Tag lhs, Tag rhs);
|
||||
|
@ -78,6 +80,9 @@ class Object {
|
|||
virtual Result<short> cmp(const Function& rhs) const {
|
||||
return cmp_tag(tag(), Tag::Function);
|
||||
}
|
||||
virtual Result<short> cmp(const StdlibFunction& rhs) const {
|
||||
return cmp_tag(tag(), Tag::StdlibFunction);
|
||||
}
|
||||
virtual Result<short> cmp(const Module& rhs) const {
|
||||
return cmp_tag(tag(), Tag::Module);
|
||||
}
|
||||
|
@ -892,6 +897,44 @@ class Function : public Object {
|
|||
GcRoot<PodFunction> _value;
|
||||
};
|
||||
|
||||
class StdlibFunction : public Object {
|
||||
public:
|
||||
StdlibFunction() {}
|
||||
StdlibFunction(StdlibFunction&& rhs) : _value(std::move(rhs._value)) {}
|
||||
StdlibFunction(GcRoot<PodStdlibFunction>&& val) : _value(std::move(val)) {}
|
||||
|
||||
StdlibFunction& operator=(StdlibFunction&& rhs) {
|
||||
_value = std::move(rhs._value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual Tag tag() const final { return Tag::StdlibFunction; }
|
||||
virtual PodObject* pod() const final { return _value.get(); }
|
||||
virtual Result<short> cmp(const Object& rhs) const final {
|
||||
return -TRY(rhs.cmp(*this));
|
||||
}
|
||||
virtual Result<short> cmp(const StdlibFunction& rhs) const final;
|
||||
|
||||
virtual void move(Object* obj) final {
|
||||
new (obj) StdlibFunction(std::move(_value));
|
||||
}
|
||||
|
||||
static Result<StdlibFunction> create(PodStdlibFunction* obj) {
|
||||
return StdlibFunction(TRY(MkGcRoot(obj)));
|
||||
}
|
||||
|
||||
static Result<StdlibFunction> create(StdlibFunctionId fun_id);
|
||||
|
||||
Result<Symbol> name() const;
|
||||
StdlibFunctionId fun_id() const;
|
||||
|
||||
virtual Result<Value> copy_value() const final;
|
||||
Result<StdlibFunction> copy() const;
|
||||
|
||||
private:
|
||||
GcRoot<PodStdlibFunction> _value;
|
||||
};
|
||||
|
||||
class Module : public Object {
|
||||
public:
|
||||
Module() {}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "compiler.hpp"
|
||||
|
||||
#include "common.hpp"
|
||||
#include "stdlib.hpp"
|
||||
|
||||
struct Context {
|
||||
Context() {}
|
||||
|
@ -183,20 +184,22 @@ Result<Expression> Compiler::compile_expr(Context& context, Value& expr) {
|
|||
case Tag::Pair:
|
||||
return compile_list(context, *expr.to<Pair>());
|
||||
case Tag::Int64:
|
||||
return compile_int64(context, *expr.to<Int64>());
|
||||
return compile_constant(context, expr);
|
||||
case Tag::Bool:
|
||||
return compile_bool(context, *expr.to<Bool>());
|
||||
case Tag::Symbol:
|
||||
return compile_symbol(context, *expr.to<Symbol>());
|
||||
case Tag::String:
|
||||
return compile_constant(context, expr);
|
||||
case Tag::Nil:
|
||||
case Tag::Float:
|
||||
case Tag::String:
|
||||
case Tag::Syntax:
|
||||
case Tag::Array:
|
||||
case Tag::ByteArray:
|
||||
case Tag::Dict:
|
||||
case Tag::Opcode:
|
||||
case Tag::Function:
|
||||
case Tag::StdlibFunction:
|
||||
case Tag::Module:
|
||||
case Tag::Stack:
|
||||
return ERROR(TypeMismatch);
|
||||
|
@ -606,11 +609,11 @@ Result<Expression> Compiler::compile_list(Context& context, Pair& expr) {
|
|||
return ERROR(TypeMismatch);
|
||||
}
|
||||
|
||||
Result<Expression> Compiler::compile_int64(Context& context, Int64& value) {
|
||||
Result<Expression> Compiler::compile_constant(Context& context, Value& value) {
|
||||
Expression ex = TRY(Expression::create());
|
||||
uint64_t reg = context.alloc_reg();
|
||||
|
||||
int64_t c = TRY(context.add_const(TRY(value.copy_value())));
|
||||
int64_t c = TRY(context.add_const(value));
|
||||
|
||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
||||
|
||||
|
@ -646,6 +649,19 @@ Result<Expression> Compiler::compile_symbol(Context& context, Symbol& value) {
|
|||
return std::move(ex);
|
||||
}
|
||||
|
||||
auto maybe_stdlib_fun = get_stdlib_function(value);
|
||||
|
||||
if (!maybe_stdlib_fun.has_error()) {
|
||||
auto stdlib_fun = TRY(StdlibFunction::create(maybe_stdlib_fun.value()));
|
||||
int64_t c = TRY(context.add_const(TRY(stdlib_fun.copy_value())));
|
||||
|
||||
uint64_t reg = context.alloc_reg();
|
||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
||||
|
||||
ex.reg = reg;
|
||||
return std::move(ex);
|
||||
}
|
||||
|
||||
// Otherwise treat unknown symbol as a global and try to load it from the
|
||||
// global scope
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class Compiler {
|
|||
Result<Expression> compile_primop(Context& context, Symbol& op, Pair& expr);
|
||||
Result<Expression> compile_comparison(Context& context, Symbol& op,
|
||||
Pair& expr);
|
||||
Result<Expression> compile_int64(Context& context, Int64& value);
|
||||
Result<Expression> compile_constant(Context& context, Value& value);
|
||||
Result<Expression> compile_symbol(Context& context, Symbol& value);
|
||||
Result<Expression> compile_bool(Context& context, Bool& value);
|
||||
Result<Expression> compile_if(Context& context, Symbol& op, Pair& expr);
|
||||
|
|
|
@ -20,6 +20,7 @@ enum class Tag : uint8_t {
|
|||
Dict,
|
||||
Opcode,
|
||||
Function,
|
||||
StdlibFunction,
|
||||
Module,
|
||||
Stack,
|
||||
};
|
||||
|
@ -169,6 +170,13 @@ class PodFunction final : public PodObject {
|
|||
OffPtr<PodObject> closure;
|
||||
};
|
||||
|
||||
class PodStdlibFunction final : public PodObject {
|
||||
public:
|
||||
PodStdlibFunction() : PodObject(Tag::StdlibFunction) {};
|
||||
|
||||
uint64_t fun_id;
|
||||
};
|
||||
|
||||
class PodModule final : public PodObject {
|
||||
public:
|
||||
PodModule() : PodObject(Tag::Module) {};
|
||||
|
|
117
src/stdlib.cpp
Normal file
117
src/stdlib.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include "stdlib.hpp"
|
||||
|
||||
#include "common.hpp"
|
||||
#include "pod.hpp"
|
||||
#include "writer.hpp"
|
||||
|
||||
typedef Result<Value> (*StdlibFunctionIdPtr)(const Array& params);
|
||||
|
||||
struct StdlibFunctionEntry {
|
||||
const char* name;
|
||||
StdlibFunctionId fun_id;
|
||||
StdlibFunctionIdPtr fun_ptr;
|
||||
};
|
||||
|
||||
Result<Value> stdlib_unknown(const Array& params) {
|
||||
return ERROR(NotImplemented);
|
||||
}
|
||||
|
||||
Result<void> print_string(const String& s) {
|
||||
auto ba = TRY(ByteArray::create(s));
|
||||
|
||||
for (uint64_t i = 0; i < ba.size(); i++) {
|
||||
std::cout << TRY(ba[i]);
|
||||
}
|
||||
|
||||
return Result<void>();
|
||||
}
|
||||
|
||||
Result<Value> stdlib_print(const Array& params) {
|
||||
for (uint64_t i = 0; i < params.size(); i++) {
|
||||
Value param = TRY(params.get(i));
|
||||
|
||||
if (i != 0) {
|
||||
std::cout << " ";
|
||||
}
|
||||
if (param.is<String>()) {
|
||||
TRY(print_string(*param.to<String>()));
|
||||
} else {
|
||||
auto s = TRY(write_one(param));
|
||||
TRY(print_string(s));
|
||||
}
|
||||
}
|
||||
|
||||
return Value(TRY(Nil::create()));
|
||||
}
|
||||
|
||||
Result<Value> stdlib_println(const Array& params) {
|
||||
TRY(stdlib_print(params));
|
||||
std::cout << "\n";
|
||||
|
||||
return Value(TRY(Nil::create()));
|
||||
}
|
||||
|
||||
Result<Value> stdlib_prn(const Array& params) { return ERROR(NotImplemented); }
|
||||
|
||||
#define STDLIB_FUNCTION(name, id) \
|
||||
[(uint64_t)StdlibFunctionId::id] = {#name, StdlibFunctionId::id, \
|
||||
stdlib_##name}
|
||||
|
||||
static StdlibFunctionEntry function_entries[] = {
|
||||
STDLIB_FUNCTION(unknown, Unknown),
|
||||
STDLIB_FUNCTION(print, Print),
|
||||
STDLIB_FUNCTION(println, PrintLn),
|
||||
STDLIB_FUNCTION(prn, Prn),
|
||||
[(uint64_t)StdlibFunctionId::Max] = {0, StdlibFunctionId::Max,
|
||||
stdlib_unknown},
|
||||
};
|
||||
|
||||
// TODO: this just scans through the array of functions linearly every time.
|
||||
// It doesn't have much effect at runtime, because such lookup is likely to
|
||||
// happen on compile-time only. But anyway, this is worth speeding up
|
||||
// eventually.
|
||||
StdlibFunctionEntry get_function_entry(const char* name) {
|
||||
for (uint64_t i = 1; i < (uint64_t)StdlibFunctionId::Max; i++) {
|
||||
if (strcmp(function_entries[i].name, name) == 0) {
|
||||
return function_entries[i];
|
||||
}
|
||||
}
|
||||
return function_entries[(uint64_t)StdlibFunctionId::Unknown];
|
||||
}
|
||||
|
||||
Result<StdlibFunctionId> get_stdlib_function(const Symbol& name) {
|
||||
const uint64_t bufsize = 256;
|
||||
char buf[bufsize];
|
||||
if (name.size() + 1 > bufsize) {
|
||||
return ERROR(KeyError);
|
||||
}
|
||||
|
||||
for (uint64_t i = 0; i < name.size(); i++) {
|
||||
buf[i] = (char)TRY(name[i]);
|
||||
}
|
||||
buf[name.size()] = 0;
|
||||
|
||||
StdlibFunctionId fun_id = get_function_entry(buf).fun_id;
|
||||
if (fun_id == StdlibFunctionId::Unknown) {
|
||||
return ERROR(KeyError);
|
||||
}
|
||||
|
||||
return fun_id;
|
||||
}
|
||||
|
||||
Result<Value> call_stdlib_function(StdlibFunctionId fun_id,
|
||||
const Array& params) {
|
||||
if (fun_id == StdlibFunctionId(0) || fun_id >= StdlibFunctionId::Max) {
|
||||
return ERROR(KeyError);
|
||||
}
|
||||
|
||||
return function_entries[(uint64_t)fun_id].fun_ptr(params);
|
||||
}
|
||||
|
||||
Result<const char*> get_stdlib_function_name(StdlibFunctionId fun_id) {
|
||||
if (fun_id == StdlibFunctionId(0) || fun_id >= StdlibFunctionId::Max) {
|
||||
return ERROR(KeyError);
|
||||
}
|
||||
|
||||
return function_entries[(uint64_t)fun_id].name;
|
||||
}
|
22
src/stdlib.hpp
Normal file
22
src/stdlib.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "result.hpp"
|
||||
|
||||
enum class StdlibFunctionId : uint64_t {
|
||||
Unknown,
|
||||
Print,
|
||||
PrintLn,
|
||||
Prn,
|
||||
Max,
|
||||
};
|
||||
|
||||
class Value;
|
||||
class Symbol;
|
||||
class Array;
|
||||
|
||||
Result<const char*> get_stdlib_function_name(StdlibFunctionId fun_id);
|
||||
Result<StdlibFunctionId> get_stdlib_function(const Symbol& name);
|
||||
Result<Value> call_stdlib_function(StdlibFunctionId fun_id,
|
||||
const Array& params);
|
|
@ -27,22 +27,22 @@ Result<void> run(int argc, const char* argv[]) {
|
|||
// TRY(String::create("((lambda (f y) (f y)) (lambda (x) (* x x)) 2)"));
|
||||
|
||||
auto parsed = TRY(read_multiple(src));
|
||||
auto code_str_written = TRY(write_multiple(parsed));
|
||||
// auto code_str_written = TRY(write_multiple(parsed));
|
||||
|
||||
TRY(arena_gc());
|
||||
|
||||
TRY(debug_print(code_str_written));
|
||||
// TRY(debug_print(code_str_written));
|
||||
|
||||
auto compiled = TRY(compile(parsed));
|
||||
Module& mod = *compiled.to<Module>();
|
||||
|
||||
TRY(debug_print(TRY(mod.globals())));
|
||||
// TRY(debug_print(TRY(mod.globals())));
|
||||
|
||||
auto vm = TRY(VM::create());
|
||||
|
||||
auto res = TRY(vm.run(mod));
|
||||
|
||||
TRY(debug_print(res));
|
||||
// TRY(debug_print(res));
|
||||
|
||||
return Result<void>();
|
||||
}
|
||||
|
|
35
src/vm.cpp
35
src/vm.cpp
|
@ -1,6 +1,7 @@
|
|||
#include "vm.hpp"
|
||||
|
||||
#include "common.hpp"
|
||||
#include "stdlib.hpp"
|
||||
|
||||
Result<Value> VM::getreg(uint64_t idx) { return _stack.get(_base + idx); }
|
||||
|
||||
|
@ -100,11 +101,7 @@ Result<void> VM::vm_less_equal(Opcode& oc) {
|
|||
return Result<void>();
|
||||
}
|
||||
|
||||
Result<void> VM::vm_call(Opcode& oc) {
|
||||
Value fun_value = TRY(get(oc.arg1().is_const, oc.arg1().arg));
|
||||
if (!fun_value.is<Function>()) return ERROR(TypeMismatch);
|
||||
Function& fun = *fun_value.to<Function>();
|
||||
|
||||
Result<void> VM::vm_call_lisp(Opcode& oc, Function& fun) {
|
||||
uint64_t reg_start = (uint64_t)oc.arg1().arg;
|
||||
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||
|
||||
|
@ -131,6 +128,34 @@ Result<void> VM::vm_call(Opcode& oc) {
|
|||
return Result<void>();
|
||||
}
|
||||
|
||||
Result<void> VM::vm_call_stdlib(Opcode& oc, StdlibFunction& fun) {
|
||||
uint64_t reg_start = (uint64_t)oc.arg1().arg;
|
||||
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||
|
||||
auto params = TRY(_stack.slice(reg_start + 1, reg_end));
|
||||
|
||||
auto res = TRY(call_stdlib_function(fun.fun_id(), params));
|
||||
setreg(oc.arg1().arg, res);
|
||||
|
||||
_pc++;
|
||||
return Result<void>();
|
||||
}
|
||||
|
||||
Result<void> VM::vm_call(Opcode& oc) {
|
||||
Value fun_value = TRY(get(oc.arg1().is_const, oc.arg1().arg));
|
||||
if (fun_value.is<Function>()) {
|
||||
Function& fun = *fun_value.to<Function>();
|
||||
return vm_call_lisp(oc, fun);
|
||||
}
|
||||
|
||||
if (fun_value.is<StdlibFunction>()) {
|
||||
StdlibFunction& fun = *fun_value.to<StdlibFunction>();
|
||||
return vm_call_stdlib(oc, fun);
|
||||
}
|
||||
|
||||
return ERROR(TypeMismatch);
|
||||
}
|
||||
|
||||
Result<void> VM::vm_ret(Opcode& oc) {
|
||||
if (_callstack.gettop() == 0) {
|
||||
_res = TRY(getreg((uint64_t)oc.arg1().arg));
|
||||
|
|
|
@ -26,6 +26,8 @@ class VM {
|
|||
Result<void> vm_sub(Opcode& oc);
|
||||
Result<void> vm_div(Opcode& oc);
|
||||
Result<void> vm_call(Opcode& oc);
|
||||
Result<void> vm_call_lisp(Opcode& oc, Function& fun);
|
||||
Result<void> vm_call_stdlib(Opcode& oc, StdlibFunction& fun);
|
||||
Result<void> vm_ret(Opcode& oc);
|
||||
|
||||
Result<void> vm_equal(Opcode& oc);
|
||||
|
|
|
@ -31,6 +31,8 @@ Result<String> Writer::write_one(const Value& obj) {
|
|||
return write_opcode(*obj.to<Opcode>());
|
||||
case Tag::Function:
|
||||
return write_function(*obj.to<Function>());
|
||||
case Tag::StdlibFunction:
|
||||
return write_stdlib_function(*obj.to<StdlibFunction>());
|
||||
case Tag::Module:
|
||||
return write_module(*obj.to<Module>());
|
||||
case Tag::Stack:
|
||||
|
@ -320,6 +322,16 @@ Result<String> Writer::write_function(const Function& val) {
|
|||
return res;
|
||||
}
|
||||
|
||||
Result<String> Writer::write_stdlib_function(const StdlibFunction& val) {
|
||||
auto name = TRY(val.name());
|
||||
String name_str = TRY(write_symbol(name));
|
||||
|
||||
String res = TRY(String::create("#<function "));
|
||||
res = TRY(res.concat(name_str));
|
||||
res = TRY(res.concat(">"));
|
||||
return res;
|
||||
}
|
||||
|
||||
Result<String> Writer::write_module(const Module& val) {
|
||||
auto name = TRY(val.name());
|
||||
if (name.is<Nil>()) {
|
||||
|
|
|
@ -24,6 +24,7 @@ class Writer {
|
|||
Result<String> write_syntax(const Syntax& val);
|
||||
Result<String> write_opcode(const Opcode& val);
|
||||
Result<String> write_function(const Function& val);
|
||||
Result<String> write_stdlib_function(const StdlibFunction& val);
|
||||
Result<String> write_module(const Module& val);
|
||||
Result<String> write_stack(const Stack& val);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue