#include "writer.hpp" #include "common.hpp" #include "error.hpp" #include "opcode.hpp" #include "sourcerange.hpp" Result Writer::write_one(const Value& obj) { switch (obj.tag()) { case Tag::Nil: return write_nil(*obj.to()); case Tag::Int64: return write_int64(*obj.to()); case Tag::Float: return write_float(*obj.to()); case Tag::Bool: return write_bool(*obj.to()); case Tag::Array: return write_array(*obj.to()); case Tag::ByteArray: return write_bytearray(*obj.to()); case Tag::Dict: return write_dict(*obj.to()); case Tag::String: return write_string(*obj.to()); case Tag::Symbol: return write_symbol(*obj.to()); case Tag::SrcLoc: return write_srcloc(*obj.to()); case Tag::Syntax: return write_syntax(*obj.to()); case Tag::Pair: return write_pair(*obj.to()); case Tag::Opcode: return write_opcode(*obj.to()); case Tag::Function: return write_function(*obj.to()); case Tag::StdlibFunction: return write_stdlib_function(*obj.to()); case Tag::Module: return write_module(*obj.to()); case Tag::StackFrame: return write_stack(*obj.to()); case Tag::Error: return write_error(*obj.to()); case Tag::Continuation: return write_continuation(*obj.to()); case Tag::Task: return write_task(*obj.to()); case Tag::TaskResult: return write_task_result(*obj.to()); }; return String(); } Result Writer::write_multiple(const Value& val) { String res = TRY(String::create("")); Value cur = TRY(val.copy()); bool is_first = true; while (!cur.is()) { if (!cur.is()) return ERROR(MalformedList); Pair& pair = *cur.to(); Value first = TRY(pair.first()); if (!is_first) res = TRY(res.concat("\n")); String first_str = TRY(write_one(first)); res = TRY(res.concat(first_str)); cur = TRY(pair.rest()); is_first = false; } res = TRY(res.concat("")); return res; } Result Writer::write_int64(const Int64& val) { char tmp[32]; sprintf(tmp, "%ld", val.value()); size_t len = strlen(tmp); return String::create(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 Writer::write_float(const 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(tmp); } Result Writer::write_nil(const Nil& val) { return String::create("nil"); } Result Writer::write_bool(const Bool& val) { if (val.value()) return String::create("true"); return String::create("false"); } Result Writer::write_bytearray(const ByteArray& val) { return ERROR(NotImplemented); } Result Writer::write_string(const String& val) { String res = TRY(String::create("\"")); auto size = TRY(val.size()); // TODO: optimize this for (uint64_t i = 0; i < 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(replace)); } else { res = TRY(res.concat(&c, 1)); } } res = TRY(res.concat("\"")); 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 Writer::write_symbol(const Symbol& val) { String res = TRY(String::create("")); auto size = TRY(val.size()); // TODO: optimize this for (uint64_t i = 0; i < size; i++) { char32_t c = TRY(val[i]); if (!is_valid_symbol_char(c)) return ERROR(InvalidSymbol); res = TRY(res.concat(&c, 1)); } return res; } Result Writer::write_srcloc(const SrcLoc& val) { char buf[1024]; String res = TRY(String::create("#")); return res; } Result Writer::write_syntax(const Syntax& val) { auto res = TRY(String::create("#")); return res; } Result Writer::write_pair(const Pair& val) { String res = TRY(String::create("(")); Value cur = TRY(val.copy_value()); bool is_first = true; while (!cur.is()) { if (!cur.is()) return ERROR(MalformedList); Pair& pair = *cur.to(); Value first = TRY(pair.first()); if (!is_first) res = TRY(res.concat(" ")); String first_str = TRY(write_one(first)); res = TRY(res.concat(first_str)); cur = TRY(pair.rest()); is_first = false; } res = TRY(res.concat(")")); return res; } Result Writer::write_array(const Array& val) { String res = TRY(String::create("[")); bool is_first = true; auto size = TRY(val.size()); for (uint64_t i = 0; i < size; i++) { Value cur = TRY(val.get(i)); if (!is_first) res = TRY(res.concat(" ")); String first_str = TRY(write_one(cur)); res = TRY(res.concat(first_str)); is_first = false; } res = TRY(res.concat("]")); return res; } Result Writer::write_dict(const Dict& val) { String res = TRY(String::create("{")); bool is_first = true; auto size = TRY(val.size()); for (uint64_t i = 0; i < size; i++) { Value k = TRY(Value::create(val._value->data[i * 2].get())); Value v = TRY(Value::create(val._value->data[i * 2 + 1].get())); if (!is_first) res = TRY(res.concat(" ")); String first_str = TRY(write_one(k)); res = TRY(res.concat(first_str)); res = TRY(res.concat(" ")); String second_str = TRY(write_one(v)); res = TRY(res.concat(second_str)); is_first = false; } res = TRY(res.concat("}")); return res; } Result Writer::write_opcode(const Opcode& val) { String res = TRY(String::create("#")); return res; } Result Writer::write_function(const Function& val) { auto name = TRY(val.name()); if (name.is()) { return TRY(String::create("#")); } if (!name.is()) return ERROR(TypeMismatch); String name_str = TRY(write_symbol(*name.to())); String res = TRY(String::create("#")); return res; } Result Writer::write_stdlib_function(const StdlibFunction& val) { auto name = TRY(val.name()); String name_str = TRY(write_symbol(name)); String res = TRY(String::create("#")); return res; } Result Writer::write_module(const Module& val) { auto name = TRY(val.name()); if (name.is()) { return TRY(String::create("#")); } if (!name.is()) return ERROR(TypeMismatch); String name_str = TRY(write_symbol(*name.to())); String res = TRY(String::create("#")); return res; } Result Writer::write_stack(const StackFrame& val) { return TRY(String::create("#")); } Result Writer::write_error(const Error& val) { auto res = TRY(String::create("#())); auto message = TRY(val.message()); auto message_str = TRY(write_one(message)); res = TRY(res.concat(name_str)); res = TRY(res.concat(" ")); res = TRY(res.concat(message_str)); res = TRY(res.concat(">")); return res; } Result Writer::write_continuation(const Continuation& val) { return TRY(String::create("#")); } Result Writer::write_task(const Task& val) { auto name = TRY(val.name()); String name_str = TRY(write_symbol(name)); String params_str = TRY(write_one(TRY(val.params()))); String res = TRY(String::create("#")); return res; } Result Writer::write_task_result(const TaskResult& val) { auto error = TRY(val.error()); auto result = TRY(val.result()); String res = TRY(String::create("#()) { res = TRY(res.concat(" :result ")); String s = TRY(write_one(result)); res = TRY(res.concat(s)); } else { res = TRY(res.concat(" :error ")); String s = TRY(write_one(error)); res = TRY(res.concat(s)); } res = TRY(res.concat(">")); return res; } Result write_one(const Value& value) { auto w = Writer(); return w.write_one(value); } Result write_multiple(const Value& value) { auto w = Writer(); return w.write_multiple(value); }