Initial take on Tracer hooks

This will allow the user to add hooks in for debugging / execution
tracing / throttling / etc for each node execution

The cost is *almost* 0 if no tracing is enabled.
This commit is contained in:
Jason Turner 2016-04-30 20:53:01 -06:00
parent dcedd64032
commit 03803ee4c4
8 changed files with 523 additions and 355 deletions

View File

@ -580,7 +580,8 @@ namespace chaiscript
{fun(&AST_Node::to_string), "to_string"}, {fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> { {fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
std::transform(t_node.children.begin(), t_node.children.end(), const auto children = t_node.get_children();
std::transform(children.begin(), children.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>); &chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
return retval; return retval;

View File

@ -37,6 +37,9 @@ class Boxed_Number;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript { namespace chaiscript {
namespace parser {
class ChaiScript_Parser_Base;
}
namespace dispatch { namespace dispatch {
class Dynamic_Proxy_Function; class Dynamic_Proxy_Function;
class Proxy_Function_Base; class Proxy_Function_Base;
@ -45,6 +48,7 @@ struct Placeholder_Object;
} // namespace chaiscript } // namespace chaiscript
/// \namespace chaiscript::dispatch /// \namespace chaiscript::dispatch
/// \brief Classes and functions specific to the runtime dispatch side of ChaiScript. Some items may be of use to the end user. /// \brief Classes and functions specific to the runtime dispatch side of ChaiScript. Some items may be of use to the end user.
@ -411,8 +415,10 @@ namespace chaiscript
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_"}; "return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_"};
}; };
Dispatch_Engine() Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser)
: m_stack_holder(this) : m_stack_holder(this),
m_parser(parser)
{ {
} }
@ -1231,6 +1237,11 @@ namespace chaiscript
return m_stack_holder->stacks.back(); return m_stack_holder->stacks.back();
} }
parser::ChaiScript_Parser_Base &get_parser()
{
return m_parser.get();
}
private: private:
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
@ -1456,6 +1467,7 @@ namespace chaiscript
Type_Conversions m_conversions; Type_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder; chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
std::reference_wrapper<parser::ChaiScript_Parser_Base> m_parser;
mutable std::atomic_uint_fast32_t m_method_missing_loc; mutable std::atomic_uint_fast32_t m_method_missing_loc;

View File

@ -465,7 +465,6 @@ namespace chaiscript
const AST_Node_Type identifier; const AST_Node_Type identifier;
const std::string text; const std::string text;
Parse_Location location; Parse_Location location;
std::vector<AST_NodePtr> children;
const std::string &filename() const { const std::string &filename() const {
return *location.filename; return *location.filename;
@ -485,13 +484,16 @@ namespace chaiscript
oss << text; oss << text;
for (auto & elem : this->children) { for (auto & elem : this->get_children()) {
oss << elem->pretty_print() << ' '; oss << elem->pretty_print() << ' ';
} }
return oss.str(); return oss.str();
} }
virtual std::vector<AST_NodePtr> get_children() const = 0;
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
/// Prints the contents of an AST node, including its children, recursively /// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") const { std::string to_string(const std::string &t_prepend = "") const {
@ -500,21 +502,12 @@ namespace chaiscript
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n'; << this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
for (auto & elem : this->children) { for (auto & elem : this->get_children()) {
oss << elem->to_string(t_prepend + " "); oss << elem->to_string(t_prepend + " ");
} }
return oss.str(); return oss.str();
} }
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
{
try {
return eval_internal(t_e);
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this());
throw;
}
}
static bool get_bool_condition(const Boxed_Value &t_bv) { static bool get_bool_condition(const Boxed_Value &t_bv) {
try { try {
@ -534,21 +527,39 @@ namespace chaiscript
protected: protected:
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc, AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
std::vector<AST_NodePtr> t_children = std::vector<AST_NodePtr>()) : : identifier(t_id), text(std::move(t_ast_node_text)),
identifier(t_id), text(std::move(t_ast_node_text)), location(std::move(t_loc))
location(std::move(t_loc)),
children(std::move(t_children))
{ {
} }
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
}; };
namespace parser {
class ChaiScript_Parser_Base
{
public:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
virtual void debug_print(AST_NodePtr t, std::string prepend = "") const = 0;
virtual void *get_tracer_ptr() = 0;
virtual ~ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
template<typename T>
T &get_tracer()
{
// to do type check this somehow?
return static_cast<T&>(*get_tracer_ptr());
}
protected:
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
};
}
namespace eval namespace eval
{ {

View File

@ -70,10 +70,10 @@ namespace chaiscript
std::vector<std::string> m_module_paths; std::vector<std::string> m_module_paths;
std::vector<std::string> m_use_paths; std::vector<std::string> m_use_paths;
chaiscript::detail::Dispatch_Engine m_engine;
std::unique_ptr<parser::ChaiScript_Parser_Base> m_parser; std::unique_ptr<parser::ChaiScript_Parser_Base> m_parser;
chaiscript::detail::Dispatch_Engine m_engine;
/// Evaluates the given string in by parsing it and running the results through the evaluator /// Evaluates the given string in by parsing it and running the results through the evaluator
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
{ {
@ -219,7 +219,9 @@ namespace chaiscript
std::vector<std::string> t_modulepaths = std::vector<std::string>(), std::vector<std::string> t_modulepaths = std::vector<std::string>(),
std::vector<std::string> t_usepaths = std::vector<std::string>()) std::vector<std::string> t_usepaths = std::vector<std::string>())
: m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths)), : m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths)),
m_parser(std::make_unique<parser::ChaiScript_Parser<optimizer::Optimizer<optimizer::Block, optimizer::Constant_Fold, optimizer::If, optimizer::Return, optimizer::For_Loop>>>()) m_parser(std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer<optimizer::Block, optimizer::Constant_Fold, optimizer::If, optimizer::Return, optimizer::For_Loop>>>()),
m_engine(*m_parser)
{ {
if (m_module_paths.empty()) if (m_module_paths.empty())
{ {
@ -244,7 +246,8 @@ namespace chaiscript
ChaiScript( std::vector<std::string> t_modulepaths = std::vector<std::string>(), ChaiScript( std::vector<std::string> t_modulepaths = std::vector<std::string>(),
std::vector<std::string> t_usepaths = std::vector<std::string>()) std::vector<std::string> t_usepaths = std::vector<std::string>())
: m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths)), : m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths)),
m_parser(std::make_unique<parser::ChaiScript_Parser<optimizer::Optimizer<optimizer::Block, optimizer::Constant_Fold, optimizer::If, optimizer::Return, optimizer::For_Loop>>>()) m_parser(std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer<optimizer::Block, optimizer::Constant_Fold, optimizer::If, optimizer::Return, optimizer::For_Loop>>>()),
m_engine(*m_parser)
{ {
if (m_module_paths.empty()) if (m_module_paths.empty())
{ {

View File

@ -41,10 +41,15 @@ namespace chaiscript
/// \brief Classes and functions that are part of the runtime eval system /// \brief Classes and functions that are part of the runtime eval system
namespace eval namespace eval
{ {
template<typename T> struct AST_Node_Impl;
template<typename T> using AST_Node_Impl_Ptr = typename std::shared_ptr<AST_Node_Impl<T>>;
namespace detail namespace detail
{ {
/// Helper function that will set up the scope around a function call, including handling the named function parameters /// Helper function that will set up the scope around a function call, including handling the named function parameters
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &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) { template<typename T>
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl_Ptr<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) {
chaiscript::detail::Dispatch_State state(t_ss); chaiscript::detail::Dispatch_State state(t_ss);
const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{ const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
@ -81,32 +86,72 @@ namespace chaiscript
} }
} }
struct Compiled_AST_Node : AST_Node {
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) : template<typename T>
AST_Node(t_original_node->text, AST_Node_Type::Compiled, t_original_node->location, std::move(t_children)), 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), std::move(t_id), std::move(t_loc)),
children(std::move(t_children))
{
}
std::vector<AST_NodePtr> get_children() const final {
return {children.begin(), children.end()};
}
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(shared_from_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_func(std::move(t_func)),
m_original_node(std::move(t_original_node)) m_original_node(std::move(t_original_node))
{ } { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
return m_func(children, t_ss); return m_func(this->children, t_ss);
} }
std::function<Boxed_Value (const std::vector<AST_NodePtr> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func; std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func;
AST_NodePtr m_original_node; AST_Node_Impl_Ptr<T> m_original_node;
}; };
struct Binary_Operator_AST_Node : AST_Node { template<typename T>
Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Binary_Operator_AST_Node : AST_Node_Impl<T> {
AST_Node(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)), 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)) m_oper(Operators::to_operator(t_oper))
{ } { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
auto lhs = this->children[0]->eval(t_ss); auto lhs = this->children[0]->eval(t_ss);
auto rhs = this->children[1]->eval(t_ss); auto rhs = this->children[1]->eval(t_ss);
return do_oper(t_ss, m_oper, text, lhs, rhs); return do_oper(t_ss, m_oper, this->text, lhs, rhs);
} }
protected: protected:
@ -141,10 +186,10 @@ namespace chaiscript
}; };
template<typename T>
struct Constant_AST_Node final : AST_Node { 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) Constant_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_value)
: AST_Node(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)), : AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)),
m_value(std::move(t_value)) m_value(std::move(t_value))
{ {
} }
@ -156,9 +201,10 @@ namespace chaiscript
Boxed_Value m_value; Boxed_Value m_value;
}; };
struct Id_AST_Node final : AST_Node { 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) : Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) :
AST_Node(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)), AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)),
m_loc(0) m_loc(0)
{ } { }
@ -177,9 +223,10 @@ namespace chaiscript
struct Fun_Call_AST_Node final : AST_Node { template<typename T>
Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Fun_Call_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { } 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)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{ {
@ -227,18 +274,20 @@ namespace chaiscript
struct Arg_AST_Node final : AST_Node { template<typename T>
Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Arg_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { } 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)) { }
}; };
struct Arg_List_AST_Node final : AST_Node { template<typename T>
Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Arg_List_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { } 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_NodePtr &t_node) { static std::string get_arg_name(const AST_Node_Impl_Ptr<T> &t_node) {
if (t_node->children.empty()) if (t_node->children.empty())
{ {
return t_node->text; return t_node->text;
@ -249,7 +298,7 @@ namespace chaiscript
} }
} }
static std::vector<std::string> get_arg_names(const AST_NodePtr &t_node) { static std::vector<std::string> get_arg_names(const AST_Node_Impl_Ptr<T> &t_node) {
std::vector<std::string> retval; std::vector<std::string> retval;
for (const auto &node : t_node->children) for (const auto &node : t_node->children)
@ -260,7 +309,7 @@ namespace chaiscript
return retval; return retval;
} }
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss) static std::pair<std::string, Type_Info> get_arg_type(const AST_Node_Impl_Ptr<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss)
{ {
if (t_node->children.size() < 2) if (t_node->children.size() < 2)
{ {
@ -270,7 +319,7 @@ namespace chaiscript
} }
} }
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss) { static dispatch::Param_Types get_arg_types(const AST_Node_Impl_Ptr<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
std::vector<std::pair<std::string, Type_Info>> retval; std::vector<std::pair<std::string, Type_Info>> retval;
for (const auto &child : t_node->children) for (const auto &child : t_node->children)
@ -282,10 +331,11 @@ namespace chaiscript
} }
}; };
struct Equation_AST_Node final : AST_Node { template<typename T>
Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Equation_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)), Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
m_oper(Operators::to_operator(text)) 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(children.size() == 2); } { assert(children.size() == 2); }
@ -368,17 +418,18 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_clone_loc; mutable std::atomic_uint_fast32_t m_clone_loc;
}; };
struct Global_Decl_AST_Node final : AST_Node { template<typename T>
Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Global_Decl_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
const std::string &idname = const std::string &idname =
[&]()->const std::string & { [&]()->const std::string & {
if (children[0]->identifier == AST_Node_Type::Reference) { if (this->children[0]->identifier == AST_Node_Type::Reference) {
return children[0]->children[0]->text; return this->children[0]->children[0]->text;
} else { } else {
return children[0]->text; return this->children[0]->text;
} }
}(); }();
@ -393,9 +444,10 @@ namespace chaiscript
}; };
struct Var_Decl_AST_Node final : AST_Node { template<typename T>
Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Var_Decl_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
const std::string &idname = this->children[0]->text; const std::string &idname = this->children[0]->text;
@ -414,14 +466,15 @@ namespace chaiscript
}; };
struct Array_Call_AST_Node final : AST_Node { template<typename T>
Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Array_Call_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
const std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)}; const std::vector<Boxed_Value> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
try { try {
fpp.save_params(params); fpp.save_params(params);
@ -437,24 +490,25 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc; mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Dot_Access_AST_Node final : AST_Node { template<typename T>
Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Dot_Access_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)), 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( m_fun_name(
((children[1]->identifier == AST_Node_Type::Fun_Call) || (children[1]->identifier == AST_Node_Type::Array_Call))? ((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call))?
children[1]->children[0]->text:children[1]->text) { } this->children[1]->children[0]->text:this->children[1]->text) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value retval = children[0]->eval(t_ss); Boxed_Value retval = this->children[0]->eval(t_ss);
std::vector<Boxed_Value> params{retval}; std::vector<Boxed_Value> params{retval};
bool has_function_params = false; bool has_function_params = false;
if (children[1]->children.size() > 1) { if (this->children[1]->children.size() > 1) {
has_function_params = true; has_function_params = true;
for (const auto &child : children[1]->children[1]->children) { for (const auto &child : this->children[1]->children[1]->children) {
params.push_back(child->eval(t_ss)); params.push_back(child->eval(t_ss));
} }
} }
@ -495,23 +549,24 @@ namespace chaiscript
}; };
struct Lambda_AST_Node final : AST_Node { template<typename T>
Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Lambda_AST_Node final : AST_Node_Impl<T> {
AST_Node(t_ast_node_text, AST_Node_Type::Lambda, std::move(t_loc), std::move(t_children)), Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
m_param_names(Arg_List_AST_Node::get_arg_names(children[1])) { } AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Lambda, std::move(t_loc), std::move(t_children)),
m_param_names(Arg_List_AST_Node<T>::get_arg_names(this->children[1])) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
const auto captures = [&]()->std::map<std::string, Boxed_Value>{ const auto captures = [&]()->std::map<std::string, Boxed_Value>{
std::map<std::string, Boxed_Value> named_captures; std::map<std::string, Boxed_Value> named_captures;
for (const auto &capture : children[0]->children) { for (const auto &capture : this->children[0]->children) {
named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss))); named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
} }
return named_captures; return named_captures;
}(); }();
const auto numparams = this->children[1]->children.size(); const auto numparams = this->children[1]->children.size();
const auto param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss); const auto param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[1], t_ss);
const auto &lambda_node = this->children.back(); const auto &lambda_node = this->children.back();
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss); std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
@ -532,36 +587,38 @@ namespace chaiscript
}; };
struct Block_AST_Node final : AST_Node { template<typename T>
Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Block_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
const auto num_children = children.size(); const auto num_children = this->children.size();
for (size_t i = 0; i < num_children-1; ++i) { for (size_t i = 0; i < num_children-1; ++i) {
children[i]->eval(t_ss); this->children[i]->eval(t_ss);
} }
return children.back()->eval(t_ss); return this->children.back()->eval(t_ss);
} }
}; };
struct Def_AST_Node final : AST_Node { template<typename T>
Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Def_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), std::move(t_children)) { } 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::move(t_children)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
std::vector<std::string> t_param_names; std::vector<std::string> t_param_names;
size_t numparams = 0; size_t numparams = 0;
AST_NodePtr guardnode; AST_Node_Impl_Ptr<T> guardnode;
dispatch::Param_Types param_types; dispatch::Param_Types param_types;
if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
numparams = this->children[1]->children.size(); numparams = this->children[1]->children.size();
t_param_names = Arg_List_AST_Node::get_arg_names(this->children[1]); t_param_names = Arg_List_AST_Node<T>::get_arg_names(this->children[1]);
param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss); param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[1], t_ss);
if (this->children.size() > 3) { if (this->children.size() > 3) {
guardnode = this->children[2]; guardnode = this->children[2];
@ -609,15 +666,16 @@ namespace chaiscript
}; };
struct While_AST_Node final : AST_Node { template<typename T>
While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct While_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try { try {
while (get_bool_condition(this->children[0]->eval(t_ss))) { while (this->get_bool_condition(this->children[0]->eval(t_ss))) {
try { try {
this->children[1]->eval(t_ss); this->children[1]->eval(t_ss);
} catch (detail::Continue_Loop &) { } catch (detail::Continue_Loop &) {
@ -634,51 +692,54 @@ namespace chaiscript
} }
}; };
struct Class_AST_Node final : AST_Node { template<typename T>
Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Class_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
/// \todo do this better /// \todo do this better
// put class name in current scope so it can be looked up by the attrs and methods // 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(children[0]->text)); t_ss.add_object("_current_class_name", const_var(this->children[0]->text));
children[1]->eval(t_ss); this->children[1]->eval(t_ss);
return void_var(); return void_var();
} }
}; };
struct Ternary_Cond_AST_Node final : AST_Node { template<typename T>
Ternary_Cond_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Ternary_Cond_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Ternary_Cond, std::move(t_loc), std::move(t_children)) Ternary_Cond_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
{ assert(children.size() == 3); } AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Ternary_Cond, 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
if (get_bool_condition(children[0]->eval(t_ss))) { if (this->get_bool_condition(this->children[0]->eval(t_ss))) {
return children[1]->eval(t_ss); return this->children[1]->eval(t_ss);
} else { } else {
return children[2]->eval(t_ss); return this->children[2]->eval(t_ss);
} }
} }
}; };
struct If_AST_Node final : AST_Node { template<typename T>
If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct If_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) 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(children.size() == 2 || children.size() == 3); assert(this->children.size() == 2 || this->children.size() == 3);
} }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
if (get_bool_condition(children[0]->eval(t_ss))) { if (this->get_bool_condition(this->children[0]->eval(t_ss))) {
return children[1]->eval(t_ss); return this->children[1]->eval(t_ss);
} else { } else {
if (children.size() == 3) { if (this->children.size() == 3) {
return children[2]->eval(t_ss); return this->children[2]->eval(t_ss);
} else { } else {
return void_var(); return void_var();
} }
@ -686,23 +747,24 @@ namespace chaiscript
} }
}; };
struct For_AST_Node final : AST_Node { template<typename T>
For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct For_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children)) For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
{ assert(children.size() == 4); } 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{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try { try {
for ( for (
children[0]->eval(t_ss); this->children[0]->eval(t_ss);
get_bool_condition(children[1]->eval(t_ss)); this->get_bool_condition(this->children[1]->eval(t_ss));
children[2]->eval(t_ss) this->children[2]->eval(t_ss)
) { ) {
try { try {
// Body of Loop // Body of Loop
children[3]->eval(t_ss); this->children[3]->eval(t_ss);
} catch (detail::Continue_Loop &) { } catch (detail::Continue_Loop &) {
// we got a continue exception, which means all of the remaining // we got a continue exception, which means all of the remaining
// loop implementation is skipped and we just need to continue to // loop implementation is skipped and we just need to continue to
@ -718,9 +780,10 @@ namespace chaiscript
}; };
struct Switch_AST_Node final : AST_Node { template<typename T>
Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Switch_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
bool breaking = false; bool breaking = false;
@ -761,45 +824,48 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc; mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Case_AST_Node final : AST_Node { template<typename T>
Case_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Case_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children)) 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(children.size() == 2); /* how many children does it have? */ } { assert(children.size() == 2); /* how many children does it have? */ }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
children[1]->eval(t_ss); this->children[1]->eval(t_ss);
return void_var(); return void_var();
} }
}; };
struct Default_AST_Node final : AST_Node { template<typename T>
Default_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Default_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children)) 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(children.size() == 1); } { assert(children.size() == 1); }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
children[0]->eval(t_ss); this->children[0]->eval(t_ss);
return void_var(); return void_var();
} }
}; };
struct Inline_Array_AST_Node final : AST_Node { template<typename T>
Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Inline_Array_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
try { try {
std::vector<Boxed_Value> vec; std::vector<Boxed_Value> vec;
if (!children.empty()) { if (!this->children.empty()) {
vec.reserve(children[0]->children.size()); vec.reserve(this->children[0]->children.size());
for (const auto &child : children[0]->children) { for (const auto &child : this->children[0]->children) {
auto obj = child->eval(t_ss); auto obj = child->eval(t_ss);
if (!obj.is_return_value()) { if (!obj.is_return_value()) {
vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions())); vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()));
@ -819,15 +885,16 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc; mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Inline_Map_AST_Node final : AST_Node { template<typename T>
Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Inline_Map_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { } 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{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
try { try {
std::map<std::string, Boxed_Value> retval; std::map<std::string, Boxed_Value> retval;
for (const auto &child : children[0]->children) { for (const auto &child : this->children[0]->children) {
auto obj = child->children[1]->eval(t_ss); auto obj = child->children[1]->eval(t_ss);
if (!obj.is_return_value()) { if (!obj.is_return_value()) {
obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()); obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions());
@ -847,13 +914,14 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc; mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Return_AST_Node final : AST_Node { template<typename T>
Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Return_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { } 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{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
if (!this->children.empty()) { if (!this->children.empty()) {
throw detail::Return_Value(children[0]->eval(t_ss)); throw detail::Return_Value(this->children[0]->eval(t_ss));
} }
else { else {
throw detail::Return_Value(void_var()); throw detail::Return_Value(void_var());
@ -861,19 +929,20 @@ namespace chaiscript
} }
}; };
struct File_AST_Node final : AST_Node { template<typename T>
File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct File_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { } 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 { Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
try { try {
const auto num_children = children.size(); const auto num_children = this->children.size();
if (num_children > 0) { if (num_children > 0) {
for (size_t i = 0; i < num_children-1; ++i) { for (size_t i = 0; i < num_children-1; ++i) {
children[i]->eval(t_ss); this->children[i]->eval(t_ss);
} }
return children.back()->eval(t_ss); return this->children.back()->eval(t_ss);
} else { } else {
return void_var(); return void_var();
} }
@ -885,9 +954,10 @@ namespace chaiscript
} }
}; };
struct Reference_AST_Node final : AST_Node { template<typename T>
Reference_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Reference_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children)) 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(children.size() == 1); } { assert(children.size() == 1); }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
@ -902,14 +972,15 @@ namespace chaiscript
} }
}; };
struct Prefix_AST_Node final : AST_Node { template<typename T>
Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Prefix_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)), Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
m_oper(Operators::to_operator(text, true)) 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 eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
Boxed_Value bv(children[0]->eval(t_ss)); Boxed_Value bv(this->children[0]->eval(t_ss));
try { try {
// short circuit arithmetic operations // short circuit arithmetic operations
@ -919,10 +990,10 @@ namespace chaiscript
} else { } else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
fpp.save_params({bv}); fpp.save_params({bv});
return t_ss->call_function(text, m_loc, {std::move(bv)}, t_ss.conversions()); return t_ss->call_function(this->text, m_loc, {std::move(bv)}, t_ss.conversions());
} }
} catch (const exception::dispatch_error &e) { } catch (const exception::dispatch_error &e) {
throw exception::eval_error("Error with prefix operator evaluation: '" + text + "'", e.parameters, e.functions, false, *t_ss); throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss);
} }
} }
@ -931,27 +1002,30 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc; mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Break_AST_Node final : AST_Node { template<typename T>
Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Break_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { } 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{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
throw detail::Break_Loop(); throw detail::Break_Loop();
} }
}; };
struct Continue_AST_Node final : AST_Node { template<typename T>
Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Continue_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { } 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{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
throw detail::Continue_Loop(); throw detail::Continue_Loop();
} }
}; };
struct Noop_AST_Node final : public AST_Node { template<typename T>
struct Noop_AST_Node final : AST_Node_Impl<T> {
Noop_AST_Node() : Noop_AST_Node() :
AST_Node("", AST_Node_Type::Noop, Parse_Location()) AST_Node_Impl<T>("", AST_Node_Type::Noop, Parse_Location())
{ } { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
@ -961,24 +1035,27 @@ namespace chaiscript
} }
}; };
struct Map_Pair_AST_Node final : AST_Node { template<typename T>
Map_Pair_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Map_Pair_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) { } 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)) { }
}; };
struct Value_Range_AST_Node final : AST_Node { template<typename T>
Value_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Value_Range_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) { } 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)) { }
}; };
struct Inline_Range_AST_Node final : AST_Node { template<typename T>
Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Inline_Range_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { } 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{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
try { try {
auto oper1 = children[0]->children[0]->children[0]->eval(t_ss); auto oper1 = this->children[0]->children[0]->children[0]->eval(t_ss);
auto oper2 = children[0]->children[0]->children[1]->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()); return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions());
} }
catch (const exception::dispatch_error &e) { catch (const exception::dispatch_error &e) {
@ -990,9 +1067,10 @@ namespace chaiscript
mutable std::atomic_uint_fast32_t m_loc; mutable std::atomic_uint_fast32_t m_loc;
}; };
struct Try_AST_Node final : AST_Node { template<typename T>
Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Try_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { } 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 handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const
{ {
@ -1005,17 +1083,17 @@ namespace chaiscript
} }
for (size_t i = 1; i < end_point; ++i) { for (size_t i = 1; i < end_point; ++i) {
chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss); chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss);
AST_NodePtr catch_block = this->children[i]; AST_Node_Impl_Ptr<T> catch_block = this->children[i];
if (catch_block->children.size() == 1) { if (catch_block->children.size() == 1) {
//No variable capture, no guards //No variable capture, no guards
retval = catch_block->children[0]->eval(t_ss); retval = catch_block->children[0]->eval(t_ss);
break; break;
} else if (catch_block->children.size() == 2 || catch_block->children.size() == 3) { } else if (catch_block->children.size() == 2 || catch_block->children.size() == 3) {
const auto name = Arg_List_AST_Node::get_arg_name(catch_block->children[0]); const auto name = Arg_List_AST_Node<T>::get_arg_name(catch_block->children[0]);
if (dispatch::Param_Types( if (dispatch::Param_Types(
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} 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())) ).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
{ {
t_ss.add_object(name, t_except); t_ss.add_object(name, t_except);
@ -1099,23 +1177,26 @@ namespace chaiscript
}; };
struct Catch_AST_Node final : AST_Node { template<typename T>
Catch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Catch_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) { } 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)) { }
}; };
struct Finally_AST_Node final : AST_Node { template<typename T>
Finally_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Finally_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) { } 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)) { }
}; };
struct Method_AST_Node final : AST_Node { template<typename T>
Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Method_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc), std::move(t_children)) { } 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::move(t_children)) { }
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
AST_NodePtr guardnode; AST_Node_Impl_Ptr<T> guardnode;
const auto d = t_ss->get_parent_locals(); const auto d = t_ss->get_parent_locals();
const auto itr = d.find("_current_class_name"); const auto itr = d.find("_current_class_name");
@ -1126,20 +1207,21 @@ namespace chaiscript
std::vector<std::string> t_param_names{"this"}; std::vector<std::string> t_param_names{"this"};
dispatch::Param_Types param_types; dispatch::Param_Types param_types;
if ((children.size() > static_cast<size_t>(3 + class_offset)) && (children[static_cast<size_t>(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) { if ((this->children.size() > static_cast<size_t>(3 + class_offset))
auto args = Arg_List_AST_Node::get_arg_names(children[static_cast<size_t>(2 + class_offset)]); && (this->children[static_cast<size_t>(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) {
auto args = Arg_List_AST_Node<T>::get_arg_names(this->children[static_cast<size_t>(2 + class_offset)]);
t_param_names.insert(t_param_names.end(), args.begin(), args.end()); t_param_names.insert(t_param_names.end(), args.begin(), args.end());
param_types = Arg_List_AST_Node::get_arg_types(children[static_cast<size_t>(2 + class_offset)], t_ss); param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[static_cast<size_t>(2 + class_offset)], t_ss);
if (children.size() > static_cast<size_t>(4 + class_offset)) { if (this->children.size() > static_cast<size_t>(4 + class_offset)) {
guardnode = children[static_cast<size_t>(3 + class_offset)]; guardnode = this->children[static_cast<size_t>(3 + class_offset)];
} }
} }
else { else {
//no parameters //no parameters
if (children.size() > static_cast<size_t>(3 + class_offset)) { if (this->children.size() > static_cast<size_t>(3 + class_offset)) {
guardnode = children[static_cast<size_t>(2 + class_offset)]; guardnode = this->children[static_cast<size_t>(2 + class_offset)];
} }
} }
@ -1156,8 +1238,8 @@ namespace chaiscript
} }
try { try {
const std::string & function_name = children[static_cast<size_t>(1 + class_offset)]->text; const std::string & function_name = this->children[static_cast<size_t>(1 + class_offset)]->text;
auto node = children.back(); auto node = this->children.back();
if (function_name == class_name) { if (function_name == class_name) {
param_types.push_front(class_name, Type_Info()); param_types.push_front(class_name, Type_Info());
@ -1198,9 +1280,10 @@ namespace chaiscript
}; };
struct Attr_Decl_AST_Node final : AST_Node { template<typename T>
Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Attr_Decl_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { } 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 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{ {
@ -1234,28 +1317,30 @@ namespace chaiscript
}; };
struct Logical_And_AST_Node final : AST_Node { template<typename T>
Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Logical_And_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children)) Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
{ assert(children.size() == 2); } 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 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{ {
return const_var(get_bool_condition(children[0]->eval(t_ss)) return const_var(this->get_bool_condition(this->children[0]->eval(t_ss))
&& get_bool_condition(children[1]->eval(t_ss))); && this->get_bool_condition(this->children[1]->eval(t_ss)));
} }
}; };
struct Logical_Or_AST_Node final : AST_Node { template<typename T>
Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) : struct Logical_Or_AST_Node final : AST_Node_Impl<T> {
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children)) Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
{ assert(children.size() == 2); } 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 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
{ {
return const_var(get_bool_condition(children[0]->eval(t_ss)) return const_var(this->get_bool_condition(this->children[0]->eval(t_ss))
|| get_bool_condition(children[1]->eval(t_ss))); || this->get_bool_condition(this->children[1]->eval(t_ss)));
} }
}; };
} }

