Browse Source

Work on csv-parse and lispy

master
Ludovic 'Archivist' Lagouardette 5 years ago
parent
commit
c14c3b6156
6 changed files with 539 additions and 1 deletions
  1. +2
    -0
      .gitignore
  2. +16
    -0
      .vscode/launch.json
  3. +63
    -0
      include/rigid_paradise/csv/csv-base.h
  4. +446
    -0
      include/rigid_paradise/lispy/lispy.hpp
  5. +1
    -1
      include/rigid_paradise/string.h
  6. +11
    -0
      src/csv-sheet/csv-parse.cpp

+ 2
- 0
.gitignore View File

@ -1 +1,3 @@
build/*
vgcore.*
a.out

+ 16
- 0
.vscode/launch.json View File

@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "gdb",
"request": "launch",
"target": "./a.out",
"cwd": "${workspaceRoot}",
"valuesFormatting": "parseText"
}
]
}

+ 63
- 0
include/rigid_paradise/csv/csv-base.h View File

@ -0,0 +1,63 @@
#pragma once
#include <vector>
#include <map>
#include <string>
#include <utility>
#include <iostream>
namespace csv {
struct cell_id {
size_t x,y;
bool operator<(const cell_id& oth) {
if (y < oth.y) return true;
if (x < oth.x) return true;
return false;
};
};
cell_id get_coords_from_id(const std::string_view id) {
size_t x = 0;
size_t y = 0;
auto c = id.begin();
while(*c < 'A' || *c > 'Z')
{
x += *c-'A';
x *= 26;
c++;
}
x /= 26;
while(*c < '0' || *c > '9')
{
y += *c-'0';
y *= 10;
c++;
}
y /= 10;
cell_id ret;
ret.x = x;
ret.y = y;
return ret;
}
class context;
class cell {
public:
std::string data = "";
mutable std::string computed_value = "";
mutable std::string display_value = "";
void eval(const context& ctx);
};
class context {
public:
std::map<cell_id, cell> data;
const cell& operator[] (const std::string_view id) const {
auto coords = get_coords_from_id(id);
return data[coords];
}
};
}

+ 446
- 0
include/rigid_paradise/lispy/lispy.hpp View File

@ -0,0 +1,446 @@
#pragma once
#include <variant>
#include <memory>
#include <vector>
#include <sstream>
#include <functional>
#include <cassert>
#include <iostream>
#include <iomanip>
#include <unordered_map>
#include <cstdlib>
#include <cmath>
namespace lispy {
class cons;
class function;
struct empty {};
struct cons_start{};
struct cons_end{};
struct atom {
int value;
};
struct sp_coords {
bool is_relative = false;
size_t x, y;
};
struct sp_range {
bool is_relative = false;
size_t x, y;
size_t width, height;
};
using lvalue = std::variant<int64_t, double, std::string, atom, empty, std::shared_ptr<cons>, sp_coords, sp_range, std::shared_ptr<function>>;
using token = std::variant<cons_start, cons_end, lvalue>;
struct context {
std::unordered_map<std::string, int> atoms;
int last_atom = 0;
bool error_crash = false;
int get_atom(const std::string& key)
{
if(atoms.count(key)) {
return atoms[key];
} else {
return atoms[key] = ++last_atom;
}
}
};
class cons {
public:
lvalue self = empty{};
std::unique_ptr<cons> other{};
cons()
{
self = empty{};
other = std::unique_ptr<cons>{};
}
cons(lvalue first)
: self(first)
, other()
{ }
cons(std::vector<lvalue> data)
{
if(data.size() == 0) {
self = empty{};
other = std::unique_ptr<cons>{};
} else if(data.size() >= 1) {
self = data[0];
for(auto it = data.begin()+1; it != data.end(); ++it)
this->append(*it);
}
}
cons(const cons& oth)
: self(oth.self)
, other(oth.other ? std::make_unique<cons>(*(oth.other)) : nullptr)
{}
void operator=(const cons& oth)
{
self = oth.self;
if(oth.other) {
other = std::make_unique<cons>(*oth.other);
} else {
other = std::unique_ptr<cons>{};
}
}
cons(cons&& oth)
: self(oth.self)
, other(oth.other ? std::move(std::make_unique<cons>(*(oth.other))) : std::unique_ptr<cons>{})
{}
void append(lvalue value)
{
if(!other) {
other = std::make_unique<cons>(value);
} else {
other->append(value);
}
}
};
class function {
public:
virtual lvalue operator() (cons arguments) = 0;
};
inline char hexdigit(char v)
{
if(v >= '0' && v<='9') {
return v - '0';
} else if(v >= 'a' && v <= 'f') {
return 10 + v - 'a';
} else if(v >= 'A' && v <= 'F') {
return 10 + v - 'A';
}
return -1;
}
inline std::string escape(std::string_view v)
{
auto it = v.begin();
std::stringstream stream;
stream<<'"';
while(it != v.end())
{
switch(*it)
{
case '"':
{
stream << "\\\"";
}
break;
case '\n':
{
stream << "\\n";
}
break;
case '\t':
{
stream << "\\t";
}
break;
case '\v':
{
stream << "\\v";
}
break;
case '\a':
{
stream << "\\a";
}
break;
default:
stream << *it;
}
++it;
}
stream<<'"';
return stream.str();
}
inline void print_visitor(std::ostream& stream, const lvalue& value, const context& ctx) {
std::visit([&](auto arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int64_t>) {
stream << arg;
} else if constexpr (std::is_same_v<T, double>) {
stream << arg;
} else if constexpr (std::is_same_v<T, empty>) {
stream << "()";
} else if constexpr (std::is_same_v<T, function>) {
stream << "#func"<<&*arg;
} else if constexpr (std::is_same_v<T, std::string>) {
stream << escape(arg);
} else if constexpr (std::is_same_v<T, std::shared_ptr<cons>>) {
stream << "(";
bool is_first = true;
cons p = *arg;
do{
if(!is_first)
{
p = *p.other;
}
print_visitor(stream, p.self, ctx);
if(p.other)
{
stream << " ";
}
is_first = false;
} while(p.other);
stream << ")";
}
else if constexpr (std::is_same_v<T, sp_coords>){
assert(false);
} else if constexpr (std::is_same_v<T, sp_range>){
assert(false);
} else if constexpr (std::is_same_v<T, atom>) {
for(auto& v : ctx.atoms)
{
if(v.second == arg.value)
{
stream << v.first;
return;
}
}
assert(false);
} else {
std::cerr << typeid(T).name() << " detected in print_visitor ?" << std::endl;
if(ctx.error_crash)
{
std::exit(-1);
}
}
}, value);
}
inline void print_types_visitor(std::ostream& stream, const lvalue& value, const context& ctx) {
std::visit([&](auto arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int64_t>) {
stream << "integer";
} else if constexpr (std::is_same_v<T, double>) {
stream << "double";
} else if constexpr (std::is_same_v<T, empty>) {
stream << "nil";
} else if constexpr (std::is_same_v<T, function>) {
stream << "function";
} else if constexpr (std::is_same_v<T, std::string>) {
stream << "string";
} else if constexpr (std::is_same_v<T, std::shared_ptr<cons>>){
stream << "(";
bool is_first = true;
cons p = *arg;
do{
if(!is_first)
{
p = *p.other;
}
print_types_visitor(stream, p.self, ctx);
if(p.other)
{
stream << " ";
}
is_first = false;
} while(p.other);
stream << ")";
} else if constexpr (std::is_same_v<T, sp_coords>){
stream << "coords";
} else if constexpr (std::is_same_v<T, sp_range>){
stream << "range";
} else if constexpr (std::is_same_v<T, atom>) {
stream << "atom";
} else {
std::cerr << typeid(T).name() << " detected in print_types_visitor ?" << std::endl;
if(ctx.error_crash)
{
std::exit(-1);
}
}
}, value);
}
inline std::pair<lvalue, std::string_view> parse_string(std::string_view data)
{
auto it = data.begin();
assert(*it == '\"');
++it;
std::stringstream value(std::string(data.begin(), data.end()));
std::string ret;
value >> std::quoted(ret);
return std::make_pair<lvalue, std::string_view>(ret, std::string_view{data.begin(), (size_t)value.rdbuf()->in_avail()});
}
inline std::pair<lvalue, std::string_view> parse_atom(std::string_view data, context& ctx)
{
assert(!iswspace(data[0]));
size_t idx = 1;
while(!iswspace(data[idx]))
{
idx++;
}
atom v;
v.value = ctx.get_atom(std::string(data.begin(), data.begin()+idx));
return std::make_pair(lvalue{v}, std::string_view{data.begin(), idx});
}
inline std::pair<lvalue, std::string_view> parse_number(std::string_view data)
{
char* end_f;
char* end_d;
double try_f = strtod (data.data(), &end_f);
int err_f = errno;
int64_t try_d = strtoll(data.data(), &end_d, 10);
int err_d = errno;
if(err_d == ERANGE)
{
return std::make_pair(lvalue{(double)try_f}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
}
if(try_f != std::trunc(try_f))
{
return std::make_pair(lvalue{(double)try_f}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
}
return std::make_pair(lvalue{int64_t(try_d)}, std::string_view{data.begin(), (size_t)(end_f-data.data())});
}
inline std::pair<lvalue, std::string_view> parse_selector(std::string_view data)
{
return std::make_pair(lvalue{}, std::string_view{data.begin(), 0});
}
inline size_t find_matching(const std::basic_string_view<token>& data, const size_t idx)
{
size_t try_idx = idx;
int mass = 1;
do{
try_idx++;
std::visit([&](auto arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, cons_start>) {
++mass;
} else if constexpr (std::is_same_v<T, cons_end>) {
--mass;
} else {}
}, data[try_idx]);
} while(mass != 0 && try_idx < data.size());
if(try_idx<data.size())
{
return try_idx;
}
return idx;
}
inline std::pair<size_t, lvalue> parse(const std::basic_string_view<token>& data, context& ctx)
{
auto ret = std::make_shared<cons>();
size_t sz = 0;
if(data.size() == 0)
{
return std::make_pair(0,(lvalue)empty{});
}
size_t skip = 0;
size_t idx = 0;
while(idx < data.size())
{
if(skip)
{
skip--;
++idx;
continue;
}
std::visit([&](const auto& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, cons_start>) {
auto matching = find_matching(data, idx);
auto res = parse(std::basic_string_view<token>{data.begin()+1, matching-idx-1}, ctx);
ret->append(res.second);
skip = matching - idx;
++sz;
} else if constexpr (std::is_same_v<T, cons_end>) {
std::cerr << typeid(T).name() << " mismatched parenthesis" << std::endl;
} else if constexpr (std::is_same_v<T, lvalue>) {
ret->append(arg);
++sz;
} else {
std::cerr << typeid(T).name() << " cat in the parser ?" << std::endl;
if(ctx.error_crash)
{
std::exit(-1);
}
}
}, data[idx]);
++idx;
}
return std::make_pair(sz, (lvalue)(std::make_shared<cons>(*ret->other)));
}
inline std::vector<token> lex(const std::string_view data, context& ctx)
{
std::vector<token> ret;
auto it = data.begin();
bool is_done = false;
do{
if (it == data.end()) {
is_done = true;
} else if(isdigit(*it) || (*it == '-' && isdigit(*(it+1)))) {
auto value = parse_number(std::string_view{it, (size_t)(data.end() - it)});
ret.push_back(value.first);
it += value.second.size()+1;
} else if(*it == '\"') {
auto value = parse_string(std::string_view{it, (size_t)(data.end() - it)});
ret.push_back(value.first);
size_t forward_jump = std::string_view{it, (size_t)(data.end() - it)}.size()-value.second.size();
it += forward_jump;
} else if (*it == '(') {
ret.push_back(cons_start{});
++it;
} else if (*it == ')') {
ret.push_back(cons_end{});
++it;
} else if (iswspace(*it)) {
++it;
} else if (*it == '$') {
auto value = parse_selector(std::string_view{it, (size_t)(data.end() - it)});
ret.push_back(value.first);
it += value.second.size()+1;
} else {
auto value = parse_atom(std::string_view{it, (size_t)(data.end() - it)}, ctx);
ret.push_back(value.first);
it += value.second.size();
}
}while(!is_done);
return ret;
}
inline lvalue eval(const std::string_view& data, context& ctx)
{
auto n = lex(data, ctx);
auto p = parse(std::basic_string_view<token>(n.data(), n.size()), ctx);
return p.second;
}
}

+ 1
- 1
include/rigid_paradise/string.h View File

@ -5,6 +5,6 @@
namespace cstring{
constexpr size_t strlen( const char* s ) noexcept
{
return *s ? 1 + strlen(s + 1) : 0;
return *s ? 1 + strlen(s + 1) : 0;
}
}

+ 11
- 0
src/csv-sheet/csv-parse.cpp View File

@ -0,0 +1,11 @@
#include "rigid_paradise/lispy/lispy.hpp"
#include <iostream>
int main() {
lispy::context ctx;
lispy::lvalue v = lispy::eval("cat 13 15.69 \"data \\ ひらがな \n\ttabulated\" \"\" \"test 2 \\x65\"", ctx);
lispy::print_types_visitor(std::cout, v, ctx);
std::cout << std::endl;
lispy::print_visitor(std::cout, v, ctx);
}

Loading…
Cancel
Save