Allow for parse time evaluation of const values.

The goal is to allow for more evaluation at parse time, in general, to
increase eval time performance.

 - Make AST_Node non-constructable except by derived classes.
 - Make data in AST_Node const (as much as possible).
 - Replace reflection "text = " with replace_child() (where the
   replacement must be with a new parse tree).
 - Evaluate floats, strings, ints, chars at parse time to avoid repeat
   evaluations (~10% speed up in loops in -O3)
This commit is contained in:
Jason Turner
2011-03-27 08:17:04 -06:00
parent bbe89e61bc
commit d6b8e32373
5 changed files with 84 additions and 51 deletions

View File

@@ -61,25 +61,14 @@ namespace chaiscript
* The struct that doubles as both a parser ast_node and an AST node * The struct that doubles as both a parser ast_node and an AST node
*/ */
struct AST_Node { struct AST_Node {
std::string text; public:
int identifier; const std::string text;
boost::shared_ptr<std::string> filename; const int identifier;
boost::shared_ptr<const std::string> filename;
File_Position start, end; File_Position start, end;
std::vector<AST_NodePtr> children; std::vector<AST_NodePtr> children;
AST_NodePtr annotation; AST_NodePtr annotation;
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(t_ast_node_text), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{
}
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname) :
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
/** /**
* Prints the contents of an AST node, including its children, recursively * Prints the contents of an AST node, including its children, recursively
*/ */
@@ -99,10 +88,30 @@ namespace chaiscript
return to_string(); return to_string();
} }
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &) { virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &)
{
Boxed_Value bv; Boxed_Value bv;
throw std::runtime_error("Undispatched ast_node (internal error)"); throw std::runtime_error("Undispatched ast_node (internal error)");
} }
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
{
std::replace(children.begin(), children.end(), t_child, t_new_child);
}
protected:
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(t_ast_node_text), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{
}
AST_Node(const std::string &t_ast_node_text, int t_id, const boost::shared_ptr<std::string> &t_fname) :
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
}; };

View File

@@ -89,23 +89,30 @@ namespace chaiscript
struct Int_AST_Node : public AST_Node { struct Int_AST_Node : public AST_Node {
public: public:
Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), m_value(const_var(int(atoi(this->text.c_str())))) { }
virtual ~Int_AST_Node() {} virtual ~Int_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){
return const_var(int(atoi(this->text.c_str()))); return m_value;
} }
private:
Boxed_Value m_value;
}; };
struct Float_AST_Node : public AST_Node { struct Float_AST_Node : public AST_Node {
public: public:
Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(double(atof(this->text.c_str())))) { }
virtual ~Float_AST_Node() {} virtual ~Float_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){
return const_var(double(atof(this->text.c_str()))); return m_value;
} }
private:
Boxed_Value m_value;
}; };
struct Id_AST_Node : public AST_Node { struct Id_AST_Node : public AST_Node {
@@ -472,7 +479,7 @@ namespace chaiscript
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
t_ss.set_stack(prev_stack); t_ss.set_stack(prev_stack);
throw exception::eval_error(std::string(e.what())); throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name);
} }
catch(detail::Return_Value &rv) { catch(detail::Return_Value &rv) {
t_ss.set_stack(prev_stack); t_ss.set_stack(prev_stack);
@@ -510,23 +517,30 @@ namespace chaiscript
struct Quoted_String_AST_Node : public AST_Node { struct Quoted_String_AST_Node : public AST_Node {
public: public:
Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Quoted_String, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Quoted_String, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(this->text)) { }
virtual ~Quoted_String_AST_Node() {} virtual ~Quoted_String_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &) {
return const_var(this->text); return m_value;
} }
private:
Boxed_Value m_value;
}; };
struct Single_Quoted_String_AST_Node : public AST_Node { struct Single_Quoted_String_AST_Node : public AST_Node {
public: public:
Single_Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Single_Quoted_String, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Single_Quoted_String_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Single_Quoted_String, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(char(this->text[0]))) { }
virtual ~Single_Quoted_String_AST_Node() {} virtual ~Single_Quoted_String_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &){
return const_var(char(this->text[0])); return m_value;
} }
private:
Boxed_Value m_value;
}; };
struct Lambda_AST_Node : public AST_Node { struct Lambda_AST_Node : public AST_Node {
@@ -656,7 +670,7 @@ namespace chaiscript
While_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::While, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : While_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::While, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~While_AST_Node() {} virtual ~While_AST_Node() {}
virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_ss) {
bool cond; bool cond;
t_ss.new_scope(); t_ss.new_scope();

View File

@@ -1312,7 +1312,12 @@ namespace chaiscript
has_matches = false; has_matches = false;
if (Keyword("else", true)) { if (Keyword("else", true)) {
if (Keyword("if")) { if (Keyword("if")) {
m_match_stack.back()->text = "else if"; AST_NodePtr back(m_match_stack.back());
m_match_stack.back() = AST_NodePtr(new eval::If_AST_Node("else if", back->identifier));
m_match_stack.back()->start = back->start;
m_match_stack.back()->end = back->end;
m_match_stack.back()->children = back->children;
m_match_stack.back()->annotation = back->annotation;
if (!Char('(')) { if (!Char('(')) {
throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename);
} }

View File

@@ -62,7 +62,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
CHAISCRIPT_CLASS( m, CHAISCRIPT_CLASS( m,
chaiscript::AST_Node, chaiscript::AST_Node,
(chaiscript::AST_Node (const std::string &, int, const boost::shared_ptr<std::string> &)), ,
((text)) ((text))
((identifier)) ((identifier))
((filename)) ((filename))
@@ -70,6 +70,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
((end)) ((end))
((internal_to_string)) ((internal_to_string))
((children)) ((children))
((replace_child))
); );
CHAISCRIPT_CLASS( m, CHAISCRIPT_CLASS( m,

View File

@@ -8,7 +8,11 @@ assert_equal(eval(a), 7)
var childs := a.children.front().children var childs := a.children.front().children
var node := childs[0] var node := childs[0]
node.text = "9" var parser2 := ChaiScript_Parser()
parser2.parse("9", "INPUT")
a.children.front().replace_child(childs[0], parser2.ast())
assert_equal(eval(a), 13) assert_equal(eval(a), 13)
assert_equal(node.filename, "INPUT") assert_equal(node.filename, "INPUT")