diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 79e24d6..0247c06 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -132,7 +132,7 @@ namespace chaiscript class AST_Node_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl, - Comparison, Additive, Multiplicative, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, + Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, Logical_And, Logical_Or @@ -146,7 +146,7 @@ namespace chaiscript */ const char *ast_node_type_to_string(int ast_node_type) { const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl", - "Comparison", "Additive", "Multiplicative", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String", + "Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String", "Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range", "Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or", "Logical_And", "Logical_Or"}; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 1951c6c..edef150 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -354,18 +354,169 @@ namespace chaiscript virtual ~Comparison_AST_Node() {} }; - struct Additive_AST_Node : public Binary_Operator_AST_Node { + struct Addition_AST_Node : public Binary_Operator_AST_Node { public: - Additive_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Additive, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Addition_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Addition, + const boost::shared_ptr &t_fname=boost::shared_ptr(), + int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Additive_AST_Node() {} + virtual ~Addition_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + Boxed_Value retval = this->children[0]->eval(t_ss); + Boxed_Value rhs(this->children[1]->eval(t_ss)); + Operators::Opers oper = Operators::sum; + + try { + if (oper != Operators::invalid && retval.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) + { + // If it's an arithmetic operation we want to short circuit dispatch + try{ + retval = Boxed_Numeric::do_oper(oper, retval, rhs); + } catch (...) { + throw exception::eval_error("Error with numeric operator calling: +"); + } + + } else { + retval = t_ss.call_function("+", retval, rhs); + } + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate '+'"); + } + return retval; + } }; - struct Multiplicative_AST_Node : public Binary_Operator_AST_Node { + struct Subtraction_AST_Node : public Binary_Operator_AST_Node { public: - Multiplicative_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplicative, const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Subtraction_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Subtraction, + const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, + int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } - virtual ~Multiplicative_AST_Node() {} + virtual ~Subtraction_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + Boxed_Value retval = this->children[0]->eval(t_ss); + Boxed_Value rhs(this->children[1]->eval(t_ss)); + Operators::Opers oper = Operators::difference; + + try { + if (oper != Operators::invalid && retval.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) + { + // If it's an arithmetic operation we want to short circuit dispatch + try{ + retval = Boxed_Numeric::do_oper(oper, retval, rhs); + } catch (...) { + throw exception::eval_error("Error with numeric operator calling: -"); + } + + } else { + retval = t_ss.call_function("-", retval, rhs); + } + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate '-'"); + } + return retval; + } + }; + + struct Multiplication_AST_Node : public Binary_Operator_AST_Node { + public: + Multiplication_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplication, + const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, + int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Multiplication_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + Boxed_Value retval = this->children[0]->eval(t_ss); + Boxed_Value rhs(this->children[1]->eval(t_ss)); + Operators::Opers oper = Operators::product; + + try { + if (oper != Operators::invalid && retval.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) + { + // If it's an arithmetic operation we want to short circuit dispatch + try{ + retval = Boxed_Numeric::do_oper(oper, retval, rhs); + } catch (...) { + throw exception::eval_error("Error with numeric operator calling: *"); + } + + } else { + retval = t_ss.call_function("*", rhs); + } + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate '*'"); + } + return retval; + } + }; + + struct Division_AST_Node : public Binary_Operator_AST_Node { + public: + Division_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Division, + const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, + int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Division_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + Boxed_Value retval = this->children[0]->eval(t_ss); + Boxed_Value rhs(this->children[1]->eval(t_ss)); + Operators::Opers oper = Operators::quotient; + + try { + if (oper != Operators::invalid && retval.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) + { + // If it's an arithmetic operation we want to short circuit dispatch + try{ + retval = Boxed_Numeric::do_oper(oper, retval, rhs); + } catch (...) { + throw exception::eval_error("Error with numeric operator calling: /"); + } + + } else { + retval = t_ss.call_function("/", retval, rhs); + } + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate '/'"); + } + return retval; + } + }; + + struct Modulus_AST_Node : public Binary_Operator_AST_Node { + public: + Modulus_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Modulus, + const boost::shared_ptr &t_fname=boost::shared_ptr(), int t_start_line = 0, + int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : + Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Modulus_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) { + Boxed_Value retval = this->children[0]->eval(t_ss); + Boxed_Value rhs(this->children[1]->eval(t_ss)); + Operators::Opers oper = Operators::remainder; + + try { + if (oper != Operators::invalid && retval.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) + { + // If it's an arithmetic operation we want to short circuit dispatch + try{ + retval = Boxed_Numeric::do_oper(oper, retval, rhs); + } catch (...) { + throw exception::eval_error("Error with numeric operator calling: %"); + } + + } else { + retval = t_ss.call_function("%", retval, rhs); + } + } + catch(const exception::dispatch_error &){ + throw exception::eval_error("Can not find appropriate '%'"); + } + return retval; + } }; struct Array_Call_AST_Node : public AST_Node { diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 217db2b..a5212a4 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -111,18 +111,20 @@ namespace chaiscript shift.push_back(">>"); m_operator_matches.push_back(shift); - m_operators.push_back(AST_Node_Type::Additive); - std::vector additive; - additive.push_back("+"); - additive.push_back("-"); - m_operator_matches.push_back(additive); + //We share precedence here but then separate them later + m_operators.push_back(AST_Node_Type::Addition); + std::vector addition; + addition.push_back("+"); + addition.push_back("-"); + m_operator_matches.push_back(addition); - m_operators.push_back(AST_Node_Type::Multiplicative); - std::vector multiplicative; - multiplicative.push_back("*"); - multiplicative.push_back("/"); - multiplicative.push_back("%"); - m_operator_matches.push_back(multiplicative); + //We share precedence here but then separate them later + m_operators.push_back(AST_Node_Type::Multiplication); + std::vector multiplication; + multiplication.push_back("*"); + multiplication.push_back("/"); + multiplication.push_back("%"); + m_operator_matches.push_back(multiplication); m_operators.push_back(AST_Node_Type::Dot_Access); std::vector dot_access; @@ -655,7 +657,6 @@ namespace chaiscript bool saw_interpolation_marker = false; size_t prev_stack_top = m_match_stack.size(); - //for (std::string::iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { std::string::const_iterator s = start + 1, end = m_input_pos - 1; while (s != end) { @@ -665,13 +666,11 @@ namespace chaiscript if (is_interpolated) { //If we've seen previous interpolation, add on instead of making a new one - AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); m_match_stack.push_back(t); - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); } else { AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); @@ -681,9 +680,6 @@ namespace chaiscript //We've finished with the part of the string up to this point, so clear it match = ""; - AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); - std::string eval_match; ++s; @@ -718,7 +714,7 @@ namespace chaiscript build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); } else { throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); @@ -765,13 +761,10 @@ namespace chaiscript } } if (is_interpolated) { - AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); m_match_stack.push_back(t); - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); } else { AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); @@ -1703,7 +1696,7 @@ namespace chaiscript bool Operator(size_t t_precedence = 0) { bool retval = false; - + AST_NodePtr oper; size_t prev_stack_top = m_match_stack.size(); if (t_precedence < m_operators.size()) { @@ -1724,11 +1717,30 @@ namespace chaiscript case(AST_Node_Type::Dot_Access) : build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); break; - case(AST_Node_Type::Additive) : - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + case(AST_Node_Type::Addition) : + oper = m_match_stack.at(m_match_stack.size()-2); + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (oper->text == "+") { + build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top); + } + else if (oper->text == "-") { + build_match(AST_NodePtr(new eval::Subtraction_AST_Node()), prev_stack_top); + } break; - case(AST_Node_Type::Multiplicative) : - build_match(AST_NodePtr(new eval::Multiplicative_AST_Node()), prev_stack_top); + case(AST_Node_Type::Multiplication) : + oper = m_match_stack.at(m_match_stack.size()-2); + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (oper->text == "*") { + build_match(AST_NodePtr(new eval::Multiplication_AST_Node()), prev_stack_top); + } + else if (oper->text == "/") { + build_match(AST_NodePtr(new eval::Division_AST_Node()), prev_stack_top); + } + else if (oper->text == "%") { + build_match(AST_NodePtr(new eval::Modulus_AST_Node()), prev_stack_top); + } break; case(AST_Node_Type::Shift) : build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top);