2015-04-15 02:06:57 +00:00
//: Writing to a literal (not computed) address of 0 in a recipe chains two
//: spaces together. When a variable has a property of /space:1, it looks up
//: the variable in the chained/surrounding space. /space:2 looks up the
//: surrounding space of the surrounding space, etc.
2015-04-17 18:22:59 +00:00
2015-04-24 17:19:03 +00:00
: ( scenario closure )
2016-03-08 09:30:14 +00:00
def main [
2016-04-24 18:54:30 +00:00
default - space : address : array : location < - new location : type , 30
1 : address : array : location / names : new - counter < - new - counter
2 : number / raw < - increment - counter 1 : address : array : location / names : new - counter
3 : number / raw < - increment - counter 1 : address : array : location / names : new - counter
2015-04-15 02:06:57 +00:00
]
2016-03-08 09:30:14 +00:00
def new - counter [
2016-04-24 18:54:30 +00:00
default - space : address : array : location < - new location : type , 30
2015-07-28 21:33:22 +00:00
x : number < - copy 23
y : number < - copy 3 # variable that will be incremented
2016-04-24 18:54:30 +00:00
return default - space : address : array : location
2015-04-15 02:06:57 +00:00
]
2016-03-08 09:30:14 +00:00
def increment - counter [
2016-04-24 18:54:30 +00:00
default - space : address : array : location < - new location : type , 30
0 : address : array : location / names : new - counter < - next - ingredient # outer space must be created by ' new - counter ' above
2015-07-28 21:33:22 +00:00
y : number / space : 1 < - add y : number / space : 1 , 1 # increment
y : number < - copy 234 # dummy
2016-03-08 09:30:14 +00:00
return y : number / space : 1
2015-04-15 02:06:57 +00:00
]
2015-10-29 19:04:30 +00:00
+ name : lexically surrounding space for recipe increment - counter comes from new - counter
2015-04-15 02:06:57 +00:00
+ mem : storing 5 in location 3
//: To make this work, compute the recipe that provides names for the
2015-11-05 07:44:46 +00:00
//: surrounding space of each recipe.
2015-04-17 18:22:59 +00:00
2015-04-15 02:06:57 +00:00
: ( before " End Globals " )
2015-07-04 16:40:50 +00:00
map < recipe_ordinal , recipe_ordinal > Surrounding_space ;
2015-04-15 02:06:57 +00:00
2015-11-05 07:44:46 +00:00
: ( before " Transform.push_back(transform_names) " )
2015-11-07 01:29:52 +00:00
Transform . push_back ( collect_surrounding_spaces ) ; // idempotent
2015-04-15 02:06:57 +00:00
: ( code )
2015-07-04 16:40:50 +00:00
void collect_surrounding_spaces ( const recipe_ordinal r ) {
2015-11-06 19:06:58 +00:00
trace ( 9991 , " transform " ) < < " --- collect surrounding spaces for recipe " < < get ( Recipe , r ) . name < < end ( ) ;
2015-11-07 01:03:02 +00:00
//? cerr << "--- collect surrounding spaces for recipe " << get(Recipe, r).name << '\n';
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( get ( Recipe , r ) . steps ) ; + + i ) {
2015-11-06 19:06:58 +00:00
const instruction & inst = get ( Recipe , r ) . steps . at ( i ) ;
2015-04-15 02:06:57 +00:00
if ( inst . is_label ) continue ;
2016-03-14 03:26:47 +00:00
for ( int j = 0 ; j < SIZE ( inst . products ) ; + + j ) {
2015-06-17 19:39:09 +00:00
if ( is_literal ( inst . products . at ( j ) ) ) continue ;
2015-05-07 22:06:53 +00:00
if ( inst . products . at ( j ) . name ! = " 0 " ) continue ;
2015-10-26 04:42:18 +00:00
type_tree * type = inst . products . at ( j ) . type ;
if ( ! type
2015-11-06 19:06:58 +00:00
| | type - > value ! = get ( Type_ordinal , " address " )
2015-10-26 04:42:18 +00:00
| | ! type - > right
2016-04-24 18:54:30 +00:00
| | type - > right - > value ! = get ( Type_ordinal , " array " )
2015-10-26 04:42:18 +00:00
| | ! type - > right - > right
2016-04-24 18:54:30 +00:00
| | type - > right - > right - > value ! = get ( Type_ordinal , " location " )
| | type - > right - > right - > right ) {
2016-05-21 05:09:06 +00:00
raise < < " slot 0 should always have type address:array:location, but is ' " < < to_string ( inst . products . at ( j ) ) < < " ' \n " < < end ( ) ;
2015-04-15 02:06:57 +00:00
continue ;
}
2015-10-27 03:00:38 +00:00
string_tree * s = property ( inst . products . at ( j ) , " names " ) ;
if ( ! s ) {
2016-05-21 05:09:06 +00:00
raise < < " slot 0 requires a /names property in recipe ' " < < get ( Recipe , r ) . name < < " ' \n " < < end ( ) ;
2015-07-25 07:02:20 +00:00
continue ;
}
2016-05-21 05:09:06 +00:00
if ( s - > right ) raise < < " slot 0 should have a single value in /names, but got ' " < < to_string ( inst . products . at ( j ) ) < < " ' \n " < < end ( ) ;
2015-10-27 03:00:38 +00:00
const string & surrounding_recipe_name = s - > value ;
2016-02-06 17:29:36 +00:00
if ( surrounding_recipe_name . empty ( ) ) {
2016-05-21 05:09:06 +00:00
raise < < " slot 0 doesn't initialize its /names property in recipe ' " < < get ( Recipe , r ) . name < < " ' \n " < < end ( ) ;
2016-02-06 17:29:36 +00:00
continue ;
}
2015-11-06 21:22:16 +00:00
if ( contains_key ( Surrounding_space , r )
2016-02-21 05:58:48 +00:00
& & get ( Surrounding_space , r ) ! = get ( Recipe_ordinal , surrounding_recipe_name ) ) {
2016-05-21 05:09:06 +00:00
raise < < " recipe ' " < < get ( Recipe , r ) . name < < " ' can have only one 'surrounding' recipe but has ' " < < get ( Recipe , get ( Surrounding_space , r ) ) . name < < " ' and ' " < < surrounding_recipe_name < < " ' \n " < < end ( ) ;
2015-04-15 02:06:57 +00:00
continue ;
}
2015-11-06 19:06:58 +00:00
trace ( 9993 , " name " ) < < " lexically surrounding space for recipe " < < get ( Recipe , r ) . name < < " comes from " < < surrounding_recipe_name < < end ( ) ;
2015-11-07 01:03:02 +00:00
if ( ! contains_key ( Recipe_ordinal , surrounding_recipe_name ) ) {
2016-05-21 05:09:06 +00:00
raise < < " can't find recipe providing surrounding space for ' " < < get ( Recipe , r ) . name < < " '; looking for ' " < < surrounding_recipe_name < < " ' \n " < < end ( ) ;
2015-11-07 01:03:02 +00:00
continue ;
}
2016-02-21 05:58:48 +00:00
put ( Surrounding_space , r , get ( Recipe_ordinal , surrounding_recipe_name ) ) ;
2015-04-15 02:06:57 +00:00
}
}
}
//: Once surrounding spaces are available, transform_names uses them to handle
//: /space properties.
2016-03-14 03:26:47 +00:00
: ( replace { } " int lookup_name(const reagent& r, const recipe_ordinal default_recipe) " )
int lookup_name ( const reagent & x , const recipe_ordinal default_recipe ) {
2015-04-15 02:06:57 +00:00
if ( ! has_property ( x , " space " ) ) {
2016-02-26 21:04:55 +00:00
if ( Name [ default_recipe ] . empty ( ) ) raise < < " name not found: " < < x . name < < ' \n ' < < end ( ) ;
2015-04-15 02:06:57 +00:00
return Name [ default_recipe ] [ x . name ] ;
}
2015-10-27 03:00:38 +00:00
string_tree * p = property ( x , " space " ) ;
2016-02-26 21:04:55 +00:00
if ( ! p | | p - > right ) raise < < " /space property should have exactly one (non-negative integer) value \n " < < end ( ) ;
2016-03-14 03:26:47 +00:00
int n = to_integer ( p - > value ) ;
2015-04-15 02:06:57 +00:00
assert ( n > = 0 ) ;
2015-07-04 16:40:50 +00:00
recipe_ordinal surrounding_recipe = lookup_surrounding_recipe ( default_recipe , n ) ;
2016-02-27 05:50:54 +00:00
if ( surrounding_recipe = = - 1 ) return - 1 ;
2015-07-04 16:40:50 +00:00
set < recipe_ordinal > done ;
vector < recipe_ordinal > path ;
2015-04-15 02:06:57 +00:00
return lookup_name ( x , surrounding_recipe , done , path ) ;
}
// If the recipe we need to lookup this name in doesn't have names done yet,
// recursively call transform_names on it.
2016-03-14 03:26:47 +00:00
int lookup_name ( const reagent & x , const recipe_ordinal r , set < recipe_ordinal > & done , vector < recipe_ordinal > & path ) {
2015-04-15 02:06:57 +00:00
if ( ! Name [ r ] . empty ( ) ) return Name [ r ] [ x . name ] ;
2015-11-06 21:22:16 +00:00
if ( contains_key ( done , r ) ) {
2016-05-21 05:09:06 +00:00
raise < < " can't compute address of ' " < < to_string ( x ) < < " ' because \n " < < end ( ) ;
2016-03-14 03:26:47 +00:00
for ( int i = 1 ; i < SIZE ( path ) ; + + i ) {
2016-02-26 21:04:55 +00:00
raise < < path . at ( i - 1 ) < < " requires computing names of " < < path . at ( i ) < < ' \n ' < < end ( ) ;
2015-04-15 02:06:57 +00:00
}
2016-02-26 21:04:55 +00:00
raise < < path . at ( SIZE ( path ) - 1 ) < < " requires computing names of " < < r < < " ..ad infinitum \n " < < end ( ) ;
2016-02-27 05:50:54 +00:00
return - 1 ;
2015-04-15 02:06:57 +00:00
}
done . insert ( r ) ;
path . push_back ( r ) ;
transform_names ( r ) ; // Not passing 'done' through. Might this somehow cause an infinite loop?
assert ( ! Name [ r ] . empty ( ) ) ;
return Name [ r ] [ x . name ] ;
}
2016-03-14 03:26:47 +00:00
recipe_ordinal lookup_surrounding_recipe ( const recipe_ordinal r , int n ) {
2015-04-15 02:06:57 +00:00
if ( n = = 0 ) return r ;
2015-11-06 21:22:16 +00:00
if ( ! contains_key ( Surrounding_space , r ) ) {
2016-05-21 05:09:06 +00:00
raise < < " don't know surrounding recipe of ' " < < get ( Recipe , r ) . name < < " ' \n " < < end ( ) ;
2016-02-27 05:50:54 +00:00
return - 1 ;
2015-04-15 02:06:57 +00:00
}
2016-02-21 05:58:48 +00:00
assert ( contains_key ( Surrounding_space , r ) ) ;
return lookup_surrounding_recipe ( get ( Surrounding_space , r ) , n - 1 ) ;
2015-04-15 02:06:57 +00:00
}
2015-10-07 05:15:45 +00:00
//: weaken use-before-set detection just a tad
2016-03-14 03:26:47 +00:00
: ( replace { } " bool already_transformed(const reagent& r, const map<string, int>& names) " )
bool already_transformed ( const reagent & r , const map < string , int > & names ) {
2015-04-15 02:06:57 +00:00
if ( has_property ( r , " space " ) ) {
2015-10-27 03:00:38 +00:00
string_tree * p = property ( r , " space " ) ;
if ( ! p | | p - > right ) {
2016-05-21 05:09:06 +00:00
raise < < " /space property should have exactly one (non-negative integer) value in ' " < < r . original_string < < " ' \n " < < end ( ) ;
2015-07-25 21:19:28 +00:00
return false ;
}
2015-10-27 03:00:38 +00:00
if ( p - > value ! = " 0 " ) return true ;
2015-04-15 02:06:57 +00:00
}
2015-11-06 21:22:16 +00:00
return contains_key ( names , r . name ) ;
2015-04-15 02:06:57 +00:00
}
2016-02-27 05:50:54 +00:00
: ( scenario missing_surrounding_space )
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def f [
2016-02-27 05:50:54 +00:00
local - scope
x : number / space : 1 < - copy 34
]
2016-05-21 05:09:06 +00:00
+ error : don ' t know surrounding recipe of ' f '
+ error : f : can ' t find a place to store ' x '
2016-05-19 00:05:22 +00:00
//: extra test for try_reclaim_locals() from previous layers
: ( scenario local_scope_ignores_nonlocal_spaces )
def new - scope [
new - default - space
x : address : number < - new number : type
* x : address : number < - copy 34
return default - space : address : array : location
]
def use - scope [
local - scope
outer : address : array : location < - next - ingredient
0 : address : array : location / names : new - scope < - copy outer : address : array : location
return * x : address : number / space : 1
]
def main [
1 : address : array : location / raw < - new - scope
2 : number / raw < - use - scope 1 : address : array : location / raw
]
+ mem : storing 34 in location 2