about summary refs log blame commit diff stats
path: root/037recipe.cc
blob: 5a4acb82d77aa7b842fa29722f638f059afe0d0d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                           

                                               








                                       
                        
                           


                                                                                   


                                                  
                                      





                                             
                              









                                                                            
//: So far we've been calling a fixed recipe in each instruction, but we'd
//: also like to make the recipe a variable, pass recipes to "higher-order"
//: recipes, return recipes from recipes and so on.

:(scenario call_literal_recipe)
recipe main [
  1:number <- call f:recipe, 34:literal
]
recipe f [
  2:number <- next-ingredient
  reply 2:number
]
+mem: storing 34 in location 1

:(scenario call_variable)
recipe main [
  1:recipe-ordinal <- copy f:recipe
  2:number <- call 1:recipe-ordinal, 34:literal
]
recipe f [
  3:number <- next-ingredient
  reply 3:number
]
+mem: storing 34 in location 2
#? ?

:(before "End Mu Types Initialization")
// 'recipe' is a literal
Type_ordinal["recipe"] = 0;
// 'recipe-ordinal' is the literal that can store recipe literals
type_ordinal recipe_ordinal = Type_ordinal["recipe-ordinal"] = Next_type_ordinal++;
Type[recipe_ordinal].name = "recipe-ordinal";

:(before "End Reagent-parsing Exceptions")
if (r.properties.at(0).second.at(0) == "recipe") {
  r.set_value(Recipe_ordinal[r.name]);
  return;
}

:(before "End Primitive Recipe Declarations")
CALL,
:(before "End Primitive Recipe Numbers")
Recipe_ordinal["call"] = CALL;
:(before "End Primitive Recipe Implementations")
case CALL: {
  assert(scalar(ingredients.at(0)));
  // todo: when we start doing type checking this will be a prime point of
  // attention, so we don't accidentally allow external data to a program to
  // run as code.
  Current_routine->calls.push_front(call(ingredients.at(0).at(0)));
  ingredients.erase(ingredients.begin());  // drop the callee
  goto complete_call;
}
>> <span class="Comment"># length</span> <span class="Comment"># pretend address:array:location; in practice we'll use new</span> <span class="Constant">20</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span> <span class="Comment"># refcount</span> <span class="Constant">21</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">5</span> <span class="Comment"># length</span> <span class="Comment"># actual start of this recipe</span> global-space:address:array:location<span class="Special"> &lt;- </span>copy <span class="Constant">20</span>/unsafe <span class="Normal">default</span>-space:address:array:location<span class="Special"> &lt;- </span>copy <span class="Constant">10</span>/unsafe <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">23</span> <span class="Constant">1</span>:number/space:global<span class="Special"> &lt;- </span>copy <span class="Constant">24</span> ] <span class="Comment"># store to default space: 10 + /*skip refcount*/1 + /*skip length*/1 + /*index*/1</span> <span class="traceContains">+mem: storing 23 in location 13</span> <span class="Comment"># store to chained space: /*contents of location 12*/20 + /*skip refcount*/1 + /*skip length*/1 + /*index*/1</span> <span class="traceContains">+mem: storing 24 in location 23</span> <span class="Comment">//: to support it, create another special variable called global space</span> <span class="Delimiter">:(before &quot;End is_disqualified Cases&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>x<span class="Delimiter">.</span>name == <span class="Constant">&quot;global-space&quot;</span><span class="Delimiter">)</span> x<span class="Delimiter">.</span>initialized = <span class="Constant">true</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End is_special_name Cases&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>s == <span class="Constant">&quot;global-space&quot;</span><span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> <span class="Comment">//: writes to this variable go to a field in the current routine</span> <span class="Delimiter">:(before &quot;End routine Fields&quot;)</span> <span class="Normal">int</span> global_space<span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End routine Constructor&quot;)</span> global_space = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">:(after &quot;void write_memory(reagent x, const vector&lt;double&gt;&amp; data)&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>x<span class="Delimiter">.</span>name == <span class="Constant">&quot;global-space&quot;</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!scalar<span class="Delimiter">(</span>data<span class="Delimiter">)</span> || !x<span class="Delimiter">.</span>type || x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value != get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;address&quot;</span><span class="Delimiter">)</span> || !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right || x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>value != get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;array&quot;</span><span class="Delimiter">)</span> || !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right || x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>value != get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;location&quot;</span><span class="Delimiter">)</span> || x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">)</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;'global-space' should be of type address:array:location, but tried to write &quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>data<span class="Delimiter">)</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>Current_routine<span class="Delimiter">-&gt;</span>global_space<span class="Delimiter">)</span> raise &lt;&lt; <span class="Constant">&quot;routine already has a global-space; you can't over-write your globals&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> Current_routine<span class="Delimiter">-&gt;</span>global_space = data<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Comment">//: now marking variables as /space:global looks them up inside this field</span> <span class="Delimiter">:(after &quot;int space_base(const reagent&amp; x)&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_global<span class="Delimiter">(</span>x<span class="Delimiter">))</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!Current_routine<span class="Delimiter">-&gt;</span>global_space<span class="Delimiter">)</span> raise &lt;&lt; <span class="Constant">&quot;routine has no global space</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Identifier">return</span> Current_routine<span class="Delimiter">-&gt;</span>global_space + <span class="Comment">/*</span><span class="Comment">skip refcount</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Comment">//: for now let's not bother giving global variables names.</span> <span class="Comment">//: don't want to make them too comfortable to use.</span> <span class="Delimiter">:(scenario global_space_with_names)</span> def main [ global-space:address:array:location<span class="Special"> &lt;- </span><span class="Normal">new</span> location:type<span class="Delimiter">,</span> <span class="Constant">10</span> <span class="Normal">x</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">23</span> <span class="Constant">1</span>:number/space:global<span class="Special"> &lt;- </span>copy <span class="Constant">24</span> ] <span class="Comment"># don't complain about mixing numeric addresses and names</span> $error: <span class="Constant">0</span> <span class="Delimiter">:(after &quot;bool is_numeric_location(const reagent&amp; x)&quot;)</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_global<span class="Delimiter">(</span>x<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Comment">//: helpers</span> <span class="Delimiter">:(code)</span> <span class="Normal">bool</span> is_global<span class="Delimiter">(</span><span class="Normal">const</span> reagent&amp; x<span class="Delimiter">)</span> <span class="Delimiter">{</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>x<span class="Delimiter">.</span>properties<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>x<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first == <span class="Constant">&quot;space&quot;</span><span class="Delimiter">)</span> <span class="Identifier">return</span> x<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>second &amp;&amp; x<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>second<span class="Delimiter">-&gt;</span>value == <span class="Constant">&quot;global&quot;</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->