Various tree optimizations
This commit is contained in:
@@ -467,14 +467,14 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
|
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<const std::string> &t_fname,
|
||||||
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
|
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
|
||||||
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname),
|
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname),
|
||||||
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
|
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
|
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<const std::string> &t_fname) :
|
||||||
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname) {}
|
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname) {}
|
||||||
|
|
||||||
virtual ~AST_Node() {}
|
virtual ~AST_Node() {}
|
||||||
|
@@ -218,6 +218,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Fun_Call_AST_Node : public AST_Node {
|
struct Fun_Call_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
Fun_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
Fun_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||||
@@ -289,6 +290,96 @@ namespace chaiscript
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Fun_Lookup_AST_Node : public AST_Node {
|
||||||
|
public:
|
||||||
|
Fun_Lookup_AST_Node(const std::string &t_fun_name)
|
||||||
|
: AST_Node(t_fun_name, 0, std::make_shared<std::string>("<EVAL>"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Fun_Lookup_AST_Node() {}
|
||||||
|
|
||||||
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||||
|
try {
|
||||||
|
Boxed_Value bv = t_ss.get_object(text);
|
||||||
|
t_ss.add_object(text, bv);
|
||||||
|
std::cout << " Saved fun lookup: " << text << '\n';
|
||||||
|
return bv;
|
||||||
|
} catch (...) {
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct Unary_Fun_Call_AST_Node : public AST_Node {
|
||||||
|
public:
|
||||||
|
Unary_Fun_Call_AST_Node(const Fun_Call_AST_Node &t_fc)
|
||||||
|
: AST_Node(t_fc.text, t_fc.identifier, t_fc.filename, t_fc.start.line, t_fc.start.column, t_fc.end.line, t_fc.end.column)
|
||||||
|
{
|
||||||
|
this->children = t_fc.children;
|
||||||
|
}
|
||||||
|
virtual ~Unary_Fun_Call_AST_Node() {}
|
||||||
|
|
||||||
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
|
|
||||||
|
std::vector<Boxed_Value> params{children[1]->children[0]->eval(t_ss)};
|
||||||
|
fpp.save_params(params);
|
||||||
|
|
||||||
|
Boxed_Value fn(this->children[0]->eval(t_ss));
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||||
|
return (*t_ss.boxed_cast<const Const_Proxy_Function &>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (const auto &child : this->children) {
|
||||||
|
oss << child->pretty_print();
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
oss << "(";
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
oss << ")";
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Used in the context of in-string ${} evals, so that no new scope is created
|
/// Used in the context of in-string ${} evals, so that no new scope is created
|
||||||
struct Inplace_Fun_Call_AST_Node : public AST_Node {
|
struct Inplace_Fun_Call_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
@@ -452,23 +543,24 @@ namespace chaiscript
|
|||||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
|
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
Operators::Opers m_oper;
|
||||||
|
|
||||||
virtual ~Equation_AST_Node() {}
|
virtual ~Equation_AST_Node() {}
|
||||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
Boxed_Value rhs = this->children.back()->eval(t_ss);
|
Boxed_Value rhs = this->children[2]->eval(t_ss);
|
||||||
Boxed_Value lhs = this->children[0]->eval(t_ss);
|
Boxed_Value lhs = this->children[0]->eval(t_ss);
|
||||||
|
|
||||||
Operators::Opers oper = Operators::to_operator(this->children[1]->text);
|
|
||||||
|
|
||||||
if (oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
|
if (m_oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
|
||||||
rhs.get_type_info().is_arithmetic())
|
rhs.get_type_info().is_arithmetic())
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return Boxed_Number::do_oper(oper, lhs, rhs);
|
return Boxed_Number::do_oper(m_oper, lhs, rhs);
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
|
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
|
||||||
}
|
}
|
||||||
} else if (oper == Operators::assign) {
|
} else if (m_oper == Operators::assign) {
|
||||||
try {
|
try {
|
||||||
if (lhs.is_undef()) {
|
if (lhs.is_undef()) {
|
||||||
if (!this->children.empty() &&
|
if (!this->children.empty() &&
|
||||||
|
@@ -196,13 +196,55 @@ namespace chaiscript
|
|||||||
return m_match_stack.front();
|
return m_match_stack.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::map<std::string, int> count_fun_calls(const AST_NodePtr &p, bool in_loop) {
|
||||||
|
if (p->identifier == AST_Node_Type::Fun_Call) {
|
||||||
|
if (p->children[0]->identifier == AST_Node_Type::Id) {
|
||||||
|
return std::map<std::string, int>{{p->children[0]->text, in_loop?99:1}};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
std::map<std::string, int> counts;
|
||||||
|
for (const auto &child : p->children) {
|
||||||
|
auto childcounts = count_fun_calls(child, in_loop || p->identifier == AST_Node_Type::For || p->identifier == AST_Node_Type::While);
|
||||||
|
for (const auto &count : childcounts) {
|
||||||
|
counts[count.first] += count.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void optimize_fun_lookups(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
for (auto &c : p->children)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (c->identifier == AST_Node_Type::Def
|
||||||
|
|| c->identifier == AST_Node_Type::Method
|
||||||
|
|| c->identifier == AST_Node_Type::Lambda) {
|
||||||
|
std::vector<AST_NodePtr> children_to_add;
|
||||||
|
auto counts = count_fun_calls(c, false);
|
||||||
|
for (const auto &count : counts) {
|
||||||
|
// std::cout << " Fun Call Count: " << count.first << " " << count.second << '\n';
|
||||||
|
if (count.second > 1) {
|
||||||
|
children_to_add.push_back(std::make_shared<eval::Fun_Lookup_AST_Node>(count.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c->children.back()->children.insert(c->children.back()->children.begin(), children_to_add.begin(), children_to_add.end());
|
||||||
|
}
|
||||||
|
optimize_fun_lookups(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void optimize_blocks(AST_NodePtr &p)
|
static void optimize_blocks(AST_NodePtr &p)
|
||||||
{
|
{
|
||||||
for (auto &c : p->children)
|
for (auto &c : p->children)
|
||||||
{
|
{
|
||||||
if (c->identifier == AST_Node_Type::Block) {
|
if (c->identifier == AST_Node_Type::Block) {
|
||||||
if (c->children.size() == 1) {
|
if (c->children.size() == 1) {
|
||||||
std::cout << "swapping out block child for block\n";
|
// std::cout << "swapping out block child for block\n";
|
||||||
c = c->children[0];
|
c = c->children[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,6 +271,30 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void optimize_fun_calls(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
for (auto &c : p->children)
|
||||||
|
{
|
||||||
|
if (c->identifier == AST_Node_Type::Fun_Call && c->children.size() == 2 && c->children[1]->children.size() == 1) {
|
||||||
|
c = std::make_shared<eval::Unary_Fun_Call_AST_Node>(dynamic_cast<eval::Fun_Call_AST_Node &>(*c));
|
||||||
|
// std::cout << "optimized unary fun call\n";
|
||||||
|
}
|
||||||
|
optimize_fun_calls(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fixup_opers(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
if (p->identifier == AST_Node_Type::Equation)
|
||||||
|
{
|
||||||
|
dynamic_cast<eval::Equation_AST_Node &>(*p).m_oper = Operators::to_operator(p->children[1]->text);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &c : p->children) {
|
||||||
|
fixup_opers(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int count_nodes(const AST_NodePtr &p)
|
static int count_nodes(const AST_NodePtr &p)
|
||||||
{
|
{
|
||||||
int count = 1;
|
int count = 1;
|
||||||
@@ -238,14 +304,15 @@ namespace chaiscript
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_NodePtr optimized_ast() {
|
AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true, bool t_optimize_fun_lookups = false,
|
||||||
std::cout << " Optimizing AST \n";
|
bool t_optimize_fun_calls = false) {
|
||||||
AST_NodePtr p = m_match_stack.front();
|
AST_NodePtr p = m_match_stack.front();
|
||||||
std::cout << "Node Count: " << count_nodes(p) << '\n';
|
fixup_opers(p);
|
||||||
// optimize_blocks(p);
|
//Note, optimize_blocks is currently broken; it breaks stack management
|
||||||
// std::cout << "Optimized Block Node Count: " << count_nodes(p) << '\n';
|
if (t_optimize_blocks) { optimize_blocks(p); }
|
||||||
optimize_returns(p);
|
if (t_optimize_returns) { optimize_returns(p); }
|
||||||
std::cout << "Returns Block Node Count: " << count_nodes(p) << '\n';
|
if (t_optimize_fun_lookups) { optimize_fun_lookups(p); }
|
||||||
|
if (t_optimize_fun_calls) { optimize_fun_calls(p); }
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user