View File

@ -22,39 +22,41 @@ namespace chaiscript {
{ {
} }
AST_NodePtr optimize(AST_NodePtr p) { template<typename Tracer>
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
(void)std::initializer_list<int>{ (p = T::optimize(p), 0)... }; (void)std::initializer_list<int>{ (p = T::optimize(p), 0)... };
return p; return p;
} }
}; };
template<typename T> template<typename T>
auto child_at(const T &node, const size_t offset) { auto child_at(const eval::AST_Node_Impl_Ptr<T> &node, const size_t offset) {
if (node->identifier == AST_Node_Type::Compiled) { if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node&>(*node).m_original_node->children[offset]; return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
} else { } else {
return node->children[offset]; return node->children[offset];
} }
} }
template<typename T> template<typename T>
auto child_count(const T &node) { auto child_count(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Compiled) { if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node&>(*node).m_original_node->children.size(); return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children.size();
} else { } else {
return node->children.size(); return node->children.size();
} }
} }
template<typename T> template<typename T, typename Callable>
AST_NodePtr make_compiled_node(const AST_NodePtr &original_node, std::vector<AST_NodePtr> children, T callable) auto make_compiled_node(const eval::AST_Node_Impl_Ptr<T> &original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable)
{ {
return chaiscript::make_shared<AST_Node, eval::Compiled_AST_Node>(original_node, std::move(children), std::move(callable)); return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(original_node, std::move(children), std::move(callable));
} }
struct Return { struct Return {
AST_NodePtr optimize(const AST_NodePtr &p) template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &p)
{ {
if (p->identifier == AST_Node_Type::Def if (p->identifier == AST_Node_Type::Def
&& !p->children.empty()) && !p->children.empty())
@ -95,7 +97,8 @@ namespace chaiscript {
} }
struct Block { struct Block {
AST_NodePtr optimize(const AST_NodePtr &node) { template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Block if (node->identifier == AST_Node_Type::Block
&& node->children.size() == 1 && node->children.size() == 1
&& !contains_var_decl_in_scope(node)) && !contains_var_decl_in_scope(node))
@ -108,12 +111,13 @@ namespace chaiscript {
}; };
struct If { struct If {
AST_NodePtr optimize(const AST_NodePtr &node) { template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if ((node->identifier == AST_Node_Type::If || node->identifier == AST_Node_Type::Ternary_Cond) if ((node->identifier == AST_Node_Type::If || node->identifier == AST_Node_Type::Ternary_Cond)
&& node->children.size() >= 2 && node->children.size() >= 2
&& node->children[0]->identifier == AST_Node_Type::Constant) && node->children[0]->identifier == AST_Node_Type::Constant)
{ {
const auto condition = std::dynamic_pointer_cast<eval::Constant_AST_Node>(node->children[0])->m_value; const auto condition = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) { if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
if (boxed_cast<bool>(condition)) { if (boxed_cast<bool>(condition)) {
return node->children[1]; return node->children[1];
@ -128,7 +132,8 @@ namespace chaiscript {
}; };
struct Constant_Fold { struct Constant_Fold {
AST_NodePtr optimize(const AST_NodePtr &node) { template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Binary if (node->identifier == AST_Node_Type::Binary
&& node->children.size() == 2 && node->children.size() == 2
@ -139,12 +144,12 @@ namespace chaiscript {
const auto oper = node->text; const auto oper = node->text;
const auto parsed = Operators::to_operator(oper); const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) { if (parsed != Operators::Opers::invalid) {
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node>(node->children[0])->m_value; const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node>(node->children[1])->m_value; const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) { if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs); const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text; const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
return chaiscript::make_shared<AST_Node, eval::Constant_AST_Node>(std::move(match), node->location, std::move(val)); return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
} }
} }
} catch (const std::exception &) { } catch (const std::exception &) {
@ -157,7 +162,8 @@ namespace chaiscript {
}; };
struct For_Loop { struct For_Loop {
AST_NodePtr optimize(const AST_NodePtr &for_node) { template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &for_node) {
if (for_node->identifier != AST_Node_Type::For) { if (for_node->identifier != AST_Node_Type::For) {
return for_node; return for_node;
@ -183,8 +189,8 @@ namespace chaiscript {
&& child_at(prefix_node, 0)->identifier == AST_Node_Type::Id && 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) && 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 &begin = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(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 Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(binary_node, 1))->m_value;
const std::string &id = child_at(prefix_node, 0)->text; const std::string &id = child_at(prefix_node, 0)->text;
if (begin.get_type_info().bare_equal(user_type<int>()) if (begin.get_type_info().bare_equal(user_type<int>())
@ -196,7 +202,7 @@ namespace chaiscript {
const auto body = child_at(for_node, 3); const auto body = child_at(for_node, 3);
return make_compiled_node(for_node, {body}, 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) { [id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) {
assert(children.size() == 1); assert(children.size() == 1);
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);

View File

@ -21,6 +21,7 @@
#include "../dispatchkit/boxed_value.hpp" #include "../dispatchkit/boxed_value.hpp"
#include "chaiscript_common.hpp" #include "chaiscript_common.hpp"
#include "chaiscript_optimizer.hpp" #include "chaiscript_optimizer.hpp"
#include "chaiscript_tracer.hpp"
#if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min) #if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min)
#define CHAISCRIPT_PUSHED_MIN_MAX #define CHAISCRIPT_PUSHED_MIN_MAX
@ -57,23 +58,12 @@ namespace chaiscript
}; };
} }
class ChaiScript_Parser_Base
{
public:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
virtual void debug_print(AST_NodePtr t, std::string prepend = "") const = 0;
virtual ~ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
protected: template<typename Tracer, typename Optimizer>
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default; class ChaiScript_Parser final : public ChaiScript_Parser_Base {
}; void *get_tracer_ptr() {
return &m_tracer;
template<typename Optimizer> }
class ChaiScript_Parser : public ChaiScript_Parser_Base {
static std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> build_alphabet() static std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> build_alphabet()
{ {
@ -190,7 +180,7 @@ namespace chaiscript
const std::array<Operator_Precidence, 11> &m_operators = create_operators(); const std::array<Operator_Precidence, 11> &m_operators = create_operators();
std::shared_ptr<std::string> m_filename; std::shared_ptr<std::string> m_filename;
std::vector<AST_NodePtr> m_match_stack; std::vector<eval::AST_Node_Impl_Ptr<Tracer>> m_match_stack;
struct Position struct Position
@ -293,11 +283,13 @@ namespace chaiscript
Position m_position; Position m_position;
Tracer m_tracer;
Optimizer m_optimizer; Optimizer m_optimizer;
public: public:
explicit ChaiScript_Parser(Optimizer optimizer=Optimizer()) explicit ChaiScript_Parser(Tracer tracer = Tracer(), Optimizer optimizer=Optimizer())
: m_optimizer(std::move(optimizer)) : m_tracer(std::move(tracer)),
m_optimizer(std::move(optimizer))
{ {
m_match_stack.reserve(2); m_match_stack.reserve(2);
} }
@ -314,8 +306,8 @@ namespace chaiscript
/// Prints the parsed ast_nodes as a tree /// Prints the parsed ast_nodes as a tree
void debug_print(AST_NodePtr t, std::string prepend = "") const override { void debug_print(AST_NodePtr t, std::string prepend = "") const override {
std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start().line << ", " << t->start().column << '\n'; std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start().line << ", " << t->start().column << '\n';
for (unsigned int j = 0; j < t->children.size(); ++j) { for (const auto &node : t->get_children()) {
debug_print(t->children[j], prepend + " "); debug_print(node, prepend + " ");
} }
} }
@ -347,7 +339,7 @@ namespace chaiscript
} }
}(); }();
std::vector<AST_NodePtr> new_children; std::vector<eval::AST_Node_Impl_Ptr<Tracer>> new_children;
if (is_deep) { if (is_deep) {
new_children.assign(std::make_move_iterator(m_match_stack.begin() + static_cast<int>(t_match_start)), new_children.assign(std::make_move_iterator(m_match_stack.begin() + static_cast<int>(t_match_start)),
@ -358,7 +350,7 @@ namespace chaiscript
/// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position /// \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( m_match_stack.push_back(
m_optimizer.optimize( m_optimizer.optimize(
chaiscript::make_shared<chaiscript::AST_Node, NodeType>( chaiscript::make_shared<chaiscript::eval::AST_Node_Impl<Tracer>, NodeType>(
std::move(t_text), std::move(t_text),
std::move(filepos), std::move(filepos),
std::move(new_children))) std::move(new_children)))
@ -669,9 +661,9 @@ namespace chaiscript
} }
template<typename T, typename ... Param> template<typename T, typename ... Param>
std::shared_ptr<AST_Node> make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param) std::shared_ptr<eval::AST_Node_Impl<Tracer>> make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param)
{ {
return chaiscript::make_shared<AST_Node, T>(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward<Param>(param)...); return chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, T>(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward<Param>(param)...);
} }
/// Reads a number from the input, detecting if it's an integer or floating point /// Reads a number from the input, detecting if it's an integer or floating point
@ -687,20 +679,20 @@ namespace chaiscript
if (Hex_()) { if (Hex_()) {
auto match = Position::str(start, m_position); auto match = Position::str(start, m_position);
auto bv = buildInt(16, match, true); auto bv = buildInt(16, match, true);
m_match_stack.emplace_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv))); m_match_stack.emplace_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
return true; return true;
} }
if (Binary_()) { if (Binary_()) {
auto match = Position::str(start, m_position); auto match = Position::str(start, m_position);
auto bv = buildInt(2, match, true); auto bv = buildInt(2, match, true);
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
return true; return true;
} }
if (Float_()) { if (Float_()) {
auto match = Position::str(start, m_position); auto match = Position::str(start, m_position);
auto bv = buildFloat(match); auto bv = buildFloat(match);
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
return true; return true;
} }
else { else {
@ -708,11 +700,11 @@ namespace chaiscript
auto match = Position::str(start, m_position); auto match = Position::str(start, m_position);
if (!match.empty() && (match[0] == '0')) { if (!match.empty() && (match[0] == '0')) {
auto bv = buildInt(8, match, false); auto bv = buildInt(8, match, false);
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
} }
else if (!match.empty()) { else if (!match.empty()) {
auto bv = buildInt(10, match, false); auto bv = buildInt(10, match, false);
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(std::move(match), start.line, start.col, std::move(bv))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
} else { } else {
return false; return false;
} }
@ -773,20 +765,20 @@ namespace chaiscript
const auto text = Position::str(start, m_position); const auto text = Position::str(start, m_position);
if (text == "true") { if (text == "true") {
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col, const_var(true))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, const_var(true)));
} else if (text == "false") { } else if (text == "false") {
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col, const_var(false))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, const_var(false)));
} else if (text == "Infinity") { } else if (text == "Infinity") {
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col, m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
const_var(std::numeric_limits<double>::infinity()))); const_var(std::numeric_limits<double>::infinity())));
} else if (text == "NaN") { } else if (text == "NaN") {
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col, m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
const_var(std::numeric_limits<double>::quiet_NaN()))); const_var(std::numeric_limits<double>::quiet_NaN())));
} else if (text == "_") { } else if (text == "_") {
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(text, start.line, start.col, m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
Boxed_Value(std::make_shared<dispatch::Placeholder_Object>()))); Boxed_Value(std::make_shared<dispatch::Placeholder_Object>())));
} else { } else {
m_match_stack.push_back(make_node<eval::Id_AST_Node>( m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(
[&]()->std::string{ [&]()->std::string{
if (*start == '`') { if (*start == '`') {
// 'escaped' literal, like an operator name // 'escaped' literal, like an operator name
@ -820,7 +812,7 @@ namespace chaiscript
Id(); Id();
} }
build_match<eval::Arg_AST_Node>(prev_stack_top); build_match<eval::Arg_AST_Node<Tracer>>(prev_stack_top);
return true; return true;
} }
@ -1020,11 +1012,11 @@ namespace chaiscript
if (*s == '{') { if (*s == '{') {
//We've found an interpolation point //We've found an interpolation point
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(match, start.line, start.col, const_var(match))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(match)));
if (cparser.is_interpolated) { if (cparser.is_interpolated) {
//If we've seen previous interpolation, add on instead of making a new one //If we've seen previous interpolation, add on instead of making a new one
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+"); build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, "+");
} }
//We've finished with the part of the string up to this point, so clear it //We've finished with the part of the string up to this point, so clear it
@ -1044,19 +1036,19 @@ namespace chaiscript
const auto tostr_stack_top = m_match_stack.size(); const auto tostr_stack_top = m_match_stack.size();
m_match_stack.push_back(make_node<eval::Id_AST_Node>("to_string", start.line, start.col)); m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>("to_string", start.line, start.col));
const auto ev_stack_top = m_match_stack.size(); const auto ev_stack_top = m_match_stack.size();
try { try {
m_match_stack.push_back(parse(eval_match, "instr eval")); m_match_stack.push_back(parse_instr_eval(eval_match));
} catch (const exception::eval_error &e) { } catch (const exception::eval_error &e) {
throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename); throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename);
} }
build_match<eval::Arg_List_AST_Node>(ev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(ev_stack_top);
build_match<eval::Fun_Call_AST_Node>(tostr_stack_top); build_match<eval::Fun_Call_AST_Node<Tracer>>(tostr_stack_top);
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+"); build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, "+");
} else { } else {
throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename); throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename);
} }
@ -1073,10 +1065,10 @@ namespace chaiscript
return cparser.is_interpolated; return cparser.is_interpolated;
}(); }();
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(match, start.line, start.col, const_var(match))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(match)));
if (is_interpolated) { if (is_interpolated) {
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+"); build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, "+");
} }
return true; return true;
@ -1138,7 +1130,7 @@ namespace chaiscript
throw exception::eval_error("Single-quoted strings must be 1 character long", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Single-quoted strings must be 1 character long", File_Position(m_position.line, m_position.col), *m_filename);
} }
m_match_stack.push_back(make_node<eval::Constant_AST_Node>(match, start.line, start.col, const_var(char(match.at(0))))); m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(char(match.at(0)))));
return true; return true;
} }
else { else {
@ -1291,7 +1283,7 @@ namespace chaiscript
} }
} }
} }
build_match<eval::Arg_List_AST_Node>(prev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
SkipWS(true); SkipWS(true);
@ -1316,7 +1308,7 @@ namespace chaiscript
} }
} }
} }
build_match<eval::Arg_List_AST_Node>(prev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
SkipWS(true); SkipWS(true);
@ -1342,7 +1334,7 @@ namespace chaiscript
} }
} }
build_match<eval::Arg_List_AST_Node>(prev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
SkipWS(true); SkipWS(true);
@ -1358,7 +1350,7 @@ namespace chaiscript
if (Value_Range()) { if (Value_Range()) {
retval = true; retval = true;
build_match<eval::Arg_List_AST_Node>(prev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
} else if (Map_Pair()) { } else if (Map_Pair()) {
retval = true; retval = true;
while (Eol()) {} while (Eol()) {}
@ -1368,7 +1360,7 @@ namespace chaiscript
throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
} }
} }
build_match<eval::Arg_List_AST_Node>(prev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
} else if (Operator()) { } else if (Operator()) {
retval = true; retval = true;
while (Eol()) {} while (Eol()) {}
@ -1378,7 +1370,7 @@ namespace chaiscript
throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
} }
} }
build_match<eval::Arg_List_AST_Node>(prev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
} }
SkipWS(true); SkipWS(true);
@ -1402,7 +1394,7 @@ namespace chaiscript
} }
} else { } else {
// make sure we always have the same number of nodes // make sure we always have the same number of nodes
build_match<eval::Arg_List_AST_Node>(prev_stack_top); build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
} }
if (Char('(')) { if (Char('(')) {
@ -1421,7 +1413,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Lambda_AST_Node>(prev_stack_top); build_match<eval::Lambda_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1472,9 +1464,9 @@ namespace chaiscript
} }
if (is_method || t_class_context) { if (is_method || t_class_context) {
build_match<eval::Method_AST_Node>(prev_stack_top); build_match<eval::Method_AST_Node<Tracer>>(prev_stack_top);
} else { } else {
build_match<eval::Def_AST_Node>(prev_stack_top); build_match<eval::Def_AST_Node<Tracer>>(prev_stack_top);
} }
} }
@ -1519,7 +1511,7 @@ namespace chaiscript
if (!Block()) { if (!Block()) {
throw exception::eval_error("Incomplete 'catch' block", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete 'catch' block", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Catch_AST_Node>(catch_stack_top); build_match<eval::Catch_AST_Node<Tracer>>(catch_stack_top);
has_matches = true; has_matches = true;
} }
} }
@ -1532,10 +1524,10 @@ namespace chaiscript
if (!Block()) { if (!Block()) {
throw exception::eval_error("Incomplete 'finally' block", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete 'finally' block", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Finally_AST_Node>(finally_stack_top); build_match<eval::Finally_AST_Node<Tracer>>(finally_stack_top);
} }
build_match<eval::Try_AST_Node>(prev_stack_top); build_match<eval::Try_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1582,7 +1574,7 @@ namespace chaiscript
} }
} }
build_match<eval::If_AST_Node>(prev_stack_top); build_match<eval::If_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1608,7 +1600,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete 'class' block", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete 'class' block", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Class_AST_Node>(prev_stack_top); build_match<eval::Class_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1638,7 +1630,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete 'while' block", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete 'while' block", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::While_AST_Node>(prev_stack_top); build_match<eval::While_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1653,7 +1645,7 @@ namespace chaiscript
{ {
throw exception::eval_error("'for' loop initial statment missing", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("'for' loop initial statment missing", File_Position(m_position.line, m_position.col), *m_filename);
} else { } else {
m_match_stack.push_back(chaiscript::make_shared<AST_Node, eval::Noop_AST_Node>()); m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
} }
} }
@ -1663,13 +1655,13 @@ namespace chaiscript
{ {
throw exception::eval_error("'for' loop condition missing", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("'for' loop condition missing", File_Position(m_position.line, m_position.col), *m_filename);
} else { } else {
m_match_stack.push_back(chaiscript::make_shared<AST_Node, eval::Noop_AST_Node>()); m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
} }
} }
if (!Equation()) if (!Equation())
{ {
m_match_stack.push_back(chaiscript::make_shared<AST_Node, eval::Noop_AST_Node>()); m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
} }
return true; return true;
@ -1699,7 +1691,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename); 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); build_match<eval::For_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1729,7 +1721,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete 'case' block", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete 'case' block", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Case_AST_Node>(prev_stack_top); build_match<eval::Case_AST_Node<Tracer>>(prev_stack_top);
} else if (Keyword("default")) { } else if (Keyword("default")) {
retval = true; retval = true;
@ -1739,7 +1731,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete 'default' block", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete 'default' block", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Default_AST_Node>(prev_stack_top); build_match<eval::Default_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1779,7 +1771,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Switch_AST_Node>(prev_stack_top); build_match<eval::Switch_AST_Node<Tracer>>(prev_stack_top);
return true; return true;
} else { } else {
@ -1804,10 +1796,10 @@ namespace chaiscript
} }
if (m_match_stack.size() == prev_stack_top) { if (m_match_stack.size() == prev_stack_top) {
m_match_stack.push_back(chaiscript::make_shared<AST_Node, eval::Noop_AST_Node>()); m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
} }
build_match<eval::Block_AST_Node>(prev_stack_top); build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1828,10 +1820,10 @@ namespace chaiscript
} }
if (m_match_stack.size() == prev_stack_top) { if (m_match_stack.size() == prev_stack_top) {
m_match_stack.push_back(chaiscript::make_shared<AST_Node, eval::Noop_AST_Node>()); m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
} }
build_match<eval::Block_AST_Node>(prev_stack_top); build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -1843,7 +1835,7 @@ namespace chaiscript
if (Keyword("return")) { if (Keyword("return")) {
Operator(); Operator();
build_match<eval::Return_AST_Node>(prev_stack_top); build_match<eval::Return_AST_Node<Tracer>>(prev_stack_top);
return true; return true;
} else { } else {
return false; return false;
@ -1855,7 +1847,7 @@ namespace chaiscript
const auto prev_stack_top = m_match_stack.size(); const auto prev_stack_top = m_match_stack.size();
if (Keyword("break")) { if (Keyword("break")) {
build_match<eval::Break_AST_Node>(prev_stack_top); build_match<eval::Break_AST_Node<Tracer>>(prev_stack_top);
return true; return true;
} else { } else {
return false; return false;
@ -1867,7 +1859,7 @@ namespace chaiscript
const auto prev_stack_top = m_match_stack.size(); const auto prev_stack_top = m_match_stack.size();
if (Keyword("continue")) { if (Keyword("continue")) {
build_match<eval::Continue_AST_Node>(prev_stack_top); build_match<eval::Continue_AST_Node<Tracer>>(prev_stack_top);
return true; return true;
} else { } else {
return false; return false;
@ -1896,14 +1888,14 @@ namespace chaiscript
throw exception::eval_error("Incomplete function call", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete function call", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Fun_Call_AST_Node>(prev_stack_top); build_match<eval::Fun_Call_AST_Node<Tracer>>(prev_stack_top);
/// \todo Work around for method calls until we have a better solution /// \todo Work around for method calls until we have a better solution
if (!m_match_stack.back()->children.empty()) { if (!m_match_stack.back()->children.empty()) {
if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) {
if (m_match_stack.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); if (m_match_stack.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
if (m_match_stack.back()->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); if (m_match_stack.back()->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
AST_NodePtr dot_access = m_match_stack.back()->children[0]; auto dot_access = m_match_stack.back()->children[0];
AST_NodePtr func_call = m_match_stack.back(); auto func_call = m_match_stack.back();
m_match_stack.pop_back(); m_match_stack.pop_back();
func_call->children.erase(func_call->children.begin()); func_call->children.erase(func_call->children.begin());
if (dot_access->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); if (dot_access->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
@ -1921,7 +1913,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete array access", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete array access", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Array_Call_AST_Node>(prev_stack_top); build_match<eval::Array_Call_AST_Node<Tracer>>(prev_stack_top);
} }
else if (Symbol(".")) { else if (Symbol(".")) {
has_more = true; has_more = true;
@ -1932,7 +1924,7 @@ namespace chaiscript
if ( std::distance(m_match_stack.begin() + static_cast<int>(prev_stack_top), m_match_stack.end()) != 2) { if ( std::distance(m_match_stack.begin() + static_cast<int>(prev_stack_top), m_match_stack.end()) != 2) {
throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Dot_Access_AST_Node>(prev_stack_top); build_match<eval::Dot_Access_AST_Node<Tracer>>(prev_stack_top);
} }
} }
} }
@ -1953,14 +1945,14 @@ namespace chaiscript
throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Attr_Decl_AST_Node>(prev_stack_top); build_match<eval::Attr_Decl_AST_Node<Tracer>>(prev_stack_top);
} else if (Keyword("auto") || Keyword("var") ) { } else if (Keyword("auto") || Keyword("var") ) {
retval = true; retval = true;
if (Reference()) { if (Reference()) {
// we built a reference node - continue // we built a reference node - continue
} else if (Id()) { } else if (Id()) {
build_match<eval::Var_Decl_AST_Node>(prev_stack_top); build_match<eval::Var_Decl_AST_Node<Tracer>>(prev_stack_top);
} else { } else {
throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename);
} }
@ -1972,7 +1964,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete global declaration", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete global declaration", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Global_Decl_AST_Node>(prev_stack_top); build_match<eval::Global_Decl_AST_Node<Tracer>>(prev_stack_top);
} else if (Keyword("attr")) { } else if (Keyword("attr")) {
retval = true; retval = true;
@ -1987,7 +1979,7 @@ namespace chaiscript
} }
build_match<eval::Attr_Decl_AST_Node>(prev_stack_top); build_match<eval::Attr_Decl_AST_Node<Tracer>>(prev_stack_top);
} }
return retval; return retval;
@ -2020,17 +2012,17 @@ namespace chaiscript
} }
if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) {
if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) {
build_match<eval::Inline_Range_AST_Node>(prev_stack_top); build_match<eval::Inline_Range_AST_Node<Tracer>>(prev_stack_top);
} }
else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) {
build_match<eval::Inline_Map_AST_Node>(prev_stack_top); build_match<eval::Inline_Map_AST_Node<Tracer>>(prev_stack_top);
} }
else { else {
build_match<eval::Inline_Array_AST_Node>(prev_stack_top); build_match<eval::Inline_Array_AST_Node<Tracer>>(prev_stack_top);
} }
} }
else { else {
build_match<eval::Inline_Array_AST_Node>(prev_stack_top); build_match<eval::Inline_Array_AST_Node<Tracer>>(prev_stack_top);
} }
return true; return true;
@ -2048,7 +2040,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete '&' expression", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete '&' expression", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Reference_AST_Node>(prev_stack_top); build_match<eval::Reference_AST_Node<Tracer>>(prev_stack_top);
return true; return true;
} else { } else {
return false; return false;
@ -2069,7 +2061,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete prefix '" + oper + "' expression", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete prefix '" + oper + "' expression", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Prefix_AST_Node>(prev_stack_top, oper); build_match<eval::Prefix_AST_Node<Tracer>>(prev_stack_top, oper);
return true; return true;
} }
} }
@ -2114,7 +2106,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete '" + oper + "' expression", throw exception::eval_error("Incomplete '" + oper + "' expression",
File_Position(m_position.line, m_position.col), *m_filename); File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Ternary_Cond_AST_Node>(prev_stack_top); build_match<eval::Ternary_Cond_AST_Node<Tracer>>(prev_stack_top);
} }
else { else {
throw exception::eval_error("Incomplete '" + oper + "' expression", throw exception::eval_error("Incomplete '" + oper + "' expression",
@ -2130,14 +2122,14 @@ namespace chaiscript
case(Operator_Precidence::Bitwise_Xor) : case(Operator_Precidence::Bitwise_Xor) :
case(Operator_Precidence::Bitwise_Or) : case(Operator_Precidence::Bitwise_Or) :
case(Operator_Precidence::Comparison) : case(Operator_Precidence::Comparison) :
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, oper); build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, oper);
break; break;
case(Operator_Precidence::Logical_And) : case(Operator_Precidence::Logical_And) :
build_match<eval::Logical_And_AST_Node>(prev_stack_top, oper); build_match<eval::Logical_And_AST_Node<Tracer>>(prev_stack_top, oper);
break; break;
case(Operator_Precidence::Logical_Or) : case(Operator_Precidence::Logical_Or) :
build_match<eval::Logical_Or_AST_Node>(prev_stack_top, oper); build_match<eval::Logical_Or_AST_Node<Tracer>>(prev_stack_top, oper);
break; break;
default: default:
@ -2167,7 +2159,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete map pair", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete map pair", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Map_Pair_AST_Node>(prev_stack_top); build_match<eval::Map_Pair_AST_Node<Tracer>>(prev_stack_top);
} }
else { else {
m_position = prev_pos; m_position = prev_pos;
@ -2194,7 +2186,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete value range", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete value range", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Value_Range_AST_Node>(prev_stack_top); build_match<eval::Value_Range_AST_Node<Tracer>>(prev_stack_top);
} }
else { else {
m_position = prev_pos; m_position = prev_pos;
@ -2220,7 +2212,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename); throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename);
} }
build_match<eval::Equation_AST_Node>(prev_stack_top, sym); build_match<eval::Equation_AST_Node<Tracer>>(prev_stack_top, sym);
return true; return true;
} }
} }
@ -2298,11 +2290,26 @@ namespace chaiscript
AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override
{ {
ChaiScript_Parser<Optimizer> parser(*this); ChaiScript_Parser<Tracer, Optimizer> parser(*this);
parser.m_match_stack.clear(); parser.m_match_stack.clear();
return parser.parse_internal(t_input, t_fname); return parser.parse_internal(t_input, t_fname);
} }
eval::AST_Node_Impl_Ptr<Tracer> parse_instr_eval(const std::string &t_input)
{
const auto last_position = m_position;
const auto last_filename = m_filename;
const auto last_match_stack = std::exchange(m_match_stack, decltype(m_match_stack){});
const auto retval = parse_internal(t_input, "instr eval");
m_position = std::move(last_position);
m_filename = std::move(last_filename);
m_match_stack = std::move(last_match_stack);
return std::dynamic_pointer_cast<eval::AST_Node_Impl<Tracer>>(retval);
}
/// Parses the given input string, tagging parsed ast_nodes with the given m_filename. /// Parses the given input string, tagging parsed ast_nodes with the given m_filename.
AST_NodePtr parse_internal(const std::string &t_input, std::string t_fname) { AST_NodePtr parse_internal(const std::string &t_input, std::string t_fname) {
m_position = Position(t_input.begin(), t_input.end()); m_position = Position(t_input.begin(), t_input.end());
@ -2319,10 +2326,10 @@ namespace chaiscript
if (m_position.has_more()) { if (m_position.has_more()) {
throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname); throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), t_fname);
} else { } else {
build_match<eval::File_AST_Node>(0); build_match<eval::File_AST_Node<Tracer>>(0);
} }
} else { } else {
m_match_stack.push_back(chaiscript::make_shared<AST_Node, eval::Noop_AST_Node>()); m_match_stack.push_back(chaiscript::make_shared<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
} }
return m_match_stack.front(); return m_match_stack.front();

View File

@ -0,0 +1,43 @@
// 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_TRACER_HPP_
#define CHAISCRIPT_TRACER_HPP_
namespace chaiscript {
namespace eval {
struct Noop_Tracer
{
template<typename T>
static void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
{
}
};
template<typename ... T>
struct Tracer : T...
{
Tracer() = default;
Tracer(T ... t)
: T(std::move(t))...
{
}
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(void)std::initializer_list<int>{ (T::trace(ds, node), 0)... };
}
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
ds->get_parser().get_tracer<Tracer<T...>>().do_trace(ds, node);
}
};
}
}
#endif