2015-04-16 17:35:49 +00:00
//: Containers contain a fixed number of elements of different types.
2015-04-17 18:22:59 +00:00
2015-03-17 03:26:59 +00:00
: ( before " End Mu Types Initialization " )
2015-05-13 17:03:26 +00:00
//: We'll use this container as a running example, with two number elements.
2015-07-04 16:40:50 +00:00
type_ordinal point = Type_ordinal [ " point " ] = Next_type_ordinal + + ;
2015-02-22 08:08:25 +00:00
Type [ point ] . size = 2 ;
2015-10-27 03:06:51 +00:00
Type [ point ] . kind = CONTAINER ;
2015-03-21 04:12:51 +00:00
Type [ point ] . name = " point " ;
2015-10-26 04:42:18 +00:00
Type [ point ] . elements . push_back ( new type_tree ( number ) ) ;
Type [ point ] . element_names . push_back ( " x " ) ;
Type [ point ] . elements . push_back ( new type_tree ( number ) ) ;
Type [ point ] . element_names . push_back ( " y " ) ;
2015-02-20 07:49:13 +00:00
2015-05-07 22:06:53 +00:00
//: Containers can be copied around with a single instruction just like
2015-05-13 17:03:26 +00:00
//: numbers, no matter how large they are.
2015-05-07 22:06:53 +00:00
2015-05-26 22:48:35 +00:00
//: Tests in this layer often explicitly setup memory before reading it as a
//: container. Don't do this in general. I'm tagging exceptions with /raw to
2015-10-07 05:15:45 +00:00
//: avoid errors.
2015-02-20 07:49:13 +00:00
: ( scenario copy_multiple_locations )
recipe main [
2015-07-28 21:33:22 +00:00
1 : number < - copy 34
2 : number < - copy 35
2015-05-26 22:48:35 +00:00
3 : point < - copy 1 : point / raw # unsafe
2015-02-20 07:49:13 +00:00
]
2015-03-24 06:59:59 +00:00
+ mem : storing 34 in location 3
+ mem : storing 35 in location 4
2015-02-20 08:03:47 +00:00
2015-10-01 20:43:32 +00:00
//: trying to copy to a differently-typed destination will fail
2015-08-07 20:01:49 +00:00
: ( scenario copy_checks_size )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-08-07 20:01:49 +00:00
recipe main [
2 : point < - copy 1 : number
]
2015-10-07 05:15:45 +00:00
+ error : main : can ' t copy 1 : number to 2 : point ; types don ' t match
2015-08-07 20:01:49 +00:00
2015-03-27 04:06:14 +00:00
: ( before " End Mu Types Initialization " )
2015-04-16 17:35:49 +00:00
// A more complex container, containing another container as one of its
// elements.
2015-07-04 16:40:50 +00:00
type_ordinal point_number = Type_ordinal [ " point-number " ] = Next_type_ordinal + + ;
2015-05-13 17:03:26 +00:00
Type [ point_number ] . size = 2 ;
2015-10-27 03:06:51 +00:00
Type [ point_number ] . kind = CONTAINER ;
2015-05-13 17:03:26 +00:00
Type [ point_number ] . name = " point-number " ;
2015-10-26 04:42:18 +00:00
Type [ point_number ] . elements . push_back ( new type_tree ( point ) ) ;
Type [ point_number ] . element_names . push_back ( " xy " ) ;
Type [ point_number ] . elements . push_back ( new type_tree ( number ) ) ;
Type [ point_number ] . element_names . push_back ( " z " ) ;
2015-03-27 04:06:14 +00:00
2015-04-24 17:19:03 +00:00
: ( scenario copy_handles_nested_container_elements )
2015-03-27 04:06:14 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
2015-05-26 22:48:35 +00:00
15 : point - number < - copy 12 : point - number / raw # unsafe
2015-03-27 04:06:14 +00:00
]
+ mem : storing 36 in location 17
2015-05-07 22:06:53 +00:00
//: Containers can be checked for equality with a single instruction just like
2015-05-13 17:03:26 +00:00
//: numbers, no matter how large they are.
2015-05-07 22:06:53 +00:00
: ( scenario compare_multiple_locations )
recipe main [
2015-07-28 21:33:22 +00:00
1 : number < - copy 34 # first
2 : number < - copy 35
3 : number < - copy 36
4 : number < - copy 34 # second
5 : number < - copy 35
6 : number < - copy 36
2015-05-26 22:48:35 +00:00
7 : boolean < - equal 1 : point - number / raw , 4 : point - number / raw # unsafe
2015-05-07 22:06:53 +00:00
]
+ mem : storing 1 in location 7
2015-08-09 19:26:31 +00:00
: ( scenario compare_multiple_locations_2 )
2015-05-07 22:06:53 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
1 : number < - copy 34 # first
2 : number < - copy 35
3 : number < - copy 36
4 : number < - copy 34 # second
5 : number < - copy 35
6 : number < - copy 37 # different
2015-05-26 22:48:35 +00:00
7 : boolean < - equal 1 : point - number / raw , 4 : point - number / raw # unsafe
2015-05-07 22:06:53 +00:00
]
+ mem : storing 0 in location 7
2015-10-26 04:42:18 +00:00
: ( before " End size_of(type) Cases " )
if ( type - > value = = 0 ) {
assert ( ! type - > left & & ! type - > right ) ;
return 1 ;
}
type_info t = Type [ type - > value ] ;
2015-10-27 03:06:51 +00:00
if ( t . kind = = CONTAINER ) {
2015-04-18 01:16:08 +00:00
// size of a container is the sum of the sizes of its elements
2015-05-17 09:22:41 +00:00
long long int result = 0 ;
for ( long long int i = 0 ; i < SIZE ( t . elements ) ; + + i ) {
2015-05-19 01:40:58 +00:00
// todo: strengthen assertion to disallow mutual type recursion
2015-10-26 04:42:18 +00:00
if ( t . elements . at ( i ) - > value = = type - > value ) {
2015-10-07 05:15:45 +00:00
raise_error < < " container " < < t . name < < " can't include itself as a member \n " < < end ( ) ;
2015-07-24 08:05:59 +00:00
return 0 ;
}
2015-10-06 02:49:43 +00:00
// End size_of(type) Container Cases
2015-05-07 22:06:53 +00:00
result + = size_of ( t . elements . at ( i ) ) ;
2015-03-27 04:06:14 +00:00
}
return result ;
}
2015-08-11 06:15:00 +00:00
: ( scenario stash_container )
recipe main [
1 : number < - copy 34 # first
2 : number < - copy 35
3 : number < - copy 36
2015-08-24 20:40:21 +00:00
stash [ foo : ] , 1 : point - number / raw
2015-08-11 06:15:00 +00:00
]
+ app : foo : 34 35 36
2015-04-18 06:24:52 +00:00
//:: To access elements of a container, use 'get'
2015-04-24 17:19:03 +00:00
: ( scenario get )
2015-03-27 04:06:14 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
12 : number < - copy 34
13 : number < - copy 35
2015-05-26 22:48:35 +00:00
15 : number < - get 12 : point / raw , 1 : offset # unsafe
2015-03-27 04:06:14 +00:00
]
+ mem : storing 35 in location 15
2015-04-17 17:31:17 +00:00
: ( before " End Primitive Recipe Declarations " )
GET ,
2015-02-20 08:03:47 +00:00
: ( before " End Primitive Recipe Numbers " )
2015-07-04 16:40:50 +00:00
Recipe_ordinal [ " get " ] = GET ;
2015-10-01 20:43:32 +00:00
: ( before " End Primitive Recipe Checks " )
2015-02-20 08:03:47 +00:00
case GET : {
2015-10-01 20:43:32 +00:00
if ( SIZE ( inst . ingredients ) ! = 2 ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " 'get' expects exactly 2 ingredients in ' " < < inst . to_string ( ) < < " ' \n " < < end ( ) ;
2015-10-01 20:43:32 +00:00
break ;
}
reagent base = inst . ingredients . at ( 0 ) ;
// Update GET base in Check
2015-10-27 03:06:51 +00:00
if ( ! base . type | | ! base . type - > value | | Type [ base . type - > value ] . kind ! = CONTAINER ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " first ingredient of 'get' should be a container, but got " < < inst . ingredients . at ( 0 ) . original_string < < ' \n ' < < end ( ) ;
2015-10-01 20:43:32 +00:00
break ;
}
2015-10-26 04:42:18 +00:00
type_ordinal base_type = base . type - > value ;
2015-10-01 20:43:32 +00:00
reagent offset = inst . ingredients . at ( 1 ) ;
if ( ! is_literal ( offset ) | | ! is_mu_scalar ( offset ) ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " second ingredient of 'get' should have type 'offset', but got " < < inst . ingredients . at ( 1 ) . original_string < < ' \n ' < < end ( ) ;
2015-07-24 08:05:59 +00:00
break ;
}
2015-10-02 07:28:08 +00:00
long long int offset_value = 0 ;
2015-11-02 02:24:17 +00:00
if ( is_integer ( offset . name ) ) // later layers permit non-integer offsets
2015-10-02 07:28:08 +00:00
offset_value = to_integer ( offset . name ) ;
2015-11-02 02:24:17 +00:00
else
2015-10-02 07:28:08 +00:00
offset_value = offset . value ;
2015-11-02 02:24:17 +00:00
if ( offset_value < 0 | | offset_value > = SIZE ( Type [ base_type ] . elements ) ) {
raise_error < < maybe ( Recipe [ r ] . name ) < < " invalid offset " < < offset_value < < " for " < < Type [ base_type ] . name < < ' \n ' < < end ( ) ;
break ;
2015-10-02 07:28:08 +00:00
}
reagent product = inst . products . at ( 0 ) ;
// Update GET product in Check
reagent element ;
2015-10-26 04:42:18 +00:00
element . type = new type_tree ( * Type [ base_type ] . elements . at ( offset_value ) ) ;
2015-10-02 07:28:08 +00:00
if ( ! types_match ( product , element ) ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " 'get' " < < offset . original_string < < " ( " < < offset_value < < " ) on " < < Type [ base_type ] . name < < " can't be saved in " < < product . original_string < < " ; type should be " < < dump_types ( element ) < < ' \n ' < < end ( ) ;
2015-10-06 00:02:32 +00:00
break ;
2015-10-02 07:28:08 +00:00
}
2015-10-01 20:43:32 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
case GET : {
2015-05-07 22:06:53 +00:00
reagent base = current_instruction ( ) . ingredients . at ( 0 ) ;
2015-10-01 20:43:32 +00:00
// Update GET base in Run
2015-05-17 09:22:41 +00:00
long long int base_address = base . value ;
2015-08-01 00:06:38 +00:00
if ( base_address = = 0 ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( current_recipe_name ( ) ) < < " tried to access location 0 in ' " < < current_instruction ( ) . to_string ( ) < < " ' \n " < < end ( ) ;
2015-08-01 00:06:38 +00:00
break ;
}
2015-10-26 04:42:18 +00:00
type_ordinal base_type = base . type - > value ;
2015-05-17 09:22:41 +00:00
long long int offset = ingredients . at ( 1 ) . at ( 0 ) ;
2015-10-02 06:44:17 +00:00
if ( offset < 0 | | offset > = SIZE ( Type [ base_type ] . elements ) ) break ; // copied from Check above
2015-05-17 09:22:41 +00:00
long long int src = base_address ;
for ( long long int i = 0 ; i < offset ; + + i ) {
2015-10-06 03:11:31 +00:00
// End GET field Cases
2015-05-07 22:06:53 +00:00
src + = size_of ( Type [ base_type ] . elements . at ( i ) ) ;
2015-02-22 08:15:14 +00:00
}
2015-10-29 19:09:23 +00:00
trace ( 9998 , " run " ) < < " address to copy is " < < src < < end ( ) ;
2015-10-26 04:42:18 +00:00
type_ordinal src_type = Type [ base_type ] . elements . at ( offset ) - > value ;
2015-10-29 19:09:23 +00:00
trace ( 9998 , " run " ) < < " its type is " < < Type [ src_type ] . name < < end ( ) ;
2015-03-26 02:06:32 +00:00
reagent tmp ;
2015-05-13 00:00:56 +00:00
tmp . set_value ( src ) ;
2015-10-26 04:42:18 +00:00
tmp . type = new type_tree ( src_type ) ;
2015-08-03 05:18:19 +00:00
products . push_back ( read_memory ( tmp ) ) ;
2015-02-20 08:03:47 +00:00
break ;
}
2015-04-24 17:19:03 +00:00
: ( scenario get_handles_nested_container_elements )
2015-02-22 08:15:14 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
2015-05-26 22:48:35 +00:00
15 : number < - get 12 : point - number / raw , 1 : offset # unsafe
2015-02-22 08:15:14 +00:00
]
2015-03-24 06:59:59 +00:00
+ mem : storing 36 in location 15
2015-02-22 08:15:14 +00:00
2015-07-17 21:30:17 +00:00
: ( scenario get_out_of_bounds )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-07-17 21:30:17 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
2015-07-17 21:30:17 +00:00
get 12 : point - number / raw , 2 : offset # point - number occupies 3 locations but has only 2 fields ; out of bounds
]
2015-10-07 05:15:45 +00:00
+ error : main : invalid offset 2 for point - number
2015-07-17 21:30:17 +00:00
2015-08-09 19:26:31 +00:00
: ( scenario get_out_of_bounds_2 )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-07-17 21:30:17 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
2015-07-17 21:30:17 +00:00
get 12 : point - number / raw , - 1 : offset
]
2015-10-07 05:15:45 +00:00
+ error : main : invalid offset - 1 for point - number
2015-07-17 21:30:17 +00:00
2015-10-02 07:28:08 +00:00
: ( scenario get_product_type_mismatch )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-10-02 07:28:08 +00:00
recipe main [
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
15 : address : number < - get 12 : point - number / raw , 1 : offset
]
2015-10-07 05:15:45 +00:00
+ error : main : ' get ' 1 : offset ( 1 ) on point - number can ' t be saved in 15 : address : number ; type should be number
2015-10-02 07:28:08 +00:00
2015-10-26 04:42:18 +00:00
//:: To write to elements of containers, you need their address.
: ( scenario get_address )
recipe main [
12 : number < - copy 34
13 : number < - copy 35
15 : address : number < - get - address 12 : point / raw , 1 : offset # unsafe
]
+ mem : storing 13 in location 15
2015-04-17 17:31:17 +00:00
: ( before " End Primitive Recipe Declarations " )
GET_ADDRESS ,
2015-02-21 04:25:45 +00:00
: ( before " End Primitive Recipe Numbers " )
2015-07-04 16:40:50 +00:00
Recipe_ordinal [ " get-address " ] = GET_ADDRESS ;
2015-10-01 20:43:32 +00:00
: ( before " End Primitive Recipe Checks " )
2015-02-21 04:25:45 +00:00
case GET_ADDRESS : {
2015-10-01 20:43:32 +00:00
if ( SIZE ( inst . ingredients ) ! = 2 ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " 'get-address' expects exactly 2 ingredients in ' " < < inst . to_string ( ) < < " ' \n " < < end ( ) ;
2015-08-01 00:06:38 +00:00
break ;
}
2015-10-01 20:43:32 +00:00
reagent base = inst . ingredients . at ( 0 ) ;
// Update GET_ADDRESS base in Check
2015-10-27 03:06:51 +00:00
if ( ! base . type | | Type [ base . type - > value ] . kind ! = CONTAINER ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " first ingredient of 'get-address' should be a container, but got " < < inst . ingredients . at ( 0 ) . original_string < < ' \n ' < < end ( ) ;
2015-07-24 08:09:35 +00:00
break ;
}
2015-10-26 04:42:18 +00:00
type_ordinal base_type = base . type - > value ;
2015-10-01 20:43:32 +00:00
reagent offset = inst . ingredients . at ( 1 ) ;
if ( ! is_literal ( offset ) | | ! is_mu_scalar ( offset ) ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " second ingredient of 'get' should have type 'offset', but got " < < inst . ingredients . at ( 1 ) . original_string < < ' \n ' < < end ( ) ;
2015-07-24 08:09:35 +00:00
break ;
}
2015-10-05 23:43:21 +00:00
long long int offset_value = 0 ;
2015-10-01 20:43:32 +00:00
if ( is_integer ( offset . name ) ) { // later layers permit non-integer offsets
2015-10-05 23:43:21 +00:00
offset_value = to_integer ( offset . name ) ;
2015-10-01 20:43:32 +00:00
if ( offset_value < 0 | | offset_value > = SIZE ( Type [ base_type ] . elements ) ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " invalid offset " < < offset_value < < " for " < < Type [ base_type ] . name < < ' \n ' < < end ( ) ;
2015-10-01 20:43:32 +00:00
break ;
}
}
2015-10-05 23:43:21 +00:00
else {
offset_value = offset . value ;
}
reagent product = inst . products . at ( 0 ) ;
2015-10-06 00:07:11 +00:00
// Update GET_ADDRESS product in Check
2015-10-05 23:43:21 +00:00
reagent element ;
2015-10-26 04:42:18 +00:00
// same type as for GET..
element . type = new type_tree ( * Type [ base_type ] . elements . at ( offset_value ) ) ;
// ..except for an address at the start
element . type = new type_tree ( Type_ordinal [ " address " ] , element . type ) ;
2015-10-05 23:43:21 +00:00
if ( ! types_match ( product , element ) ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( Recipe [ r ] . name ) < < " 'get-address' " < < offset . original_string < < " ( " < < offset_value < < " ) on " < < Type [ base_type ] . name < < " can't be saved in " < < product . original_string < < " ; type should be " < < dump_types ( element ) < < ' \n ' < < end ( ) ;
2015-10-06 00:02:32 +00:00
break ;
2015-10-05 23:43:21 +00:00
}
2015-10-01 20:43:32 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
case GET_ADDRESS : {
reagent base = current_instruction ( ) . ingredients . at ( 0 ) ;
// Update GET_ADDRESS base in Run
long long int base_address = base . value ;
if ( base_address = = 0 ) {
2015-10-07 05:15:45 +00:00
raise_error < < maybe ( current_recipe_name ( ) ) < < " tried to access location 0 in ' " < < current_instruction ( ) . to_string ( ) < < " ' \n " < < end ( ) ;
2015-07-17 21:30:17 +00:00
break ;
}
2015-10-26 04:42:18 +00:00
type_ordinal base_type = base . type - > value ;
2015-10-01 20:43:32 +00:00
long long int offset = ingredients . at ( 1 ) . at ( 0 ) ;
2015-10-02 06:44:17 +00:00
if ( offset < 0 | | offset > = SIZE ( Type [ base_type ] . elements ) ) break ; // copied from Check above
2015-05-17 09:22:41 +00:00
long long int result = base_address ;
for ( long long int i = 0 ; i < offset ; + + i ) {
2015-10-06 03:11:31 +00:00
// End GET_ADDRESS field Cases
2015-05-07 22:06:53 +00:00
result + = size_of ( Type [ base_type ] . elements . at ( i ) ) ;
2015-02-22 08:44:30 +00:00
}
2015-10-29 19:09:23 +00:00
trace ( 9998 , " run " ) < < " address to copy is " < < result < < end ( ) ;
2015-08-03 05:18:19 +00:00
products . resize ( 1 ) ;
2015-05-13 00:00:56 +00:00
products . at ( 0 ) . push_back ( result ) ;
2015-02-21 04:25:45 +00:00
break ;
}
2015-05-14 17:30:01 +00:00
2015-07-17 21:30:17 +00:00
: ( scenario get_address_out_of_bounds )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-07-17 21:30:17 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
2015-07-17 21:30:17 +00:00
get - address 12 : point - number / raw , 2 : offset # point - number occupies 3 locations but has only 2 fields ; out of bounds
]
2015-10-07 05:15:45 +00:00
+ error : main : invalid offset 2 for point - number
2015-07-17 21:30:17 +00:00
2015-08-09 19:26:31 +00:00
: ( scenario get_address_out_of_bounds_2 )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-07-17 21:30:17 +00:00
recipe main [
2015-07-28 21:33:22 +00:00
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
2015-07-17 21:30:17 +00:00
get - address 12 : point - number / raw , - 1 : offset
]
2015-10-07 05:15:45 +00:00
+ error : main : invalid offset - 1 for point - number
2015-07-17 21:30:17 +00:00
2015-10-05 23:43:21 +00:00
: ( scenario get_address_product_type_mismatch )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-10-05 23:43:21 +00:00
recipe main [
12 : number < - copy 34
13 : number < - copy 35
14 : number < - copy 36
15 : number < - get - address 12 : point - number / raw , 1 : offset
]
2015-10-27 23:34:58 +00:00
+ error : main : ' get - address ' 1 : offset ( 1 ) on point - number can ' t be saved in 15 : number ; type should be < address : < number : < > > >
2015-10-05 23:43:21 +00:00
2015-05-14 17:30:01 +00:00
//:: Allow containers to be defined in mu code.
: ( scenarios load )
: ( scenario container )
container foo [
x : number
y : number
]
2015-10-29 18:56:10 +00:00
+ parse : - - - defining container foo
2015-10-30 17:08:43 +00:00
+ parse : element name : x
+ parse : type : 1
+ parse : element name : y
+ parse : type : 1
2015-05-14 17:30:01 +00:00
2015-05-18 23:09:09 +00:00
: ( scenario container_use_before_definition )
container foo [
x : number
y : bar
]
container bar [
x : number
y : number
]
2015-10-29 18:56:10 +00:00
+ parse : - - - defining container foo
2015-05-18 23:09:09 +00:00
+ parse : type number : 1000
+ parse : element name : x
+ parse : type : 1
+ parse : element name : y
+ parse : type : 1001
2015-10-29 18:56:10 +00:00
+ parse : - - - defining container bar
2015-05-18 23:09:09 +00:00
+ parse : type number : 1001
2015-05-14 17:30:01 +00:00
: ( before " End Command Handlers " )
else if ( command = = " container " ) {
2015-10-27 03:06:51 +00:00
insert_container ( command , CONTAINER , in ) ;
2015-05-14 17:30:01 +00:00
}
: ( code )
void insert_container ( const string & command , kind_of_type kind , istream & in ) {
skip_whitespace ( in ) ;
string name = next_word ( in ) ;
2015-10-30 20:00:16 +00:00
// End container Name Refinements
2015-10-29 18:56:10 +00:00
trace ( 9991 , " parse " ) < < " --- defining " < < command < < ' ' < < name < < end ( ) ;
2015-07-04 16:40:50 +00:00
if ( Type_ordinal . find ( name ) = = Type_ordinal . end ( )
| | Type_ordinal [ name ] = = 0 ) {
Type_ordinal [ name ] = Next_type_ordinal + + ;
2015-05-14 17:30:01 +00:00
}
2015-10-29 18:56:10 +00:00
trace ( 9999 , " parse " ) < < " type number: " < < Type_ordinal [ name ] < < end ( ) ;
2015-05-14 17:30:01 +00:00
skip_bracket ( in , " 'container' must begin with '[' " ) ;
2015-10-06 02:49:43 +00:00
type_info & info = Type [ Type_ordinal [ name ] ] ;
2015-07-04 16:40:50 +00:00
recently_added_types . push_back ( Type_ordinal [ name ] ) ;
2015-10-06 02:49:43 +00:00
info . name = name ;
info . kind = kind ;
2015-05-14 17:30:01 +00:00
while ( ! in . eof ( ) ) {
skip_whitespace_and_comments ( in ) ;
string element = next_word ( in ) ;
if ( element = = " ] " ) break ;
2015-10-06 02:49:43 +00:00
// End insert_container Special Definitions(element)
2015-05-14 17:30:01 +00:00
istringstream inner ( element ) ;
2015-10-06 02:49:43 +00:00
info . element_names . push_back ( slurp_until ( inner , ' : ' ) ) ;
2015-10-29 18:56:10 +00:00
trace ( 9993 , " parse " ) < < " element name: " < < info . element_names . back ( ) < < end ( ) ;
2015-10-26 04:42:18 +00:00
type_tree * new_type = NULL ;
2015-10-30 17:10:35 +00:00
for ( type_tree * * curr_type = & new_type ; ! inner . eof ( ) ; curr_type = & ( * curr_type ) - > right ) {
2015-05-14 17:30:01 +00:00
string type_name = slurp_until ( inner , ' : ' ) ;
2015-10-06 02:49:43 +00:00
// End insert_container Special Uses(type_name)
2015-08-14 23:58:59 +00:00
if ( Type_ordinal . find ( type_name ) = = Type_ordinal . end ( )
// types can contain integers, like for array sizes
& & ! is_integer ( type_name ) ) {
2015-07-04 16:40:50 +00:00
Type_ordinal [ type_name ] = Next_type_ordinal + + ;
2015-05-19 01:40:58 +00:00
}
2015-10-26 04:42:18 +00:00
* curr_type = new type_tree ( Type_ordinal [ type_name ] ) ;
2015-10-29 18:56:10 +00:00
trace ( 9993 , " parse " ) < < " type: " < < Type_ordinal [ type_name ] < < end ( ) ;
2015-05-14 17:30:01 +00:00
}
2015-10-26 04:42:18 +00:00
info . elements . push_back ( new_type ) ;
2015-05-14 17:30:01 +00:00
}
2015-10-06 02:49:43 +00:00
assert ( SIZE ( info . elements ) = = SIZE ( info . element_names ) ) ;
info . size = SIZE ( info . elements ) ;
2015-05-14 17:30:01 +00:00
}
2015-10-06 01:49:21 +00:00
void skip_bracket ( istream & in , string message ) {
skip_whitespace_and_comments ( in ) ;
if ( in . get ( ) ! = ' [ ' )
2015-10-07 05:15:45 +00:00
raise_error < < message < < ' \n ' < < end ( ) ;
2015-10-06 01:49:21 +00:00
}
2015-08-05 02:28:45 +00:00
: ( scenarios run )
: ( scenario container_define_twice )
container foo [
x : number
]
container foo [
y : number
]
recipe main [
1 : number < - copy 34
2 : number < - copy 35
2015-08-07 02:02:32 +00:00
3 : number < - get 1 : foo , 0 : offset
4 : number < - get 1 : foo , 1 : offset
2015-08-05 02:28:45 +00:00
]
+ mem : storing 34 in location 3
+ mem : storing 35 in location 4
2015-05-14 17:30:01 +00:00
//: ensure types created in one scenario don't leak outside it.
: ( before " End Globals " )
2015-07-04 16:40:50 +00:00
vector < type_ordinal > recently_added_types ;
2015-05-14 17:30:01 +00:00
: ( before " End load_permanently " ) //: for non-tests
recently_added_types . clear ( ) ;
: ( before " End Setup " ) //: for tests
2015-05-17 09:22:41 +00:00
for ( long long int i = 0 ; i < SIZE ( recently_added_types ) ; + + i ) {
2015-07-04 16:40:50 +00:00
Type_ordinal . erase ( Type [ recently_added_types . at ( i ) ] . name ) ;
2015-10-26 04:42:18 +00:00
// todo: why do I explicitly need to provide this?
for ( long long int j = 0 ; j < SIZE ( Type . at ( recently_added_types . at ( i ) ) . elements ) ; + + j ) {
delete Type . at ( recently_added_types . at ( i ) ) . elements . at ( j ) ;
}
2015-05-14 17:30:01 +00:00
Type . erase ( recently_added_types . at ( i ) ) ;
}
recently_added_types . clear ( ) ;
2015-05-19 01:40:58 +00:00
// delete recent type references
2015-07-04 16:40:50 +00:00
// can't rely on recently_added_types to cleanup Type_ordinal, because of deliberately misbehaving tests with references to undefined types
map < string , type_ordinal > : : iterator p = Type_ordinal . begin ( ) ;
while ( p ! = Type_ordinal . end ( ) ) {
2015-05-19 01:40:58 +00:00
// save current item
string name = p - > first ;
2015-07-04 16:40:50 +00:00
type_ordinal t = p - > second ;
2015-05-19 01:40:58 +00:00
// increment iterator
+ + p ;
// now delete current item if necessary
if ( t > = 1000 ) {
2015-07-04 16:40:50 +00:00
Type_ordinal . erase ( name ) ;
2015-05-19 01:40:58 +00:00
}
}
2015-05-14 17:30:01 +00:00
//: lastly, ensure scenarios are consistent by always starting them at the
//: same type number.
2015-07-04 16:40:50 +00:00
Next_type_ordinal = 1000 ;
2015-05-14 17:30:01 +00:00
: ( before " End Test Run Initialization " )
2015-07-04 16:40:50 +00:00
assert ( Next_type_ordinal < 1000 ) ;
2015-05-14 17:30:01 +00:00
: ( before " End Setup " )
2015-07-04 16:40:50 +00:00
Next_type_ordinal = 1000 ;
2015-05-14 17:30:01 +00:00
2015-10-07 05:15:45 +00:00
//:: Allow container definitions anywhere in the codebase, but complain if you
//:: can't find a definition at the end.
2015-05-19 01:40:58 +00:00
2015-10-07 05:15:45 +00:00
: ( scenario run_complains_on_unknown_types )
% Hide_errors = true ;
2015-05-19 01:40:58 +00:00
recipe main [
# integer is not a type
2015-07-28 21:33:22 +00:00
1 : integer < - copy 0
2015-05-19 01:40:58 +00:00
]
2015-10-26 04:42:18 +00:00
+ error : main : unknown type in ' 1 : integer < - copy 0 '
2015-05-19 01:40:58 +00:00
: ( scenario run_allows_type_definition_after_use )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-05-19 01:40:58 +00:00
recipe main [
2015-09-30 07:07:33 +00:00
1 : bar < - copy 0 / raw
2015-05-19 01:40:58 +00:00
]
container bar [
x : number
]
2015-10-07 05:15:45 +00:00
- error : unknown type : bar
$ error : 0
2015-05-19 01:40:58 +00:00
: ( after " int main " )
Transform . push_back ( check_invalid_types ) ;
: ( code )
2015-07-04 16:40:50 +00:00
void check_invalid_types ( const recipe_ordinal r ) {
2015-05-19 01:40:58 +00:00
for ( long long int index = 0 ; index < SIZE ( Recipe [ r ] . steps ) ; + + index ) {
const instruction & inst = Recipe [ r ] . steps . at ( index ) ;
for ( long long int i = 0 ; i < SIZE ( inst . ingredients ) ; + + i ) {
2015-10-26 04:42:18 +00:00
check_invalid_types ( inst . ingredients . at ( i ) . type , maybe ( Recipe [ r ] . name ) , " ' " + inst . to_string ( ) + " ' " ) ;
2015-05-19 01:40:58 +00:00
}
for ( long long int i = 0 ; i < SIZE ( inst . products ) ; + + i ) {
2015-10-26 04:42:18 +00:00
check_invalid_types ( inst . products . at ( i ) . type , maybe ( Recipe [ r ] . name ) , " ' " + inst . to_string ( ) + " ' " ) ;
2015-05-19 01:40:58 +00:00
}
}
}
2015-10-26 04:42:18 +00:00
void check_invalid_types ( const type_tree * type , const string & block , const string & name ) {
if ( ! type ) return ; // will throw a more precise error elsewhere
2015-10-30 20:00:16 +00:00
// End Container Type Checks
2015-10-26 04:42:18 +00:00
if ( type - > value & & Type . find ( type - > value ) = = Type . end ( ) ) {
raise_error < < block < < " unknown type in " < < name < < ' \n ' < < end ( ) ;
2015-05-19 01:40:58 +00:00
}
2015-10-26 04:42:18 +00:00
if ( type - > left ) check_invalid_types ( type - > left , block , name ) ;
if ( type - > right ) check_invalid_types ( type - > right , block , name ) ;
2015-05-19 01:40:58 +00:00
}
: ( scenario container_unknown_field )
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2015-05-19 01:40:58 +00:00
container foo [
x : number
y : bar
]
2015-10-26 04:42:18 +00:00
+ error : foo : unknown type in y
2015-05-19 01:40:58 +00:00
2015-05-28 18:28:15 +00:00
: ( scenario read_container_with_bracket_in_comment )
container foo [
x : number
# ']' in comment
y : number
]
2015-10-29 18:56:10 +00:00
+ parse : - - - defining container foo
2015-10-30 17:08:43 +00:00
+ parse : element name : x
+ parse : type : 1
+ parse : element name : y
+ parse : type : 1
2015-05-28 18:28:15 +00:00
2015-09-05 18:23:20 +00:00
: ( before " End Transform " )
2015-05-19 01:40:58 +00:00
check_container_field_types ( ) ;
: ( code )
void check_container_field_types ( ) {
2015-07-04 16:40:50 +00:00
for ( map < type_ordinal , type_info > : : iterator p = Type . begin ( ) ; p ! = Type . end ( ) ; + + p ) {
2015-05-19 01:40:58 +00:00
const type_info & info = p - > second ;
for ( long long int i = 0 ; i < SIZE ( info . elements ) ; + + i ) {
2015-10-26 04:42:18 +00:00
check_invalid_types ( info . elements . at ( i ) , maybe ( info . name ) , info . element_names . at ( i ) ) ;
2015-05-19 01:40:58 +00:00
}
}
}
2015-06-23 19:05:18 +00:00
//:: Construct types out of their constituent fields. Doesn't currently do
//:: type-checking but *does* match sizes.
: ( before " End Primitive Recipe Declarations " )
MERGE ,
: ( before " End Primitive Recipe Numbers " )
2015-07-04 16:40:50 +00:00
Recipe_ordinal [ " merge " ] = MERGE ;
2015-10-02 06:44:17 +00:00
: ( before " End Primitive Recipe Checks " )
case MERGE : {
break ;
}
2015-06-23 19:05:18 +00:00
: ( before " End Primitive Recipe Implementations " )
case MERGE : {
products . resize ( 1 ) ;
for ( long long int i = 0 ; i < SIZE ( ingredients ) ; + + i )
for ( long long int j = 0 ; j < SIZE ( ingredients . at ( i ) ) ; + + j )
products . at ( 0 ) . push_back ( ingredients . at ( i ) . at ( j ) ) ;
break ;
}
: ( scenario merge )
container foo [
x : number
y : number
]
recipe main [
2015-07-28 21:33:22 +00:00
1 : foo < - merge 3 , 4
2015-06-23 19:05:18 +00:00
]
+ mem : storing 3 in location 1
+ mem : storing 4 in location 2