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-07-04 16:40:50 +00:00
Recipe_ordinal [ " reply " ] = REPLY ;
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-05-22 01:57:25 +00:00
- - Callstack_depth ;
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-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-07-11 03:26:28 +00:00
if ( SIZE ( caller_instruction . products ) > SIZE ( ingredients ) )
2015-07-25 07:02:20 +00:00
raise < < " too few values replied from " < < callee < < ' \n ' < < end ( ) ;
2015-05-17 09:22:41 +00:00
for ( long long int i = 0 ; i < SIZE ( caller_instruction . products ) ; + + i ) {
2015-07-25 07:02:20 +00:00
trace ( Primitive_recipe_depth , " 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 " ) ) {
vector < string > tmp = property ( reply_inst . ingredients . at ( i ) , " same-as-ingredient " ) ;
2015-07-25 21:19:28 +00:00
if ( SIZE ( tmp ) ! = 1 ) {
raise < < current_recipe_name ( ) < < " : 'same-as-ingredient' metadata should take exactly one value in " < < reply_inst . to_string ( ) < < ' \n ' < < end ( ) ;
goto finish_reply ;
}
2015-05-17 04:24:21 +00:00
long long int ingredient_index = to_integer ( tmp . at ( 0 ) ) ;
2015-07-10 09:00:49 +00:00
if ( ingredient_index > = SIZE ( caller_instruction . ingredients ) )
2015-07-25 07:02:20 +00:00
raise < < 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-08-21 17:09:32 +00:00
raise < < current_recipe_name ( ) < < " : 'same-as-ingredient' product from call to " < < callee < < " must be " < < 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-05-26 22:48:35 +00:00
reply 12 : point / raw # unsafe
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-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 )
% Hide_warnings = true ;
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-05-13 17:03:26 +00:00
10 : address : number < - next - ingredient
reply 10 : address : number / same - as - ingredient : 0
2015-04-28 19:42:54 +00:00
]
2015-08-21 17:09:32 +00:00
+ warn : main : ' same - as - ingredient ' product from call to test1 must be 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 )
% Hide_warnings = true ;
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 [
10 : address : number < - next - ingredient
reply 10 : address : number / same - as - ingredient : 0
]
$ warn : 0
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-05-07 22:06:53 +00:00
out < < 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-05-07 22:06:53 +00:00
out < < 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
: ( before " End Rewrite Instruction(curr) " )
// 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 ( ) ) {
curr . operation = Recipe_ordinal [ " jump-unless " ] ;
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 ( ) ;
curr . operation = Recipe_ordinal [ " reply " ] ;
curr . name = " reply " ;
curr . ingredients . swap ( results ) ;
}
else {
raise < < " 'reply-if' never yields any products \n " < < end ( ) ;
}
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 ( ) ) {
curr . operation = Recipe_ordinal [ " jump-if " ] ;
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 ( ) ;
curr . operation = Recipe_ordinal [ " reply " ] ;
curr . name = " reply " ;
curr . ingredients . swap ( results ) ;
}
else {
raise < < " 'reply-unless' never yields any products \n " < < end ( ) ;
}
2015-06-18 17:50:54 +00:00
}