diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 742be5a..e7263ba 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -82,10 +82,11 @@ namespace chaiscript } struct Compiled_AST_Node : AST_Node { - Compiled_AST_Node(std::string t_text, Parse_Location t_loc, std::vector t_children, + Compiled_AST_Node(AST_NodePtr t_original_node, std::vector t_children, std::function &, const chaiscript::detail::Dispatch_State &t_ss)> t_func) : - AST_Node(std::move(t_text), AST_Node_Type::Compiled, std::move(t_loc), std::move(t_children)), - m_func(std::move(t_func)) + AST_Node(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 { @@ -93,6 +94,7 @@ namespace chaiscript } std::function &, const chaiscript::detail::Dispatch_State &t_ss)> m_func; + AST_NodePtr m_original_node; }; struct Binary_Operator_AST_Node : AST_Node { @@ -170,7 +172,6 @@ namespace chaiscript } private: - mutable std::atomic_uint_fast32_t m_loc; }; diff --git a/include/chaiscript/language/chaiscript_optimizer.hpp b/include/chaiscript/language/chaiscript_optimizer.hpp new file mode 100644 index 0000000..8d1173b --- /dev/null +++ b/include/chaiscript/language/chaiscript_optimizer.hpp @@ -0,0 +1,120 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_OPTIMIZER_HPP_ +#define CHAISCRIPT_OPTIMIZER_HPP_ + +#include "chaiscript_eval.hpp" + + +namespace chaiscript { + namespace optimizer { + + + template + auto child_at(const T &node, const size_t offset) { + if (node->identifier == AST_Node_Type::Compiled) { + return dynamic_cast(*node).m_original_node->children[offset]; + } else { + return node->children[offset]; + } + } + + template + auto child_count(const T &node) { + if (node->identifier == AST_Node_Type::Compiled) { + return dynamic_cast(*node).m_original_node->children.size(); + } else { + return node->children.size(); + } + } + + template + AST_NodePtr make_compiled_node(const AST_NodePtr &original_node, std::vector children, T callable) + { + return chaiscript::make_shared(original_node, children, std::move(callable)); + } + + struct For_Loop_Optimizer { + AST_NodePtr optimize(const AST_NodePtr &for_node) { + + if (for_node->identifier != AST_Node_Type::For) { + return for_node; + } + + const auto eq_node = child_at(for_node, 0); + const auto binary_node = child_at(for_node, 1); + const auto prefix_node = child_at(for_node, 2); + + if (eq_node->identifier == AST_Node_Type::Equation + && child_count(eq_node) == 2 + && child_at(eq_node, 0)->identifier == AST_Node_Type::Var_Decl + && child_at(eq_node, 1)->identifier == AST_Node_Type::Constant + && binary_node->identifier == AST_Node_Type::Binary + && binary_node->text == "<" + && child_count(binary_node) == 2 + && child_at(binary_node, 0)->identifier == AST_Node_Type::Id + && child_at(binary_node, 0)->text == child_at(child_at(eq_node,0), 0)->text + && child_at(binary_node, 1)->identifier == AST_Node_Type::Constant + && prefix_node->identifier == AST_Node_Type::Prefix + && prefix_node->text == "++" + && child_count(prefix_node) == 1 + && child_at(prefix_node, 0)->identifier == AST_Node_Type::Id + && child_at(prefix_node, 0)->text == child_at(child_at(eq_node,0), 0)->text) + { + const Boxed_Value &begin = std::dynamic_pointer_cast(child_at(eq_node, 1))->m_value; + const Boxed_Value &end = std::dynamic_pointer_cast(child_at(binary_node, 1))->m_value; + const std::string &id = child_at(prefix_node, 0)->text; + + if (begin.get_type_info().bare_equal(user_type()) + && end.get_type_info().bare_equal(user_type())) { + + const auto start_int = boxed_cast(begin); + const auto end_int = boxed_cast(end); + + const auto body = child_at(for_node, 3); + + return make_compiled_node(for_node, {body}, + [id, start_int, end_int](const std::vector &children, const chaiscript::detail::Dispatch_State &t_ss) { + assert(children.size() == 1); + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + + int i = start_int; + t_ss.add_object(id, var(&i)); + + try { + for (; i < end_int; ++i) { + try { + // Body of Loop + children[0]->eval(t_ss); + } catch (eval::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 (eval::detail::Break_Loop &) { + // loop broken + } + + return void_var(); + } + ); + } else { + return for_node; + } + } else { + return for_node; + } + } + }; + + + } +} + + +#endif diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index fa009b4..e1597a8 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -20,7 +20,7 @@ #include "../dispatchkit/boxed_value.hpp" #include "chaiscript_common.hpp" - +#include "chaiscript_optimizer.hpp" #if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min) #pragma push_macro("max") // Why Microsoft? why? This is worse than bad @@ -276,8 +276,11 @@ namespace chaiscript Position m_position; + optimizer::For_Loop_Optimizer m_optimizer; + public: ChaiScript_Parser() + : m_optimizer(optimizer::For_Loop_Optimizer()) { m_match_stack.reserve(2); } @@ -368,10 +371,12 @@ namespace chaiscript /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position m_match_stack.push_back( - chaiscript::make_shared( - std::move(t_text), - std::move(filepos), - std::move(new_children))); + m_optimizer.optimize( + chaiscript::make_shared( + std::move(t_text), + std::move(filepos), + std::move(new_children))) + ); } @@ -1687,56 +1692,6 @@ namespace chaiscript } - auto standard_for_loop(const size_t t_prev_top) { - assert(t_prev_top = m_match_stack.size() - 4); - - struct Result { - Result(const bool t_is, std::string t_id, const int t_start, const int t_stop) - : is_standard(t_is), id(std::move(t_id)), start(t_start), stop(t_stop) {} - Result() = default; - bool is_standard = false; - std::string id = ""; - int start = 0; - int stop = 0; - }; - - const auto eq_node = m_match_stack.at(t_prev_top); - const auto binary_node = m_match_stack.at(t_prev_top+1); - const auto prefix_node = m_match_stack.at(t_prev_top+2); - - if (eq_node->identifier == AST_Node_Type::Equation - && eq_node->children.size() == 2 - && eq_node->children[0]->identifier == AST_Node_Type::Var_Decl - && eq_node->children[1]->identifier == AST_Node_Type::Constant - && binary_node->identifier == AST_Node_Type::Binary - && binary_node->children.size() == 2 - && binary_node->text == "<" - && binary_node->children[0]->identifier == AST_Node_Type::Id - && binary_node->children[0]->text == eq_node->children[0]->children.at(0)->text - && binary_node->children[1]->identifier == AST_Node_Type::Constant - && prefix_node->identifier == AST_Node_Type::Prefix - && prefix_node->children.size() == 1 - && prefix_node->text == "++" - && prefix_node->children[0]->identifier == AST_Node_Type::Id - && prefix_node->children[0]->text == eq_node->children[0]->children.at(0)->text) - { - const Boxed_Value &begin = std::dynamic_pointer_cast(eq_node->children[1])->m_value; - const Boxed_Value &end = std::dynamic_pointer_cast(binary_node->children[1])->m_value; - const std::string &id = prefix_node->children[0]->text; - - if (begin.get_type_info().bare_equal(user_type()) - && end.get_type_info().bare_equal(user_type())) { - return Result(true, id, boxed_cast(begin), boxed_cast(end)); - } else { - return Result(); - } - } else { - return Result(); - } - } - - - /// Reads a for block from input bool For() { bool retval = false; @@ -1760,48 +1715,7 @@ namespace chaiscript throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename); } - const auto for_loop_params = standard_for_loop(prev_stack_top); - if (for_loop_params.is_standard) { - const auto body = m_match_stack.back(); - const auto start = m_match_stack[prev_stack_top]->location; - m_match_stack.pop_back(); - m_match_stack.pop_back(); - m_match_stack.pop_back(); - m_match_stack.pop_back(); - - m_match_stack.push_back( - make_node(std::string(), start.start.line, start.start.column, std::vector({body}), - - [for_loop_params](const std::vector &children, const chaiscript::detail::Dispatch_State &t_ss) { - assert(children.size() == 1); - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - - int i = for_loop_params.start; - t_ss.add_object(for_loop_params.id, var(&i)); - - try { - for (; i < for_loop_params.stop; ++i) { - try { - // Body of Loop - children[0]->eval(t_ss); - } catch (eval::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 (eval::detail::Break_Loop &) { - // loop broken - } - - return void_var(); - } - ) - ); - - } else { - build_match(prev_stack_top); - } + build_match(prev_stack_top); } return retval;