diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 23f3b9c..f677674 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -23,7 +23,7 @@ namespace chaiscript 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, Reference, Switch, Case, Default + Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond }; }; @@ -37,7 +37,7 @@ namespace chaiscript "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", "Reference", "Switch", "Case", "Default"}; + "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition"}; return ast_node_types[ast_node_type]; } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 3775c2d..618fd31 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -687,6 +687,29 @@ namespace chaiscript }; + struct Ternary_Cond_AST_Node : public AST_Node { + public: + Ternary_Cond_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const std::shared_ptr &t_fname=std::shared_ptr(), 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) { } + virtual ~Ternary_Cond_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ + bool cond; + try { + cond = boxed_cast(this->children[0]->eval(t_ss)); + } + catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("If condition not boolean"); + } + + if (cond) { + return this->children[1]->eval(t_ss); + } + else { + return this->children[2]->eval(t_ss); + } + } + }; + struct If_AST_Node : public AST_Node { public: If_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const std::shared_ptr &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 6cdf964..d350e37 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -67,6 +67,11 @@ namespace chaiscript void setup_operators() { + m_operators.push_back(AST_Node_Type::Ternary_Cond); + std::vector ternary_cond; + ternary_cond.push_back("?"); + m_operator_matches.push_back(ternary_cond); + m_operators.push_back(AST_Node_Type::Logical_Or); std::vector logical_or; logical_or.push_back("||"); @@ -132,6 +137,7 @@ namespace chaiscript m_alphabet[a][c]=false; } } + m_alphabet[detail::symbol_alphabet][static_cast('?')]=true; m_alphabet[detail::symbol_alphabet][static_cast('+')]=true; m_alphabet[detail::symbol_alphabet][static_cast('-')]=true; m_alphabet[detail::symbol_alphabet][static_cast('*')]=true; @@ -1841,6 +1847,23 @@ namespace chaiscript case(AST_Node_Type::Comparison) : build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top); break; + case(AST_Node_Type::Ternary_Cond) : + m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, + m_match_stack.begin() + m_match_stack.size() - 1); + if (Symbol(":")) { + if (!Operator(t_precedence+1)) { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + build_match(AST_NodePtr(new eval::Ternary_Cond_AST_Node()), prev_stack_top); + } + else { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + break; 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, diff --git a/unittests/ternary_condition.chai b/unittests/ternary_condition.chai new file mode 100644 index 0000000..7114048 --- /dev/null +++ b/unittests/ternary_condition.chai @@ -0,0 +1,2 @@ +var x = 4; +assert_equal(x < 3 ? 4 < 1 : 5 > 3, true);