Add ability to 'compile' for loops

This commit is contained in:
Jason Turner 2016-04-21 08:09:10 -06:00
parent 647f8842fd
commit 683164650a
3 changed files with 111 additions and 4 deletions

View File

@ -36,7 +36,7 @@ namespace chaiscript
Array_Call, Dot_Access,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Try, Catch, Finally, Method, Attr_Decl,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl, Constant
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
};
enum class Operator_Precidence { Ternary_Cond, Logical_Or, Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And, Equality, Comparison, Shift, Addition, Multiplication };
@ -49,7 +49,7 @@ namespace chaiscript
"Array_Call", "Dot_Access",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg", "Constant"};
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
return ast_node_types[static_cast<int>(ast_node_type)];
}

View File

@ -81,6 +81,20 @@ 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,
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))
{ }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
return m_func(children, t_ss);
}
std::function<Boxed_Value (const std::vector<AST_NodePtr> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func;
};
struct Binary_Operator_AST_Node : AST_Node {
Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)),

View File

@ -1686,6 +1686,57 @@ namespace chaiscript
return true;
}
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;
@ -1709,12 +1760,54 @@ namespace chaiscript
throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename);
}
build_match<eval::For_AST_Node>(prev_stack_top);
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);
}
}
return retval;
}
/// Reads a case block from input
bool Case() {
bool retval = false;
@ -2352,7 +2445,7 @@ namespace chaiscript
throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname);
} else {
build_match<eval::File_AST_Node>(0);
//debug_print(ast());
// debug_print(ast());
return true;
}
} else {