valeri/src/writer.cpp

227 lines
5.3 KiB
C++
Raw Normal View History

2024-07-28 16:54:04 +00:00
#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::Array:
return write_array(*obj.to<Array>());
2024-07-28 16:54:04 +00:00
case Tag::ByteArray:
return write_bytearray(*obj.to<ByteArray>());
case Tag::Dict:
return write_dict(*obj.to<Dict>());
2024-07-28 16:54:04 +00:00
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>());
2024-08-10 17:24:16 +00:00
case Tag::Opcode:
return write_opcode(*obj.to<Opcode>());
2024-07-28 16:54:04 +00:00
};
return String();
}
Result<String> Writer::write_int64(Int64& val) {
char tmp[32];
2024-07-28 23:14:30 +00:00
sprintf(tmp, "%lu", val.value());
2024-07-28 16:54:04 +00:00
size_t len = strlen(tmp);
2024-08-09 22:45:06 +00:00
return String::create(tmp);
2024-07-28 16:54:04 +00:00
}
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;
}
2024-08-09 22:45:06 +00:00
return String::create(tmp);
2024-07-28 16:54:04 +00:00
}
2024-08-09 22:45:06 +00:00
Result<String> Writer::write_nil(Nil& val) { return String::create("nil"); }
2024-07-28 16:54:04 +00:00
Result<String> Writer::write_bool(Bool& val) {
2024-08-09 22:45:06 +00:00
if (val.value()) return String::create("true");
2024-07-28 16:54:04 +00:00
2024-08-09 22:45:06 +00:00
return String::create("false");
2024-07-28 16:54:04 +00:00
}
Result<String> Writer::write_bytearray(ByteArray& val) {
2024-08-10 10:17:20 +00:00
return ERROR(NotImplemented);
2024-07-28 16:54:04 +00:00
}
Result<String> Writer::write_string(String& val) {
2024-08-09 22:45:06 +00:00
String res = TRY(String::create("\""));
2024-07-28 16:54:04 +00:00
// 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) {
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(replace));
2024-07-28 16:54:04 +00:00
} else {
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(&c, 1));
2024-07-28 16:54:04 +00:00
}
}
2024-08-09 22:45:06 +00:00
res = TRY(res.concat("\""));
2024-07-28 16:54:04 +00:00
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) {
2024-08-09 22:45:06 +00:00
String res = TRY(String::create(""));
2024-07-28 16:54:04 +00:00
// TODO: optimize this
for (uint64_t i = 0; i < val.size(); i++) {
char32_t c = TRY(val[i]);
2024-08-10 10:17:20 +00:00
if (!is_valid_symbol_char(c)) return ERROR(InvalidSymbol);
2024-07-28 16:54:04 +00:00
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(&c, 1));
2024-07-28 16:54:04 +00:00
}
return res;
}
Result<String> Writer::write_syntax(Syntax& val) {
2024-08-10 10:17:20 +00:00
return ERROR(NotImplemented);
2024-07-28 16:54:04 +00:00
}
Result<String> Writer::write_pair(Pair& val) {
2024-08-09 22:45:06 +00:00
String res = TRY(String::create("("));
2024-07-28 16:54:04 +00:00
2024-08-09 22:45:06 +00:00
Value cur = TRY(val.copy());
2024-07-28 16:54:04 +00:00
bool is_first = true;
while (!cur.is<Nil>()) {
2024-08-10 10:17:20 +00:00
if (!cur.is<Pair>()) return ERROR(MalformedList);
2024-07-28 16:54:04 +00:00
Pair& pair = *cur.to<Pair>();
2024-08-09 22:45:06 +00:00
Value first = TRY(pair.first());
if (!is_first) res = TRY(res.concat(" "));
2024-07-28 16:54:04 +00:00
String first_str = TRY(write_one(first));
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(first_str));
2024-07-28 16:54:04 +00:00
2024-08-09 22:45:06 +00:00
cur = TRY(pair.rest());
2024-07-28 23:14:30 +00:00
is_first = false;
2024-07-28 16:54:04 +00:00
}
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(")"));
2024-07-28 16:54:04 +00:00
return res;
}
Result<String> Writer::write_array(Array& val) {
2024-08-09 22:45:06 +00:00
String res = TRY(String::create("["));
bool is_first = true;
for (uint64_t i = 0; i < val.size(); i++) {
2024-08-09 22:45:06 +00:00
Value cur = TRY(val.get(i));
2024-08-09 22:45:06 +00:00
if (!is_first) res = TRY(res.concat(" "));
String first_str = TRY(write_one(cur));
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(first_str));
is_first = false;
}
2024-08-09 22:45:06 +00:00
res = TRY(res.concat("]"));
return res;
}
Result<String> Writer::write_dict(Dict& val) {
2024-08-09 22:45:06 +00:00
String res = TRY(String::create("{"));
2024-08-01 21:45:16 +00:00
bool is_first = true;
for (uint64_t i = 0; i < val.size(); i++) {
2024-08-09 22:45:06 +00:00
Value k = TRY(Value::create(val._value->data[i * 2].get()));
Value v = TRY(Value::create(val._value->data[i * 2 + 1].get()));
2024-08-01 21:45:16 +00:00
2024-08-09 22:45:06 +00:00
if (!is_first) res = TRY(res.concat(" "));
2024-08-01 21:45:16 +00:00
String first_str = TRY(write_one(k));
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(first_str));
2024-08-01 21:45:16 +00:00
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(" "));
2024-08-01 21:45:16 +00:00
String second_str = TRY(write_one(v));
2024-08-09 22:45:06 +00:00
res = TRY(res.concat(second_str));
2024-08-01 21:45:16 +00:00
is_first = false;
}
2024-08-09 22:45:06 +00:00
res = TRY(res.concat("}"));
2024-08-01 21:45:16 +00:00
return res;
}
2024-08-02 22:27:36 +00:00
2024-08-10 17:24:16 +00:00
Result<String> Writer::write_opcode(Opcode& val) {
String res = TRY(String::create("#<opcode>"));
return res;
2024-08-10 17:24:16 +00:00
}
2024-08-09 22:45:06 +00:00
Result<String> write_one(Value& value) {
auto w = Writer();
2024-08-02 22:27:36 +00:00
return w.write_one(value);
}