Skip to content

Commit

Permalink
#216 - enable break and continue within for loops (#222)
Browse files Browse the repository at this point in the history
Co-Authored-By: Alvin Yan <aussiroth@users.noreply.github.com>
Co-Authored-By: Victor Loh <lohvht@users.noreply.github.com>

* #216 - experimenting with using signal variable
* #216 - possible solution found
use casper.bypass() to count how many steps to teleport to and bypass when a break statement is issued. nice catch @Aussiroth !
* #216 - use teleport marker
* #216 - use stricter matching conditions
* #216 - more complicated test
* #216 - cleaned up to work for break step
* #216 - initial implementation of continue
doesn't work but don't break existing break test case.
* #216 - working version of continue + break
* #216 - add infinity constant for looping
eg

for n from 1 to infinity
{
echo n
}

if constant too big, takes very large to build stack before execution. trade-off decided to be 1024
  • Loading branch information
kensoh committed Jun 21, 2018
1 parent 24f599d commit 4ebe951
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 6 deletions.
6 changes: 6 additions & 0 deletions src/samples/loop_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
for n from 1 to 10
{
echo n
if n equals to 6
break;
}
26 changes: 26 additions & 0 deletions src/samples/loop_test2
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
for n from 1 to 10
{
echo n
if n equals to 6
{
for k from 80 to 85
{
echo k
if k equals to 83
{
break;
}
}
}
}

for cde from 1 to 5
{
echo "cde " + cde
}

for abc from 1 to 5
{
echo "abc " + abc
}

35 changes: 35 additions & 0 deletions src/samples/loop_test3
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
for n from 1 to 10
{
echo n
if n equals to 6
{
for k from 80 to 85
{
echo k
if k equals to 83
{
break;
}
}
}
}

for cde from 1 to 5
{
echo "cde " + cde
}

for abc from 1 to 5
{
echo "abc " + abc
}

for n from 30 to 35
{
echo n
}

for k from 20 to 25
{
echo k
}
39 changes: 39 additions & 0 deletions src/samples/loop_test4
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
for n from 1 to 10
{
echo n
if n equals to 6
{
for k from 80 to 85
{
echo k
if k equals to 83
{
break;
}
}
}
}

for cde from 1 to 5
{
echo "cde " + cde
if cde equals to 3
break;
}

for abc from 1 to 5
{
if abc equals to 3
break
echo "abc " + abc
}

for n from 30 to 35
{
echo n
}

for k from 20 to 25
{
echo k
}
40 changes: 40 additions & 0 deletions src/samples/loop_test5
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
for n from 1 to 10
{
echo n
if n equals to 6
{
for k from 80 to 85
{
continue
echo k
if k equals to 83
{
break;
}
}
}
}

for cde from 1 to 5
{
echo "cde " + cde
if cde equals to 3
continue;
}

for abc from 1 to 5
{
if abc equals to 3
continue
echo "abc " + abc
}

for n from 30 to 35
{
echo n
}

