| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522 |
- // This file is distributed under the BSD License.
- // See "license.txt" for details.
- // Copyright 2009-2012, Jonathan Turner ([email protected])
- // Copyright 2009-2017, Jason Turner ([email protected])
- // http://www.chaiscript.com
- // This is an open source non-commercial project. Dear PVS-Studio, please check it.
- // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
- #ifndef CHAISCRIPT_EVAL_HPP_
- #define CHAISCRIPT_EVAL_HPP_
- #include <exception>
- #include <functional>
- #include <limits>
- #include <map>
- #include <memory>
- #include <ostream>
- #include <stdexcept>
- #include <string>
- #include <vector>
- #include "../chaiscript_defines.hpp"
- #include "../dispatchkit/boxed_cast.hpp"
- #include "../dispatchkit/boxed_number.hpp"
- #include "../dispatchkit/boxed_value.hpp"
- #include "../dispatchkit/dispatchkit.hpp"
- #include "../dispatchkit/dynamic_object_detail.hpp"
- #include "../dispatchkit/proxy_functions.hpp"
- #include "../dispatchkit/proxy_functions_detail.hpp"
- #include "../dispatchkit/register_function.hpp"
- #include "../dispatchkit/type_info.hpp"
- #include "chaiscript_algebraic.hpp"
- #include "chaiscript_common.hpp"
- namespace chaiscript {
- namespace exception {
- class bad_boxed_cast;
- } // namespace exception
- } // namespace chaiscript
- namespace chaiscript
- {
- /// \brief Classes and functions that are part of the runtime eval system
- namespace eval
- {
- template<typename T> struct AST_Node_Impl;
- template<typename T> using AST_Node_Impl_Ptr = typename std::unique_ptr<AST_Node_Impl<T>>;
- namespace detail
- {
- /// Helper function that will set up the scope around a function call, including handling the named function parameters
- template<typename T>
- static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl<T> &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr, bool has_this_capture = false) {
- chaiscript::detail::Dispatch_State state(t_ss);
- const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
- auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
- if (!stack.empty() && stack.back().first == "__this") {
- return &stack.back().second;
- } else if (!t_vals.empty()) {
- return &t_vals[0];
- } else {
- return nullptr;
- }
- }();
- chaiscript::eval::detail::Stack_Push_Pop tpp(state);
- if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); }
- if (t_locals) {
- for (const auto &local : *t_locals) {
- state.add_object(local.first, local.second);
- }
- }
- for (size_t i = 0; i < t_param_names.size(); ++i) {
- if (t_param_names[i] != "this") {
- state.add_object(t_param_names[i], t_vals[i]);
- }
- }
- try {
- return t_node.eval(state);
- } catch (detail::Return_Value &rv) {
- return std::move(rv.retval);
- }
- }
- }
- template<typename T>
- struct AST_Node_Impl : AST_Node
- {
- AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc,
- std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>())
- : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)),
- children(std::move(t_children))
- {
- }
- static bool get_scoped_bool_condition(const AST_Node_Impl<T> &node, const chaiscript::detail::Dispatch_State &t_ss) {
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- return get_bool_condition(node.eval(t_ss), t_ss);
- }
- std::vector<std::reference_wrapper<AST_Node>> get_children() const final {
- std::vector<std::reference_wrapper<AST_Node>> retval;
- retval.reserve(children.size());
- for (auto &&child : children) {
- retval.emplace_back(*child);
- }
- return retval;
- }
- Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final
- {
- try {
- T::trace(t_e, this);
- return eval_internal(t_e);
- } catch (exception::eval_error &ee) {
- ee.call_stack.push_back(*this);
- throw;
- }
- }
- std::vector<AST_Node_Impl_Ptr<T>> children;
- protected:
- virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
- {
- throw std::runtime_error("Undispatched ast_node (internal error)");
- }
- };
- template<typename T>
- struct Compiled_AST_Node : AST_Node_Impl<T> {
- Compiled_AST_Node(AST_Node_Impl_Ptr<T> t_original_node, std::vector<AST_Node_Impl_Ptr<T>> t_children,
- std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> t_func) :
- AST_Node_Impl<T>(t_original_node->text, AST_Node_Type::Compiled, t_original_node->location, std::move(t_children)),
- m_func(std::move(t_func)),
- m_original_node(std::move(t_original_node))
- { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- return m_func(this->children, t_ss);
- }
- std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func;
- AST_Node_Impl_Ptr<T> m_original_node;
- };
- template<typename T>
- struct Fold_Right_Binary_Operator_AST_Node : AST_Node_Impl<T> {
- Fold_Right_Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children, Boxed_Value t_rhs) :
- AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)),
- m_oper(Operators::to_operator(t_oper)),
- m_rhs(std::move(t_rhs))
- { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- return do_oper(t_ss, this->text, this->children[0]->eval(t_ss));
- }
- protected:
- Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss,
- const std::string &t_oper_string, const Boxed_Value &t_lhs) const
- {
- try {
- if (t_lhs.get_type_info().is_arithmetic())
- {
- // If it's an arithmetic operation we want to short circuit dispatch
- try{
- return Boxed_Number::do_oper(m_oper, t_lhs, m_rhs);
- } catch (const chaiscript::exception::arithmetic_error &) {
- throw;
- } catch (...) {
- throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
- }
- } else {
- chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
- fpp.save_params({t_lhs, m_rhs});
- return t_ss->call_function(t_oper_string, m_loc, {t_lhs, m_rhs}, t_ss.conversions());
- }
- }
- catch(const exception::dispatch_error &e){
- throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
- }
- }
- private:
- Operators::Opers m_oper;
- Boxed_Value m_rhs;
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Binary_Operator_AST_Node : AST_Node_Impl<T> {
- Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)),
- m_oper(Operators::to_operator(t_oper))
- { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- auto lhs = this->children[0]->eval(t_ss);
- auto rhs = this->children[1]->eval(t_ss);
- return do_oper(t_ss, m_oper, this->text, lhs, rhs);
- }
- protected:
- Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss,
- Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const
- {
- try {
- if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic())
- {
- // If it's an arithmetic operation we want to short circuit dispatch
- try{
- return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
- } catch (const chaiscript::exception::arithmetic_error &) {
- throw;
- } catch (...) {
- throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
- }
- } else {
- chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
- fpp.save_params({t_lhs, t_rhs});
- return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}, t_ss.conversions());
- }
- }
- catch(const exception::dispatch_error &e){
- throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
- }
- }
- private:
- Operators::Opers m_oper;
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Constant_AST_Node final : AST_Node_Impl<T> {
- Constant_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_value)
- : AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)),
- m_value(std::move(t_value))
- {
- }
- explicit Constant_AST_Node(Boxed_Value t_value)
- : AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()),
- m_value(std::move(t_value))
- {
- }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override {
- return m_value;
- }
- Boxed_Value m_value;
- };
- template<typename T>
- struct Id_AST_Node final : AST_Node_Impl<T> {
- Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) :
- AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc))
- { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- try {
- return t_ss.get_object(this->text, m_loc);
- }
- catch (std::exception &) {
- throw exception::eval_error("Can not find object: " + this->text);
- }
- }
- private:
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Fun_Call_AST_Node : AST_Node_Impl<T> {
- Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) {
- assert(!this->children.empty());
- }
- template<bool Save_Params>
- Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const
- {
- chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
- std::vector<Boxed_Value> params;
- params.reserve(this->children[1]->children.size());
- for (const auto &child : this->children[1]->children) {
- params.push_back(child->eval(t_ss));
- }
- if (Save_Params) {
- fpp.save_params(params);
- }
- Boxed_Value fn(this->children[0]->eval(t_ss));
- try {
- return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(params, t_ss.conversions());
- }
- catch(const exception::dispatch_error &e){
- throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
- }
- catch(const exception::bad_boxed_cast &){
- try {
- Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
- // handle the case where there is only 1 function to try to call and dispatch fails on it
- throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
- } catch (const exception::bad_boxed_cast &) {
- throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
- }
- }
- catch(const exception::arity_error &e){
- throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
- }
- catch(const exception::guard_error &e){
- throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
- }
- catch(detail::Return_Value &rv) {
- return rv.retval;
- }
- }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
- {
- return do_eval_internal<true>(t_ss);
- }
- };
- template<typename T>
- struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node<T> {
- Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- Fun_Call_AST_Node<T>(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
- {
- return this->template do_eval_internal<false>(t_ss);
- }
- };
- template<typename T>
- struct Arg_AST_Node final : AST_Node_Impl<T> {
- Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
- };
- template<typename T>
- struct Arg_List_AST_Node final : AST_Node_Impl<T> {
- Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
- static std::string get_arg_name(const AST_Node_Impl<T> &t_node) {
- if (t_node.children.empty())
- {
- return t_node.text;
- } else if (t_node.children.size() == 1) {
- return t_node.children[0]->text;
- } else {
- return t_node.children[1]->text;
- }
- }
- static std::vector<std::string> get_arg_names(const AST_Node_Impl<T> &t_node) {
- std::vector<std::string> retval;
- for (const auto &node : t_node.children)
- {
- retval.push_back(get_arg_name(*node));
- }
- return retval;
- }
- static std::pair<std::string, Type_Info> get_arg_type(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss)
- {
- if (t_node.children.size() < 2)
- {
- return {};
- } else {
- return {t_node.children[0]->text, t_ss->get_type(t_node.children[0]->text, false)};
- }
- }
- static dispatch::Param_Types get_arg_types(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
- std::vector<std::pair<std::string, Type_Info>> retval;
- for (const auto &child : t_node.children)
- {
- retval.push_back(get_arg_type(*child, t_ss));
- }
- return dispatch::Param_Types(std::move(retval));
- }
- };
- template<typename T>
- struct Equation_AST_Node final : AST_Node_Impl<T> {
- Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)),
- m_oper(Operators::to_operator(this->text))
- { assert(this->children.size() == 2); }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
- Boxed_Value rhs = this->children[1]->eval(t_ss);
- Boxed_Value lhs = this->children[0]->eval(t_ss);
- if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() &&
- rhs.get_type_info().is_arithmetic())
- {
- try {
- return Boxed_Number::do_oper(m_oper, lhs, rhs);
- } catch (const std::exception &) {
- throw exception::eval_error("Error with unsupported arithmetic assignment operation");
- }
- } else if (m_oper == Operators::Opers::assign) {
- if (lhs.is_return_value()) {
- throw exception::eval_error("Error, cannot assign to temporary value.");
- }
- try {
- if (lhs.is_undef()) {
- if (!this->children.empty()
- && ((this->children[0]->identifier == AST_Node_Type::Reference)
- || (!this->children[0]->children.empty()
- && this->children[0]->children[0]->identifier == AST_Node_Type::Reference)
- )
- )
-
- {
- /// \todo This does not handle the case of an unassigned reference variable
- /// being assigned outside of its declaration
- lhs.assign(rhs);
- lhs.reset_return_value();
- return rhs;
- } else {
- if (!rhs.is_return_value())
- {
- rhs = t_ss->call_function("clone", m_clone_loc, {rhs}, t_ss.conversions());
- }
- rhs.reset_return_value();
- }
- }
- try {
- return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
- }
- catch(const exception::dispatch_error &e){
- throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
- }
- }
- catch(const exception::dispatch_error &e){
- throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss);
- }
- }
- else if (this->text == ":=") {
- if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
- lhs.assign(rhs);
- lhs.reset_return_value();
- } else {
- throw exception::eval_error("Mismatched types in equation");
- }
- }
- else {
- try {
- return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
- } catch(const exception::dispatch_error &e){
- throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
- }
- }
- return rhs;
- }
- private:
- Operators::Opers m_oper;
- mutable std::atomic_uint_fast32_t m_loc = {0};
- mutable std::atomic_uint_fast32_t m_clone_loc = {0};
- };
- template<typename T>
- struct Global_Decl_AST_Node final : AST_Node_Impl<T> {
- Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- const std::string &idname =
- [&]()->const std::string & {
- if (this->children[0]->identifier == AST_Node_Type::Reference) {
- return this->children[0]->children[0]->text;
- } else {
- return this->children[0]->text;
- }
- }();
- return t_ss->add_global_no_throw(Boxed_Value(), idname);
- }
- };
- template<typename T>
- struct Var_Decl_AST_Node final : AST_Node_Impl<T> {
- Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- const std::string &idname = this->children[0]->text;
- try {
- Boxed_Value bv;
- t_ss.add_object(idname, bv);
- return bv;
- } catch (const exception::name_conflict_error &e) {
- throw exception::eval_error("Variable redefined '" + e.name() + "'");
- }
- }
- };
- template<typename T>
- struct Array_Call_AST_Node final : AST_Node_Impl<T> {
- Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
- const std::vector<Boxed_Value> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
- try {
- fpp.save_params(params);
- return t_ss->call_function("[]", m_loc, params, t_ss.conversions());
- }
- catch(const exception::dispatch_error &e){
- throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss );
- }
- }
- private:
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Dot_Access_AST_Node final : AST_Node_Impl<T> {
- Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)),
- m_fun_name(
- ((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call))?
- this->children[1]->children[0]->text:this->children[1]->text) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
- Boxed_Value retval = this->children[0]->eval(t_ss);
- std::vector<Boxed_Value> params{retval};
- bool has_function_params = false;
- if (this->children[1]->children.size() > 1) {
- has_function_params = true;
- for (const auto &child : this->children[1]->children[1]->children) {
- params.push_back(child->eval(t_ss));
- }
- }
- fpp.save_params(params);
- try {
- retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params, t_ss.conversions());
- }
- catch(const exception::dispatch_error &e){
- if (e.functions.empty())
- {
- throw exception::eval_error("'" + m_fun_name + "' is not a function.");
- } else {
- throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss);
- }
- }
- catch(detail::Return_Value &rv) {
- retval = std::move(rv.retval);
- }
- if (this->children[1]->identifier == AST_Node_Type::Array_Call) {
- try {
- retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[1]->children[1]->eval(t_ss)}, t_ss.conversions());
- }
- catch(const exception::dispatch_error &e){
- throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
- }
- }
- return retval;
- }
- private:
- mutable std::atomic_uint_fast32_t m_loc = {0};
- mutable std::atomic_uint_fast32_t m_array_loc = {0};
- const std::string m_fun_name;
- };
- template<typename T>
- struct Lambda_AST_Node final : AST_Node_Impl<T> {
- Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(t_ast_node_text,
- AST_Node_Type::Lambda,
- std::move(t_loc),
- std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
- std::make_move_iterator(std::prev(t_children.end())))
- ),
- m_param_names(Arg_List_AST_Node<T>::get_arg_names(*this->children[1])),
- m_this_capture(has_this_capture(this->children[0]->children)),
- m_lambda_node(std::move(t_children.back()))
- { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- const auto captures = [&]()->std::map<std::string, Boxed_Value>{
- std::map<std::string, Boxed_Value> named_captures;
- for (const auto &capture : this->children[0]->children) {
- named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
- }
- return named_captures;
- }();
- const auto numparams = this->children[1]->children.size();
- const auto param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
- std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
- return Boxed_Value(
- dispatch::make_dynamic_proxy_function(
- [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures,
- this_capture = this->m_this_capture] (const std::vector<Boxed_Value> &t_params)
- {
- return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture);
- },
- static_cast<int>(numparams), m_lambda_node, param_types
- )
- );
- }
- static bool has_this_capture(const std::vector<AST_Node_Impl_Ptr<T>> &children) {
- return std::any_of(std::begin(children), std::end(children),
- [](const auto &child){
- return child->children[0]->text == "this";
- }
- );
- }
- private:
- const std::vector<std::string> m_param_names;
- const bool m_this_capture = false;
- const std::shared_ptr<AST_Node_Impl<T>> m_lambda_node;
- };
- template<typename T>
- struct Scopeless_Block_AST_Node final : AST_Node_Impl<T> {
- Scopeless_Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Scopeless_Block, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- const auto num_children = this->children.size();
- for (size_t i = 0; i < num_children-1; ++i) {
- this->children[i]->eval(t_ss);
- }
- return this->children.back()->eval(t_ss);
- }
- };
- template<typename T>
- struct Block_AST_Node final : AST_Node_Impl<T> {
- Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- const auto num_children = this->children.size();
- for (size_t i = 0; i < num_children-1; ++i) {
- this->children[i]->eval(t_ss);
- }
- return this->children.back()->eval(t_ss);
- }
- };
- template<typename T>
- struct Def_AST_Node final : AST_Node_Impl<T> {
- std::shared_ptr<AST_Node_Impl<T>> m_body_node;
- std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
- Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc),
- std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
- std::make_move_iterator(std::prev(t_children.end(), has_guard(t_children, 1)?2:1)))
- ),
- m_body_node(get_body_node(std::move(t_children))),
- m_guard_node(get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
- { }
- static std::shared_ptr<AST_Node_Impl<T>> get_guard_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec, bool has_guard)
- {
- if (has_guard) {
- return std::move(*std::prev(vec.end(), 2));
- } else {
- return {};
- }
- }
- static std::shared_ptr<AST_Node_Impl<T>> get_body_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec)
- {
- return std::move(vec.back());
- }
- static bool has_guard(const std::vector<AST_Node_Impl_Ptr<T>> &t_children, const std::size_t offset)
- {
- if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) {
- if (t_children.size() > 3 + offset) {
- return true;
- }
- }
- else {
- if (t_children.size() > 2 + offset) {
- return true;
- }
- }
- return false;
- }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- std::vector<std::string> t_param_names;
- size_t numparams = 0;
- dispatch::Param_Types param_types;
- if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
- numparams = this->children[1]->children.size();
- t_param_names = Arg_List_AST_Node<T>::get_arg_names(*this->children[1]);
- param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
- }
- std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
- std::shared_ptr<dispatch::Proxy_Function_Base> guard;
- if (m_guard_node) {
- guard = dispatch::make_dynamic_proxy_function(
- [engine, guardnode = m_guard_node, t_param_names](const std::vector<Boxed_Value> &t_params)
- {
- return detail::eval_function(engine, *guardnode, t_param_names, t_params);
- },
- static_cast<int>(numparams), m_guard_node);
- }
- try {
- const std::string & l_function_name = this->children[0]->text;
- t_ss->add(
- dispatch::make_dynamic_proxy_function(
- [engine, func_node = m_body_node, t_param_names](const std::vector<Boxed_Value> &t_params)
- {
- return detail::eval_function(engine, *func_node, t_param_names, t_params);
- },
- static_cast<int>(numparams), m_body_node,
- param_types, guard), l_function_name);
- } catch (const exception::name_conflict_error &e) {
- throw exception::eval_error("Function redefined '" + e.name() + "'");
- }
- return void_var();
- }
- };
- template<typename T>
- struct While_AST_Node final : AST_Node_Impl<T> {
- While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- try {
- while (this->get_scoped_bool_condition(*this->children[0], t_ss)) {
- try {
- this->children[1]->eval(t_ss);
- } catch (detail::Continue_Loop &) {
- // we got a continue exception, which means all of the remaining
- // loop implementation is skipped and we just need to continue to
- // the next condition test
- }
- }
- } catch (detail::Break_Loop &) {
- // loop was broken intentionally
- }
- return void_var();
- }
- };
- template<typename T>
- struct Class_AST_Node final : AST_Node_Impl<T> {
- Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- /// \todo do this better
- // put class name in current scope so it can be looked up by the attrs and methods
- t_ss.add_object("_current_class_name", const_var(this->children[0]->text));
- this->children[1]->eval(t_ss);
- return void_var();
- }
- };
- template<typename T>
- struct If_AST_Node final : AST_Node_Impl<T> {
- If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children))
- {
- assert(this->children.size() == 3);
- }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) {
- return this->children[1]->eval(t_ss);
- } else {
- return this->children[2]->eval(t_ss);
- }
- }
- };
- template<typename T>
- struct Ranged_For_AST_Node final : AST_Node_Impl<T> {
- Ranged_For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Ranged_For, std::move(t_loc), std::move(t_children))
- { assert(this->children.size() == 3); }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){
- uint_fast32_t hint = t_hint;
- auto funs = t_ss->get_function(t_name, hint);
- if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); }
- return std::move(funs.second);
- };
- const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) {
- return dispatch::dispatch(*t_funcs, {t_param}, t_ss.conversions());
- };
- const std::string &loop_var_name = this->children[0]->text;
- Boxed_Value range_expression_result = this->children[1]->eval(t_ss);
- const auto do_loop = [&loop_var_name, &t_ss, this](const auto &ranged_thing){
- try {
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var());
- for (auto loop_var : ranged_thing) {
- obj = Boxed_Value(std::move(loop_var));
- try {
- this->children[2]->eval(t_ss);
- } catch (detail::Continue_Loop &) {
- }
- }
- } catch (detail::Break_Loop &) {
- // loop broken
- }
- return void_var();
- };
- if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::vector<Boxed_Value>))) {
- return do_loop(boxed_cast<const std::vector<Boxed_Value> &>(range_expression_result));
- } else if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::map<std::string, Boxed_Value>))) {
- return do_loop(boxed_cast<const std::map<std::string, Boxed_Value> &>(range_expression_result));
- } else {
- const auto range_funcs = get_function("range", m_range_loc);
- const auto empty_funcs = get_function("empty", m_empty_loc);
- const auto front_funcs = get_function("front", m_front_loc);
- const auto pop_front_funcs = get_function("pop_front", m_pop_front_loc);
- try {
- const auto range_obj = call_function(range_funcs, range_expression_result);
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var());
- while (!boxed_cast<bool>(call_function(empty_funcs, range_obj))) {
- obj = call_function(front_funcs, range_obj);
- try {
- this->children[2]->eval(t_ss);
- } catch (detail::Continue_Loop &) {
- }
- call_function(pop_front_funcs, range_obj);
- }
- } catch (detail::Break_Loop &) {
- // loop broken
- }
- return void_var();
- }
- }
- private:
- mutable std::atomic_uint_fast32_t m_range_loc = {0};
- mutable std::atomic_uint_fast32_t m_empty_loc = {0};
- mutable std::atomic_uint_fast32_t m_front_loc = {0};
- mutable std::atomic_uint_fast32_t m_pop_front_loc = {0};
- };
- template<typename T>
- struct For_AST_Node final : AST_Node_Impl<T> {
- For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children))
- { assert(this->children.size() == 4); }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- try {
- for (
- this->children[0]->eval(t_ss);
- this->get_scoped_bool_condition(*this->children[1], t_ss);
- this->children[2]->eval(t_ss)
- ) {
- try {
- // Body of Loop
- this->children[3]->eval(t_ss);
- } catch (detail::Continue_Loop &) {
- // we got a continue exception, which means all of the remaining
- // loop implementation is skipped and we just need to continue to
- // the next iteration step
- }
- }
- } catch (detail::Break_Loop &) {
- // loop broken
- }
- return void_var();
- }
- };
- template<typename T>
- struct Switch_AST_Node final : AST_Node_Impl<T> {
- Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- bool breaking = false;
- size_t currentCase = 1;
- bool hasMatched = false;
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- Boxed_Value match_value(this->children[0]->eval(t_ss));
- while (!breaking && (currentCase < this->children.size())) {
- try {
- if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
- //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
- try {
- if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}, t_ss.conversions()))) {
- this->children[currentCase]->eval(t_ss);
- hasMatched = true;
- }
- }
- catch (const exception::bad_boxed_cast &) {
- throw exception::eval_error("Internal error: case guard evaluation not boolean");
- }
- }
- else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
- this->children[currentCase]->eval(t_ss);
- hasMatched = true;
- }
- }
- catch (detail::Break_Loop &) {
- breaking = true;
- }
- ++currentCase;
- }
- return void_var();
- }
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Case_AST_Node final : AST_Node_Impl<T> {
- Case_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children))
- { assert(this->children.size() == 2); /* how many children does it have? */ }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- this->children[1]->eval(t_ss);
- return void_var();
- }
- };
-
- template<typename T>
- struct Default_AST_Node final : AST_Node_Impl<T> {
- Default_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children))
- { assert(this->children.size() == 1); }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- this->children[0]->eval(t_ss);
- return void_var();
- }
- };
- template<typename T>
- struct Inline_Array_AST_Node final : AST_Node_Impl<T> {
- Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- try {
- std::vector<Boxed_Value> vec;
- if (!this->children.empty()) {
- vec.reserve(this->children[0]->children.size());
- for (const auto &child : this->children[0]->children) {
- auto obj = child->eval(t_ss);
- if (!obj.is_return_value()) {
- vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()));
- } else {
- vec.push_back(std::move(obj));
- }
- }
- }
- return const_var(std::move(vec));
- }
- catch (const exception::dispatch_error &) {
- throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements");
- }
- }
- private:
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Inline_Map_AST_Node final : AST_Node_Impl<T> {
- Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
- {
- try {
- std::map<std::string, Boxed_Value> retval;
- for (const auto &child : this->children[0]->children) {
- auto obj = child->children[1]->eval(t_ss);
- if (!obj.is_return_value()) {
- obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions());
- }
- retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
- }
- return const_var(std::move(retval));
- }
- catch (const exception::dispatch_error &e) {
- throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss);
- }
- }
- private:
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Return_AST_Node final : AST_Node_Impl<T> {
- Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- if (!this->children.empty()) {
- throw detail::Return_Value(this->children[0]->eval(t_ss));
- }
- else {
- throw detail::Return_Value(void_var());
- }
- }
- };
- template<typename T>
- struct File_AST_Node final : AST_Node_Impl<T> {
- File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- try {
- const auto num_children = this->children.size();
- if (num_children > 0) {
- for (size_t i = 0; i < num_children-1; ++i) {
- this->children[i]->eval(t_ss);
- }
- return this->children.back()->eval(t_ss);
- } else {
- return void_var();
- }
- } catch (const detail::Continue_Loop &) {
- throw exception::eval_error("Unexpected `continue` statement outside of a loop");
- } catch (const detail::Break_Loop &) {
- throw exception::eval_error("Unexpected `break` statement outside of a loop");
- }
- }
- };
- template<typename T>
- struct Reference_AST_Node final : AST_Node_Impl<T> {
- Reference_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children))
- { assert(this->children.size() == 1); }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- Boxed_Value bv;
- t_ss.add_object(this->children[0]->text, bv);
- return bv;
- }
- };
- template<typename T>
- struct Prefix_AST_Node final : AST_Node_Impl<T> {
- Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)),
- m_oper(Operators::to_operator(this->text, true))
- { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- Boxed_Value bv(this->children[0]->eval(t_ss));
- try {
- // short circuit arithmetic operations
- if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic())
- {
- return Boxed_Number::do_oper(m_oper, bv);
- } else {
- chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
- fpp.save_params({bv});
- return t_ss->call_function(this->text, m_loc, {std::move(bv)}, t_ss.conversions());
- }
- } catch (const exception::dispatch_error &e) {
- throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss);
- }
- }
- private:
- Operators::Opers m_oper = Operators::Opers::invalid;
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Break_AST_Node final : AST_Node_Impl<T> {
- Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
- throw detail::Break_Loop();
- }
- };
- template<typename T>
- struct Continue_AST_Node final : AST_Node_Impl<T> {
- Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
- throw detail::Continue_Loop();
- }
- };
- template<typename T>
- struct Noop_AST_Node final : AST_Node_Impl<T> {
- Noop_AST_Node() :
- AST_Node_Impl<T>("", AST_Node_Type::Noop, Parse_Location())
- { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
- // It's a no-op, that evaluates to "void"
- return val;
- }
- Boxed_Value val = void_var();
- };
- template<typename T>
- struct Map_Pair_AST_Node final : AST_Node_Impl<T> {
- Map_Pair_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) { }
- };
- template<typename T>
- struct Value_Range_AST_Node final : AST_Node_Impl<T> {
- Value_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) { }
- };
- template<typename T>
- struct Inline_Range_AST_Node final : AST_Node_Impl<T> {
- Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- try {
- auto oper1 = this->children[0]->children[0]->children[0]->eval(t_ss);
- auto oper2 = this->children[0]->children[0]->children[1]->eval(t_ss);
- return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions());
- }
- catch (const exception::dispatch_error &e) {
- throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss);
- }
- }
- private:
- mutable std::atomic_uint_fast32_t m_loc = {0};
- };
- template<typename T>
- struct Try_AST_Node final : AST_Node_Impl<T> {
- Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const
- {
- Boxed_Value retval;
- size_t end_point = this->children.size();
- if (this->children.back()->identifier == AST_Node_Type::Finally) {
- assert(end_point > 0);
- end_point = this->children.size() - 1;
- }
- for (size_t i = 1; i < end_point; ++i) {
- chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss);
- auto &catch_block = *this->children[i];
- if (catch_block.children.size() == 1) {
- //No variable capture, no guards
- retval = catch_block.children[0]->eval(t_ss);
- break;
- } else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) {
- const auto name = Arg_List_AST_Node<T>::get_arg_name(*catch_block.children[0]);
- if (dispatch::Param_Types(
- std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)}
- ).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()).first)
- {
- t_ss.add_object(name, t_except);
- if (catch_block.children.size() == 2) {
- //Variable capture, no guards
- retval = catch_block.children[1]->eval(t_ss);
- break;
- }
- else if (catch_block.children.size() == 3) {
- //Variable capture, guards
- bool guard = false;
- try {
- guard = boxed_cast<bool>(catch_block.children[1]->eval(t_ss));
- } catch (const exception::bad_boxed_cast &) {
- if (this->children.back()->identifier == AST_Node_Type::Finally) {
- this->children.back()->children[0]->eval(t_ss);
- }
- throw exception::eval_error("Guard condition not boolean");
- }
- if (guard) {
- retval = catch_block.children[2]->eval(t_ss);
- break;
- }
- }
- }
- }
- else {
- if (this->children.back()->identifier == AST_Node_Type::Finally) {
- this->children.back()->children[0]->eval(t_ss);
- }
- throw exception::eval_error("Internal error: catch block size unrecognized");
- }
- }
- return retval;
- }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
- Boxed_Value retval;
- chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
- try {
- retval = this->children[0]->eval(t_ss);
- }
- catch (const exception::eval_error &e) {
- retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
- }
- catch (const std::runtime_error &e) {
- retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
- }
- catch (const std::out_of_range &e) {
- retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
- }
- catch (const std::exception &e) {
- retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
- }
- catch (Boxed_Value &e) {
- retval = handle_exception(t_ss, e);
- }
- catch (...) {
- if (this->children.back()->identifier == AST_Node_Type::Finally) {
- this->children.back()->children[0]->eval(t_ss);
- }
- throw;
- }
- if (this->children.back()->identifier == AST_Node_Type::Finally) {
- retval = this->children.back()->children[0]->eval(t_ss);
- }
- return retval;
- }
- };
- template<typename T>
- struct Catch_AST_Node final : AST_Node_Impl<T> {
- Catch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) { }
- };
- template<typename T>
- struct Finally_AST_Node final : AST_Node_Impl<T> {
- Finally_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) { }
- };
- template<typename T>
- struct Method_AST_Node final : AST_Node_Impl<T> {
- std::shared_ptr<AST_Node_Impl<T>> m_body_node;
- std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
- Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc),
- std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
- std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node<T>::has_guard(t_children, 1)?2:1)))
- ),
- m_body_node(Def_AST_Node<T>::get_body_node(std::move(t_children))),
- m_guard_node(Def_AST_Node<T>::get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
- {
- }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
- AST_Node_Impl_Ptr<T> guardnode;
- const std::string & class_name = this->children[0]->text;
- //The first param of a method is always the implied this ptr.
- std::vector<std::string> t_param_names{"this"};
- dispatch::Param_Types param_types;
- if ((this->children.size() > 2)
- && (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
- auto args = Arg_List_AST_Node<T>::get_arg_names(*this->children[2]);
- t_param_names.insert(t_param_names.end(), args.begin(), args.end());
- param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[2], t_ss);
- }
- const size_t numparams = t_param_names.size();
- std::shared_ptr<dispatch::Proxy_Function_Base> guard;
- std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
- if (m_guard_node) {
- guard = dispatch::make_dynamic_proxy_function(
- [engine, t_param_names, guardnode = m_guard_node](const std::vector<Boxed_Value> &t_params) {
- return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params);
- },
- static_cast<int>(numparams), m_guard_node);
- }
- try {
- const std::string & function_name = this->children[1]->text;
- if (function_name == class_name) {
- param_types.push_front(class_name, Type_Info());
- t_ss->add(
- std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
- dispatch::make_dynamic_proxy_function(
- [engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
- return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
- },
- static_cast<int>(numparams), m_body_node, param_types, guard
- )
- ),
- function_name);
- } else {
- // if the type is unknown, then this generates a function that looks up the type
- // at runtime. Defining the type first before this is called is better
- auto type = t_ss->get_type(class_name, false);
- param_types.push_front(class_name, type);
- t_ss->add(
- std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
- dispatch::make_dynamic_proxy_function(
- [engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
- return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
- },
- static_cast<int>(numparams), m_body_node, param_types, guard), type),
- function_name);
- }
- } catch (const exception::name_conflict_error &e) {
- std::cout << "Method!!" << std::endl;
- throw exception::eval_error("Method redefined '" + e.name() + "'");
- }
- return void_var();
- }
- };
- template<typename T>
- struct Attr_Decl_AST_Node final : AST_Node_Impl<T> {
- Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
- {
- std::string class_name = this->children[0]->text;
- try {
- std::string attr_name = this->children[1]->text;
- t_ss->add(
- std::make_shared<dispatch::detail::Dynamic_Object_Function>(
- std::move(class_name),
- fun([attr_name](dispatch::Dynamic_Object &t_obj) {
- return t_obj.get_attr(attr_name);
- }),
- true
- ), this->children[1]->text);
- } catch (const exception::name_conflict_error &e) {
- throw exception::eval_error("Attribute redefined '" + e.name() + "'");
- }
- return void_var();
- }
- };
- template<typename T>
- struct Logical_And_AST_Node final : AST_Node_Impl<T> {
- Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children))
- { assert(this->children.size() == 2); }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
- {
- return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
- && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
- }
- };
- template<typename T>
- struct Logical_Or_AST_Node final : AST_Node_Impl<T> {
- Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
- AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children))
- { assert(this->children.size() == 2); }
- Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
- {
- return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
- || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
- }
- };
- }
- }
- #endif /* CHAISCRIPT_EVAL_HPP_ */
|