#include "interpolate.h" #include "error.h" #include "logger.h" #include "srell.hpp" #include #include #include using namespace std::literals; template using vstack = kblib::stack; using kblib::pop; using kblib::coerce; using kblib::lexical_coerce; [[nodiscard]] std::string stringize(const arg_t& arg) { return std::visit(kblib::visitor{ [](const std::string& str) {return str;}, [](const std::vector& vec) { return std::accumulate(vec.begin(), vec.end(), std::string{}); }, [](const node* n) {return kblib::concat(n->name, std::string(n->declared_argc, '|'), kblib::repeat("..."s, n->variadic));}, [](const std::unique_ptr&) -> std::string { throw wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) -> std::string {throw e;} }, arg); } [[nodiscard]] static std::string stringize(const arg_t& arg, const std::string& joiner) { return std::visit(kblib::visitor{ [](const std::string& str) {return str;}, [&joiner](const std::vector& vec) { return std::accumulate(vec.begin(), vec.end(), std::string{}, [&joiner](std::string l, const std::string& r) { return (l+=joiner)+=r; }); }, [](const node* n) {return kblib::concat(n->name, std::string(n->declared_argc, '|'), kblib::repeat("..."s, n->variadic));}, [](const std::unique_ptr&) -> std::string { throw wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) -> std::string {throw e;} }, arg); } [[nodiscard]] std::string stringize(arg_t&& arg) { return std::visit(kblib::visitor{ [](std::string&& str) {return std::move(str);}, [](std::vector&& vec) { return std::accumulate(vec.begin(), vec.end(), std::string{}); }, [](const node* n) {return kblib::concat(n->name, std::string(n->declared_argc, '|'), kblib::repeat("..."s, n->variadic));}, [](const std::unique_ptr&) -> std::string { throw wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) -> std::string {throw e;} }, std::move(arg)); } [[nodiscard]] static std::string stringize(arg_t&& arg, const std::string& joiner) { return std::visit(kblib::visitor{ [](std::string&& str) {return std::move(str);}, [&joiner](std::vector&& vec) { return std::accumulate(vec.begin(), vec.end(), std::string{}, [&joiner](std::string l, const std::string& r) { return (l+=joiner)+=r; }); }, [](const node* n) { return kblib::concat(n->name, std::string(n->declared_argc, '|'), kblib::repeat("..."s, n->variadic)); }, [](const std::unique_ptr&) -> std::string { throw wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) -> std::string {throw e;} }, std::move(arg)); } [[nodiscard]] static arg_t to_string(const arg_t& arg) { return std::visit(kblib::visitor{ [](const std::string& str) -> arg_t {return str;}, [](const std::vector& vec) -> arg_t { return std::accumulate(vec.begin(), vec.end(), std::string{}); }, [](const node* n) -> arg_t { return kblib::concat(n->name, std::string(n->declared_argc, '|'), kblib::repeat("..."s, n->variadic)); }, [](const std::unique_ptr&) -> arg_t { return wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) -> arg_t {return e;} }, arg); } [[nodiscard]] static arg_t to_string(arg_t&& arg) { return std::visit(kblib::visitor{ [](std::string&& str) -> arg_t {return std::move(str);}, [](const std::vector& vec) -> arg_t { std::string out; out.reserve(std::accumulate(vec.begin(), vec.end(), std::size_t{}, [](std::size_t acc, const std::string& s) { return acc + s.length(); })); std::copy(vec.begin(), vec.end(), kblib::consumer([&](const std::string& s) {out += s;})); return out; }, [](const node* n) -> arg_t { return kblib::concat(n->name, std::string(n->declared_argc, '|'), kblib::repeat("..."s, n->variadic)); }, [](const std::unique_ptr&) -> arg_t { return wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) -> arg_t {return e;} }, std::move(arg)); } // std::vector flatten(argslist args) // { // return std::accumulate( // args.begin(), args.end(), // std::vector{}, // [](std::vector vec, const arg_t& a) { // std::visit(kblib::visitor{ // [&](const std::string& s) {vec.push_back(s);}, // [&](const std::vector& v) { // vec.insert(vec.end(), v.begin(), v.end()); // }, // }, a); // return vec; // }); // } [[nodiscard]] static std::vector flatten_impl(argslist args) { return std::accumulate( args.begin(), args.end(), std::vector{}, [](std::vector vec, const arg_t& a) { std::visit(kblib::visitor{ [&](const std::string& s) {vec.push_back(s);}, [&](const std::vector& v) { vec.insert(vec.end(), v.begin(), v.end()); }, [&](const node* n) {vec.push_back(stringize(n));}, [](const std::unique_ptr&) { throw wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) {throw e;} }, a); return vec; }); } [[nodiscard]] static arg_t flatten(argslist args) { try { return flatten_impl(std::move(args)); } catch (const wordgen_error& e) { return e; } } [[nodiscard]] static std::vector listize(arg_t arg) { return std::visit(kblib::visitor{ [](std::string&& s) -> std::vector { std::vector v; v.emplace_back(std::move(s)); return v; }, [](std::vector&& v) -> std::vector { return {std::move(v)}; }, [](const node* n) -> std::vector { return std::vector{stringize(n)}; }, [](const std::unique_ptr&) -> std::vector { throw wordgen_error(ec::node_bad_cvt, "", "", ""); }, [](const wordgen_error& e) -> std::vector {throw e;} }, std::move(arg)); } [[nodiscard]] arg_t Echo::operator()(argslist v) const { try { return std::accumulate( v.begin(), v.end(), std::string{}, [](std::string s, const arg_t& arg) { return s += stringize(arg, "|"); } ); } catch (const wordgen_error& e) { return e; } } [[nodiscard]] arg_t Evaluator::operator()(argslist v) const { if (v.empty()) { return wordgen_error(ec::invoke_null, "", "", ""); } if (!std::holds_alternative(v.front())) { return wordgen_error(ec::invoke_type, "", "", ""); } try { //the first argument is the name of the function to invoke std::string fun = [&] { if (auto f = std::get_if(&v.front()); f) { return std::move(*f); } else { return stringize(v.front()); } }(); v.erase(v.begin()); return owner->lookup(fun)(std::move(v)); } catch (const wordgen_error& e) { return e; } } [[nodiscard]] static arg_t concat(argslist v) { try { return std::accumulate( v.begin(), v.end(), std::string{}, [](std::string s, const arg_t& arg) { return s += stringize(arg); } ); } catch (const wordgen_error& e) { return e; } } [[nodiscard]] static arg_t repeat(argslist args) { if (args.size() % 2) { args.push_back("1"s); //handle odd lists by adding the last element once } std::string out; auto pos = args.begin(); auto end = args.end(); for (; pos != end; pos += 2) { if (!std::holds_alternative(*std::next(pos))) { return wordgen_error(ec::e_internal, "", "", ""); } try { out += kblib::repeat(stringize(*pos, "|"), std::stoi(std::get(*std::next(pos)))); } catch (const wordgen_error& e) { return e; } } return out; } [[nodiscard]] static arg_t len(argslist args) { if (args.size() > 1) { return wordgen_error(ec::too_many_args, "len", std::to_string(args.size()), ""); } else if (args.empty()) { return wordgen_error(ec::not_enough_args, "len", std::to_string(args.size()), ""); } return std::visit(kblib::visitor{ [](const std::string&) -> arg_t {return "1"s;}, [](const std::vector& vec) -> arg_t { return std::to_string(vec.size()); }, [](const node* n) -> arg_t {return std::to_string(n->vals.size());}, [](const std::unique_ptr& n) -> arg_t {return std::to_string(n->vals.size());}, [](const wordgen_error& e) -> arg_t {return e;} }, args[0]); } template struct power { [[nodiscard]] T operator()(const T& l, const T& r) {return std::pow(l, r);} }; //left fold template [[nodiscard]] arg_t left_fold(argslist args) { try { auto flat = flatten_impl(std::move(args)); return kblib::toStr(std::accumulate( flat.begin(), flat.end(), static_cast(init), [](double L, const std::string& str) { return op{}(L, pFromStr(double, str)); })); } catch (const wordgen_error& e) { return e; } #if 0 return kblib::toStr(std::accumulate( args.begin(), args.end(), static_cast(init), [](double L, const arg_t& a) { return op{}(L, std::visit(kblib::visitor{ [](const std::string& str) { return pFromStr(double, str); }, [](const std::vector& vec) { return std::accumulate( vec.begin(), vec.end(), static_cast(init), [](double L, std::string str) { return op{}(L, pFromStr(double, str)); } ); }, }, a)); } )); #endif } template [[nodiscard]] arg_t left_fold(argslist args) { try { auto flat = flatten_impl(std::move(args)); return kblib::toStr(std::accumulate( std::next(flat.begin()), flat.end(), pFromStr(double, flat.front()), [](double L, const std::string& str) { return op{}(L, pFromStr(double, str)); })); } catch (const wordgen_error& e) { return e; } } [[nodiscard]] static arg_t select_(argslist args) { try { return std::move(args.at(1+pFromStr(unsigned, stringize(std::move(args.at(0)))))); } catch (const wordgen_error& e) { return e; } catch (const std::out_of_range& e) { return wordgen_error(ec::range_error, "?", kblib::concat("failed to index ", stringize(args.front())), kblib::concat("with ", args.size(), " args")); } } [[nodiscard]] static arg_t which(argslist args) { return std::to_string(kblib::find_in( args.begin()+1, args.end(), args.at(0) )); } [[nodiscard]] static arg_t normalizeNum(argslist args) { if (args.size() > 1) { return wordgen_error(ec::too_many_args, "num", std::to_string(args.size()), ""); } return kblib::toStr(pFromStr(double, stringize(args[0]))); } [[nodiscard]] static arg_t greater(argslist args) { if (args.size() > 4) { return wordgen_error(ec::too_many_args, "gt", std::to_string(args.size()), ""); } else if (args.size() < 4) { return wordgen_error(ec::not_enough_args, "gt", std::to_string(args.size()), ""); } if (pFromStr(unsigned, stringize(args[0])) > pFromStr(unsigned, stringize(args[1]))) { return std::move(args[2]); } else { return std::move(args[3]); } } [[nodiscard]] static arg_t lesser(argslist args) { if (args.size() > 4) { return wordgen_error(ec::too_many_args, "lt", std::to_string(args.size()), ""); } else if (args.size() < 4) { return wordgen_error(ec::not_enough_args, "lt", std::to_string(args.size()), ""); } if (pFromStr(unsigned, stringize(args[0])) < pFromStr(unsigned, stringize(args[1]))) { return std::move(args[2]); } else { return std::move(args[3]); } } [[nodiscard]] static arg_t equal(argslist args) { if (args.size() > 4) { return wordgen_error(ec::too_many_args, "eq", std::to_string(args.size()), ""); } else if (args.size() < 4) { return wordgen_error(ec::not_enough_args, "eq", std::to_string(args.size()), ""); } if (args[0] == args[1]) { return std::move(args[2]); } else { return std::move(args[3]); } } [[nodiscard]] static arg_t nequal(argslist args) { if (args.size() > 4) { return wordgen_error(ec::too_many_args, "ne", std::to_string(args.size()), ""); } else if (args.size() < 4) { return wordgen_error(ec::not_enough_args, "ne", std::to_string(args.size()), ""); } if (args[0] != args[1]) { return std::move(args[2]); } else { return std::move(args[3]); } } #if 0 static icu::UnicodeString math(const std::vector& p, int s, const ArgsType& a) { //Fill pvals with the substituted values of the parameter list (flattening ...) std::vector pvals; std::for_each( p.begin(), p.end(), [&a, &s, &pvals](const param& p) { if (p.isRest()) { std::transform( std::next(a.begin(), s), a.end(), std::back_inserter(pvals), [&a, &s](const icu::UnicodeString& s){return s;} ); } else { pvals.push_back(p.getVal(s, a)); } } ); const std::array ops = {u'+',u'-',u'*',u'/',u'.'}; std::stack opstack; std::stack valstack; bool pending = false; for (auto& p : pvals) { decltype(&ops[0]) op; if (p.countChar32() == 1 && (op = std::find(ops.begin(), ops.end(), p.char32At(0))) != ops.end()) { opstack.push(*op); } else { if (pending) { while(valstack.size()) { auto v1 = pop(valstack); auto op = pop(opstack); #define APPLYOP(OP) \ p=fromUTF8(toStr(pFromStr(double, v1) OP pFromStr(double, p))) if (op == '+') APPLYOP(+); else if (op == '-') APPLYOP(-); else if (op == '*') APPLYOP(*); else if (op == '/') APPLYOP(/); else if (op == '.') p=v1+p; } } valstack.push(p); pending = true; } } return pop(valstack); } #endif //save effort and accuracy on reconverting between double and string by using a variant value type using math_type = std::variant; [[nodiscard]] static bool is_operator(char c) { static const std::string ops = "+-*/^."; return ops.find(c) != std::string::npos; } [[nodiscard]] static math_type plus(math_type v1, math_type v2) { return lexical_coerce(v1) + lexical_coerce(v2); } [[nodiscard]] static math_type minus(math_type v1, math_type v2) { return lexical_coerce(v1) - lexical_coerce(v2); } [[nodiscard]] static math_type mul(math_type v1, math_type v2) { return lexical_coerce(v1) * lexical_coerce(v2); } [[nodiscard]] static math_type div(math_type v1, math_type v2) { auto rhs = lexical_coerce(v2); if (rhs == 0) { } return lexical_coerce(v1) / rhs; } [[nodiscard]] static math_type pow(math_type v1, math_type v2) { return std::pow(lexical_coerce(v1), lexical_coerce(v2)); } [[nodiscard]] static math_type cat(math_type v1, math_type v2) { return lexical_coerce(v1) + lexical_coerce(v2); } [[nodiscard]] static arg_t pn(argslist args) { auto check_pn = [](const std::vector tokens) { int expected_vals = 1; for (const auto& tok : tokens) { if (expected_vals == 0) { throw wordgen_error(ec::bad_math, "validation failure\n", kblib::quoted(tok), ""); } if (tok.size() == 1 && is_operator(tok[0])) { ++expected_vals; } else { --expected_vals; } } if (expected_vals != 0) { throw wordgen_error(ec::bad_math, "validation failure", "", ""); } return tokens; }; vstack valstack; vstack opstack; bool pending = false; // auto print_state = [&](const math_type& curr, bool nested = false){ // using std::clog; // if (!nested) clog<<"---"; // clog<<"---\n" // <<"current token: "<(curr)<<'\n' // <<"pending: "<(c)<<", "; // })); // clog<<'\n'; // }; try { for (const std::string& a : check_pn(flatten_impl(std::move(args)))) { // print_state(a); if (a.size() == 1 && is_operator(a[0])) { opstack.push(a[0]); pending = false; } else { math_type v2 = a; if (pending) { while (valstack.size()) { // print_state(v1, true); if (opstack.empty()) { throw wordgen_error(ec::bad_math, "pn", "\nnot enough operators", ""); } auto v1 = pop(valstack); switch (pop(opstack)) { case '+': v2 = plus(v1, v2); break; case '-': v2 = minus(v1, v2); break; case '*': v2 = mul(v1, v2); break; case '/': v2 = div(v1, v2); break; case '^': v2 = pow(v1, v2); break; case '.': v2 = cat(v1, v2); } } } valstack.push(std::move(v2)); pending = true; } } if (!pending || !opstack.empty() || valstack.size() != 1) { return wordgen_error(ec::bad_math, "pn", "", ""); } return kblib::lexical_coerce(pop(valstack)); } catch (const wordgen_error& e) { return e; } } [[nodiscard]] static arg_t rpn(argslist args) { vstack valstack; try { for (const auto& a : flatten_impl(std::move(args))) { if (a.size() == 1 && is_operator(a[0])) { auto v2 = pop(valstack); auto v1 = pop(valstack); switch (a[0]) { case '+': valstack.push(plus(v1, v2)); break; case '-': valstack.push(minus(v1, v2)); break; case '*': valstack.push(mul(v1, v2)); break; case '/': valstack.push(div(v1, v2)); break; case '^': valstack.push(pow(v1, v2)); break; case '.': valstack.push(cat(v1, v2)); } } else { valstack.push(a); } } if (valstack.size() != 1) { return wordgen_error(ec::bad_math, "rpn", "", ""); } return kblib::lexical_coerce(pop(valstack)); } catch (const wordgen_error& e) { return e; } } [[nodiscard]] static bool truthy(const arg_t& arg) { auto str = stringize(arg); if (str.empty()) return false; try { if (pFromStr(double, str) == 0) return false; } catch (std::runtime_error& e) { return true; } return true; } [[nodiscard]] static arg_t if_(argslist args) { if (args.size() > 3) { return wordgen_error(ec::too_many_args, "if", std::to_string(args.size()), ""); } else if (args.size() < 3) { return wordgen_error(ec::not_enough_args, "if", std::to_string(args.size()), ""); } return std::move(truthy(args[0]) ? args[1] : args[2]); } [[nodiscard]] static arg_t ifn(argslist args) { if (args.size() > 3) { return wordgen_error(ec::too_many_args, "ifn", std::to_string(args.size()), ""); } else if (args.size() < 3) { return wordgen_error(ec::not_enough_args, "ifn", std::to_string(args.size()), ""); } return std::move((!truthy(args[0])) ? args[1] : args[2]); } [[nodiscard]] static arg_t negate(argslist args) { if (args.size() > 1) { return wordgen_error(ec::too_many_args, "not", std::to_string(args.size()), ""); } else if (args.empty()) { return wordgen_error(ec::not_enough_args, "not", std::to_string(args.size()), ""); } return (!truthy(args[0])) ? "1" : "0"; } [[nodiscard]] static arg_t subscript(argslist args) { if (args.size() < 2) { return wordgen_error(ec::not_enough_args, "[]", std::to_string(args.size()), ""); } auto list = listize(std::move(args.front())); auto remainder = flatten(argslist{ std::make_move_iterator(args.begin() + 1), std::make_move_iterator(args.end())}); args.clear(); //TODO return wordgen_error(ec::no_feature, "[]", "", ""); } [[nodiscard]] static arg_t replacer(argslist args) { if (!(args.size() % 2)) { return wordgen_error(ec::unpaired_args, "[]", std::to_string(args.size()), "Even number of arguments expected."); } auto str = stringize(args.front()); auto pos = std::next(args.begin()); auto end = args.end(); for (; pos != end; pos += 2) { str = srell::regex_replace(str, srell::regex{stringize(*pos), srell::regex_constants::dotall}, stringize(*std::next(pos))); } return str; } [[nodiscard]] static arg_t polychannel_literal(argslist args) { //Replace literal nodes with an inline syntax, using template-strings. //ex: //These control characters will be interpreted by the noderef layer. if (!(args.size() % 2)) { return wordgen_error(ec::unpaired_args, "_literal", std::to_string(args.size()), "Even number of arguments expected."); } auto out = "\021!"s; auto pos = args.begin(); auto end = args.end(); for (; pos != end; pos += 2) { std::string ch = stringize(*pos); std::string contents = stringize(*std::next(pos)); out = kblib::concat(out, '\036', ch, '\037', contents); } out.push_back('\023'); return out; } [[nodiscard]] std::map, std::less<>> default_transformers(bytecode_machine* owner, datafile* df, RandomGenerator& rng) { std::map, std::less<>> transformers; transformers.emplace("cat", make_transformer(concat)); transformers.emplace(".*", make_transformer(repeat)); transformers.emplace("flatten", make_transformer(flatten)); transformers.emplace("len", make_transformer(len)); transformers.emplace("+", make_transformer(left_fold, 0>)); transformers.emplace("-", make_transformer(left_fold>)); transformers.emplace("*", make_transformer(left_fold, 1>)); transformers.emplace("/", make_transformer(left_fold, 1>)); transformers.emplace("^", make_transformer(left_fold>)); transformers.emplace("not", make_transformer(negate)); transformers.emplace("if", make_transformer(if_)); transformers.emplace("ifn", make_transformer(ifn)); transformers.emplace("?", make_transformer(select_)); transformers.emplace("which", make_transformer(which)); transformers.emplace("num", make_transformer(normalizeNum)); transformers.emplace("gt", make_transformer(greater)); transformers.emplace("lt", make_transformer(lesser)); transformers.emplace("=", make_transformer(equal)); transformers.emplace("eq", make_transformer(equal)); transformers.emplace("!=", make_transformer(nequal)); transformers.emplace("ne", make_transformer(nequal)); transformers.emplace("math", make_transformer(pn)); transformers.emplace("calc", make_transformer(pn)); transformers.emplace("pn", make_transformer(pn)); transformers.emplace("rpn", make_transformer(rpn)); transformers.emplace("replace", make_transformer(replacer)); transformers.emplace("rand", make_transformer([&rng](argslist argsin) -> arg_t { auto args = flatten_impl(std::move(argsin)); if (args.size() == 0) { throw wordgen_error(ec::bad_randspec, "No arguments received. Expected either max or min|max.", "", ""); } else if (args.size() == 1) { std::uniform_real_distribution dist(0.0, std::stod(args[0])); return std::to_string(dist(rng)); } else if (args.size() == 2) { std::uniform_real_distribution dist(std::stod(args[0]), std::stod(args[1])); return std::to_string(dist(rng)); } else { throw wordgen_error(ec::bad_randspec, "Too many arguments received. Expected either max or min|max.", "", ""); } })); transformers.emplace("randnorm", make_transformer([&rng](argslist argsin) -> arg_t { auto args = flatten_impl(std::move(argsin)); if (args.size() == 2) { std::normal_distribution dist(std::stod(args[0]), std::stod(args[1])); return std::to_string(dist(rng)); } else { throw wordgen_error(ec::bad_randspec, "Expected avg|stddev.", "", ""); } })); transformers.emplace("randint", make_transformer([&rng](argslist argsin) -> arg_t { auto args = flatten_impl(std::move(argsin)); if (args.size() == 0) { throw wordgen_error(ec::bad_randspec, "No arguments received. Expected either max or min|max.", "", ""); } else if (args.size() == 1) { return std::to_string(rng(std::stoi(args[0]))); } else if (args.size() == 2) { std::uniform_int_distribution dist(std::stoll(args[0]), std::stoll(args[1])); return std::to_string(dist(rng)); } else { throw wordgen_error(ec::bad_randspec, "Too many arguments received. Expected either max or min|max.", "", ""); } })); transformers.emplace("randcat", make_transformer([&rng](argslist argsin) -> arg_t { auto args = flatten_impl(std::move(argsin)); auto freqs = kblib::build>(args.begin(), args.end(), [](const std::string& str) -> double { return std::stod(str); }); return std::to_string(kblib::chooseCategorical(freqs, rng)); })); transformers.emplace("invoke", std::make_unique(owner)); #if 0 transformers.emplace("node", make_transformer([df](argslist args) -> arg_t { assert(args.size() == 1); assert(std::holds_alternative(args[0])); auto name = std::get(args[0]); const node* n = df->find_node(name); if (n) return n; else return wordgen_error(ec::e_nonode, name, "", ""); })); transformers.emplace("branches", make_transformer([df](argslist args) -> arg_t { assert(args.size() > 0); if (args.size() == 1) { return kblib::visit(args.front(), [](const node* n) { return std::to_string(n->vals.size()); }, [&](const std::string& str) { const node* n = df->find_node(str); if (n) return std::to_string(n->vals.size()); else throw wordgen_error(ec::e_nonode, str, "", ""); }, [&](const std::vector& vec) -> std::string { if (vec.size() != 1) throw wordgen_error(ec::bad_arg_rank, stringize(vec), "", "'branches' expects either a node-name or a node."); const node* n = df->find_node(vec[0]); if (n) return std::to_string(n->vals.size()); else throw wordgen_error(ec::e_nonode, vec[0], "", ""); }, [](const wordgen_error& e) -> std::string {throw e;} ); } else { throw wordgen_error(ec::bad_arg_rank, stringize(args), "", "'branches' expects either a node-name or a node."); } })); transformers.emplace("freqs", make_transformer([df, owner](argslist args) -> arg_t { assert(args.size() > 0); if (args.size() == 1) { auto node_to_freqs = [&](const node* n) -> std::vector { return kblib::build>( n->freqs.begin(), n->freqs.end(), [&](const std::variant& v) { return kblib::visit(v, [](double d) {return std::to_string(d);}, [&](const bytecodes& b) {return owner->eval(b);} ); } ); }; return kblib::visit(args.front(), node_to_freqs, [&](const std::string& str) -> std::vector { const node* n = df->find_node(str); if (n) return node_to_freqs(n); else throw wordgen_error(ec::e_nonode, str, "", ""); }, [](const std::vector& vec) -> std::vector { if (vec.size() != 1) throw wordgen_error(ec::bad_arg_rank, stringize(vec), "", "'freqs' expects either a node-name or a node."); const node* n = df->find_node(vec[0]); if (n) return node_to_freqs(n); else throw wordgen_error(ec::e_nonode, str, "", ""); }, [](const wordgen_error& e) -> std::vector {throw e;} ); } else { throw wordgen_error(ec::bad_arg_rank, stringize(vec), "", "'freqs' expects either a node-name or a node."); } })); transformers.emplace("makenode", make_transformer([df, owner](argslist args) -> arg_t { })); transformers.emplace("[]", make_transformer(subscript)); transformers.emplace("_literal", make_transformer(polychannel_literal)); #endif // transformers.emplace("rand", make_transformer(randint)); return transformers; } [[nodiscard]] std::vector> default_names() { return { {"p", -12}, {"lt", -11}, {"gt", -10}, {"d", -9}, {"D", -8}, {"e", -7}, {"E", -6}, {"c", -5}, {"C", -4}, {"a", -3}, {"A", -2}, {"...", -1} }; } [[nodiscard]] int bytecode_machine::min_argument() const { return -12; } ArgsType copy(const ArgsType& special, const std::vector& vals) { ArgsType ret{origin_tag{special.low()}}; for (auto i = special.low(); i < 0; ++i) { ret.push_back(special[i]); } std::copy(vals.begin(), vals.end(), std::back_inserter(ret)); return ret; } template void set_sieve(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt1 out1, OutputIt2 out2) { while (first1 != last1) { if (first2 == last2) { std::copy(first1, last1, out1); return; } if (*first1 < *first2) { *out1++ = *first1++; } else { if (!(*first2 < *first1)) { *out2++ = *first1++; } ++first2; } } } template void set_copy_and_difference(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt1 out1, OutputIt2 out2, Compare comp) { while (first1 != last1) { if (first2 == last2) { std::copy(first1, last1, out1); } if (comp(*first2, *first1)) { *out2 = *first2; ++first2; ++out2; } else { *out1 = *first1; ++out1; if (!comp(*first1, *first2)) ++first2; ++first1; } } std::copy(first2, last2, out2); } Word ReplaceStage::operator()(const Word& word) const { Word ret = word; for (auto& [ch, act] : actions) { auto& chname = datafile::ch_db()[ch]; log_info(chname, ": ", kblib::quoted(kblib::get_or(word.data, ch, ""))); for (auto& step : act) { ret.data = step(std::move(ret), ch); log_debug(" ", kblib::quoted(kblib::get_or(word.data, ch, ""))); //ret.data.insert_or_assign(ch, step(ret, kblib::get_or(ret.data, ch, std::string{}))); } } // set_copy_and_difference( // actions.begin(), actions.end(), // word.data.begin(), word.data.end(), // kblib::consumer([&](const std::pair& f) { // channelID ch = f.first; // for (const auto& step : f.second) { // ret.data[ch] = step(word, kblib::get_or(word.data, ch, std::string{})); // } // }), // kblib::consumer([&](const std::pair& s) { // ret.data.insert(s); // }), // [](const auto& f, const auto& s) {return f.first < s.first;} // ); // std::set_intersection( // actions.begin(), actions.end(), // word.data.begin(), word.data.end(), // kblib::consumer([&](const auto& p) { // channelID ch = p.first; // for (const auto& step : actions.at(ch)) { //std::clog<