summaryrefslogtreecommitdiff
path: root/chapter09
diff options
context:
space:
mode:
Diffstat (limited to 'chapter09')
-rw-r--r--chapter09/README.md51
-rw-r--r--chapter09/docs/09-graph1.json28
-rw-r--r--chapter09/docs/09-graph1.svg352
-rw-r--r--chapter09/docs/09-graph2.json26
-rw-r--r--chapter09/docs/09-graph2.svg318
-rw-r--r--chapter09/docs/09-graph3.json19
-rw-r--r--chapter09/docs/09-graph3.svg205
-rw-r--r--chapter09/docs/09-graph4.json16
-rw-r--r--chapter09/docs/09-graph4.svg147
-rw-r--r--chapter09/docs/09-graph5.json27
-rw-r--r--chapter09/docs/09-graph5.svg334
-rw-r--r--chapter09/docs/09-graph6.json26
-rw-r--r--chapter09/docs/09-graph6.svg303
-rw-r--r--chapter09/docs/Makefile13
14 files changed, 840 insertions, 1025 deletions
diff --git a/chapter09/README.md b/chapter09/README.md
index d3b55a19..2a9abe4e 100644
--- a/chapter09/README.md
+++ b/chapter09/README.md
@@ -1,17 +1,19 @@
# Chapter 9: Global Value Numbering and Iterative Peepholes
+[Previous: Chapter 8](../chapter08/README.md) |
+[Next: Chapter 10a](../chapter10a/README.md)
+
# Table of Contents
1. [Engineering Peepholes](#engineering-peepholes)
2. [Global Value Numbering](#global-value-numbering)
3. [Post-Parse Iterative Peepholes](#post-parse-iterative-peepholes)
4. [Distant Neighbors](#distant-neighbors)
-5. [Identification of Basic Blocks in SoN graph](#identification-of-basic-blocks-in-son-graph)
-6. [Other Concerns](#other-concerns)
-7. [Common SubExpressions via GVN](#common-subexpressions-via-gvn)
- - [Example 1](#example-1)
- - [Example 2](#example-2)
-8. [Post Parse Iterative Optimizations](#post-parse-iterative-optimizations)
+5. [Other Concerns](#other-concerns)
+6. [Common SubExpressions via GVN](#common-subexpressions-via-gvn)
+ - [Example 1](#example-1)
+ - [Example 2](#example-2)
+7. [Post Parse Iterative Optimizations](#post-parse-iterative-optimizations)
You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter09) in a linear Git revision history on the [linear](https://github.com/SeaOfNodes/Simple/tree/linear) branch and [compare](https://github.com/SeaOfNodes/Simple/compare/linear-chapter08...linear-chapter09) it to the previous chapter.
@@ -41,7 +43,7 @@ opcode and inputs. If two Nodes do the same function on the same inputs, they
get the same result - and can be shared.
* We add a global static hash table `GVN` in Node.
-* We add a `Node.equals` call. Two Nodes are equals if they have the same
+* We add a `Node.equals` call. Two Nodes are equal if they have the same
opcode - same Java class - on the same inputs.
* We add a `hashCode` on the Node opcode (proxy: Node string name) and inputs.
* `ConstantNode` and a few others need some extra custom bits here: the
@@ -50,8 +52,7 @@ get the same result - and can be shared.
Note the intentional *value* equality here. In many places in Simple we use
*reference* equality - e.g. node/edge maintenance is via reference equality, not
-value equality, so e.g. the `Utils.find()` call finds via reference. Through
-out the Simple project whenever a Node lookup is happening, beware if its via
+value equality, so e.g. the `Utils.find()` call finds via reference. Throughout the Simple project whenever a Node lookup is happening, beware if it's via
*value* or *reference* equality; this is not always explicitly called out but
should be obvious from context.
@@ -72,7 +73,7 @@ remove the Node from `GVN` first, before modifying the edges.
"edge-locked" and IS in `GVN`.
* The `hashCode` function uses the cached hash if available and disallows an
accidental zero hash.
-* We add a `unlock()` call to remove a Node from `GVN` before any edge is
+* We add an `unlock()` call to remove a Node from `GVN` before any edge is
changed. This is inserted in front of all calls which hack Node edges. All
edge modify code paths already ensure the Node is re-peepholed, and during
this revisit the Node will get re-inserted in the `GVN` table.
@@ -112,19 +113,19 @@ Rinse, Repeat until the worklist runs dry.
The main issues we have to deal with:
* Nodes have uses; replacing some set of Nodes with another requires more graph
- reworking. Not rocket science, but it can be fiddly. Its helpful to have a
+ reworking. Not rocket science, but it can be fiddly. It's helpful to have a
small set of graph munging utilities, and the strong invariant that the graph
is stable and correct between peepholes. In our case `Node.subsume` does
most of the munging, building on our prior stable Node utilities.
-* Changing a Node also changes the graph "neighborhood". The neigbors need to
+* Changing a Node also changes the graph "neighborhood". The neighbors need to
be checked to see if THEY can also peephole, and so on. After any peephole
- or graph update we put a Nodes uses and defs on the worklist.
+ or graph update we put a Node's uses and defs on the worklist.
* Our strong invariant is that for all Nodes, either they are on the worklist
OR no peephole applies. This invariant is easy to check, although expensive.
Basically the normal "iterate peepholes to a fixed point" is linear, and this
- check is linear at each peephole step... so quadratic overall. Its a useful
+ check is linear at each peephole step... so quadratic overall. It's a useful
assert, but one we can disable once the overall algorithm is stable - and
then turn it back on again when some new set of peepholes is misbehaving.
The code for this is turned on in `IterPeeps.iterate` as `assert
@@ -143,11 +144,11 @@ Updating "B" throws the dependent list ("this") onto the "todo" list.
An example of a distant neighbor check is in `AddNode`, where we check for
stacked constants: `(Add (Add x 2) 1)` and we'd like `(Add x 3)` instead.
Suppose we're doing this check and we find instead `(Add (Phi (Add x 2) self)
-1)` The check naturally bails out at the `Phi` since its not an `Add`, but the
+1)` The check naturally bails out at the `Phi` since it's not an `Add`, but the
`(Phi y self)` only has one unique input, and will itself peephole to `y`
eventually. When it does, our stacked `Add` peephole can apply. So the
failing Add peephole calls `phi.addDep(Add)` and registers a dependency on the
-`Phi`. If the `Phi` indeed later optimizes, we add its depencencies (e.g. the
+`Phi`. If the `Phi` indeed later optimizes, we add its dependencies (e.g. the
`Add`) back on our `IterPeeps` worklist and retry the stacked Add peephole.
The general rule is:
@@ -173,7 +174,7 @@ In this chapter we trigger on following patterns
Changes:
-* We add a `ArrayList<Node> _deps` field to Node; initially null.
+* We add an `ArrayList<Node> _deps` field to Node; initially null.
* Some peepholes (see above) add dependencies if they fail a remote check, by calling
`distant.addDep(this)`. The `addDep` call creates `_deps` and
filters for various kinds of duplicate adds.
@@ -191,7 +192,7 @@ There are more issues we will want to deal with in a later Chapter:
- Dead infinite loops often lead to infinite peephole cycles... if only we
would get around to working on the "base" of the dead loop it would fold
up.
- - Some peepholes naturally reduce the graph directly; while some keeps its
+ - Some peepholes naturally reduce the graph directly; while some keep its
size the same but reduce other things (e.g. swapping a Mul-by-2 with a
Shift), and we might end up with a few which try to grow the graph briefly
before collapsing.
@@ -211,15 +212,15 @@ There are more issues we will want to deal with in a later Chapter:
many peep patterns might go quadratic if approached from one end or another,
because they modify something then push it back onto the list where it
immediately gets pulled again. I.e., you end up spinning in a loop repeating
- the same peeps while slowly migrating a e.g. left-spine add-tree into a
- right-spine add-tree. A psuedo-random pull uses randomization to defeat bad
+ the same peeps while slowly migrating e.g. left-spine add-tree into a
+ right-spine add-tree. A pseudo-random pull uses randomization to defeat bad
peep patterns.
* Why isn't `IterPeeps` just passing over all of the Nodes once or twice,
instead of using a worklist with the `addDeps` mechanism? We could even
visit them in a defs-before-uses order (e.g. Reverse Post Order).
- In the absense of loops exactly one such pass will find all local peepholes,
+ In the absence of loops exactly one such pass will find all local peepholes,
and indeed the Parser already does this. However, this will fail to find
opportunities at loops and farther remote cases - and to get those peepholes
around loops will require another visit. It is easy to construct a case
@@ -249,7 +250,7 @@ else {
return x;
```
-Prior to GVN, this would result in following graph. Note that the `arg+arg` is translated to `arg*2`.
+Prior to GVN, this would result in the following graph. Note that the `arg+arg` is translated to `arg*2`.
![Graph1](./docs/09-graph1.svg)
@@ -269,8 +270,8 @@ Without GVN the peepholes cannot see that both sides of the subtraction have the
![Graph3](./docs/09-graph3.svg)
-- Each multiplication(*) node has two edges going to `arg`.
-- In the example above, we fused them to make the graph more readable.
+- Each multiplication(*) node has two edges going to `arg`.
+- The input-slot labels distinguish these two uses of the same definition.
With GVN, the peepholes can do a better job:
@@ -290,7 +291,7 @@ return arg;
```
While parsing the `while` loop it is not yet known that `step` is a constant and will not change. Therefore,
-without the post parse optimization we get following:
+without the post parse optimization we get the following:
![Graph5](./docs/09-graph5.svg)
diff --git a/chapter09/docs/09-graph1.json b/chapter09/docs/09-graph1.json
new file mode 100644
index 00000000..746d4de2
--- /dev/null
+++ b/chapter09/docs/09-graph1.json
@@ -0,0 +1,28 @@
+{
+ "ver": 1,
+ "comp": "chapter09/docs/09-graph1.svg",
+ "step": 1,
+ "roots": [],
+ "scope": 0,
+ "nodes": [
+ {"id": 1, "label": "$ctrl", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 2, "role": "CTRL", "label": null}], "proj": {"par": 2, "idx": 0}},
+ {"id": 2, "label": "Start", "type": null, "kind": "CTRL", "edges": [], "proj": null},
+ {"id": 3, "label": "Stop", "type": null, "kind": "STOP", "edges": [{"idx": 0, "def": 18, "role": "CTRL", "label": null}, {"idx": 1, "def": 24, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 4, "label": "arg", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 2, "role": "DATA", "label": null}], "proj": {"par": 2, "idx": 1}},
+ {"id": 5, "label": "True", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 11, "role": "CTRL", "label": null}], "proj": {"par": 11, "idx": 0}},
+ {"id": 6, "label": "False", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 11, "role": "CTRL", "label": null}], "proj": {"par": 11, "idx": 1}},
+ {"id": 7, "label": "2", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 8, "label": "*", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 7, "role": "DATA", "label": null}], "proj": null},
+ {"id": 9, "label": "10", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 10, "label": "<", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 9, "role": "DATA", "label": null}], "proj": null},
+ {"id": 11, "label": "If", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 1, "role": "CTRL", "label": null}, {"idx": 1, "def": 10, "role": "DATA", "label": null}], "proj": null},
+ {"id": 16, "label": "2", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 17, "label": "*", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 16, "role": "DATA", "label": null}], "proj": null},
+ {"id": 18, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 5, "role": "CTRL", "label": null}, {"idx": 1, "def": 17, "role": "DATA", "label": null}], "proj": null},
+ {"id": 20, "label": "1", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 21, "label": "+", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 8, "role": "DATA", "label": null}, {"idx": 2, "def": 20, "role": "DATA", "label": null}], "proj": null},
+ {"id": 24, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 6, "role": "CTRL", "label": null}, {"idx": 1, "def": 21, "role": "DATA", "label": null}], "proj": null}
+ ],
+ "groups": [
+ ]
+}
diff --git a/chapter09/docs/09-graph1.svg b/chapter09/docs/09-graph1.svg
index fce8d53c..e639b36b 100644
--- a/chapter09/docs/09-graph1.svg
+++ b/chapter09/docs/09-graph1.svg
@@ -1,222 +1,130 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.43.0 (0)
- -->
-<!-- Title: chapter08 Pages: 1 -->
-<svg width="350pt" height="420pt"
- viewBox="0.00 0.00 350.00 420.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 416)">
-<title>chapter08</title>
-<polygon fill="white" stroke="transparent" points="-4,4 -4,-416 346,-416 346,4 -4,4"/>
-<g id="clust1" class="cluster">
-<title>cluster_Nodes</title>
-<polygon fill="none" stroke="black" points="8,-8 8,-404 334,-404 334,-8 8,-8"/>
-</g>
-<!-- Start2 -->
-<g id="node1" class="node">
-<title>Start2</title>
-<polygon fill="yellow" stroke="transparent" points="56,-367 56,-392 137,-392 137,-367 56,-367"/>
-<polygon fill="none" stroke="black" points="56,-367 56,-392 137,-392 137,-367 56,-367"/>
-<text text-anchor="start" x="78" y="-375.8" font-family="Times,serif" font-size="14.00">Start</text>
-<polygon fill="none" stroke="black" points="56,-336 56,-367 137,-367 137,-336 56,-336"/>
-<polygon fill="yellow" stroke="transparent" points="61,-341 61,-362 101,-362 101,-341 61,-341"/>
-<polygon fill="none" stroke="black" points="61,-341 61,-362 101,-362 101,-341 61,-341"/>
-<text text-anchor="start" x="64" y="-347.8" font-family="Times,serif" font-size="14.00">$ctrl</text>
-<polygon fill="none" stroke="black" points="101,-341 101,-362 132,-362 132,-341 101,-341"/>
-<text text-anchor="start" x="104" y="-347.8" font-family="Times,serif" font-size="14.00">arg</text>
-</g>
-<!-- Stop3 -->
-<g id="node2" class="node">
-<title>Stop3</title>
-<polygon fill="yellow" stroke="black" points="175,-52 121,-52 121,-16 175,-16 175,-52"/>
-<text text-anchor="middle" x="148" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text>
-</g>
-<!-- Return18 -->
-<g id="node10" class="node">
-<title>Return18</title>
-<polygon fill="yellow" stroke="black" points="139,-124 73,-124 73,-88 139,-88 139,-124"/>
-<text text-anchor="middle" x="106" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return18 -->
-<g id="edge1" class="edge">
-<title>Stop3&#45;&gt;Return18</title>
-<path fill="none" stroke="red" d="M137.62,-52.3C132.74,-60.44 126.81,-70.31 121.42,-79.3"/>
-<polygon fill="red" stroke="red" points="118.41,-77.52 116.26,-87.9 124.41,-81.12 118.41,-77.52"/>
-<text text-anchor="middle" x="134.62" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Return24 -->
-<g id="node13" class="node">
-<title>Return24</title>
-<polygon fill="yellow" stroke="black" points="223,-124 157,-124 157,-88 223,-88 223,-124"/>
-<text text-anchor="middle" x="190" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return24 -->
-<g id="edge2" class="edge">
-<title>Stop3&#45;&gt;Return24</title>
-<path fill="none" stroke="red" d="M158.38,-52.3C163.26,-60.44 169.19,-70.31 174.58,-79.3"/>
-<polygon fill="red" stroke="red" points="171.59,-81.12 179.74,-87.9 177.59,-77.52 171.59,-81.12"/>
-<text text-anchor="middle" x="155.38" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_7 -->
-<g id="node3" class="node">
-<title>Con_7</title>
-<ellipse fill="none" stroke="black" cx="262" cy="-364" rx="27" ry="18"/>
-<text text-anchor="middle" x="262" y="-360.3" font-family="Times,serif" font-size="14.00">2</text>
-</g>
-<!-- Mul8 -->
-<g id="node4" class="node">
-<title>Mul8</title>
-<ellipse fill="none" stroke="black" cx="227" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="227" y="-274.3" font-family="Times,serif" font-size="14.00">*</text>
-</g>
-<!-- Mul8&#45;&gt;Start2 -->
-<g id="edge3" class="edge">
-<title>Mul8&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M208.6,-291.54C193.58,-301.96 172,-317.39 154,-332 147.74,-337.08 146.05,-343.45 142.33,-347.37"/>
-<polygon fill="black" stroke="black" points="141.05,-344.11 133,-351 143.59,-350.64 141.05,-344.11"/>
-<text text-anchor="middle" x="205.6" y="-294.14" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Mul8&#45;&gt;Con_7 -->
-<g id="edge4" class="edge">
-<title>Mul8&#45;&gt;Con_7</title>
-<path fill="none" stroke="black" d="M233.91,-295.6C238.85,-307.45 245.59,-323.62 251.23,-337.15"/>
-<polygon fill="black" stroke="black" points="248.02,-338.55 255.1,-346.44 254.48,-335.86 248.02,-338.55"/>
-<text text-anchor="middle" x="230.91" y="-298.2" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Con_9 -->
-<g id="node5" class="node">
-<title>Con_9</title>
-<ellipse fill="none" stroke="black" cx="190" cy="-364" rx="27" ry="18"/>
-<text text-anchor="middle" x="190" y="-360.3" font-family="Times,serif" font-size="14.00">10</text>
-</g>
-<!-- LT10 -->
-<g id="node6" class="node">
-<title>LT10</title>
-<ellipse fill="none" stroke="black" cx="155" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="155" y="-274.3" font-family="Times,serif" font-size="14.00">&lt;</text>
-</g>
-<!-- LT10&#45;&gt;Start2 -->
-<g id="edge5" class="edge">
-<title>LT10&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M139.98,-293.02C131.35,-302.35 121.57,-315.51 118.21,-329.88"/>
-<polygon fill="black" stroke="black" points="114.71,-329.65 117,-340 121.66,-330.49 114.71,-329.65"/>
-<text text-anchor="middle" x="136.98" y="-295.62" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- LT10&#45;&gt;Con_9 -->
-<g id="edge6" class="edge">
-<title>LT10&#45;&gt;Con_9</title>
-<path fill="none" stroke="black" d="M161.91,-295.6C166.85,-307.45 173.59,-323.62 179.23,-337.15"/>
-<polygon fill="black" stroke="black" points="176.02,-338.55 183.1,-346.44 182.48,-335.86 176.02,-338.55"/>
-<text text-anchor="middle" x="158.91" y="-298.2" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- If11 -->
-<g id="node7" class="node">
-<title>If11</title>
-<polygon fill="yellow" stroke="transparent" points="102,-195 102,-220 196,-220 196,-195 102,-195"/>
-<polygon fill="none" stroke="black" points="102,-195 102,-220 196,-220 196,-195 102,-195"/>
-<text text-anchor="start" x="143.5" y="-203.8" font-family="Times,serif" font-size="14.00">If</text>
-<polygon fill="none" stroke="black" points="102,-164 102,-195 196,-195 196,-164 102,-164"/>
-<polygon fill="yellow" stroke="transparent" points="107,-169 107,-190 147,-190 147,-169 107,-169"/>
-<polygon fill="none" stroke="black" points="107,-169 107,-190 147,-190 147,-169 107,-169"/>
-<text text-anchor="start" x="110" y="-175.8" font-family="Times,serif" font-size="14.00">True</text>
-<polygon fill="yellow" stroke="transparent" points="147,-169 147,-190 191,-190 191,-169 147,-169"/>
-<polygon fill="none" stroke="black" points="147,-169 147,-190 191,-190 191,-169 147,-169"/>
-<text text-anchor="start" x="150" y="-175.8" font-family="Times,serif" font-size="14.00">False</text>
-</g>
-<!-- If11&#45;&gt;Start2 -->
-<g id="edge7" class="edge">
-<title>If11&#45;&gt;Start2:p0</title>
-<path fill="none" stroke="red" d="M133.74,-224.23C117.53,-257.6 93.05,-308.62 84.28,-330.23"/>
-<polygon fill="red" stroke="red" points="80.86,-329.41 81,-340 87.5,-331.63 80.86,-329.41"/>
-<text text-anchor="middle" x="130.74" y="-226.83" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- If11&#45;&gt;LT10 -->
-<g id="edge8" class="edge">
-<title>If11&#45;&gt;LT10</title>
-<path fill="none" stroke="black" d="M151.23,-224.28C151.83,-232.58 152.46,-241.48 153.04,-249.56"/>
-<polygon fill="black" stroke="black" points="149.55,-249.87 153.76,-259.6 156.54,-249.37 149.55,-249.87"/>
-<text text-anchor="middle" x="148.23" y="-226.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_16 -->
-<g id="node8" class="node">
-<title>Con_16</title>
-<ellipse fill="none" stroke="black" cx="43" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="43" y="-274.3" font-family="Times,serif" font-size="14.00">2</text>
-</g>
-<!-- Mul17 -->
-<g id="node9" class="node">
-<title>Mul17</title>
-<ellipse fill="none" stroke="black" cx="49" cy="-192" rx="27" ry="18"/>
-<text text-anchor="middle" x="49" y="-188.3" font-family="Times,serif" font-size="14.00">*</text>
-</g>
-<!-- Mul17&#45;&gt;Start2 -->
-<g id="edge9" class="edge">
-<title>Mul17&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M58.46,-208.9C75.17,-237.54 108.83,-297.79 115.74,-329.91"/>
-<polygon fill="black" stroke="black" points="112.29,-330.51 117,-340 119.24,-329.64 112.29,-330.51"/>
-<text text-anchor="middle" x="55.46" y="-211.5" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Mul17&#45;&gt;Con_16 -->
-<g id="edge10" class="edge">
-<title>Mul17&#45;&gt;Con_16</title>
-<path fill="none" stroke="black" d="M47.79,-210C46.98,-221.31 45.9,-236.42 44.97,-249.43"/>
-<polygon fill="black" stroke="black" points="41.45,-249.51 44.23,-259.74 48.44,-250.01 41.45,-249.51"/>
-<text text-anchor="middle" x="44.79" y="-212.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Return18&#45;&gt;If11 -->
-<g id="edge11" class="edge">
-<title>Return18&#45;&gt;If11:p0</title>
-<path fill="none" stroke="red" d="M115.27,-124.08C119.67,-133.41 124.35,-145.54 126.19,-157.76"/>
-<polygon fill="red" stroke="red" points="122.72,-158.31 127,-168 129.7,-157.76 122.72,-158.31"/>
-<text text-anchor="middle" x="112.27" y="-126.68" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Return18&#45;&gt;Mul17 -->
-<g id="edge12" class="edge">
-<title>Return18&#45;&gt;Mul17</title>
-<path fill="none" stroke="black" d="M94.19,-124.4C85.84,-136.7 74.55,-153.35 65.34,-166.92"/>
-<polygon fill="black" stroke="black" points="62.36,-165.08 59.64,-175.32 68.15,-169.01 62.36,-165.08"/>
-<text text-anchor="middle" x="91.19" y="-127" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_20 -->
-<g id="node11" class="node">
-<title>Con_20</title>
-<ellipse fill="none" stroke="black" cx="299" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="299" y="-274.3" font-family="Times,serif" font-size="14.00">1</text>
-</g>
-<!-- Add21 -->
-<g id="node12" class="node">
-<title>Add21</title>
-<ellipse fill="none" stroke="black" cx="249" cy="-192" rx="27" ry="18"/>
-<text text-anchor="middle" x="249" y="-188.3" font-family="Times,serif" font-size="14.00">+</text>
-</g>
-<!-- Add21&#45;&gt;Mul8 -->
-<g id="edge13" class="edge">
-<title>Add21&#45;&gt;Mul8</title>
-<path fill="none" stroke="black" d="M244.55,-210C241.54,-221.5 237.49,-236.93 234.05,-250.08"/>
-<polygon fill="black" stroke="black" points="230.59,-249.47 231.45,-260.03 237.36,-251.24 230.59,-249.47"/>
-<text text-anchor="middle" x="241.55" y="-212.6" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Add21&#45;&gt;Con_20 -->
-<g id="edge14" class="edge">
-<title>Add21&#45;&gt;Con_20</title>
-<path fill="none" stroke="black" d="M258.64,-209.2C265.9,-221.4 275.99,-238.34 284.26,-252.24"/>
-<polygon fill="black" stroke="black" points="281.27,-254.05 289.39,-260.85 287.28,-250.47 281.27,-254.05"/>
-<text text-anchor="middle" x="255.64" y="-211.8" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Return24&#45;&gt;If11 -->
-<g id="edge15" class="edge">
-<title>Return24&#45;&gt;If11:p1</title>
-<path fill="none" stroke="red" d="M180.73,-124.08C176.33,-133.41 171.65,-145.54 169.81,-157.76"/>
-<polygon fill="red" stroke="red" points="166.3,-157.76 169,-168 173.28,-158.31 166.3,-157.76"/>
-<text text-anchor="middle" x="177.73" y="-126.68" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Return24&#45;&gt;Add21 -->
-<g id="edge16" class="edge">
-<title>Return24&#45;&gt;Add21</title>
-<path fill="none" stroke="black" d="M202.22,-124.4C210.86,-136.7 222.55,-153.35 232.09,-166.92"/>
-<polygon fill="black" stroke="black" points="229.37,-169.15 237.98,-175.32 235.1,-165.12 229.37,-169.15"/>
-<text text-anchor="middle" x="199.22" y="-127" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-</g>
-</svg>
+<svg aria-label="Compiler graph" width="847" height="572" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 847 572" style="font-family: sans-serif;"><style>
+ html, body { height:100%; margin:0; font-family:sans-serif; }
+ .viewer { height:100%; display:grid; grid-template-rows:auto minmax(0,1fr) auto; }
+ .source { padding:8px; border-bottom:1px solid #ccc; }
+ #program { width:min(600px,80vw); vertical-align:middle; }
+ #status { margin-top:4px; }
+ #graph { min-height:0; overflow:hidden; position:relative; background:#fafbfc; }
+ #elk { width:100%; height:100%; }
+ #graph svg { display:block; }
+ .tools { display:flex; flex-wrap:wrap; align-items:center; gap:14px; margin-top:8px; font-size:12px; }
+ .hint { color:#616c78; }
+ .ctrl { color:#b63838; } .mem { color:#2867b2; } .data { color:#536477; }
+ .edge { fill:none; stroke-width:1.5; }
+ .edge.CTRL { stroke-width:2; }
+ .edge.ASSOC { stroke-dasharray:4 4; }
+ .edge.PARSER { stroke-dasharray:5 4; }
+ .parser rect { fill:#f6f0ff; stroke:#7956a5; stroke-width:1.5; stroke-dasharray:5 4; }
+ .edge.selected { stroke-width:3.5; }
+ .edge.bundle { stroke-width:4; }
+ .edge.bundle.selected { stroke-width:6; }
+ .edge-hit { fill:none; stroke:transparent; stroke-width:12; vector-effect:non-scaling-stroke; pointer-events:stroke; cursor:pointer; }
+ .edge-jump { fill:transparent; pointer-events:all; cursor:pointer; }
+ .node { cursor:pointer; }
+ .box { stroke:#758191; stroke-width:1; }
+ .node.held .box { stroke-dasharray:5 3; }
+ .node.near .box { stroke:#c18221; stroke-width:2; }
+ .node.focus .box { stroke:#9c4900; stroke-width:3; }
+ .node.selected .box { stroke:#1569b9; stroke-width:3; }
+ .node.folded .box { stroke-width:4; }
+ .node.folding .box { fill:#f4ccd7; }
+ .fold-tag { font-size:9px; font-weight:700; fill:#963751; }
+ .peep-area { fill:#fff3d9; fill-opacity:.8; stroke:#c18221; stroke-width:2; pointer-events:none; }
+ .node.peep-edit .box { stroke:#9c4900; stroke-width:3; }
+ .node.error .box { stroke:#b42318; stroke-width:4; }
+ #event.error { color:#b42318; font-weight:600; white-space:pre-wrap; overflow-wrap:anywhere; }
+ .peep-ghosts { pointer-events:none; }
+ .region-box { stroke:#9da9b8; stroke-width:1.5; }
+ .fold-btn { cursor:pointer; }
+ .fold-btn rect { fill:white; stroke:#596674; }
+ .fold-btn text { font-size:14px; fill:#152330; }
+ .fold-btn:focus rect { stroke:#1569b9; stroke-width:2; }
+ .shortcut { cursor:pointer; }
+ .shortcut path { fill:none; stroke-width:1.5; }
+ .shortcut rect { fill:#fff8ec; stroke:#b63838; stroke-dasharray:3 2; }
+ .shortcut text { font-size:11px; fill:#783030; }
+ .shortcut.selected rect, .shortcut:focus rect { stroke-width:2.5; }
+ .label { font-size:12px; fill:#152330; font-weight:600; }
+ .node-id { font-size:10px; fill:#596674; font-weight:400; }
+ .type { font-size:11px; fill:#455768; }
+ .port { stroke:#536477; stroke-width:1; }
+ .row { stroke:#b6afcf; stroke-width:1; }
+ .bind { font-size:12px; fill:#152330; }
+ .slot { font-size:10px; fill:#364352; paint-order:stroke; stroke:#fafbfc; stroke-width:3; }
+ #detail { position:absolute; top:8px; right:8px; margin:0; padding:12px; max-width:320px;
+ max-height:45%; overflow:auto; white-space:pre-wrap; overflow-wrap:anywhere;
+ background:#fffffff2; border:1px solid #bac5d0; border-radius:4px; font-size:12px; }
+ .controls { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:6px; padding:6px; }
+ .button { color:white; background:black; font-size:20px; min-width:30px; }
+ .button:disabled { background:grey; }
+ .count { font-size:20px; min-width:35px; text-align:center; }
+ #N { width:6ch; }
+ #scrub { width:clamp(120px,35vw,600px); }
+ </style><defs><marker id="arrow-CTRL" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#b63838"/></marker><marker id="arrow-DATA" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#536477"/></marker><marker id="arrow-MEM" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#2867b2"/></marker><marker id="arrow-ASSOC" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#9396a3"/></marker><marker id="arrow-PARSER" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#7956a5"/></marker></defs><rect width="100%" height="100%" fill="rgb(250, 251, 252)"/><g><g class="regions" style="opacity: 1;"/><rect class="peep-area" rx="36" style="opacity: 0;"/><g class="edges"><path class="edge CTRL" id="e3i0" d="M236,471 C236,495 411.5,498 411.5,522" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[0] → #18 · CTRL</title></path><path class="edge CTRL" id="e3i1" d="M388,471 C388,495 435.5,498 435.5,522" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[1] → #24 · CTRL</title></path><path class="edge DATA" id="e8i1" d="M356,118 L356,138 L611,138 L611,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#8[1] → #4 · DATA</title></path><path class="edge DATA" id="e8i2" d="M666,118 L666,128 L641,128 L641,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#8[2] → #7 · DATA</title></path><path class="edge DATA" id="e10i1" d="M356,118 L356,138 L307,138 L307,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#10[1] → #4 · DATA</title></path><path class="edge DATA" id="e10i2" d="M84,118 L84,148 L337,148 L337,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#10[2] → #9 · DATA</title></path><path class="edge CTRL" id="e11i0" d="M236,118 L236,270" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#11[0] → #1 · CTRL</title></path><path class="edge DATA" id="e11i1" d="M307,222 L307,232 L316,232 L316,270" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#11[1] → #10 · DATA</title></path><path class="edge DATA" id="e17i1" d="M356,118 L356,138 L459,138 L459,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#17[1] → #4 · DATA</title></path><path class="edge DATA" id="e17i2" d="M514,118 L514,128 L489,128 L489,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#17[2] → #16 · DATA</title></path><path class="edge CTRL" id="e18i0" d="M216,370 L216,418" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#18[0] → #5 · CTRL</title></path><path class="edge DATA" id="e18i1" d="M459,222 L459,380 L256,380 L256,418" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#18[1] → #17 · DATA</title></path><path class="edge DATA" id="e21i1" d="M611,222 L611,284.6666666666667" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#21[1] → #8 · DATA</title></path><path class="edge DATA" id="e21i2" d="M763,222 L763,232 L641,232 L641,284.6666666666667" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#21[2] → #20 · DATA</title></path><path class="edge CTRL" id="e24i0" d="M336,370 L336,390 L368,390 L368,418" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#24[0] → #6 · CTRL</title></path><path class="edge DATA" id="e24i1" d="M611,340.6666666666667 L611,390 L408,390 L408,418" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#24[1] → #21 · DATA</title></path></g><g class="edge-hits"/><g class="parser" style="opacity: 1;"/><g class="nodes"><g class="node" id="n1" data-id="1" transform="translate(176,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>$ctrl</tspan><tspan class="node-id">  #1/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#1 $ctrl
+Projection 0 of #2
+Type not computed
+
+[0] → #2 CTRL</title></g><g class="node" id="n2" data-id="2" transform="translate(176,24)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>Start</tspan><tspan class="node-id">  #2</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#2 Start
+Type not computed
+
+</title></g><g class="node" id="n3" data-id="3" transform="translate(387.5,522)" style="opacity: 1;"><path class="box" d="M0,0H72V26H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="36" y="17"><tspan>Stop</tspan><tspan class="node-id">  #3</tspan></text><text class="type" text-anchor="middle" y="35" x="36"/><title>#3 Stop
+Type not computed
+
+[0] → #18 CTRL
+[1] → #24 CTRL</title><circle class="port" cx="24" cy="0" r="3" fill="#536477"/><circle class="port" cx="48" cy="0" r="3" fill="#536477"/><text class="slot" x="24" y="-7" text-anchor="middle">0</text><text class="slot" x="48" y="-7" text-anchor="middle">1</text></g><g class="node" id="n4" data-id="4" transform="translate(296,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>arg</tspan><tspan class="node-id">  #4/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#4 arg
+Projection 1 of #2
+Type not computed
+
+[0] → #2 DATA</title></g><g class="node" id="n5" data-id="5" transform="translate(156,320)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>True</tspan><tspan class="node-id">  #5/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#5 True
+Projection 0 of #11
+Type not computed
+
+[0] → #11 CTRL</title></g><g class="node" id="n6" data-id="6" transform="translate(276,320)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>False</tspan><tspan class="node-id">  #6/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#6 False
+Projection 1 of #11
+Type not computed
+
+[0] → #11 CTRL</title></g><g class="node" id="n7" data-id="7" transform="translate(606,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>2</tspan><tspan class="node-id">  #7</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#7 2
+Type not computed
+
+</title></g><g class="node" id="n8" data-id="8" transform="translate(551,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>*</tspan><tspan class="node-id">  #8</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#8 *
+Type not computed
+
+[0] → — DATA
+[1] → #4 DATA
+[2] → #7 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n9" data-id="9" transform="translate(24,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>10</tspan><tspan class="node-id">  #9</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#9 10
+Type not computed
+
+</title></g><g class="node" id="n10" data-id="10" transform="translate(247,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>&lt;</tspan><tspan class="node-id">  #10</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#10 &lt;
+Type not computed
+
+[0] → — DATA
+[1] → #4 DATA
+[2] → #9 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n11" data-id="11" transform="translate(156,276)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>If</tspan><tspan class="node-id">  #11</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#11 If
+Type not computed
+
+[0] → #1 CTRL
+[1] → #10 DATA</title><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><circle class="port" cx="160" cy="-3" r="3" fill="#536477"/><text class="slot" x="80" y="-10" text-anchor="middle">0</text><text class="slot" x="160" y="-10" text-anchor="middle">1</text></g><g class="node" id="n16" data-id="16" transform="translate(454,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>2</tspan><tspan class="node-id">  #16</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#16 2
+Type not computed
+
+</title></g><g class="node" id="n17" data-id="17" transform="translate(399,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>*</tspan><tspan class="node-id">  #17</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#17 *
+Type not computed
+
+[0] → — DATA
+[1] → #4 DATA
+[2] → #16 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n18" data-id="18" transform="translate(176,424)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #18</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#18 Return
+Type not computed
+
+[0] → #5 CTRL
+[1] → #17 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g><g class="node" id="n20" data-id="20" transform="translate(703,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>1</tspan><tspan class="node-id">  #20</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#20 1
+Type not computed
+
+</title></g><g class="node" id="n21" data-id="21" transform="translate(551,290.6666666666667)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>+</tspan><tspan class="node-id">  #21</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#21 +
+Type not computed
+
+[0] → — DATA
+[1] → #8 DATA
+[2] → #20 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n24" data-id="24" transform="translate(328,424)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #24</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#24 Return
+Type not computed
+
+[0] → #6 CTRL
+[1] → #21 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g></g><g class="region-heads" style="opacity: 1;"/><g class="shortcuts" style="opacity: 1;"/><g class="peep-ghosts" pointer-events="none"/></g></svg>
diff --git a/chapter09/docs/09-graph2.json b/chapter09/docs/09-graph2.json
new file mode 100644
index 00000000..5b449041
--- /dev/null
+++ b/chapter09/docs/09-graph2.json
@@ -0,0 +1,26 @@
+{
+ "ver": 1,
+ "comp": "chapter09/docs/09-graph2.svg",
+ "step": 1,
+ "roots": [],
+ "scope": 0,
+ "nodes": [
+ {"id": 1, "label": "$ctrl", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 2, "role": "CTRL", "label": null}], "proj": {"par": 2, "idx": 0}},
+ {"id": 2, "label": "Start", "type": null, "kind": "CTRL", "edges": [], "proj": null},
+ {"id": 3, "label": "Stop", "type": null, "kind": "STOP", "edges": [{"idx": 0, "def": 18, "role": "CTRL", "label": null}, {"idx": 1, "def": 24, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 4, "label": "arg", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 2, "role": "DATA", "label": null}], "proj": {"par": 2, "idx": 1}},
+ {"id": 5, "label": "True", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 11, "role": "CTRL", "label": null}], "proj": {"par": 11, "idx": 0}},
+ {"id": 6, "label": "False", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 11, "role": "CTRL", "label": null}], "proj": {"par": 11, "idx": 1}},
+ {"id": 7, "label": "#2", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 8, "label": "*", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 7, "role": "DATA", "label": null}], "proj": null},
+ {"id": 9, "label": "<", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 10, "role": "DATA", "label": null}], "proj": null},
+ {"id": 10, "label": "#10", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 11, "label": "If", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 1, "role": "CTRL", "label": null}, {"idx": 1, "def": 9, "role": "DATA", "label": null}], "proj": null},
+ {"id": 18, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 5, "role": "CTRL", "label": null}, {"idx": 1, "def": 8, "role": "DATA", "label": null}], "proj": null},
+ {"id": 20, "label": "+", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 8, "role": "DATA", "label": null}, {"idx": 2, "def": 21, "role": "DATA", "label": null}], "proj": null},
+ {"id": 21, "label": "#1", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 24, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 6, "role": "CTRL", "label": null}, {"idx": 1, "def": 20, "role": "DATA", "label": null}], "proj": null}
+ ],
+ "groups": [
+ ]
+}
diff --git a/chapter09/docs/09-graph2.svg b/chapter09/docs/09-graph2.svg
index 111ec172..a2484f5c 100644
--- a/chapter09/docs/09-graph2.svg
+++ b/chapter09/docs/09-graph2.svg
@@ -1,196 +1,122 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.43.0 (0)
- -->
-<!-- Title: chapter09 Pages: 1 -->
-<svg width="289pt" height="420pt"
- viewBox="0.00 0.00 289.00 420.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 416)">
-<title>chapter09</title>
-<polygon fill="white" stroke="transparent" points="-4,4 -4,-416 285,-416 285,4 -4,4"/>
-<g id="clust1" class="cluster">
-<title>cluster_Nodes</title>
-<polygon fill="none" stroke="black" points="8,-8 8,-404 273,-404 273,-8 8,-8"/>
-</g>
-<!-- Start2 -->
-<g id="node1" class="node">
-<title>Start2</title>
-<polygon fill="yellow" stroke="transparent" points="97,-367 97,-392 178,-392 178,-367 97,-367"/>
-<polygon fill="none" stroke="black" points="97,-367 97,-392 178,-392 178,-367 97,-367"/>
-<text text-anchor="start" x="119" y="-375.8" font-family="Times,serif" font-size="14.00">Start</text>
-<polygon fill="none" stroke="black" points="97,-336 97,-367 178,-367 178,-336 97,-336"/>
-<polygon fill="yellow" stroke="transparent" points="102,-341 102,-362 142,-362 142,-341 102,-341"/>
-<polygon fill="none" stroke="black" points="102,-341 102,-362 142,-362 142,-341 102,-341"/>
-<text text-anchor="start" x="105" y="-347.8" font-family="Times,serif" font-size="14.00">$ctrl</text>
-<polygon fill="none" stroke="black" points="142,-341 142,-362 173,-362 173,-341 142,-341"/>
-<text text-anchor="start" x="145" y="-347.8" font-family="Times,serif" font-size="14.00">arg</text>
-</g>
-<!-- Stop3 -->
-<g id="node2" class="node">
-<title>Stop3</title>
-<polygon fill="yellow" stroke="black" points="164,-52 110,-52 110,-16 164,-16 164,-52"/>
-<text text-anchor="middle" x="137" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text>
-</g>
-<!-- Return18 -->
-<g id="node8" class="node">
-<title>Return18</title>
-<polygon fill="yellow" stroke="black" points="128,-124 62,-124 62,-88 128,-88 128,-124"/>
-<text text-anchor="middle" x="95" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return18 -->
-<g id="edge1" class="edge">
-<title>Stop3&#45;&gt;Return18</title>
-<path fill="none" stroke="red" d="M126.62,-52.3C121.74,-60.44 115.81,-70.31 110.42,-79.3"/>
-<polygon fill="red" stroke="red" points="107.41,-77.52 105.26,-87.9 113.41,-81.12 107.41,-77.52"/>
-<text text-anchor="middle" x="123.62" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Return24 -->
-<g id="node11" class="node">
-<title>Return24</title>
-<polygon fill="yellow" stroke="black" points="212,-124 146,-124 146,-88 212,-88 212,-124"/>
-<text text-anchor="middle" x="179" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return24 -->
-<g id="edge2" class="edge">
-<title>Stop3&#45;&gt;Return24</title>
-<path fill="none" stroke="red" d="M147.38,-52.3C152.26,-60.44 158.19,-70.31 163.58,-79.3"/>
-<polygon fill="red" stroke="red" points="160.59,-81.12 168.74,-87.9 166.59,-77.52 160.59,-81.12"/>
-<text text-anchor="middle" x="144.38" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_7 -->
-<g id="node3" class="node">
-<title>Con_7</title>
-<ellipse fill="none" stroke="black" cx="43" cy="-364" rx="27" ry="18"/>
-<text text-anchor="middle" x="43" y="-360.3" font-family="Times,serif" font-size="14.00">#2</text>
-</g>
-<!-- Mul8 -->
-<g id="node4" class="node">
-<title>Mul8</title>
-<ellipse fill="none" stroke="black" cx="94" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="94" y="-274.3" font-family="Times,serif" font-size="14.00">*</text>
-</g>
-<!-- Mul8&#45;&gt;Start2 -->
-<g id="edge3" class="edge">
-<title>Mul8&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M116.03,-288.88C131.86,-297.42 151.32,-311.35 156.62,-330.09"/>
-<polygon fill="black" stroke="black" points="153.15,-330.58 158,-340 160.08,-329.61 153.15,-330.58"/>
-<text text-anchor="middle" x="119.03" y="-291.48" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Mul8&#45;&gt;Con_7 -->
-<g id="edge4" class="edge">
-<title>Mul8&#45;&gt;Con_7</title>
-<path fill="none" stroke="black" d="M84.17,-295.2C76.71,-307.48 66.34,-324.56 57.87,-338.51"/>
-<polygon fill="black" stroke="black" points="54.83,-336.77 52.63,-347.14 60.81,-340.41 54.83,-336.77"/>
-<text text-anchor="middle" x="81.17" y="-297.8" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- LT9 -->
-<g id="node5" class="node">
-<title>LT9</title>
-<ellipse fill="none" stroke="black" cx="166" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="166" y="-274.3" font-family="Times,serif" font-size="14.00">&lt;</text>
-</g>
-<!-- LT9&#45;&gt;Start2 -->
-<g id="edge5" class="edge">
-<title>LT9&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M162.56,-296.01C160.87,-305.54 159.04,-317.9 158.32,-329.98"/>
-<polygon fill="black" stroke="black" points="154.82,-329.89 158,-340 161.81,-330.12 154.82,-329.89"/>
-<text text-anchor="middle" x="159.56" y="-298.61" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_10 -->
-<g id="node6" class="node">
-<title>Con_10</title>
-<ellipse fill="none" stroke="black" cx="234" cy="-364" rx="30.59" ry="18"/>
-<text text-anchor="middle" x="234" y="-360.3" font-family="Times,serif" font-size="14.00">#10</text>
-</g>
-<!-- LT9&#45;&gt;Con_10 -->
-<g id="edge6" class="edge">
-<title>LT9&#45;&gt;Con_10</title>
-<path fill="none" stroke="black" d="M178.47,-294.41C188.66,-307 203.24,-325 214.9,-339.41"/>
-<polygon fill="black" stroke="black" points="212.36,-341.84 221.38,-347.41 217.8,-337.43 212.36,-341.84"/>
-<text text-anchor="middle" x="175.47" y="-297.01" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- If11 -->
-<g id="node7" class="node">
-<title>If11</title>
-<polygon fill="yellow" stroke="transparent" points="91,-195 91,-220 185,-220 185,-195 91,-195"/>
-<polygon fill="none" stroke="black" points="91,-195 91,-220 185,-220 185,-195 91,-195"/>
-<text text-anchor="start" x="132.5" y="-203.8" font-family="Times,serif" font-size="14.00">If</text>
-<polygon fill="none" stroke="black" points="91,-164 91,-195 185,-195 185,-164 91,-164"/>
-<polygon fill="yellow" stroke="transparent" points="96,-169 96,-190 136,-190 136,-169 96,-169"/>
-<polygon fill="none" stroke="black" points="96,-169 96,-190 136,-190 136,-169 96,-169"/>
-<text text-anchor="start" x="99" y="-175.8" font-family="Times,serif" font-size="14.00">True</text>
-<polygon fill="yellow" stroke="transparent" points="136,-169 136,-190 180,-190 180,-169 136,-169"/>
-<polygon fill="none" stroke="black" points="136,-169 136,-190 180,-190 180,-169 136,-169"/>
-<text text-anchor="start" x="139" y="-175.8" font-family="Times,serif" font-size="14.00">False</text>
-</g>
-<!-- If11&#45;&gt;Start2 -->
-<g id="edge7" class="edge">
-<title>If11&#45;&gt;Start2:p0</title>
-<path fill="none" stroke="red" d="M87.32,-224.07C75.52,-233.97 64.51,-246.05 58,-260 51.23,-274.5 52.79,-280.87 58,-296 59.97,-301.73 80.37,-332.08 92.9,-345.08"/>
-<polygon fill="red" stroke="red" points="90.86,-347.92 101,-351 94.99,-342.27 90.86,-347.92"/>
-<text text-anchor="middle" x="84.32" y="-226.67" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- If11&#45;&gt;LT9 -->
-<g id="edge8" class="edge">
-<title>If11&#45;&gt;LT9</title>
-<path fill="none" stroke="black" d="M148.43,-224.28C151.3,-232.9 154.39,-242.17 157.16,-250.49"/>
-<polygon fill="black" stroke="black" points="153.87,-251.69 160.36,-260.07 160.51,-249.48 153.87,-251.69"/>
-<text text-anchor="middle" x="145.43" y="-226.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Return18&#45;&gt;Mul8 -->
-<g id="edge10" class="edge">
-<title>Return18&#45;&gt;Mul8</title>
-<path fill="none" stroke="black" d="M86.28,-124.17C81.63,-134.31 76.38,-147.56 74,-160 68.67,-187.94 68.9,-196.02 74,-224 75.67,-233.18 78.85,-242.83 82.19,-251.35"/>
-<polygon fill="black" stroke="black" points="79.03,-252.85 86.11,-260.73 85.49,-250.15 79.03,-252.85"/>
-<text text-anchor="middle" x="83.28" y="-126.77" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Return18&#45;&gt;If11 -->
-<g id="edge9" class="edge">
-<title>Return18&#45;&gt;If11:p0</title>
-<path fill="none" stroke="red" d="M104.27,-124.08C108.67,-133.41 113.35,-145.54 115.19,-157.76"/>
-<polygon fill="red" stroke="red" points="111.72,-158.31 116,-168 118.7,-157.76 111.72,-158.31"/>
-<text text-anchor="middle" x="101.27" y="-126.68" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Add20 -->
-<g id="node9" class="node">
-<title>Add20</title>
-<ellipse fill="none" stroke="black" cx="238" cy="-192" rx="27" ry="18"/>
-<text text-anchor="middle" x="238" y="-188.3" font-family="Times,serif" font-size="14.00">+</text>
-</g>
-<!-- Add20&#45;&gt;Mul8 -->
-<g id="edge11" class="edge">
-<title>Add20&#45;&gt;Mul8</title>
-<path fill="none" stroke="black" d="M223.27,-207.18C217,-212.81 209.43,-219.09 202,-224 194.96,-228.65 153.81,-248.53 124.4,-262.57"/>
-<polygon fill="black" stroke="black" points="122.84,-259.44 115.32,-266.9 125.85,-265.75 122.84,-259.44"/>
-<text text-anchor="middle" x="220.27" y="-209.78" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_21 -->
-<g id="node10" class="node">
-<title>Con_21</title>
-<ellipse fill="none" stroke="black" cx="238" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="238" y="-274.3" font-family="Times,serif" font-size="14.00">#1</text>
-</g>
-<!-- Add20&#45;&gt;Con_21 -->
-<g id="edge12" class="edge">
-<title>Add20&#45;&gt;Con_21</title>
-<path fill="none" stroke="black" d="M238,-210.4C238,-221.74 238,-236.77 238,-249.68"/>
-<polygon fill="black" stroke="black" points="234.5,-249.9 238,-259.9 241.5,-249.9 234.5,-249.9"/>
-<text text-anchor="middle" x="235" y="-213" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Return24&#45;&gt;If11 -->
-<g id="edge13" class="edge">
-<title>Return24&#45;&gt;If11:p1</title>
-<path fill="none" stroke="red" d="M169.73,-124.08C165.33,-133.41 160.65,-145.54 158.81,-157.76"/>
-<polygon fill="red" stroke="red" points="155.3,-157.76 158,-168 162.28,-158.31 155.3,-157.76"/>
-<text text-anchor="middle" x="166.73" y="-126.68" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Return24&#45;&gt;Add20 -->
-<g id="edge14" class="edge">
-<title>Return24&#45;&gt;Add20</title>
-<path fill="none" stroke="black" d="M191.22,-124.4C199.86,-136.7 211.55,-153.35 221.09,-166.92"/>
-<polygon fill="black" stroke="black" points="218.37,-169.15 226.98,-175.32 224.1,-165.12 218.37,-169.15"/>
-<text text-anchor="middle" x="188.22" y="-127" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-</g>
-</svg>
+<svg aria-label="Compiler graph" width="618" height="572" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 618 572" style="font-family: sans-serif;"><style>
+ html, body { height:100%; margin:0; font-family:sans-serif; }
+ .viewer { height:100%; display:grid; grid-template-rows:auto minmax(0,1fr) auto; }
+ .source { padding:8px; border-bottom:1px solid #ccc; }
+ #program { width:min(600px,80vw); vertical-align:middle; }
+ #status { margin-top:4px; }
+ #graph { min-height:0; overflow:hidden; position:relative; background:#fafbfc; }
+ #elk { width:100%; height:100%; }
+ #graph svg { display:block; }
+ .tools { display:flex; flex-wrap:wrap; align-items:center; gap:14px; margin-top:8px; font-size:12px; }
+ .hint { color:#616c78; }
+ .ctrl { color:#b63838; } .mem { color:#2867b2; } .data { color:#536477; }
+ .edge { fill:none; stroke-width:1.5; }
+ .edge.CTRL { stroke-width:2; }
+ .edge.ASSOC { stroke-dasharray:4 4; }
+ .edge.PARSER { stroke-dasharray:5 4; }
+ .parser rect { fill:#f6f0ff; stroke:#7956a5; stroke-width:1.5; stroke-dasharray:5 4; }
+ .edge.selected { stroke-width:3.5; }
+ .edge.bundle { stroke-width:4; }
+ .edge.bundle.selected { stroke-width:6; }
+ .edge-hit { fill:none; stroke:transparent; stroke-width:12; vector-effect:non-scaling-stroke; pointer-events:stroke; cursor:pointer; }
+ .edge-jump { fill:transparent; pointer-events:all; cursor:pointer; }
+ .node { cursor:pointer; }
+ .box { stroke:#758191; stroke-width:1; }
+ .node.held .box { stroke-dasharray:5 3; }
+ .node.near .box { stroke:#c18221; stroke-width:2; }
+ .node.focus .box { stroke:#9c4900; stroke-width:3; }
+ .node.selected .box { stroke:#1569b9; stroke-width:3; }
+ .node.folded .box { stroke-width:4; }
+ .node.folding .box { fill:#f4ccd7; }
+ .fold-tag { font-size:9px; font-weight:700; fill:#963751; }
+ .peep-area { fill:#fff3d9; fill-opacity:.8; stroke:#c18221; stroke-width:2; pointer-events:none; }
+ .node.peep-edit .box { stroke:#9c4900; stroke-width:3; }
+ .node.error .box { stroke:#b42318; stroke-width:4; }
+ #event.error { color:#b42318; font-weight:600; white-space:pre-wrap; overflow-wrap:anywhere; }
+ .peep-ghosts { pointer-events:none; }
+ .region-box { stroke:#9da9b8; stroke-width:1.5; }
+ .fold-btn { cursor:pointer; }
+ .fold-btn rect { fill:white; stroke:#596674; }
+ .fold-btn text { font-size:14px; fill:#152330; }
+ .fold-btn:focus rect { stroke:#1569b9; stroke-width:2; }
+ .shortcut { cursor:pointer; }
+ .shortcut path { fill:none; stroke-width:1.5; }
+ .shortcut rect { fill:#fff8ec; stroke:#b63838; stroke-dasharray:3 2; }
+ .shortcut text { font-size:11px; fill:#783030; }
+ .shortcut.selected rect, .shortcut:focus rect { stroke-width:2.5; }
+ .label { font-size:12px; fill:#152330; font-weight:600; }
+ .node-id { font-size:10px; fill:#596674; font-weight:400; }
+ .type { font-size:11px; fill:#455768; }
+ .port { stroke:#536477; stroke-width:1; }
+ .row { stroke:#b6afcf; stroke-width:1; }
+ .bind { font-size:12px; fill:#152330; }
+ .slot { font-size:10px; fill:#364352; paint-order:stroke; stroke:#fafbfc; stroke-width:3; }
+ #detail { position:absolute; top:8px; right:8px; margin:0; padding:12px; max-width:320px;
+ max-height:45%; overflow:auto; white-space:pre-wrap; overflow-wrap:anywhere;
+ background:#fffffff2; border:1px solid #bac5d0; border-radius:4px; font-size:12px; }
+ .controls { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:6px; padding:6px; }
+ .button { color:white; background:black; font-size:20px; min-width:30px; }
+ .button:disabled { background:grey; }
+ .count { font-size:20px; min-width:35px; text-align:center; }
+ #N { width:6ch; }
+ #scrub { width:clamp(120px,35vw,600px); }
+ </style><defs><marker id="arrow-CTRL" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#b63838"/></marker><marker id="arrow-DATA" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#536477"/></marker><marker id="arrow-MEM" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#2867b2"/></marker><marker id="arrow-ASSOC" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#9396a3"/></marker><marker id="arrow-PARSER" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#7956a5"/></marker></defs><rect width="100%" height="100%" fill="rgb(250, 251, 252)"/><g><g class="regions" style="opacity: 1;"/><rect class="peep-area" rx="36" style="opacity: 0;"/><g class="edges"><path class="edge CTRL" id="e3i0" d="M104,471 C104,495 297,498 297,522" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[0] → #18 · CTRL</title></path><path class="edge CTRL" id="e3i1" d="M256,471 C256,495 321,498 321,522" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[1] → #24 · CTRL</title></path><path class="edge DATA" id="e8i1" d="M224,118 L224,128 L336,128 L336,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#8[1] → #4 · DATA</title></path><path class="edge DATA" id="e8i2" d="M534,118 L534,148 L366,148 L366,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#8[2] → #7 · DATA</title></path><path class="edge DATA" id="e9i1" d="M224,118 L224,128 L184,128 L184,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#9[1] → #4 · DATA</title></path><path class="edge DATA" id="e9i2" d="M382,118 L382,138 L214,138 L214,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#9[2] → #10 · DATA</title></path><path class="edge CTRL" id="e11i0" d="M104,118 L104,270" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#11[0] → #1 · CTRL</title></path><path class="edge DATA" id="e11i1" d="M184,222 L184,270" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#11[1] → #9 · DATA</title></path><path class="edge CTRL" id="e18i0" d="M84,370 L84,418" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#18[0] → #5 · CTRL</title></path><path class="edge DATA" id="e18i1" d="M336,222 L336,232 L280,232 L280,380 L124,380 L124,418" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#18[1] → #8 · DATA</title></path><path class="edge DATA" id="e20i1" d="M336,222 L336,232 L351,232 L351,284.6666666666667" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#20[1] → #8 · DATA</title></path><path class="edge DATA" id="e20i2" d="M488,222 L488,232 L381,232 L381,284.6666666666667" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#20[2] → #21 · DATA</title></path><path class="edge CTRL" id="e24i0" d="M204,370 L204,390 L236,390 L236,418" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#24[0] → #6 · CTRL</title></path><path class="edge DATA" id="e24i1" d="M351,340.6666666666667 L351,390 L276,390 L276,418" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#24[1] → #20 · DATA</title></path></g><g class="edge-hits"/><g class="parser" style="opacity: 1;"/><g class="nodes"><g class="node" id="n1" data-id="1" transform="translate(44,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>$ctrl</tspan><tspan class="node-id">  #1/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#1 $ctrl
+Projection 0 of #2
+Type not computed
+
+[0] → #2 CTRL</title></g><g class="node" id="n2" data-id="2" transform="translate(44,24)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>Start</tspan><tspan class="node-id">  #2</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#2 Start
+Type not computed
+
+</title></g><g class="node" id="n3" data-id="3" transform="translate(273,522)" style="opacity: 1;"><path class="box" d="M0,0H72V26H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="36" y="17"><tspan>Stop</tspan><tspan class="node-id">  #3</tspan></text><text class="type" text-anchor="middle" y="35" x="36"/><title>#3 Stop
+Type not computed
+
+[0] → #18 CTRL
+[1] → #24 CTRL</title><circle class="port" cx="24" cy="0" r="3" fill="#536477"/><circle class="port" cx="48" cy="0" r="3" fill="#536477"/><text class="slot" x="24" y="-7" text-anchor="middle">0</text><text class="slot" x="48" y="-7" text-anchor="middle">1</text></g><g class="node" id="n4" data-id="4" transform="translate(164,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>arg</tspan><tspan class="node-id">  #4/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#4 arg
+Projection 1 of #2
+Type not computed
+
+[0] → #2 DATA</title></g><g class="node" id="n5" data-id="5" transform="translate(24,320)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>True</tspan><tspan class="node-id">  #5/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#5 True
+Projection 0 of #11
+Type not computed
+
+[0] → #11 CTRL</title></g><g class="node" id="n6" data-id="6" transform="translate(144,320)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>False</tspan><tspan class="node-id">  #6/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#6 False
+Projection 1 of #11
+Type not computed
+
+[0] → #11 CTRL</title></g><g class="node" id="n7" data-id="7" transform="translate(474,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#2</tspan><tspan class="node-id">  #7</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#7 #2
+Type not computed
+
+</title></g><g class="node" id="n8" data-id="8" transform="translate(276,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>*</tspan><tspan class="node-id">  #8</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#8 *
+Type not computed
+
+[0] → — DATA
+[1] → #4 DATA
+[2] → #7 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n9" data-id="9" transform="translate(124,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>&lt;</tspan><tspan class="node-id">  #9</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#9 &lt;
+Type not computed
+
+[0] → — DATA
+[1] → #4 DATA
+[2] → #10 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n10" data-id="10" transform="translate(322,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#10</tspan><tspan class="node-id">  #10</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#10 #10
+Type not computed
+
+</title></g><g class="node" id="n11" data-id="11" transform="translate(24,276)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>If</tspan><tspan class="node-id">  #11</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#11 If
+Type not computed
+
+[0] → #1 CTRL
+[1] → #9 DATA</title><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><circle class="port" cx="160" cy="-3" r="3" fill="#536477"/><text class="slot" x="80" y="-10" text-anchor="middle">0</text><text class="slot" x="160" y="-10" text-anchor="middle">1</text></g><g class="node" id="n18" data-id="18" transform="translate(44,424)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #18</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#18 Return
+Type not computed
+
+[0] → #5 CTRL
+[1] → #8 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g><g class="node" id="n20" data-id="20" transform="translate(291,290.6666666666667)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>+</tspan><tspan class="node-id">  #20</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#20 +
+Type not computed
+
+[0] → — DATA
+[1] → #8 DATA
+[2] → #21 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n21" data-id="21" transform="translate(428,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#1</tspan><tspan class="node-id">  #21</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#21 #1
+Type not computed
+
+</title></g><g class="node" id="n24" data-id="24" transform="translate(196,424)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #24</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#24 Return
+Type not computed
+
+[0] → #6 CTRL
+[1] → #20 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g></g><g class="region-heads" style="opacity: 1;"/><g class="shortcuts" style="opacity: 1;"/><g class="peep-ghosts" pointer-events="none"/></g></svg>
diff --git a/chapter09/docs/09-graph3.json b/chapter09/docs/09-graph3.json
new file mode 100644
index 00000000..57546e51
--- /dev/null
+++ b/chapter09/docs/09-graph3.json
@@ -0,0 +1,19 @@
+{
+ "ver": 1,
+ "comp": "chapter09/docs/09-graph3.svg",
+ "step": 1,
+ "roots": [],
+ "scope": 0,
+ "nodes": [
+ {"id": 1, "label": "$ctrl", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 2, "role": "CTRL", "label": null}], "proj": {"par": 2, "idx": 0}},
+ {"id": 2, "label": "Start", "type": null, "kind": "CTRL", "edges": [], "proj": null},
+ {"id": 3, "label": "Stop", "type": null, "kind": "STOP", "edges": [{"idx": 0, "def": 9, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 4, "label": "arg", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 2, "role": "DATA", "label": null}], "proj": {"par": 2, "idx": 1}},
+ {"id": 6, "label": "*", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 4, "role": "DATA", "label": null}], "proj": null},
+ {"id": 7, "label": "*", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 4, "role": "DATA", "label": null}], "proj": null},
+ {"id": 8, "label": "-", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 6, "role": "DATA", "label": null}, {"idx": 2, "def": 7, "role": "DATA", "label": null}], "proj": null},
+ {"id": 9, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 1, "role": "CTRL", "label": null}, {"idx": 1, "def": 8, "role": "DATA", "label": null}], "proj": null}
+ ],
+ "groups": [
+ ]
+}
diff --git a/chapter09/docs/09-graph3.svg b/chapter09/docs/09-graph3.svg
index f26c96e8..51804b59 100644
--- a/chapter09/docs/09-graph3.svg
+++ b/chapter09/docs/09-graph3.svg
@@ -1,109 +1,96 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.43.0 (0)
- -->
-<!-- Title: chapter08 Pages: 1 -->
-<svg width="186pt" height="392pt"
- viewBox="0.00 0.00 186.00 392.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 388)">
-<title>chapter08</title>
-<polygon fill="white" stroke="transparent" points="-4,4 -4,-388 182,-388 182,4 -4,4"/>
-<g id="clust1" class="cluster">
-<title>cluster_Nodes</title>
-<polygon fill="none" stroke="black" points="8,-8 8,-376 170,-376 170,-8 8,-8"/>
-</g>
-<!-- Start2 -->
-<g id="node1" class="node">
-<title>Start2</title>
-<polygon fill="yellow" stroke="transparent" points="24,-339 24,-364 105,-364 105,-339 24,-339"/>
-<polygon fill="none" stroke="black" points="24,-339 24,-364 105,-364 105,-339 24,-339"/>
-<text text-anchor="start" x="46" y="-347.8" font-family="Times,serif" font-size="14.00">Start</text>
-<polygon fill="none" stroke="black" points="24,-308 24,-339 105,-339 105,-308 24,-308"/>
-<polygon fill="yellow" stroke="transparent" points="29,-313 29,-334 69,-334 69,-313 29,-313"/>
-<polygon fill="none" stroke="black" points="29,-313 29,-334 69,-334 69,-313 29,-313"/>
-<text text-anchor="start" x="32" y="-319.8" font-family="Times,serif" font-size="14.00">$ctrl</text>
-<polygon fill="none" stroke="black" points="69,-313 69,-334 100,-334 100,-313 69,-313"/>
-<text text-anchor="start" x="72" y="-319.8" font-family="Times,serif" font-size="14.00">arg</text>
-</g>
-<!-- Stop3 -->
-<g id="node2" class="node">
-<title>Stop3</title>
-<polygon fill="yellow" stroke="black" points="83,-52 29,-52 29,-16 83,-16 83,-52"/>
-<text text-anchor="middle" x="56" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text>
-</g>
-<!-- Return9 -->
-<g id="node6" class="node">
-<title>Return9</title>
-<polygon fill="yellow" stroke="black" points="89,-124 23,-124 23,-88 89,-88 89,-124"/>
-<text text-anchor="middle" x="56" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return9 -->
-<g id="edge1" class="edge">
-<title>Stop3&#45;&gt;Return9</title>
-<path fill="none" stroke="red" d="M56,-52.3C56,-60.02 56,-69.29 56,-77.89"/>
-<polygon fill="red" stroke="red" points="52.5,-77.9 56,-87.9 59.5,-77.9 52.5,-77.9"/>
-<text text-anchor="middle" x="53" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Mul6 -->
-<g id="node3" class="node">
-<title>Mul6</title>
-<ellipse fill="none" stroke="black" cx="63" cy="-250" rx="27" ry="18"/>
-<text text-anchor="middle" x="63" y="-246.3" font-family="Times,serif" font-size="14.00">*</text>
-</g>
-<!-- Mul6&#45;&gt;Start2 -->
-<g id="edge2" class="edge">
-<title>Mul6&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M72.2,-267.01C76.96,-276.47 82.18,-289.06 84.17,-301.8"/>
-<polygon fill="black" stroke="black" points="80.7,-302.32 85,-312 87.67,-301.75 80.7,-302.32"/>
-<text text-anchor="middle" x="69.2" y="-269.61" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Mul7 -->
-<g id="node4" class="node">
-<title>Mul7</title>
-<ellipse fill="none" stroke="black" cx="135" cy="-250" rx="27" ry="18"/>
-<text text-anchor="middle" x="135" y="-246.3" font-family="Times,serif" font-size="14.00">*</text>
-</g>
-<!-- Mul7&#45;&gt;Start2 -->
-<g id="edge4" class="edge">
-<title>Mul7&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M116.38,-263.15C104.61,-272.17 90.81,-285.67 86.42,-301.7"/>
-<polygon fill="black" stroke="black" points="82.9,-301.62 85,-312 89.83,-302.57 82.9,-301.62"/>
-<text text-anchor="middle" x="113.38" y="-265.75" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Sub8 -->
-<g id="node5" class="node">
-<title>Sub8</title>
-<ellipse fill="none" stroke="black" cx="63" cy="-178" rx="27" ry="18"/>
-<text text-anchor="middle" x="63" y="-174.3" font-family="Times,serif" font-size="14.00">&#45;</text>
-</g>
-<!-- Sub8&#45;&gt;Mul6 -->
-<g id="edge6" class="edge">
-<title>Sub8&#45;&gt;Mul6</title>
-<path fill="none" stroke="black" d="M63,-196.3C63,-204.02 63,-213.29 63,-221.89"/>
-<polygon fill="black" stroke="black" points="59.5,-221.9 63,-231.9 66.5,-221.9 59.5,-221.9"/>
-<text text-anchor="middle" x="60" y="-198.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Sub8&#45;&gt;Mul7 -->
-<g id="edge7" class="edge">
-<title>Sub8&#45;&gt;Mul7</title>
-<path fill="none" stroke="black" d="M77.57,-193.17C87.75,-203.06 101.52,-216.45 113.03,-227.64"/>
-<polygon fill="black" stroke="black" points="110.59,-230.15 120.2,-234.62 115.47,-225.13 110.59,-230.15"/>
-<text text-anchor="middle" x="74.57" y="-195.77" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Return9&#45;&gt;Start2 -->
-<g id="edge8" class="edge">
-<title>Return9&#45;&gt;Start2:p0</title>
-<path fill="none" stroke="red" d="M43.69,-124.22C37.35,-134.16 30.27,-147.2 27,-160 15.11,-206.5 15.97,-221.28 27,-268 31.12,-285.46 43.28,-289.17 47.52,-302.01"/>
-<polygon fill="red" stroke="red" points="44.08,-302.62 49,-312 51,-301.6 44.08,-302.62"/>
-<text text-anchor="middle" x="40.69" y="-126.82" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Return9&#45;&gt;Sub8 -->
-<g id="edge9" class="edge">
-<title>Return9&#45;&gt;Sub8</title>
-<path fill="none" stroke="black" d="M57.73,-124.3C58.5,-132.02 59.43,-141.29 60.29,-149.89"/>
-<polygon fill="black" stroke="black" points="56.81,-150.29 61.29,-159.9 63.78,-149.6 56.81,-150.29"/>
-<text text-anchor="middle" x="54.73" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-</g>
-</svg>
+<svg aria-label="Compiler graph" width="391" height="528" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 391 528" style="font-family: sans-serif;"><style>
+ html, body { height:100%; margin:0; font-family:sans-serif; }
+ .viewer { height:100%; display:grid; grid-template-rows:auto minmax(0,1fr) auto; }
+ .source { padding:8px; border-bottom:1px solid #ccc; }
+ #program { width:min(600px,80vw); vertical-align:middle; }
+ #status { margin-top:4px; }
+ #graph { min-height:0; overflow:hidden; position:relative; background:#fafbfc; }
+ #elk { width:100%; height:100%; }
+ #graph svg { display:block; }
+ .tools { display:flex; flex-wrap:wrap; align-items:center; gap:14px; margin-top:8px; font-size:12px; }
+ .hint { color:#616c78; }
+ .ctrl { color:#b63838; } .mem { color:#2867b2; } .data { color:#536477; }
+ .edge { fill:none; stroke-width:1.5; }
+ .edge.CTRL { stroke-width:2; }
+ .edge.ASSOC { stroke-dasharray:4 4; }
+ .edge.PARSER { stroke-dasharray:5 4; }
+ .parser rect { fill:#f6f0ff; stroke:#7956a5; stroke-width:1.5; stroke-dasharray:5 4; }
+ .edge.selected { stroke-width:3.5; }
+ .edge.bundle { stroke-width:4; }
+ .edge.bundle.selected { stroke-width:6; }
+ .edge-hit { fill:none; stroke:transparent; stroke-width:12; vector-effect:non-scaling-stroke; pointer-events:stroke; cursor:pointer; }
+ .edge-jump { fill:transparent; pointer-events:all; cursor:pointer; }
+ .node { cursor:pointer; }
+ .box { stroke:#758191; stroke-width:1; }
+ .node.held .box { stroke-dasharray:5 3; }
+ .node.near .box { stroke:#c18221; stroke-width:2; }
+ .node.focus .box { stroke:#9c4900; stroke-width:3; }
+ .node.selected .box { stroke:#1569b9; stroke-width:3; }
+ .node.folded .box { stroke-width:4; }
+ .node.folding .box { fill:#f4ccd7; }
+ .fold-tag { font-size:9px; font-weight:700; fill:#963751; }
+ .peep-area { fill:#fff3d9; fill-opacity:.8; stroke:#c18221; stroke-width:2; pointer-events:none; }
+ .node.peep-edit .box { stroke:#9c4900; stroke-width:3; }
+ .node.error .box { stroke:#b42318; stroke-width:4; }
+ #event.error { color:#b42318; font-weight:600; white-space:pre-wrap; overflow-wrap:anywhere; }
+ .peep-ghosts { pointer-events:none; }
+ .region-box { stroke:#9da9b8; stroke-width:1.5; }
+ .fold-btn { cursor:pointer; }
+ .fold-btn rect { fill:white; stroke:#596674; }
+ .fold-btn text { font-size:14px; fill:#152330; }
+ .fold-btn:focus rect { stroke:#1569b9; stroke-width:2; }
+ .shortcut { cursor:pointer; }
+ .shortcut path { fill:none; stroke-width:1.5; }
+ .shortcut rect { fill:#fff8ec; stroke:#b63838; stroke-dasharray:3 2; }
+ .shortcut text { font-size:11px; fill:#783030; }
+ .shortcut.selected rect, .shortcut:focus rect { stroke-width:2.5; }
+ .label { font-size:12px; fill:#152330; font-weight:600; }
+ .node-id { font-size:10px; fill:#596674; font-weight:400; }
+ .type { font-size:11px; fill:#455768; }
+ .port { stroke:#536477; stroke-width:1; }
+ .row { stroke:#b6afcf; stroke-width:1; }
+ .bind { font-size:12px; fill:#152330; }
+ .slot { font-size:10px; fill:#364352; paint-order:stroke; stroke:#fafbfc; stroke-width:3; }
+ #detail { position:absolute; top:8px; right:8px; margin:0; padding:12px; max-width:320px;
+ max-height:45%; overflow:auto; white-space:pre-wrap; overflow-wrap:anywhere;
+ background:#fffffff2; border:1px solid #bac5d0; border-radius:4px; font-size:12px; }
+ .controls { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:6px; padding:6px; }
+ .button { color:white; background:black; font-size:20px; min-width:30px; }
+ .button:disabled { background:grey; }
+ .count { font-size:20px; min-width:35px; text-align:center; }
+ #N { width:6ch; }
+ #scrub { width:clamp(120px,35vw,600px); }
+ </style><defs><marker id="arrow-CTRL" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#b63838"/></marker><marker id="arrow-DATA" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#536477"/></marker><marker id="arrow-MEM" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#2867b2"/></marker><marker id="arrow-ASSOC" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#9396a3"/></marker><marker id="arrow-PARSER" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#7956a5"/></marker></defs><rect width="100%" height="100%" fill="rgb(250, 251, 252)"/><g><g class="regions" style="opacity: 1;"/><rect class="peep-area" rx="36" style="opacity: 0;"/><g class="edges"><path class="edge CTRL" id="e3i0" d="M104,427 C104,451 195.5,454 195.5,478" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[0] → #9 · CTRL</title></path><path class="edge DATA" id="e6i1" d="M204,118 L204,128 L155,128 L155,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#6[1] → #4 · DATA</title></path><path class="edge DATA" id="e6i2" d="M204,118 L204,128 L185,128 L185,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#6[2] → #4 · DATA</title></path><path class="edge DATA" id="e7i1" d="M204,118 L204,128 L307,128 L307,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#7[1] → #4 · DATA</title></path><path class="edge DATA" id="e7i2" d="M204,118 L204,128 L337,128 L337,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#7[2] → #4 · DATA</title></path><path class="edge DATA" id="e8i1" d="M155,222 L155,270" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#8[1] → #6 · DATA</title></path><path class="edge DATA" id="e8i2" d="M307,222 L307,232 L185,232 L185,270" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#8[2] → #7 · DATA</title></path><path class="edge CTRL" id="e9i0" d="M84,118 L84,374" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#9[0] → #1 · CTRL</title></path><path class="edge DATA" id="e9i1" d="M155,326 L155,336 L124,336 L124,374" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#9[1] → #8 · DATA</title></path></g><g class="edge-hits"/><g class="parser" style="opacity: 1;"/><g class="nodes"><g class="node" id="n1" data-id="1" transform="translate(24,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>$ctrl</tspan><tspan class="node-id">  #1/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#1 $ctrl
+Projection 0 of #2
+Type not computed
+
+[0] → #2 CTRL</title></g><g class="node" id="n2" data-id="2" transform="translate(24,24)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>Start</tspan><tspan class="node-id">  #2</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#2 Start
+Type not computed
+
+</title></g><g class="node" id="n3" data-id="3" transform="translate(159.5,478)" style="opacity: 1;"><path class="box" d="M0,0H72V26H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="36" y="17"><tspan>Stop</tspan><tspan class="node-id">  #3</tspan></text><text class="type" text-anchor="middle" y="35" x="36"/><title>#3 Stop
+Type not computed
+
+[0] → #9 CTRL</title><circle class="port" cx="36" cy="0" r="3" fill="#536477"/><text class="slot" x="36" y="-7" text-anchor="middle">0</text></g><g class="node" id="n4" data-id="4" transform="translate(144,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>arg</tspan><tspan class="node-id">  #4/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#4 arg
+Projection 1 of #2
+Type not computed
+
+[0] → #2 DATA</title></g><g class="node" id="n6" data-id="6" transform="translate(95,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>*</tspan><tspan class="node-id">  #6</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#6 *
+Type not computed
+
+[0] → — DATA
+[1] → #4 DATA
+[2] → #4 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n7" data-id="7" transform="translate(247,172)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>*</tspan><tspan class="node-id">  #7</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#7 *
+Type not computed
+
+[0] → — DATA
+[1] → #4 DATA
+[2] → #4 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n8" data-id="8" transform="translate(95,276)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>-</tspan><tspan class="node-id">  #8</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#8 -
+Type not computed
+
+[0] → — DATA
+[1] → #6 DATA
+[2] → #7 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n9" data-id="9" transform="translate(44,380)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #9</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#9 Return
+Type not computed
+
+[0] → #1 CTRL
+[1] → #8 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g></g><g class="region-heads" style="opacity: 1;"/><g class="shortcuts" style="opacity: 1;"/><g class="peep-ghosts" pointer-events="none"/></g></svg>
diff --git a/chapter09/docs/09-graph4.json b/chapter09/docs/09-graph4.json
new file mode 100644
index 00000000..accad3ff
--- /dev/null
+++ b/chapter09/docs/09-graph4.json
@@ -0,0 +1,16 @@
+{
+ "ver": 1,
+ "comp": "chapter09/docs/09-graph4.svg",
+ "step": 1,
+ "roots": [],
+ "scope": 0,
+ "nodes": [
+ {"id": 1, "label": "$ctrl", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 2, "role": "CTRL", "label": null}], "proj": {"par": 2, "idx": 0}},
+ {"id": 2, "label": "Start", "type": null, "kind": "CTRL", "edges": [], "proj": null},
+ {"id": 3, "label": "Stop", "type": null, "kind": "STOP", "edges": [{"idx": 0, "def": 10, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 9, "label": "#0", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 10, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 1, "role": "CTRL", "label": null}, {"idx": 1, "def": 9, "role": "DATA", "label": null}], "proj": null}
+ ],
+ "groups": [
+ ]
+}
diff --git a/chapter09/docs/09-graph4.svg b/chapter09/docs/09-graph4.svg
index 4eef5414..89045214 100644
--- a/chapter09/docs/09-graph4.svg
+++ b/chapter09/docs/09-graph4.svg
@@ -1,67 +1,80 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.43.0 (0)
- -->
-<!-- Title: chapter09 Pages: 1 -->
-<svg width="178pt" height="248pt"
- viewBox="0.00 0.00 178.00 248.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 244)">
-<title>chapter09</title>
-<polygon fill="white" stroke="transparent" points="-4,4 -4,-244 174,-244 174,4 -4,4"/>
-<g id="clust1" class="cluster">
-<title>cluster_Nodes</title>
-<polygon fill="none" stroke="black" points="8,-8 8,-232 162,-232 162,-8 8,-8"/>
-</g>
-<!-- Start2 -->
-<g id="node1" class="node">
-<title>Start2</title>
-<polygon fill="yellow" stroke="transparent" points="24,-195 24,-220 74,-220 74,-195 24,-195"/>
-<polygon fill="none" stroke="black" points="24,-195 24,-220 74,-220 74,-195 24,-195"/>
-<text text-anchor="start" x="30.5" y="-203.8" font-family="Times,serif" font-size="14.00">Start</text>
-<polygon fill="none" stroke="black" points="24,-164 24,-195 74,-195 74,-164 24,-164"/>
-<polygon fill="yellow" stroke="transparent" points="29,-169 29,-190 69,-190 69,-169 29,-169"/>
-<polygon fill="none" stroke="black" points="29,-169 29,-190 69,-190 69,-169 29,-169"/>
-<text text-anchor="start" x="32" y="-175.8" font-family="Times,serif" font-size="14.00">$ctrl</text>
-</g>
-<!-- Stop3 -->
-<g id="node2" class="node">
-<title>Stop3</title>
-<polygon fill="yellow" stroke="black" points="112,-52 58,-52 58,-16 112,-16 112,-52"/>
-<text text-anchor="middle" x="85" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text>
-</g>
-<!-- Return10 -->
-<g id="node4" class="node">
-<title>Return10</title>
-<polygon fill="yellow" stroke="black" points="118,-124 52,-124 52,-88 118,-88 118,-124"/>
-<text text-anchor="middle" x="85" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return10 -->
-<g id="edge1" class="edge">
-<title>Stop3&#45;&gt;Return10</title>
-<path fill="none" stroke="red" d="M85,-52.3C85,-60.02 85,-69.29 85,-77.89"/>
-<polygon fill="red" stroke="red" points="81.5,-77.9 85,-87.9 88.5,-77.9 81.5,-77.9"/>
-<text text-anchor="middle" x="82" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Con_9 -->
-<g id="node3" class="node">
-<title>Con_9</title>
-<ellipse fill="none" stroke="black" cx="127" cy="-192" rx="27" ry="18"/>
-<text text-anchor="middle" x="127" y="-188.3" font-family="Times,serif" font-size="14.00">#0</text>
-</g>
-<!-- Return10&#45;&gt;Start2 -->
-<g id="edge2" class="edge">
-<title>Return10&#45;&gt;Start2:p0</title>
-<path fill="none" stroke="red" d="M68.26,-124.13C60.77,-133.26 52.99,-145.23 50.13,-158.06"/>
-<polygon fill="red" stroke="red" points="46.66,-157.67 49,-168 53.61,-158.46 46.66,-157.67"/>
-<text text-anchor="middle" x="65.26" y="-126.73" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Return10&#45;&gt;Con_9 -->
-<g id="edge3" class="edge">
-<title>Return10&#45;&gt;Con_9</title>
-<path fill="none" stroke="black" d="M93.7,-124.4C99.66,-136.31 107.65,-152.3 114.31,-165.62"/>
-<polygon fill="black" stroke="black" points="111.28,-167.38 118.88,-174.76 117.54,-164.25 111.28,-167.38"/>
-<text text-anchor="middle" x="90.7" y="-127" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-</g>
-</svg>
+<svg aria-label="Compiler graph" width="326" height="320" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 326 320" style="font-family: sans-serif;"><style>
+ html, body { height:100%; margin:0; font-family:sans-serif; }
+ .viewer { height:100%; display:grid; grid-template-rows:auto minmax(0,1fr) auto; }
+ .source { padding:8px; border-bottom:1px solid #ccc; }
+ #program { width:min(600px,80vw); vertical-align:middle; }
+ #status { margin-top:4px; }
+ #graph { min-height:0; overflow:hidden; position:relative; background:#fafbfc; }
+ #elk { width:100%; height:100%; }
+ #graph svg { display:block; }
+ .tools { display:flex; flex-wrap:wrap; align-items:center; gap:14px; margin-top:8px; font-size:12px; }
+ .hint { color:#616c78; }
+ .ctrl { color:#b63838; } .mem { color:#2867b2; } .data { color:#536477; }
+ .edge { fill:none; stroke-width:1.5; }
+ .edge.CTRL { stroke-width:2; }
+ .edge.ASSOC { stroke-dasharray:4 4; }
+ .edge.PARSER { stroke-dasharray:5 4; }
+ .parser rect { fill:#f6f0ff; stroke:#7956a5; stroke-width:1.5; stroke-dasharray:5 4; }
+ .edge.selected { stroke-width:3.5; }
+ .edge.bundle { stroke-width:4; }
+ .edge.bundle.selected { stroke-width:6; }
+ .edge-hit { fill:none; stroke:transparent; stroke-width:12; vector-effect:non-scaling-stroke; pointer-events:stroke; cursor:pointer; }
+ .edge-jump { fill:transparent; pointer-events:all; cursor:pointer; }
+ .node { cursor:pointer; }
+ .box { stroke:#758191; stroke-width:1; }
+ .node.held .box { stroke-dasharray:5 3; }
+ .node.near .box { stroke:#c18221; stroke-width:2; }
+ .node.focus .box { stroke:#9c4900; stroke-width:3; }
+ .node.selected .box { stroke:#1569b9; stroke-width:3; }
+ .node.folded .box { stroke-width:4; }
+ .node.folding .box { fill:#f4ccd7; }
+ .fold-tag { font-size:9px; font-weight:700; fill:#963751; }
+ .peep-area { fill:#fff3d9; fill-opacity:.8; stroke:#c18221; stroke-width:2; pointer-events:none; }
+ .node.peep-edit .box { stroke:#9c4900; stroke-width:3; }
+ .node.error .box { stroke:#b42318; stroke-width:4; }
+ #event.error { color:#b42318; font-weight:600; white-space:pre-wrap; overflow-wrap:anywhere; }
+ .peep-ghosts { pointer-events:none; }
+ .region-box { stroke:#9da9b8; stroke-width:1.5; }
+ .fold-btn { cursor:pointer; }
+ .fold-btn rect { fill:white; stroke:#596674; }
+ .fold-btn text { font-size:14px; fill:#152330; }
+ .fold-btn:focus rect { stroke:#1569b9; stroke-width:2; }
+ .shortcut { cursor:pointer; }
+ .shortcut path { fill:none; stroke-width:1.5; }
+ .shortcut rect { fill:#fff8ec; stroke:#b63838; stroke-dasharray:3 2; }
+ .shortcut text { font-size:11px; fill:#783030; }
+ .shortcut.selected rect, .shortcut:focus rect { stroke-width:2.5; }
+ .label { font-size:12px; fill:#152330; font-weight:600; }
+ .node-id { font-size:10px; fill:#596674; font-weight:400; }
+ .type { font-size:11px; fill:#455768; }
+ .port { stroke:#536477; stroke-width:1; }
+ .row { stroke:#b6afcf; stroke-width:1; }
+ .bind { font-size:12px; fill:#152330; }
+ .slot { font-size:10px; fill:#364352; paint-order:stroke; stroke:#fafbfc; stroke-width:3; }
+ #detail { position:absolute; top:8px; right:8px; margin:0; padding:12px; max-width:320px;
+ max-height:45%; overflow:auto; white-space:pre-wrap; overflow-wrap:anywhere;
+ background:#fffffff2; border:1px solid #bac5d0; border-radius:4px; font-size:12px; }
+ .controls { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:6px; padding:6px; }
+ .button { color:white; background:black; font-size:20px; min-width:30px; }
+ .button:disabled { background:grey; }
+ .count { font-size:20px; min-width:35px; text-align:center; }
+ #N { width:6ch; }
+ #scrub { width:clamp(120px,35vw,600px); }
+ </style><defs><marker id="arrow-CTRL" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#b63838"/></marker><marker id="arrow-DATA" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#536477"/></marker><marker id="arrow-MEM" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#2867b2"/></marker><marker id="arrow-ASSOC" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#9396a3"/></marker><marker id="arrow-PARSER" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#7956a5"/></marker></defs><rect width="100%" height="100%" fill="rgb(250, 251, 252)"/><g><g class="regions" style="opacity: 1;"/><rect class="peep-area" rx="36" style="opacity: 0;"/><g class="edges"><path class="edge CTRL" id="e3i0" d="M104,219 C104,243 163,246 163,270" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[0] → #10 · CTRL</title></path><path class="edge CTRL" id="e10i0" d="M84,118 L84,166" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#10[0] → #1 · CTRL</title></path><path class="edge DATA" id="e10i1" d="M242,118 L242,128 L124,128 L124,166" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#10[1] → #9 · DATA</title></path></g><g class="edge-hits"/><g class="parser" style="opacity: 1;"/><g class="nodes"><g class="node" id="n1" data-id="1" transform="translate(24,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>$ctrl</tspan><tspan class="node-id">  #1/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#1 $ctrl
+Projection 0 of #2
+Type not computed
+
+[0] → #2 CTRL</title></g><g class="node" id="n2" data-id="2" transform="translate(24,24)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Start</tspan><tspan class="node-id">  #2</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#2 Start
+Type not computed
+
+</title></g><g class="node" id="n3" data-id="3" transform="translate(127,270)" style="opacity: 1;"><path class="box" d="M0,0H72V26H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="36" y="17"><tspan>Stop</tspan><tspan class="node-id">  #3</tspan></text><text class="type" text-anchor="middle" y="35" x="36"/><title>#3 Stop
+Type not computed
+
+[0] → #10 CTRL</title><circle class="port" cx="36" cy="0" r="3" fill="#536477"/><text class="slot" x="36" y="-7" text-anchor="middle">0</text></g><g class="node" id="n9" data-id="9" transform="translate(182,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#0</tspan><tspan class="node-id">  #9</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#9 #0
+Type not computed
+
+</title></g><g class="node" id="n10" data-id="10" transform="translate(44,172)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #10</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#10 Return
+Type not computed
+
+[0] → #1 CTRL
+[1] → #9 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g></g><g class="region-heads" style="opacity: 1;"/><g class="shortcuts" style="opacity: 1;"/><g class="peep-ghosts" pointer-events="none"/></g></svg>
diff --git a/chapter09/docs/09-graph5.json b/chapter09/docs/09-graph5.json
new file mode 100644
index 00000000..31957bfa
--- /dev/null
+++ b/chapter09/docs/09-graph5.json
@@ -0,0 +1,27 @@
+{
+ "ver": 1,
+ "comp": "chapter09/docs/09-graph5.svg",
+ "step": 1,
+ "roots": [],
+ "scope": 0,
+ "nodes": [
+ {"id": 1, "label": "$ctrl", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 2, "role": "CTRL", "label": null}], "proj": {"par": 2, "idx": 0}},
+ {"id": 2, "label": "Start", "type": null, "kind": "CTRL", "edges": [], "proj": null},
+ {"id": 3, "label": "Stop", "type": null, "kind": "STOP", "edges": [{"idx": 0, "def": 21, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 4, "label": "arg", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 2, "role": "DATA", "label": null}], "proj": {"par": 2, "idx": 1}},
+ {"id": 5, "label": "True", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 12, "role": "CTRL", "label": null}], "proj": {"par": 12, "idx": 0}},
+ {"id": 6, "label": "#1", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 7, "label": "Loop", "type": null, "kind": "LOOP", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 1, "role": "CTRL", "label": null}, {"idx": 2, "def": 5, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 8, "label": "False", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 12, "role": "CTRL", "label": null}], "proj": {"par": 12, "idx": 1}},
+ {"id": 9, "label": "φ_arg", "type": null, "kind": "PHI", "edges": [{"idx": 0, "def": 7, "role": "ASSOC", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 18, "role": "DATA", "label": null}], "proj": null},
+ {"id": 10, "label": "<", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 9, "role": "DATA", "label": null}, {"idx": 2, "def": 11, "role": "DATA", "label": null}], "proj": null},
+ {"id": 11, "label": "#10", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 12, "label": "If", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 7, "role": "CTRL", "label": null}, {"idx": 1, "def": 10, "role": "DATA", "label": null}], "proj": null},
+ {"id": 16, "label": "+", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 6, "role": "DATA", "label": null}, {"idx": 2, "def": 9, "role": "DATA", "label": null}], "proj": null},
+ {"id": 18, "label": "+", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 16, "role": "DATA", "label": null}, {"idx": 2, "def": 6, "role": "DATA", "label": null}], "proj": null},
+ {"id": 21, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 8, "role": "CTRL", "label": null}, {"idx": 1, "def": 9, "role": "DATA", "label": null}], "proj": null}
+ ],
+ "groups": [
+ {"id": 7, "par": 0, "nodes": [5, 7, 8, 9, 10, 12, 16, 18]}
+ ]
+}
diff --git a/chapter09/docs/09-graph5.svg b/chapter09/docs/09-graph5.svg
index 9d0698db..7457cb38 100644
--- a/chapter09/docs/09-graph5.svg
+++ b/chapter09/docs/09-graph5.svg
@@ -1,210 +1,124 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.43.0 (0)
- -->
-<!-- Title: chapter09 Pages: 1 -->
-<svg width="338pt" height="492pt"
- viewBox="0.00 0.00 338.00 492.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 488)">
-<title>chapter09</title>
-<polygon fill="white" stroke="transparent" points="-4,4 -4,-488 334,-488 334,4 -4,4"/>
-<g id="clust1" class="cluster">
-<title>cluster_Nodes</title>
-<polygon fill="none" stroke="black" points="8,-8 8,-476 322,-476 322,-8 8,-8"/>
-</g>
-<!-- Start2 -->
-<g id="node1" class="node">
-<title>Start2</title>
-<polygon fill="yellow" stroke="transparent" points="153,-439 153,-464 234,-464 234,-439 153,-439"/>
-<polygon fill="none" stroke="black" points="153,-439 153,-464 234,-464 234,-439 153,-439"/>
-<text text-anchor="start" x="175" y="-447.8" font-family="Times,serif" font-size="14.00">Start</text>
-<polygon fill="none" stroke="black" points="153,-408 153,-439 234,-439 234,-408 153,-408"/>
-<polygon fill="yellow" stroke="transparent" points="158,-413 158,-434 198,-434 198,-413 158,-413"/>
-<polygon fill="none" stroke="black" points="158,-413 158,-434 198,-434 198,-413 158,-413"/>
-<text text-anchor="start" x="161" y="-419.8" font-family="Times,serif" font-size="14.00">$ctrl</text>
-<polygon fill="none" stroke="black" points="198,-413 198,-434 229,-434 229,-413 198,-413"/>
-<text text-anchor="start" x="201" y="-419.8" font-family="Times,serif" font-size="14.00">arg</text>
-</g>
-<!-- Stop3 -->
-<g id="node2" class="node">
-<title>Stop3</title>
-<polygon fill="yellow" stroke="black" points="271,-52 217,-52 217,-16 271,-16 271,-52"/>
-<text text-anchor="middle" x="244" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text>
-</g>
-<!-- Return21 -->
-<g id="node11" class="node">
-<title>Return21</title>
-<polygon fill="yellow" stroke="black" points="277,-124 211,-124 211,-88 277,-88 277,-124"/>
-<text text-anchor="middle" x="244" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return21 -->
-<g id="edge1" class="edge">
-<title>Stop3&#45;&gt;Return21</title>
-<path fill="none" stroke="red" d="M244,-52.3C244,-60.02 244,-69.29 244,-77.89"/>
-<polygon fill="red" stroke="red" points="240.5,-77.9 244,-87.9 247.5,-77.9 240.5,-77.9"/>
-<text text-anchor="middle" x="241" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Con_6 -->
-<g id="node3" class="node">
-<title>Con_6</title>
-<ellipse fill="none" stroke="black" cx="43" cy="-350" rx="27" ry="18"/>
-<text text-anchor="middle" x="43" y="-346.3" font-family="Times,serif" font-size="14.00">#1</text>
-</g>
-<!-- Loop7 -->
-<g id="node4" class="node">
-<title>Loop7</title>
-<polygon fill="yellow" stroke="black" points="142,-368 88,-368 88,-332 142,-332 142,-368"/>
-<text text-anchor="middle" x="115" y="-346.3" font-family="Times,serif" font-size="14.00">Loop</text>
-</g>
-<!-- Loop7&#45;&gt;Start2 -->
-<g id="edge2" class="edge">
-<title>Loop7&#45;&gt;Start2:p0</title>
-<path fill="none" stroke="red" d="M117.35,-368.06C120.75,-386.19 128.75,-413.28 146.69,-420.93"/>
-<polygon fill="red" stroke="red" points="146.51,-424.46 157,-423 147.89,-417.6 146.51,-424.46"/>
-<text text-anchor="middle" x="114.35" y="-370.66" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- If12 -->
-<g id="node8" class="node">
-<title>If12</title>
-<polygon fill="yellow" stroke="transparent" points="147,-195 147,-220 241,-220 241,-195 147,-195"/>
-<polygon fill="none" stroke="black" points="147,-195 147,-220 241,-220 241,-195 147,-195"/>
-<text text-anchor="start" x="188.5" y="-203.8" font-family="Times,serif" font-size="14.00">If</text>
-<polygon fill="none" stroke="black" points="147,-164 147,-195 241,-195 241,-164 147,-164"/>
-<polygon fill="yellow" stroke="transparent" points="152,-169 152,-190 192,-190 192,-169 152,-169"/>
-<polygon fill="none" stroke="black" points="152,-169 152,-190 192,-190 192,-169 152,-169"/>
-<text text-anchor="start" x="155" y="-175.8" font-family="Times,serif" font-size="14.00">True</text>
-<polygon fill="yellow" stroke="transparent" points="192,-169 192,-190 236,-190 236,-169 192,-169"/>
-<polygon fill="none" stroke="black" points="192,-169 192,-190 236,-190 236,-169 192,-169"/>
-<text text-anchor="start" x="195" y="-175.8" font-family="Times,serif" font-size="14.00">False</text>
-</g>
-<!-- Loop7&#45;&gt;If12 -->
-<g id="edge3" class="edge">
-<title>Loop7&#45;&gt;If12:p0</title>
-<path fill="none" stroke="red" d="M142.11,-336.15C145.11,-334.74 148.12,-333.34 151,-332 186,-315.76 209.13,-328.45 230,-296 238.66,-282.54 239,-273.23 230,-260 205.55,-224.03 163.45,-259.97 139,-224 125.26,-203.78 121.98,-186.54 139,-169 146.02,-161.76 158.99,-157.07 166.4,-159.61"/>
-<polygon fill="red" stroke="red" points="163.54,-161.62 172,-168 169.36,-157.74 163.54,-161.62"/>
-<text text-anchor="middle" x="145.11" y="-329.75" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Phi_arg9 -->
-<g id="node5" class="node">
-<title>Phi_arg9</title>
-<ellipse fill="lightyellow" stroke="black" cx="277" cy="-350" rx="37.09" ry="18"/>
-<text text-anchor="middle" x="277" y="-346.3" font-family="Times,serif" font-size="14.00">φ_arg</text>
-</g>
-<!-- Phi_arg9&#45;&gt;Start2 -->
-<g id="edge5" class="edge">
-<title>Phi_arg9&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M273.71,-368.06C269.21,-386.44 259.37,-414.03 239.96,-421.23"/>
-<polygon fill="black" stroke="black" points="239.23,-417.81 230,-423 240.46,-424.7 239.23,-417.81"/>
-<text text-anchor="middle" x="270.71" y="-370.66" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Phi_arg9&#45;&gt;Loop7 -->
-<g id="edge4" class="edge">
-<title>Phi_arg9&#45;&gt;Loop7</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M258.53,-334.01C248.46,-326.34 235.34,-317.98 222,-314 195.59,-306.13 186,-304.88 160,-314 152.86,-316.5 146.01,-320.67 139.91,-325.3"/>
-<polygon fill="black" stroke="black" points="137.55,-322.71 132.08,-331.78 142.01,-328.1 137.55,-322.71"/>
-<text text-anchor="middle" x="255.53" y="-327.61" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Add18 -->
-<g id="node10" class="node">
-<title>Add18</title>
-<ellipse fill="none" stroke="black" cx="66" cy="-192" rx="27" ry="18"/>
-<text text-anchor="middle" x="66" y="-188.3" font-family="Times,serif" font-size="14.00">+</text>
-</g>
-<!-- Phi_arg9&#45;&gt;Add18 -->
-<g id="edge6" class="edge">
-<title>Phi_arg9&#45;&gt;Add18</title>
-<path fill="none" stroke="black" d="M249.01,-337.87C243.12,-335.75 236.9,-333.68 231,-332 153.36,-309.94 104.1,-358.47 53,-296 35.4,-274.49 43.72,-241.53 53.12,-218.71"/>
-<polygon fill="black" stroke="black" points="56.43,-219.88 57.28,-209.32 50.03,-217.04 56.43,-219.88"/>
-<text text-anchor="middle" x="246.01" y="-331.47" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- LT10 -->
-<g id="node6" class="node">
-<title>LT10</title>
-<ellipse fill="none" stroke="black" cx="194" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="194" y="-274.3" font-family="Times,serif" font-size="14.00">&lt;</text>
-</g>
-<!-- LT10&#45;&gt;Phi_arg9 -->
-<g id="edge7" class="edge">
-<title>LT10&#45;&gt;Phi_arg9</title>
-<path fill="none" stroke="black" d="M210.4,-292.83C222.06,-302.66 237.95,-316.07 251.29,-327.31"/>
-<polygon fill="black" stroke="black" points="249.3,-330.22 259.2,-333.99 253.81,-324.86 249.3,-330.22"/>
-<text text-anchor="middle" x="207.4" y="-295.43" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_11 -->
-<g id="node7" class="node">
-<title>Con_11</title>
-<ellipse fill="none" stroke="black" cx="191" cy="-350" rx="30.59" ry="18"/>
-<text text-anchor="middle" x="191" y="-346.3" font-family="Times,serif" font-size="14.00">#10</text>
-</g>
-<!-- LT10&#45;&gt;Con_11 -->
-<g id="edge8" class="edge">
-<title>LT10&#45;&gt;Con_11</title>
-<path fill="none" stroke="black" d="M193.26,-296.3C192.93,-304.02 192.53,-313.29 192.16,-321.89"/>
-<polygon fill="black" stroke="black" points="188.66,-321.75 191.73,-331.9 195.66,-322.05 188.66,-321.75"/>
-<text text-anchor="middle" x="190.26" y="-298.9" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- If12&#45;&gt;Loop7 -->
-<g id="edge9" class="edge">
-<title>If12&#45;&gt;Loop7</title>
-<path fill="none" stroke="red" d="M176.87,-224.21C170.8,-235.44 164,-248.24 158,-260 147.34,-280.9 135.81,-304.85 127.37,-322.64"/>
-<polygon fill="red" stroke="red" points="124.14,-321.29 123.03,-331.83 130.46,-324.29 124.14,-321.29"/>
-<text text-anchor="middle" x="173.87" y="-226.81" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- If12&#45;&gt;LT10 -->
-<g id="edge10" class="edge">
-<title>If12&#45;&gt;LT10</title>
-<path fill="none" stroke="black" d="M194,-224.28C194,-232.58 194,-241.48 194,-249.56"/>
-<polygon fill="black" stroke="black" points="190.5,-249.6 194,-259.6 197.5,-249.6 190.5,-249.6"/>
-<text text-anchor="middle" x="191" y="-226.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Add16 -->
-<g id="node9" class="node">
-<title>Add16</title>
-<ellipse fill="none" stroke="black" cx="89" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="89" y="-274.3" font-family="Times,serif" font-size="14.00">+</text>
-</g>
-<!-- Add16&#45;&gt;Con_6 -->
-<g id="edge11" class="edge">
-<title>Add16&#45;&gt;Con_6</title>
-<path fill="none" stroke="black" d="M78.56,-294.88C72.8,-303.66 65.52,-314.74 59.04,-324.58"/>
-<polygon fill="black" stroke="black" points="55.96,-322.9 53.4,-333.18 61.81,-326.74 55.96,-322.9"/>
-<text text-anchor="middle" x="75.56" y="-297.48" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Add16&#45;&gt;Phi_arg9 -->
-<g id="edge12" class="edge">
-<title>Add16&#45;&gt;Phi_arg9</title>
-<path fill="none" stroke="black" d="M112.05,-287.58C143.64,-299.35 200.8,-320.63 238.83,-334.79"/>
-<polygon fill="black" stroke="black" points="237.94,-338.19 248.54,-338.4 240.39,-331.63 237.94,-338.19"/>
-<text text-anchor="middle" x="115.05" y="-290.18" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Add18&#45;&gt;Con_6 -->
-<g id="edge14" class="edge">
-<title>Add18&#45;&gt;Con_6</title>
-<path fill="none" stroke="black" d="M62.31,-210.01C59.48,-223.51 55.62,-242.9 53,-260 49.85,-280.62 47.25,-304.07 45.5,-321.72"/>
-<polygon fill="black" stroke="black" points="41.99,-321.59 44.51,-331.88 48.96,-322.27 41.99,-321.59"/>
-<text text-anchor="middle" x="59.31" y="-212.61" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Add18&#45;&gt;Add16 -->
-<g id="edge13" class="edge">
-<title>Add18&#45;&gt;Add16</title>
-<path fill="none" stroke="black" d="M70.65,-210C73.8,-221.5 78.03,-236.93 81.63,-250.08"/>
-<polygon fill="black" stroke="black" points="78.34,-251.31 84.35,-260.03 85.09,-249.46 78.34,-251.31"/>
-<text text-anchor="middle" x="67.65" y="-212.6" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Return21&#45;&gt;Phi_arg9 -->
-<g id="edge16" class="edge">
-<title>Return21&#45;&gt;Phi_arg9</title>
-<path fill="none" stroke="black" d="M249.23,-124.03C252.22,-134.35 255.79,-147.83 258,-160 268.31,-216.9 273.41,-284.53 275.6,-321.49"/>
-<polygon fill="black" stroke="black" points="272.13,-322.15 276.19,-331.93 279.12,-321.75 272.13,-322.15"/>
-<text text-anchor="middle" x="246.23" y="-126.63" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Return21&#45;&gt;If12 -->
-<g id="edge15" class="edge">
-<title>Return21&#45;&gt;If12:p1</title>
-<path fill="none" stroke="red" d="M230.4,-124.06C224.14,-133.27 217.55,-145.31 215.05,-157.87"/>
-<polygon fill="red" stroke="red" points="211.55,-157.69 214,-168 218.51,-158.41 211.55,-157.69"/>
-<text text-anchor="middle" x="227.4" y="-126.66" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-</g>
-</svg>
+<svg aria-label="Compiler graph" width="668" height="788" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 668 788" style="font-family: sans-serif;"><style>
+ html, body { height:100%; margin:0; font-family:sans-serif; }
+ .viewer { height:100%; display:grid; grid-template-rows:auto minmax(0,1fr) auto; }
+ .source { padding:8px; border-bottom:1px solid #ccc; }
+ #program { width:min(600px,80vw); vertical-align:middle; }
+ #status { margin-top:4px; }
+ #graph { min-height:0; overflow:hidden; position:relative; background:#fafbfc; }
+ #elk { width:100%; height:100%; }
+ #graph svg { display:block; }
+ .tools { display:flex; flex-wrap:wrap; align-items:center; gap:14px; margin-top:8px; font-size:12px; }
+ .hint { color:#616c78; }
+ .ctrl { color:#b63838; } .mem { color:#2867b2; } .data { color:#536477; }
+ .edge { fill:none; stroke-width:1.5; }
+ .edge.CTRL { stroke-width:2; }
+ .edge.ASSOC { stroke-dasharray:4 4; }
+ .edge.PARSER { stroke-dasharray:5 4; }
+ .parser rect { fill:#f6f0ff; stroke:#7956a5; stroke-width:1.5; stroke-dasharray:5 4; }
+ .edge.selected { stroke-width:3.5; }
+ .edge.bundle { stroke-width:4; }
+ .edge.bundle.selected { stroke-width:6; }
+ .edge-hit { fill:none; stroke:transparent; stroke-width:12; vector-effect:non-scaling-stroke; pointer-events:stroke; cursor:pointer; }
+ .edge-jump { fill:transparent; pointer-events:all; cursor:pointer; }
+ .node { cursor:pointer; }
+ .box { stroke:#758191; stroke-width:1; }
+ .node.held .box { stroke-dasharray:5 3; }
+ .node.near .box { stroke:#c18221; stroke-width:2; }
+ .node.focus .box { stroke:#9c4900; stroke-width:3; }
+ .node.selected .box { stroke:#1569b9; stroke-width:3; }
+ .node.folded .box { stroke-width:4; }
+ .node.folding .box { fill:#f4ccd7; }
+ .fold-tag { font-size:9px; font-weight:700; fill:#963751; }
+ .peep-area { fill:#fff3d9; fill-opacity:.8; stroke:#c18221; stroke-width:2; pointer-events:none; }
+ .node.peep-edit .box { stroke:#9c4900; stroke-width:3; }
+ .node.error .box { stroke:#b42318; stroke-width:4; }
+ #event.error { color:#b42318; font-weight:600; white-space:pre-wrap; overflow-wrap:anywhere; }
+ .peep-ghosts { pointer-events:none; }
+ .region-box { stroke:#9da9b8; stroke-width:1.5; }
+ .fold-btn { cursor:pointer; }
+ .fold-btn rect { fill:white; stroke:#596674; }
+ .fold-btn text { font-size:14px; fill:#152330; }
+ .fold-btn:focus rect { stroke:#1569b9; stroke-width:2; }
+ .shortcut { cursor:pointer; }
+ .shortcut path { fill:none; stroke-width:1.5; }
+ .shortcut rect { fill:#fff8ec; stroke:#b63838; stroke-dasharray:3 2; }
+ .shortcut text { font-size:11px; fill:#783030; }
+ .shortcut.selected rect, .shortcut:focus rect { stroke-width:2.5; }
+ .label { font-size:12px; fill:#152330; font-weight:600; }
+ .node-id { font-size:10px; fill:#596674; font-weight:400; }
+ .type { font-size:11px; fill:#455768; }
+ .port { stroke:#536477; stroke-width:1; }
+ .row { stroke:#b6afcf; stroke-width:1; }
+ .bind { font-size:12px; fill:#152330; }
+ .slot { font-size:10px; fill:#364352; paint-order:stroke; stroke:#fafbfc; stroke-width:3; }
+ #detail { position:absolute; top:8px; right:8px; margin:0; padding:12px; max-width:320px;
+ max-height:45%; overflow:auto; white-space:pre-wrap; overflow-wrap:anywhere;
+ background:#fffffff2; border:1px solid #bac5d0; border-radius:4px; font-size:12px; }
+ .controls { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:6px; padding:6px; }
+ .button { color:white; background:black; font-size:20px; min-width:30px; }
+ .button:disabled { background:grey; }
+ .count { font-size:20px; min-width:35px; text-align:center; }
+ #N { width:6ch; }
+ #scrub { width:clamp(120px,35vw,600px); }
+ </style><defs><marker id="arrow-CTRL" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#b63838"/></marker><marker id="arrow-DATA" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#536477"/></marker><marker id="arrow-MEM" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#2867b2"/></marker><marker id="arrow-ASSOC" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#9396a3"/></marker><marker id="arrow-PARSER" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#7956a5"/></marker></defs><rect width="100%" height="100%" fill="rgb(250, 251, 252)"/><g><g class="regions" style="opacity: 1;"><g class="region" transform="translate(134,171)"><rect class="region-box" rx="8" width="510" height="410" fill="#f1f6fc"/></g></g><rect class="peep-area" rx="36" style="opacity: 0;"/><g class="edges"><path class="edge CTRL" id="e3i0" d="M356,687 C356,711 334,714 334,738" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[0] → #21 · CTRL</title></path><path class="edge CTRL" id="e7i1" d="M236,118 L236,241" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#7[1] → #1 · CTRL</title></path><path class="edge CTRL" id="e7i2" d="M216,546 L216,556 L632,556 L632,224 L266,224 L266,244" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#7[2] → #5 · CTRL</title></path><path class="edge DATA" id="e9i1" d="M356,118 L356,128 L368,128 L368,241" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#9[1] → #4 · DATA</title></path><path class="edge DATA" id="e9i2" d="M529,502 L529,512 L622,512 L622,232 L408,232 L408,244" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#9[2] → #18 · DATA</title></path><path class="edge DATA" id="e10i1" d="M388,297 L388,307 L316,307 L316,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#10[1] → #9 · DATA</title></path><path class="edge DATA" id="e10i2" d="M84,118 L84,128 L165,128 L165,317 L346,317 L346,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#10[2] → #11 · DATA</title></path><path class="edge CTRL" id="e12i0" d="M236,297 L236,449" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#12[0] → #7 · CTRL</title></path><path class="edge DATA" id="e12i1" d="M316,401 L316,449" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#12[1] → #10 · DATA</title></path><path class="edge DATA" id="e16i1" d="M529,118 L529,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#16[1] → #6 · DATA</title></path><path class="edge DATA" id="e16i2" d="M388,297 L388,307 L559,307 L559,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#16[2] → #9 · DATA</title></path><path class="edge DATA" id="e18i1" d="M529,401 L529,449" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#18[1] → #16 · DATA</title></path><path class="edge DATA" id="e18i2" d="M529,118 L529,128 L599,128 L599,411 L559,411 L559,449" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#18[2] → #6 · DATA</title></path><path class="edge CTRL" id="e21i0" d="M336,549 L336,634" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#21[0] → #8 · CTRL</title></path><path class="edge DATA" id="e21i1" d="M388,297 L388,307 L412,307 L412,596 L376,596 L376,634" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#21[1] → #9 · DATA</title></path></g><g class="edge-hits"/><g class="parser" style="opacity: 1;"/><g class="nodes"><g class="node" id="n1" data-id="1" transform="translate(176,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>$ctrl</tspan><tspan class="node-id">  #1/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#1 $ctrl
+Projection 0 of #2
+Type not computed
+
+[0] → #2 CTRL</title></g><g class="node" id="n2" data-id="2" transform="translate(176,24)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>Start</tspan><tspan class="node-id">  #2</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#2 Start
+Type not computed
+
+</title></g><g class="node" id="n3" data-id="3" transform="translate(298,738)" style="opacity: 1;"><path class="box" d="M0,0H72V26H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="36" y="17"><tspan>Stop</tspan><tspan class="node-id">  #3</tspan></text><text class="type" text-anchor="middle" y="35" x="36"/><title>#3 Stop
+Type not computed
+
+[0] → #21 CTRL</title><circle class="port" cx="36" cy="0" r="3" fill="#536477"/><text class="slot" x="36" y="-7" text-anchor="middle">0</text></g><g class="node" id="n4" data-id="4" transform="translate(296,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>arg</tspan><tspan class="node-id">  #4/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#4 arg
+Projection 1 of #2
+Type not computed
+
+[0] → #2 DATA</title></g><g class="node" id="n5" data-id="5" transform="translate(156,499)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>True</tspan><tspan class="node-id">  #5/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#5 True
+Projection 0 of #12
+Type not computed
+
+[0] → #12 CTRL</title></g><g class="node" id="n6" data-id="6" transform="translate(469,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#1</tspan><tspan class="node-id">  #6</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#6 #1
+Type not computed
+
+</title></g><g class="node" id="n7" data-id="7" transform="translate(176,247)" style="opacity: 1;"><path class="box" d="M20,0H100Q120,0 120,20V24Q120,44 100,44H20Q0,44 0,24V20Q0,0 20,0Z" fill="#ffe0ab"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Loop</tspan><tspan class="node-id">  #7</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#7 Loop
+Type not computed
+
+[0] → — DATA
+[1] → #1 CTRL
+[2] → #5 CTRL</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n8" data-id="8" transform="translate(276,499)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>False</tspan><tspan class="node-id">  #8/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#8 False
+Projection 1 of #12
+Type not computed
+
+[0] → #12 CTRL</title></g><g class="node" id="n9" data-id="9" transform="translate(328,247)" style="opacity: 1;"><path class="box" d="M12,0H108L120,22L108,44H12L0,22Z" fill="#f5e4fa"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>φ_arg</tspan><tspan class="node-id">  #9</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#9 φ_arg
+Type not computed
+
+[0] → #7 ASSOC
+[1] → #4 DATA
+[2] → #18 DATA</title><circle class="port" cx="-3" cy="22" r="3" fill="#536477"/><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><path class="reg" fill="none" stroke="#b63838" d="M-3,22H-18m4,-3l-4,3l4,3"><title>[0] → #7</title></path><text class="slot" x="-10" y="15" text-anchor="middle">0</text><text class="slot" x="40" y="-10" text-anchor="middle">1</text><text class="slot" x="80" y="-10" text-anchor="middle">2</text></g><g class="node" id="n10" data-id="10" transform="translate(256,351)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>&lt;</tspan><tspan class="node-id">  #10</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#10 &lt;
+Type not computed
+
+[0] → — DATA
+[1] → #9 DATA
+[2] → #11 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n11" data-id="11" transform="translate(24,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#10</tspan><tspan class="node-id">  #11</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#11 #10
+Type not computed
+
+</title></g><g class="node" id="n12" data-id="12" transform="translate(156,455)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>If</tspan><tspan class="node-id">  #12</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#12 If
+Type not computed
+
+[0] → #7 CTRL
+[1] → #10 DATA</title><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><circle class="port" cx="160" cy="-3" r="3" fill="#536477"/><text class="slot" x="80" y="-10" text-anchor="middle">0</text><text class="slot" x="160" y="-10" text-anchor="middle">1</text></g><g class="node" id="n16" data-id="16" transform="translate(469,351)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>+</tspan><tspan class="node-id">  #16</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#16 +
+Type not computed
+
+[0] → — DATA
+[1] → #6 DATA
+[2] → #9 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n18" data-id="18" transform="translate(469,455)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>+</tspan><tspan class="node-id">  #18</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#18 +
+Type not computed
+
+[0] → — DATA
+[1] → #16 DATA
+[2] → #6 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n21" data-id="21" transform="translate(296,640)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #21</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#21 Return
+Type not computed
+
+[0] → #8 CTRL
+[1] → #9 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g></g><g class="region-heads" style="opacity: 1;"><g class="region-head" transform="translate(134,171)"><text class="label" x="26" y="17"><tspan>Loop</tspan><tspan class="node-id">  #7</tspan></text><title>Loop · 8 nodes</title><g class="fold-btn" role="button" tabindex="0" transform="translate(4,4)" aria-label="Fold region #7"><rect width="16" height="16" rx="2"/><text x="8" y="12" text-anchor="middle">−</text><title>Fold region</title></g></g></g><g class="shortcuts" style="opacity: 1;"/><g class="peep-ghosts" pointer-events="none"/></g></svg>
diff --git a/chapter09/docs/09-graph6.json b/chapter09/docs/09-graph6.json
new file mode 100644
index 00000000..09fa1202
--- /dev/null
+++ b/chapter09/docs/09-graph6.json
@@ -0,0 +1,26 @@
+{
+ "ver": 1,
+ "comp": "chapter09/docs/09-graph6.svg",
+ "step": 1,
+ "roots": [],
+ "scope": 0,
+ "nodes": [
+ {"id": 1, "label": "$ctrl", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 2, "role": "CTRL", "label": null}], "proj": {"par": 2, "idx": 0}},
+ {"id": 2, "label": "Start", "type": null, "kind": "CTRL", "edges": [], "proj": null},
+ {"id": 3, "label": "Stop", "type": null, "kind": "STOP", "edges": [{"idx": 0, "def": 21, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 4, "label": "arg", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 2, "role": "DATA", "label": null}], "proj": {"par": 2, "idx": 1}},
+ {"id": 5, "label": "True", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 12, "role": "CTRL", "label": null}], "proj": {"par": 12, "idx": 0}},
+ {"id": 6, "label": "False", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 12, "role": "CTRL", "label": null}], "proj": {"par": 12, "idx": 1}},
+ {"id": 7, "label": "Loop", "type": null, "kind": "LOOP", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 1, "role": "CTRL", "label": null}, {"idx": 2, "def": 5, "role": "CTRL", "label": null}], "proj": null},
+ {"id": 9, "label": "φ_arg", "type": null, "kind": "PHI", "edges": [{"idx": 0, "def": 7, "role": "ASSOC", "label": null}, {"idx": 1, "def": 4, "role": "DATA", "label": null}, {"idx": 2, "def": 25, "role": "DATA", "label": null}], "proj": null},
+ {"id": 10, "label": "<", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 9, "role": "DATA", "label": null}, {"idx": 2, "def": 11, "role": "DATA", "label": null}], "proj": null},
+ {"id": 11, "label": "#10", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 12, "label": "If", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 7, "role": "CTRL", "label": null}, {"idx": 1, "def": 10, "role": "DATA", "label": null}], "proj": null},
+ {"id": 21, "label": "Return", "type": null, "kind": "CTRL", "edges": [{"idx": 0, "def": 6, "role": "CTRL", "label": null}, {"idx": 1, "def": 9, "role": "DATA", "label": null}], "proj": null},
+ {"id": 24, "label": "#2", "type": null, "kind": "DATA", "edges": [], "proj": null},
+ {"id": 25, "label": "+", "type": null, "kind": "DATA", "edges": [{"idx": 0, "def": 0, "role": "DATA", "label": null}, {"idx": 1, "def": 9, "role": "DATA", "label": null}, {"idx": 2, "def": 24, "role": "DATA", "label": null}], "proj": null}
+ ],
+ "groups": [
+ {"id": 7, "par": 0, "nodes": [5, 6, 7, 9, 10, 12, 25]}
+ ]
+}
diff --git a/chapter09/docs/09-graph6.svg b/chapter09/docs/09-graph6.svg
index 36c70099..2d530c46 100644
--- a/chapter09/docs/09-graph6.svg
+++ b/chapter09/docs/09-graph6.svg
@@ -1,184 +1,119 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.43.0 (0)
- -->
-<!-- Title: chapter09 Pages: 1 -->
-<svg width="338pt" height="492pt"
- viewBox="0.00 0.00 338.00 492.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 488)">
-<title>chapter09</title>
-<polygon fill="white" stroke="transparent" points="-4,4 -4,-488 334,-488 334,4 -4,4"/>
-<g id="clust1" class="cluster">
-<title>cluster_Nodes</title>
-<polygon fill="none" stroke="black" points="8,-8 8,-476 322,-476 322,-8 8,-8"/>
-</g>
-<!-- Start2 -->
-<g id="node1" class="node">
-<title>Start2</title>
-<polygon fill="yellow" stroke="transparent" points="149,-439 149,-464 230,-464 230,-439 149,-439"/>
-<polygon fill="none" stroke="black" points="149,-439 149,-464 230,-464 230,-439 149,-439"/>
-<text text-anchor="start" x="171" y="-447.8" font-family="Times,serif" font-size="14.00">Start</text>
-<polygon fill="none" stroke="black" points="149,-408 149,-439 230,-439 230,-408 149,-408"/>
-<polygon fill="yellow" stroke="transparent" points="154,-413 154,-434 194,-434 194,-413 154,-413"/>
-<polygon fill="none" stroke="black" points="154,-413 154,-434 194,-434 194,-413 154,-413"/>
-<text text-anchor="start" x="157" y="-419.8" font-family="Times,serif" font-size="14.00">$ctrl</text>
-<polygon fill="none" stroke="black" points="194,-413 194,-434 225,-434 225,-413 194,-413"/>
-<text text-anchor="start" x="197" y="-419.8" font-family="Times,serif" font-size="14.00">arg</text>
-</g>
-<!-- Stop3 -->
-<g id="node2" class="node">
-<title>Stop3</title>
-<polygon fill="yellow" stroke="black" points="157,-52 103,-52 103,-16 157,-16 157,-52"/>
-<text text-anchor="middle" x="130" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text>
-</g>
-<!-- Return21 -->
-<g id="node8" class="node">
-<title>Return21</title>
-<polygon fill="yellow" stroke="black" points="163,-124 97,-124 97,-88 163,-88 163,-124"/>
-<text text-anchor="middle" x="130" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text>
-</g>
-<!-- Stop3&#45;&gt;Return21 -->
-<g id="edge1" class="edge">
-<title>Stop3&#45;&gt;Return21</title>
-<path fill="none" stroke="red" d="M130,-52.3C130,-60.02 130,-69.29 130,-77.89"/>
-<polygon fill="red" stroke="red" points="126.5,-77.9 130,-87.9 133.5,-77.9 126.5,-77.9"/>
-<text text-anchor="middle" x="127" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Loop7 -->
-<g id="node3" class="node">
-<title>Loop7</title>
-<polygon fill="yellow" stroke="black" points="314,-368 260,-368 260,-332 314,-332 314,-368"/>
-<text text-anchor="middle" x="287" y="-346.3" font-family="Times,serif" font-size="14.00">Loop</text>
-</g>
-<!-- Loop7&#45;&gt;Start2 -->
-<g id="edge2" class="edge">
-<title>Loop7&#45;&gt;Start2:p0</title>
-<path fill="none" stroke="red" d="M259.93,-364.13C234.34,-376.71 197.56,-395.24 181.73,-405.41"/>
-<polygon fill="red" stroke="red" points="179.34,-402.85 174,-412 183.88,-408.18 179.34,-402.85"/>
-<text text-anchor="middle" x="256.93" y="-357.73" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- If12 -->
-<g id="node7" class="node">
-<title>If12</title>
-<polygon fill="yellow" stroke="transparent" points="36,-195 36,-220 130,-220 130,-195 36,-195"/>
-<polygon fill="none" stroke="black" points="36,-195 36,-220 130,-220 130,-195 36,-195"/>
-<text text-anchor="start" x="77.5" y="-203.8" font-family="Times,serif" font-size="14.00">If</text>
-<polygon fill="none" stroke="black" points="36,-164 36,-195 130,-195 130,-164 36,-164"/>
-<polygon fill="yellow" stroke="transparent" points="41,-169 41,-190 81,-190 81,-169 41,-169"/>
-<polygon fill="none" stroke="black" points="41,-169 41,-190 81,-190 81,-169 41,-169"/>
-<text text-anchor="start" x="44" y="-175.8" font-family="Times,serif" font-size="14.00">True</text>
-<polygon fill="yellow" stroke="transparent" points="81,-169 81,-190 125,-190 125,-169 81,-169"/>
-<polygon fill="none" stroke="black" points="81,-169 81,-190 125,-190 125,-169 81,-169"/>
-<text text-anchor="start" x="84" y="-175.8" font-family="Times,serif" font-size="14.00">False</text>
-</g>
-<!-- Loop7&#45;&gt;If12 -->
-<g id="edge3" class="edge">
-<title>Loop7&#45;&gt;If12:p0</title>
-<path fill="none" stroke="red" d="M259.79,-335.23C256.86,-334.03 253.9,-332.92 251,-332 163.26,-304.1 109.06,-364.01 47,-296 22.33,-268.96 18.57,-203.69 31.46,-184.44"/>
-<polygon fill="red" stroke="red" points="33.44,-187.32 40,-179 29.68,-181.42 33.44,-187.32"/>
-<text text-anchor="middle" x="256.79" y="-328.83" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- Phi_arg9 -->
-<g id="node4" class="node">
-<title>Phi_arg9</title>
-<ellipse fill="lightyellow" stroke="black" cx="133" cy="-350" rx="37.09" ry="18"/>
-<text text-anchor="middle" x="133" y="-346.3" font-family="Times,serif" font-size="14.00">φ_arg</text>
-</g>
-<!-- Phi_arg9&#45;&gt;Start2 -->
-<g id="edge5" class="edge">
-<title>Phi_arg9&#45;&gt;Start2:p1</title>
-<path fill="none" stroke="black" d="M162.55,-360.93C181.21,-369 202.84,-382.27 208.56,-401.87"/>
-<polygon fill="black" stroke="black" points="205.12,-402.59 210,-412 212.05,-401.61 205.12,-402.59"/>
-<text text-anchor="middle" x="159.55" y="-363.53" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Phi_arg9&#45;&gt;Loop7 -->
-<g id="edge4" class="edge">
-<title>Phi_arg9&#45;&gt;Loop7</title>
-<path fill="none" stroke="black" stroke-dasharray="1,5" d="M151.47,-334.01C161.54,-326.34 174.66,-317.98 188,-314 211,-307.14 219.35,-306.06 242,-314 249.14,-316.5 255.99,-320.67 262.09,-325.3"/>
-<polygon fill="black" stroke="black" points="259.99,-328.1 269.92,-331.78 264.45,-322.71 259.99,-328.1"/>
-<text text-anchor="middle" x="148.47" y="-327.61" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Add25 -->
-<g id="node10" class="node">
-<title>Add25</title>
-<ellipse fill="none" stroke="black" cx="209" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="209" y="-274.3" font-family="Times,serif" font-size="14.00">+</text>
-</g>
-<!-- LT10 -->
-<g id="node5" class="node">
-<title>LT10</title>
-<ellipse fill="none" stroke="black" cx="83" cy="-278" rx="27" ry="18"/>
-<text text-anchor="middle" x="83" y="-274.3" font-family="Times,serif" font-size="14.00">&lt;</text>
-</g>
-<!-- LT10&#45;&gt;Phi_arg9 -->
-<g id="edge7" class="edge">
-<title>LT10&#45;&gt;Phi_arg9</title>
-<path fill="none" stroke="black" d="M94.1,-294.54C100.33,-303.26 108.25,-314.35 115.31,-324.24"/>
-<polygon fill="black" stroke="black" points="112.58,-326.43 121.24,-332.53 118.27,-322.36 112.58,-326.43"/>
-<text text-anchor="middle" x="91.1" y="-297.14" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Con_11 -->
-<g id="node6" class="node">
-<title>Con_11</title>
-<ellipse fill="none" stroke="black" cx="47" cy="-350" rx="30.59" ry="18"/>
-<text text-anchor="middle" x="47" y="-346.3" font-family="Times,serif" font-size="14.00">#10</text>
-</g>
-<!-- LT10&#45;&gt;Con_11 -->
-<g id="edge8" class="edge">
-<title>LT10&#45;&gt;Con_11</title>
-<path fill="none" stroke="black" d="M74.65,-295.24C70.35,-303.6 65.01,-313.98 60.17,-323.39"/>
-<polygon fill="black" stroke="black" points="57.02,-321.87 55.55,-332.37 63.24,-325.07 57.02,-321.87"/>
-<text text-anchor="middle" x="71.65" y="-297.84" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-<!-- If12&#45;&gt;Loop7 -->
-<g id="edge9" class="edge">
-<title>If12&#45;&gt;Loop7</title>
-<path fill="none" stroke="red" d="M138.19,-204.98C172.47,-214.83 215.47,-231.87 245,-260 262.62,-276.78 273.63,-302.43 279.94,-321.89"/>
-<polygon fill="red" stroke="red" points="276.66,-323.13 282.89,-331.7 283.36,-321.11 276.66,-323.13"/>
-<text text-anchor="middle" x="141.19" y="-198.58" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- If12&#45;&gt;LT10 -->
-<g id="edge10" class="edge">
-<title>If12&#45;&gt;LT10</title>
-<path fill="none" stroke="black" d="M83,-224.28C83,-232.58 83,-241.48 83,-249.56"/>
-<polygon fill="black" stroke="black" points="79.5,-249.6 83,-259.6 86.5,-249.6 79.5,-249.6"/>
-<text text-anchor="middle" x="80" y="-226.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Return21&#45;&gt;Phi_arg9 -->
-<g id="edge12" class="edge">
-<title>Return21&#45;&gt;Phi_arg9</title>
-<path fill="none" stroke="black" d="M137.07,-124.33C140.84,-134.53 145.09,-147.78 147,-160 155.96,-217.25 145.96,-285.18 138.86,-322"/>
-<polygon fill="black" stroke="black" points="135.39,-321.46 136.86,-331.95 142.26,-322.84 135.39,-321.46"/>
-<text text-anchor="middle" x="134.07" y="-126.93" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Return21&#45;&gt;If12 -->
-<g id="edge11" class="edge">
-<title>Return21&#45;&gt;If12:p1</title>
-<path fill="none" stroke="red" d="M117.92,-124C112.25,-133.3 106.24,-145.44 103.95,-157.94"/>
-<polygon fill="red" stroke="red" points="100.46,-157.71 103,-168 107.43,-158.38 100.46,-157.71"/>
-<text text-anchor="middle" x="114.92" y="-126.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text>
-</g>
-<!-- Con_24 -->
-<g id="node9" class="node">
-<title>Con_24</title>
-<ellipse fill="none" stroke="black" cx="215" cy="-350" rx="27" ry="18"/>
-<text text-anchor="middle" x="215" y="-346.3" font-family="Times,serif" font-size="14.00">#2</text>
-</g>
-<!-- Add25&#45;&gt;Phi_arg9 -->
-<g id="edge13" class="edge">
-<title>Add25&#45;&gt;Phi_arg9</title>
-<path fill="none" stroke="black" d="M185.95,-300.23C176.82,-308.64 166.31,-318.32 157.07,-326.83"/>
-<polygon fill="black" stroke="black" points="188.64,-302.51 193.62,-293.17 183.89,-297.37 188.64,-302.51"/>
-<polygon fill="black" stroke="black" points="154.66,-324.29 149.68,-333.64 159.4,-329.44 154.66,-324.29"/>
-<text text-anchor="middle" x="190.62" y="-295.77" font-family="Helvetica,sans-Serif" font-size="8.00">1</text>
-</g>
-<!-- Add25&#45;&gt;Con_24 -->
-<g id="edge14" class="edge">
-<title>Add25&#45;&gt;Con_24</title>
-<path fill="none" stroke="black" d="M210.48,-296.3C211.14,-304.02 211.94,-313.29 212.68,-321.89"/>
-<polygon fill="black" stroke="black" points="209.19,-322.23 213.53,-331.9 216.17,-321.63 209.19,-322.23"/>
-<text text-anchor="middle" x="207.48" y="-298.9" font-family="Helvetica,sans-Serif" font-size="8.00">2</text>
-</g>
-</g>
-</svg>
+<svg aria-label="Compiler graph" width="841" height="788" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841 788" style="font-family: sans-serif;"><style>
+ html, body { height:100%; margin:0; font-family:sans-serif; }
+ .viewer { height:100%; display:grid; grid-template-rows:auto minmax(0,1fr) auto; }
+ .source { padding:8px; border-bottom:1px solid #ccc; }
+ #program { width:min(600px,80vw); vertical-align:middle; }
+ #status { margin-top:4px; }
+ #graph { min-height:0; overflow:hidden; position:relative; background:#fafbfc; }
+ #elk { width:100%; height:100%; }
+ #graph svg { display:block; }
+ .tools { display:flex; flex-wrap:wrap; align-items:center; gap:14px; margin-top:8px; font-size:12px; }
+ .hint { color:#616c78; }
+ .ctrl { color:#b63838; } .mem { color:#2867b2; } .data { color:#536477; }
+ .edge { fill:none; stroke-width:1.5; }
+ .edge.CTRL { stroke-width:2; }
+ .edge.ASSOC { stroke-dasharray:4 4; }
+ .edge.PARSER { stroke-dasharray:5 4; }
+ .parser rect { fill:#f6f0ff; stroke:#7956a5; stroke-width:1.5; stroke-dasharray:5 4; }
+ .edge.selected { stroke-width:3.5; }
+ .edge.bundle { stroke-width:4; }
+ .edge.bundle.selected { stroke-width:6; }
+ .edge-hit { fill:none; stroke:transparent; stroke-width:12; vector-effect:non-scaling-stroke; pointer-events:stroke; cursor:pointer; }
+ .edge-jump { fill:transparent; pointer-events:all; cursor:pointer; }
+ .node { cursor:pointer; }
+ .box { stroke:#758191; stroke-width:1; }
+ .node.held .box { stroke-dasharray:5 3; }
+ .node.near .box { stroke:#c18221; stroke-width:2; }
+ .node.focus .box { stroke:#9c4900; stroke-width:3; }
+ .node.selected .box { stroke:#1569b9; stroke-width:3; }
+ .node.folded .box { stroke-width:4; }
+ .node.folding .box { fill:#f4ccd7; }
+ .fold-tag { font-size:9px; font-weight:700; fill:#963751; }
+ .peep-area { fill:#fff3d9; fill-opacity:.8; stroke:#c18221; stroke-width:2; pointer-events:none; }
+ .node.peep-edit .box { stroke:#9c4900; stroke-width:3; }
+ .node.error .box { stroke:#b42318; stroke-width:4; }
+ #event.error { color:#b42318; font-weight:600; white-space:pre-wrap; overflow-wrap:anywhere; }
+ .peep-ghosts { pointer-events:none; }
+ .region-box { stroke:#9da9b8; stroke-width:1.5; }
+ .fold-btn { cursor:pointer; }
+ .fold-btn rect { fill:white; stroke:#596674; }
+ .fold-btn text { font-size:14px; fill:#152330; }
+ .fold-btn:focus rect { stroke:#1569b9; stroke-width:2; }
+ .shortcut { cursor:pointer; }
+ .shortcut path { fill:none; stroke-width:1.5; }
+ .shortcut rect { fill:#fff8ec; stroke:#b63838; stroke-dasharray:3 2; }
+ .shortcut text { font-size:11px; fill:#783030; }
+ .shortcut.selected rect, .shortcut:focus rect { stroke-width:2.5; }
+ .label { font-size:12px; fill:#152330; font-weight:600; }
+ .node-id { font-size:10px; fill:#596674; font-weight:400; }
+ .type { font-size:11px; fill:#455768; }
+ .port { stroke:#536477; stroke-width:1; }
+ .row { stroke:#b6afcf; stroke-width:1; }
+ .bind { font-size:12px; fill:#152330; }
+ .slot { font-size:10px; fill:#364352; paint-order:stroke; stroke:#fafbfc; stroke-width:3; }
+ #detail { position:absolute; top:8px; right:8px; margin:0; padding:12px; max-width:320px;
+ max-height:45%; overflow:auto; white-space:pre-wrap; overflow-wrap:anywhere;
+ background:#fffffff2; border:1px solid #bac5d0; border-radius:4px; font-size:12px; }
+ .controls { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:6px; padding:6px; }
+ .button { color:white; background:black; font-size:20px; min-width:30px; }
+ .button:disabled { background:grey; }
+ .count { font-size:20px; min-width:35px; text-align:center; }
+ #N { width:6ch; }
+ #scrub { width:clamp(120px,35vw,600px); }
+ </style><defs><marker id="arrow-CTRL" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#b63838"/></marker><marker id="arrow-DATA" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#536477"/></marker><marker id="arrow-MEM" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#2867b2"/></marker><marker id="arrow-ASSOC" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#9396a3"/></marker><marker id="arrow-PARSER" viewBox="0 -4 8 8" refX="8" refY="0" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,-4L8,0L0,4Z" fill="#7956a5"/></marker></defs><rect width="100%" height="100%" fill="rgb(250, 251, 252)"/><g><g class="regions" style="opacity: 1;"><g class="region" transform="translate(24,171)"><rect class="region-box" rx="8" width="637" height="410" fill="#f1f6fc"/></g></g><rect class="peep-area" rx="36" style="opacity: 0;"/><g class="edges"><path class="edge CTRL" id="e3i0" d="M246,687 C246,711 420.5,714 420.5,738" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#3[0] → #21 · CTRL</title></path><path class="edge CTRL" id="e7i1" d="M126,118 L126,241" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#7[1] → #1 · CTRL</title></path><path class="edge CTRL" id="e7i2" d="M106,546 L106,556 L649,556 L649,224 L156,224 L156,244" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#7[2] → #5 · CTRL</title></path><path class="edge DATA" id="e9i1" d="M246,118 L246,128 L258,128 L258,241" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#9[1] → #4 · DATA</title></path><path class="edge DATA" id="e9i2" d="M525,398 L525,408 L639,408 L639,232 L298,232 L298,244" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#9[2] → #25 · DATA</title></path><path class="edge DATA" id="e10i1" d="M278,297 L278,317 L373,317 L373,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#10[1] → #9 · DATA</title></path><path class="edge DATA" id="e10i2" d="M605,118 L605,307 L403,307 L403,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#10[2] → #11 · DATA</title></path><path class="edge CTRL" id="e12i0" d="M126,297 L126,449" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#12[0] → #7 · CTRL</title></path><path class="edge DATA" id="e12i1" d="M373,401 L373,411 L206,411 L206,449" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#12[1] → #10 · DATA</title></path><path class="edge CTRL" id="e21i0" d="M226,549 L226,634" stroke="#b63838" marker-start="url(#arrow-CTRL)" style="opacity: 1;"><title>#21[0] → #6 · CTRL</title></path><path class="edge DATA" id="e21i1" d="M278,297 L278,317 L302,317 L302,596 L266,596 L266,634" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#21[1] → #9 · DATA</title></path><path class="edge DATA" id="e25i1" d="M278,297 L278,317 L525,317 L525,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#25[1] → #9 · DATA</title></path><path class="edge DATA" id="e25i2" d="M757,118 L757,128 L616,128 L616,317 L555,317 L555,345" stroke="#536477" marker-start="url(#arrow-DATA)" style="opacity: 1;"><title>#25[2] → #24 · DATA</title></path></g><g class="edge-hits"/><g class="parser" style="opacity: 1;"/><g class="nodes"><g class="node" id="n1" data-id="1" transform="translate(66,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>$ctrl</tspan><tspan class="node-id">  #1/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#1 $ctrl
+Projection 0 of #2
+Type not computed
+
+[0] → #2 CTRL</title></g><g class="node" id="n2" data-id="2" transform="translate(66,24)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>Start</tspan><tspan class="node-id">  #2</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#2 Start
+Type not computed
+
+</title></g><g class="node" id="n3" data-id="3" transform="translate(384.5,738)" style="opacity: 1;"><path class="box" d="M0,0H72V26H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="36" y="17"><tspan>Stop</tspan><tspan class="node-id">  #3</tspan></text><text class="type" text-anchor="middle" y="35" x="36"/><title>#3 Stop
+Type not computed
+
+[0] → #21 CTRL</title><circle class="port" cx="36" cy="0" r="3" fill="#536477"/><text class="slot" x="36" y="-7" text-anchor="middle">0</text></g><g class="node" id="n4" data-id="4" transform="translate(186,68)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>arg</tspan><tspan class="node-id">  #4/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#4 arg
+Projection 1 of #2
+Type not computed
+
+[0] → #2 DATA</title></g><g class="node" id="n5" data-id="5" transform="translate(46,499)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>True</tspan><tspan class="node-id">  #5/0</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#5 True
+Projection 0 of #12
+Type not computed
+
+[0] → #12 CTRL</title></g><g class="node" id="n6" data-id="6" transform="translate(166,499)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>False</tspan><tspan class="node-id">  #6/1</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#6 False
+Projection 1 of #12
+Type not computed
+
+[0] → #12 CTRL</title></g><g class="node" id="n7" data-id="7" transform="translate(66,247)" style="opacity: 1;"><path class="box" d="M20,0H100Q120,0 120,20V24Q120,44 100,44H20Q0,44 0,24V20Q0,0 20,0Z" fill="#ffe0ab"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Loop</tspan><tspan class="node-id">  #7</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#7 Loop
+Type not computed
+
+[0] → — DATA
+[1] → #1 CTRL
+[2] → #5 CTRL</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n9" data-id="9" transform="translate(218,247)" style="opacity: 1;"><path class="box" d="M12,0H108L120,22L108,44H12L0,22Z" fill="#f5e4fa"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>φ_arg</tspan><tspan class="node-id">  #9</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#9 φ_arg
+Type not computed
+
+[0] → #7 ASSOC
+[1] → #4 DATA
+[2] → #25 DATA</title><circle class="port" cx="-3" cy="22" r="3" fill="#536477"/><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><path class="reg" fill="none" stroke="#b63838" d="M-3,22H-18m4,-3l-4,3l4,3"><title>[0] → #7</title></path><text class="slot" x="-10" y="15" text-anchor="middle">0</text><text class="slot" x="40" y="-10" text-anchor="middle">1</text><text class="slot" x="80" y="-10" text-anchor="middle">2</text></g><g class="node" id="n10" data-id="10" transform="translate(313,351)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>&lt;</tspan><tspan class="node-id">  #10</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#10 &lt;
+Type not computed
+
+[0] → — DATA
+[1] → #9 DATA
+[2] → #11 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g><g class="node" id="n11" data-id="11" transform="translate(545,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#10</tspan><tspan class="node-id">  #11</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#11 #10
+Type not computed
+
+</title></g><g class="node" id="n12" data-id="12" transform="translate(46,455)" style="opacity: 1;"><path class="box" d="M0,0H240V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="120" y="18"><tspan>If</tspan><tspan class="node-id">  #12</tspan></text><text class="type" text-anchor="middle" y="35" x="120"/><title>#12 If
+Type not computed
+
+[0] → #7 CTRL
+[1] → #10 DATA</title><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><circle class="port" cx="160" cy="-3" r="3" fill="#536477"/><text class="slot" x="80" y="-10" text-anchor="middle">0</text><text class="slot" x="160" y="-10" text-anchor="middle">1</text></g><g class="node" id="n21" data-id="21" transform="translate(186,640)" style="opacity: 1;"><path class="box" d="M0,0H120V44H0Z" fill="#fff1c4"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>Return</tspan><tspan class="node-id">  #21</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#21 Return
+Type not computed
+
+[0] → #6 CTRL
+[1] → #9 DATA</title><circle class="port" cx="40" cy="-3" r="3" fill="#536477"/><circle class="port" cx="80" cy="-3" r="3" fill="#536477"/><text class="slot" x="40" y="-10" text-anchor="middle">0</text><text class="slot" x="80" y="-10" text-anchor="middle">1</text></g><g class="node" id="n24" data-id="24" transform="translate(697,68)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>#2</tspan><tspan class="node-id">  #24</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#24 #2
+Type not computed
+
+</title></g><g class="node" id="n25" data-id="25" transform="translate(465,351)" style="opacity: 1;"><path class="box" d="M14,0H106Q120,0 120,14V30Q120,44 106,44H14Q0,44 0,30V14Q0,0 14,0Z" fill="#edf3f7"/><text class="label" text-anchor="middle" x="60" y="18"><tspan>+</tspan><tspan class="node-id">  #25</tspan></text><text class="type" text-anchor="middle" y="35" x="60"/><title>#25 +
+Type not computed
+
+[0] → — DATA
+[1] → #9 DATA
+[2] → #24 DATA</title><circle class="port" cx="30" cy="-3" r="3" fill="white"/><circle class="port" cx="60" cy="-3" r="3" fill="#536477"/><circle class="port" cx="90" cy="-3" r="3" fill="#536477"/><text class="slot" x="30" y="-10" text-anchor="middle">0</text><text class="slot" x="60" y="-10" text-anchor="middle">1</text><text class="slot" x="90" y="-10" text-anchor="middle">2</text></g></g><g class="region-heads" style="opacity: 1;"><g class="region-head" transform="translate(24,171)"><text class="label" x="26" y="17"><tspan>Loop</tspan><tspan class="node-id">  #7</tspan></text><title>Loop · 7 nodes</title><g class="fold-btn" role="button" tabindex="0" transform="translate(4,4)" aria-label="Fold region #7"><rect width="16" height="16" rx="2"/><text x="8" y="12" text-anchor="middle">−</text><title>Fold region</title></g></g></g><g class="shortcuts" style="opacity: 1;"/><g class="peep-ghosts" pointer-events="none"/></g></svg>
diff --git a/chapter09/docs/Makefile b/chapter09/docs/Makefile
index 12659b8f..6fa0f057 100644
--- a/chapter09/docs/Makefile
+++ b/chapter09/docs/Makefile
@@ -1,12 +1 @@
-GV := $(wildcard *.gv)
-SVG := $(patsubst %.gv,%.svg,$(GV))
-
-.PHONY: all
-all: $(SVG)
-
-%.svg: %.gv
- dot -Tsvg $< > $@
-
-.PHONY: clean
-clean:
- @rm -f $(SVG)
+include ../../graph/docs.mk