Complete String Parser except context.
parent
a481f23dfd
commit
075226bfcf
67
src/Main.cpp
67
src/Main.cpp
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>
|
||||
};
|
Loading…
Reference in New Issue