2024-07-27 15:25:44 +00:00
|
|
|
#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<Value> 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<Value> 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;
|
|
|
|
}
|
2024-07-27 18:40:13 +00:00
|
|
|
|
|
|
|
Result<Value> Reader::read_list() {
|
|
|
|
if (!match('(')) return ErrorCode::ReadError;
|
|
|
|
|
|
|
|
forward();
|
|
|
|
|
|
|
|
Value res = TRY(Nil::create(_arena));
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
forward_whitespace();
|
|
|
|
|
|
|
|
if (is_eof()) {
|
|
|
|
return ErrorCode::ReadError;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match(')')) {
|
|
|
|
forward();
|
|
|
|
return reverse(_arena, res);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto val = TRY(read_one());
|
|
|
|
|
|
|
|
res = Value(TRY(Pair::create(_arena, val, res)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return ErrorCode::ReadError;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<Value> Reader::read_bool() {
|
|
|
|
if (match("true")) {
|
|
|
|
forward(4);
|
|
|
|
if (!is_separator(get()) && !is_eof()) return ErrorCode::ReadError;
|
|
|
|
return Value(TRY(Bool::create(_arena, true)));
|
|
|
|
}
|
|
|
|
if (match("false")) {
|
|
|
|
forward(5);
|
|
|
|
if (!is_separator(get()) && !is_eof()) return ErrorCode::ReadError;
|
|
|
|
return Value(TRY(Bool::create(_arena, false)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return ErrorCode::ReadError;
|
|
|
|
}
|