diff --git a/CMakeLists.txt b/CMakeLists.txt index cb7f166..6382957 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ target_sources(vm_lib src/vm.cpp src/common.cpp src/arena.cpp + src/reader.cpp PUBLIC FILE_SET HEADERS @@ -25,6 +26,8 @@ target_sources(vm_lib src/pod.hpp src/result.hpp src/vm.hpp + src/sourcerange.hpp + src/reader.hpp ) add_executable(vli src/vli.cpp) diff --git a/src/arena.hpp b/src/arena.hpp index faa6eb9..3b5e673 100644 --- a/src/arena.hpp +++ b/src/arena.hpp @@ -17,6 +17,8 @@ class GcRootBase { ~GcRootBase(); + PodObject* get() { return _ptr; } + protected: PodObject* _ptr; GcRootList* _node; @@ -35,6 +37,7 @@ class GcRoot : public GcRootBase { return GcRoot::create((T*)_ptr, arena); } + T* get() { return (T*)_ptr; } T& operator*() { return *(T*)_ptr; } T* operator->() { return (T*)_ptr; } }; diff --git a/src/common.cpp b/src/common.cpp index 858e3b5..edc00a0 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1,6 +1,8 @@ #include "common.hpp" #include "arena.hpp" +#include "error.hpp" +#include "pod.hpp" Syntax::Syntax(String filename, String modulename, Value expression) {} @@ -11,11 +13,11 @@ Result Syntax::get_value(Arena& arena) { Result Value::create(Arena& arena, PodObject* obj) { switch (obj->header.tag) { case Tag::Nil: - return Value(); + return Value(TRY(Nil::create(arena, (PodNil*)obj))); case Tag::Int64: - return Value(Int64(((PodInt64*)obj)->value)); + return Value(TRY(Int64::create(arena, (PodInt64*)obj))); case Tag::Float: - return Value(Int64(((PodFloat*)obj)->value)); + return Value(TRY(Float::create(arena, (PodFloat*)obj))); case Tag::String: return Value(TRY(String::create(arena, (PodString*)obj))); case Tag::Symbol: @@ -37,8 +39,12 @@ Result syntax_unwrap(Arena& arena, Value& val) { Result Nil::copy(Arena& arena) { return Value(Nil()); } -Result Int64::copy(Arena& arena) { return Value(Int64(_value)); } -Result Float::copy(Arena& arena) { return Value(Float(_value)); } +Result Int64::copy(Arena& arena) { + return Value(Int64(TRY(_value.copy(arena)))); +} +Result Float::copy(Arena& arena) { + return Value(Float(TRY(_value.copy(arena)))); +} Result String::copy(Arena& arena) { return Value(String(TRY(_value.copy(arena)))); @@ -55,3 +61,37 @@ Result Syntax::copy(Arena& arena) { Result Pair::copy(Arena& arena) { return Value(Pair(TRY(_value.copy(arena)))); } + +Result Pair::create(Arena& arena, Value& first, Value& rest) { + auto pod = TRY(arena.alloc()); + pod->first = OffPtr(pod, first.pod()); + pod->rest = OffPtr(pod, rest.pod()); + + return Pair(TRY(MkGcRoot(pod, arena))); +} + +Result Pair::first(Arena& arena) { + auto val = _value->first.get(pod()); + return Value::create(arena, val); +} +Result Pair::rest(Arena& arena) { + auto val = _value->rest.get(pod()); + return Value::create(arena, val); +} + +Result reverse(Arena& arena, Value& val) { + if (!val.is()) return ErrorCode::TypeMismatch; + + auto res = Value(TRY(Nil::create(arena))); + auto cur = TRY(val.copy(arena)); + + while (!cur.is()) { + if (!cur.is()) return ErrorCode::TypeMismatch; + Pair& pair = *cur.to(); + Value first = TRY(pair.first(arena)); + cur = TRY(pair.rest(arena)); + res = TRY(Pair::create(arena, first, res)); + } + + return res; +} diff --git a/src/common.hpp b/src/common.hpp index 8721a15..87206b4 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -12,75 +12,35 @@ class Value; -struct SourcePosition { - size_t line{1}; - size_t column{1}; - size_t offset{0}; -}; - -struct SourceRange { - SourcePosition start; - SourcePosition end; -}; - -class PodInt64 final : public PodObject { - public: - PodInt64() : PodObject(Tag::Int64){}; - - int64_t value; -}; - -class PodFloat final : public PodObject { - public: - PodFloat() : PodObject(Tag::Float){}; - - double value; -}; - -class PodString final : public PodObject { - public: - PodString() : PodObject(Tag::String){}; - - uint64_t size; - char32_t data[]; -}; - -class PodSymbol final : public PodObject { - public: - PodSymbol() : PodObject(Tag::Symbol){}; - - uint64_t size; - char32_t data[]; -}; - -class PodSyntax : public PodObject { - public: - PodSyntax() : PodObject(Tag::Syntax){}; - OffPtr filename; - OffPtr modulename; - OffPtr expression; - SourceRange sourcerange; -}; - -class PodPair : public PodObject { - public: - PodPair() : PodObject(Tag::Pair){}; - OffPtr first; - OffPtr second; -}; - class Object { public: virtual Tag tag() = 0; virtual Result copy(Arena& arena) = 0; + virtual PodObject* pod() = 0; }; class Nil : public Object { public: Nil() {} + Nil(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Nil; } + virtual PodObject* pod() final { return _value.get(); } + + static Result create(Arena& arena, PodNil* obj) { + return Nil(TRY(MkGcRoot(obj, arena))); + } + + static Result create(Arena& arena) { + auto pod = TRY(arena.alloc()); + + return Nil(TRY(MkGcRoot(pod, arena))); + } + virtual Result copy(Arena& arena) final; + + private: + GcRoot _value; }; class String : public Object { @@ -88,6 +48,7 @@ class String : public Object { String() {} String(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::String; } + virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodString* obj) { return String(TRY(MkGcRoot(obj, arena))); @@ -129,6 +90,7 @@ class Symbol : public Object { Symbol() {} Symbol(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Symbol; } + virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodSymbol* obj) { return Symbol(TRY(MkGcRoot(obj, arena))); @@ -154,6 +116,7 @@ class Syntax : public Object { Syntax(GcRoot&& val) : _value(std::move(val)) {} Syntax(String filename, String modulename, Value expression); virtual Tag tag() final { return Tag::Syntax; } + virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodSyntax* obj) { return Syntax(TRY(MkGcRoot(obj, arena))); @@ -172,12 +135,15 @@ class Pair : public Object { Pair() {} Pair(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Pair; } + virtual PodObject* pod() final { return _value.get(); } static Result create(Arena& arena, PodPair* obj) { return Pair(TRY(MkGcRoot(obj, arena))); } + static Result create(Arena& arena, Value& first, Value& rest); - static Result first(Arena& arena); + Result first(Arena& arena); + Result rest(Arena& arena); virtual Result copy(Arena& arena) final; @@ -187,34 +153,54 @@ class Pair : public Object { class Int64 : public Object { public: - Int64() : _value(0) {} - Int64(int64_t val) : _value(val) {} - virtual ~Int64() = default; - + Int64() {} + Int64(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Int64; } + virtual PodObject* pod() final { return _value.get(); } - int64_t value() { return _value; } + static Result create(Arena& arena, PodInt64* obj) { + return Int64(TRY(MkGcRoot(obj, arena))); + } + + static Result create(Arena& arena, double val) { + auto pod = TRY(arena.alloc()); + pod->value = val; + + return Int64(TRY(MkGcRoot(pod, arena))); + } + + int64_t value() { return _value->value; } virtual Result copy(Arena& arena) final; private: - int64_t _value; + GcRoot _value; }; class Float : public Object { public: - Float() : _value(0) {} - Float(double val) : _value(val) {} - virtual ~Float() = default; - + Float() {} + Float(GcRoot&& val) : _value(std::move(val)) {} virtual Tag tag() final { return Tag::Float; } + virtual PodObject* pod() final { return _value.get(); } - double value() { return _value; } + static Result create(Arena& arena, PodFloat* obj) { + return Float(TRY(MkGcRoot(obj, arena))); + } + + static Result create(Arena& arena, double val) { + auto pod = TRY(arena.alloc()); + pod->value = val; + + return Float(TRY(MkGcRoot(pod, arena))); + } + + double value() { return _value->value; } virtual Result copy(Arena& arena) final; private: - double _value; + GcRoot _value; }; // note: this class doesn't perform proper destruction of objects in some cases @@ -235,6 +221,12 @@ class Value { new (buf) T(std::move(obj)); } + Value& operator=(Value&& val) { + memcpy(buf, val.buf, 24); + new (val.buf) Nil(); + return *this; + } + static Result create(Arena& arena, PodObject* obj); template @@ -247,6 +239,8 @@ class Value { return dynamic_cast((Object*)buf); } + PodObject* pod() { return ((Object*)buf)->pod(); } + Object& operator*() { return *(Object*)(buf); } Object* operator->() { return (Object*)(buf); } @@ -257,3 +251,5 @@ class Value { }; Result syntax_unwrap(Value& val); + +Result reverse(Arena& arena, Value& val); diff --git a/src/error.hpp b/src/error.hpp index 294cf77..c09caa2 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -3,6 +3,7 @@ enum class ErrorCode { Success, OutOfMemory, - IndexOutOfRange - + IndexOutOfRange, + TypeMismatch, + ReadError }; diff --git a/src/pod.hpp b/src/pod.hpp index a276bf8..a64a05c 100644 --- a/src/pod.hpp +++ b/src/pod.hpp @@ -2,6 +2,9 @@ #include +#include "result.hpp" +#include "sourcerange.hpp" + enum class Tag : uint8_t { Nil, Int64, @@ -43,3 +46,78 @@ static_assert(sizeof(PodHeader) == 8); struct PodObject { PodHeader header; }; + +class PodNil final : public PodObject { + public: + PodNil() : PodObject(Tag::Nil){}; +}; + +class PodInt64 final : public PodObject { + public: + PodInt64() : PodObject(Tag::Int64){}; + + int64_t value; +}; + +class PodFloat final : public PodObject { + public: + PodFloat() : PodObject(Tag::Float){}; + + double value; +}; + +class PodString final : public PodObject { + public: + PodString() : PodObject(Tag::String){}; + + uint64_t size; + char32_t data[]; +}; + +class PodSymbol final : public PodObject { + public: + PodSymbol() : PodObject(Tag::Symbol){}; + + uint64_t size; + char32_t data[]; +}; + +class PodSyntax : public PodObject { + public: + PodSyntax() : PodObject(Tag::Syntax){}; + OffPtr filename; + OffPtr modulename; + OffPtr expression; + SourceRange sourcerange; +}; + +class PodPair : public PodObject { + public: + PodPair() : PodObject(Tag::Pair){}; + OffPtr first; + OffPtr rest; +}; + +template +class Ptr { + public: + Ptr() : _ptr(0) {} + Ptr(T* ptr) : _ptr(ptr){}; + + T* get() { return _ptr; } + T& operator*() { return *_ptr; } + T* operator->() { return _ptr; } + + Result get_int() { + if (_ptr->tag != Tag::Int64) return ErrorCode::TypeMismatch; + return ((PodInt64*)_ptr)->value; + } + + Result get_float() { + if (_ptr->tag != Tag::Float) return ErrorCode::TypeMismatch; + return ((PodFloat*)_ptr)->value; + } + + private: + T* _ptr; +}; diff --git a/src/reader.cpp b/src/reader.cpp new file mode 100644 index 0000000..83c8ca9 --- /dev/null +++ b/src/reader.cpp @@ -0,0 +1,85 @@ +#include "reader.hpp" + +#include "common.hpp" + +static bool is_digit(char32_t c) { return c >= '0' && c <= '9'; } +static bool is_alpha(char32_t c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +static bool is_hex_digit(char32_t c) { + return is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static bool is_symbol_char(char32_t c) { + static char valid_char[] = {'!', '$', '%', '&', '*', '+', '-', '.', '/', + ':', '<', '=', '>', '?', '@', '^', '_', '~'}; + + if (is_digit(c)) return true; + if (is_alpha(c)) return true; + + for (size_t i = 0; i < sizeof(valid_char); ++i) { + if (char32_t(valid_char[i]) == c) return true; + } + return false; +} + +static bool is_whitespace(char32_t c) { + return c == ' ' || c == '\t' || c == '\v' || c == '\f'; +} + +static bool is_brace(char32_t c) { + return c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}'; +} + +static bool is_newline(char32_t c) { return c == '\r' || c == '\n'; } + +static bool is_separator(char32_t c) { + return is_whitespace(c) || is_brace(c) || is_newline(c) || c == ';'; +} + +#define EOS 0 + +Result Reader::read_one() { + forward_whitespace(); + + auto saved_position = position_; + if (is_numeric_start()) { + auto res = read_number(); + if (res.has_value()) return res; + } else if (match("true") || match("false")) { + auto res = read_bool(); + if (res.has_value()) return res; + } else if (is_string_start()) { + return read_string(); + } else if (match('(')) { + return read_list(); + } else if (match('[')) { + return read_array(); + } else if (match('{')) { + return read_dict(); + } + + position_ = saved_position; + if (is_symbol_start()) { + return read_symbol(); + } + + return ErrorCode::ReadError; +} + +Result Reader::read_multiple() { + Value res = TRY(Nil::create(_arena)); + + while (1) { + forward_whitespace(); + if (is_eof()) { + return reverse(_arena, res); + } + + auto val = TRY(read_one()); + res = Value(TRY(Pair::create(_arena, val, res))); + } + + return ErrorCode::ReadError; +} diff --git a/src/reader.hpp b/src/reader.hpp new file mode 100644 index 0000000..d4a2229 --- /dev/null +++ b/src/reader.hpp @@ -0,0 +1,44 @@ +#pragma once +#include "common.hpp" +#include "result.hpp" +#include "sourcerange.hpp" + +class Reader { + public: + Reader(Arena& arena, String&& str) : _arena(arena), _str(std::move(str)) {} + + Result read_one(); + Result read_multiple(); + + private: + void forward(); + void forward(size_t n); + bool forward_exponent(); + bool forward_decimal_number(); + bool forward_hex_number(); + void forward_whitespace(); + + bool is_eol(); + bool is_eof(); + bool is_whitespace(); + bool is_comment_start(); + bool is_numeric_start(); + bool is_symbol_start(); + bool is_string_start(); + + Result read_list(); + Result read_string(); + Result read_array(); + Result read_dict(); + Result read_number(); + Result read_symbol(); + Result read_bool(); + + char32_t get(size_t offset = 0); + bool match(const char* str); + bool match(char c); + + Arena& _arena; + String _str; + SourcePosition position_{1, 1, 0}; +}; diff --git a/src/sourcerange.hpp b/src/sourcerange.hpp new file mode 100644 index 0000000..6478e70 --- /dev/null +++ b/src/sourcerange.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +struct SourcePosition { + size_t line{1}; + size_t column{1}; + size_t offset{0}; +}; + +struct SourceRange { + SourcePosition start; + SourcePosition end; +}; diff --git a/src/vli.cpp b/src/vli.cpp index 0432c38..258fa83 100644 --- a/src/vli.cpp +++ b/src/vli.cpp @@ -21,10 +21,10 @@ int main() { { auto s = DIEIF(String::create(arena, "foo")); - std::cout << "roout count: " << arena.root_count() << "\n"; + std::cout << "root count: " << arena.root_count() << "\n"; std::cout << "char: " << (char)DIEIF(s[2]) << "\n"; } - std::cout << "roout count: " << arena.root_count() << "\n"; + std::cout << "root count: " << arena.root_count() << "\n"; return 0; }