for k from 20 to 25
{
echo k
}
6 changes: 6 additions & 0 deletions src/samples/loop_test6
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
for n from 1 to 10
{
if n equals to 5
continue
echo n
}
5 changes: 5 additions & 0 deletions src/samples/loop_test7
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
echo infinity
for n from 1 to infinity
{
echo n
}
20 changes: 19 additions & 1 deletion src/tagui_header.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ var automation_start_time = Date.now(); casper.echo('\nSTART - automation starte
// initialise time for timer() function
var timer_start_time = Date.now();

// infinity constant for use in for loops
var infinity = 1024;

// initialise default global variables
var quiet_mode = false; var save_text_count = 0; var snap_image_count = 0;

Expand Down Expand Up @@ -41,6 +44,19 @@ var r_result = ''; var r_json = {}; var py_result = ''; var py_json = {};
var inside_py_block = 0; var inside_r_block = 0; var inside_run_block = 0;
var inside_vision_block = 0; var inside_js_block = 0; var inside_dom_block = 0;

// determine how many casper.then steps to skip
function teleport_distance(teleport_marker) {number_to_hop = 0;
if (teleport_marker.indexOf('[BREAK_SIGNAL]') > -1) {for (s = casper.steps.length-1; s >= 0; s--) {
if (casper.steps[s].toString() == ("function () {for_loop_signal = '"+teleport_marker+"';}"))
{number_to_hop = s; break;}};} // search backward direction for break step
else if (teleport_marker.indexOf('[CONTINUE_SIGNAL]') > -1) {for (s = casper.step; s <= casper.steps.length-1; s++) {
if (casper.steps[s].toString() == ("function () {for_loop_signal = '"+teleport_marker+"';}"))
{number_to_hop = s; break;}}; // search forward direction for continue step
if (number_to_hop == 0) {for (s = casper.steps.length-1; s >= 0; s--) {if (casper.steps[s].toString() ==
("function () {for_loop_signal = '"+teleport_marker.replace('[CONTINUE_SIGNAL]','[BREAK_SIGNAL]')+"';}"))
{number_to_hop = s; break;}};}} // handle as break if no step left to continue
else return 0; if ((number_to_hop - casper.step) > 0) return (number_to_hop - casper.step); else return 0;}

// techo function for handling quiet option
function techo(echo_string) {if (!quiet_mode) { // mute about:blank, eg for desktop automation
if ((echo_string == 'about:blank - \n') || (echo_string == '\nabout:blank - ')) casper.echo('');
Expand Down Expand Up @@ -777,11 +793,13 @@ if ((raw_intent.charAt(raw_intent.length-1) == '{') || (raw_intent.charAt(raw_in
if ((raw_intent.substr(0,3) == 'if ') || (raw_intent.substr(0,4) == 'else')) return true;
if ((raw_intent.substr(0,4) == 'for ') || (raw_intent.substr(0,6) == 'while ')) return true;
if ((raw_intent.substr(0,7) == 'switch ') || (raw_intent.substr(0,5) == 'case ')) return true;
if ((raw_intent.substr(0,6) == 'break;') || (raw_intent.substr(0,9) == 'function ')) return true;
if ((raw_intent.substr(0,6) == 'break;') || (raw_intent == 'break')) return true;
if ((raw_intent.substr(0,9) == 'continue;') || (raw_intent == 'continue')) return true;
if ((raw_intent.substr(0,7) == 'casper.') || (raw_intent.substr(0,5) == 'this.')) return true;
if (raw_intent.substr(0,7) == 'chrome.') return true; // chrome object for chrome integration
if (raw_intent.substr(0,5) == ('test'+'.')) return true; // avoid replacement with test option
if ((raw_intent.substr(0,2) == '//') || (raw_intent.charAt(raw_intent.length-1) == ';')) return true;
if (raw_intent.substr(0,9) == 'function ') return true; // function definition
// assume = is assignment statement, kinda acceptable as this is checked at the very end
if (raw_intent.indexOf('=') > -1) return true; return false;}

Expand Down
20 changes: 15 additions & 5 deletions src/tagui_parse.php
Original file line number Diff line number Diff line change
Expand Up @@ -485,12 +485,13 @@ function is_code($raw_intent) {
if ((substr($raw_intent,0,3)=="if ") or (substr($raw_intent,0,4)=="else")) return true;
if ((substr($raw_intent,0,4)=="for ") or (substr($raw_intent,0,6)=="while ")) return true;
if ((substr($raw_intent,0,7)=="switch ") or (substr($raw_intent,0,5)=="case ")) return true;
if ((substr($raw_intent,0,6)=="break;") or (substr($raw_intent,0,9)=="function ")) return true;
if ((substr($raw_intent,0,6)=="break;") or ($raw_intent=="break")) return true;
if ((substr($raw_intent,0,9)=="continue;") or ($raw_intent=="continue")) return true;
if ((substr($raw_intent,0,7)=="casper.") or (substr($raw_intent,0,5)=="this.")) return true;
if (substr($raw_intent,0,7)=="chrome.") return true; // chrome object for chrome integration
if (substr($raw_intent,0,5)=="test.") {$GLOBALS['test_automation']++; return true;}
if (substr($raw_intent,0,2)=="//") {$GLOBALS['real_line_number']--; return true;}
if (substr($raw_intent,-1)==";") return true;
if (substr($raw_intent,-1)==";") return true; if (substr($raw_intent,0,9)=="function ") return true;
// assume = is assignment statement, kinda acceptable as this is checked at the very end
if (strpos($raw_intent,"=")!==false) return true; return false;}

Expand Down Expand Up @@ -952,12 +953,14 @@ function parse_condition($logic) { // natural language handling for conditions
else if (($code_block_intent == "for") and (substr($logic,0,1) == "{")) {
$last_delimiter_pos = strrpos($GLOBALS['for_loop_tracker'],"|");
$for_loop_variable_name = substr($GLOBALS['for_loop_tracker'],$last_delimiter_pos+1);
$code_block_header = "(function (" . $for_loop_variable_name . ") { // start of IIFE pattern\n";}
$code_block_header = "{casper.then(function() {for_loop_signal = '[CONTINUE_SIGNAL][".$for_loop_variable_name."]';});\n".
"(function (" . $for_loop_variable_name . ") { // start of IIFE pattern\n";}

else if (($code_block_intent == "for") and (substr($logic,0,1) == "}")) {
$last_delimiter_pos = strrpos($GLOBALS['for_loop_tracker'],"|");
$for_loop_variable_name = substr($GLOBALS['for_loop_tracker'],$last_delimiter_pos+1);
$code_block_footer = "})(" . $for_loop_variable_name . "); // end of IIFE pattern\n";
$code_block_footer = "})(" . $for_loop_variable_name . "); // end of IIFE pattern, with dummy marker for break step\n".
"casper.then(function() {for_loop_signal = '[BREAK_SIGNAL][".$for_loop_variable_name."]';});}";
$last_delimiter_pos = strrpos($GLOBALS['code_block_tracker'],"|");
$GLOBALS['code_block_tracker']=substr($GLOBALS['code_block_tracker'],0,$last_delimiter_pos);
$last_delimiter_pos = strrpos($GLOBALS['for_loop_tracker'],"|");
Expand All @@ -973,7 +976,6 @@ function parse_condition($logic) { // natural language handling for conditions
else if (substr($logic,0,1) == "}") $logic = "} // end of code block\n".substr($logic,1)."\n".$code_block_footer."});\n";
$logic = str_replace("\n\n","\n",$logic); // clean up empty lines from { and } processing


// section 2 - natural language handling for conditions and loops
if ((substr($logic,0,3)=="if ") or (substr($logic,0,8)=="else if ")
or (substr($logic,0,4)=="for ") or (substr($logic,0,6)=="while ")) {
Expand Down Expand Up @@ -1059,6 +1061,14 @@ function parse_condition($logic) { // natural language handling for conditions
// then avoid async wait (casper.then/waitFor/timeout will hang casperjs/phantomjs??)
if (substr($logic,0,6)=="while ") $GLOBALS['inside_while_loop'] = 1;

// section 4 - to handle break and continue steps in for loops
if (($logic=="break") or ($logic=="break;"))
{$teleport_marker = str_replace("|","",substr($GLOBALS['for_loop_tracker'],strrpos($GLOBALS['for_loop_tracker'],"|")));
$logic = "casper.bypass(teleport_distance('[BREAK_SIGNAL][".$teleport_marker."]')); return;";}
if (($logic=="continue") or ($logic=="continue;"))
{$teleport_marker = str_replace("|","",substr($GLOBALS['for_loop_tracker'],strrpos($GLOBALS['for_loop_tracker'],"|")));
$logic = "casper.bypass(teleport_distance('[CONTINUE_SIGNAL][".$teleport_marker."]')); return;";}

// return code after all the parsing and special handling
return $logic;}

Expand Down

0 comments on commit 4ebe951

Please sign in to comment.