2016-10-22 23:56:07 +00:00
//: Helper for various programming environments: run arbitrary Mu code and
//: return some result in text form.
2015-07-07 19:32:31 +00:00
: ( scenario run_interactive_code )
2016-03-08 09:30:14 +00:00
def main [
2018-06-24 16:16:17 +00:00
1 : num < - copy 0 # reserve space for the sandbox
10 : text < - new [ 1 : num / raw < - copy 34 ]
# ? $print 10:num [|] 11:num [: ] 1000:num [|] *10:text [ (] 10:text [)] 10 / newline
run - sandboxed 10 : text
20 : num < - copy 1 : num
2015-07-07 19:32:31 +00:00
]
2018-06-24 16:16:17 +00:00
+ mem : storing 34 in location 20
2015-07-07 19:32:31 +00:00
: ( scenario run_interactive_empty )
2016-03-08 09:30:14 +00:00
def main [
2018-06-24 16:16:17 +00:00
10 : text < - copy null
20 : text < - run - sandboxed 10 : text
2015-07-07 19:32:31 +00:00
]
# result is null
2018-06-24 16:16:17 +00:00
+ mem : storing 0 in location 20
+ mem : storing 0 in location 21
2015-06-01 06:44:52 +00:00
2016-08-12 21:51:53 +00:00
//: As the name suggests, 'run-sandboxed' will prevent certain operations that
//: regular Mu code can perform.
: ( before " End Globals " )
bool Sandbox_mode = false ;
//: for starters, users can't override 'main' when the environment is running
: ( before " End Load Recipe Name " )
if ( Sandbox_mode & & result . name = = " main " ) {
slurp_balanced_bracket ( in ) ;
return - 1 ;
}
2016-02-25 15:58:09 +00:00
//: run code in 'interactive mode', i.e. with errors off and return:
2015-07-17 19:51:32 +00:00
//: stringified output in case we want to print it to screen
2016-02-25 15:58:09 +00:00
//: any errors encountered
2015-07-17 19:51:32 +00:00
//: simulated screen any prints went to
2015-08-02 22:26:58 +00:00
//: any 'app' layer traces generated
2015-06-01 06:44:52 +00:00
: ( before " End Primitive Recipe Declarations " )
2016-08-12 21:51:53 +00:00
RUN_SANDBOXED ,
2015-06-01 06:44:52 +00:00
: ( before " End Primitive Recipe Numbers " )
2016-08-12 21:51:53 +00:00
put ( Recipe_ordinal , " run-sandboxed " , RUN_SANDBOXED ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
2016-08-12 21:51:53 +00:00
case RUN_SANDBOXED : {
2015-10-02 00:30:14 +00:00
if ( SIZE ( inst . ingredients ) ! = 1 ) {
2016-08-12 21:51:53 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'run-sandboxed' requires exactly one ingredient, but got ' " < < inst . original_string < < " ' \n " < < end ( ) ;
2015-07-25 21:19:28 +00:00
break ;
}
2016-09-17 06:52:15 +00:00
if ( ! is_mu_text ( inst . ingredients . at ( 0 ) ) ) {
2016-08-12 21:51:53 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " first ingredient of 'run-sandboxed' should be a string, but got ' " < < to_string ( inst . ingredients . at ( 0 ) ) < < " ' \n " < < end ( ) ;
2015-07-25 21:19:28 +00:00
break ;
}
2015-10-02 00:30:14 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
2016-08-12 21:51:53 +00:00
case RUN_SANDBOXED : {
2018-06-24 16:16:17 +00:00
bool new_code_pushed_to_stack = run_interactive ( ingredients . at ( 0 ) . at ( /*skip alloc id*/ 1 ) ) ;
2015-07-07 19:32:31 +00:00
if ( ! new_code_pushed_to_stack ) {
2015-08-17 04:10:30 +00:00
products . resize ( 5 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 0 ) . push_back ( /*alloc id*/ 0 ) ;
2015-07-08 19:54:06 +00:00
products . at ( 0 ) . push_back ( 0 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 1 ) . push_back ( /*alloc id*/ 0 ) ;
2016-02-25 15:58:09 +00:00
products . at ( 1 ) . push_back ( trace_error_contents ( ) ) ;
2018-06-24 16:16:17 +00:00
products . at ( 2 ) . push_back ( /*alloc id*/ 0 ) ;
2015-07-17 19:51:32 +00:00
products . at ( 2 ) . push_back ( 0 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 3 ) . push_back ( /*alloc id*/ 0 ) ;
2015-10-07 06:38:28 +00:00
products . at ( 3 ) . push_back ( trace_app_contents ( ) ) ;
2015-08-17 04:10:30 +00:00
products . at ( 4 ) . push_back ( 1 ) ; // completed
2015-09-16 02:48:53 +00:00
run_code_end ( ) ;
2015-07-08 19:54:06 +00:00
break ; // done with this instruction
2015-07-07 19:32:31 +00:00
}
else {
continue ; // not done with caller; don't increment current_step_index()
}
2015-06-01 06:44:52 +00:00
}
2016-09-16 00:25:07 +00:00
//: To show results in the sandbox Mu uses a hack: it saves the products
//: returned by each instruction while Track_most_recent_products is true, and
//: keeps the most recent such result around so that it can be returned as the
//: result of a sandbox.
2015-07-08 21:47:12 +00:00
: ( before " End Globals " )
2015-08-16 05:37:55 +00:00
bool Track_most_recent_products = false ;
2017-03-20 19:55:36 +00:00
int Call_depth_to_track_most_recent_products_at = 0 ;
2016-09-16 00:25:07 +00:00
string Most_recent_products ;
2017-07-09 21:34:17 +00:00
: ( before " End Reset " )
2015-08-16 05:37:55 +00:00
Track_most_recent_products = false ;
2017-03-20 19:55:36 +00:00
Call_depth_to_track_most_recent_products_at = 0 ;
2016-09-16 00:25:07 +00:00
Most_recent_products = " " ;
: ( before " End Globals " )
trace_stream * Save_trace_stream = NULL ;
string Save_trace_file ;
2015-06-01 06:44:52 +00:00
: ( code )
2015-07-16 05:08:21 +00:00
// reads a string, tries to call it as code (treating it as a test), saving
2016-02-25 15:58:09 +00:00
// all errors.
2015-07-08 19:54:06 +00:00
// returns true if successfully called (no errors found during load and transform)
2016-03-14 03:26:47 +00:00
bool run_interactive ( int address ) {
2018-06-24 16:16:17 +00:00
//? cerr << "run_interactive: " << address << '\n';
2015-11-06 21:22:16 +00:00
assert ( contains_key ( Recipe_ordinal , " interactive " ) & & get ( Recipe_ordinal , " interactive " ) ! = 0 ) ;
2015-07-16 05:08:21 +00:00
// try to sandbox the run as best you can
// todo: test this
if ( ! Current_scenario ) {
2016-03-14 03:26:47 +00:00
for ( int i = 1 ; i < Reserved_for_tests ; + + i )
2015-07-16 05:08:21 +00:00
Memory . erase ( i ) ;
}
2016-09-17 06:52:15 +00:00
string command = trim ( strip_comments ( read_mu_text ( address ) ) ) ;
2018-06-24 16:16:17 +00:00
//? cerr << "command: " << command << '\n';
2015-11-06 19:06:58 +00:00
Name [ get ( Recipe_ordinal , " interactive " ) ] . clear ( ) ;
2016-03-22 06:45:42 +00:00
run_code_begin ( /*should_stash_snapshots*/ true ) ;
2016-03-20 07:48:04 +00:00
if ( command . empty ( ) ) return false ;
2015-09-12 22:33:21 +00:00
// don't kill the current routine on parse errors
routine * save_current_routine = Current_routine ;
Current_routine = NULL ;
2015-06-01 06:44:52 +00:00
// call run(string) but without the scheduling
2015-11-15 07:16:21 +00:00
load ( string ( " recipe! interactive [ \n " ) +
2017-10-21 15:52:25 +00:00
" local-scope \n " +
2016-09-17 19:55:10 +00:00
" screen:&:screen <- next-ingredient \n " +
2015-08-17 02:13:45 +00:00
" $start-tracking-products \n " +
2015-07-17 19:51:32 +00:00
command + " \n " +
2015-08-17 02:13:45 +00:00
" $stop-tracking-products \n " +
2016-03-08 09:30:14 +00:00
" return screen \n " +
2015-07-17 19:51:32 +00:00
" ] \n " ) ;
2015-06-01 06:44:52 +00:00
transform_all ( ) ;
2015-09-12 22:33:21 +00:00
Current_routine = save_current_routine ;
2015-10-07 05:15:45 +00:00
if ( trace_count ( " error " ) > 0 ) return false ;
2015-08-17 02:13:45 +00:00
// now call 'sandbox' which will run 'interactive' in a separate routine,
// and wait for it
2015-10-19 22:07:54 +00:00
if ( Save_trace_stream ) {
+ + Save_trace_stream - > callstack_depth ;
2016-08-12 21:51:53 +00:00
trace ( 9999 , " trace " ) < < " run-sandboxed: incrementing callstack depth to " < < Save_trace_stream - > callstack_depth < < end ( ) ;
2015-10-19 22:07:54 +00:00
assert ( Save_trace_stream - > callstack_depth < 9000 ) ; // 9998-101 plus cushion
}
2015-11-06 19:06:58 +00:00
Current_routine - > calls . push_front ( call ( get ( Recipe_ordinal , " sandbox " ) ) ) ;
2015-07-07 19:32:31 +00:00
return true ;
2015-06-01 06:44:52 +00:00
}
2015-06-02 07:48:32 +00:00
2016-03-20 07:48:04 +00:00
//: Carefully update all state to exactly how it was -- including snapshots.
: ( before " End Globals " )
2017-05-29 06:42:54 +00:00
bool Run_profiler_stash = false ;
2016-03-20 07:48:04 +00:00
map < string , recipe_ordinal > Recipe_ordinal_snapshot_stash ;
map < recipe_ordinal , recipe > Recipe_snapshot_stash ;
map < string , type_ordinal > Type_ordinal_snapshot_stash ;
map < type_ordinal , type_info > Type_snapshot_stash ;
map < recipe_ordinal , map < string , int > > Name_snapshot_stash ;
map < string , vector < recipe_ordinal > > Recipe_variants_snapshot_stash ;
2016-09-22 23:30:21 +00:00
map < string , type_tree * > Type_abbreviations_snapshot_stash ;
2017-01-07 06:09:29 +00:00
vector < scenario > Scenarios_snapshot_stash ;
set < string > Scenario_names_snapshot_stash ;
2016-08-12 21:51:53 +00:00
2016-03-20 07:48:04 +00:00
: ( code )
2016-03-22 06:45:42 +00:00
void run_code_begin ( bool should_stash_snapshots ) {
2015-09-16 02:48:53 +00:00
// stuff to undo later, in run_code_end()
2015-10-07 05:15:45 +00:00
Hide_errors = true ;
2016-02-25 19:29:42 +00:00
Disable_redefine_checks = true ;
2017-05-29 06:42:54 +00:00
Run_profiler_stash = Run_profiler ;
Run_profiler = false ;
2016-03-22 06:45:42 +00:00
if ( should_stash_snapshots )
2016-03-20 07:48:04 +00:00
stash_snapshots ( ) ;
2015-09-16 02:48:53 +00:00
Save_trace_stream = Trace_stream ;
Trace_stream = new trace_stream ;
2015-10-07 06:38:28 +00:00
Trace_stream - > collect_depth = App_depth ;
2015-09-16 02:48:53 +00:00
}
void run_code_end ( ) {
2015-10-07 05:15:45 +00:00
Hide_errors = false ;
2016-02-25 19:29:42 +00:00
Disable_redefine_checks = false ;
2017-05-29 06:42:54 +00:00
Run_profiler = Run_profiler_stash ;
Run_profiler_stash = false ;
2016-09-16 00:25:07 +00:00
//? ofstream fout("sandbox.log");
//? fout << Trace_stream->readable_contents("");
//? fout.close();
2015-09-16 02:48:53 +00:00
delete Trace_stream ;
Trace_stream = Save_trace_stream ;
Save_trace_stream = NULL ;
Save_trace_file . clear ( ) ;
2015-11-18 19:30:54 +00:00
Recipe . erase ( get ( Recipe_ordinal , " interactive " ) ) ; // keep past sandboxes from inserting errors
2016-03-20 07:48:04 +00:00
if ( ! Recipe_snapshot_stash . empty ( ) )
unstash_snapshots ( ) ;
}
// keep sync'd with save_snapshots and restore_snapshots
void stash_snapshots ( ) {
2016-08-12 21:29:34 +00:00
assert ( Recipe_ordinal_snapshot_stash . empty ( ) ) ;
2016-03-20 07:48:04 +00:00
Recipe_ordinal_snapshot_stash = Recipe_ordinal_snapshot ;
2016-08-12 21:29:34 +00:00
assert ( Recipe_snapshot_stash . empty ( ) ) ;
2016-03-20 07:48:04 +00:00
Recipe_snapshot_stash = Recipe_snapshot ;
2016-08-12 21:29:34 +00:00
assert ( Type_ordinal_snapshot_stash . empty ( ) ) ;
2016-03-20 07:48:04 +00:00
Type_ordinal_snapshot_stash = Type_ordinal_snapshot ;
2016-08-12 21:29:34 +00:00
assert ( Type_snapshot_stash . empty ( ) ) ;
2016-03-20 07:48:04 +00:00
Type_snapshot_stash = Type_snapshot ;
2016-08-12 21:29:34 +00:00
assert ( Name_snapshot_stash . empty ( ) ) ;
2016-03-20 07:48:04 +00:00
Name_snapshot_stash = Name_snapshot ;
2016-08-12 21:29:34 +00:00
assert ( Recipe_variants_snapshot_stash . empty ( ) ) ;
2016-03-20 07:48:04 +00:00
Recipe_variants_snapshot_stash = Recipe_variants_snapshot ;
2016-09-22 23:30:21 +00:00
assert ( Type_abbreviations_snapshot_stash . empty ( ) ) ;
Type_abbreviations_snapshot_stash = Type_abbreviations_snapshot ;
2017-01-07 06:09:29 +00:00
assert ( Scenarios_snapshot_stash . empty ( ) ) ;
Scenarios_snapshot_stash = Scenarios_snapshot ;
assert ( Scenario_names_snapshot_stash . empty ( ) ) ;
Scenario_names_snapshot_stash = Scenario_names_snapshot ;
2016-03-20 07:48:04 +00:00
save_snapshots ( ) ;
}
void unstash_snapshots ( ) {
restore_snapshots ( ) ;
Recipe_ordinal_snapshot = Recipe_ordinal_snapshot_stash ; Recipe_ordinal_snapshot_stash . clear ( ) ;
Recipe_snapshot = Recipe_snapshot_stash ; Recipe_snapshot_stash . clear ( ) ;
Type_ordinal_snapshot = Type_ordinal_snapshot_stash ; Type_ordinal_snapshot_stash . clear ( ) ;
Type_snapshot = Type_snapshot_stash ; Type_snapshot_stash . clear ( ) ;
Name_snapshot = Name_snapshot_stash ; Name_snapshot_stash . clear ( ) ;
Recipe_variants_snapshot = Recipe_variants_snapshot_stash ; Recipe_variants_snapshot_stash . clear ( ) ;
2016-09-22 23:30:21 +00:00
Type_abbreviations_snapshot = Type_abbreviations_snapshot_stash ; Type_abbreviations_snapshot_stash . clear ( ) ;
2017-01-07 06:09:29 +00:00
Scenarios_snapshot = Scenarios_snapshot_stash ; Scenarios_snapshot_stash . clear ( ) ;
Scenario_names_snapshot = Scenario_names_snapshot_stash ; Scenario_names_snapshot_stash . clear ( ) ;
2015-09-16 02:48:53 +00:00
}
2018-07-26 17:09:29 +00:00
: ( before " End Mu Prelude " )
2015-08-17 02:13:45 +00:00
load ( string (
" recipe interactive [ \n " ) + // just a dummy version to initialize the Recipe_ordinal and so on
" ] \n " +
" recipe sandbox [ \n " +
" local-scope \n " +
2018-06-24 16:16:17 +00:00
//? "$print [aaa] 10/newline\n" +
2016-09-17 19:55:10 +00:00
" screen:&:screen <- new-fake-screen 30, 5 \n " +
2016-09-17 17:28:25 +00:00
" routine-id:num <- start-running interactive, screen \n " +
2016-07-14 11:47:18 +00:00
" limit-time routine-id, 100000/instructions \n " +
" wait-for-routine routine-id \n " +
2018-06-24 16:16:17 +00:00
//? "$print [bbb] 10/newline\n" +
2016-09-17 17:28:25 +00:00
" instructions-run:num <- number-of-instructions routine-id \n " +
2016-07-14 11:47:18 +00:00
" stash instructions-run [instructions run] \n " +
2016-09-17 17:28:25 +00:00
" sandbox-state:num <- routine-state routine-id \n " +
2016-09-17 17:32:57 +00:00
" completed?:bool <- equal sandbox-state, 1/completed \n " +
2018-06-24 16:16:17 +00:00
//? "$print [completed: ] completed? 10/newline\n" +
2016-09-17 07:10:28 +00:00
" output:text <- $most-recent-products \n " +
2018-06-24 16:16:17 +00:00
//? "$print [zzz] 10/newline\n" +
//? "$print output\n" +
2016-09-17 07:10:28 +00:00
" errors:text <- save-errors \n " +
" stashes:text <- save-app-trace \n " +
2016-08-12 21:51:53 +00:00
" $cleanup-run-sandboxed \n " +
2016-03-08 09:30:14 +00:00
" return output, errors, screen, stashes, completed? \n " +
2015-08-17 02:13:45 +00:00
" ] \n " ) ;
2016-02-25 15:58:09 +00:00
//: adjust errors in the sandbox
2017-06-15 17:45:03 +00:00
: ( before " End maybe(recipe_name) Special-cases " )
if ( recipe_name = = " interactive " ) return " " ;
2015-10-01 20:13:10 +00:00
2015-08-25 02:01:38 +00:00
: ( scenario run_interactive_comments )
2016-03-08 09:30:14 +00:00
def main [
2016-09-17 07:10:28 +00:00
1 : text < - new [ # ab
2015-08-25 02:01:38 +00:00
add 2 , 2 ]
2016-09-17 07:10:28 +00:00
2 : text < - run - sandboxed 1 : text
2016-09-17 20:00:39 +00:00
3 : @ : char < - copy * 2 : text
2015-08-25 02:01:38 +00:00
]
+ mem : storing 52 in location 4
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Declarations " )
_START_TRACKING_PRODUCTS ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " $start-tracking-products " , _START_TRACKING_PRODUCTS ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case _START_TRACKING_PRODUCTS : {
break ;
}
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Implementations " )
case _START_TRACKING_PRODUCTS : {
Track_most_recent_products = true ;
2017-03-20 19:55:36 +00:00
Call_depth_to_track_most_recent_products_at = SIZE ( Current_routine - > calls ) ;
2015-08-17 02:13:45 +00:00
break ;
}
: ( before " End Primitive Recipe Declarations " )
_STOP_TRACKING_PRODUCTS ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " $stop-tracking-products " , _STOP_TRACKING_PRODUCTS ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case _STOP_TRACKING_PRODUCTS : {
break ;
}
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Implementations " )
case _STOP_TRACKING_PRODUCTS : {
Track_most_recent_products = false ;
break ;
}
: ( before " End Primitive Recipe Declarations " )
_MOST_RECENT_PRODUCTS ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " $most-recent-products " , _MOST_RECENT_PRODUCTS ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case _MOST_RECENT_PRODUCTS : {
break ;
}
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Implementations " )
case _MOST_RECENT_PRODUCTS : {
products . resize ( 1 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 0 ) . push_back ( /*alloc id*/ 0 ) ;
2016-09-17 06:52:15 +00:00
products . at ( 0 ) . push_back ( new_mu_text ( Most_recent_products ) ) ;
2015-08-17 02:13:45 +00:00
break ;
}
2015-10-07 05:15:45 +00:00
: ( before " End Primitive Recipe Declarations " )
2016-02-25 16:24:14 +00:00
SAVE_ERRORS ,
2015-10-07 05:15:45 +00:00
: ( before " End Primitive Recipe Numbers " )
2016-02-25 16:24:14 +00:00
put ( Recipe_ordinal , " save-errors " , SAVE_ERRORS ) ;
2015-10-07 05:15:45 +00:00
: ( before " End Primitive Recipe Checks " )
2016-02-25 16:24:14 +00:00
case SAVE_ERRORS : {
2015-10-07 05:15:45 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
2016-02-25 16:24:14 +00:00
case SAVE_ERRORS : {
2015-10-07 05:15:45 +00:00
products . resize ( 1 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 0 ) . push_back ( /*alloc id*/ 0 ) ;
2016-02-25 15:58:09 +00:00
products . at ( 0 ) . push_back ( trace_error_contents ( ) ) ;
2015-10-07 05:15:45 +00:00
break ;
}
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Declarations " )
2015-10-07 07:22:49 +00:00
SAVE_APP_TRACE ,
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " save-app-trace " , SAVE_APP_TRACE ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
2015-10-07 07:22:49 +00:00
case SAVE_APP_TRACE : {
2015-10-02 00:30:14 +00:00
break ;
}
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Implementations " )
2015-10-07 07:22:49 +00:00
case SAVE_APP_TRACE : {
2015-08-17 02:13:45 +00:00
products . resize ( 1 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 0 ) . push_back ( /*alloc id*/ 0 ) ;
2015-10-07 06:38:28 +00:00
products . at ( 0 ) . push_back ( trace_app_contents ( ) ) ;
2015-08-17 02:13:45 +00:00
break ;
}
: ( before " End Primitive Recipe Declarations " )
2016-08-12 21:51:53 +00:00
_CLEANUP_RUN_SANDBOXED ,
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Numbers " )
2016-08-12 21:51:53 +00:00
put ( Recipe_ordinal , " $cleanup-run-sandboxed " , _CLEANUP_RUN_SANDBOXED ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
2016-08-12 21:51:53 +00:00
case _CLEANUP_RUN_SANDBOXED : {
2015-10-02 00:30:14 +00:00
break ;
}
2015-08-17 02:13:45 +00:00
: ( before " End Primitive Recipe Implementations " )
2016-08-12 21:51:53 +00:00
case _CLEANUP_RUN_SANDBOXED : {
2015-09-16 02:48:53 +00:00
run_code_end ( ) ;
2015-08-17 02:13:45 +00:00
break ;
}
2015-11-21 18:01:12 +00:00
: ( scenario " run_interactive_converts_result_to_text " )
2016-03-08 09:30:14 +00:00
def main [
2015-07-08 21:47:12 +00:00
# try to interactively add 2 and 2
2018-06-24 16:16:17 +00:00
10 : text < - new [ add 2 , 2 ]
20 : text < - run - sandboxed 10 : text
30 : @ : char < - copy * 20 : text
2015-07-08 21:47:12 +00:00
]
# first letter in the output should be '4' in unicode
2018-06-24 16:16:17 +00:00
+ mem : storing 52 in location 31
2015-07-08 21:47:12 +00:00
2017-03-20 19:55:36 +00:00
: ( scenario " run_interactive_ignores_products_in_nested_functions " )
def main [
2018-06-24 16:16:17 +00:00
10 : text < - new [ foo ]
20 : text < - run - sandboxed 10 : text
30 : @ : char < - copy * 20 : text
2017-03-20 19:55:36 +00:00
]
def foo [
2018-06-24 16:16:17 +00:00
40 : num < - copy 1234
2017-03-20 19:55:36 +00:00
{
break
reply 5678
}
]
# no product should have been tracked
2018-06-24 16:16:17 +00:00
+ mem : storing 0 in location 30
2017-03-20 19:55:36 +00:00
2017-03-21 01:03:21 +00:00
: ( scenario " run_interactive_ignores_products_in_previous_instructions " )
def main [
2018-06-24 16:16:17 +00:00
10 : text < - new [
2017-03-21 01:03:21 +00:00
add 1 , 1 # generates a product
foo ] # no products
2018-06-24 16:16:17 +00:00
20 : text < - run - sandboxed 10 : text
30 : @ : char < - copy * 20 : text
2017-03-21 01:03:21 +00:00
]
def foo [
2018-06-24 16:16:17 +00:00
40 : num < - copy 1234
2017-03-21 01:03:21 +00:00
{
break
reply 5678
}
]
# no product should have been tracked
2018-06-24 16:16:17 +00:00
+ mem : storing 0 in location 30
2017-03-21 01:03:21 +00:00
: ( scenario " run_interactive_remembers_products_before_final_label " )
def main [
2018-06-24 16:16:17 +00:00
10 : text < - new [
2017-03-21 01:03:21 +00:00
add 1 , 1 # generates a product
+ foo ] # no products
2018-06-24 16:16:17 +00:00
20 : text < - run - sandboxed 10 : text
30 : @ : char < - copy * 20 : text
2017-03-21 01:03:21 +00:00
]
def foo [
2018-06-24 16:16:17 +00:00
40 : num < - copy 1234
2017-03-21 01:03:21 +00:00
{
break
reply 5678
}
]
# product tracked
2018-06-24 16:16:17 +00:00
+ mem : storing 50 in location 31
2017-03-21 01:03:21 +00:00
2015-11-21 18:01:12 +00:00
: ( scenario " run_interactive_returns_text " )
2016-03-08 09:30:14 +00:00
def main [
2015-07-08 22:25:11 +00:00
# try to interactively add 2 and 2
2016-09-17 07:10:28 +00:00
1 : text < - new [
x : text < - new [ a ]
y : text < - new [ b ]
z : text < - append x : text , y : text
2015-07-08 22:25:11 +00:00
]
2018-06-24 16:16:17 +00:00
10 : text < - run - sandboxed 1 : text
# ? $print 10:text 10 / newline
20 : @ : char < - copy * 10 : text
2015-07-08 22:25:11 +00:00
]
# output contains "ab"
2018-06-24 16:16:17 +00:00
+ mem : storing 97 in location 21
+ mem : storing 98 in location 22
2015-07-08 22:25:11 +00:00
2015-10-07 05:15:45 +00:00
: ( scenario " run_interactive_returns_errors " )
2016-03-08 09:30:14 +00:00
def main [
2015-10-07 05:15:45 +00:00
# run a command that generates an error
2018-06-24 16:16:17 +00:00
10 : text < - new [ x : num < - copy 34
2016-09-17 17:28:25 +00:00
get x : num , foo : offset ]
2018-06-24 16:16:17 +00:00
20 : text , 30 : text < - run - sandboxed 10 : text
40 : @ : char < - copy * 30 : text
2015-07-08 23:16:11 +00:00
]
2015-10-07 05:15:45 +00:00
# error should be "unknown element foo in container number"
2018-06-24 16:16:17 +00:00
+ mem : storing 117 in location 41
+ mem : storing 110 in location 42
+ mem : storing 107 in location 43
+ mem : storing 110 in location 44
2015-09-12 22:33:21 +00:00
# ...
2015-07-08 23:16:11 +00:00
2015-10-10 03:03:18 +00:00
: ( scenario run_interactive_with_comment )
2016-03-08 09:30:14 +00:00
def main [
2015-10-10 03:03:18 +00:00
# 2 instructions, with a comment after the first
2018-06-24 16:16:17 +00:00
10 : text < - new [ a : num < - copy 0 # abc
2016-09-17 17:28:25 +00:00
b : num < - copy 0
2015-10-10 03:03:18 +00:00
]
2018-06-24 16:16:17 +00:00
20 : text , 30 : text < - run - sandboxed 10 : text
2015-10-10 03:03:18 +00:00
]
# no errors
2018-06-24 16:16:17 +00:00
# skip alloc id
+ mem : storing 0 in location 30
+ mem : storing 0 in location 31
2015-10-10 03:03:18 +00:00
2017-03-21 01:03:21 +00:00
: ( after " Running One Instruction " )
if ( Track_most_recent_products & & SIZE ( Current_routine - > calls ) = = Call_depth_to_track_most_recent_products_at
& & ! current_instruction ( ) . is_label
& & current_instruction ( ) . name ! = " $stop-tracking-products " ) {
Most_recent_products = " " ;
}
2016-08-16 21:55:10 +00:00
: ( before " End Running One Instruction " )
2017-03-20 19:55:36 +00:00
if ( Track_most_recent_products & & SIZE ( Current_routine - > calls ) = = Call_depth_to_track_most_recent_products_at ) {
2017-03-21 01:03:21 +00:00
Most_recent_products = track_most_recent_products ( current_instruction ( ) , products ) ;
2018-06-24 16:16:17 +00:00
//? cerr << "most recent products: " << Most_recent_products << '\n';
2015-07-08 21:53:37 +00:00
}
2015-07-08 21:47:12 +00:00
: ( code )
2017-03-21 01:03:21 +00:00
string track_most_recent_products ( const instruction & instruction , const vector < vector < double > > & products ) {
2015-07-08 21:47:12 +00:00
ostringstream out ;
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( products ) ; + + i ) {
2016-09-16 00:25:07 +00:00
// A sandbox can print a string result, but only if it is actually saved
// to a variable in the sandbox, because otherwise the results are
// reclaimed before the sandbox sees them. So you get these interactions
// in the sandbox:
//
// new [abc]
// => <address>
//
// x:text <- new [abc]
// => abc
2015-07-08 22:25:11 +00:00
if ( i < SIZE ( instruction . products ) ) {
2016-09-17 06:52:15 +00:00
if ( is_mu_text ( instruction . products . at ( i ) ) ) {
2018-06-24 16:16:17 +00:00
if ( SIZE ( products . at ( i ) ) ! = 2 ) continue ; // weak silent check for address
out < < read_mu_text ( products . at ( i ) . at ( /*skip alloc id*/ 1 ) ) < < ' \n ' ;
2015-07-08 22:25:11 +00:00
continue ;
}
}
2016-03-14 03:26:47 +00:00
for ( int j = 0 ; j < SIZE ( products . at ( i ) ) ; + + j )
2015-09-15 06:30:03 +00:00
out < < no_scientific ( products . at ( i ) . at ( j ) ) < < ' ' ;
2015-07-08 21:47:12 +00:00
out < < ' \n ' ;
}
2017-03-21 01:03:21 +00:00
return out . str ( ) ;
2015-07-08 21:47:12 +00:00
}
2015-08-16 07:01:49 +00:00
2015-07-08 21:47:12 +00:00
: ( code )
2015-06-06 18:10:46 +00:00
string strip_comments ( string in ) {
ostringstream result ;
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( in ) ; + + i ) {
2015-06-06 18:10:46 +00:00
if ( in . at ( i ) ! = ' # ' ) {
result < < in . at ( i ) ;
}
else {
2015-10-10 03:03:18 +00:00
while ( i + 1 < SIZE ( in ) & & in . at ( i + 1 ) ! = ' \n ' )
2015-06-06 18:10:46 +00:00
+ + i ;
}
}
return result . str ( ) ;
}
2016-03-14 03:26:47 +00:00
int stringified_value_of_location ( int address ) {
2015-06-06 17:38:51 +00:00
// convert to string
ostringstream out ;
2015-11-06 19:06:58 +00:00
out < < no_scientific ( get_or_insert ( Memory , address ) ) ;
2016-09-17 06:52:15 +00:00
return new_mu_text ( out . str ( ) ) ;
2015-06-06 17:38:51 +00:00
}
2016-03-14 03:26:47 +00:00
int trace_error_contents ( ) {
2015-10-07 05:15:45 +00:00
if ( ! Trace_stream ) return 0 ;
ostringstream out ;
for ( vector < trace_line > : : iterator p = Trace_stream - > past_lines . begin ( ) ; p ! = Trace_stream - > past_lines . end ( ) ; + + p ) {
2016-02-25 15:58:09 +00:00
if ( p - > label ! = " error " ) continue ;
2015-10-07 05:15:45 +00:00
out < < p - > contents ;
if ( * - - p - > contents . end ( ) ! = ' \n ' ) out < < ' \n ' ;
}
string result = out . str ( ) ;
truncate ( result ) ;
2016-12-12 00:18:18 +00:00
if ( result . empty ( ) ) return 0 ;
2016-09-17 06:52:15 +00:00
return new_mu_text ( result ) ;
2015-10-07 05:15:45 +00:00
}
2016-03-14 03:26:47 +00:00
int trace_app_contents ( ) {
2015-07-08 23:16:11 +00:00
if ( ! Trace_stream ) return 0 ;
ostringstream out ;
for ( vector < trace_line > : : iterator p = Trace_stream - > past_lines . begin ( ) ; p ! = Trace_stream - > past_lines . end ( ) ; + + p ) {
2015-10-07 06:38:28 +00:00
if ( p - > depth ! = App_depth ) continue ;
2015-07-08 23:16:11 +00:00
out < < p - > contents ;
if ( * - - p - > contents . end ( ) ! = ' \n ' ) out < < ' \n ' ;
}
2015-08-25 03:13:32 +00:00
string result = out . str ( ) ;
2015-10-07 06:38:28 +00:00
if ( result . empty ( ) ) return 0 ;
2015-08-25 03:13:32 +00:00
truncate ( result ) ;
2016-09-17 06:52:15 +00:00
return new_mu_text ( result ) ;
2015-08-25 03:13:32 +00:00
}
void truncate ( string & x ) {
2016-03-19 16:14:25 +00:00
if ( SIZE ( x ) > 1024 ) {
x . erase ( 1024 ) ;
2015-08-25 03:13:32 +00:00
* x . rbegin ( ) = ' \n ' ;
* + + x . rbegin ( ) = ' . ' ;
* + + + + x . rbegin ( ) = ' . ' ;
}
2015-07-08 23:16:11 +00:00
}
2015-07-09 06:10:02 +00:00
2016-08-12 21:51:53 +00:00
//: simpler version of run-sandboxed: doesn't do any running, just loads
2016-02-25 15:58:09 +00:00
//: recipes and reports errors.
2015-09-16 02:48:53 +00:00
2015-07-09 06:10:02 +00:00
: ( before " End Primitive Recipe Declarations " )
RELOAD ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " reload " , RELOAD ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
2015-07-09 06:10:02 +00:00
case RELOAD : {
2015-10-02 00:30:14 +00:00
if ( SIZE ( inst . ingredients ) ! = 1 ) {
2016-07-22 02:22:03 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'reload' requires exactly one ingredient, but got ' " < < inst . original_string < < " ' \n " < < end ( ) ;
2015-07-25 21:19:28 +00:00
break ;
}
2016-09-17 06:52:15 +00:00
if ( ! is_mu_text ( inst . ingredients . at ( 0 ) ) ) {
2016-05-21 05:09:06 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " first ingredient of 'reload' should be a string, but got ' " < < inst . ingredients . at ( 0 ) . original_string < < " ' \n " < < end ( ) ;
2015-07-25 21:19:28 +00:00
break ;
}
2015-10-02 00:30:14 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
case RELOAD : {
2016-09-22 23:30:09 +00:00
restore_non_recipe_snapshots ( ) ;
2018-06-24 16:16:17 +00:00
string code = read_mu_text ( ingredients . at ( 0 ) . at ( /*skip alloc id*/ 1 ) ) ;
2016-03-22 06:45:42 +00:00
run_code_begin ( /*should_stash_snapshots*/ false ) ;
2015-09-16 02:48:53 +00:00
routine * save_current_routine = Current_routine ;
Current_routine = NULL ;
2016-08-12 21:51:53 +00:00
Sandbox_mode = true ;
2015-08-20 05:13:15 +00:00
vector < recipe_ordinal > recipes_reloaded = load ( code ) ;
2015-07-09 06:10:02 +00:00
transform_all ( ) ;
2015-07-22 06:38:21 +00:00
Trace_stream - > newline ( ) ; // flush trace
2016-08-12 21:51:53 +00:00
Sandbox_mode = false ;
2015-09-16 02:48:53 +00:00
Current_routine = save_current_routine ;
2015-08-03 05:18:19 +00:00
products . resize ( 1 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 0 ) . push_back ( /*alloc id*/ 0 ) ;
2016-02-25 15:58:09 +00:00
products . at ( 0 ) . push_back ( trace_error_contents ( ) ) ;
2015-09-16 02:48:53 +00:00
run_code_end ( ) ; // wait until we're done with the trace contents
2015-07-09 06:10:02 +00:00
break ;
}
2015-09-16 02:48:53 +00:00
2018-06-24 16:16:17 +00:00
: ( scenario reload_loads_function_definitions )
def main [
local - scope
x : text < - new [ recipe foo [
1 : num / raw < - copy 34
] ]
reload x
run - sandboxed [ foo ]
2 : num / raw < - copy 1 : num / raw
]
+ mem : storing 34 in location 2
2015-10-07 05:15:45 +00:00
: ( scenario reload_continues_past_error )
2016-03-08 09:30:14 +00:00
def main [
2015-09-16 02:48:53 +00:00
local - scope
2016-09-17 07:10:28 +00:00
x : text < - new [ recipe foo [
2018-06-24 16:16:17 +00:00
get 1234 : num , foo : offset
] ]
2015-09-16 02:48:53 +00:00
reload x
2016-09-17 17:28:25 +00:00
1 : num / raw < - copy 34
2015-09-16 02:48:53 +00:00
]
+ mem : storing 34 in location 1
2016-03-22 06:45:42 +00:00
: ( scenario reload_can_repeatedly_load_container_definitions )
# define a container and try to create it (merge requires knowing container size)
def main [
local - scope
2016-09-17 07:10:28 +00:00
x : text < - new [
2016-03-22 06:45:42 +00:00
container foo [
2016-09-17 17:28:25 +00:00
x : num
y : num
2016-03-22 06:45:42 +00:00
]
recipe bar [
local - scope
x : foo < - merge 34 , 35
]
]
# save warning addresses in locations of type 'number' to avoid spurious changes to them due to 'abandon'
2018-06-24 16:16:17 +00:00
10 : text / raw < - reload x
20 : text / raw < - reload x
2016-03-22 06:45:42 +00:00
]
# no errors on either load
2018-06-24 16:16:17 +00:00
+ mem : storing 0 in location 10
+ mem : storing 0 in location 11
+ mem : storing 0 in location 20
+ mem : storing 0 in location 21