2016-03-08 09:30:14 +00:00
//: Calls can also generate products, using 'reply' or 'return'.
2015-04-17 18:22:59 +00:00
2016-04-27 22:37:09 +00:00
: ( scenario return )
2016-03-08 09:30:14 +00:00
def main [
2015-07-28 21:33:22 +00:00
1 : number , 2 : number < - f 34
2015-03-15 16:49:23 +00:00
]
2016-03-08 09:30:14 +00:00
def 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 " )
2016-04-27 22:37:09 +00:00
RETURN ,
2015-03-15 16:49:23 +00:00
: ( before " End Primitive Recipe Numbers " )
2016-04-27 22:37:09 +00:00
put ( Recipe_ordinal , " return " , RETURN ) ;
put ( Recipe_ordinal , " reply " , RETURN ) ; // synonym while teaching
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
2016-04-27 22:37:09 +00:00
case RETURN : {
2015-12-14 04:49:23 +00:00
break ; // checks will be performed by a transform below
2015-10-02 00:30:14 +00:00
}
2015-03-15 16:49:23 +00:00
: ( before " End Primitive Recipe Implementations " )
2016-04-27 22:37:09 +00:00
case RETURN : {
2015-07-08 20:26:02 +00:00
// Starting Reply
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 ) {
2015-12-14 18:20:42 +00:00
Current_routine - > calls . clear ( ) ;
2015-12-08 07:23:12 +00:00
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 ;
2016-07-23 04:15:09 +00:00
for ( int i = 0 ; i < SIZE ( ingredients ) ; + + i )
2015-12-14 04:49:23 +00:00
trace ( 9998 , " run " ) < < " result " < < i < < " is " < < to_string ( ingredients . at ( i ) ) < < end ( ) ;
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 ( ) ) ) ;
2015-07-17 19:51:32 +00:00
// End 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-12-14 04:49:23 +00:00
//: Types in reply instructions are checked ahead of time.
: ( before " End Checks " )
Transform . push_back ( check_types_of_reply_instructions ) ;
: ( code )
void check_types_of_reply_instructions ( recipe_ordinal r ) {
const recipe & caller = get ( Recipe , r ) ;
2016-02-15 07:18:33 +00:00
trace ( 9991 , " transform " ) < < " --- check types of reply instructions in recipe " < < caller . name < < end ( ) ;
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( caller . steps ) ; + + i ) {
2015-12-14 04:49:23 +00:00
const instruction & caller_instruction = caller . steps . at ( i ) ;
if ( caller_instruction . is_label ) continue ;
if ( caller_instruction . products . empty ( ) ) continue ;
if ( caller_instruction . operation < MAX_PRIMITIVE_RECIPES ) continue ;
const recipe & callee = get ( Recipe , caller_instruction . operation ) ;
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( callee . steps ) ; + + i ) {
2015-12-14 04:49:23 +00:00
const instruction & reply_inst = callee . steps . at ( i ) ;
2016-04-27 22:37:09 +00:00
if ( reply_inst . operation ! = RETURN ) continue ;
2015-12-14 04:49:23 +00:00
// check types with the caller
if ( SIZE ( caller_instruction . products ) > SIZE ( reply_inst . ingredients ) ) {
2016-05-21 05:09:06 +00:00
raise < < maybe ( caller . name ) < < " too few values returned from " < < callee . name < < ' \n ' < < end ( ) ;
2015-12-14 04:49:23 +00:00
break ;
}
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( caller_instruction . products ) ; + + i ) {
2016-05-06 07:46:39 +00:00
reagent /*copy*/ lhs = reply_inst . ingredients . at ( i ) ;
reagent /*copy*/ rhs = caller_instruction . products . at ( i ) ;
2016-04-27 22:37:09 +00:00
// End Check RETURN Copy(lhs, rhs)
2016-02-25 05:14:24 +00:00
if ( ! types_coercible ( rhs , lhs ) ) {
2016-05-21 05:09:06 +00:00
raise < < maybe ( callee . name ) < < reply_inst . name < < " ingredient ' " < < lhs . original_string < < " ' can't be saved in ' " < < rhs . original_string < < " ' \n " < < end ( ) ;
2016-09-05 21:07:33 +00:00
raise < < " [' " < < to_string ( lhs . type ) < < " ' vs ' " < < to_string ( rhs . type ) < < " '] \n " < < end ( ) ;
2015-12-14 04:49:23 +00:00
goto finish_reply_check ;
}
}
// check that any reply ingredients with /same-as-ingredient connect up
// the corresponding ingredient and product in the caller.
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( caller_instruction . products ) ; + + i ) {
2015-12-14 04:49:23 +00:00
if ( has_property ( reply_inst . ingredients . at ( i ) , " same-as-ingredient " ) ) {
string_tree * tmp = property ( reply_inst . ingredients . at ( i ) , " same-as-ingredient " ) ;
if ( ! tmp | | tmp - > right ) {
2016-05-21 05:09:06 +00:00
raise < < maybe ( caller . name ) < < " 'same-as-ingredient' metadata should take exactly one value in ' " < < to_original_string ( reply_inst ) < < " ' \n " < < end ( ) ;
2015-12-14 04:49:23 +00:00
goto finish_reply_check ;
}
2016-03-14 03:26:47 +00:00
int ingredient_index = to_integer ( tmp - > value ) ;
2016-01-25 02:41:26 +00:00
if ( ingredient_index > = SIZE ( caller_instruction . ingredients ) ) {
2016-03-21 09:25:52 +00:00
raise < < maybe ( caller . name ) < < " too few ingredients in ' " < < to_original_string ( caller_instruction ) < < " ' \n " < < end ( ) ;
2016-01-25 02:41:26 +00:00
goto finish_reply_check ;
}
2016-02-15 21:52:51 +00:00
if ( ! is_dummy ( caller_instruction . products . at ( i ) ) & & ! is_literal ( caller_instruction . ingredients . at ( ingredient_index ) ) & & caller_instruction . products . at ( i ) . name ! = caller_instruction . ingredients . at ( ingredient_index ) . name ) {
2016-05-21 05:09:06 +00:00
raise < < maybe ( caller . name ) < < " ' " < < to_original_string ( caller_instruction ) < < " ' should write to ' " < < caller_instruction . ingredients . at ( ingredient_index ) . original_string < < " ' rather than ' " < < caller_instruction . products . at ( i ) . original_string < < " ' \n " < < end ( ) ;
2016-02-15 21:52:51 +00:00
}
2015-12-14 04:49:23 +00:00
}
}
finish_reply_check : ;
}
}
}
2016-04-27 22:37:09 +00:00
: ( scenario return_type_mismatch )
2015-11-09 07:36:37 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-11-09 07:36:37 +00:00
3 : number < - f 2
]
2016-03-08 09:30:14 +00:00
def f [
2015-11-09 07:36:37 +00:00
12 : number < - next - ingredient
13 : number < - copy 35
14 : point < - copy 12 : point / raw
2016-03-08 09:30:14 +00:00
return 14 : point
2015-11-09 07:36:37 +00:00
]
2016-05-21 05:09:06 +00:00
+ error : f : return 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
2016-04-27 22:37:09 +00:00
: ( scenario return_same_as_ingredient )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def 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
]
2016-03-08 09:30:14 +00:00
def test1 [
2015-10-06 01:40:51 +00:00
10 : number < - next - ingredient
2016-03-08 09:30:14 +00:00
return 10 : number / same - as - ingredient : 0
2015-04-28 19:42:54 +00:00
]
2016-05-21 05:09:06 +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
2016-04-27 22:37:09 +00:00
: ( scenario return_same_as_ingredient_dummy )
2016-03-08 09:30:14 +00:00
def 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
]
2016-03-08 09:30:14 +00:00
def test1 [
2015-10-28 20:08:26 +00:00
10 : number < - next - ingredient
2016-03-08 09:30:14 +00:00
return 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 < < " [ " ;
2016-03-14 03:26:47 +00:00
for ( 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 ( ) ;
}