From d225e09d5d0edab9ec8bbd8ab7a35689c691a12a Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 23 Feb 2013 08:49:31 -0700 Subject: [PATCH 1/5] Add profile for calling functions on members of a heterogeneous array --- contrib/codeanalysis/heterogenous_array_loop.chai | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 contrib/codeanalysis/heterogenous_array_loop.chai diff --git a/contrib/codeanalysis/heterogenous_array_loop.chai b/contrib/codeanalysis/heterogenous_array_loop.chai new file mode 100644 index 0000000..f4aeb11 --- /dev/null +++ b/contrib/codeanalysis/heterogenous_array_loop.chai @@ -0,0 +1,10 @@ + +var my_array=["1", 4, 6.6, 10, "1000", 100, 10.9 ]; + +for (var j = 0; j < 10000; ++j) +{ + for (var i = 0; i < 6; ++i) + { + to_string(my_array[i]); + } +} From e298333ac6d510bf04a92200cb29e42cb4548066 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 23 Feb 2013 08:53:25 -0700 Subject: [PATCH 2/5] Add unit test of suffixed number inside of vector initialization --- unittests/vector_of_suffixed_numbers.chai | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 unittests/vector_of_suffixed_numbers.chai diff --git a/unittests/vector_of_suffixed_numbers.chai b/unittests/vector_of_suffixed_numbers.chai new file mode 100644 index 0000000..be3cb3a --- /dev/null +++ b/unittests/vector_of_suffixed_numbers.chai @@ -0,0 +1,2 @@ +var x = [1, 2u] +assert_equal(2u, x[0]) From c9995480e6b4bccbafd44fdf858f7cd145262ef5 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 23 Feb 2013 14:49:20 -0700 Subject: [PATCH 3/5] Add 'continue' command for loops. Also enhance for() unit tests which are now breaking and need to be fixed --- .../chaiscript/language/chaiscript_common.hpp | 8 +++ .../chaiscript/language/chaiscript_eval.hpp | 38 ++++++++++++-- .../chaiscript/language/chaiscript_parser.hpp | 25 +++++++++ unittests/break_for.chai | 11 ++++ unittests/continue_for.chai | 16 ++++++ unittests/continue_while.chai | 14 +++++ unittests/for.chai | 52 +++++++++++++++++++ 7 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 unittests/break_for.chai create mode 100644 unittests/continue_for.chai create mode 100644 unittests/continue_while.chai diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 911ac95..a694cfd 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -494,6 +494,14 @@ namespace chaiscript Break_Loop() { } }; + /** + * Special type indicating a call to 'continue' + */ + struct Continue_Loop { + Continue_Loop() { } + }; + + /// Creates a new scope then pops it on destruction struct Scope_Push_Pop { diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index b2c684a..3657cb3 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -803,7 +803,13 @@ namespace chaiscript } while (cond) { try { - this->children[1]->eval(t_ss); + try { + this->children[1]->eval(t_ss); + } catch (detail::Continue_Loop &) { + // we got a continue exception, which means all of the remaining + // loop implementation is skipped and we just need to continue to + // the next condition test + } try { cond = boxed_cast(this->children[0]->eval(t_ss)); @@ -914,13 +920,27 @@ namespace chaiscript while (cond) { try { if (this->children.size() == 4) { - this->children[3]->eval(t_ss); - this->children[2]->eval(t_ss); + + try { + this->children[3]->eval(t_ss); + } catch (detail::Continue_Loop &) { + // we got a continue exception, which means all of the remaining + // loop implementation is skipped and we just need to continue to + // the next iteration step + } + + this->children[2]->eval(t_ss); cond = boxed_cast(this->children[1]->eval(t_ss)); } else { - this->children[2]->eval(t_ss); + try { + this->children[2]->eval(t_ss); + } catch (detail::Continue_Loop &) { + // we got a continue exception, which means all of the remaining + // loop implementation is skipped and we just need to continue to + // the next iteration step + } this->children[1]->eval(t_ss); @@ -1129,6 +1149,16 @@ namespace chaiscript } }; + struct Continue_AST_Node : public AST_Node { + public: + Continue_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Break, 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) : + AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } + virtual ~Continue_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ + throw detail::Continue_Loop(); + } + }; + struct Map_Pair_AST_Node : public AST_Node { public: Map_Pair_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Map_Pair, 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) : diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index c829ebb..0deca71 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1760,6 +1760,23 @@ namespace chaiscript return retval; } + /** + * Reads a continue statement from input + */ + bool Continue() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("continue")) { + retval = true; + + build_match(AST_NodePtr(new eval::Continue_AST_Node()), prev_stack_top); + } + + return retval; + } + /** * Reads a dot expression(member access), then proceeds to check if it's a function or array call */ @@ -2257,6 +2274,14 @@ namespace chaiscript retval = true; saw_eol = false; } + else if (Continue()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } else if (Equation()) { if (!saw_eol) { throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); diff --git a/unittests/break_for.chai b/unittests/break_for.chai new file mode 100644 index 0000000..aaac7b9 --- /dev/null +++ b/unittests/break_for.chai @@ -0,0 +1,11 @@ +var j = 0; + +for (var i = 0; i < 10; ++i) { + if (i == 5) { + break + } + + j = i +} + +assert_equal(4, j); diff --git a/unittests/continue_for.chai b/unittests/continue_for.chai new file mode 100644 index 0000000..838b8e1 --- /dev/null +++ b/unittests/continue_for.chai @@ -0,0 +1,16 @@ +var j = 0; +var k = 0; + +for (var i = 0; i < 10; ++i) +{ + j = i + if (i > 5) + { + continue + } + + k = i +} + +assert_equal(5, k); +assert_equal(9, j); diff --git a/unittests/continue_while.chai b/unittests/continue_while.chai new file mode 100644 index 0000000..a1b44cb --- /dev/null +++ b/unittests/continue_while.chai @@ -0,0 +1,14 @@ +var i = 0 +var j = 0 + +while (i < 10) { + if (++i > 5) + { + continue + } + + j = i; +} + +assert_equal(10, i); +assert_equal(5, j); diff --git a/unittests/for.chai b/unittests/for.chai index 9799be2..850f4f5 100644 --- a/unittests/for.chai +++ b/unittests/for.chai @@ -5,3 +5,55 @@ for (var i = 0; i < 5; ++i) { } assert_equal([0,1,2,3,4], ret); + + +var j = 0; + +for (;j<10; ++j) +{ +} + +assert_equal(10, j); + + +var k = 0; + +for (;k<10; ) +{ + ++k; +} + +assert_equal(10, k); + + +for (;;) +{ + break; +} + +var l = 0; + +for (;;l = 1) +{ + break; +} + +assert_equal(0, l) + +def isTrue(x) +{ + if (x == 5) + { + return true + } else { + return false + } +} + +for (var m = 0; isTrue(m); m = m + 1) +{ + +} + +assert_equal(5, m); + From 48f538438d7f45f106cf819b1bcc3cf85e241ae3 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 23 Feb 2013 21:14:37 -0700 Subject: [PATCH 4/5] Get all for loop related unit tests passing and expand the types of expressions that can exist in a for loop --- .../chaiscript/language/chaiscript_common.hpp | 8 ++--- .../chaiscript/language/chaiscript_eval.hpp | 19 ++++++++++- .../chaiscript/language/chaiscript_parser.hpp | 32 ++++++++++++++++--- unittests/for.chai | 8 +++-- 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index a694cfd..ffed54e 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -21,9 +21,9 @@ namespace chaiscript public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl, 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, + Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, 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, Switch, Case, Default, Ternary_Cond + Logical_And, Logical_Or, Switch, Case, Default, Ternary_Cond, Noop }; }; @@ -35,9 +35,9 @@ 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", "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", + "Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "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", "Switch", "Case", "Default", "Ternary Condition"}; + "Logical_And", "Logical_Or", "Switch", "Case", "Default", "Ternary Condition", "Noop"}; return ast_node_types[ast_node_type]; } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 3657cb3..6a536a9 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -1151,7 +1151,7 @@ namespace chaiscript struct Continue_AST_Node : public AST_Node { public: - Continue_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Break, 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) : + Continue_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Continue, 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) : AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Continue_AST_Node() {} virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ @@ -1159,6 +1159,23 @@ namespace chaiscript } }; + struct Noop_AST_Node : public AST_Node { + public: + Noop_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Noop, 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) : + 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(true)) + { } + + virtual ~Noop_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ + // It's a no-op, that evaluates to "true" + return m_value; + } + + private: + Boxed_Value m_value; + }; + struct Map_Pair_AST_Node : public AST_Node { public: Map_Pair_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Map_Pair, 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) : diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 0deca71..a537431 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -1574,18 +1574,40 @@ namespace chaiscript return retval; } + /** * Reads the C-style for conditions from input */ bool For_Guards() { - Equation(); + if (!(Equation() && Eol())) + { + if (!Eol()) + { + throw exception::eval_error("'for' loop initial statment missing", File_Position(m_line, m_col), *m_filename); + } else { + AST_NodePtr t(new eval::Noop_AST_Node()); + m_match_stack.push_back(t); + } + } - if (Char(';') && Operator() && Char(';') && Equation()) { - return true; + if (!(Equation() && Eol())) + { + if (!Eol()) + { + throw exception::eval_error("'for' loop condition missing", File_Position(m_line, m_col), *m_filename); + } else { + AST_NodePtr t(new eval::Noop_AST_Node()); + m_match_stack.push_back(t); + } } - else { - throw exception::eval_error("Incomplete conditions in 'for' loop", File_Position(m_line, m_col), *m_filename); + + if (!Equation()) + { + AST_NodePtr t(new eval::Noop_AST_Node()); + m_match_stack.push_back(t); } + + return true; } /** diff --git a/unittests/for.chai b/unittests/for.chai index 850f4f5..389c02e 100644 --- a/unittests/for.chai +++ b/unittests/for.chai @@ -40,9 +40,9 @@ for (;;l = 1) assert_equal(0, l) -def isTrue(x) +def isNotFive(x) { - if (x == 5) + if (x != 5) { return true } else { @@ -50,7 +50,9 @@ def isTrue(x) } } -for (var m = 0; isTrue(m); m = m + 1) +var m; + +for (m = 0; isNotFive(m); m = m + 1) { } From fd72b2951a8a5a1c1e419bf354fa3f396aa87418 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 23 Feb 2013 21:27:01 -0700 Subject: [PATCH 5/5] Correct broken unit test for vector of suffixed numbers --- contrib/codeanalysis/heterogenous_array_loop.chai | 2 +- unittests/vector_of_suffixed_numbers.chai | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/codeanalysis/heterogenous_array_loop.chai b/contrib/codeanalysis/heterogenous_array_loop.chai index f4aeb11..5c688d1 100644 --- a/contrib/codeanalysis/heterogenous_array_loop.chai +++ b/contrib/codeanalysis/heterogenous_array_loop.chai @@ -1,5 +1,5 @@ -var my_array=["1", 4, 6.6, 10, "1000", 100, 10.9 ]; +var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ]; for (var j = 0; j < 10000; ++j) { diff --git a/unittests/vector_of_suffixed_numbers.chai b/unittests/vector_of_suffixed_numbers.chai index be3cb3a..aee96b9 100644 --- a/unittests/vector_of_suffixed_numbers.chai +++ b/unittests/vector_of_suffixed_numbers.chai @@ -1,2 +1,3 @@ -var x = [1, 2u] -assert_equal(2u, x[0]) +var x = [1, 2u, 3.0l] +assert_equal(3.0l, x[2]) +assert_equal(2u, x[1])