2015-07-07 19:32:31 +00:00
//: Helper for various programming environments: run arbitrary mu code and
//: return some result in string form.
: ( scenario run_interactive_code )
recipe main [
2015-08-16 17:45:11 +00:00
2 : address : array : character < - new [ 1 : number / raw < - copy 34 ]
run - interactive 2 : address : array : character
2015-07-07 19:32:31 +00:00
]
2015-08-16 17:45:11 +00:00
+ mem : storing 34 in location 1
2015-07-07 19:32:31 +00:00
: ( scenario run_interactive_empty )
recipe main [
2015-07-28 21:33:22 +00:00
1 : address : array : character < - run - interactive 0
2015-07-07 19:32:31 +00:00
]
# result is null
+ mem : storing 0 in location 1
2015-06-01 06:44:52 +00:00
2015-07-17 19:51:32 +00:00
//: run code in 'interactive mode', i.e. with warnings off and return:
//: stringified output in case we want to print it to screen
//: any warnings encountered
//: 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 " )
RUN_INTERACTIVE ,
: ( before " End Primitive Recipe Numbers " )
2015-07-04 16:40:50 +00:00
Recipe_ordinal [ " run-interactive " ] = RUN_INTERACTIVE ;
2015-06-01 06:44:52 +00:00
//? cerr << "run-interactive: " << RUN_INTERACTIVE << '\n'; //? 1
: ( before " End Primitive Recipe Implementations " )
case RUN_INTERACTIVE : {
2015-07-25 21:19:28 +00:00
if ( SIZE ( ingredients ) ! = 1 ) {
raise < < current_recipe_name ( ) < < " : 'run-interactive' requires exactly one ingredient, but got " < < current_instruction ( ) . to_string ( ) < < ' \n ' < < end ( ) ;
break ;
}
if ( ! scalar ( ingredients . at ( 0 ) ) ) {
raise < < current_recipe_name ( ) < < " : first ingredient of 'run-interactive' should be a literal string, but got " < < current_instruction ( ) . ingredients . at ( 0 ) . original_string < < ' \n ' < < end ( ) ;
break ;
}
2015-07-08 19:54:06 +00:00
bool new_code_pushed_to_stack = run_interactive ( ingredients . at ( 0 ) . at ( 0 ) ) ;
2015-07-07 19:32:31 +00:00
if ( ! new_code_pushed_to_stack ) {
2015-08-03 05:18:19 +00:00
products . resize ( 4 ) ;
2015-07-08 19:54:06 +00:00
products . at ( 0 ) . push_back ( 0 ) ;
2015-08-02 19:58:24 +00:00
products . at ( 1 ) . push_back ( trace_contents ( " warn " ) ) ;
2015-07-17 19:51:32 +00:00
products . at ( 2 ) . push_back ( 0 ) ;
2015-08-02 22:26:58 +00:00
products . at ( 3 ) . push_back ( trace_contents ( " app " ) ) ;
2015-07-16 01:05:28 +00:00
clean_up_interactive ( ) ;
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
}
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 ;
2015-07-08 21:47:12 +00:00
: ( before " End Setup " )
2015-08-16 05:37:55 +00:00
Track_most_recent_products = false ;
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
// all warnings.
2015-07-08 19:54:06 +00:00
// returns true if successfully called (no errors found during load and transform)
bool run_interactive ( long long int address ) {
2015-07-04 16:40:50 +00:00
if ( Recipe_ordinal . find ( " interactive " ) = = Recipe_ordinal . end ( ) )
Recipe_ordinal [ " interactive " ] = Next_recipe_ordinal + + ;
2015-07-16 05:08:21 +00:00
// try to sandbox the run as best you can
// todo: test this
if ( ! Current_scenario ) {
for ( long long int i = 1 ; i < Reserved_for_tests ; + + i )
Memory . erase ( i ) ;
}
2015-07-19 16:57:40 +00:00
string command = trim ( strip_comments ( read_mu_string ( address ) ) ) ;
2015-07-07 19:32:31 +00:00
if ( command . empty ( ) ) return false ;
2015-07-04 16:40:50 +00:00
Recipe . erase ( Recipe_ordinal [ " interactive " ] ) ;
2015-08-16 07:01:49 +00:00
Name [ Recipe_ordinal [ " interactive " ] ] . clear ( ) ;
2015-07-08 18:43:59 +00:00
Hide_warnings = true ;
2015-07-11 07:55:01 +00:00
if ( ! Trace_stream ) {
Trace_file = " " ; // if there wasn't already a stream we don't want to save it
Trace_stream = new trace_stream ;
2015-08-02 22:26:58 +00:00
Trace_stream - > collect_layers . insert ( " warn " ) ;
Trace_stream - > collect_layers . insert ( " app " ) ;
2015-07-11 07:55:01 +00:00
}
2015-06-01 06:44:52 +00:00
// call run(string) but without the scheduling
2015-07-17 19:51:32 +00:00
load ( string ( " recipe interactive [ \n " ) +
2015-08-16 07:01:49 +00:00
" local-scope \n " +
2015-07-26 05:11:58 +00:00
" screen:address <- new-fake-screen 30, 5 \n " +
2015-07-17 19:51:32 +00:00
command + " \n " +
2015-08-16 07:01:49 +00:00
" reply screen \n " +
2015-07-17 19:51:32 +00:00
" ] \n " ) ;
2015-06-01 06:44:52 +00:00
transform_all ( ) ;
2015-07-16 01:05:28 +00:00
if ( trace_count ( " warn " ) > 0 ) return false ;
2015-08-16 05:37:55 +00:00
Track_most_recent_products = true ;
2015-07-04 16:40:50 +00:00
Current_routine - > calls . push_front ( call ( Recipe_ordinal [ " interactive " ] ) ) ;
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
2015-07-08 21:47:12 +00:00
: ( scenario " run_interactive_returns_stringified_result " )
recipe main [
# try to interactively add 2 and 2
2015-07-28 21:33:22 +00:00
1 : address : array : character < - new [ add 2 , 2 ]
2015-07-08 21:47:12 +00:00
2 : address : array : character < - run - interactive 1 : address : array : character
2015-07-28 22:03:46 +00:00
10 : array : character < - copy 2 : address : array : character / lookup
2015-07-08 21:47:12 +00:00
]
# first letter in the output should be '4' in unicode
+ mem : storing 52 in location 11
2015-07-08 22:25:11 +00:00
: ( scenario " run_interactive_returns_string " )
recipe main [
# try to interactively add 2 and 2
1 : address : array : character < - new [
100 : address : array : character < - new [ a ]
101 : address : array : character < - new [ b ]
102 : address : array : character < - string - append 100 : address : array : character , 101 : address : array : character
]
2 : address : array : character < - run - interactive 1 : address : array : character
2015-07-28 22:03:46 +00:00
10 : array : character < - copy 2 : address : array : character / lookup
2015-07-08 22:25:11 +00:00
]
# output contains "ab"
+ mem : storing 97 in location 11
+ mem : storing 98 in location 12
2015-07-08 23:16:11 +00:00
: ( scenario " run_interactive_returns_warnings " )
recipe main [
# run a command that generates a warning
1 : address : array : character < - new [ get 1234 : number , foo : offset ]
2 : address : array : character , 3 : address : array : character < - run - interactive 1 : address : array : character
2015-07-28 22:03:46 +00:00
10 : array : character < - copy 3 : address : array : character / lookup
2015-07-08 23:16:11 +00:00
]
# warning should be "unknown element foo in container number"
+ mem : storing 117 in location 11
+ mem : storing 110 in location 12
+ mem : storing 107 in location 13
+ mem : storing 110 in location 14
2015-07-08 21:47:12 +00:00
: ( before " End Globals " )
2015-08-16 05:37:55 +00:00
string Most_recent_products ;
2015-07-08 21:53:37 +00:00
: ( before " End Setup " )
2015-08-16 05:37:55 +00:00
Most_recent_products = " " ;
2015-07-08 21:47:12 +00:00
: ( before " End of Instruction " )
2015-08-16 05:37:55 +00:00
if ( Track_most_recent_products ) {
track_most_recent_products ( current_instruction ( ) , products ) ;
2015-07-08 21:53:37 +00:00
}
2015-07-08 21:47:12 +00:00
: ( code )
2015-08-16 05:37:55 +00:00
void track_most_recent_products ( const instruction & instruction , const vector < vector < double > > & products ) {
2015-07-08 21:47:12 +00:00
ostringstream out ;
for ( long long int i = 0 ; i < SIZE ( products ) ; + + i ) {
2015-07-08 22:25:11 +00:00
// string
if ( i < SIZE ( instruction . products ) ) {
2015-08-02 05:16:09 +00:00
if ( is_mu_string ( instruction . products . at ( i ) ) ) {
2015-08-03 05:18:19 +00:00
if ( ! scalar ( products . at ( i ) ) ) {
tb_shutdown ( ) ;
cerr < < read_mu_string ( trace_contents ( " warn " ) ) < < ' \n ' ;
cerr < < SIZE ( products . at ( i ) ) < < " : " ;
for ( long long int j = 0 ; j < SIZE ( products . at ( i ) ) ; + + j )
cerr < < products . at ( i ) . at ( j ) < < ' ' ;
cerr < < ' \n ' ;
}
2015-07-08 22:25:11 +00:00
assert ( scalar ( products . at ( i ) ) ) ;
2015-07-19 16:57:40 +00:00
out < < read_mu_string ( products . at ( i ) . at ( 0 ) ) < < ' \n ' ;
2015-07-08 22:25:11 +00:00
continue ;
}
// End Record Product Special-cases
}
2015-07-16 01:05:28 +00:00
for ( long long int j = 0 ; j < SIZE ( products . at ( i ) ) ; + + j )
out < < products . at ( i ) . at ( j ) < < ' ' ;
2015-07-08 21:47:12 +00:00
out < < ' \n ' ;
}
2015-08-16 05:37:55 +00:00
Most_recent_products = out . str ( ) ;
2015-07-08 21:47:12 +00:00
}
2015-08-16 07:01:49 +00:00
//: Recipe 'interactive' doesn't return what 'run-interactive seems to return.
//: Massage results from former to latter.
: ( after " Starting Reply " )
if ( Current_routine - > calls . front ( ) . running_recipe = = Recipe_ordinal [ " interactive " ] ) {
products . resize ( 4 ) ;
products . at ( 0 ) . push_back ( new_mu_string ( Most_recent_products ) ) ;
products . at ( 1 ) . push_back ( trace_contents ( " warn " ) ) ;
assert ( SIZE ( ingredients ) = = 1 ) ;
assert ( scalar ( ingredients . at ( 0 ) ) ) ;
products . at ( 2 ) . push_back ( ingredients . at ( 0 ) . at ( 0 ) ) ; // screen
products . at ( 3 ) . push_back ( trace_contents ( " app " ) ) ;
- - Callstack_depth ;
Current_routine - > calls . pop_front ( ) ;
assert ( ! Current_routine - > calls . empty ( ) ) ;
2015-08-16 16:22:22 +00:00
clean_up_interactive ( ) ;
2015-08-16 07:01:49 +00:00
break ;
2015-07-17 19:51:32 +00:00
}
//: clean up reply after we've popped it off the call-stack
: ( code )
void clean_up_interactive ( ) {
Hide_warnings = false ;
2015-08-16 05:37:55 +00:00
Track_most_recent_products = false ;
2015-08-16 16:22:22 +00:00
if ( Trace_stream - > is_narrowly_collecting ( " warn " ) ) { // hack
2015-07-17 19:51:32 +00:00
delete Trace_stream ;
Trace_stream = NULL ;
}
2015-07-08 20:26:02 +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 ;
for ( long long int i = 0 ; i < SIZE ( in ) ; + + i ) {
if ( in . at ( i ) ! = ' # ' ) {
result < < in . at ( i ) ;
}
else {
while ( i < SIZE ( in ) & & in . at ( i ) ! = ' \n ' )
+ + i ;
if ( i < SIZE ( in ) & & in . at ( i ) = = ' \n ' ) + + i ;
}
}
return result . str ( ) ;
}
2015-07-07 19:32:31 +00:00
long long int stringified_value_of_location ( long long int address ) {
2015-06-06 17:38:51 +00:00
// convert to string
ostringstream out ;
2015-07-07 19:32:31 +00:00
out < < Memory [ address ] ;
2015-07-19 16:57:40 +00:00
return new_mu_string ( out . str ( ) ) ;
2015-06-06 17:38:51 +00:00
}
2015-08-02 19:58:24 +00:00
long long int trace_contents ( const string & layer ) {
2015-07-08 23:16:11 +00:00
if ( ! Trace_stream ) return 0 ;
2015-08-02 22:26:58 +00:00
//? cerr << "trace stream exists\n"; //? 1
2015-08-02 19:58:24 +00:00
if ( trace_count ( layer ) < = 0 ) return 0 ;
2015-08-02 22:26:58 +00:00
//? cerr << layer << " has something\n"; //? 1
2015-07-08 23:16:11 +00:00
ostringstream out ;
for ( vector < trace_line > : : iterator p = Trace_stream - > past_lines . begin ( ) ; p ! = Trace_stream - > past_lines . end ( ) ; + + p ) {
2015-08-02 19:58:24 +00:00
if ( p - > label ! = layer ) continue ;
2015-07-08 23:16:11 +00:00
out < < p - > contents ;
if ( * - - p - > contents . end ( ) ! = ' \n ' ) out < < ' \n ' ;
}
assert ( ! out . str ( ) . empty ( ) ) ;
2015-08-02 22:26:58 +00:00
//? cerr << layer << ":\n" << out.str() << "\n--\n"; //? 1
2015-07-19 16:57:40 +00:00
return new_mu_string ( out . str ( ) ) ;
2015-07-08 23:16:11 +00:00
}
2015-07-09 06:10:02 +00:00
//: simpler version of run-interactive: doesn't do any running, just loads
//: recipes and reports warnings.
: ( before " End Primitive Recipe Declarations " )
RELOAD ,
: ( before " End Primitive Recipe Numbers " )
Recipe_ordinal [ " reload " ] = RELOAD ;
: ( before " End Primitive Recipe Implementations " )
case RELOAD : {
2015-07-25 21:19:28 +00:00
if ( SIZE ( ingredients ) ! = 1 ) {
raise < < current_recipe_name ( ) < < " : 'reload' requires exactly one ingredient, but got " < < current_instruction ( ) . to_string ( ) < < ' \n ' < < end ( ) ;
break ;
}
if ( ! scalar ( ingredients . at ( 0 ) ) ) {
raise < < current_recipe_name ( ) < < " : first ingredient of 'reload' should be a literal string, but got " < < current_instruction ( ) . ingredients . at ( 0 ) . original_string < < ' \n ' < < end ( ) ;
break ;
}
2015-07-22 06:38:21 +00:00
if ( ! Trace_stream ) {
Trace_file = " " ; // if there wasn't already a stream we don't want to save it
Trace_stream = new trace_stream ;
2015-08-02 22:26:58 +00:00
Trace_stream - > collect_layers . insert ( " warn " ) ;
2015-07-22 06:38:21 +00:00
}
2015-07-09 06:10:02 +00:00
Hide_warnings = true ;
2015-07-25 07:24:12 +00:00
Disable_redefine_warnings = true ;
2015-08-14 23:46:49 +00:00
vector < recipe_ordinal > recipes_reloaded = load ( read_mu_string ( ingredients . at ( 0 ) . at ( 0 ) ) ) ;
for ( long long int i = 0 ; i < SIZE ( recipes_reloaded ) ; + + i ) {
Name . erase ( recipes_reloaded . at ( i ) ) ;
}
2015-07-09 06:10:02 +00:00
transform_all ( ) ;
2015-07-22 06:38:21 +00:00
Trace_stream - > newline ( ) ; // flush trace
2015-07-25 07:24:12 +00:00
Disable_redefine_warnings = false ;
2015-07-09 06:10:02 +00:00
Hide_warnings = false ;
2015-08-03 05:18:19 +00:00
products . resize ( 1 ) ;
2015-08-02 19:58:24 +00:00
products . at ( 0 ) . push_back ( trace_contents ( " warn " ) ) ;
2015-08-02 22:26:58 +00:00
// hack: assume collect_layers isn't set anywhere else
if ( Trace_stream - > is_narrowly_collecting ( " warn " ) ) {
2015-07-22 06:38:21 +00:00
delete Trace_stream ;
Trace_stream = NULL ;
}
2015-07-09 06:10:02 +00:00
break ;
}