2015-04-17 18:22:59 +00:00
//: Calls can also generate products, using 'reply'.
2015-04-24 17:19:03 +00:00
: ( scenario reply )
2015-03-15 16:49:23 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
1 : number , 2 : number < - f 34
2015-03-15 16:49:23 +00:00
]
recipe f [
2015-05-13 17:03:26 +00:00
12 : number < - next - ingredient
2015-07-28 21:33:22 +00:00
13 : number < - add 1 , 12 : number
2015-05-13 17:03:26 +00:00
reply 12 : number , 13 : number
2015-03-15 16:49:23 +00:00
]
2015-05-07 22:06:53 +00:00
+ mem : storing 34 in location 1
+ mem : storing 35 in location 2
2015-03-15 16:49:23 +00:00
2015-04-17 17:31:17 +00:00
: ( before " End Primitive Recipe Declarations " )
REPLY ,
2015-03-15 16:49:23 +00:00
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " reply " , REPLY ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case REPLY : {
break ; // continue to process rest of *caller* instruction
}
2015-03-15 16:49:23 +00:00
: ( before " End Primitive Recipe Implementations " )
case REPLY : {
2015-07-08 20:26:02 +00:00
// Starting Reply
2015-04-28 19:42:54 +00:00
const instruction & reply_inst = current_instruction ( ) ; // save pointer into recipe before pop
2015-06-17 00:52:49 +00:00
const string & callee = current_recipe_name ( ) ;
2015-10-19 22:07:54 +00:00
if ( Trace_stream ) {
2015-10-29 18:56:10 +00:00
trace ( 9999 , " trace " ) < < " reply: decrementing callstack depth from " < < Trace_stream - > callstack_depth < < end ( ) ;
2015-10-19 22:07:54 +00:00
- - Trace_stream - > callstack_depth ;
2015-12-08 07:23:12 +00:00
if ( Trace_stream - > callstack_depth < 0 ) {
Current_routine - > state = COMPLETED ;
goto stop_running_current_routine ;
}
2015-10-19 22:07:54 +00:00
}
2015-05-13 23:33:40 +00:00
Current_routine - > calls . pop_front ( ) ;
2015-05-08 01:35:33 +00:00
// just in case 'main' returns a value, drop it for now
if ( Current_routine - > calls . empty ( ) ) goto stop_running_current_routine ;
2015-04-25 03:49:53 +00:00
const instruction & caller_instruction = current_instruction ( ) ;
2015-10-06 01:40:51 +00:00
// check types with the caller
if ( SIZE ( caller_instruction . products ) > SIZE ( ingredients ) ) {
2015-10-07 05:15:45 +00:00
raise_error < < " too few values replied from " < < callee < < ' \n ' < < end ( ) ;
2015-10-06 01:40:51 +00:00
break ;
}
for ( long long int i = 0 ; i < SIZE ( caller_instruction . products ) ; + + i ) {
2015-11-27 18:32:34 +00:00
if ( ! types_coercible ( caller_instruction . products . at ( i ) , reply_inst . ingredients . at ( i ) ) ) {
2015-11-09 07:36:37 +00:00
raise_error < < maybe ( callee ) < < " reply ingredient " < < reply_inst . ingredients . at ( i ) . original_string < < " can't be saved in " < < caller_instruction . products . at ( i ) . original_string < < ' \n ' < < end ( ) ;
2015-11-08 08:10:56 +00:00
reagent lhs = reply_inst . ingredients . at ( i ) ;
canonize_type ( lhs ) ;
reagent rhs = caller_instruction . products . at ( i ) ;
canonize_type ( rhs ) ;
2015-11-09 07:36:37 +00:00
raise_error < < debug_string ( lhs . type ) < < " vs " < < debug_string ( rhs . type ) < < ' \n ' < < end ( ) ;
2015-11-29 20:10:22 +00:00
// End reply Type Mismatch Error
2015-10-06 01:40:51 +00:00
goto finish_reply ;
}
}
2015-07-14 03:50:25 +00:00
// make reply products available to caller
2015-05-07 22:06:53 +00:00
copy ( ingredients . begin ( ) , ingredients . end ( ) , inserter ( products , products . begin ( ) ) ) ;
// check that any reply ingredients with /same-as-ingredient connect up
// the corresponding ingredient and product in the caller.
2015-05-17 09:22:41 +00:00
for ( long long int i = 0 ; i < SIZE ( caller_instruction . products ) ; + + i ) {
2015-10-29 19:09:23 +00:00
trace ( 9998 , " run " ) < < " result " < < i < < " is " < < to_string ( ingredients . at ( i ) ) < < end ( ) ;
2015-05-07 22:06:53 +00:00
if ( has_property ( reply_inst . ingredients . at ( i ) , " same-as-ingredient " ) ) {
2015-10-27 03:00:38 +00:00
string_tree * tmp = property ( reply_inst . ingredients . at ( i ) , " same-as-ingredient " ) ;
if ( ! tmp | | tmp - > right ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( current_recipe_name ( ) ) < < " 'same-as-ingredient' metadata should take exactly one value in " < < reply_inst . to_string ( ) < < ' \n ' < < end ( ) ;
2015-07-25 21:19:28 +00:00
goto finish_reply ;
}
2015-10-27 03:00:38 +00:00
long long int ingredient_index = to_integer ( tmp - > value ) ;
2015-07-10 09:00:49 +00:00
if ( ingredient_index > = SIZE ( caller_instruction . ingredients ) )
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( current_recipe_name ( ) ) < < " 'same-as-ingredient' metadata overflows ingredients in: " < < caller_instruction . to_string ( ) < < ' \n ' < < end ( ) ;
2015-07-10 09:00:49 +00:00
if ( ! is_dummy ( caller_instruction . products . at ( i ) ) & & caller_instruction . products . at ( i ) . value ! = caller_instruction . ingredients . at ( ingredient_index ) . value )
2015-11-11 03:19:53 +00:00
raise_error < < maybe ( current_recipe_name ( ) ) < < " ' " < < caller_instruction . to_string ( ) < < " ' should write to " < < caller_instruction . ingredients . at ( ingredient_index ) . original_string < < " rather than " < < caller_instruction . products . at ( i ) . original_string < < ' \n ' < < end ( ) ;
2015-04-28 19:42:54 +00:00
}
2015-03-15 16:49:23 +00:00
}
2015-07-17 19:51:32 +00:00
// End Reply
2015-07-25 21:19:28 +00:00
finish_reply :
2015-06-04 01:00:11 +00:00
break ; // continue to process rest of *caller* instruction
2015-03-15 16:49:23 +00:00
}
2015-03-31 17:56:01 +00:00
2015-04-17 18:22:59 +00:00
//: Products can include containers and exclusive containers, addresses and arrays.
2015-04-24 17:19:03 +00:00
: ( scenario reply_container )
2015-03-31 17:56:01 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
3 : point < - f 2
2015-03-31 17:56:01 +00:00
]
recipe f [
2015-05-13 17:03:26 +00:00
12 : number < - next - ingredient
2015-07-28 21:33:22 +00:00
13 : number < - copy 35
2015-10-06 01:40:51 +00:00
reply 12 : point / raw
2015-03-31 17:56:01 +00:00
]
+ run : result 0 is [ 2 , 35 ]
+ mem : storing 2 in location 3
+ mem : storing 35 in location 4
2015-11-09 07:36:37 +00:00
: ( scenario reply_type_mismatch )
% Hide_errors = true ;
recipe main [
3 : number < - f 2
]
recipe f [
12 : number < - next - ingredient
13 : number < - copy 35
14 : point < - copy 12 : point / raw
reply 14 : point
]
+ error : f : reply ingredient 14 : point can ' t be saved in 3 : number
2015-10-06 01:40:51 +00:00
2015-04-28 19:42:54 +00:00
//: In mu we'd like to assume that any instruction doesn't modify its
//: ingredients unless they're also products. The /same-as-ingredient inside
//: the recipe's 'reply' will help catch accidental misuse of such
2015-07-14 03:50:25 +00:00
//: 'ingredient-products' (sometimes called in-out parameters in other languages).
2015-05-10 18:38:18 +00:00
2015-04-28 19:42:54 +00:00
: ( scenario reply_same_as_ingredient )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-04-28 19:42:54 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
1 : number < - copy 0
2015-05-13 17:03:26 +00:00
2 : number < - test1 1 : number # call with different ingredient and product
2015-04-28 19:42:54 +00:00
]
recipe test1 [
2015-10-06 01:40:51 +00:00
10 : number < - next - ingredient
reply 10 : number / same - as - ingredient : 0
2015-04-28 19:42:54 +00:00
]
2015-11-11 03:19:53 +00:00
+ error : main : ' 2 : number < - test1 1 : number ' should write to 1 : number rather than 2 : number
2015-04-28 19:42:54 +00:00
2015-07-10 09:00:49 +00:00
: ( scenario reply_same_as_ingredient_dummy )
2015-10-28 20:08:26 +00:00
# % Hide_errors = true;
2015-07-10 09:00:49 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
1 : number < - copy 0
2015-07-10 09:00:49 +00:00
_ < - test1 1 : number # call with different ingredient and product
]
recipe test1 [
2015-10-28 20:08:26 +00:00
10 : number < - next - ingredient
reply 10 : number / same - as - ingredient : 0
2015-07-10 09:00:49 +00:00
]
2015-10-07 05:15:45 +00:00
$ error : 0
2015-07-10 09:00:49 +00:00
2015-03-31 17:56:01 +00:00
: ( code )
2015-05-13 01:08:47 +00:00
string to_string ( const vector < double > & in ) {
2015-03-31 17:56:01 +00:00
if ( in . empty ( ) ) return " [] " ;
ostringstream out ;
2015-05-17 09:22:41 +00:00
if ( SIZE ( in ) = = 1 ) {
2015-09-15 06:30:03 +00:00
out < < no_scientific ( in . at ( 0 ) ) ;
2015-03-31 17:56:01 +00:00
return out . str ( ) ;
}
out < < " [ " ;
2015-05-17 09:22:41 +00:00
for ( long long int i = 0 ; i < SIZE ( in ) ; + + i ) {
2015-03-31 17:56:01 +00:00
if ( i > 0 ) out < < " , " ;
2015-09-15 06:30:03 +00:00
out < < no_scientific ( in . at ( i ) ) ;
2015-03-31 17:56:01 +00:00
}
out < < " ] " ;
return out . str ( ) ;
}
2015-05-10 18:38:18 +00:00
//: Conditional reply.
: ( scenario reply_if )
recipe main [
2015-05-13 17:03:26 +00:00
1 : number < - test1
2015-05-10 18:38:18 +00:00
]
recipe test1 [
2015-07-28 21:33:22 +00:00
reply - if 0 , 34
reply 35
2015-05-10 18:38:18 +00:00
]
+ mem : storing 35 in location 1
2015-08-09 19:26:31 +00:00
: ( scenario reply_if_2 )
2015-05-10 18:38:18 +00:00
recipe main [
2015-05-13 17:03:26 +00:00
1 : number < - test1
2015-05-10 18:38:18 +00:00
]
recipe test1 [
2015-07-28 21:33:22 +00:00
reply - if 1 , 34
reply 35
2015-05-10 18:38:18 +00:00
]
+ mem : storing 34 in location 1
2015-10-29 01:19:41 +00:00
: ( before " End Rewrite Instruction(curr, recipe result) " )
2015-05-10 18:38:18 +00:00
// rewrite `reply-if a, b, c, ...` to
// ```
// jump-unless a, 1:offset
// reply b, c, ...
// ```
if ( curr . name = = " reply-if " ) {
2015-07-25 21:19:28 +00:00
if ( curr . products . empty ( ) ) {
2015-11-06 19:06:58 +00:00
curr . operation = get ( Recipe_ordinal , " jump-unless " ) ;
2015-07-25 21:19:28 +00:00
curr . name = " jump-unless " ;
vector < reagent > results ;
copy ( + + curr . ingredients . begin ( ) , curr . ingredients . end ( ) , inserter ( results , results . end ( ) ) ) ;
curr . ingredients . resize ( 1 ) ;
curr . ingredients . push_back ( reagent ( " 1:offset " ) ) ;
result . steps . push_back ( curr ) ;
curr . clear ( ) ;
2015-11-06 19:06:58 +00:00
curr . operation = get ( Recipe_ordinal , " reply " ) ;
2015-07-25 21:19:28 +00:00
curr . name = " reply " ;
curr . ingredients . swap ( results ) ;
}
else {
2015-10-07 05:15:45 +00:00
raise_error < < " 'reply-if' never yields any products \n " < < end ( ) ;
2015-07-25 21:19:28 +00:00
}
2015-05-10 18:38:18 +00:00
}
2015-06-18 17:50:54 +00:00
// rewrite `reply-unless a, b, c, ...` to
// ```
// jump-if a, 1:offset
// reply b, c, ...
// ```
if ( curr . name = = " reply-unless " ) {
2015-07-25 21:19:28 +00:00
if ( curr . products . empty ( ) ) {
2015-11-06 19:06:58 +00:00
curr . operation = get ( Recipe_ordinal , " jump-if " ) ;
2015-07-25 21:19:28 +00:00
curr . name = " jump-if " ;
vector < reagent > results ;
copy ( + + curr . ingredients . begin ( ) , curr . ingredients . end ( ) , inserter ( results , results . end ( ) ) ) ;
curr . ingredients . resize ( 1 ) ;
curr . ingredients . push_back ( reagent ( " 1:offset " ) ) ;
result . steps . push_back ( curr ) ;
curr . clear ( ) ;
2015-11-06 19:06:58 +00:00
curr . operation = get ( Recipe_ordinal , " reply " ) ;
2015-07-25 21:19:28 +00:00
curr . name = " reply " ;
curr . ingredients . swap ( results ) ;
}
else {
2015-10-07 05:15:45 +00:00
raise_error < < " 'reply-unless' never yields any products \n " < < end ( ) ;
2015-07-25 21:19:28 +00:00
}
2015-06-18 17:50:54 +00:00
}