Make optimizer split out
This commit is contained in:
parent
25575564c0
commit
ff2ab6bb8d
@ -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<AST_NodePtr> t_children,
|
||||
Compiled_AST_Node(AST_NodePtr t_original_node, std::vector<AST_NodePtr> t_children,
|
||||
std::function<Boxed_Value (const std::vector<AST_NodePtr> &, 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<Boxed_Value (const std::vector<AST_NodePtr> &, 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;
|
||||
};
|
||||
|
||||
|
120
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
120
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
@ -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<typename T>
|
||||
auto child_at(const T &node, const size_t offset) {
|
||||
if (node->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node&>(*node).m_original_node->children[offset];
|
||||
} else {
|
||||
return node->children[offset];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto child_count(const T &node) {
|
||||
if (node->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node&>(*node).m_original_node->children.size();
|
||||
} else {
|
||||
return node->children.size();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
AST_NodePtr make_compiled_node(const AST_NodePtr &original_node, std::vector<AST_NodePtr> children, T callable)
|
||||
{
|
||||
return chaiscript::make_shared<AST_Node, eval::Compiled_AST_Node>(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<const eval::Constant_AST_Node>(child_at(eq_node, 1))->m_value;
|
||||
const Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node>(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<int>())
|
||||
&& end.get_type_info().bare_equal(user_type<int>())) {
|
||||
|
||||
const auto start_int = boxed_cast<int>(begin);
|
||||
const auto end_int = boxed_cast<int>(end);
|
||||
|
||||
const auto body = child_at(for_node, 3);
|
||||
|
||||
return make_compiled_node(for_node, {body},
|
||||
[id, start_int, end_int](const std::vector<AST_NodePtr> &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
|
@ -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<chaiscript::AST_Node, NodeType>(
|
||||
std::move(t_text),
|
||||
std::move(filepos),
|
||||
std::move(new_children)));
|
||||
m_optimizer.optimize(
|
||||
chaiscript::make_shared<chaiscript::AST_Node, NodeType>(
|
||||
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<const eval::Constant_AST_Node>(eq_node->children[1])->m_value;
|
||||
const Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node>(binary_node->children[1])->m_value;
|
||||
const std::string &id = prefix_node->children[0]->text;
|
||||
|
||||
if (begin.get_type_info().bare_equal(user_type<int>())
|
||||
&& end.get_type_info().bare_equal(user_type<int>())) {
|
||||
return Result(true, id, boxed_cast<int>(begin), boxed_cast<int>(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<eval::Compiled_AST_Node>(std::string(), start.start.line, start.start.column, std::vector<AST_NodePtr>({body}),
|
||||
|
||||
[for_loop_params](const std::vector<AST_NodePtr> &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<eval::For_AST_Node>(prev_stack_top);
|
||||
}
|
||||
build_match<eval::For_AST_Node>(prev_stack_top);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
Loading…
x
Reference in New Issue
Block a user