https://github.com/akkartik/mu/blob/master/072recipe.cc
1
2
3
4
5 :(scenario call_literal_recipe)
6 def main [
7 1:num <- call f, 34
8 ]
9 def f x:num -> y:num [
10 local-scope
11 load-ingredients
12 y <- copy x
13 ]
14 +mem: storing 34 in location 1
15
16 :(before "End Mu Types Initialization")
17 put(Type_ordinal, "recipe-literal", 0);
18
19 type_ordinal recipe = put(Type_ordinal, "recipe", Next_type_ordinal++);
20 get_or_insert(Type, recipe).name = "recipe";
21
22 :(after "Deduce Missing Type(x, caller)")
23 if (!x.type)
24 try_initialize_recipe_literal(x, caller);
25 :(before "Type Check in Type-ingredient-aware check_or_set_types_by_name")
26 if (!x.type)
27 try_initialize_recipe_literal(x, variant);
28 :(code)
29 void try_initialize_recipe_literal(reagent& x, const recipe& caller) {
30 if (x.type) return;
31 if (!contains_key(Recipe_ordinal, x.name)) return;
32 if (contains_reagent_with_non_recipe_literal_type(caller, x.name)) return;
33 x.type = new type_tree("recipe-literal");
34 x.set_value(get(Recipe_ordinal, x.name));
35 }
36 bool contains_reagent_with_non_recipe_literal_type(const recipe& caller, const string& name) {
37 for (int i = 0; i < SIZE(caller.steps); ++i) {
38 const instruction& inst = caller.steps.at(i);
39 for (int i = 0; i < SIZE(inst.ingredients); ++i)
40 if (is_matching_non_recipe_literal(inst.ingredients.at(i), name)) return true;
41 for (int i = 0; i < SIZE(inst.products); ++i)
42 if (is_matching_non_recipe_literal(inst.products.at(i), name)) return true;
43 }
44 return false;
45 }
46 bool is_matching_non_recipe_literal(const reagent& x, const string& name) {
47 if (x.name != name) return false;
48 if (!x.type) return false;
49 return !x.type->atom || x.type->name != "recipe-literal";
50 }
51
52
53
54 :(scenario error_on_recipe_literal_used_as_a_variable)
55 % Hide_errors = true;
56 def main [
57 local-scope
58 a:bool <- equal break 0
59 break:bool <- copy 0
60 ]
61 +error: main: missing type for 'break' in 'a:bool <- equal break, 0'
62
63 :(before "End Primitive Recipe Declarations")
64 CALL,
65 :(before "End Primitive Recipe Numbers")
66 put(Recipe_ordinal, "call", CALL);
67 :(before "End Primitive Recipe Checks")
68 case CALL: {
69 if (inst.ingredients.empty()) {
70 raise << maybe(get(Recipe, r).name) << "'call' requires at least one ingredient (the recipe to call)\n" << end();
71 break;
72 }
73 if (!is_mu_recipe(inst.ingredients.at(0))) {
74 raise << maybe(get(Recipe, r).name) << "first ingredient of 'call' should be a recipe, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
75 break;
76 }
77 break;
78 }
79 :(before "End Primitive Recipe Implementations")
80 case CALL: {
81
82 if (Trace_stream) {
83 ++Trace_stream->callstack_depth;
84 trace("trace") << "indirect 'call': incrementing callstack depth to " << Trace_stream->callstack_depth << end();
85 assert(Trace_stream->callstack_depth < 9000);
86 }
87 if (!ingredients.at(0).at(0)) {
88 raise << maybe(current_recipe_name()) << "tried to call empty recipe in '" << to_string(current_instruction()) << "'" << end();
89 break;
90 }
91 const call& caller_frame = current_call();
92 instruction call_instruction = to_instruction(caller_frame);
93 call_instruction.operation = ingredients.at(0).at(0);
94 call_instruction.ingredients.erase(call_instruction.ingredients.begin());
95 Current_routine->calls.push_front(call(ingredients.at(0).at(0)));
96 ingredients.erase(ingredients.begin());
97 finish_call_housekeeping(call_instruction, ingredients);
98
99 write_products = false;
100 fall_through_to_next_instruction = false;
101 break;
102 }
103
104 :(scenario call_variable)
105 def main [
106 {1: (recipe number -> number)} <- copy f
107 2:num <- call {1: (recipe number -> number)}, 34
108 ]
109 def f x:num -> y:num [
110 local-scope
111 load-ingredients
112 y <- copy x
113 ]
114 +mem: storing 34 in location 2
115
116 :(scenario call_literal_recipe_repeatedly)
117 def main [
118 1:num <- call f, 34
119 1:num <- call f, 35
120 ]
121 def f x:num -> y:num [
122 local-scope
123 load-ingredients
124 y <- copy x
125 ]
126 +mem: storing 34 in location 1
127 +mem: storing 35 in location 1
128
129 :(scenario call_shape_shifting_recipe)
130 def main [
131 1:num <- call f, 34
132 ]
133 def f x:_elem -> y:_elem [
134 local-scope
135 load-ingredients
136 y <- copy x
137 ]
138 +mem: storing 34 in location 1
139
140 :(scenario call_shape_shifting_recipe_inside_shape_shifting_recipe)
141 def main [
142 1:num <- f 34
143 ]
144 def f x:_elem -> y:_elem [
145 local-scope
146 load-ingredients
147 y <- call g x
148 ]
149 def g x:_elem -> y:_elem [
150 local-scope
151 load-ingredients
152 y <- copy x
153 ]
154 +mem: storing 34 in location 1
155
156 :(scenario call_shape_shifting_recipe_repeatedly_inside_shape_shifting_recipe)
157 def main [
158 1:num <- f 34
159 ]
160 def f x:_elem -> y:_elem [
161 local-scope
162 load-ingredients
163 y <- call g x
164 y <- call g x
165 ]
166 def g x:_elem -> y:_elem [
167 local-scope
168 load-ingredients
169 y <- copy x
170 ]
171 +mem: storing 34 in location 1
172
173
174
175 :(scenario call_check_literal_recipe)
176 % Hide_errors = true;
177 def main [
178 1:num <- call f, 34
179 ]
180 def f x:point -> y:point [
181 local-scope
182 load-ingredients
183 y <- copy x
184 ]
185 +error: main: ingredient 0 has the wrong type at '1:num <- call f, 34'
186 +error: main: product 0 has the wrong type at '1:num <- call f, 34'
187
188 :(scenario call_check_variable_recipe)
189 % Hide_errors = true;
190 def main [
191 {1: (recipe point -> point)} <- copy f
192 2:num <- call {1: (recipe point -> point)}, 34
193 ]
194 def f x:point -> y:point [
195 local-scope
196 load-ingredients
197 y <- copy x
198 ]
199 +error: main: ingredient 0 has the wrong type at '2:num <- call {1: (recipe point -> point)}, 34'
200 +error: main: product 0 has the wrong type at '2:num <- call {1: (recipe point -> point)}, 34'
201
202 :(before "End resolve_ambiguous_call(r, index, inst, caller_recipe) Special-cases")
203 if (inst.name == "call" && !inst.ingredients.empty() && is_recipe_literal(inst.ingredients.at(0))) {
204 resolve_indirect_ambiguous_call(r, index, inst, caller_recipe);
205 return;
206 }
207 :(code)
208 bool is_recipe_literal(const reagent& x) {
209 return x.type && x.type->atom && x.type->name == "recipe-literal";
210 }
211 void resolve_indirect_ambiguous_call(const recipe_ordinal r, int index, instruction& inst, const recipe& caller_recipe) {
212 instruction inst2;
213 inst2.name = inst.ingredients.at(0).name;
214 for (int i = 1; i < SIZE(inst.ingredients); ++i)
215 inst2.ingredients.push_back(inst.ingredients.at(i));
216 for (int i = 0; i < SIZE(inst.products); ++i)
217 inst2.products.push_back(inst.products.at(i));
218 resolve_ambiguous_call(r, index, inst2, caller_recipe);
219 inst.ingredients.at(0).name = inst2.name;
220 inst.ingredients.at(0).set_value(get(Recipe_ordinal, inst2.name));
221 }
222
223 :(after "Transform.push_back(check_instruction)")
224 Transform.push_back(check_indirect_calls_against_header);
225 :(code)
226 void check_indirect_calls_against_header(const recipe_ordinal r) {
227 trace(9991, "transform") << "--- type-check 'call' instructions inside recipe " << get(Recipe, r).name << end();
228 const recipe& caller = get(Recipe, r);
229 for (int i = 0; i < SIZE(caller.steps); ++i) {
230 const instruction& inst = caller.steps.at(i);
231 if (!is_indirect_call(inst.operation)) continue;
232 if (inst.ingredients.empty()) continue;
233 const reagent& callee = inst.ingredients.at(0);
234 if (!is_mu_recipe(callee)) continue;
235 const recipe callee_header = is_literal(callee) ? get(Recipe, callee.value) : from_reagent(inst.ingredients.at(0));
236 pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */<!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 - same-fringe.mu</title>
<meta name="Generator" content="Vim/8.0">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal-light">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #c6c6c6; }
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.muControl { color: #804000; }
.muRecipe { color: #ff8700; }
.LineNr { }
.muData { color: #ffff00; }
.Delimiter { color: #c000c0; }
.Constant { color: #008787; }
.Special { color: #ff6060; }
.Comment { color: #005faf; }
-->
</style>
<script type='text/javascript'>
<!--
/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
var lineNum;
lineNum = window.location.hash;
lineNum = lineNum.substr(1); /* strip off '#' */
if (lineNum.indexOf('L') == -1) {
lineNum = 'L'+lineNum;
}
lineElem = document.getElementById(lineNum);
/* Always jump to new location even if the line was hidden inside a fold, or
* we corrected the raw number to a line ID.
*/
if (lineElem) {
lineElem.scrollIntoView(true);
}
return true;
}
if ('onhashchange' in window) {
window.onhashchange = JumpToLine;
}
-->
</script>
</head>
<body onload='JumpToLine();'>
<a href='https://github.com/akkartik/mu/blob/master/same-fringe.mu'>https://github.com/akkartik/mu/blob/master/same-fringe.mu</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span><span class="Comment"># The 'same fringe' problem: <a href="http://wiki.c2.com/?SameFringeProblem">http://wiki.c2.com/?SameFringeProblem</a></span>
<span id="L2" class="LineNr"> 2 </span><span class="Comment"># Example program demonstrating coroutines using Mu's delimited continuations.</span>
<span id="L3" class="LineNr"> 3 </span><span class="Comment">#</span>
<span id="L4" class="LineNr"> 4 </span><span class="Comment"># Expected output:</span>
<span id="L5" class="LineNr"> 5 </span><span class="Comment"># 1</span>
<span id="L6" class="LineNr"> 6 </span><span class="Comment"># (i.e. that the two given trees x and y have the same leaves, in the same</span>
<span id="L7" class="LineNr"> 7 </span><span class="Comment"># order from left to right)</span>
<span id="L8" class="LineNr"> 8 </span>
<span id="L9" class="LineNr"> 9 </span><span class="muData">container</span> <a href='same-fringe.mu.html#L9'>tree</a>:_elem [
<span id="L10" class="LineNr">10 </span> val:_elem
<span id="L11" class="LineNr">11 </span> left:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem
<span id="L12" class="LineNr">12 </span> right:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem
<span id="L13" class="LineNr">13 </span>]
<span id="L14" class="LineNr">14 </span>
<span id="L15" class="LineNr">15 </span><span class="muRecipe">def</span> <a href='same-fringe.mu.html#L15'>main</a> [
<span id="L16" class="LineNr">16 </span> <span class="Constant">local-scope</span>
<span id="L17" class="LineNr">17 </span> <span class="Comment"># x: ((a b) c)</span>
<span id="L18" class="LineNr">18 </span> <span class="Comment"># y: (a (b c))</span>
<span id="L19" class="LineNr">19 </span> a:&:<a href='same-fringe.mu.html#L9'>tree</a>:num <span class="Special"><-</span> new-tree<span class="Constant"> 3</span>
<span id="L20" class="LineNr">20 </span> b:&:<a href='same-fringe.mu.html#L9'>tree</a>:num <span class="Special"><-</span> new-tree<span class="Constant"> 4</span>
<span id="L21" class="LineNr">21 </span> c:&:<a href='same-fringe.mu.html#L9'>tree</a>:num <span class="Special"><-</span> new-tree<span class="Constant"> 5</span>
<span id="L22" class="LineNr">22 </span> x1:&:<a href='same-fringe.mu.html#L9'>tree</a>:num <span class="Special"><-</span> new-tree a, b
<span id="L23" class="LineNr">23 </span> x:&:<a href='same-fringe.mu.html#L9'>tree</a>:num <span class="Special"><-</span> new-tree x1, c
<span id="L24" class="LineNr">24 </span> y1:&:<a href='same-fringe.mu.html#L9'>tree</a>:num <span class="Special"><-</span> new-tree b, c
<span id="L25" class="LineNr">25 </span> y:&:<a href='same-fringe.mu.html#L9'>tree</a>:num <span class="Special"><-</span> new-tree a, y1
<span id="L26" class="LineNr">26 </span> result:bool <span class="Special"><-</span> <a href='same-fringe.mu.html#L30'>same-fringe</a> x, y
<span id="L27" class="LineNr">27 </span> $print result <span class="Constant">10/newline</span>
<span id="L28" class="LineNr">28 </span>]
<span id="L29" class="LineNr">29 </span>
<span id="L30" class="LineNr">30 </span><span class="muRecipe">def</span> <a href='same-fringe.mu.html#L30'>same-fringe</a> a:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem, b:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem<span class="muRecipe"> -> </span>result:bool [
<span id="L31" class="LineNr">31 </span> <span class="Constant">local-scope</span>
<span id="L32" class="LineNr">32 </span> <span class="Constant">load-inputs</span>
<span id="L33" class="LineNr">33 </span> k1:continuation <span class="Special"><-</span> <span class="muControl">call-with-continuation-mark</span> <span class="Constant">100/mark</span>, <a href='same-fringe.mu.html#L48'>process</a>, a
<span id="L34" class="LineNr">34 </span> k2:continuation <span class="Special"><-</span> <span class="muControl">call-with-continuation-mark</span> <span class="Constant">100/mark</span>, <a href='same-fringe.mu.html#L48'>process</a>, b
<span id="L35" class="LineNr">35 </span> <span class="Delimiter">{</span>
<span id="L36" class="LineNr">36 </span> k1, x:_elem, a-done?:bool <span class="Special"><-</span> call k1
<span id="L37" class="LineNr">37 </span> k2, y:_elem, b-done?:bool <span class="Special"><-</span> call k2
<span id="L38" class="LineNr">38 </span> <span class="muControl">break-if</span> a-done?
<span id="L39" class="LineNr">39 </span> <span class="muControl">break-if</span> b-done?
<span id="L40" class="LineNr">40 </span> match?:bool <span class="Special"><-</span> equal x, y
<span id="L41" class="LineNr">41 </span> <span class="muControl">return-unless</span> match?,<span class="Constant"> false</span>
<span id="L42" class="LineNr">42 </span> <span class="muControl"> loop</span>
<span id="L43" class="LineNr">43 </span> <span class="Delimiter">}</span>
<span id="L44" class="LineNr">44 </span> result <span class="Special"><-</span> and a-done?, b-done?
<span id="L45" class="LineNr">45 </span>]
<span id="L46" class="LineNr">46 </span>
<span id="L47" class="LineNr">47 </span><span class="Comment"># harness around traversal</span>
<span id="L48" class="LineNr">48 </span><span class="muRecipe">def</span> <a href='same-fringe.mu.html#L48'>process</a> t:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem [
<span id="L49" class="LineNr">49 </span> <span class="Constant">local-scope</span>
<span id="L50" class="LineNr">50 </span> <span class="Constant">load-inputs</span>
<span id="L51" class="LineNr">51 </span> <span class="muControl">return-continuation-until-mark</span> <span class="Constant">100/mark</span> <span class="Comment"># initial</span>
<span id="L52" class="LineNr">52 </span> <a href='same-fringe.mu.html#L59'>traverse</a> t
<span id="L53" class="LineNr">53 </span> zero-val:&:_elem <span class="Special"><-</span> new <span class="Constant">_elem:type</span>
<span id="L54" class="LineNr">54 </span> <span class="muControl">return-continuation-until-mark</span> <span class="Constant">100/mark</span>, *zero-val,<span class="Constant"> true/done</span> <span class="Comment"># final</span>
<span id="L55" class="LineNr">55 </span> assert<span class="Constant"> false</span>, <span class="Constant">[continuation called past done]</span>
<span id="L56" class="LineNr">56 </span>]
<span id="L57" class="LineNr">57 </span>
<span id="L58" class="LineNr">58 </span><span class="Comment"># core traversal</span>
<span id="L59" class="LineNr">59 </span><span class="muRecipe">def</span> <a href='same-fringe.mu.html#L59'>traverse</a> t:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem [
<span id="L60" class="LineNr">60 </span> <span class="Constant">local-scope</span>
<span id="L61" class="LineNr">61 </span> <span class="Constant">load-inputs</span>
<span id="L62" class="LineNr">62 </span> <span class="muControl">return-unless</span> t
<span id="L63" class="LineNr">63 </span> l:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem <span class="Special"><-</span> get *t, <span class="Constant">left:offset</span>
<span id="L64" class="LineNr">64 </span> <a href='same-fringe.mu.html#L59'>traverse</a> l
<span id="L65" class="LineNr">65 </span> r:&:<a href='same-fringe.mu.html#L9'>tree</a>:_elem <span class="Special"><-</span> get *t, <span class="Constant">right:offset</span>
<span id="L66" class="LineNr">66 </span> <a href='same-fringe.mu.html#L59'>traverse</a> r
<span id="L67" class="LineNr">67 </span> <span class="muControl">return-if</span> l
<span id="L68" class="LineNr">68 </span> <span class="muControl">return-if</span> r
<span id="L69" class="LineNr">69 </span> <span class="Comment"># leaf</span>
<span id="L70" class="LineNr">70 </span> v:_elem <span class="Special"><-</span> get *t, <span class="Constant">val:offset</span>
<span id="L71" class="LineNr">71 </span> <span class="muControl">return-continuation-until-mark</span> <span class="Constant">100/mark</span>, v,<span class