Complete String Parser except context.

master
Auri 2021-09-22 23:00:53 -07:00
parent a481f23dfd
commit 075226bfcf
2 changed files with 172 additions and 133 deletions

View File

@ -13,6 +13,7 @@
#pragma clang diagnostic pop
//#include "StartGame.h"
#include <iostream>
/*
* Zepha, designed, developed, and created by Nicole Collings
@ -20,27 +21,57 @@
* Copyright 2018 - present Auri Collings, All Rights Reserved.
*/
//constexpr char c[] = "ha";
struct TexData {
TexData() = default;
TexData(string p): p(p) {}
string p;
};
int main(int argc, char* argv[]) {
// // return StartGame(argc, argv);
StringParser<string> s {{
{ "crop", Fn::create<int, int, int, int, string>([](int x, int y, int w, int h, string tex) {
std::cout << "cropping " << x << "/" << y << ", " << w << "/" << h << " : " << tex << std::endl;
})},
{ "tint", Fn::create<int, string>([](int ind, string tex) {
std::cout << "tinting " << tex << " with ind " << ind << std::endl;
})},
{ "_", Fn::create<string>([](string tex) {
std::cout << "UNARY _ DEFAULT BITCH: " << tex << std::endl;
})}
}};
s.parse("crop(0,0,0,0,tint(0,hello_world))");
s.parse("crop(0,8,16,24,tint(0,hello_world))");
s.parse("tint(0,hello_world)");
s.parse("hello_world");
// using DataOrIden = variant<string, TexData>;
//
StringParser<TexData> s;
//
// s.addFn<std::variant<int, string>>("variant", [](std::variant<int, string> var) {
// const int* intV = std::get_if<int>(&var);
// if (intV) std::cout << "int " << *intV << std::endl;
// else std::cout << "str " << std::get<string>(var) << std::endl;
// return Res { 1 };
// });
//
// s.addFn<std::optional<string>>("optional", [](std::optional<string> var) {
// if (var) std::cout << "opt filled " << *var << std::endl;
// else std::cout << "opt empty" << std::endl;
// return Res { 2 };
// });
////
//// s.parse("crop(0, 0, 8, 8, tint(0, zeus:default:grass))");
//
// std::cout << s.parse("variant(2)") << std::endl;
// std::cout << s.parse("variant(hello)") << std::endl;
// std::cout << s.parse("optional(,,,)") << std::endl;
// std::cout << s.parse("optional(hello)") << std::endl;
// std::cout << s.parse("optional()") << std::endl;
s.addFn<u16, u16, u16, u16, TexData>("crop", [](u16 x, u16 y, u16 w, u16 h, TexData tex) {
return TexData { "cropped(" + tex.p + ")" };
});
s.addFn<u16, TexData>("tint", [](u16 ind, TexData tex) {
return TexData { "tinted(" + tex.p + ")" };
});
s.addLiteralFn<string>([](string lit) {
return TexData { lit };
});
std::cout << s.parse("crop(0,0,0,0,hello world)").p << std::endl;
std::cout << s.parse("tint(1,tint(2, crop(0,0,0,0,tint(0,delta))))").p << std::endl;
std::cout << s.parse("hello").p << std::endl;
// s.parse("aaa");
// return 0;

View File

@ -1,77 +1,84 @@
#pragma once
#include <iostream>
#include <functional>
#include <unordered_map>
#include "util/Types.h"
//template<typename R, typename... Args>
//struct Fn {
// typedef std::function<R(Args...)> FN_TYPE;
// Fn(const string& name, const FN_TYPE& fn): name(name), fn(fn) {}
// const string name;
// const FN_TYPE fn;
//};
//
class Fn {
using EXEC_ARGS = const vec<std::string_view>&;
using EXEC_FN = std::function<void(std::unordered_map<string, Fn>, EXEC_ARGS)>;
namespace {
template<typename T> struct is_variant : std::false_type {};
public:
Fn(EXEC_FN exec): exec(exec) {};
template<typename... Args>
struct is_variant<std::variant<Args...>> : std::true_type {};
template <typename... Args, typename Func>
static Fn create(const Func& fn) {
using TYPES = std::tuple<Args...>;
return Fn([=](std::unordered_map<string, Fn> functions, EXEC_ARGS strArgs) {
TYPES args = {};
parseStrArgs<TYPES>(strArgs, args);
std::apply(fn, args);
});
}
template<typename T>
inline constexpr bool is_variant_v = is_variant<T>::value;
void operator()(std::unordered_map<string, Fn> functions, EXEC_ARGS args) const {
return exec(functions, args);
}
template<typename T> struct is_optional : std::false_type {};
private:
EXEC_FN exec;
template<typename... Args>
struct is_optional<std::optional<Args...>> : std::true_type {};
template <typename T, usize I, std::enable_if_t<std::is_same_v<T, string>, bool> = true>
static T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return string(args[I]);
}
template <typename T, usize I, std::enable_if_t<std::is_integral_v<T>, bool> = true>
static T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return std::stoi(args[I].data());
}
template <typename T, usize I, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
static T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return std::stod(args[I].data());
}
template <typename T, usize I = 0>
static void parseStrArgs(EXEC_ARGS strArgs, T& args) {
std::get<I>(args) = parseStrArg<std::tuple_element_t<I, T>, I>(strArgs);
if constexpr (I + 1 < std::tuple_size_v<T>) parseStrArgs<T, I + 1>(strArgs, args);
}
};
template<typename T>
inline constexpr bool is_optional_v = is_optional<T>::value;
}
template <typename R>
class StringParser {
class Fn;
using EXEC_ARGS = const vec<std::string_view>&;
using EXEC_FN = std::function<R(std::unordered_map<string, Fn>, EXEC_ARGS)>;
struct Fn {
Fn(EXEC_FN exec): exec(exec) {};
R operator()(std::unordered_map<string, Fn> functions, EXEC_ARGS args) const {
return exec(functions, args);
}
private:
EXEC_FN exec;
};
public:
using PARAM_TYPES = variant<string, int, float, R>;
explicit StringParser(const std::unordered_map<string, Fn>& functions): functions(functions) {};
explicit StringParser() = default;
template <typename... Args, typename Func>
void addFn(const string& name, const Func& fn) {
using TYPES = std::tuple<Args...>;
functions.emplace(name, [=, this](std::unordered_map<string, Fn> functions, EXEC_ARGS strArgs) {
TYPES args = {};
parseStrArgs<TYPES>(strArgs, args);
return std::apply(fn, args);
});
}
template <typename... Args, typename Func>
void addLiteralFn(const Func& fn) {
addFn<Args...>("_", fn);
}
const R parse(string str) const {
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
return std::move(parseRaw(str));
}
private:
const R parseRaw(const std::string_view str) const {
if (strIsFunction(str)) {
let func = parseFunction(str);
const let f = functions.find(string(func.first));
if (f == functions.end()) throw std::invalid_argument("Unknown function '" + string(func.first) + "'!");
return f->second(functions, func.second);
}
else {
const let& f = functions.find("_");
if (f == functions.end()) throw std::invalid_argument("No default function handler!");
return f->second(functions, { str });
}
}
const usize findClosingParen(const std::string_view& str, usize start) const {
usize levels = 0;
for (usize i = start + 1; i < str.size(); i++) {
@ -81,27 +88,27 @@ public:
else return i;
}
}
throw std::invalid_argument("Mismatched parentheses.");
}
const bool strIsFunction(const std::string_view& str) const {
return str.find_first_of('(') != string::npos;
}
const std::pair<std::string_view, vec<std::string_view>> parseFunction(const std::string_view& str) const {
let nextParen = str.find_first_of('(');
let nextComma = str.find_first_of(',');
if (nextParen == string::npos || (nextComma != string::npos && nextComma < nextParen))
throw std::invalid_argument("Not a function");
let name = str.substr(0, nextParen);
vec<std::string_view> args {};
let end = findClosingParen(str, nextParen);
let s = nextParen + 1;
while (s <= end) {
nextParen = str.find_first_of('(', s);
nextComma = str.find_first_of(',', s);
@ -111,64 +118,65 @@ public:
args.emplace_back(str.substr(s, nextComma - s));
s = nextComma + 1;
}
return { name, args };
}
const R parse(string str) const {
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
let view = std::string_view(str);
if (strIsFunction(view)) {
let func = parseFunction(view);
const let f = functions.find(string(func.first));
if (f == functions.end()) throw std::invalid_argument("Unknown function '" + string(func.first) + "'!");
f->second(functions, func.second);
template <typename T, usize I, std::enable_if_t<std::is_same_v<T, string>, bool> = true>
T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return string(args[I]);
}
template <typename T, usize I, std::enable_if_t<std::is_integral_v<T>, bool> = true>
T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return std::stoi(args[I].data());
}
template <typename T, usize I, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return std::stod(args[I].data());
}
template <typename T, usize I, usize VI = 0>
T parseStrVariantArg(EXEC_ARGS args) {
try {
return parseStrArg<std::variant_alternative_t<VI, T>, I>(args);
}
catch (...) {}
if constexpr (VI + 1 < std::variant_size_v<T>) {
return parseStrVariantArg<T, I, VI + 1>(args);
}
else {
const let& f = functions.find("_");
if (f == functions.end()) throw std::invalid_argument("No default function handler!");
f->second(functions, { view });
throw std::invalid_argument("Argument does not match types required.");
}
return R {};
}
template<typename T, usize I, std::enable_if_t<is_variant_v<T>, bool> = true>
T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return parseStrVariantArg<T, I>(args);
}
template<typename T, usize I, std::enable_if_t<is_optional_v<T>, bool> = true>
T parseStrArg(EXEC_ARGS args) {
if (I >= args.size() || args[I].empty()) return {};
return parseStrArg<typename T::value_type, I>(args);
}
template <typename T, usize I, std::enable_if_t<std::is_same_v<T, R>, bool> = true>
T parseStrArg(EXEC_ARGS args) {
if (I >= args.size()) throw std::invalid_argument("Not enough parameters.");
return parseRaw(parseStrArg<string, I>(args));
}
template <typename T, usize I = 0>
void parseStrArgs(EXEC_ARGS strArgs, T& args) {
std::get<I>(args) = parseStrArg<std::tuple_element_t<I, T>, I>(strArgs);
if constexpr (I + 1 < std::tuple_size_v<T>) parseStrArgs<T, I + 1>(strArgs, args);
}
private:
// template <class T, template <class...> class Template>
// struct is_specialization : std::false_type {};
//
// template <template <class...> class Template, class... Args>
// struct is_specialization<Template<Args...>, Template> : std::true_type {};
//
// template <typename T, usize I = 0>
// T parseVariantVal(const std::string_view& str) {
// try {
// return parseVal<std::variant_alternative_t<I, T>>(str);
// }
// catch (...) {}
// if constexpr (I + 1 < std::variant_size_v<T>) {
// return parseVariantVal<T, I + 1>(str);
// }
// else {
// throw std::invalid_argument("Argument does not match types required.");
// }
// }
//
// template<typename T, std::enable_if_t<std::variant_size_v<T> != 0, bool> = true>
// T parseVal(const std::string_view& str) {
// return parseVariantVal<T>(str);
// }
std::unordered_map<string, Fn> functions {};
// template<typename T, std::enable_if_t<is_specialization<T, optional>::value, bool> = true>
// T parseVal(const std::string_view& str) {
// try {
//
// }
// }
// template<typename>
};