From ceea8889580225bf73bd1912313e0a8a388fc440 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Sun, 11 Aug 2019 08:51:01 +0200 Subject: [PATCH] can evaluate integer operations in lispy --- include/rigid_paradise/csv/csv-base.h | 4 +- include/rigid_paradise/lispy/lispy.hpp | 252 +++++++++++++++++++++++-- src/csv-sheet/csv-parse.cpp | 3 +- 3 files changed, 237 insertions(+), 22 deletions(-) diff --git a/include/rigid_paradise/csv/csv-base.h b/include/rigid_paradise/csv/csv-base.h index 8a4dd06..e7bc326 100644 --- a/include/rigid_paradise/csv/csv-base.h +++ b/include/rigid_paradise/csv/csv-base.h @@ -54,10 +54,10 @@ namespace csv { public: std::map data; - const cell& operator[] (const std::string_view id) const { + /*const cell& operator[] (const std::string_view id) const { auto coords = get_coords_from_id(id); return data[coords]; - } + }*/ }; } \ No newline at end of file diff --git a/include/rigid_paradise/lispy/lispy.hpp b/include/rigid_paradise/lispy/lispy.hpp index 7b91a71..e9059b5 100644 --- a/include/rigid_paradise/lispy/lispy.hpp +++ b/include/rigid_paradise/lispy/lispy.hpp @@ -42,6 +42,8 @@ namespace lispy { std::unordered_map atoms; int last_atom = 0; bool error_crash = false; + std::unordered_map> function_table; + std::unordered_map variable_table; int get_atom(const std::string& key) { @@ -56,12 +58,12 @@ namespace lispy { class cons { public: lvalue self = empty{}; - std::unique_ptr other{}; + std::shared_ptr other{}; cons() { self = empty{}; - other = std::unique_ptr{}; + other = std::shared_ptr{}; } cons(lvalue first) @@ -73,7 +75,7 @@ namespace lispy { { if(data.size() == 0) { self = empty{}; - other = std::unique_ptr{}; + other = std::shared_ptr{}; } else if(data.size() >= 1) { self = data[0]; for(auto it = data.begin()+1; it != data.end(); ++it) @@ -83,27 +85,27 @@ namespace lispy { cons(const cons& oth) : self(oth.self) - , other(oth.other ? std::make_unique(*(oth.other)) : nullptr) + , other(oth.other ? std::make_shared(*(oth.other)) : nullptr) {} void operator=(const cons& oth) { self = oth.self; if(oth.other) { - other = std::make_unique(*oth.other); + other = std::make_shared(*oth.other); } else { - other = std::unique_ptr{}; + other = std::shared_ptr{}; } } cons(cons&& oth) : self(oth.self) - , other(oth.other ? std::move(std::make_unique(*(oth.other))) : std::unique_ptr{}) + , other(oth.other ? std::move(std::make_shared(*(oth.other))) : std::shared_ptr{}) {} void append(lvalue value) { if(!other) { - other = std::make_unique(value); + other = std::make_shared(value); } else { other->append(value); } @@ -112,7 +114,8 @@ namespace lispy { class function { public: - virtual lvalue operator() (cons arguments) = 0; + virtual lvalue operator() (const std::shared_ptr arguments, lispy::context& ctx) = 0; + virtual ~function(){}; }; inline char hexdigit(char v) @@ -179,7 +182,7 @@ namespace lispy { stream << arg; } else if constexpr (std::is_same_v) { stream << "()"; - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v>) { stream << "#func"<<&*arg; } else if constexpr (std::is_same_v) { stream << escape(arg); @@ -203,9 +206,9 @@ namespace lispy { stream << ")"; } else if constexpr (std::is_same_v){ - assert(false); + stream << (arg.is_relative ? "$[" : "@[") << arg.x << "," << arg.y << "]"; } else if constexpr (std::is_same_v){ - assert(false); + stream << (arg.is_relative ? "$[" : "@[") << arg.x << "," << arg.y << "," << arg.width << "," << arg.height << "]"; } else if constexpr (std::is_same_v) { for(auto& v : ctx.atoms) { @@ -235,7 +238,7 @@ namespace lispy { stream << "double"; } else if constexpr (std::is_same_v) { stream << "nil"; - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v>) { stream << "function"; } else if constexpr (std::is_same_v) { stream << "string"; @@ -319,9 +322,52 @@ namespace lispy { return std::make_pair(lvalue{int64_t(try_d)}, std::string_view{data.begin(), (size_t)(end_f-data.data())}); } + inline std::pair 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'+1; + x *= 26; + c++; + } + x /= 26; + while(*c >= '0' && *c <= '9') + { + y += *c-'0'; + y *= 10; + c++; + } + y /= 10; + sp_coords ret; + ret.x = x; + ret.y = y; + return std::make_pair((size_t)(c-id.begin()) ,ret); + } + inline std::pair parse_selector(std::string_view data) { - return std::make_pair(lvalue{}, std::string_view{data.begin(), 0}); + auto it = data.begin(); + auto is_rel = *it == '$'; + ++it; + auto a = get_coords_from_id(std::string_view{it, data.size()-1}); + a.second.is_relative = is_rel; + it += a.first; + if(*it == ':') + { + auto b = get_coords_from_id(std::string_view{++it, data.size()-1}); + it += b.first; + sp_range ret; + a.second.is_relative = is_rel; + ret.x = a.second.x; + ret.y = a.second.y; + ret.width = b.second.x; + ret.height = b.second.y; + return std::make_pair(lvalue{ret}, std::string_view{data.begin(), (size_t)(it - data.begin())}); + } else { + return std::make_pair(lvalue{a.second}, std::string_view{data.begin(), (size_t)(it - data.begin())}); + } } inline size_t find_matching(const std::basic_string_view& data, const size_t idx) @@ -375,9 +421,9 @@ namespace lispy { using T = std::decay_t; if constexpr (std::is_same_v) { auto matching = find_matching(data, idx); - auto res = parse(std::basic_string_view{data.begin()+1, matching-idx-1}, ctx); + auto res = parse(std::basic_string_view{data.begin()+idx+1, matching-idx-1}, ctx); ret->append(res.second); - skip = matching - idx; + skip = matching - idx + 1; ++sz; } else if constexpr (std::is_same_v) { std::cerr << typeid(T).name() << " mismatched parenthesis" << std::endl; @@ -409,7 +455,7 @@ namespace lispy { } 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; + it += value.second.size(); } else if(*it == '\"') { auto value = parse_string(std::string_view{it, (size_t)(data.end() - it)}); ret.push_back(value.first); @@ -423,7 +469,7 @@ namespace lispy { ++it; } else if (iswspace(*it)) { ++it; - } else if (*it == '$') { + } else if (*it == '$' || *it == '@') { auto value = parse_selector(std::string_view{it, (size_t)(data.end() - it)}); ret.push_back(value.first); it += value.second.size()+1; @@ -437,10 +483,178 @@ namespace lispy { return ret; } + inline lvalue eval(lvalue& data, context& ctx) + { + lvalue ret = empty{}; + std::visit([&](auto& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + auto it = arg; + auto evaluated = std::make_shared(); + auto iterated = evaluated; + + do{ + iterated->self = eval(it->self, ctx); + if(it->other) + { + iterated->other = std::make_shared(); + iterated = iterated->other; + } + it = it->other; + } while(it); + std::visit([&](auto arg) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + ret = (*arg)(evaluated->other, ctx); + } else { + ret = evaluated; + } + }, evaluated->self); + } else if constexpr (std::is_same_v) { + if(ctx.function_table.count(arg.value)) + { + ret = ctx.function_table[arg.value]; + } else if (ctx.variable_table.count(arg.value)) { + ret = ctx.variable_table[arg.value]; + } else { + ret = arg; + } + } else { + ret = arg; + } + }, data); + return ret; + } + inline lvalue eval(const std::string_view& data, context& ctx) { auto n = lex(data, ctx); auto p = parse(std::basic_string_view(n.data(), n.size()), ctx); - return p.second; + return eval(p.second, ctx); + } +} + +namespace lispy_math { + + int64_t next_as_int(std::shared_ptr& arguments, lispy::context& ctx) { + int64_t ret = 0; + if(!arguments) + { + std::cerr << "no argument provided, integer expected" << std::endl; + if(ctx.error_crash) + { + std::exit(-1); + } + return ret; + } + std::visit([&](auto arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + ret = arg; + } else if constexpr (std::is_same_v) { + ret = arg; + } else { + std::cerr << "bad argument provided, integer expected" << std::endl; + if(ctx.error_crash) + { + std::exit(-1); + } + } + }, arguments->self); + arguments = arguments->other; + return ret; + } + + namespace integer_functions { + class plus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr arguments, lispy::context& ctx) { + auto p = arguments; + int64_t a = next_as_int(p, ctx); + int64_t b = next_as_int(p, ctx); + + if(p) + { + std::cerr << "expected arity of 2 but more arguments provided" << std::endl; + if(ctx.error_crash) + { + std::exit(-1); + } + } + return a+b; + }}; + class minus : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr arguments, lispy::context& ctx) { + auto p = arguments; + int64_t a = next_as_int(p, ctx); + + if(!p) { + return -a; + } + + int64_t b = next_as_int(p, ctx); + + if(p) + { + std::cerr << "expected arity of 1 or 2 but more arguments provided" << std::endl; + if(ctx.error_crash) + { + std::exit(-1); + } + } + return a-b; + }}; + class product : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr arguments, lispy::context& ctx) { + auto p = arguments; + int64_t a = next_as_int(p, ctx); + int64_t b = next_as_int(p, ctx); + + if(p) + { + std::cerr << "expected arity of 2 but more arguments provided" << std::endl; + if(ctx.error_crash) + { + std::exit(-1); + } + } + return a*b; + }}; + class divide : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr arguments, lispy::context& ctx) { + auto p = arguments; + int64_t a = next_as_int(p, ctx); + int64_t b = next_as_int(p, ctx); + + if(p) + { + std::cerr << "expected arity of 2 but more arguments provided" << std::endl; + if(ctx.error_crash) + { + std::exit(-1); + } + } + return a/b; + }}; + class remainder : lispy::function {virtual lispy::lvalue operator() (const std::shared_ptr arguments, lispy::context& ctx) { + auto p = arguments; + int64_t a = next_as_int(p, ctx); + int64_t b = next_as_int(p, ctx); + + if(p) + { + std::cerr << "expected arity of 2 but more arguments provided" << std::endl; + if(ctx.error_crash) + { + std::exit(-1); + } + } + return a%b; + }}; + }; + + inline void add_integer_functions(lispy::context& ctx) { + using func_ptr = std::shared_ptr; + + ctx.function_table[ctx.get_atom("+")] = func_ptr{(lispy::function*)new integer_functions::plus()}; + ctx.function_table[ctx.get_atom("-")] = func_ptr{(lispy::function*)new integer_functions::minus()}; + ctx.function_table[ctx.get_atom("*")] = func_ptr{(lispy::function*)new integer_functions::product()}; + ctx.function_table[ctx.get_atom("/")] = func_ptr{(lispy::function*)new integer_functions::divide()}; + ctx.function_table[ctx.get_atom("%")] = func_ptr{(lispy::function*)new integer_functions::remainder()}; } } \ No newline at end of file diff --git a/src/csv-sheet/csv-parse.cpp b/src/csv-sheet/csv-parse.cpp index 4e11a82..05132a2 100644 --- a/src/csv-sheet/csv-parse.cpp +++ b/src/csv-sheet/csv-parse.cpp @@ -3,7 +3,8 @@ int main() { lispy::context ctx; - lispy::lvalue v = lispy::eval("cat 13 15.69 \"data \\ ひらがな \n\ttabulated\" \"\" \"test 2 \\x65\"", ctx); + lispy_math::add_integer_functions(ctx); + lispy::lvalue v = lispy::eval("cat $AA12 @A12:C23 (+ 3 (* 5 6) ) \"data \\ ひらがな \n\ttabulated\" \"\" \"test 2 \\x65\"", ctx); lispy::print_types_visitor(std::cout, v, ctx); std::cout << std::endl;