Add 'continue' command for loops. Also enhance for() unit tests which are now breaking and need to be fixed

This commit is contained in:
Jason Turner 2013-02-23 14:49:20 -07:00
parent e298333ac6
commit c9995480e6
7 changed files with 160 additions and 4 deletions

View File

@ -494,6 +494,14 @@ namespace chaiscript
Break_Loop() { } Break_Loop() { }
}; };
/**
* Special type indicating a call to 'continue'
*/
struct Continue_Loop {
Continue_Loop() { }
};
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Scope_Push_Pop struct Scope_Push_Pop
{ {

View File

@ -802,8 +802,14 @@ namespace chaiscript
throw exception::eval_error("While condition not boolean"); throw exception::eval_error("While condition not boolean");
} }
while (cond) { while (cond) {
try {
try { try {
this->children[1]->eval(t_ss); 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 { try {
cond = boxed_cast<bool>(this->children[0]->eval(t_ss)); cond = boxed_cast<bool>(this->children[0]->eval(t_ss));
@ -914,13 +920,27 @@ namespace chaiscript
while (cond) { while (cond) {
try { try {
if (this->children.size() == 4) { if (this->children.size() == 4) {
try {
this->children[3]->eval(t_ss); 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); this->children[2]->eval(t_ss);
cond = boxed_cast<bool>(this->children[1]->eval(t_ss)); cond = boxed_cast<bool>(this->children[1]->eval(t_ss));
} }
else { else {
try {
this->children[2]->eval(t_ss); 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); 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<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) { }
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 { struct Map_Pair_AST_Node : public AST_Node {
public: public:
Map_Pair_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Map_Pair, 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) : Map_Pair_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Map_Pair, 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) :

View File

@ -1760,6 +1760,23 @@ namespace chaiscript
return retval; 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 * 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; retval = true;
saw_eol = false; 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()) { else if (Equation()) {
if (!saw_eol) { if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);

11
unittests/break_for.chai Normal file
View File

@ -0,0 +1,11 @@
var j = 0;
for (var i = 0; i < 10; ++i) {
if (i == 5) {
break
}
j = i
}
assert_equal(4, j);

View File

@ -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);

View File

@ -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);

View File

@ -5,3 +5,55 @@ for (var i = 0; i < 5; ++i) {
} }
assert_equal([0,1,2,3,4], ret); 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);