Implement basic writer
This commit is contained in:
parent
220adaace9
commit
ba433dafe9
6 changed files with 210 additions and 1 deletions
|
@ -15,6 +15,7 @@ target_sources(vm_lib
|
||||||
src/common.cpp
|
src/common.cpp
|
||||||
src/arena.cpp
|
src/arena.cpp
|
||||||
src/reader.cpp
|
src/reader.cpp
|
||||||
|
src/writer.cpp
|
||||||
src/utf8.cpp
|
src/utf8.cpp
|
||||||
|
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
@ -29,6 +30,7 @@ target_sources(vm_lib
|
||||||
src/vm.hpp
|
src/vm.hpp
|
||||||
src/sourcerange.hpp
|
src/sourcerange.hpp
|
||||||
src/reader.hpp
|
src/reader.hpp
|
||||||
|
src/writer.hpp
|
||||||
src/utf8.hpp
|
src/utf8.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,13 @@ class Symbol : public Object {
|
||||||
static Result<Symbol> create(Arena& arena, String& rhs);
|
static Result<Symbol> create(Arena& arena, String& rhs);
|
||||||
virtual Result<Value> copy(Arena& arena) final;
|
virtual Result<Value> copy(Arena& arena) final;
|
||||||
|
|
||||||
|
uint64_t size() { return _value->size; }
|
||||||
|
|
||||||
|
Result<char32_t> operator[](uint64_t idx) {
|
||||||
|
if (idx >= _value->size) return ErrorCode::IndexOutOfRange;
|
||||||
|
return _value->data[idx];
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GcRoot<PodSymbol> _value;
|
GcRoot<PodSymbol> _value;
|
||||||
};
|
};
|
||||||
|
@ -434,6 +441,7 @@ class Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
PodObject* pod() { return ((Object*)buf)->pod(); }
|
PodObject* pod() { return ((Object*)buf)->pod(); }
|
||||||
|
Tag tag() { return ((Object*)buf)->tag(); }
|
||||||
|
|
||||||
Object& operator*() { return *(Object*)(buf); }
|
Object& operator*() { return *(Object*)(buf); }
|
||||||
Object* operator->() { return (Object*)(buf); }
|
Object* operator->() { return (Object*)(buf); }
|
||||||
|
|
|
@ -7,5 +7,8 @@ enum class ErrorCode {
|
||||||
TypeMismatch,
|
TypeMismatch,
|
||||||
ReadError,
|
ReadError,
|
||||||
UnterminatedStringLiteral,
|
UnterminatedStringLiteral,
|
||||||
InvalidNumericLiteral
|
InvalidNumericLiteral,
|
||||||
|
NotImplemented,
|
||||||
|
InvalidSymbol,
|
||||||
|
MalformedList,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "arena.hpp"
|
#include "arena.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "reader.hpp"
|
#include "reader.hpp"
|
||||||
|
#include "writer.hpp"
|
||||||
|
|
||||||
StaticArena<64 * 1024 * 1024> arena;
|
StaticArena<64 * 1024 * 1024> arena;
|
||||||
|
|
||||||
|
@ -31,5 +32,9 @@ int main() {
|
||||||
auto reader = Reader(arena, s);
|
auto reader = Reader(arena, s);
|
||||||
|
|
||||||
auto r = DIEIF(reader.read_one());
|
auto r = DIEIF(reader.read_one());
|
||||||
|
|
||||||
|
auto writer = Writer(arena);
|
||||||
|
auto s2 = DIEIF(writer.write_one(r));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
166
src/writer.cpp
Normal file
166
src/writer.cpp
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include "writer.hpp"
|
||||||
|
|
||||||
|
Result<String> Writer::write_one(Value& obj) {
|
||||||
|
switch (obj.tag()) {
|
||||||
|
case Tag::Nil:
|
||||||
|
return write_nil(*obj.to<Nil>());
|
||||||
|
case Tag::Int64:
|
||||||
|
return write_int64(*obj.to<Int64>());
|
||||||
|
case Tag::Float:
|
||||||
|
return write_float(*obj.to<Float>());
|
||||||
|
case Tag::Bool:
|
||||||
|
return write_bool(*obj.to<Bool>());
|
||||||
|
case Tag::ByteArray:
|
||||||
|
return write_bytearray(*obj.to<ByteArray>());
|
||||||
|
case Tag::String:
|
||||||
|
return write_string(*obj.to<String>());
|
||||||
|
case Tag::Symbol:
|
||||||
|
return write_symbol(*obj.to<Symbol>());
|
||||||
|
case Tag::Syntax:
|
||||||
|
return write_syntax(*obj.to<Syntax>());
|
||||||
|
case Tag::Pair:
|
||||||
|
return write_pair(*obj.to<Pair>());
|
||||||
|
};
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_int64(Int64& val) {
|
||||||
|
char tmp[32];
|
||||||
|
sprintf(tmp, "%luu64", val.value());
|
||||||
|
size_t len = strlen(tmp);
|
||||||
|
|
||||||
|
return String::create(_arena, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needs_dot(char* str) {
|
||||||
|
bool has_e = 0;
|
||||||
|
bool has_dot = 0;
|
||||||
|
for (char* c = str; *c != 0; c++) {
|
||||||
|
if (*c == 'e' || *c == 'E') has_e = true;
|
||||||
|
if (*c == '.') has_dot = true;
|
||||||
|
}
|
||||||
|
return !has_e && !has_dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_float(Float& val) {
|
||||||
|
char tmp[32];
|
||||||
|
sprintf(tmp, "%g", val.value());
|
||||||
|
size_t len = strlen(tmp);
|
||||||
|
|
||||||
|
if (needs_dot(tmp)) {
|
||||||
|
tmp[len] = '.';
|
||||||
|
tmp[len + 1] = '0';
|
||||||
|
tmp[len + 2] = 0;
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String::create(_arena, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_nil(Nil& val) {
|
||||||
|
return String::create(_arena, "nil");
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_bool(Bool& val) {
|
||||||
|
if (val.value()) return String::create(_arena, "true");
|
||||||
|
|
||||||
|
return String::create(_arena, "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_bytearray(ByteArray& val) {
|
||||||
|
return ErrorCode::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_string(String& val) {
|
||||||
|
String res = TRY(String::create(_arena, "\""));
|
||||||
|
|
||||||
|
// TODO: optimize this
|
||||||
|
for (uint64_t i = 0; i < val.size(); i++) {
|
||||||
|
char32_t c = TRY(val[i]);
|
||||||
|
const char* replace = 0;
|
||||||
|
switch (c) {
|
||||||
|
case '\r':
|
||||||
|
replace = "\\r";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
replace = "\\n";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
replace = "\\t";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
replace = "\\\\";
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
replace = "\\\"";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (replace != 0) {
|
||||||
|
res = TRY(res.concat(_arena, replace));
|
||||||
|
} else {
|
||||||
|
res = TRY(res.concat(_arena, &c, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = TRY(res.concat(_arena, "\""));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_valid_symbol_char(char32_t codepoint) {
|
||||||
|
return ('a' <= codepoint && codepoint <= 'z') ||
|
||||||
|
('A' <= codepoint && codepoint <= 'Z') ||
|
||||||
|
('0' <= codepoint && codepoint <= '9') || codepoint == '!' ||
|
||||||
|
codepoint == '$' || codepoint == '%' || codepoint == '&' ||
|
||||||
|
codepoint == '*' || codepoint == '+' || codepoint == '-' ||
|
||||||
|
codepoint == '.' || codepoint == '/' || codepoint == ':' ||
|
||||||
|
codepoint == '<' || codepoint == '=' || codepoint == '>' ||
|
||||||
|
codepoint == '?' || codepoint == '@' || codepoint == '^' ||
|
||||||
|
codepoint == '_' || codepoint == '~';
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_symbol(Symbol& val) {
|
||||||
|
String res = TRY(String::create(_arena, ""));
|
||||||
|
|
||||||
|
// TODO: optimize this
|
||||||
|
for (uint64_t i = 0; i < val.size(); i++) {
|
||||||
|
char32_t c = TRY(val[i]);
|
||||||
|
|
||||||
|
if (!is_valid_symbol_char(c)) return ErrorCode::InvalidSymbol;
|
||||||
|
|
||||||
|
res = TRY(res.concat(_arena, &c, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_syntax(Syntax& val) {
|
||||||
|
return ErrorCode::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> Writer::write_pair(Pair& val) {
|
||||||
|
String res = TRY(String::create(_arena, "("));
|
||||||
|
|
||||||
|
Value cur = TRY(val.copy(_arena));
|
||||||
|
|
||||||
|
bool is_first = true;
|
||||||
|
while (!cur.is<Nil>()) {
|
||||||
|
if (!cur.is<Pair>()) return ErrorCode::MalformedList;
|
||||||
|
|
||||||
|
Pair& pair = *cur.to<Pair>();
|
||||||
|
|
||||||
|
Value first = TRY(pair.first(_arena));
|
||||||
|
if (!is_first) res = TRY(res.concat(_arena, " "));
|
||||||
|
|
||||||
|
String first_str = TRY(write_one(first));
|
||||||
|
res = TRY(res.concat(_arena, first_str));
|
||||||
|
|
||||||
|
cur = TRY(pair.rest(_arena));
|
||||||
|
}
|
||||||
|
|
||||||
|
res = TRY(res.concat(_arena, ")"));
|
||||||
|
return res;
|
||||||
|
}
|
25
src/writer.hpp
Normal file
25
src/writer.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "arena.hpp"
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
class Writer {
|
||||||
|
public:
|
||||||
|
Writer(Arena& arena) : _arena(arena){};
|
||||||
|
|
||||||
|
Result<String> write_one(Value& obj);
|
||||||
|
Result<String> write_multiple(Value& obj);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result<String> write_int64(Int64& val);
|
||||||
|
Result<String> write_float(Float& val);
|
||||||
|
Result<String> write_string(String& val);
|
||||||
|
Result<String> write_pair(Pair& val);
|
||||||
|
Result<String> write_nil(Nil& val);
|
||||||
|
Result<String> write_bool(Bool& val);
|
||||||
|
Result<String> write_bytearray(ByteArray& val);
|
||||||
|
Result<String> write_symbol(Symbol& val);
|
||||||
|
Result<String> write_syntax(Syntax& val);
|
||||||
|
|
||||||
|
Arena& _arena;
|
||||||
|
};
|
Loading…
Reference in a new issue