2016-02-18 09:19:36 +00:00
//:: Container definitions can contain 'type ingredients'
2015-10-30 20:00:16 +00:00
2015-11-11 04:24:03 +00:00
: ( scenario size_of_shape_shifting_container )
2015-10-30 20:00:16 +00:00
container foo : _t [
x : _t
y : number
]
recipe main [
1 : foo : number < - merge 12 , 13
3 : foo : point < - merge 14 , 15 , 16
]
+ mem : storing 12 in location 1
+ mem : storing 13 in location 2
+ mem : storing 14 in location 3
+ mem : storing 15 in location 4
+ mem : storing 16 in location 5
2016-02-18 09:19:36 +00:00
: ( scenario size_of_shape_shifting_container_2 )
# multiple type ingredients
container foo : _a : _b [
x : _a
y : _b
]
recipe main [
1 : foo : number : boolean < - merge 34 , 1 / true
]
2016-02-19 07:45:53 +00:00
$ error : 0
2016-02-18 09:19:36 +00:00
: ( scenario size_of_shape_shifting_container_3 )
container foo : _a : _b [
x : _a
y : _b
]
recipe main [
1 : address : shared : array : character < - new [ abc ]
# compound types for type ingredients
{ 2 : ( foo number ( address shared array character ) ) } < - merge 34 / x , 1 : address : shared : array : character / y
]
2016-02-19 07:45:53 +00:00
$ error : 0
2016-02-18 09:19:36 +00:00
: ( scenario size_of_shape_shifting_container_4 )
container foo : _a : _b [
x : _a
y : _b
]
container bar : _a : _b [
# dilated element
{ data : ( foo _a ( address shared _b ) ) }
]
recipe main [
1 : address : shared : array : character < - new [ abc ]
2 : bar : number : array : character < - merge 34 / x , 1 : address : shared : array : character / y
]
2016-02-19 07:45:53 +00:00
$ error : 0
2016-02-18 09:19:36 +00:00
2015-10-30 20:00:16 +00:00
: ( before " End Globals " )
// We'll use large type ordinals to mean "the following type of the variable".
const int START_TYPE_INGREDIENTS = 2000 ;
: ( before " End Test Run Initialization " )
assert ( Next_type_ordinal < START_TYPE_INGREDIENTS ) ;
: ( before " End type_info Fields " )
map < string , type_ordinal > type_ingredient_names ;
2015-11-11 04:24:03 +00:00
//: Suppress unknown type checks in shape-shifting containers.
2015-11-05 07:44:46 +00:00
: ( before " Check Container Field Types(info) " )
if ( ! info . type_ingredient_names . empty ( ) ) continue ;
2015-10-30 20:00:16 +00:00
: ( before " End container Name Refinements " )
if ( name . find ( ' : ' ) ! = string : : npos ) {
trace ( 9999 , " parse " ) < < " container has type ingredients; parsing " < < end ( ) ;
read_type_ingredients ( name ) ;
}
: ( code )
void read_type_ingredients ( string & name ) {
string save_name = name ;
istringstream in ( save_name ) ;
name = slurp_until ( in , ' : ' ) ;
2015-11-06 21:22:16 +00:00
if ( ! contains_key ( Type_ordinal , name ) | | get ( Type_ordinal , name ) = = 0 )
2015-11-06 19:06:58 +00:00
put ( Type_ordinal , name , Next_type_ordinal + + ) ;
2015-11-06 19:31:37 +00:00
type_info & info = get_or_insert ( Type , get ( Type_ordinal , name ) ) ;
2015-10-30 20:00:16 +00:00
long long int next_type_ordinal = START_TYPE_INGREDIENTS ;
2015-11-17 09:21:00 +00:00
while ( has_data ( in ) ) {
2015-10-30 20:00:16 +00:00
string curr = slurp_until ( in , ' : ' ) ;
if ( info . type_ingredient_names . find ( curr ) ! = info . type_ingredient_names . end ( ) ) {
2016-02-26 21:04:55 +00:00
raise < < " can't repeat type ingredient names in a single container definition \n " < < end ( ) ;
2015-10-30 20:00:16 +00:00
return ;
}
2015-11-08 06:56:06 +00:00
put ( info . type_ingredient_names , curr , next_type_ordinal + + ) ;
2015-10-30 20:00:16 +00:00
}
}
2016-02-07 00:47:10 +00:00
: ( before " End insert_container Special-cases " )
2015-10-30 20:00:16 +00:00
// check for use of type ingredients
2016-02-22 04:30:02 +00:00
else if ( is_type_ingredient_name ( type - > name ) ) {
type - > value = get ( info . type_ingredient_names , type - > name ) ;
}
: ( code )
bool is_type_ingredient_name ( const string & type ) {
return ! type . empty ( ) & & type . at ( 0 ) = = ' _ ' ;
2015-10-30 20:00:16 +00:00
}
: ( before " End Container Type Checks " )
if ( type - > value > = START_TYPE_INGREDIENTS
2015-11-06 19:06:58 +00:00
& & ( type - > value - START_TYPE_INGREDIENTS ) < SIZE ( get ( Type , type - > value ) . type_ingredient_names ) )
2015-10-30 20:00:16 +00:00
return ;
2016-02-15 07:15:03 +00:00
: ( scenario size_of_shape_shifting_exclusive_container )
exclusive - container foo : _t [
x : _t
y : number
]
recipe main [
1 : foo : number < - merge 0 / x , 34
3 : foo : point < - merge 0 / x , 15 , 16
6 : foo : point < - merge 1 / y , 23
]
+ mem : storing 0 in location 1
+ mem : storing 34 in location 2
+ mem : storing 0 in location 3
+ mem : storing 15 in location 4
+ mem : storing 16 in location 5
+ mem : storing 1 in location 6
+ mem : storing 23 in location 7
$ mem : 7
2015-10-30 20:00:16 +00:00
: ( code )
2015-11-11 04:24:03 +00:00
// shape-shifting version of size_of
2015-10-31 04:12:54 +00:00
long long int size_of_type_ingredient ( const type_tree * element_template , const type_tree * rest_of_use ) {
2016-02-15 07:30:59 +00:00
type_tree * element_type = type_ingredient ( element_template , rest_of_use ) ;
if ( ! element_type ) return 0 ;
long long int result = size_of ( element_type ) ;
delete element_type ;
return result ;
}
type_tree * type_ingredient ( const type_tree * element_template , const type_tree * rest_of_use ) {
2015-10-31 04:12:54 +00:00
long long int type_ingredient_index = element_template - > value - START_TYPE_INGREDIENTS ;
const type_tree * curr = rest_of_use ;
2016-02-15 07:30:59 +00:00
if ( ! curr ) return NULL ;
2015-10-30 20:00:16 +00:00
while ( type_ingredient_index > 0 ) {
- - type_ingredient_index ;
curr = curr - > right ;
2016-02-15 07:30:59 +00:00
if ( ! curr ) return NULL ;
2015-10-30 20:00:16 +00:00
}
assert ( curr ) ;
2016-02-18 09:19:36 +00:00
if ( curr - > left ) curr = curr - > left ;
assert ( curr - > value > 0 ) ;
2015-11-06 19:06:58 +00:00
trace ( 9999 , " type " ) < < " type deduced to be " < < get ( Type , curr - > value ) . name < < " $ " < < end ( ) ;
2016-02-15 07:30:59 +00:00
return new type_tree ( * curr ) ;
2015-10-30 20:00:16 +00:00
}
2015-10-31 04:12:54 +00:00
2015-11-11 04:24:03 +00:00
: ( scenario get_on_shape_shifting_container )
2015-10-31 04:12:54 +00:00
container foo : _t [
x : _t
y : number
]
recipe main [
1 : foo : point < - merge 14 , 15 , 16
2015-11-02 03:38:30 +00:00
2 : number < - get 1 : foo : point , y : offset
2015-10-31 04:12:54 +00:00
]
+ mem : storing 16 in location 2
: ( before " End GET field Cases " )
2016-02-17 18:09:48 +00:00
const type_tree * type = get ( Type , base_type ) . elements . at ( i ) . type ;
2015-11-08 22:46:48 +00:00
if ( type - > value > = START_TYPE_INGREDIENTS ) {
long long int size = size_of_type_ingredient ( type , base . type - > right ) ;
if ( ! size )
2016-02-26 21:04:55 +00:00
raise < < " illegal field type ' " < < to_string ( type ) < < " ' seems to be missing a type ingredient or three \n " < < end ( ) ;
2015-11-08 22:46:48 +00:00
src + = size ;
2015-10-31 04:12:54 +00:00
continue ;
}
2015-11-11 04:24:03 +00:00
: ( scenario get_on_shape_shifting_container_2 )
2015-11-02 03:38:30 +00:00
container foo : _t [
x : _t
y : number
]
recipe main [
1 : foo : point < - merge 14 , 15 , 16
2 : point < - get 1 : foo : point , x : offset
]
+ mem : storing 14 in location 2
+ mem : storing 15 in location 3
2015-11-11 04:24:03 +00:00
: ( scenario get_on_shape_shifting_container_3 )
2015-11-09 22:48:46 +00:00
container foo : _t [
x : _t
y : number
]
recipe main [
2016-02-15 07:30:59 +00:00
1 : foo : address : point < - merge 34 / unsafe , 48
2015-11-09 22:48:46 +00:00
2 : address : point < - get 1 : foo : address : point , x : offset
]
+ mem : storing 34 in location 2
2016-02-19 10:21:37 +00:00
: ( scenario get_on_shape_shifting_container_inside_container )
container foo : _t [
x : _t
y : number
]
container bar [
x : foo : point
y : number
]
recipe main [
1 : bar < - merge 14 , 15 , 16 , 17
2 : number < - get 1 : bar , 1 : offset
]
+ mem : storing 17 in location 2
2016-02-19 17:45:06 +00:00
: ( scenario get_on_complex_shape_shifting_container )
container foo : _a : _b [
x : _a
y : _b
]
recipe main [
1 : address : shared : array : character < - new [ abc ]
{ 2 : ( foo number ( address shared array character ) ) } < - merge 34 / x , 1 : address : shared : array : character / y
3 : address : shared : array : character < - get { 2 : ( foo number ( address shared array character ) ) } , y : offset
4 : boolean < - equal 1 : address : shared : array : character , 3 : address : shared : array : character
]
+ mem : storing 1 in location 4
2015-11-02 03:38:30 +00:00
: ( before " End element_type Special-cases " )
if ( contains_type_ingredient ( element ) ) {
2015-11-08 22:46:48 +00:00
if ( ! canonized_base . type - > right )
2016-02-26 21:04:55 +00:00
raise < < " illegal type " < < names_to_string ( canonized_base . type ) < < " seems to be missing a type ingredient or three \n " < < end ( ) ;
2016-02-22 04:30:02 +00:00
replace_type_ingredients ( element . type , canonized_base . type - > right , info ) ;
2015-11-02 03:38:30 +00:00
}
: ( code )
bool contains_type_ingredient ( const reagent & x ) {
return contains_type_ingredient ( x . type ) ;
}
bool contains_type_ingredient ( const type_tree * type ) {
if ( ! type ) return false ;
if ( type - > value > = START_TYPE_INGREDIENTS ) return true ;
return contains_type_ingredient ( type - > left ) | | contains_type_ingredient ( type - > right ) ;
}
2016-02-19 10:53:19 +00:00
// todo: too complicated and likely incomplete; maybe avoid replacing in place? Maybe process element_type and element_type_name in separate functions?
2016-02-22 04:30:02 +00:00
void replace_type_ingredients ( type_tree * element_type , const type_tree * callsite_type , const type_info & container_info ) {
2015-11-04 21:14:41 +00:00
if ( ! callsite_type ) return ; // error but it's already been raised above
2015-11-02 03:38:30 +00:00
if ( ! element_type ) return ;
2016-02-19 07:52:12 +00:00
2016-02-19 18:45:18 +00:00
// A. recurse first to avoid nested replaces (which I can't reason about yet)
2016-02-22 04:30:02 +00:00
replace_type_ingredients ( element_type - > left , callsite_type , container_info ) ;
replace_type_ingredients ( element_type - > right , callsite_type , container_info ) ;
2016-02-19 18:45:18 +00:00
if ( element_type - > value < START_TYPE_INGREDIENTS ) return ;
2016-02-19 10:21:37 +00:00
2016-02-19 18:45:18 +00:00
const long long int type_ingredient_index = element_type - > value - START_TYPE_INGREDIENTS ;
if ( ! has_nth_type ( callsite_type , type_ingredient_index ) ) {
2016-02-26 21:04:55 +00:00
raise < < " illegal type " < < names_to_string ( callsite_type ) < < " seems to be missing a type ingredient or three \n " < < end ( ) ;
2016-02-19 18:45:18 +00:00
return ;
}
// B. replace the current location
const type_tree * replacement = NULL ;
bool splice_right = true ;
{
const type_tree * curr = callsite_type ;
for ( long long int i = 0 ; i < type_ingredient_index ; + + i )
curr = curr - > right ;
if ( curr & & curr - > left ) {
replacement = curr - > left ;
2016-02-19 08:02:34 +00:00
}
2016-02-19 10:21:37 +00:00
else {
2016-02-20 16:36:06 +00:00
// We want foo:_t to be used like foo:number, which expands to {foo: number}
// rather than {foo: (number)}
// We'd also like to use it with multiple types: foo:address:number.
2016-02-19 18:45:18 +00:00
replacement = curr ;
2016-02-21 04:05:52 +00:00
if ( ! final_type_ingredient ( type_ingredient_index , container_info ) ) {
2016-02-19 18:45:18 +00:00
splice_right = false ;
2016-02-21 04:05:52 +00:00
}
2016-02-19 08:29:03 +00:00
}
2016-02-19 07:52:12 +00:00
}
2016-02-21 04:05:52 +00:00
element_type - > name = replacement - > name ;
2016-02-19 18:45:18 +00:00
element_type - > value = replacement - > value ;
assert ( ! element_type - > left ) ; // since value is set
element_type - > left = replacement - > left ? new type_tree ( * replacement - > left ) : NULL ;
if ( splice_right ) {
type_tree * old_right = element_type - > right ;
element_type - > right = replacement - > right ? new type_tree ( * replacement - > right ) : NULL ;
append ( element_type - > right , old_right ) ;
}
2016-02-19 08:29:03 +00:00
}
bool final_type_ingredient ( long long int type_ingredient_index , const type_info & container_info ) {
for ( map < string , type_ordinal > : : const_iterator p = container_info . type_ingredient_names . begin ( ) ;
p ! = container_info . type_ingredient_names . end ( ) ;
+ + p ) {
if ( p - > second > START_TYPE_INGREDIENTS + type_ingredient_index ) return false ;
2015-11-02 03:38:30 +00:00
}
2016-02-19 08:29:03 +00:00
return true ;
2015-11-02 03:38:30 +00:00
}
2016-02-18 19:51:57 +00:00
void append ( type_tree * & base , type_tree * extra ) {
if ( ! base ) {
base = extra ;
return ;
}
type_tree * curr = base ;
while ( curr - > right ) curr = curr - > right ;
curr - > right = extra ;
}
void append ( string_tree * & base , string_tree * extra ) {
if ( ! base ) {
base = extra ;
return ;
}
string_tree * curr = base ;
while ( curr - > right ) curr = curr - > right ;
curr - > right = extra ;
}
2016-02-19 07:47:16 +00:00
void test_replace_type_ingredients_entire ( ) {
2016-02-18 09:19:36 +00:00
run ( " container foo:_elem [ \n "
" x:_elem \n "
" y:number \n "
" ] \n " ) ;
reagent callsite ( " x:foo:point " ) ;
reagent element = element_type ( callsite , 0 ) ;
CHECK_EQ ( element . name , " x " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element . type - > name , " point " ) ;
CHECK ( ! element . type - > right ) ;
2016-02-18 09:19:36 +00:00
}
2016-02-19 07:47:16 +00:00
void test_replace_type_ingredients_tail ( ) {
2016-02-18 09:19:36 +00:00
run ( " container foo:_elem [ \n "
" x:_elem \n "
" ] \n "
" container bar:_elem [ \n "
" x:foo:_elem \n "
" ] \n " ) ;
reagent callsite ( " x:bar:point " ) ;
reagent element = element_type ( callsite , 0 ) ;
CHECK_EQ ( element . name , " x " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element . type - > name , " foo " ) ;
CHECK_EQ ( element . type - > right - > name , " point " ) ;
CHECK ( ! element . type - > right - > right ) ;
2016-02-18 09:19:36 +00:00
}
2016-02-19 07:47:16 +00:00
void test_replace_type_ingredients_head_tail_multiple ( ) {
2016-02-18 09:19:36 +00:00
run ( " container foo:_elem [ \n "
" x:_elem \n "
" ] \n "
" container bar:_elem [ \n "
" x:foo:_elem \n "
" ] \n " ) ;
reagent callsite ( " x:bar:address:shared:array:character " ) ;
reagent element = element_type ( callsite , 0 ) ;
CHECK_EQ ( element . name , " x " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element . type - > name , " foo " ) ;
CHECK_EQ ( element . type - > right - > name , " address " ) ;
CHECK_EQ ( element . type - > right - > right - > name , " shared " ) ;
CHECK_EQ ( element . type - > right - > right - > right - > name , " array " ) ;
CHECK_EQ ( element . type - > right - > right - > right - > right - > name , " character " ) ;
CHECK ( ! element . type - > right - > right - > right - > right - > right ) ;
2016-02-18 09:19:36 +00:00
}
2016-02-19 07:47:16 +00:00
void test_replace_type_ingredients_head_middle ( ) {
2016-02-18 09:19:36 +00:00
run ( " container foo:_elem [ \n "
" x:_elem \n "
" ] \n "
" container bar:_elem [ \n "
" x:foo:_elem:number \n "
" ] \n " ) ;
reagent callsite ( " x:bar:address " ) ;
reagent element = element_type ( callsite , 0 ) ;
CHECK_EQ ( element . name , " x " ) ;
2016-02-21 04:05:52 +00:00
CHECK ( element . type )
CHECK_EQ ( element . type - > name , " foo " ) ;
CHECK ( element . type - > right )
CHECK_EQ ( element . type - > right - > name , " address " ) ;
CHECK ( element . type - > right - > right )
CHECK_EQ ( element . type - > right - > right - > name , " number " ) ;
CHECK ( ! element . type - > right - > right - > right ) ;
2016-02-18 09:19:36 +00:00
}
void test_replace_last_type_ingredient_with_multiple ( ) {
run ( " container foo:_a:_b [ \n "
" x:_a \n "
" y:_b \n "
" ] \n " ) ;
reagent callsite ( " {f: (foo number (address shared array character) ) } " ) ;
2016-02-19 10:43:36 +00:00
reagent element1 = element_type ( callsite , 0 ) ;
CHECK_EQ ( element1 . name , " x " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element1 . type - > name , " number " ) ;
CHECK ( ! element1 . type - > right ) ;
2016-02-19 10:43:36 +00:00
reagent element2 = element_type ( callsite , 1 ) ;
CHECK_EQ ( element2 . name , " y " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element2 . type - > name , " address " ) ;
CHECK_EQ ( element2 . type - > right - > name , " shared " ) ;
CHECK_EQ ( element2 . type - > right - > right - > name , " array " ) ;
CHECK_EQ ( element2 . type - > right - > right - > right - > name , " character " ) ;
CHECK ( ! element2 . type - > right - > right - > right - > right ) ;
2016-02-18 09:19:36 +00:00
}
void test_replace_middle_type_ingredient_with_multiple ( ) {
run ( " container foo:_a:_b:_c [ \n "
" x:_a \n "
" y:_b \n "
" z:_c \n "
" ] \n " ) ;
reagent callsite ( " {f: (foo number (address shared array character) boolean ) } " ) ;
2016-02-19 10:43:36 +00:00
reagent element1 = element_type ( callsite , 0 ) ;
CHECK_EQ ( element1 . name , " x " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element1 . type - > name , " number " ) ;
CHECK ( ! element1 . type - > right ) ;
2016-02-19 10:43:36 +00:00
reagent element2 = element_type ( callsite , 1 ) ;
CHECK_EQ ( element2 . name , " y " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element2 . type - > name , " address " ) ;
CHECK_EQ ( element2 . type - > right - > name , " shared " ) ;
CHECK_EQ ( element2 . type - > right - > right - > name , " array " ) ;
CHECK_EQ ( element2 . type - > right - > right - > right - > name , " character " ) ;
CHECK ( ! element2 . type - > right - > right - > right - > right ) ;
2016-02-19 10:43:36 +00:00
reagent element3 = element_type ( callsite , 2 ) ;
CHECK_EQ ( element3 . name , " z " ) ;
2016-02-21 04:05:52 +00:00
CHECK_EQ ( element3 . type - > name , " boolean " ) ;
CHECK ( ! element3 . type - > right ) ;
2016-02-18 09:19:36 +00:00
}
2015-11-08 23:19:01 +00:00
bool has_nth_type ( const type_tree * base , long long int n ) {
2015-11-04 21:14:41 +00:00
assert ( n > = 0 ) ;
if ( base = = NULL ) return false ;
if ( n = = 0 ) return true ;
return has_nth_type ( base - > right , n - 1 ) ;
}
2015-11-11 04:24:03 +00:00
: ( scenario get_on_shape_shifting_container_error )
2015-11-04 21:14:41 +00:00
% Hide_errors = true ;
container foo : _t [
x : _t
y : number
]
recipe main [
10 : foo : point < - merge 14 , 15 , 16
1 : number < - get 10 : foo , 1 : offset
]
2016-02-22 04:30:02 +00:00
+ error : illegal type " foo " seems to be missing a type ingredient or three
2015-11-04 21:14:41 +00:00
//: get-address similarly
2015-11-11 04:24:03 +00:00
: ( scenario get_address_on_shape_shifting_container )
2015-10-31 04:12:54 +00:00
container foo : _t [
x : _t
y : number
]
recipe main [
10 : foo : point < - merge 14 , 15 , 16
1 : address : number < - get - address 10 : foo : point , 1 : offset
]
+ mem : storing 12 in location 1
: ( before " End GET_ADDRESS field Cases " )
2016-02-17 18:09:48 +00:00
const type_tree * type = get ( Type , base_type ) . elements . at ( i ) . type ;
2015-11-08 22:46:48 +00:00
if ( type - > value > = START_TYPE_INGREDIENTS ) {
long long int size = size_of_type_ingredient ( type , base . type - > right ) ;
if ( ! size )
2016-02-26 21:04:55 +00:00
raise < < " illegal type ' " < < to_string ( type ) < < " ' seems to be missing a type ingredient or three \n " < < end ( ) ;
2015-11-08 22:46:48 +00:00
result + = size ;
2015-10-31 04:12:54 +00:00
continue ;
}
2016-02-15 07:30:59 +00:00
//: 'merge' on shape-shifting containers
: ( scenario merge_check_shape_shifting_container_containing_exclusive_container )
container foo : _elem [
x : number
y : _elem
]
exclusive - container bar [
x : number
y : number
]
recipe main [
1 : foo : bar < - merge 23 , 1 / y , 34
]
+ mem : storing 23 in location 1
+ mem : storing 1 in location 2
+ mem : storing 34 in location 3
$ error : 0
: ( scenario merge_check_shape_shifting_container_containing_exclusive_container_2 )
% Hide_errors = true ;
container foo : _elem [
x : number
y : _elem
]
exclusive - container bar [
x : number
y : number
]
recipe main [
1 : foo : bar < - merge 23 , 1 / y , 34 , 35
]
+ error : main : too many ingredients in ' 1 : foo : bar < - merge 23 , 1 / y , 34 , 35 '
: ( scenario merge_check_shape_shifting_exclusive_container_containing_container )
exclusive - container foo : _elem [
x : number
y : _elem
]
container bar [
x : number
y : number
]
recipe main [
1 : foo : bar < - merge 1 / y , 23 , 34
]
+ mem : storing 1 in location 1
+ mem : storing 23 in location 2
+ mem : storing 34 in location 3
$ error : 0
: ( scenario merge_check_shape_shifting_exclusive_container_containing_container_2 )
exclusive - container foo : _elem [
x : number
y : _elem
]
container bar [
x : number
y : number
]
recipe main [
1 : foo : bar < - merge 0 / x , 23
]
$ error : 0
: ( scenario merge_check_shape_shifting_exclusive_container_containing_container_3 )
% Hide_errors = true ;
exclusive - container foo : _elem [
x : number
y : _elem
]
container bar [
x : number
y : number
]
recipe main [
1 : foo : bar < - merge 1 / y , 23
]
+ error : main : too few ingredients in ' 1 : foo : bar < - merge 1 / y , 23 '
: ( before " End variant_type Special-cases " )
if ( contains_type_ingredient ( element ) ) {
if ( ! canonized_base . type - > right )
2016-02-26 21:04:55 +00:00
raise < < " illegal type ' " < < to_string ( canonized_base . type ) < < " ' seems to be missing a type ingredient or three \n " < < end ( ) ;
2016-02-22 04:30:02 +00:00
replace_type_ingredients ( element . type , canonized_base . type - > right , info ) ;
2016-02-15 07:30:59 +00:00
}