about summary refs log tree commit diff stats
path: root/html/045closure_name.cc.html
blob: c4f9a0ef6e0f825b959412f0688c6debe7614c91 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 045closure_name.cc</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="cpp">
<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 12pt; font-size: 1em; }
.Constant { color: #00a0a0; }
.cSpecial { color: #008000; }
.traceContains { color: #008000; }
.Comment { color: #9090ff; }
.Delimiter { color: #800080; }
.Special { color: #c00000; }
.Identifier { color: #fcb165; }
.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
.CommentedCode { color: #6c6c6c; }
-->
</style>

<script type='text/javascript'>
<!--

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment">//: Writing to a literal (not computed) address of 0 in a recipe chains two</span>
<span class="Comment">//: spaces together. When a variable has a property of /space:1, it looks up</span>
<span class="Comment">//: the variable in the chained/surrounding space. /space:2 looks up the</span>
<span class="Comment">//: surrounding space of the surrounding space, etc.</span>

<span class="Delimiter">:(scenario closure)</span>
def main [
  <span class="Normal">default</span>-space:space<span class="Special"> &lt;- </span><span class="Normal">new</span> location:type<span class="Delimiter">,</span> <span class="Constant">30</span>
  <span class="Constant">1</span>:space/names:<span class="Normal">new</span>-counter<span class="Special"> &lt;- </span><span class="Normal">new</span>-counter
  <span class="Constant">2</span>:num/<span class="Special">raw &lt;- </span>increment-counter <span class="Constant">1</span>:space/names:<span class="Normal">new</span>-counter
  <span class="Constant">3</span>:num/<span class="Special">raw &lt;- </span>increment-counter <span class="Constant">1</span>:space/names:<span class="Normal">new</span>-counter
]
def <span class="Normal">new</span>-counter [
  <span class="Normal">default</span>-space:space<span class="Special"> &lt;- </span><span class="Normal">new</span> location:type<span class="Delimiter">,</span> <span class="Constant">30</span>
  <span class="Normal">x</span>:num<span class="Special"> &lt;- </span>copy <span class="Constant">23</span>
  <span class="Normal">y</span>:num<span class="Special"> &lt;- </span>copy <span class="Constant">3</span>  <span class="Comment"># variable that will be incremented</span>
  <span class="Identifier">return</span> <span class="Normal">default</span>-space:space
]
def increment-counter [
  <span class="Normal">default</span>-space:space<span class="Special"> &lt;- </span><span class="Normal">new</span> location:type<span class="Delimiter">,</span> <span class="Constant">30</span>
  <span class="Constant">0</span>:space/names:<span class="Normal">new</span>-counter<span class="Special"> &lt;- </span>next-ingredient  <span class="Comment"># outer space must be created by 'new-counter' above</span>
  <span class="Normal">y</span>:num/space:<span class="Constant">1</span><span class="Special"> &lt;- </span>add y:num/space:<span class="Constant">1</span><span class="Delimiter">,</span> <span class="Constant">1</span>  <span class="Comment"># increment</span>
  <span class="Normal">y</span>:num<span class="Special"> &lt;- </span>copy <span class="Constant">234</span>  <span class="Comment"># dummy</span>
  <span class="Identifier">return</span> y:num/space:<span class="Constant">1</span>
]
<span class="traceContains">+name: lexically surrounding space for recipe increment-counter comes from new-counter</span>
<span class="traceContains">+mem: storing 5 in location 3</span>

<span class="Comment">//: To make this work, compute the recipe that provides names for the</span>
<span class="Comment">//: surrounding space of each recipe.</span>

<span class="Delimiter">:(before &quot;End Globals&quot;)</span>
map&lt;recipe_ordinal<span class="Delimiter">,</span> recipe_ordinal&gt; Surrounding_space<span class="Delimiter">;</span>

<span class="Delimiter">:(before &quot;Transform.push_back(transform_names)&quot;)</span>
Transform<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>collect_surrounding_spaces<span class="Delimiter">);</span>  <span class="Comment">// idempotent</span>

<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> collect_surrounding_spaces<span class="Delimiter">(</span><span class="Normal">const</span> recipe_ordinal r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  trace<span class="Delimiter">(</span><span class="Constant">9991</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;--- collect surrounding spaces for recipe &quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name &lt;&lt; end<span class="Delimiter">();</span>
<span class="CommentedCode">//?   cerr &lt;&lt; &quot;--- collect surrounding spaces for recipe &quot; &lt;&lt; get(Recipe, r).name &lt;&lt; '\n';</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>steps<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">const</span> instruction&amp; inst = get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>steps<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>inst<span class="Delimiter">.</span>is_label<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
    <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> j = <span class="Constant">0</span><span class="Delimiter">;</span> j &lt; SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++j<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>is_literal<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">)))</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">).</span>name != <span class="Constant">&quot;0&quot;</span><span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>!is_space<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">)))</span> <span class="Delimiter">{</span>
        raise &lt;&lt; <span class="Constant">&quot;slot 0 should always have type address:array:location, but is '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
        <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      string_tree* s = property<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">),</span> <span class="Constant">&quot;names&quot;</span><span class="Delimiter">);</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>!s<span class="Delimiter">)</span> <span class="Delimiter">{</span>
        raise &lt;&lt; <span class="Constant">&quot;slot 0 requires a /names property in recipe '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
        <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>!s<span class="Delimiter">-&gt;</span>atom<span class="Delimiter">)</span> raise &lt;&lt; <span class="Constant">&quot;slot 0 should have a single value in /names, but got '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>j<span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
      <span class="Normal">const</span> string&amp; surrounding_recipe_name = s<span class="Delimiter">-&gt;</span>value<span class="Delimiter">;</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>surrounding_recipe_name<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span>
        raise &lt;&lt; <span class="Constant">&quot;slot 0 doesn't initialize its /names property in recipe '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
        <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Surrounding_space<span class="Delimiter">,</span> r<span class="Delimiter">)</span>
          &amp;&amp; get<span class="Delimiter">(</span>Surrounding_space<span class="Delimiter">,</span> r<span class="Delimiter">)</span> != get<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> surrounding_recipe_name<span class="Delimiter">))</span> <span class="Delimiter">{</span>
        raise &lt;&lt; <span class="Constant">&quot;recipe '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name &lt;&lt; <span class="Constant">&quot;' can have only one 'surrounding' recipe but has '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> get<span class="Delimiter">(</span>Surrounding_space<span class="Delimiter">,</span> r<span class="Delimiter">)).</span>name &lt;&lt; <span class="Constant">&quot;' and '&quot;</span> &lt;&lt; surrounding_recipe_name &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
        <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">&quot;name&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;lexically surrounding space for recipe &quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name &lt;&lt; <span class="Constant">&quot; comes from &quot;</span> &lt;&lt; surrounding_recipe_name &lt;&lt; end<span class="Delimiter">();</span>
      <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> surrounding_recipe_name<span class="Delimiter">))</span> <span class="Delimiter">{</span>
        raise &lt;&lt; <span class="Constant">&quot;can't find recipe providing surrounding space for '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name &lt;&lt; <span class="Constant">&quot;'; looking for '&quot;</span> &lt;&lt; surrounding_recipe_name &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
        <span class="Identifier">continue</span><span class="Delimiter">;</span>
      <span class="Delimiter">}</span>
      put<span class="Delimiter">(</span>Surrounding_space<span class="Delimiter">,</span> r<span class="Delimiter">,</span> get<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> surrounding_recipe_name<span class="Delimiter">));</span>
    <span class="Delimiter">}</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">}</span>

<span class="Comment">//: Once surrounding spaces are available, transform_names uses them to handle</span>
<span class="Comment">//: /space properties.</span>

<span class="Delimiter">:(replace{} &quot;int lookup_name(const reagent&amp; r, const recipe_ordinal default_recipe)&quot;)</span>
<span class="Normal">int</span> lookup_name<span class="Delimiter">(</span><span class="Normal">const</span> reagent&amp; x<span class="Delimiter">,</span> <span class="Normal">const</span> recipe_ordinal default_recipe<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!has_property<span class="Delimiter">(</span>x<span class="Delimiter">,</span> <span class="Constant">&quot;space&quot;</span><span class="Delimiter">))</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>Name[default_recipe]<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> raise &lt;&lt; <span class="Constant">&quot;name not found: &quot;</span> &lt;&lt; x<span class="Delimiter">.</span>name &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Identifier">return</span> Name[default_recipe][x<span class="Delimiter">.</span>name]<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  string_tree* p = property<span class="Delimiter">(</span>x<span class="Delimiter">,</span> <span class="Constant">&quot;space&quot;</span><span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!p || !p<span class="Delimiter">-&gt;</span>atom<span class="Delimiter">)</span> raise &lt;&lt; <span class="Constant">&quot;/space property should have exactly one (non-negative integer) value</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
  <span class="Normal">int</span> n = to_integer<span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>value<span class="Delimiter">);</span>
  assert<span class="Delimiter">(</span>n &gt;= <span class="Constant">0</span><span class="Delimiter">);</span>
  recipe_ordinal surrounding_recipe = lookup_surrounding_recipe<span class="Delimiter">(</span>default_recipe<span class="Delimiter">,</span> n<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>surrounding_recipe == -<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Identifier">return</span> -<span class="Constant">1</span><span class="Delimiter">;</span>
  set&lt;recipe_ordinal&gt; done<span class="Delimiter">;</span>
  vector&lt;recipe_ordinal&gt; path<span class="Delimiter">;</span>
  <span class="Identifier">return</span> lookup_name<span class="Delimiter">(</span>x<span class="Delimiter">,</span> surrounding_recipe<span class="Delimiter">,</span> done<span class="Delimiter">,</span> path<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Comment">// If the recipe we need to lookup this name in doesn't have names done yet,</span>
<span class="Comment">// recursively call transform_names on it.</span>
<span class="Normal">int</span> lookup_name<span class="Delimiter">(</span><span class="Normal">const</span> reagent&amp; x<span class="Delimiter">,</span> <span class="Normal">const</span> recipe_ordinal r<span class="Delimiter">,</span> set&lt;recipe_ordinal&gt;&amp; done<span class="Delimiter">,</span> vector&lt;recipe_ordinal&gt;&amp; path<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!Name[r]<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">return</span> Name[r][x<span class="Delimiter">.</span>name]<span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>done<span class="Delimiter">,</span> r<span class="Delimiter">))</span> <span class="Delimiter">{</span>
    raise &lt;&lt; <span class="Constant">&quot;can't compute address of '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>x<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;' because</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">1</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>path<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      raise &lt;&lt; path<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i-<span class="Constant">1</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; requires computing names of &quot;</span> &lt;&lt; path<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">)</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Delimiter">}</span>
    raise &lt;&lt; path<span class="Delimiter">.</span>at<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>path<span class="Delimiter">)</span>-<span class="Constant">1</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; requires computing names of &quot;</span> &lt;&lt; r &lt;&lt; <span class="Constant">&quot;..ad infinitum</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Identifier">return</span> -<span class="Constant">1</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  done<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
  path<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
  transform_names<span class="Delimiter">(</span>r<span class="Delimiter">);</span>  <span class="Comment">// Not passing 'done' through. Might this somehow cause an infinite loop?</span>
  assert<span class="Delimiter">(</span>!Name[r]<span class="Delimiter">.</span>empty<span class="Delimiter">());</span>
  <span class="Identifier">return</span> Name[r][x<span class="Delimiter">.</span>name]<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

recipe_ordinal lookup_surrounding_recipe<span class="Delimiter">(</span><span class="Normal">const</span> recipe_ordinal r<span class="Delimiter">,</span> <span class="Normal">int</span> n<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>n == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">return</span> r<span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Surrounding_space<span class="Delimiter">,</span> r<span class="Delimiter">))</span> <span class="Delimiter">{</span>
    raise &lt;&lt; <span class="Constant">&quot;don't know surrounding recipe of '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Identifier">return</span> -<span class="Constant">1</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  assert<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Surrounding_space<span class="Delimiter">,</span> r<span class="Delimiter">));</span>
  <span class="Identifier">return</span> lookup_surrounding_recipe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Surrounding_space<span class="Delimiter">,</span> r<span class="Delimiter">),</span> n-<span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Comment">//: weaken use-before-set detection just a tad</span>
<span class="Delimiter">:(replace{} &quot;bool already_transformed(const reagent&amp; r, const map&lt;string, int&gt;&amp; names)&quot;)</span>
<span class="Normal">bool</span> already_transformed<span class="Delimiter">(</span><span class="Normal">const</span> reagent&amp; r<span class="Delimiter">,</span> <span class="Normal">const</span> map&lt;string<span class="Delimiter">,</span> <span class="Normal">int</span>&gt;&amp; names<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>has_property<span class="Delimiter">(</span>r<span class="Delimiter">,</span> <span class="Constant">&quot;space&quot;</span><span class="Delimiter">))</span> <span class="Delimiter">{</span>
    string_tree* p = property<span class="Delimiter">(</span>r<span class="Delimiter">,</span> <span class="Constant">&quot;space&quot;</span><span class="Delimiter">);</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>!p || !p<span class="Delimiter">-&gt;</span>atom<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      raise &lt;&lt; <span class="Constant">&quot;/space property should have exactly one (non-negative integer) value in '&quot;</span> &lt;&lt; r<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
      <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>value != <span class="Constant">&quot;0&quot;</span><span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  <span class="Identifier">return</span> contains_key<span class="Delimiter">(</span>names<span class="Delimiter">,</span> r<span class="Delimiter">.</span>name<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(scenario missing_surrounding_space)</span>
<span class="Special">% Hide_errors = true;</span>
def f [
  local-scope
  <span class="Normal">x</span>:num/space:<span class="Constant">1</span><span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
]
<span class="traceContains">+error: don't know surrounding recipe of 'f'</span>
<span class="traceContains">+error: f: can't find a place to store 'x'</span>

<span class="Comment">//: extra test for try_reclaim_locals() from previous layers</span>
<span class="Delimiter">:(scenario local_scope_ignores_nonlocal_spaces)</span>
def <span class="Normal">new</span>-scope [
  <span class="Normal">new</span>-<span class="Normal">default</span>-space
  <span class="Normal">x</span>:&amp;:num<span class="Special"> &lt;- </span><span class="Normal">new</span> number:type
  *x:&amp;:num<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Identifier">return</span> <span class="Normal">default</span>-space:space
]
def use-scope [
  local-scope
  <span class="Normal">outer</span>:space<span class="Special"> &lt;- </span>next-ingredient
  <span class="Constant">0</span>:space/names:<span class="Normal">new</span>-scope<span class="Special"> &lt;- </span>copy outer:space
  <span class="Identifier">return</span> *x:&amp;:num/space:<span class="Constant">1</span>
]
def main [
  <span class="Constant">1</span>:space/<span class="Special">raw &lt;- </span><span class="Normal">new</span>-scope
  <span class="Constant">2</span>:num/<span class="Special">raw &lt;- </span>use-scope <span class="Constant">1</span>:space/<span class="Special">raw</span>
]
<span class="traceContains">+mem: storing 34 in location 2</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->