diff --git a/src/arena.cpp b/src/arena.cpp index 4388331..f3485b3 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -91,6 +91,8 @@ Result Arena::gc_pod(PodObject* obj) { return gc_module((PodModule*)obj); case Tag::Stack: return gc_stack((PodStack*)obj); + case Tag::Error: + return gc_error((PodError*)obj); } return ERROR(TypeMismatch); @@ -264,6 +266,16 @@ Result Arena::gc_stack(PodStack* obj) { return nobj; } +Result Arena::gc_error(PodError* obj) { + auto nobj = TRY(alloc()); + nobj->header.tag = Tag::Error; + + nobj->name = TRY(gc_pod(obj->name.get())); + nobj->message = TRY(gc_pod(obj->message.get())); + + return nobj; +} + Arena& get_arena() { if (current_arena == 0) die("Arena not set\n"); return *current_arena; diff --git a/src/arena.hpp b/src/arena.hpp index 6270020..af51b95 100644 --- a/src/arena.hpp +++ b/src/arena.hpp @@ -160,6 +160,7 @@ class Arena { Result gc_stdlib_function(PodStdlibFunction* obj); Result gc_module(PodModule* obj); Result gc_stack(PodStack* obj); + Result gc_error(PodError* obj); void add_root(GcRootList* node) { _gcroot.insert(node); } diff --git a/src/common.cpp b/src/common.cpp index 7821582..014c51d 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -44,6 +44,8 @@ Result Value::create(PodObject* obj) { return Value(TRY(Module::create((PodModule*)obj))); case Tag::Stack: return Value(TRY(Stack::create((PodStack*)obj))); + case Tag::Error: + return Value(TRY(Error::create((PodError*)obj))); }; return Value(); } @@ -314,6 +316,28 @@ Result Stack::settop(uint64_t idx) { return Result(); } +Result Error::copy_value() const { + return Value(Error(TRY(_value.copy()))); +} +Result Error::copy() const { return Error(TRY(_value.copy())); } + +Result Error::name() const { return Value::create(_value->name.get()); } +Result Error::message() const { + return Value::create(_value->message.get()); +} + +Result Error::cmp(const Error& rhs) const { + auto lhs_name = TRY(name()); + auto rhs_name = TRY(rhs.name()); + short res = TRY(lhs_name.cmp(rhs_name)); + if (res != 0) return res; + + auto lhs_message = TRY(message()); + auto rhs_message = TRY(rhs.message()); + res = TRY(lhs_message.cmp(rhs_message)); + return res; +} + Result Pair::create(const Value& first, const Value& rest) { auto pod = TRY(arena_alloc()); pod->header.tag = Tag::Pair; diff --git a/src/common.hpp b/src/common.hpp index 2de9afc..e28e3da 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -33,6 +33,7 @@ class ByteArray; class Writer; class Opcode; class Stack; +class Error; class Function; class StdlibFunction; class Module; @@ -102,6 +103,9 @@ class Object { virtual Result cmp(const Stack& rhs) const { return ERROR(NotImplemented); } + virtual Result cmp(const Error& rhs) const { + return cmp_tag(tag(), Tag::Error); + } virtual Result add(const Object&) const; virtual Result add(const Int64&) const; @@ -1130,6 +1134,48 @@ class Stack : public Object { GcRoot _value; }; +class Error : public Object { + public: + Error() {} + Error(Error&& rhs) : _value(std::move(rhs._value)) {} + Error(GcRoot&& val) : _value(std::move(val)) {} + + virtual Tag tag() const final { return Tag::Error; } + virtual PodObject* pod() const final { return _value.get(); } + virtual Result cmp(const Object& rhs) const final { + return -TRY(rhs.cmp(*this)); + } + virtual Result cmp(const Error& rhs) const final; + + virtual void move(Object* obj) final { new (obj) Error(std::move(_value)); } + + static Result create(PodError* obj) { + return Error(TRY(MkGcRoot(obj))); + } + + static Result create(const char* name, const char* message) { + auto name_str = TRY(Symbol::create(name)); + auto message_str = TRY(String::create(message)); + + auto pod = TRY(arena_alloc()); + pod->header.tag = Tag::Error; + + pod->name = name_str.pod(); + pod->message = message_str.pod(); + + return Error(TRY(MkGcRoot(pod))); + } + + Result name() const; + Result message() const; + + virtual Result copy_value() const final; + Result copy() const; + + private: + GcRoot _value; +}; + // note: this class doesn't perform proper destruction of objects in some cases class Value { public: diff --git a/src/compiler.cpp b/src/compiler.cpp index 1ab1349..523d35d 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -238,6 +238,7 @@ Result Compiler::compile_expr(Context& context, const Value& expr) { case Tag::StdlibFunction: case Tag::Module: case Tag::Stack: + case Tag::Error: return ERROR(TypeMismatch); } return ERROR(TypeMismatch); diff --git a/src/pod.hpp b/src/pod.hpp index 5054e02..8432ce9 100644 --- a/src/pod.hpp +++ b/src/pod.hpp @@ -24,6 +24,7 @@ enum class Tag : uint8_t { StdlibFunction, Module, Stack, + Error, }; template @@ -200,6 +201,14 @@ class PodStack final : public PodObject { OffPtr data[]; }; +class PodError final : public PodObject { + public: + PodError() : PodObject(Tag::Error) {}; + + OffPtr name; + OffPtr message; +}; + template class Ptr { public: diff --git a/src/writer.cpp b/src/writer.cpp index ee41057..2017dba 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -41,6 +41,8 @@ Result Writer::write_one(const Value& obj) { return write_module(*obj.to()); case Tag::Stack: return write_stack(*obj.to()); + case Tag::Error: + return write_error(*obj.to()); }; return String(); } @@ -376,6 +378,10 @@ Result Writer::write_stack(const Stack& val) { return TRY(String::create("#")); } +Result Writer::write_error(const Error& val) { + return TRY(String::create("#")); +} + Result write_one(const Value& value) { auto w = Writer(); return w.write_one(value); diff --git a/src/writer.hpp b/src/writer.hpp index 84e3e30..bc79004 100644 --- a/src/writer.hpp +++ b/src/writer.hpp @@ -28,6 +28,7 @@ class Writer { Result write_stdlib_function(const StdlibFunction& val); Result write_module(const Module& val); Result write_stack(const Stack& val); + Result write_error(const Error& val); }; Result write_one(const Value& value);