mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 18:16:31 +00:00
107 lines
3.0 KiB
C++
107 lines
3.0 KiB
C++
|
#include "json.hpp"
|
||
|
#include <cstdlib>
|
||
|
#include <format>
|
||
|
#include <iostream>
|
||
|
#include <string>
|
||
|
#include <unordered_map>
|
||
|
|
||
|
using namespace sliger::json;
|
||
|
|
||
|
auto ident_tok_typs = std::unordered_map<std::string, TokTyp> {
|
||
|
{ "null", TokTyp::Null },
|
||
|
{ "false", TokTyp::False },
|
||
|
{ "true", TokTyp::True },
|
||
|
};
|
||
|
|
||
|
auto id_start_chars = "abcdefghijklmnopqrstuvwxyz"
|
||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_";
|
||
|
|
||
|
auto id_tail_chars = "abcdefghijklmnopqrstuvwxyz"
|
||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
|
"1234567890";
|
||
|
|
||
|
auto Lexer::next() -> Tok
|
||
|
{
|
||
|
if (done()) {
|
||
|
return TokTyp::Eof;
|
||
|
}
|
||
|
auto pos = this->pos();
|
||
|
if (test('"')) {
|
||
|
step();
|
||
|
auto value = std::string();
|
||
|
while (!done() and !test('"')) {
|
||
|
if (cur() == '\\') {
|
||
|
step();
|
||
|
if (done())
|
||
|
break;
|
||
|
value.push_back([&] {
|
||
|
char ch = cur();
|
||
|
switch (ch) {
|
||
|
case 'n':
|
||
|
return '\n';
|
||
|
case 'r':
|
||
|
return '\r';
|
||
|
case 't':
|
||
|
return '\t';
|
||
|
case '0':
|
||
|
return '\0';
|
||
|
default:
|
||
|
return ch;
|
||
|
}
|
||
|
}());
|
||
|
} else {
|
||
|
value.push_back(cur());
|
||
|
}
|
||
|
step();
|
||
|
}
|
||
|
}
|
||
|
auto step_n_ret = [&](auto tok) {
|
||
|
step();
|
||
|
return tok;
|
||
|
};
|
||
|
switch (cur()) {
|
||
|
case '0':
|
||
|
return step_n_ret(Tok(TokTyp::Float, 0.0));
|
||
|
case '{':
|
||
|
return step_n_ret(TokTyp::LBrace);
|
||
|
case '}':
|
||
|
return step_n_ret(TokTyp::RBrace);
|
||
|
case '[':
|
||
|
return step_n_ret(TokTyp::LBracket);
|
||
|
case ']':
|
||
|
return step_n_ret(TokTyp::RBracket);
|
||
|
case ',':
|
||
|
return step_n_ret(TokTyp::Comma);
|
||
|
case ':':
|
||
|
return step_n_ret(TokTyp::Colon);
|
||
|
}
|
||
|
if (test_in(id_start_chars)) {
|
||
|
auto value = std::string();
|
||
|
while (test_in(id_tail_chars)) {
|
||
|
value.push_back(cur());
|
||
|
step();
|
||
|
}
|
||
|
if (ident_tok_typs.find(value) == ident_tok_typs.end()) {
|
||
|
std::cerr << std::format("sliger::json::Lexer error: unknown "
|
||
|
"identifier \"{}\" at {}:{}",
|
||
|
value, pos.col, pos.line);
|
||
|
return TokTyp::Error;
|
||
|
}
|
||
|
return ident_tok_typs.at(value);
|
||
|
}
|
||
|
if (test_in("123456789")) {
|
||
|
auto value_str = std::string();
|
||
|
while (test_in("1234567890")) {
|
||
|
value_str.push_back(cur());
|
||
|
step();
|
||
|
}
|
||
|
auto value = std::atof(value_str.c_str());
|
||
|
return Tok(TokTyp::Float, value);
|
||
|
}
|
||
|
std::cerr << std::format(
|
||
|
"sliger::json::Lexer error: unknown character '{}' at {}:{}", cur(),
|
||
|
this->line, this->col);
|
||
|
step();
|
||
|
return TokTyp::Error;
|
||
|
}
|