summaryrefslogtreecommitdiff
path: root/chapter18
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2024-12-21 16:43:03 -0800
committerCliff Click <cliffc@acm.org>2025-01-15 15:07:30 -0800
commit8095c50f846699f7570bdea4c6517653c5795c2e (patch)
tree1d5ed8477dd796766a3a6aa7b6c5d2e6cb883946 /chapter18
parentb0b26bd248fad6f6d2ac23f673ae73095cd5c3cb (diff)
downloadSimple-8095c50f846699f7570bdea4c6517653c5795c2e.tar.gz
Simple-8095c50f846699f7570bdea4c6517653c5795c2e.zip
All parsing null to be TFP or TMP
Insert a TypePtr/TypeNil around TypeMemPtr and TypeFunPtr in the lattice; allows the parsing of "null" to mean either a TMP or TFP null. Cleanup Type null checks and several prints. Drop Type.lub, Type.makeInit. Add a Parser NIL & ZERO. Clean up parser errors, track line numbers for future parser errors.
Diffstat (limited to 'chapter18')
-rw-r--r--chapter18/Makefile3
-rw-r--r--chapter18/docs/lattice.gv11
-rw-r--r--chapter18/docs/lattice.svg691
-rw-r--r--chapter18/docs/lattice2.gv85
-rw-r--r--chapter18/docs/lattice2.svg260
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/IterPeeps.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/Parser.java148
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java15
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java1
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java14
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java3
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java10
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/Node.java5
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java24
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java12
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/SarNode.java1
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java4
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java35
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ShlNode.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ShrNode.java1
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java4
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java7
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java4
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/Field.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/Type.java87
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java116
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java44
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeInteger.java79
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java15
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java91
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java57
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypePtr.java53
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java24
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/BrainFuckTest.java9
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter01Test.java2
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter03Test.java1
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java6
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java4
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter13Test.java4
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter14Test.java4
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter15Test.java4
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter17Test.java2
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java3
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java52
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java3
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java8
51 files changed, 1606 insertions, 429 deletions
diff --git a/chapter18/Makefile b/chapter18/Makefile
index 0be7b659..f42659de 100644
--- a/chapter18/Makefile
+++ b/chapter18/Makefile
@@ -68,7 +68,8 @@ JVM=nice java -ea -cp "build/classes/main${SEP}${jars}${SEP}$(CLZDIR)/test"
tests: $(default_targets)
@echo "testing " $(test_cp)
- @$(JVM) org.junit.runner.JUnitCore $(test_cp) com.seaofnodes.simple.FuzzerWrap
+ @$(JVM) org.junit.runner.JUnitCore $(test_cp)
+ @$(JVM) org.junit.runner.JUnitCore com.seaofnodes.simple.FuzzerWrap
fuzzer: $(default_targets)
@echo "fuzzing " $(test_cp)
diff --git a/chapter18/docs/lattice.gv b/chapter18/docs/lattice.gv
index 4a8b1d4c..f8af5718 100644
--- a/chapter18/docs/lattice.gv
+++ b/chapter18/docs/lattice.gv
@@ -3,7 +3,8 @@ digraph Lattice {
// Define nodes
splines=false;
node [shape=circle, style=filled];
- nodesep=0.6;
+ nodesep=0.2;
+ ranksep=0.2;
TOP [label=<<B>⊤</B >>, fillcolor=black, fontcolor=white];
BOT [label=<<B>⊥</B>>, fillcolor=black, fontcolor=white];
@@ -22,13 +23,13 @@ digraph Lattice {
INT_TOP [label=<<B>⊤</B >:int>, fillcolor=lightblue, shape=oval];
INT_BOT [label=<<B>⊥</B>:int>, fillcolor=lightblue, shape=oval];
- INT_HI [label="max < min" , fillcolor=lightblue, shape=oval];
- INT_XBOOL [label="1...0", fillcolor=lightblue, shape=oval];
+ INT_HI [label="[min>max]" , fillcolor=lightblue, shape=oval];
+ INT_XBOOL [label="[1...0]", fillcolor=lightblue, shape=oval];
INT_CON [label="constants", fillcolor=lightblue, shape=oval];
INT_CON0 [label="0", fillcolor=lightblue];
INT_CON1 [label="1", fillcolor=lightblue];
- INT_BOOL [label="0...1", fillcolor=lightblue,shape=oval];
- INT_LO [label="max > min" , fillcolor=lightblue, shape=oval];
+ INT_BOOL [label="[0...1]", fillcolor=lightblue,shape=oval];
+ INT_LO [label="[min<max]" , fillcolor=lightblue, shape=oval];
TOP -> INT_TOP;
INT_TOP -> INT_HI;
diff --git a/chapter18/docs/lattice.svg b/chapter18/docs/lattice.svg
new file mode 100644
index 00000000..030f4826
--- /dev/null
+++ b/chapter18/docs/lattice.svg
@@ -0,0 +1,691 @@
+<?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 12.2.0 (20241103.1931)
+ -->
+<!-- Title: Lattice Pages: 1 -->
+<svg width="1330pt" height="584pt"
+ viewBox="0.00 0.00 1329.51 583.54" 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 579.54)">
+<title>Lattice</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-579.54 1325.51,-579.54 1325.51,4 -4,4"/>
+<!-- TOP -->
+<g id="node1" class="node">
+<title>TOP</title>
+<ellipse fill="black" stroke="black" cx="641.51" cy="-554.42" rx="21.12" ry="21.12"/>
+<text text-anchor="start" x="633.63" y="-549.99" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text>
+</g>
+<!-- XCTRL -->
+<g id="node3" class="node">
+<title>XCTRL</title>
+<ellipse fill="yellow" stroke="black" cx="36.51" cy="-492.79" rx="36.51" ry="18"/>
+<text text-anchor="start" x="17.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="33.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text>
+</g>
+<!-- TOP&#45;&gt;XCTRL -->
+<g id="edge1" class="edge">
+<title>TOP&#45;&gt;XCTRL</title>
+<path fill="none" stroke="black" d="M620.33,-551.33C533.82,-542.8 206.01,-510.5 83.28,-498.4"/>
+<polygon fill="black" stroke="black" points="83.86,-494.94 73.56,-497.44 83.17,-501.91 83.86,-494.94"/>
+</g>
+<!-- INT_TOP -->
+<g id="node5" class="node">
+<title>INT_TOP</title>
+<ellipse fill="lightblue" stroke="black" cx="316.51" cy="-492.79" rx="33.95" ry="18"/>
+<text text-anchor="start" x="299.63" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="315.38" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:int</text>
+</g>
+<!-- TOP&#45;&gt;INT_TOP -->
+<g id="edge4" class="edge">
+<title>TOP&#45;&gt;INT_TOP</title>
+<path fill="none" stroke="black" d="M620.68,-549.6C568.33,-539.99 430.36,-514.68 359.64,-501.71"/>
+<polygon fill="black" stroke="black" points="360.44,-498.29 349.97,-499.93 359.18,-505.18 360.44,-498.29"/>
+</g>
+<!-- FLT_TOP -->
+<g id="node14" class="node">
+<title>FLT_TOP</title>
+<ellipse fill="aqua" stroke="black" cx="494.51" cy="-492.79" rx="32.41" ry="18"/>
+<text text-anchor="start" x="478.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="494.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:flt</text>
+</g>
+<!-- TOP&#45;&gt;FLT_TOP -->
+<g id="edge18" class="edge">
+<title>TOP&#45;&gt;FLT_TOP</title>
+<path fill="none" stroke="black" d="M621.99,-545.5C598.79,-536.09 559.6,-520.19 530.78,-508.5"/>
+<polygon fill="black" stroke="black" points="532.29,-505.34 521.7,-504.82 529.65,-511.82 532.29,-505.34"/>
+</g>
+<!-- PTR -->
+<g id="node22" class="node">
+<title>PTR</title>
+<polygon fill="none" stroke="none" points="668.51,-519.29 614.51,-519.29 614.51,-466.29 668.51,-466.29 668.51,-519.29"/>
+<polygon fill="green" stroke="none" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/>
+<polygon fill="none" stroke="black" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/>
+<text text-anchor="start" x="630.63" y="-498.99" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr</text>
+<polygon fill="lightgreen" stroke="none" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/>
+<polygon fill="none" stroke="black" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/>
+<text text-anchor="start" x="626.51" y="-476.49" font-family="Times New Roman,serif" font-size="14.00">struct</text>
+</g>
+<!-- TOP&#45;&gt;PTR -->
+<g id="edge33" class="edge">
+<title>TOP&#45;&gt;PTR</title>
+<path fill="none" stroke="black" d="M641.51,-532.9C641.51,-532.06 641.51,-531.22 641.51,-530.37"/>
+<polygon fill="black" stroke="black" points="645.01,-530.61 641.51,-520.61 638.01,-530.61 645.01,-530.61"/>
+</g>
+<!-- STRUCT_TOP -->
+<g id="node24" class="node">
+<title>STRUCT_TOP</title>
+<ellipse fill="lightgreen" stroke="black" cx="746.51" cy="-492.79" rx="44.7" ry="18"/>
+<text text-anchor="start" x="721.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="737.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:struct</text>
+</g>
+<!-- TOP&#45;&gt;STRUCT_TOP -->
+<g id="edge36" class="edge">
+<title>TOP&#45;&gt;STRUCT_TOP</title>
+<path fill="none" stroke="black" d="M659.8,-543.03C674.04,-534.94 694.24,-523.47 711.55,-513.64"/>
+<polygon fill="black" stroke="black" points="713.07,-516.81 720.03,-508.83 709.61,-510.72 713.07,-516.81"/>
+</g>
+<!-- MEM_TOP -->
+<g id="node29" class="node">
+<title>MEM_TOP</title>
+<ellipse fill="blue" stroke="black" cx="998.51" cy="-492.79" rx="43.67" ry="18"/>
+<text text-anchor="start" x="974.51" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text>
+<text text-anchor="start" x="990.26" y="-488.74" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text>
+</g>
+<!-- TOP&#45;&gt;MEM_TOP -->
+<g id="edge46" class="edge">
+<title>TOP&#45;&gt;MEM_TOP</title>
+<path fill="none" stroke="black" d="M662.51,-549.91C717.64,-540.7 867.72,-515.64 947.33,-502.34"/>
+<polygon fill="black" stroke="black" points="947.77,-505.82 957.06,-500.72 946.62,-498.91 947.77,-505.82"/>
+</g>
+<!-- TUPLE_TOP -->
+<g id="node34" class="node">
+<title>TUPLE_TOP</title>
+<ellipse fill="pink" stroke="black" cx="1182.51" cy="-492.79" rx="42.65" ry="18"/>
+<text text-anchor="start" x="1159.26" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="1175.01" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:tuple</text>
+</g>
+<!-- TOP&#45;&gt;TUPLE_TOP -->
+<g id="edge56" class="edge">
+<title>TOP&#45;&gt;TUPLE_TOP</title>
+<path fill="none" stroke="black" d="M662.72,-551.08C740.91,-542.46 1014.51,-512.31 1130.21,-499.56"/>
+<polygon fill="black" stroke="black" points="1130.5,-503.05 1140.05,-498.47 1129.73,-496.09 1130.5,-503.05"/>
+</g>
+<!-- BOT -->
+<g id="node2" class="node">
+<title>BOT</title>
+<ellipse fill="black" stroke="black" cx="641.51" cy="-21.12" rx="21.12" ry="21.12"/>
+<text text-anchor="start" x="633.63" y="-16.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text>
+</g>
+<!-- CTRL -->
+<g id="node4" class="node">
+<title>CTRL</title>
+<ellipse fill="yellow" stroke="black" cx="49.51" cy="-82.75" rx="36.51" ry="18"/>
+<text text-anchor="start" x="30.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="46.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text>
+</g>
+<!-- XCTRL&#45;&gt;CTRL -->
+<g id="edge2" class="edge">
+<title>XCTRL&#45;&gt;CTRL</title>
+<path fill="none" stroke="black" d="M37.09,-474.38C39.15,-409.6 46.05,-191.88 48.57,-112.25"/>
+<polygon fill="black" stroke="black" points="52.06,-112.73 48.88,-102.63 45.06,-112.51 52.06,-112.73"/>
+</g>
+<!-- CTRL&#45;&gt;BOT -->
+<g id="edge3" class="edge">
+<title>CTRL&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M85.21,-78.15C191.74,-67.42 506.36,-35.74 608.84,-25.41"/>
+<polygon fill="black" stroke="black" points="609.15,-28.9 618.75,-24.42 608.45,-21.94 609.15,-28.9"/>
+</g>
+<!-- INT_HI -->
+<g id="node7" class="node">
+<title>INT_HI</title>
+<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-434.29" rx="53.91" ry="18"/>
+<text text-anchor="middle" x="174.51" y="-429.24" font-family="Times New Roman,serif" font-size="14.00">[min&gt;max]</text>
+</g>
+<!-- INT_TOP&#45;&gt;INT_HI -->
+<g id="edge5" class="edge">
+<title>INT_TOP&#45;&gt;INT_HI</title>
+<path fill="none" stroke="black" d="M289.8,-481.17C269.89,-473.25 242.26,-462.25 219.03,-453.01"/>
+<polygon fill="black" stroke="black" points="220.37,-449.77 209.78,-449.33 217.78,-456.28 220.37,-449.77"/>
+</g>
+<!-- INT_BOT -->
+<g id="node6" class="node">
+<title>INT_BOT</title>
+<ellipse fill="lightblue" stroke="black" cx="329.51" cy="-82.75" rx="33.95" ry="18"/>
+<text text-anchor="start" x="312.63" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="328.38" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:int</text>
+</g>
+<!-- INT_BOT&#45;&gt;BOT -->
+<g id="edge15" class="edge">
+<title>INT_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M361.14,-75.7C420.84,-64.3 549.47,-39.71 609.47,-28.25"/>
+<polygon fill="black" stroke="black" points="609.86,-31.73 619.03,-26.42 608.55,-24.86 609.86,-31.73"/>
+</g>
+<!-- INT_XBOOL -->
+<g id="node8" class="node">
+<title>INT_XBOOL</title>
+<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-373.97" rx="33.95" ry="18"/>
+<text text-anchor="middle" x="97.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">[1...0]</text>
+</g>
+<!-- INT_HI&#45;&gt;INT_XBOOL -->
+<g id="edge6" class="edge">
+<title>INT_HI&#45;&gt;INT_XBOOL</title>
+<path fill="none" stroke="black" d="M153.47,-417.36C144.79,-410.78 134.6,-403.06 125.31,-396.03"/>
+<polygon fill="black" stroke="black" points="127.71,-393.46 117.63,-390.21 123.48,-399.04 127.71,-393.46"/>
+</g>
+<!-- INT_CON -->
+<g id="node9" class="node">
+<title>INT_CON</title>
+<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-282.65" rx="45.21" ry="18"/>
+<text text-anchor="middle" x="174.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">constants</text>
+</g>
+<!-- INT_HI&#45;&gt;INT_CON -->
+<g id="edge9" class="edge">
+<title>INT_HI&#45;&gt;INT_CON</title>
+<path fill="none" stroke="black" d="M174.51,-416C174.51,-390.27 174.51,-343.1 174.51,-312.31"/>
+<polygon fill="black" stroke="black" points="178.01,-312.52 174.51,-302.52 171.01,-312.52 178.01,-312.52"/>
+</g>
+<!-- INT_CON0 -->
+<g id="node10" class="node">
+<title>INT_CON0</title>
+<ellipse fill="lightblue" stroke="black" cx="47.51" cy="-282.65" rx="18" ry="18"/>
+<text text-anchor="middle" x="47.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0</text>
+</g>
+<!-- INT_XBOOL&#45;&gt;INT_CON0 -->
+<g id="edge7" class="edge">
+<title>INT_XBOOL&#45;&gt;INT_CON0</title>
+<path fill="none" stroke="black" d="M88.34,-356.59C80.82,-343.17 70.07,-323.96 61.49,-308.62"/>
+<polygon fill="black" stroke="black" points="64.63,-307.08 56.69,-300.06 58.53,-310.5 64.63,-307.08"/>
+</g>
+<!-- INT_CON1 -->
+<g id="node11" class="node">
+<title>INT_CON1</title>
+<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-282.65" rx="18" ry="18"/>
+<text text-anchor="middle" x="97.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">1</text>
+</g>
+<!-- INT_XBOOL&#45;&gt;INT_CON1 -->
+<g id="edge8" class="edge">
+<title>INT_XBOOL&#45;&gt;INT_CON1</title>
+<path fill="none" stroke="black" d="M97.51,-355.75C97.51,-343.47 97.51,-326.68 97.51,-312.39"/>
+<polygon fill="black" stroke="black" points="101.01,-312.64 97.51,-302.64 94.01,-312.64 101.01,-312.64"/>
+</g>
+<!-- INT_LO -->
+<g id="node13" class="node">
+<title>INT_LO</title>
+<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-141.25" rx="53.91" ry="18"/>
+<text text-anchor="middle" x="174.51" y="-136.2" font-family="Times New Roman,serif" font-size="14.00">[min&lt;max]</text>
+</g>
+<!-- INT_CON&#45;&gt;INT_LO -->
+<g id="edge13" class="edge">
+<title>INT_CON&#45;&gt;INT_LO</title>
+<path fill="none" stroke="black" d="M174.51,-264.17C174.51,-240.45 174.51,-199.04 174.51,-170.9"/>
+<polygon fill="black" stroke="black" points="178.01,-171.25 174.51,-161.25 171.01,-171.25 178.01,-171.25"/>
+</g>
+<!-- INT_CON0&#45;&gt;INT_CON1 -->
+<!-- INT_BOOL -->
+<g id="node12" class="node">
+<title>INT_BOOL</title>
+<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-196.45" rx="33.95" ry="18"/>
+<text text-anchor="middle" x="97.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">[0...1]</text>
+</g>
+<!-- INT_CON0&#45;&gt;INT_BOOL -->
+<g id="edge10" class="edge">
+<title>INT_CON0&#45;&gt;INT_BOOL</title>
+<path fill="none" stroke="black" d="M56.45,-266.6C63.5,-254.72 73.51,-237.87 81.88,-223.77"/>
+<polygon fill="black" stroke="black" points="84.75,-225.79 86.85,-215.41 78.73,-222.22 84.75,-225.79"/>
+</g>
+<!-- INT_CON1&#45;&gt;INT_CON -->
+<!-- INT_CON1&#45;&gt;INT_BOOL -->
+<g id="edge11" class="edge">
+<title>INT_CON1&#45;&gt;INT_BOOL</title>
+<path fill="none" stroke="black" d="M97.51,-264.21C97.51,-253.25 97.51,-238.87 97.51,-226.25"/>
+<polygon fill="black" stroke="black" points="101.01,-226.39 97.51,-216.39 94.01,-226.39 101.01,-226.39"/>
+</g>
+<!-- INT_BOOL&#45;&gt;INT_LO -->
+<g id="edge12" class="edge">
+<title>INT_BOOL&#45;&gt;INT_LO</title>
+<path fill="none" stroke="black" d="M117.34,-181.75C124.98,-176.47 133.91,-170.3 142.42,-164.42"/>
+<polygon fill="black" stroke="black" points="144.27,-167.4 150.5,-158.83 140.29,-161.64 144.27,-167.4"/>
+</g>
+<!-- INT_LO&#45;&gt;INT_BOT -->
+<g id="edge14" class="edge">
+<title>INT_LO&#45;&gt;INT_BOT</title>
+<path fill="none" stroke="black" d="M210.07,-127.29C234.52,-118.37 266.93,-106.56 291.82,-97.49"/>
+<polygon fill="black" stroke="black" points="292.71,-100.89 300.91,-94.17 290.31,-94.31 292.71,-100.89"/>
+</g>
+<!-- FLT_CON64 -->
+<g id="node16" class="node">
+<title>FLT_CON64</title>
+<ellipse fill="aqua" stroke="black" cx="564.51" cy="-282.65" rx="55.33" ry="40.66"/>
+<text text-anchor="middle" x="564.51" y="-294.1" font-family="Times New Roman,serif" font-size="14.00">64b consts</text>
+<text text-anchor="middle" x="564.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">[excludes</text>
+<text text-anchor="middle" x="564.51" y="-261.1" font-family="Times New Roman,serif" font-size="14.00">32b consts]</text>
+</g>
+<!-- FLT_TOP&#45;&gt;FLT_CON64 -->
+<g id="edge19" class="edge">
+<title>FLT_TOP&#45;&gt;FLT_CON64</title>
+<path fill="none" stroke="black" d="M500.48,-474.88C510.8,-443.88 532.35,-379.2 547.59,-333.44"/>
+<polygon fill="black" stroke="black" points="550.9,-334.57 550.74,-323.98 544.26,-332.36 550.9,-334.57"/>
+</g>
+<!-- FLT_CONPI -->
+<g id="node18" class="node">
+<title>FLT_CONPI</title>
+<ellipse fill="aqua" stroke="black" cx="446.51" cy="-282.65" rx="48.79" ry="18"/>
+<text text-anchor="middle" x="446.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">3.14159...</text>
+</g>
+<!-- FLT_TOP&#45;&gt;FLT_CONPI -->
+<g id="edge20" class="edge">
+<title>FLT_TOP&#45;&gt;FLT_CONPI</title>
+<path fill="none" stroke="black" d="M490.33,-474.51C482.02,-438.11 463.32,-356.27 453.25,-312.16"/>
+<polygon fill="black" stroke="black" points="456.69,-311.49 451.05,-302.52 449.86,-313.04 456.69,-311.49"/>
+</g>
+<!-- FLT_X32 -->
+<g id="node19" class="node">
+<title>FLT_X32</title>
+<ellipse fill="aqua" stroke="black" cx="333.51" cy="-373.97" rx="28.32" ry="28.32"/>
+<text text-anchor="middle" x="333.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">~f32</text>
+</g>
+<!-- FLT_TOP&#45;&gt;FLT_X32 -->
+<g id="edge23" class="edge">
+<title>FLT_TOP&#45;&gt;FLT_X32</title>
+<path fill="none" stroke="black" d="M474.77,-478.22C447.56,-458.14 398.22,-421.73 365.65,-397.69"/>
+<polygon fill="black" stroke="black" points="367.88,-394.99 357.75,-391.86 363.72,-400.62 367.88,-394.99"/>
+</g>
+<!-- FLT_BOT -->
+<g id="node15" class="node">
+<title>FLT_BOT</title>
+<ellipse fill="aqua" stroke="black" cx="507.51" cy="-82.75" rx="32.41" ry="18"/>
+<text text-anchor="start" x="491.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="507.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:flt</text>
+</g>
+<!-- FLT_BOT&#45;&gt;BOT -->
+<g id="edge29" class="edge">
+<title>FLT_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M532.4,-70.67C554.98,-60.63 588.29,-45.81 612.16,-35.19"/>
+<polygon fill="black" stroke="black" points="613.29,-38.51 621,-31.25 610.44,-32.12 613.29,-38.51"/>
+</g>
+<!-- FLT_CON64&#45;&gt;FLT_BOT -->
+<g id="edge21" class="edge">
+<title>FLT_CON64&#45;&gt;FLT_BOT</title>
+<path fill="none" stroke="black" d="M553.11,-242.68C542.05,-203.88 525.53,-145.95 515.71,-111.5"/>
+<polygon fill="black" stroke="black" points="519.17,-110.89 513.06,-102.23 512.44,-112.81 519.17,-110.89"/>
+</g>
+<!-- FLT_CON32 -->
+<g id="node17" class="node">
+<title>FLT_CON32</title>
+<ellipse fill="aqua" stroke="black" cx="333.51" cy="-282.65" rx="50.33" ry="18"/>
+<text text-anchor="middle" x="333.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">32b consts</text>
+</g>
+<!-- FLT_CON32&#45;&gt;FLT_CONPI -->
+<!-- FLT_32 -->
+<g id="node21" class="node">
+<title>FLT_32</title>
+<ellipse fill="aqua" stroke="black" cx="333.51" cy="-196.45" rx="23.2" ry="23.2"/>
+<text text-anchor="middle" x="333.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">f32</text>
+</g>
+<!-- FLT_CON32&#45;&gt;FLT_32 -->
+<g id="edge27" class="edge">
+<title>FLT_CON32&#45;&gt;FLT_32</title>
+<path fill="none" stroke="black" d="M333.51,-264.21C333.51,-254.7 333.51,-242.59 333.51,-231.31"/>
+<polygon fill="black" stroke="black" points="337.01,-231.51 333.51,-221.51 330.01,-231.51 337.01,-231.51"/>
+</g>
+<!-- FLT_CONPI&#45;&gt;FLT_BOT -->
+<g id="edge22" class="edge">
+<title>FLT_CONPI&#45;&gt;FLT_BOT</title>
+<path fill="none" stroke="black" d="M452.03,-264.56C462.62,-229.86 485.86,-153.69 498.65,-111.79"/>
+<polygon fill="black" stroke="black" points="501.94,-112.98 501.51,-102.39 495.25,-110.93 501.94,-112.98"/>
+</g>
+<!-- FLT_CONPI&#45;&gt;FLT_CON64 -->
+<!-- FLT_X32&#45;&gt;FLT_CON32 -->
+<g id="edge25" class="edge">
+<title>FLT_X32&#45;&gt;FLT_CON32</title>
+<path fill="none" stroke="black" d="M333.51,-345.2C333.51,-334.71 333.51,-322.76 333.51,-312.19"/>
+<polygon fill="black" stroke="black" points="337.01,-312.52 333.51,-302.52 330.01,-312.53 337.01,-312.52"/>
+</g>
+<!-- FLT_CON0 -->
+<g id="node20" class="node">
+<title>FLT_CON0</title>
+<ellipse fill="aqua" stroke="black" cx="251.51" cy="-282.65" rx="18.08" ry="18.08"/>
+<text text-anchor="middle" x="251.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0.</text>
+</g>
+<!-- FLT_X32&#45;&gt;FLT_CON0 -->
+<g id="edge24" class="edge">
+<title>FLT_X32&#45;&gt;FLT_CON0</title>
+<path fill="none" stroke="black" d="M314.9,-352.7C301.83,-338.47 284.38,-319.46 271.1,-304.99"/>
+<polygon fill="black" stroke="black" points="273.81,-302.77 264.47,-297.77 268.65,-307.5 273.81,-302.77"/>
+</g>
+<!-- FLT_CON0&#45;&gt;FLT_CON32 -->
+<!-- FLT_CON0&#45;&gt;FLT_32 -->
+<g id="edge26" class="edge">
+<title>FLT_CON0&#45;&gt;FLT_32</title>
+<path fill="none" stroke="black" d="M263.96,-268.86C276.06,-256.44 294.74,-237.26 309.69,-221.91"/>
+<polygon fill="black" stroke="black" points="312.03,-224.53 316.5,-214.92 307.01,-219.64 312.03,-224.53"/>
+</g>
+<!-- FLT_32&#45;&gt;FLT_BOT -->
+<g id="edge28" class="edge">
+<title>FLT_32&#45;&gt;FLT_BOT</title>
+<path fill="none" stroke="black" d="M353.13,-183.63C383.19,-163.99 440.9,-126.28 476.61,-102.94"/>
+<polygon fill="black" stroke="black" points="478.34,-105.99 484.79,-97.59 474.51,-100.13 478.34,-105.99"/>
+</g>
+<!-- PTR0 -->
+<g id="node23" class="node">
+<title>PTR0</title>
+<polygon fill="none" stroke="none" points="668.51,-109.25 614.51,-109.25 614.51,-56.25 668.51,-56.25 668.51,-109.25"/>
+<polygon fill="green" stroke="none" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/>
+<polygon fill="none" stroke="black" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/>
+<text text-anchor="start" x="627.63" y="-88.95" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr?</text>
+<polygon fill="lightgreen" stroke="none" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/>
+<polygon fill="none" stroke="black" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/>
+<text text-anchor="start" x="626.51" y="-66.45" font-family="Times New Roman,serif" font-size="14.00">struct</text>
+</g>
+<!-- PTR&#45;&gt;PTR0 -->
+<g id="edge34" class="edge">
+<title>PTR&#45;&gt;PTR0</title>
+<path fill="none" stroke="black" d="M641.51,-466.52C641.51,-396.01 641.51,-202.44 641.51,-120.34"/>
+<polygon fill="black" stroke="black" points="645.01,-120.58 641.51,-110.58 638.01,-120.58 645.01,-120.58"/>
+</g>
+<!-- PTR0&#45;&gt;BOT -->
+<g id="edge35" class="edge">
+<title>PTR0&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M641.51,-56.46C641.51,-55.58 641.51,-54.7 641.51,-53.81"/>
+<polygon fill="black" stroke="black" points="645.01,-53.9 641.51,-43.9 638.01,-53.9 645.01,-53.9"/>
+</g>
+<!-- STRUCT_S1 -->
+<g id="node26" class="node">
+<title>STRUCT_S1</title>
+<polygon fill="none" stroke="none" points="741.38,-300.65 663.63,-300.65 663.63,-264.65 741.38,-264.65 741.38,-300.65"/>
+<polygon fill="lightgreen" stroke="none" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/>
+<polygon fill="none" stroke="black" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/>
+<text text-anchor="start" x="672.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="703.51" y1="-289.19" x2="728.26" y2="-276.11" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_0)" stroke="none" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/>
+<polygon fill="none" stroke="black" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/>
+<text text-anchor="start" x="699.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+</g>
+<!-- STRUCT_TOP&#45;&gt;STRUCT_S1 -->
+<g id="edge37" class="edge">
+<title>STRUCT_TOP&#45;&gt;STRUCT_S1</title>
+<path fill="none" stroke="black" d="M742.68,-474.51C735.02,-437.92 717.75,-355.45 708.55,-311.5"/>
+<polygon fill="black" stroke="black" points="712.02,-311 706.54,-301.93 705.17,-312.43 712.02,-311"/>
+</g>
+<!-- STRUCT_S2 -->
+<g id="node27" class="node">
+<title>STRUCT_S2</title>
+<polygon fill="none" stroke="none" points="841.38,-309.15 755.63,-309.15 755.63,-256.15 841.38,-256.15 841.38,-309.15"/>
+<polygon fill="lightgreen" stroke="none" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/>
+<polygon fill="none" stroke="black" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/>
+<text text-anchor="start" x="766.63" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="800.1" y1="-301.86" x2="827.67" y2="-285.95" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_1)" stroke="none" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/>
+<polygon fill="none" stroke="black" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/>
+<text text-anchor="start" x="797.38" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+<polygon fill="lightgreen" stroke="none" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/>
+<polygon fill="none" stroke="black" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/>
+<text text-anchor="start" x="766.63" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="800.1" y1="-279.36" x2="827.67" y2="-263.45" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_2)" stroke="none" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/>
+<polygon fill="none" stroke="black" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/>
+<text text-anchor="start" x="797.38" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+</g>
+<!-- STRUCT_TOP&#45;&gt;STRUCT_S2 -->
+<g id="edge38" class="edge">
+<title>STRUCT_TOP&#45;&gt;STRUCT_S2</title>
+<path fill="none" stroke="black" d="M751.03,-474.51C759.53,-440.16 778.05,-365.34 789.28,-319.95"/>
+<polygon fill="black" stroke="black" points="792.67,-320.83 791.67,-310.28 785.87,-319.15 792.67,-320.83"/>
+</g>
+<!-- STRUCT_SN -->
+<g id="node28" class="node">
+<title>STRUCT_SN</title>
+<polygon fill="none" stroke="none" points="941.38,-320.4 855.63,-320.4 855.63,-244.9 941.38,-244.9 941.38,-320.4"/>
+<polygon fill="lightgreen" stroke="none" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/>
+<polygon fill="none" stroke="black" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/>
+<text text-anchor="start" x="866.63" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_3" gradientUnits="userSpaceOnUse" x1="900.1" y1="-313.11" x2="927.67" y2="-297.2" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_3)" stroke="none" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/>
+<polygon fill="none" stroke="black" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/>
+<text text-anchor="start" x="897.38" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+<polygon fill="lightgreen" stroke="none" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/>
+<polygon fill="none" stroke="black" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/>
+<text text-anchor="start" x="869.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">... &#160;</text>
+<defs>
+<linearGradient id="l_4" gradientUnits="userSpaceOnUse" x1="900.1" y1="-290.61" x2="927.67" y2="-274.7" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_4)" stroke="none" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/>
+<polygon fill="none" stroke="black" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/>
+<text text-anchor="start" x="897.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+<polygon fill="lightgreen" stroke="none" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/>
+<polygon fill="none" stroke="black" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/>
+<text text-anchor="start" x="866.63" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_5" gradientUnits="userSpaceOnUse" x1="900.1" y1="-268.11" x2="927.67" y2="-252.2" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_5)" stroke="none" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/>
+<polygon fill="none" stroke="black" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/>
+<text text-anchor="start" x="897.38" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+</g>
+<!-- STRUCT_TOP&#45;&gt;STRUCT_SN -->
+<g id="edge39" class="edge">
+<title>STRUCT_TOP&#45;&gt;STRUCT_SN</title>
+<path fill="none" stroke="black" d="M759.21,-475.24C782.17,-443.49 831.3,-375.56 864.63,-329.48"/>
+<polygon fill="black" stroke="black" points="867.37,-331.67 870.4,-321.52 861.7,-327.57 867.37,-331.67"/>
+</g>
+<!-- STRUCT_BOT -->
+<g id="node25" class="node">
+<title>STRUCT_BOT</title>
+<ellipse fill="lightgreen" stroke="black" cx="751.51" cy="-82.75" rx="44.7" ry="18"/>
+<text text-anchor="start" x="726.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="742.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:struct</text>
+</g>
+<!-- STRUCT_BOT&#45;&gt;BOT -->
+<g id="edge43" class="edge">
+<title>STRUCT_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M725.72,-67.77C709,-58.7 687.2,-46.89 669.97,-37.55"/>
+<polygon fill="black" stroke="black" points="671.71,-34.51 661.25,-32.82 668.37,-40.67 671.71,-34.51"/>
+</g>
+<!-- STRUCT_S1&#45;&gt;STRUCT_BOT -->
+<g id="edge40" class="edge">
+<title>STRUCT_S1&#45;&gt;STRUCT_BOT</title>
+<path fill="none" stroke="black" d="M706.86,-264.91C715.3,-230.49 733.97,-154.31 744.29,-112.19"/>
+<polygon fill="black" stroke="black" points="747.69,-113.04 746.67,-102.5 740.89,-111.37 747.69,-113.04"/>
+</g>
+<!-- STRUCT_S1&#45;&gt;STRUCT_S2 -->
+<!-- STRUCT_S2&#45;&gt;STRUCT_BOT -->
+<g id="edge41" class="edge">
+<title>STRUCT_S2&#45;&gt;STRUCT_BOT</title>
+<path fill="none" stroke="black" d="M792.36,-256.52C783.62,-219.3 767.61,-151.25 758.45,-112.26"/>
+<polygon fill="black" stroke="black" points="761.88,-111.57 756.18,-102.64 755.07,-113.17 761.88,-111.57"/>
+</g>
+<!-- STRUCT_S2&#45;&gt;STRUCT_SN -->
+<!-- STRUCT_SN&#45;&gt;STRUCT_BOT -->
+<g id="edge42" class="edge">
+<title>STRUCT_SN&#45;&gt;STRUCT_BOT</title>
+<path fill="none" stroke="black" d="M870.86,-245.05C841.74,-205.46 796.64,-144.13 771.03,-109.3"/>
+<polygon fill="black" stroke="black" points="773.99,-107.42 765.25,-101.44 768.36,-111.57 773.99,-107.42"/>
+</g>
+<!-- MEM_ALIAS1 -->
+<g id="node31" class="node">
+<title>MEM_ALIAS1</title>
+<ellipse fill="blue" stroke="black" cx="975.51" cy="-282.65" rx="20.13" ry="20.13"/>
+<text text-anchor="middle" x="975.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#1</text>
+</g>
+<!-- MEM_TOP&#45;&gt;MEM_ALIAS1 -->
+<g id="edge47" class="edge">
+<title>MEM_TOP&#45;&gt;MEM_ALIAS1</title>
+<path fill="none" stroke="black" d="M996.51,-474.51C992.58,-438.66 983.84,-358.73 978.96,-314.18"/>
+<polygon fill="black" stroke="black" points="982.45,-313.94 977.89,-304.38 975.5,-314.7 982.45,-313.94"/>
+</g>
+<!-- MEM_ALIASDOTS -->
+<g id="node32" class="node">
+<title>MEM_ALIASDOTS</title>
+<ellipse fill="blue" stroke="black" cx="1036.51" cy="-282.65" rx="27" ry="18"/>
+<text text-anchor="middle" x="1036.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text>
+</g>
+<!-- MEM_TOP&#45;&gt;MEM_ALIASDOTS -->
+<g id="edge48" class="edge">
+<title>MEM_TOP&#45;&gt;MEM_ALIASDOTS</title>
+<path fill="none" stroke="black" d="M1001.81,-474.51C1008.41,-438.02 1023.27,-355.86 1031.23,-311.83"/>
+<polygon fill="black" stroke="black" points="1034.63,-312.69 1032.97,-302.23 1027.74,-311.45 1034.63,-312.69"/>
+</g>
+<!-- MEM_ALIASN -->
+<g id="node33" class="node">
+<title>MEM_ALIASN</title>
+<ellipse fill="blue" stroke="black" cx="1097.51" cy="-282.65" rx="20.13" ry="20.13"/>
+<text text-anchor="middle" x="1097.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#n</text>
+</g>
+<!-- MEM_TOP&#45;&gt;MEM_ALIASN -->
+<g id="edge49" class="edge">
+<title>MEM_TOP&#45;&gt;MEM_ALIASN</title>
+<path fill="none" stroke="black" d="M1006.95,-474.88C1024.11,-438.46 1063.18,-355.52 1083.95,-311.44"/>
+<polygon fill="black" stroke="black" points="1087.07,-313.03 1088.16,-302.49 1080.73,-310.05 1087.07,-313.03"/>
+</g>
+<!-- MEM_BOT -->
+<g id="node30" class="node">
+<title>MEM_BOT</title>
+<ellipse fill="blue" stroke="black" cx="998.51" cy="-82.75" rx="43.67" ry="18"/>
+<text text-anchor="start" x="974.51" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text>
+<text text-anchor="start" x="990.26" y="-78.7" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text>
+</g>
+<!-- MEM_BOT&#45;&gt;BOT -->
+<g id="edge53" class="edge">
+<title>MEM_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M958.6,-75.08C887.17,-63.15 738.86,-38.38 673.56,-27.48"/>
+<polygon fill="black" stroke="black" points="674.3,-24.05 663.86,-25.86 673.15,-30.96 674.3,-24.05"/>
+</g>
+<!-- MEM_ALIAS1&#45;&gt;MEM_BOT -->
+<g id="edge50" class="edge">
+<title>MEM_ALIAS1&#45;&gt;MEM_BOT</title>
+<path fill="none" stroke="black" d="M977.84,-262.38C981.92,-226.96 990.35,-153.62 995.09,-112.45"/>
+<polygon fill="black" stroke="black" points="998.57,-112.87 996.23,-102.53 991.61,-112.07 998.57,-112.87"/>
+</g>
+<!-- MEM_ALIAS1&#45;&gt;MEM_ALIASDOTS -->
+<!-- MEM_ALIASDOTS&#45;&gt;MEM_BOT -->
+<g id="edge51" class="edge">
+<title>MEM_ALIASDOTS&#45;&gt;MEM_BOT</title>
+<path fill="none" stroke="black" d="M1033.07,-264.56C1026.49,-229.93 1012.06,-154.01 1004.08,-112.06"/>
+<polygon fill="black" stroke="black" points="1007.56,-111.6 1002.25,-102.43 1000.68,-112.91 1007.56,-111.6"/>
+</g>
+<!-- MEM_ALIASDOTS&#45;&gt;MEM_ALIASN -->
+<!-- MEM_ALIASN&#45;&gt;MEM_BOT -->
+<g id="edge52" class="edge">
+<title>MEM_ALIASN&#45;&gt;MEM_BOT</title>
+<path fill="none" stroke="black" d="M1088.37,-264.2C1070.97,-229.07 1032.98,-152.35 1012.41,-110.82"/>
+<polygon fill="black" stroke="black" points="1015.58,-109.34 1008.01,-101.93 1009.31,-112.45 1015.58,-109.34"/>
+</g>
+<!-- TUPLE1 -->
+<g id="node36" class="node">
+<title>TUPLE1</title>
+<polygon fill="none" stroke="none" points="1185.51,-309.15 1131.51,-309.15 1131.51,-256.15 1185.51,-256.15 1185.51,-309.15"/>
+<polygon fill="pink" stroke="none" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/>
+<polygon fill="none" stroke="black" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/>
+<text text-anchor="start" x="1142.76" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
+<polygon fill="black" stroke="none" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/>
+<polygon fill="none" stroke="black" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/>
+<text text-anchor="start" x="1146.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+</g>
+<!-- TUPLE_TOP&#45;&gt;TUPLE1 -->
+<g id="edge57" class="edge">
+<title>TUPLE_TOP&#45;&gt;TUPLE1</title>
+<path fill="none" stroke="black" d="M1180.42,-474.51C1176.51,-440.23 1167.99,-365.66 1162.8,-320.24"/>
+<polygon fill="black" stroke="black" points="1166.28,-319.86 1161.67,-310.32 1159.33,-320.65 1166.28,-319.86"/>
+</g>
+<!-- TUPLE2 -->
+<g id="node37" class="node">
+<title>TUPLE2</title>
+<polygon fill="none" stroke="none" points="1253.51,-320.4 1199.51,-320.4 1199.51,-244.9 1253.51,-244.9 1253.51,-320.4"/>
+<polygon fill="pink" stroke="none" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/>
+<polygon fill="none" stroke="black" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/>
+<text text-anchor="start" x="1210.76" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
+<polygon fill="black" stroke="none" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/>
+<polygon fill="none" stroke="black" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/>
+<text text-anchor="start" x="1214.88" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+<polygon fill="black" stroke="none" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/>
+<polygon fill="none" stroke="black" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/>
+<text text-anchor="start" x="1214.88" y="-255.1" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+</g>
+<!-- TUPLE_TOP&#45;&gt;TUPLE2 -->
+<g id="edge58" class="edge">
+<title>TUPLE_TOP&#45;&gt;TUPLE2</title>
+<path fill="none" stroke="black" d="M1186.34,-474.51C1192.95,-442.94 1206.72,-377.19 1216.28,-331.51"/>
+<polygon fill="black" stroke="black" points="1219.68,-332.35 1218.3,-321.85 1212.83,-330.92 1219.68,-332.35"/>
+</g>
+<!-- TUPLEN -->
+<g id="node38" class="node">
+<title>TUPLEN</title>
+<polygon fill="none" stroke="none" points="1321.51,-331.65 1267.51,-331.65 1267.51,-233.65 1321.51,-233.65 1321.51,-331.65"/>
+<polygon fill="pink" stroke="none" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/>
+<polygon fill="none" stroke="black" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/>
+<text text-anchor="start" x="1278.76" y="-311.35" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
+<polygon fill="black" stroke="none" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/>
+<polygon fill="none" stroke="black" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/>
+<text text-anchor="start" x="1282.88" y="-288.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+<polygon fill="black" stroke="none" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/>
+<polygon fill="none" stroke="black" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/>
+<text text-anchor="start" x="1288.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text>
+<polygon fill="black" stroke="none" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/>
+<polygon fill="none" stroke="black" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/>
+<text text-anchor="start" x="1282.88" y="-243.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+</g>
+<!-- TUPLE_TOP&#45;&gt;TUPLEN -->
+<g id="edge59" class="edge">
+<title>TUPLE_TOP&#45;&gt;TUPLEN</title>
+<path fill="none" stroke="black" d="M1192.06,-474.88C1207.65,-445.62 1239.24,-386.36 1263.24,-341.32"/>
+<polygon fill="black" stroke="black" points="1266.22,-343.18 1267.83,-332.71 1260.04,-339.88 1266.22,-343.18"/>
+</g>
+<!-- TUPLE_BOT -->
+<g id="node35" class="node">
+<title>TUPLE_BOT</title>
+<ellipse fill="pink" stroke="black" cx="1192.51" cy="-82.75" rx="42.65" ry="18"/>
+<text text-anchor="start" x="1169.26" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="1185.01" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:tuple</text>
+</g>
+<!-- TUPLE_BOT&#45;&gt;BOT -->
+<g id="edge63" class="edge">
+<title>TUPLE_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M1151.54,-77.32C1046.53,-65.95 769.32,-35.95 674.14,-25.65"/>
+<polygon fill="black" stroke="black" points="674.52,-22.18 664.2,-24.58 673.77,-29.14 674.52,-22.18"/>
+</g>
+<!-- TUPLE1&#45;&gt;TUPLE_BOT -->
+<g id="edge60" class="edge">
+<title>TUPLE1&#45;&gt;TUPLE_BOT</title>
+<path fill="none" stroke="black" d="M1162.95,-256.52C1169.28,-219.3 1180.86,-151.25 1187.49,-112.26"/>
+<polygon fill="black" stroke="black" points="1190.9,-113.1 1189.12,-102.66 1184,-111.93 1190.9,-113.1"/>
+</g>
+<!-- TUPLE2&#45;&gt;TUPLE_BOT -->
+<g id="edge61" class="edge">
+<title>TUPLE2&#45;&gt;TUPLE_BOT</title>
+<path fill="none" stroke="black" d="M1220.11,-245.05C1213.55,-206.44 1203.46,-147.16 1197.47,-111.94"/>
+<polygon fill="black" stroke="black" points="1200.99,-111.74 1195.86,-102.47 1194.09,-112.92 1200.99,-111.74"/>
+</g>
+<!-- TUPLEN&#45;&gt;TUPLE_BOT -->
+<g id="edge62" class="edge">
+<title>TUPLEN&#45;&gt;TUPLE_BOT</title>
+<path fill="none" stroke="black" d="M1269.56,-233.75C1249.85,-195.12 1223.04,-142.58 1206.8,-110.75"/>
+<polygon fill="black" stroke="black" points="1210.07,-109.46 1202.41,-102.15 1203.83,-112.65 1210.07,-109.46"/>
+</g>
+</g>
+</svg>
diff --git a/chapter18/docs/lattice2.gv b/chapter18/docs/lattice2.gv
new file mode 100644
index 00000000..6aa37fa0
--- /dev/null
+++ b/chapter18/docs/lattice2.gv
@@ -0,0 +1,85 @@
+digraph Lattice {
+ compound = true;
+ // Define nodes
+ splines=false;
+ node [shape=oval, style=filled];
+ nodesep=0.2;
+ ranksep=0.4;
+
+ TOP [label="~scalar\n+int+tmp+0", fillcolor=black, fontcolor=white, group=center];
+
+ // ------------------------
+ PTRHQ [label="~tmp\n+tmp+0", fillcolor=green, fontcolor=white, group=left];
+ TOP -> PTRHQ
+
+ VALH_ [label="~nscalar\n+int+tmp", fillcolor=white, group=center];
+ TOP -> VALH_
+
+ INTHQ [label="~int\n+int+0", fillcolor=lightblue, group=right];
+ TOP -> INTHQ
+
+ LEFTHI [label="junk", style=invis, group=junkleft]
+
+
+ PTRHQ -> LEFTHI-> VALH_ -> INTHQ [style=invis];
+ { rank=same; PTRHQ; LEFTHI; VALH_; INTHQ }
+
+ // ------------------------
+ PTRH_ [label="~ntmp\n+tmp", fillcolor=green, fontcolor=white, group=left];
+ VALH_ -> PTRH_
+ PTRHQ -> PTRH_
+
+ INTH_ [label="~nint\n+int", fillcolor=lightblue, group=right];
+ VALH_ -> INTH_
+ INTHQ -> INTH_
+ { rank=same; PTRH_; INTH_ }
+
+ // ------------------------
+ NILX_ [label="~nil\n[int,tmp]+0", fillcolor=aqua, group=junkleft];
+ INTHQ -> NILX_
+ PTRHQ -> NILX_
+
+ NIL__ [label="nil\n[+int+tmp],0", fillcolor=pink];
+ VALH_ -> NIL__;
+
+ NILX_ -> NIL__ [style=invis];
+ { rank=same; NIL__; NILX_ }
+
+ // ------------------------
+ PTRL_ [label="ntmp\ntmp", fillcolor=green, fontcolor=white, group=left];
+ PTRH_ -> PTRL_
+
+ INTL_ [label="nint\nint", fillcolor=lightblue, group=right];
+ INTH_ -> INTL_
+ { rank=same; PTRL_; INTL_ }
+
+ // ------------------------
+ PTRL0 [label="tmp\ntmp,0", fillcolor=green, fontcolor=white, group=left];
+ PTRL_ -> PTRL0
+ NIL__ -> PTRL0
+
+ VALL_ [label="nscalar\nint,tmp", fillcolor=white, group=center];
+ PTRL_ -> VALL_
+ INTL_ -> VALL_
+ NILX_ -> VALL_
+
+ INTL0 [label="int\nint,0", fillcolor=lightblue, group=right];
+ INTL_ -> INTL0
+ NIL__ -> INTL0
+
+ PTRL0 -> VALL_ -> INTL0 [style=invis];
+ { rank=same; PTRL0; VALL_; INTL0 }
+
+ // ------------------------
+ BOT [label="scalar\nint,tmp,0", fillcolor=black, fontcolor=white, group=center];
+ PTRL0 -> BOT
+ INTL0 -> BOT
+ VALL_ -> BOT
+
+ // ------------------------
+ // Verticle alignment
+ TOP -> VALH_ -> VALL_ -> BOT [style=invis];
+ PTRHQ -> PTRH_ -> PTRL_ -> PTRL0 [style=invis];
+ INTHQ -> INTH_ -> INTL_ -> INTL0 [style=invis];
+ LEFTHI -> NILX_ [style=invis]
+}
diff --git a/chapter18/docs/lattice2.svg b/chapter18/docs/lattice2.svg
new file mode 100644
index 00000000..857bca2d
--- /dev/null
+++ b/chapter18/docs/lattice2.svg
@@ -0,0 +1,260 @@
+<?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 12.2.0 (20241103.1931)
+ -->
+<!-- Title: Lattice Pages: 1 -->
+<svg width="478pt" height="501pt"
+ viewBox="0.00 0.00 477.96 500.90" 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 496.9)">
+<title>Lattice</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-496.9 473.96,-496.9 473.96,4 -4,4"/>
+<!-- TOP -->
+<g id="node1" class="node">
+<title>TOP</title>
+<ellipse fill="black" stroke="black" cx="240.13" cy="-463.91" rx="59.04" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-467.11" font-family="Times New Roman,serif" font-size="14.00" fill="white">~scalar</text>
+<text text-anchor="middle" x="240.13" y="-450.61" font-family="Times New Roman,serif" font-size="14.00" fill="white">+int+tmp+0</text>
+</g>
+<!-- PTRHQ -->
+<g id="node2" class="node">
+<title>PTRHQ</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-376.92" rx="43.13" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00" fill="white">~tmp</text>
+<text text-anchor="middle" x="43.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp+0</text>
+</g>
+<!-- TOP&#45;&gt;PTRHQ -->
+<g id="edge1" class="edge">
+<title>TOP&#45;&gt;PTRHQ</title>
+<path fill="none" stroke="black" d="M196.41,-444.04C164.74,-430.38 121.99,-411.94 89.68,-398"/>
+<polygon fill="black" stroke="black" points="91.11,-394.81 80.55,-394.06 88.34,-401.24 91.11,-394.81"/>
+</g>
+<!-- VALH_ -->
+<g id="node3" class="node">
+<title>VALH_</title>
+<ellipse fill="white" stroke="black" cx="240.13" cy="-376.92" rx="48.44" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~nscalar</text>
+<text text-anchor="middle" x="240.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+tmp</text>
+</g>
+<!-- TOP&#45;&gt;VALH_ -->
+<g id="edge2" class="edge">
+<title>TOP&#45;&gt;VALH_</title>
+<path fill="none" stroke="black" d="M235.15,-434.61C234.93,-429.02 234.85,-423.06 234.9,-417.18"/>
+<polygon fill="black" stroke="black" points="238.39,-417.69 235.12,-407.61 231.39,-417.52 238.39,-417.69"/>
+</g>
+<!-- TOP&#45;&gt;VALH_ -->
+<!-- INTHQ -->
+<g id="node4" class="node">
+<title>INTHQ</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-376.92" rx="37.83" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~int</text>
+<text text-anchor="middle" x="432.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+0</text>
+</g>
+<!-- TOP&#45;&gt;INTHQ -->
+<g id="edge3" class="edge">
+<title>TOP&#45;&gt;INTHQ</title>
+<path fill="none" stroke="black" d="M283.22,-443.83C314.91,-429.81 357.78,-410.83 389.39,-396.84"/>
+<polygon fill="black" stroke="black" points="390.53,-400.16 398.26,-392.92 387.7,-393.76 390.53,-400.16"/>
+</g>
+<!-- LEFTHI -->
+<!-- PTRHQ&#45;&gt;LEFTHI -->
+<!-- PTRH_ -->
+<g id="node6" class="node">
+<title>PTRH_</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-289.94" rx="36.77" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00" fill="white">~ntmp</text>
+<text text-anchor="middle" x="43.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp</text>
+</g>
+<!-- PTRHQ&#45;&gt;PTRH_ -->
+<g id="edge8" class="edge">
+<title>PTRHQ&#45;&gt;PTRH_</title>
+<path fill="none" stroke="black" d="M38.15,-347.62C37.93,-342.03 37.85,-336.07 37.9,-330.2"/>
+<polygon fill="black" stroke="black" points="41.39,-330.71 38.12,-320.63 34.39,-330.54 41.39,-330.71"/>
+</g>
+<!-- PTRHQ&#45;&gt;PTRH_ -->
+<!-- NILX_ -->
+<g id="node8" class="node">
+<title>NILX_</title>
+<ellipse fill="aqua" stroke="black" cx="150.13" cy="-289.94" rx="56.39" ry="28.99"/>
+<text text-anchor="middle" x="150.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nil</text>
+<text text-anchor="middle" x="150.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[int,tmp]+0</text>
+</g>
+<!-- PTRHQ&#45;&gt;NILX_ -->
+<g id="edge12" class="edge">
+<title>PTRHQ&#45;&gt;NILX_</title>
+<path fill="none" stroke="black" d="M70.41,-354.26C82.91,-344.33 97.94,-332.4 111.56,-321.58"/>
+<polygon fill="black" stroke="black" points="113.43,-324.56 119.09,-315.6 109.08,-319.08 113.43,-324.56"/>
+</g>
+<!-- VALH_&#45;&gt;INTHQ -->
+<!-- VALH_&#45;&gt;PTRH_ -->
+<g id="edge7" class="edge">
+<title>VALH_&#45;&gt;PTRH_</title>
+<path fill="none" stroke="black" d="M201.21,-359.13C167.78,-344.71 119.68,-323.96 85.33,-309.14"/>
+<polygon fill="black" stroke="black" points="87.1,-306.09 76.53,-305.35 84.33,-312.52 87.1,-306.09"/>
+</g>
+<!-- INTH_ -->
+<g id="node7" class="node">
+<title>INTH_</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-289.94" rx="31.47" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nint</text>
+<text text-anchor="middle" x="432.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">+int</text>
+</g>
+<!-- VALH_&#45;&gt;INTH_ -->
+<g id="edge9" class="edge">
+<title>VALH_&#45;&gt;INTH_</title>
+<path fill="none" stroke="black" d="M278.53,-358.93C311.9,-344.16 360.02,-322.86 393.48,-308.05"/>
+<polygon fill="black" stroke="black" points="394.67,-311.35 402.4,-304.1 391.84,-304.95 394.67,-311.35"/>
+</g>
+<!-- NIL__ -->
+<g id="node9" class="node">
+<title>NIL__</title>
+<ellipse fill="pink" stroke="black" cx="324.13" cy="-289.94" rx="62.23" ry="28.99"/>
+<text text-anchor="middle" x="324.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">nil</text>
+<text text-anchor="middle" x="324.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[+int+tmp],0</text>
+</g>
+<!-- VALH_&#45;&gt;NIL__ -->
+<g id="edge13" class="edge">
+<title>VALH_&#45;&gt;NIL__</title>
+<path fill="none" stroke="black" d="M264.43,-351.34C272.67,-343.01 282.01,-333.55 290.83,-324.64"/>
+<polygon fill="black" stroke="black" points="293.12,-327.3 297.66,-317.72 288.14,-322.38 293.12,-327.3"/>
+</g>
+<!-- VALL_ -->
+<g id="node13" class="node">
+<title>VALL_</title>
+<ellipse fill="white" stroke="black" cx="240.13" cy="-115.97" rx="39.42" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">nscalar</text>
+<text text-anchor="middle" x="240.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,tmp</text>
+</g>
+<!-- VALH_&#45;&gt;VALL_ -->
+<!-- INTHQ&#45;&gt;INTH_ -->
+<g id="edge10" class="edge">
+<title>INTHQ&#45;&gt;INTH_</title>
+<path fill="none" stroke="black" d="M427.17,-348.1C426.94,-342.37 426.85,-336.25 426.9,-330.21"/>
+<polygon fill="black" stroke="black" points="430.39,-330.42 427.13,-320.34 423.39,-330.26 430.39,-330.42"/>
+</g>
+<!-- INTHQ&#45;&gt;INTH_ -->
+<!-- INTHQ&#45;&gt;NILX_ -->
+<g id="edge11" class="edge">
+<title>INTHQ&#45;&gt;NILX_</title>
+<path fill="none" stroke="black" d="M396.99,-365.33C350,-351.17 266.03,-325.87 209.23,-308.75"/>
+<polygon fill="black" stroke="black" points="210.28,-305.41 199.69,-305.88 208.26,-312.11 210.28,-305.41"/>
+</g>
+<!-- LEFTHI&#45;&gt;VALH_ -->
+<!-- LEFTHI&#45;&gt;NILX_ -->
+<!-- PTRL_ -->
+<g id="node10" class="node">
+<title>PTRL_</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-202.96" rx="31.47" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00" fill="white">ntmp</text>
+<text text-anchor="middle" x="43.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text>
+</g>
+<!-- PTRH_&#45;&gt;PTRL_ -->
+<g id="edge15" class="edge">
+<title>PTRH_&#45;&gt;PTRL_</title>
+<path fill="none" stroke="black" d="M38.17,-261.11C37.94,-255.39 37.85,-249.26 37.9,-243.22"/>
+<polygon fill="black" stroke="black" points="41.39,-243.44 38.13,-233.36 34.39,-243.27 41.39,-243.44"/>
+</g>
+<!-- PTRH_&#45;&gt;PTRL_ -->
+<!-- INTL_ -->
+<g id="node11" class="node">
+<title>INTL_</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-202.96" rx="27" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00">nint</text>
+<text text-anchor="middle" x="432.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00">int</text>
+</g>
+<!-- INTH_&#45;&gt;INTL_ -->
+<g id="edge16" class="edge">
+<title>INTH_&#45;&gt;INTL_</title>
+<path fill="none" stroke="black" d="M427.17,-261.11C426.94,-255.39 426.85,-249.26 426.9,-243.22"/>
+<polygon fill="black" stroke="black" points="430.39,-243.44 427.13,-233.36 423.39,-243.27 430.39,-243.44"/>
+</g>
+<!-- INTH_&#45;&gt;INTL_ -->
+<!-- NILX_&#45;&gt;NIL__ -->
+<!-- NILX_&#45;&gt;VALL_ -->
+<g id="edge21" class="edge">
+<title>NILX_&#45;&gt;VALL_</title>
+<path fill="none" stroke="black" d="M164.79,-261.6C180.03,-232.15 203.95,-185.91 220.74,-153.45"/>
+<polygon fill="black" stroke="black" points="223.74,-155.27 225.23,-144.78 217.53,-152.06 223.74,-155.27"/>
+</g>
+<!-- PTRL0 -->
+<g id="node12" class="node">
+<title>PTRL0</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-115.97" rx="34.12" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text>
+<text text-anchor="middle" x="43.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp,0</text>
+</g>
+<!-- NIL__&#45;&gt;PTRL0 -->
+<g id="edge18" class="edge">
+<title>NIL__&#45;&gt;PTRL0</title>
+<path fill="none" stroke="black" d="M286.24,-266.48C232.36,-233.13 134.24,-172.38 80.6,-139.17"/>
+<polygon fill="black" stroke="black" points="82.76,-136.39 72.41,-134.1 79.07,-142.34 82.76,-136.39"/>
+</g>
+<!-- INTL0 -->
+<g id="node14" class="node">
+<title>INTL0</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-115.97" rx="28.81" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">int</text>
+<text text-anchor="middle" x="432.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,0</text>
+</g>
+<!-- NIL__&#45;&gt;INTL0 -->
+<g id="edge23" class="edge">
+<title>NIL__&#45;&gt;INTL0</title>
+<path fill="none" stroke="black" d="M341.49,-261.99C360.34,-231.61 390.49,-183.05 410.79,-150.35"/>
+<polygon fill="black" stroke="black" points="413.65,-152.38 415.95,-142.04 407.7,-148.69 413.65,-152.38"/>
+</g>
+<!-- PTRL_&#45;&gt;PTRL0 -->
+<g id="edge17" class="edge">
+<title>PTRL_&#45;&gt;PTRL0</title>
+<path fill="none" stroke="black" d="M38.17,-174.13C37.94,-168.47 37.85,-162.41 37.9,-156.43"/>
+<polygon fill="black" stroke="black" points="41.39,-156.75 38.12,-146.67 34.39,-156.58 41.39,-156.75"/>
+</g>
+<!-- PTRL_&#45;&gt;PTRL0 -->
+<!-- PTRL_&#45;&gt;VALL_ -->
+<g id="edge19" class="edge">
+<title>PTRL_&#45;&gt;VALL_</title>
+<path fill="none" stroke="black" d="M71.36,-189.78C103.94,-175.73 157.92,-152.44 196.04,-135.99"/>
+<polygon fill="black" stroke="black" points="197.16,-139.32 204.96,-132.15 194.39,-132.9 197.16,-139.32"/>
+</g>
+<!-- INTL_&#45;&gt;VALL_ -->
+<g id="edge20" class="edge">
+<title>INTL_&#45;&gt;VALL_</title>
+<path fill="none" stroke="black" d="M407.43,-191.02C376.23,-177.21 322.01,-153.22 283.77,-136.29"/>
+<polygon fill="black" stroke="black" points="285.39,-133.18 274.83,-132.33 282.55,-139.58 285.39,-133.18"/>
+</g>
+<!-- INTL_&#45;&gt;INTL0 -->
+<g id="edge22" class="edge">
+<title>INTL_&#45;&gt;INTL0</title>
+<path fill="none" stroke="black" d="M427.17,-174.13C426.94,-168.41 426.85,-162.28 426.9,-156.24"/>
+<polygon fill="black" stroke="black" points="430.39,-156.46 427.13,-146.38 423.39,-156.29 430.39,-156.46"/>
+</g>
+<!-- INTL_&#45;&gt;INTL0 -->
+<!-- PTRL0&#45;&gt;VALL_ -->
+<!-- BOT -->
+<g id="node15" class="node">
+<title>BOT</title>
+<ellipse fill="black" stroke="black" cx="240.13" cy="-28.99" rx="46.85" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-32.19" font-family="Times New Roman,serif" font-size="14.00" fill="white">scalar</text>
+<text text-anchor="middle" x="240.13" y="-15.69" font-family="Times New Roman,serif" font-size="14.00" fill="white">int,tmp,0</text>
+</g>
+<!-- PTRL0&#45;&gt;BOT -->
+<g id="edge26" class="edge">
+<title>PTRL0&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M73.48,-101.88C105.02,-88.28 154.83,-66.79 191.79,-50.85"/>
+<polygon fill="black" stroke="black" points="193.14,-54.08 200.94,-46.9 190.37,-47.65 193.14,-54.08"/>
+</g>
+<!-- VALL_&#45;&gt;INTL0 -->
+<!-- VALL_&#45;&gt;BOT -->
+<g id="edge28" class="edge">
+<title>VALL_&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M235.17,-87.15C234.94,-81.48 234.85,-75.42 234.9,-69.44"/>
+<polygon fill="black" stroke="black" points="238.39,-69.76 235.12,-59.68 231.39,-69.6 238.39,-69.76"/>
+</g>
+<!-- VALL_&#45;&gt;BOT -->
+<!-- INTL0&#45;&gt;BOT -->
+<g id="edge27" class="edge">
+<title>INTL0&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M405.84,-103.34C375.52,-89.91 325.06,-67.58 287.78,-51.08"/>
+<polygon fill="black" stroke="black" points="289.59,-48.05 279.03,-47.21 286.75,-54.45 289.59,-48.05"/>
+</g>
+</g>
+</svg>
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/IterPeeps.java b/chapter18/src/main/java/com/seaofnodes/simple/IterPeeps.java
index c0b34263..aad9bf31 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/IterPeeps.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/IterPeeps.java
@@ -115,7 +115,7 @@ public abstract class IterPeeps {
int old_cnt = Node.ITER_CNT, old_nop = Node.ITER_NOP_CNT;
Node changed = stop.walk( n -> {
Node m = n;
- if( n.compute().isa(n._type) && (!n.iskeep() || n._nid<=5) ) { // Types must be forwards, even if on worklist
+ if( n.compute().isa(n._type) && (!n.iskeep() || n._nid<=6) ) { // Types must be forwards, even if on worklist
if( WORK.on(n) ) return null;
m = n.peepholeOpt();
if( m==null ) return null;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java
index d208fc0c..7b8f2631 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java
@@ -198,7 +198,7 @@ public class JSViewer implements AutoCloseable {
if( level==0 && n!=null && n.nIns()>2 ) {
sb.i().p("<TR>");
for( int m=2; m<n.nIns(); m++ )
- cell(sb,"#"+m,n.in(m),"m"+m);
+ cell(sb,"#"+m,n.alias(m),"m"+m);
sb.p("</TR>\n"); // End scope level
}
// Scope variables, empty if none
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
index 04af20f7..f7b7d0e9 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
@@ -24,6 +24,7 @@ public class Parser {
public static StartNode START;
public static ConstantNode ZERO; // Very common node, cached here
+ public static ConstantNode NIL; // Very common node, cached here
public static XCtrlNode XCTRL; // Very common node, cached here
// Next available memory alias number
@@ -110,7 +111,8 @@ public class Parser {
_continueScope = _breakScope = null;
START = new StartNode(arg);
STOP = new StopNode(source);
- ZERO = con(0).keep();
+ ZERO = con(TypeInteger.ZERO).keep();
+ NIL = con(Type.NIL).keep();
XCTRL= new XCtrlNode().peephole().keep();
ALIAS = 2; // alias 0 for the control, 1 for memory
TYPES = defaultTypes();
@@ -124,9 +126,9 @@ public class Parser {
return new HashMap<>() {{
put("bool",TypeInteger.U1 );
put("byte",TypeInteger.U8 );
- put("f32" ,TypeFloat .B32);
- put("f64" ,TypeFloat .BOT);
- put("flt" ,TypeFloat .BOT);
+ put("f32" ,TypeFloat .F32);
+ put("f64" ,TypeFloat .F64);
+ put("flt" ,TypeFloat .F64);
put("i16" ,TypeInteger.I16);
put("i32" ,TypeInteger.I32);
put("i64" ,TypeInteger.BOT);
@@ -170,7 +172,7 @@ public class Parser {
for( StructNode init : INITS.values() )
init.unkeep().kill();
INITS.clear();
- if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken());
+ if( !_lexer.isEOF() ) throw _errorSyntax("unexpected");
STOP.peephole();
JSViewer.show();
if( show ) showGraph();
@@ -207,7 +209,6 @@ public class Parser {
private Node parseStatement() {
if( false ) return null;
else if (matchx("return") ) return parseReturn();
- else if (match ("{") ) return require(parseBlock(false),"}");
else if (matchx("if") ) return parseIf();
else if (matchx("while") ) return parseWhile();
else if (matchx("for") ) return parseFor();
@@ -216,6 +217,11 @@ public class Parser {
else if (matchx("struct") ) return parseStruct();
else if (matchx("#showGraph")) return require(showGraph(),";");
else if (matchx(";") ) return null; // Empty statement
+ // Break ambiguity around leading function types and starting a block
+ else if (peek('{') && !isTypeFun() ) {
+ match("{");
+ return require(parseBlock(false),"}");
+ }
// Declaration or normal assignment/expression
else return parseDeclarationStatement();
}
@@ -378,7 +384,7 @@ public class Parser {
return toScope;
}
- private void checkLoopActive() { if (_breakScope == null) throw Parser.error("No active loop for a break or continue"); }
+ private void checkLoopActive() { if (_breakScope == null) throw error("No active loop for a break or continue"); }
private Node parseContinue() { checkLoopActive(); return (_continueScope = require(jumpTo( _continueScope ),";")); }
private Node parseBreak () {
@@ -602,13 +608,16 @@ public class Parser {
// var is always not-final, final if no Bang AND TMP since primitives are not-final by default
(t!=Type.BOTTOM && !hasBang && (t instanceof TypeMemPtr));
// var/val, then type comes from expression
- if( inferType )
+ if( inferType ) {
+ if( expr._type==Type.NIL )
+ throw error("a not-null/non-zero expression");
t = expr._type.glb();
+ }
} else {
if( inferType && !_scope.inCon() )
throw errorSyntax("=expression");
- expr = con(t.makeInit());
+ expr = t instanceof TypeMemPtr tn ? (tn._nil==3 ? NIL : con(Type.TOP)) : (t==Type.BOTTOM ? con(t) : ZERO);
}
// Lift expression, based on type
@@ -632,11 +641,11 @@ public class Parser {
* @return The statement following the struct
*/
private Node parseStruct() {
- if (_xScopes.size() > 1) throw errorSyntax("struct declarations can only appear in top level scope");
+ if (_xScopes.size() > 1) throw error("struct declarations can only appear in top level scope");
String typeName = requireId();
Type t = TYPES.get(typeName);
if( t!=null && !(t instanceof TypeMemPtr tmp && tmp.isFRef() ) )
- throw errorSyntax("struct '" + typeName + "' cannot be redefined");
+ throw error("struct '" + typeName + "' cannot be redefined");
// A Block scope parse, and inspect the scope afterward for fields.
_scope.push(true);
@@ -655,7 +664,7 @@ public class Parser {
fs[i-lexlen] = Field.make(v._name,v.type(),ALIAS++,v._final);
}
TypeStruct ts = s._ts = TypeStruct.make(typeName, fs);
- TYPES.put(typeName, TypeMemPtr.make(ts));
+ TYPES.put(typeName, TypeMemPtr.make((byte)2,ts));
INITS.put(typeName,s.peephole().keep());
// Done with struct/block scope
require("}");
@@ -673,23 +682,28 @@ public class Parser {
// t = int|i8|i16|i32|i64|u8|u16|u32|u64|byte|bool | flt|f32|f64 | val | var | struct[?]
private Type type() {
int old1 = pos();
+ // Only type with a leading `{` is a function pointer...
+ if( peek('{') ) return typeFunPtr();
+
+ // Otherwise you get a type name
String tname = _lexer.matchId();
if( tname==null ) return null;
+
// Convert the type name to a type.
Type t0 = TYPES.get(tname);
// No new types as keywords
if( t0 == null && KEYWORDS.contains(tname) )
return posT(old1);
- Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.makeFRef(tname)) : t0; // Null: assume a forward ref type
+ if( t0 == Type.BOTTOM || t0 == Type.TOP ) return t0; // var/val type inference
+ Type t1 = t0 == null ? TypeMemPtr.make((byte)2,TypeStruct.makeFRef(tname)) :t0; // Null: assume a forward ref type
// Nest arrays and '?' as needed
Type t2 = t1;
while( true ) {
- assert !(t2 instanceof TypeStruct);
if( match("?") ) {
if( !(t2 instanceof TypeMemPtr tmp) )
throw error("Type "+t0+" cannot be null");
- if( tmp._nil ) throw error("Type "+t2+" already allows null");
- t2 = TypeMemPtr.make(tmp._obj,true);
+ if( tmp._nil==3 ) throw error("Type "+t2+" already allows null");
+ t2 = tmp.makeFrom((byte)3);
} else if( match("[]") ) {
t2 = typeAry(t2);
} else
@@ -712,7 +726,7 @@ public class Parser {
// Make an array type of t
private TypeMemPtr typeAry( Type t ) {
- if( t instanceof TypeMemPtr tmp && !tmp._nil )
+ if( t instanceof TypeMemPtr tmp && (tmp._nil==1|| tmp._nil==2) )
throw error("Arrays of reference types must always be nullable");
String tname = "["+t.str()+"]";
Type ta = TYPES.get(tname);
@@ -720,20 +734,44 @@ public class Parser {
// Need make an array type.
TypeStruct ts = TypeStruct.makeAry(TypeInteger.BOT,ALIAS++,t,ALIAS++);
assert ts.str().equals(tname);
- TypeMemPtr tary = TypeMemPtr.make(ts);
+ TypeMemPtr tary = TypeMemPtr.make((byte)2,ts);
TYPES.put(tname,tary);
return tary;
}
- // Fixup forward refs lazily. Basically a Union-Find flavored read
- // barrier.
- Type lazyFRef(Type t) {
- //if( !t.isFRef() ) return t;
- //Type def = Parser.TYPES.get(((TypeMemPtr)t)._obj._name);
- throw Utils.TODO();
+ // A function type is `{ type... -> type }` or `{ type }`.
+ private Type typeFunPtr() {
+ int old = pos(); // Record lexer position
+ match("{"); // Skip already-peeked '{'
+ Type t0 = type(); // Either return or first arg
+ if( t0==null ) return posT(old); // Not a function
+ if( match("}") ) // No-arg function { -> type }
+ throw Utils.TODO();
+ Ary<Type> ts = new Ary<>(Type.class);
+ ts.push(null); // Return filled in later
+ ts.push(t0); // First argument
+ while( true ) {
+ if( match("->") ) { // End of arguments, parse return
+ Type ret = type();
+ if( ret==null ) return posT(old);
+ ts.set(0,ret);
+ if( !match("}") ) return posT(old); // Not a function
+ return TypeFunPtr.make(TypeTuple.make(ts.asAry()),match("?"));
+ }
+ Type t1 = type();
+ if( t1==null ) return posT(old); // Not a function
+ ts.push(t1);
+ }
}
+ // True if a TypeFunPtr, without advancing parser
+ private boolean isTypeFun() {
+ int old = pos();
+ if( typeFunPtr()==null ) return false;
+ pos(old);
+ return true;
+ }
/**
* Parse an expression of the form:
@@ -908,7 +946,7 @@ public class Parser {
if( _lexer.isNumber(_lexer.peek()) ) return parseLiteral();
if( matchx("true" ) ) return con(1);
if( matchx("false") ) return ZERO;
- if( matchx("null" ) ) return con(TypeMemPtr.NULLPTR);
+ if( matchx("null" ) ) return NIL;
if( match("(") ) return require(parseAsgn(), ")");
if( matchx("new" ) ) return alloc();
// Expect an identifier now
@@ -1021,7 +1059,7 @@ public class Parser {
// Initial values for every field
for( int i = 0; i < len; i++ )
ns[2+len+i] = init.get(i+idx);
- Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole();
+ Node nnn = new NewNode(TypeMemPtr.make((byte)2,obj), ns).peephole();
for( int i = 0; i < len; i++ )
memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole());
return new ProjNode(nnn,1,obj._name).peephole();
@@ -1032,7 +1070,7 @@ public class Parser {
int base = ary.aryBase ();
int scale= ary.aryScale();
Node size = peep(new AddNode(con(base),peep(new ShlNode(len.keep(),con(scale)))));
- ALTMP.clear(); ALTMP.add(len.unkeep()); ALTMP.add(con(ary._fields[1]._type.makeInit()));
+ ALTMP.clear(); ALTMP.add(len.unkeep()); ALTMP.add(con(ary._fields[1]._type.makeZero()));
return newStruct(ary,size,0,ALTMP);
}
@@ -1061,10 +1099,6 @@ public class Parser {
else if( match("[") ) name = "[]";
else return expr; // No postfix
- // Sanity check expr for being a reference
- if( !(expr._type instanceof TypeMemPtr ptr) )
- throw error("Expected reference but got " + expr._type.str());
-
// Happens when parsing known dead code, which often has other typing
// issues. Since the code is dead, possibly due to inlining, lets not
// spoil the user experience with error messages.
@@ -1072,6 +1106,14 @@ public class Parser {
// Exit out via parsing the trailing expression
return matchOpx('=','=') ? parseAsgn() : parsePostfix(con(Type.TOP));
+ //
+ if( expr._type==Type.NIL )
+ throw error("Accessing unknown field '" + name + "' from 'null'");
+
+ // Sanity check expr for being a reference
+ if( !(expr._type instanceof TypeMemPtr ptr) )
+ throw error("Expected reference but got " + expr._type.str());
+
// Sanity check field name for existing
TypeMemPtr tmp = (TypeMemPtr)TYPES.get(ptr._obj._name);
if( tmp == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr + "'");
@@ -1162,7 +1204,7 @@ public class Parser {
* </pre>
*/
private ConstantNode parseLiteral() { return con(_lexer.parseNumber()); }
- public static Node con( long con ) { return con(TypeInteger.constant(con)); }
+ public static Node con( long con ) { return con==0 ? ZERO : con(TypeInteger.constant(con)); }
public static ConstantNode con( Type t ) { return (ConstantNode)new ConstantNode(t).peephole(); }
public Node peep( Node n ) {
// Peephole, then improve with lexically scoped guards
@@ -1212,13 +1254,11 @@ public class Parser {
throw errorSyntax(syntax);
}
- RuntimeException errorSyntax(String syntax) {
- return error("Syntax error, expected " + syntax + ": " + _lexer.getAnyNextToken());
- }
-
- public static RuntimeException error( String errorMessage ) {
- return new RuntimeException(errorMessage);
+ RuntimeException errorSyntax(String syntax) { return _errorSyntax("expected "+syntax); }
+ private RuntimeException _errorSyntax(String msg) {
+ return _lexer.error("Syntax error, "+msg+": " + _lexer.getAnyNextToken());
}
+ RuntimeException error(String msg) { return _lexer.error(msg); }
////////////////////////////////////
// Lexer components
@@ -1230,6 +1270,11 @@ public class Parser {
// Tracks current position in input buffer
private int _position = 0;
+ //
+ private int _line_number = 1;
+ // Start of current line
+ private int _line_start = 0;
+
/**
* Record the source text for lexing
*/
@@ -1263,9 +1308,16 @@ public class Parser {
// Just crash if misused
public byte peek(int off) { return _input[_position+off]; }
+ private void inc() {
+ if( _position++ < _input.length && _input[_position-1] == '\n' ) {
+ _line_number++;
+ _line_start = _position;
+ }
+ }
+ // Does not honor LF, so caller must roll back position on a LF
private char nextChar() {
char ch = peek();
- _position++;
+ inc();
return ch;
}
@@ -1279,13 +1331,13 @@ public class Parser {
*/
private void skipWhiteSpace() {
while( true ) {
- if( isWhiteSpace() ) _position++;
+ if( isWhiteSpace() ) inc();
// Skip // to end of line
else if( _position+2 < _input.length &&
_input[_position ] == '/' &&
_input[_position+1] == '/') {
- _position += 2;
- while( !isEOF() && _input[_position] != '\n' ) _position++;
+ inc(); inc();
+ while( !isEOF() && _input[_position] != '\n' ) inc();
} else break;
}
}
@@ -1297,6 +1349,7 @@ public class Parser {
// then advance the cursor past syntax.
// Return false otherwise, and do not advance the cursor.
boolean match(String syntax) {
+ assert syntax.indexOf('\n')==-1; // No newlines in match
skipWhiteSpace();
int len = syntax.length();
if (_position + len > _input.length) return false;
@@ -1319,7 +1372,7 @@ public class Parser {
skipWhiteSpace();
if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c1 )
return false;
- _position++;
+ inc();
return true;
}
@@ -1357,7 +1410,8 @@ public class Parser {
if( len > 0 ) {
if( len > 1 && _input[old]=='0' )
throw error("Syntax error: integer values cannot start with '0'");
- return TypeInteger.constant(Long.parseLong(new String(_input,old,len)));
+ long i = Long.parseLong(new String(_input,old,len));
+ return TypeInteger.constant(i);
}
return TypeFloat.constant(Double.parseDouble(new String(_input,old,-len)));
}
@@ -1419,5 +1473,11 @@ public class Parser {
if( ch0 == '-' && ch1 == '-' ) { _position += 2; return (char)-1; }
return 0;
}
+
+ public RuntimeException error( String errorMessage ) {
+ // file:line:charoff err
+ //String msg = "src:"+_line_number+":"+(_position-_line_start)+" "+errorMessage;
+ return new RuntimeException(errorMessage);
+ }
}
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 0834a381..e6704ea6 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -48,7 +48,7 @@ public class AddNode extends Node {
// Add of 0. We do not check for (0+x) because this will already
// canonicalize to (x+0)
- if( t2 instanceof TypeInteger i && i.isConstant() && i.value()==0 )
+ if( t2 == TypeInteger.ZERO )
return lhs;
// Add of same to a multiply by 2
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 7126806d..bf8f7455 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -2,10 +2,7 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import com.seaofnodes.simple.type.TypeFloat;
-import com.seaofnodes.simple.type.TypeMemPtr;
+import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
@@ -35,6 +32,10 @@ abstract public class BoolNode extends Node {
public TypeInteger compute() {
Type t1 = in(1)._type;
Type t2 = in(2)._type;
+ // Exactly equals?
+ if( in(1)==in(2) )
+ // LT fails, both EQ and LE succeed
+ return this instanceof LT ? TypeInteger.FALSE : TypeInteger.TRUE;
if( t1.isHigh() || t2.isHigh() )
return BOOL.dual();
if( t1 instanceof TypeInteger i1 &&
@@ -43,7 +44,7 @@ abstract public class BoolNode extends Node {
if( t1 instanceof TypeFloat f1 &&
t2 instanceof TypeFloat f2 &&
f1.isConstant() && f2.isConstant() )
- return TypeInteger.constant(doOp(f1.value(), f2.value()) ? 1 : 0);
+ return doOp(f1.value(), f2.value()) ? TypeInteger.TRUE : TypeInteger.FALSE;
return BOOL;
}
@@ -55,7 +56,7 @@ abstract public class BoolNode extends Node {
public Node idealize() {
// Compare of same
if( in(1)==in(2) )
- return new ConstantNode(doOp(ZERO,ZERO));
+ return this instanceof LT ? Parser.ZERO : new ConstantNode(TypeInteger.TRUE);
// Equals pushes constant to the right; 5==X becomes X==5.
if( this instanceof EQ ) {
@@ -66,7 +67,7 @@ abstract public class BoolNode extends Node {
return in(1)._type instanceof TypeFloat ? new EQF(in(2),in(1)) : new EQ(in(2),in(1));
}
// Equals X==0 becomes a !X
- if( (in(2)._type == ZERO || in(2)._type == TypeMemPtr.NULLPTR) )
+ if( (in(2)._type == ZERO || in(2)._type == Type.NIL) )
return new NotNode(in(1));
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 76e98678..0d5ed297 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -2,7 +2,6 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-
import java.util.BitSet;
public class DivNode extends Node {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 513b4721..dcd2d4c7 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,9 +1,7 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.IterPeeps;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import com.seaofnodes.simple.type.TypeTuple;
+import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashSet;
@@ -37,14 +35,14 @@ public class IfNode extends CFGNode implements MultiNode {
Type t = pred._type;
// High types mean NEITHER side is reachable.
// Wait until the type falls to decide which way to go.
- if( t == Type.TOP || t == TypeInteger.TOP )
+ if( t.isHigh() )
return TypeTuple.IF_NEITHER;
// If constant is 0 then false branch is reachable
// Else true branch is reachable
if( t.isConstant() )
- return t.makeInit()==t ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE;
- // Integers allow non-zero ranges: "1-65535"
- if( t.makeZero().meet(t) != t )
+ return (t==Type.NIL || t==TypeInteger.ZERO) ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE;
+ // If adding a zero makes a difference, the predicate must not have a zero/null
+ if( !t.makeZero().isa(t) )
return TypeTuple.IF_TRUE;
return TypeTuple.IF_BOTH;
@@ -57,7 +55,7 @@ public class IfNode extends CFGNode implements MultiNode {
if( !pred()._type.isHighOrConst() )
for( CFGNode dom = idom(), prior=this; dom!=null; prior = dom, dom = dom.idom() )
if( dom.addDep(this) instanceof IfNode iff && iff.pred().addDep(this)==pred() && prior instanceof CProjNode prj ) {
- setDef(1,new ConstantNode(TypeInteger.make(true,prj._idx==0?1:0)).peephole());
+ setDef(1,new ConstantNode(TypeInteger.constant(prj._idx==0?1:0)).peephole());
return this;
}
return null;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index 82aab8ac..818d6352 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
@@ -48,7 +49,7 @@ public abstract class MemOpNode extends Node {
// Already an error, but better error messages come from elsewhere
if( ptr == Type.BOTTOM ) return null;
// Better be a not-nil TMP
- if( ptr instanceof TypeMemPtr tmp && !tmp._nil )
+ if( ptr instanceof TypeMemPtr tmp && tmp._nil==2 )
return null;
return "Might be null accessing '" + _name + "'";
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 9727f58b..2b749ba3 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -22,7 +22,7 @@ public class MinusFNode extends Node {
public Type compute() {
if (in(1)._type instanceof TypeFloat i0)
return i0.isConstant() ? TypeFloat.constant(-i0.value()) : i0;
- return TypeFloat.BOT;
+ return TypeFloat.F64;
}
@Override
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 760a4274..dd2cbd26 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -21,13 +21,11 @@ public class MinusNode extends Node {
@Override
public Type compute() {
- if( in(1)._type instanceof TypeInteger i0 ) {
- if( i0.isHigh() ) return TypeInteger.TOP;
- if( i0==TypeInteger.BOT || i0._min == Long.MIN_VALUE || i0._max == Long.MIN_VALUE )
- return TypeInteger.BOT;
+ if( in(1)._type.isHigh() ) return TypeInteger.TOP;
+ if( in(1)._type instanceof TypeInteger i0 &&
+ !(i0==TypeInteger.BOT || i0._min == Long.MIN_VALUE || i0._max == Long.MIN_VALUE) )
return TypeInteger.make(-i0._max,-i0._min);
- }
- return TypeInteger.TOP.meet(in(1)._type);
+ return TypeInteger.BOT;
}
@Override
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java
index ddb1e09a..54defe13 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -17,15 +17,16 @@ public class NewNode extends Node implements MultiNode {
public NewNode(TypeMemPtr ptr, Node... nodes) {
super(nodes);
+ assert ptr._nil!=3;
_ptr = ptr;
_len = ptr._obj._fields.length;
// Control in slot 0
assert nodes[0]._type==Type.CONTROL || nodes[0]._type == Type.XCONTROL;
// Malloc-length in slot 1
- assert nodes[1]._type instanceof TypeInteger;
+ assert nodes[1]._type instanceof TypeInteger || nodes[1]._type==Type.NIL;
for( int i=0; i<_len; i++ ) {
// Memory slices for all fields.
- assert nodes[2+ i]._type instanceof TypeMem;
+ assert nodes[2+ i]._type.isa(TypeMem.BOT);
// Value slices for all fields.
assert nodes[2 + _len + i]._type != null;
}
@@ -57,7 +58,8 @@ public class NewNode extends Node implements MultiNode {
ts[0] = Type.CONTROL;
ts[1] = _ptr;
for( int i=0; i<fs.length; i++ ) {
- TypeMem mem = (TypeMem)in(i+2)._type;
+ Type mt = in(i+2)._type;
+ TypeMem mem = mt==Type.TOP ? TypeMem.TOP : (TypeMem)in(i+2)._type;
Type tfld = in(2+_len+i)._type.meet(mem._t);
ts[i+2] = TypeMem.make(fs[i]._alias,tfld);
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java
index e23a128a..1a595f49 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -359,8 +359,9 @@ public abstract class Node implements OutNode {
if( n != null ) // Something changed
return n; // Report progress
- if( old==_type ) ITER_NOP_CNT++;
- return old==_type ? null : this; // Report progress
+ if( old!=_type ) return this; // Report progress;
+ ITER_NOP_CNT++;
+ return null; // No progress
}
public static int ITER_CNT, ITER_NOP_CNT;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 664d7c7b..d71e0fe6 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -18,25 +18,13 @@ public class NotNode extends Node {
}
@Override
- public Type compute() {
+ public TypeInteger compute() {
Type t0 = in(1)._type;
- if( t0.isHigh() ) return TypeInteger.BOOL.dual();
- switch( t0 ) {
- case TypeInteger i0: return i0._max < 0 || i0._min > 0 ? TypeInteger.FALSE : (i0==TypeInteger.ZERO ? TypeInteger.TRUE : TypeInteger.BOOL);
- case TypeFloat i0: return i0.isConstant() ? TypeInteger.constant(i0.value()==0 ? 1 : 0) : i0;
- case TypeMemPtr p0:
- // top->top, bot->bot, null->1, *void->0, not-null ptr->0, ptr/nil->bot
- // If input in null then true
- // If input is not null ptr then false
- if( p0 == TypeMemPtr.NULLPTR ) return TypeInteger.TRUE;
- if( !p0._nil ) return TypeInteger.FALSE;
- return TypeInteger.BOOL;
- case Type t:
- if( t0.getClass() != Type.class )
- // Only doing NOT on ints and ptrs
- throw Utils.TODO();
- return TypeInteger.BOOL;
- }
+ if( t0.isHigh() ) return TypeInteger.BOOL.dual();
+ if( t0 == Type.NIL || t0 == TypeInteger.ZERO ) return TypeInteger.TRUE;
+ if( t0 instanceof TypeNil tn && tn._nil==2 ) return TypeInteger.FALSE;
+ if( t0 instanceof TypeInteger i && (i._min > 0 || i._max < 0) ) return TypeInteger.FALSE;
+ return TypeInteger.BOOL;
}
@Override
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 407cf378..c0557639 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import com.seaofnodes.simple.Utils;
-
+import com.seaofnodes.simple.type.TypeNil;
import java.util.BitSet;
public class PhiNode extends Node {
@@ -47,7 +47,7 @@ public class PhiNode extends Node {
// During parsing Phis have to be computed type pessimistically.
if( r.inProgress() ) return _declaredType;
// Set type to local top of the starting type
- Type t = _declaredType.lub();
+ Type t = Type.TOP;
for (int i = 1; i < nIns(); i++)
// If the region's control input is live, add this as a dependency
// to the control because we can be peeped should it become dead.
@@ -101,10 +101,12 @@ public class PhiNode extends Node {
// then replace with plain val.
if( nIns()==3 ) {
int nullx = -1;
- if( in(1)._type == in(1)._type.makeInit() ) nullx = 1;
- if( in(2)._type == in(2)._type.makeInit() ) nullx = 2;
+ if( in(1)._type == in(1)._type.makeZero() ) nullx = 1;
+ if( in(2)._type == in(2)._type.makeZero() ) nullx = 2;
if( nullx != -1 ) {
Node val = in(3-nullx);
+ if( val instanceof CastNode cast )
+ val = cast.in(1);
if( r.idom(this).addDep(this) instanceof IfNode iff && iff.pred().addDep(this)==val ) {
// Must walk the idom on the null side to make sure we hit False.
CFGNode idom = (CFGNode)r.in(nullx);
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 44d3a587..8311405d 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -30,7 +30,7 @@ public class RoundF32Node extends Node {
Type t1 = lhs._type;
// RoundF32 of float
- if( t1 instanceof TypeFloat tf && tf._sz==32 )
+ if( t1 instanceof TypeFloat tf && tf._f32 )
return lhs;
return null;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/SarNode.java
index 59cec99c..4270ef88 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/SarNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/SarNode.java
@@ -2,7 +2,6 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-
import java.util.BitSet;
public class SarNode extends Node {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java
index f69461cc..e9a4eb82 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java
@@ -70,7 +70,7 @@ public class ScopeMinNode extends Node {
public Node in( Var v ) { return in(v._idx); }
- Node alias( int alias ) {
+ public Node alias( int alias ) {
return in(alias<nIns() && in(alias)!=null ? alias : 1);
}
@@ -114,7 +114,7 @@ public class ScopeMinNode extends Node {
//Var v = _vars.at(i);
Node lhs = this._mem(i,null);
Node rhs = that._mem(i,null);
- alias(i, new PhiNode(Parser.memName(i), TypeMem.BOT, r, lhs, rhs).peephole());
+ alias(i, new PhiNode(Parser.memName(i), lhs._type.glb().meet(rhs._type.glb()), r, lhs, rhs).peephole());
}
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 0d8ad2fc..e720a58f 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -1,8 +1,6 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.IterPeeps;
-import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
import java.util.*;
import static com.seaofnodes.simple.Utils.TODO;
@@ -230,7 +228,7 @@ public class ScopeNode extends ScopeMinNode {
* @return A new node representing the merge point
*/
public RegionNode mergeScopes(ScopeNode that) {
- RegionNode r = (RegionNode) ctrl(new RegionNode(null,ctrl(), that.ctrl()).keep());
+ RegionNode r = ctrl(new RegionNode(null,ctrl(), that.ctrl()).keep());
mem()._merge(that.mem(),r);
this ._merge(that ,r);
that.kill(); // Kill merged scope
@@ -296,29 +294,28 @@ public class ScopeNode extends ScopeMinNode {
pred = pred instanceof NotNode not ? not.in(1) : IterPeeps.add(new NotNode(pred).peephole());
// This is a zero/null test.
// Compute the positive test type.
- Type tnz = pred._type.nonZero();
- Type tcast = tnz.join(pred._type);
- if( tcast != pred._type ) {
- Node cast = new CastNode(tnz,ctrl,pred.keep()).peephole().keep();
- _guards.add(pred);
- _guards.add(cast);
- replace(pred,cast);
- }
+ Type tnz = pred._type.nonZero();
+ _addGuard(tnz,ctrl,pred);
// Compute the negative test type.
if( pred instanceof NotNode not ) {
Node npred = not.in(1);
Type tzero = npred._type.makeZero();
- Type tzcast= tzero.join(npred._type);
- if( tzcast != npred._type ) {
- Node cast = new CastNode(tzero,ctrl,npred.keep()).peephole().keep();
- _guards.add(npred);
- _guards.add( cast);
- replace(npred,cast);
- }
+ _addGuard(tzero,ctrl,npred);
+ }
+ }
+
+ private void _addGuard(Type guard, Node ctrl, Node pred) {
+ Type tcast = guard.join(pred._type);
+ if( tcast != pred._type ) {
+ Node cast = new CastNode(tcast,ctrl,pred.keep()).peephole().keep();
+ _guards.add(pred);
+ _guards.add(cast);
+ replace(pred,cast);
}
}
+
// Remove matching pred/cast pairs from this guarded region.
public void removeGuards( Node ctrl ) {
assert ctrl instanceof CFGNode;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ShlNode.java
index e167fd68..d3639ed7 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ShlNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ShlNode.java
@@ -44,7 +44,7 @@ public class ShlNode extends Node {
if( (shl.value()&63)==0 )
return lhs;
// (x + c) << i => (x << i) + (c << i)
- if( lhs instanceof AddNode add && add.addDep(this).in(2)._type instanceof TypeInteger c && c.isConstant() && c!=TypeInteger.ZERO ) {
+ if( lhs instanceof AddNode add && add.addDep(this).in(2)._type instanceof TypeInteger c && c.isConstant() ) {
long sum = c.value() << shl.value();
if( Integer.MIN_VALUE <= sum && sum <= Integer.MAX_VALUE )
return new AddNode( new ShlNode(add.in(1),rhs).peephole(), Parser.con(sum) );
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ShrNode.java
index b8c226bd..6f4a2c6c 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ShrNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ShrNode.java
@@ -2,7 +2,6 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-
import java.util.BitSet;
public class ShrNode extends Node {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 44a56a93..5bc88aa5 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -71,7 +71,7 @@ public class StoreNode extends MemOpNode {
return this;
}
- // Simple store-after-new on same address. Should pick up the
+ // Simple store-after-new on same address. Should pick up
// an init-store being stomped by a first user store.
if( mem() instanceof ProjNode st && st .in(0) instanceof NewNode nnn &&
ptr() instanceof ProjNode ptr && ptr.in(0) == nnn &&
@@ -86,7 +86,7 @@ public class StoreNode extends MemOpNode {
val()._type.isHighOrConst() &&
// Must have exactly one use of "this" or you get weird
// non-serializable memory effects in the worse case.
- //checkOnlyUse(st) &&
+ checkOnlyUse(st) &&
// Folding away a broken store
err()==null ) {
nnn.setDef(nnn.findAlias(_alias),val());
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 5d6c2643..339c65ca 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -3,7 +3,6 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-
import java.util.BitSet;
public class SubNode extends Node {
@@ -25,6 +24,9 @@ public class SubNode extends Node {
Type t1 = in(1)._type, t2 = in(2)._type;
if( t1.isHigh() || t2.isHigh() )
return TypeInteger.TOP;
+ // Sub of same is 0
+ if( in(1)==in(2) )
+ return TypeInteger.ZERO;
if( t1 instanceof TypeInteger i1 &&
t2 instanceof TypeInteger i2 ) {
if (i1.isConstant() && i2.isConstant())
@@ -35,9 +37,6 @@ public class SubNode extends Node {
i2._min != Long.MIN_VALUE )
return TypeInteger.make(i1._min-i2._max,i1._max-i2._min);
}
- // Sub of same is 0
- if( in(1)==in(2) )
- return TypeInteger.ZERO;
return TypeInteger.BOT;
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index 1d147cf6..4557a29e 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -21,8 +21,8 @@ public class ToFloatNode extends Node {
@Override
public Type compute() {
if (in(1)._type instanceof TypeInteger i0 && i0.isConstant() )
- return TypeFloat.constant(i0.value());
- return TypeFloat.BOT;
+ return i0.value()==0 ? Type.NIL : TypeFloat.constant(i0.value());
+ return TypeFloat.F64;
}
@Override public Node idealize() { return null; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/Field.java b/chapter18/src/main/java/com/seaofnodes/simple/type/Field.java
index 39f7fcc2..1ed75fe4 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/Field.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/Field.java
@@ -37,7 +37,7 @@ public class Field extends Type {
@Override public Field makeRO() { return _final ? this : make(_fname,_type.makeRO(),_alias,true); }
@Override public boolean isFinal() { return _final && _type.isFinal(); }
- public static final Field TEST = make("test",TypeInteger.ZERO,-2,false);
+ public static final Field TEST = make("test",Type.NIL,-2,false);
public static void gather(ArrayList<Type> ts) { ts.add(TEST); }
@Override Field xmeet( Type that ) {
@@ -52,12 +52,7 @@ public class Field extends Type {
@Override public Field glb() {
Type glb = _type.glb();
- return glb==_type ? this : make(_fname,glb,_alias,_final);
- }
-
- @Override public Field lub() {
- Type lub = _type.lub();
- return lub==_type ? this : make(_fname,lub,_alias,_final);
+ return (glb==_type && _final) ? this : make(_fname,glb,_alias,true);
}
// Override in subclasses
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java b/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java
index 70e2dccf..5104f080 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java
@@ -31,39 +31,48 @@ public class Type {
static final byte TTOP = 1; // Top (ANY)
static final byte TCTRL = 2; // Ctrl flow bottom
static final byte TXCTRL = 3; // Ctrl flow top (mini-lattice: any-xctrl-ctrl-all)
- static final byte TSIMPLE = 4; // End of the Simple Types
- static final byte TINT = 5; // All Integers; see TypeInteger
- static final byte TFLT = 6; // All Integers; see TypeInteger
- static final byte TTUPLE = 7; // Tuples; finite collections of unrelated Types, kept in parallel
- static final byte TMEM = 8; // All memory (alias 0) or A slice of memory - with specific alias
- static final byte TMEMPTR = 9; // Memory pointer type
- static final byte TSTRUCT =10; // Structs; tuples with named fields
- static final byte TFLD =11; // Fields into struct
- static final byte TARRAY =12; // Array
- static final byte TFUNPTR =13; // Function
+ static final byte TNIL = 4; // low null of all flavors
+ static final byte TXNIL = 5; // high or choice null
+ static final byte TSIMPLE = 6; // End of the Simple Types
+
+ static final byte TPTR = 7; // All nil-able scalar values
+ static final byte TINT = 8; // All Integers; see TypeInteger
+ static final byte TFLT = 9; // All Floats ; see TypeFloat
+ static final byte TMEMPTR =10; // Memory pointer to a struct type
+ static final byte TFUNPTR =11; // Function pointer; unique signature and code address (just a bit)
+ static final byte TTUPLE =12; // Tuples; finite collections of unrelated Types, kept in parallel
+ static final byte TMEM =13; // All memory (alias 0) or A slice of memory - with specific alias
+ static final byte TSTRUCT =14; // Structs; tuples with named fields
+ static final byte TFLD =15; // Named fields in structs
public final byte _type;
public boolean is_simple() { return _type < TSIMPLE; }
- private static final String[] STRS = new String[]{"Bot","Top","Ctrl","~Ctrl"};
+ private static final String[] STRS = new String[]{"Bot","Top","Ctrl","~Ctrl","nil","~nil"};
protected Type(byte type) { _type = type; }
public static final Type BOTTOM = new Type( TBOT ).intern(); // ALL
public static final Type TOP = new Type( TTOP ).intern(); // ANY
public static final Type CONTROL = new Type( TCTRL ).intern(); // Ctrl
public static final Type XCONTROL = new Type( TXCTRL ).intern(); // ~Ctrl
+ public static final Type NIL = new Type( TNIL ).intern(); // low null of all flavors
+ public static final Type XNIL = new Type( TXNIL ).intern(); // high or choice null
public static Type[] gather() {
ArrayList<Type> ts = new ArrayList<>();
ts.add(BOTTOM);
ts.add(CONTROL);
- Field.gather(ts);
+ ts.add(NIL);
+ ts.add(XNIL);
+ TypeNil.gather(ts);
+ TypePtr.gather(ts);
TypeInteger.gather(ts);
TypeFloat.gather(ts);
- TypeMem.gather(ts);
TypeMemPtr.gather(ts);
+ TypeFunPtr.gather(ts);
+ TypeMem.gather(ts);
+ Field.gather(ts);
TypeStruct.gather(ts);
TypeTuple.gather(ts);
- TypeFunPtr.gather(ts);
int sz = ts.size();
for( int i = 0; i < sz; i++ )
ts.add(ts.get(i).dual());
@@ -71,12 +80,12 @@ public class Type {
}
// Is high or on the lattice centerline.
- public boolean isHigh () { return _type==TTOP || _type==TXCTRL; }
- public boolean isHighOrConst() { return _type==TTOP || _type==TXCTRL; }
+ public boolean isHigh () { return _type==TTOP || _type==TXCTRL || _type==TXNIL; }
+ public boolean isHighOrConst() { return isHigh() || isConstant(); }
// Strict constant values, things on the lattice centerline.
// Excludes both high and low values
- public boolean isConstant() { return false; }
+ public boolean isConstant() { return _type==TNIL; }
// ----------------------------------------------------------
@@ -88,7 +97,7 @@ public class Type {
// to be immutable once defined. The rationale for interning is
// *correctness* with cyclic type definitions. Simple structural recursive
// checks go exponential with merely sharing, but with cycles they will
- // stack overflow and crash. Intering means we do not need to have sharing
+ // stack overflow and crash. Interning means we do not need to have sharing
// checks with every type compare, only during interning.
// Factory method which interns "this"
@@ -127,6 +136,9 @@ public class Type {
if( t == this ) return this;
// Same-type is always safe in the subclasses
if( _type==t._type ) return xmeet(t);
+ // TypeNil vs TypeNil meet
+ if( this instanceof TypeNil ptr0 && t instanceof TypeNil ptr1 )
+ return ptr0.nmeet(ptr1);
// Reverse; xmeet 2nd arg is never "is_simple" and never equal to "this".
if( is_simple() ) return this.xmeet(t );
if( t.is_simple() ) return t .xmeet(this);
@@ -141,18 +153,27 @@ public class Type {
// ANY meet anything is thing; thing meet ALL is ALL
if( _type==TBOT || t._type==TTOP ) return this;
if( _type==TTOP || t._type==TBOT ) return t;
- // 'this' is {TCTRL,TXCTRL}
+
+ // RHS TypeNil vs NIL/XNIL
+ if( _type== TNIL ) return t instanceof TypeNil ptr ? ptr.meet0() : (t._type==TXNIL ? TypePtr.PTR : BOTTOM);
+ if( _type== TXNIL ) return t instanceof TypeNil ptr ? ptr.meetX() : (t._type== TNIL ? TypePtr.PTR : BOTTOM);
+ // 'this' is only {TCTRL,TXCTRL}
+ // Other non-simple RHS things bottom out
if( !t.is_simple() ) return BOTTOM;
- // 't' is {TCTRL,TXCTRL}
+ // If RHS is NIL/XNIL
+ if( t._type==TNIL || t._type==TXNIL ) return BOTTOM;
+ // Both are {TCTRL,TXCTRL} and unequal to each other
return _type==TCTRL || t._type==TCTRL ? CONTROL : XCONTROL;
}
public Type dual() {
return switch( _type ) {
- case TBOT -> TOP;
- case TTOP -> BOTTOM;
- case TCTRL -> XCONTROL;
- case TXCTRL -> CONTROL;
+ case TBOT -> TOP;
+ case TTOP -> BOTTOM;
+ case TCTRL ->XCONTROL;
+ case TXCTRL-> CONTROL;
+ case TNIL ->XNIL;
+ case TXNIL -> NIL;
default -> throw Utils.TODO(); // Should not reach here
};
}
@@ -168,19 +189,13 @@ public class Type {
// True if this "isa" t; e.g. 17 isa TypeInteger.BOT
public boolean isa( Type t ) { return meet(t)==t; }
- /** Compute greatest lower bound in the lattice */
- public Type glb() { return _type==TCTRL ? CONTROL : BOTTOM; }
- /** Compute least upper bound in the lattice */
- public Type lub() { return _type==TCTRL ? XCONTROL : TOP; }
+ public Type nonZero() { return TypePtr.NPTR; }
- // Make an initial/default version of this type. Typically, 0 for integers
- // and null for nullable pointers.
- public Type makeInit() { return this; }
// Make a zero version of this type, 0 for integers and null for pointers.
- public Type makeZero() { return null; }
- // Make a non-zero version of this type, if possible. Integers attempt to
- // exclude zero from their range and pointers become not-null.
- public Type nonZero() { return glb(); }
+ public Type makeZero() { return Type.NIL; }
+
+ /** Compute greatest lower bound in the lattice */
+ public Type glb() { return Type.NIL; }
// Is forward-reference
public boolean isFRef() { return false; }
@@ -207,7 +222,7 @@ public class Type {
return print(new SB()).toString();
}
- public SB print(SB sb) { return is_simple() ? sb.p(STRS[_type]) : sb;}
+ public SB print(SB sb) { return sb.p(str()); }
public SB gprint(SB sb) { return print(sb); }
// This is used by error messages, and is a shorted print.
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
index a11eec90..143adbcd 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
@@ -6,104 +6,90 @@ import java.util.ArrayList;
/**
* Float Type
*/
-public class TypeFloat extends Type {
+public class TypeFloat extends TypeNil {
- public final static TypeFloat TOP = make((byte)-64, 0);
- public final static TypeFloat T32 = make((byte)-32, 0);
- public final static TypeFloat ZERO= make((byte) 0, 0);
- public final static TypeFloat B32 = make((byte) 32, 0);
- public final static TypeFloat BOT = make((byte) 64, 0);
+ public final static TypeFloat ONE = constant(1.0);
+ public final static TypeFloat F32 = make((byte)3, true, 0);
+ public final static TypeFloat NF64 = make((byte)2,false, 0);
+ public final static TypeFloat F64 = make((byte)3,false, 0);
- /** +/-64 for double; +/-32 for float, or 0 for constants */
- public final byte _sz;
+ // true for 32bits, false for 64bits
+ public final boolean _f32;
/**
* The constant value or 0
*/
public final double _con;
- private TypeFloat(byte sz, double con) {
- super(TFLT);
- _sz = sz ;
+ private TypeFloat(byte nil, boolean f32, double con) {
+ super(TFLT,nil);
+ assert !isConstant() || ((float)con == con) == f32;
+ _f32 = f32;
_con = con;
}
- private static TypeFloat make(byte sz, double con) {
- return new TypeFloat(sz,con).intern();
+ private static TypeFloat make(byte nil, boolean f32, double con) {
+ return new TypeFloat(nil,f32,con).intern();
+ }
+ @Override public TypeFloat makeFrom(byte nil) {
+ return nil==_nil ? this : make(nil,_f32,_con);
}
- public static TypeFloat constant(double con) { return make((byte)0, con); }
-
- public static void gather(ArrayList<Type> ts) { ts.add(ZERO); ts.add(BOT); ts.add(B32); ts.add(constant(3.141592653589793)); }
+ public static TypeFloat constant(double con) { assert con!=0; return make((byte)2,((float)con)==con, con); }
- // FIXME this display format is problematic
- // In visualizer '#' gets prepended if its a constant
- @Override
- public SB print(SB sb) {
- if( this==TOP ) return sb.p("FltTop");
- if( this==T32 ) return sb.p("F32Top");
- if( this==B32 ) return sb.p("F32Bot");
- if( this==BOT ) return sb.p("FltBot");
- return sb.p(_con);
- }
+ public static void gather(ArrayList<Type> ts) { ts.add(F64); ts.add(F32); ts.add(constant(3.141592653589793)); }
@Override public String str() {
- if( this==TOP ) return "~flt";
- if( this==T32 ) return "~f32";
- if( this==B32 ) return "f32";
- if( this==BOT ) return "flt";
- return ""+_con+(isF32() ? "f" : "");
+ if( isConstant() )
+ return ""+_con+(_f32 ? "f" : "");
+ String s = "";
+ if( isHigh() ) s = "~";
+ if( 1 <= _nil && _nil <= 2 ) // Disallow nil?
+ s += "n";
+ s += "f";
+ s += _f32 ? "32" : "lt";
+ return s;
}
- boolean isF32() { return ((float)_con)==_con; }
- @Override public boolean isHigh() { return _sz< 0; }
- @Override public boolean isHighOrConst() { return _sz<=0; }
- @Override public boolean isConstant() { return _sz==0; }
-
- @Override public int log_size() {
- int sz = _sz==0 ? (isF32() ? 32 : 64) : Math.abs(_sz);
- return _sz==32 ? 2 : 3;
- }
+ @Override public boolean isConstant() { return _con!=0; }
+ @Override public int log_size() { return _f32 ? 2 : 3; }
public double value() { return _con; }
@Override
- public Type xmeet(Type other) {
- // Invariant from caller: 'this' != 'other' and same class (TypeFloat)
+ public TypeFloat xmeet(Type other) {
+ // Invariant from caller: 'this' != 'other' and same class (TypeFloat).
TypeFloat i = (TypeFloat)other; // Contract
- // Larger size in i1, smaller in i0
- TypeFloat i0 = _sz < i._sz ? this : i;
- TypeFloat i1 = _sz < i._sz ? i : this;
-
- if( i1._sz== 64 ) return BOT;
- if( i0._sz==-64 ) return i1;
- if( i1._sz== 32 )
- return i0._sz==0 && !i0.isF32() ? BOT : B32;
- if( i1._sz!= 0 ) return i1;
- // i1 is a constant
- if( i0._sz==-32 )
- return i1.isF32() ? i1 : BOT;
- // Since both are constants, and are never equals (contract) unequals
- // constants fall to bottom
- return i0.isF32() && i1.isF32() ? B32 : BOT;
+ if( isConstant() && i.isHigh() ) return i._f32 && ! _f32 ? NF64 : this;
+ if( i.isConstant() && isHigh() ) return _f32 && !i._f32 ? NF64 : i ;
+
+
+ // From online Karnaugh map; if both values are small the result is
+ // small, otherwise the result is small if the otherside is high.
+ boolean f32 = (_f32&i._f32) | (i.isHigh()&_f32) | (isHigh()&i._f32);
+ return make(xmeet0(i), f32, 0);
}
@Override
public Type dual() {
- if( _sz==0 ) return this; // Constants are a self-dual
- return make((byte)-_sz,0);
+ if( isConstant() ) return this; // Constants are a self-dual
+ return make(dual0(),_f32,0);
}
- @Override public Type glb() { return BOT; }
- @Override public Type lub() { return TOP; }
- @Override public TypeFloat makeInit() { return ZERO; }
- @Override public TypeFloat makeZero() { return ZERO; }
+ // RHS is NIL
+ @Override Type meet0() {
+ // From high, falling to the least Float that contains a zero
+ return isHigh() || _f32 ? F32 : F64;
+ }
+
+
+ @Override public Type glb() { return F64; }
@Override
- int hash() { return (int)(Double.hashCode(_con) ^ _sz); }
+ int hash() { return (int)(Double.hashCode(_con) ^ (_f32 ? 2048 : 0) ^ super.hash()); }
@Override
public boolean eq( Type t ) {
TypeFloat i = (TypeFloat)t; // Contract
- return _con==i._con && _sz==i._sz;
+ return _con==i._con && _f32==i._f32 && super.eq(i);
}
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
index 3a0c91ea..9d4e5795 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
@@ -32,6 +32,8 @@ public class TypeFunPtr extends Type {
}
public static TypeFunPtr make( TypeTuple sig, long fidxs ) { return new TypeFunPtr(sig,fidxs).intern(); }
+ // Make a TFP with all functions
+ public static TypeFunPtr make( TypeTuple sig, boolean nil ) { return new TypeFunPtr(sig,-2|(nil ? 1 : 0)).intern(); }
public static TypeFunPtr BOT = make(TypeTuple.SIGBOT,-1);
public static TypeFunPtr TOP = BOT.dual();
@@ -51,12 +53,8 @@ public class TypeFunPtr extends Type {
public TypeFunPtr dual() { return TypeFunPtr.make(_sig.dual(), ~_fidxs); }
@Override public TypeFunPtr glb() { throw Utils.TODO(); }
- @Override public TypeFunPtr lub() { throw Utils.TODO(); }
// Is forward-reference
@Override public boolean isFRef() { return false; }
- @Override public Type makeInit() { return (_fidxs&1)==1 ? NULLPTR : Type.TOP; }
- @Override public Type makeZero() { return NULLPTR; }
- @Override public Type nonZero() { return VOIDPTR; }
@Override public boolean isHigh() { return this==TOP; }
@Override public boolean isConstant() { return Long.bitCount(_fidxs)==1; }
@@ -73,38 +71,48 @@ public class TypeFunPtr extends Type {
return _sig == ptr._sig && _fidxs == ptr._fidxs;
}
+
+ @Override public String str() {
+ if( this== NULLPTR) return "null";
+ if( this== VOIDPTR) return "*void";
+ return print(new SB()).toString();
+ }
+
// [void,name,MANY]*[,?]
- @Override
- public SB print(SB sb) {
+ @Override public SB print(SB sb) {
if( this== NULLPTR) return sb.p("null");
if( this== VOIDPTR) return sb.p("*void");
sb.p("{ ");
for( int i=1; i<_sig._types.length; i++ )
_sig._types[i].print(sb).p(" ");
_sig._types[0].print(sb.p("-> "));
- sb.p(String.format(" #%X",_fidxs));
- sb.p("}");
+ sb.p(" #");
+ long fidxs = _fidxs&-2; // Strip off the null flag bit
+ String fidx = fidxs==0 ? ""
+ : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs)
+ : fidxs == -2 ? "ALL"
+ : "b"+Long.toBinaryString(fidxs); // Just some function bits
+ sb.p(fidx).p("}");
if( (_fidxs&1)==1 ) sb.p("?");
return sb;
}
- @Override
- public SB gprint(SB sb) {
+
+ @Override public SB gprint(SB sb) {
if( this== NULLPTR) return sb.p("null");
if( this== VOIDPTR) return sb.p("*void");
sb.p("{ ");
for( int i=1; i<_sig._types.length; i++ )
_sig._types[i].gprint(sb).p(" ");
_sig._types[0].gprint(sb.p("-> "));
- sb.p(String.format(" #%X",_fidxs));
- sb.p("}");
+ sb.p(" #");
+ long fidxs = _fidxs&-2; // Strip off the null flag bit
+ String fidx = fidxs==0 ? ""
+ : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs)
+ : fidxs == -2 ? "ALL"
+ : "b"+Long.toBinaryString(fidxs); // Just some function bits
+ sb.p(fidx).p("}");
if( (_fidxs&1)==1 ) sb.p("?");
return sb;
}
- @Override public String str() {
- if( this== NULLPTR) return "null";
- if( this== VOIDPTR) return "*void";
- return print(new SB()).toString();
- }
-
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
index 2be4f4d8..77b280f3 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
@@ -9,17 +9,19 @@ import java.util.ArrayList;
*/
public class TypeInteger extends Type {
- public final static TypeInteger TOP = make(false, 0);
- public final static TypeInteger BOT = make(false, 1);
public final static TypeInteger ZERO= make(0,0);
- public final static TypeInteger U1 = make(0,1);
- public final static TypeInteger BOOL= U1;
public final static TypeInteger FALSE=ZERO;
public final static TypeInteger TRUE= make(1,1);
+
+ public final static TypeInteger I1 = make(-1,0);
public final static TypeInteger I8 = make(-128,127);
public final static TypeInteger I16 = make(-32768,32767);
public final static TypeInteger I32 = make(-1L<<31,(1L<<31)-1);
+ public final static TypeInteger BOT = make(Long.MIN_VALUE,Long.MAX_VALUE);
+ public final static TypeInteger TOP = BOT.dual();
+ public final static TypeInteger U1 = make(0,1);
+ public final static TypeInteger BOOL= U1;
public final static TypeInteger U8 = make(0,255);
public final static TypeInteger U16 = make(0,65535);
public final static TypeInteger U32 = make(0,(1L<<32)-1);
@@ -27,45 +29,50 @@ public class TypeInteger extends Type {
/**
* Describes an integer *range* - everything from min to max; both min and
* max are inclusive. If min==max, this is a constant.
- *
+ * <br>
* If min <= max, this is a below center (towards bottom).
* If min > max, this is an above center (towards top).
*/
public final long _min, _max;
- private TypeInteger(long min, long max) { super(TINT); _min = min; _max = max; }
- public static TypeInteger make(long lo, long hi) { return new TypeInteger(lo,hi).intern(); }
- public static TypeInteger make(boolean is_con, long con) {
- return make(is_con ? con : (con==0 ? Long.MAX_VALUE : Long.MIN_VALUE),
- is_con ? con : (con==0 ? Long.MIN_VALUE : Long.MAX_VALUE));
+ private TypeInteger(long min, long max) {
+ super(TINT);
+ _min = min;
+ _max = max;
}
- public static TypeInteger constant(long con) { return make(true, con); }
+ // Strict non-zero contract
+ public static TypeInteger make(long lo, long hi) { return new TypeInteger(lo,hi).intern(); }
- public static void gather(ArrayList<Type> ts) { ts.add(ZERO); ts.add(BOT); ts.add(U1); ts.add(U8); }
+ public static TypeInteger constant(long con) { return make(con, con); }
- // FIXME this display format is problematic
- // In visualizer '#' gets prepended if its a constant
- @Override
- public SB print(SB sb) { return sb.p(str()); }
+ public static void gather(ArrayList<Type> ts) { ts.add(I32); ts.add(BOT); ts.add(U1); ts.add(I1); ts.add(U8); }
@Override public String str() {
- if( this==TOP ) return "~int";
- if( this==BOT ) return "int";
- if( this==BOOL) return ("bool");
- if( this==I8 ) return ("i8");
- if( this==I16 ) return ("i16");
- if( this==I32 ) return ("i32");
- if( this==U8 ) return ("u8");
- if( this==U16 ) return ("u16");
- if( this==U32 ) return ("u32");
if( isConstant() ) return ""+_min;
- return "["+_min+"-"+_max+"]";
+ long lo = _min, hi = _max;
+ String x = "";
+ if( hi < lo ) {
+ lo = _max; hi = _min;
+ x = "~";
+ }
+ return x+_str(lo,hi);
+ }
+ private static String _str(long lo, long hi) {
+ if( lo==Long.MIN_VALUE && hi==Long.MAX_VALUE ) return "int";
+ if( lo== 0 && hi== 1 ) return "bool";
+ if( lo== -1 && hi== 0 ) return "i1";
+ if( lo== -128 && hi== 127 ) return "i8";
+ if( lo== -32768 && hi== 32767 ) return "i16";
+ if( lo== -1L<<31 && hi==(1L<<31)-1 ) return "i32";
+ if( lo== 0 && hi== 255 ) return "u8";
+ if( lo== 0 && hi== 65535 ) return "u16";
+ if( lo== 0 && hi==(1L<<32)-1 ) return "u32";
+ return "["+lo+"-"+hi+"]";
}
- @Override public boolean isHigh () { return _min > _max; }
- @Override public boolean isHighOrConst() { return _min >= _max; }
- @Override public boolean isConstant () { return _min == _max; }
+ @Override public boolean isHigh () { return _min > _max; }
+ @Override public boolean isConstant() { return _min == _max; }
@Override public int log_size() {
if( this==I8 || this==U8 || this==BOOL ) return 0; // 1<<0 == 1 bytes
@@ -84,8 +91,6 @@ public class TypeInteger extends Type {
public long mask() {
if( isHigh() ) return 0;
if( isConstant() ) return _min;
- //if( _min<0 ) return -1L;
- //if( _max==Long.MAX_VALUE ) return -1L;
// Those bit positions which differ min to max
long x = _min ^ _max;
// Highest '1' bit in the differ set. Since the range is from min to
@@ -105,19 +110,17 @@ public class TypeInteger extends Type {
}
@Override public TypeInteger dual() { return make(_max,_min); }
- @Override public TypeInteger glb() { return BOT; }
- @Override public TypeInteger lub() { return TOP; }
- @Override public TypeInteger makeInit() { return ZERO; }
- @Override public TypeInteger makeZero() { return ZERO; }
+
@Override public TypeInteger nonZero() {
if( isHigh() ) return this;
if( _min==0 ) return make(1,Math.max(_max,1)); // specifically good on BOOL
if( _max==0 ) return make(_min,-1);
return this;
}
- @Override int hash() { return (int)((_min ^ (_min>>32)) *(_max ^ (_max>>32))); }
- @Override
- public boolean eq( Type t ) {
+ @Override public Type makeZero() { return TypeInteger.ZERO; }
+ @Override public TypeInteger glb() { return BOT; }
+ @Override int hash() { return Utils.fold(_min) * Utils.fold(_max); }
+ @Override public boolean eq( Type t ) {
TypeInteger i = (TypeInteger)t; // Contract
return _min==i._min && _max==i._max;
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java
index 007a18d6..60b3612f 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java
@@ -25,7 +25,7 @@ public class TypeMem extends Type {
public static final TypeMem TOP = make(0, Type.TOP );
public static final TypeMem BOT = make(0, Type.BOTTOM);
- public static void gather(ArrayList<Type> ts) { ts.add(make(1,TypeInteger.ZERO)); ts.add(BOT); }
+ public static void gather(ArrayList<Type> ts) { ts.add(make(1,Type.NIL)); ts.add(make(1,TypeInteger.ZERO)); ts.add(BOT); }
@Override
TypeMem xmeet(Type t) {
@@ -45,25 +45,20 @@ public class TypeMem extends Type {
}
@Override public Type glb() { return make(_alias,_t.glb()); }
- @Override public Type lub() { return make(_alias,_t.lub()); }
- @Override
- int hash() { return 9876543 + _alias + _t.hashCode(); }
+ @Override int hash() { return 9876543 + _alias + _t.hashCode(); }
- @Override
- boolean eq(Type t) {
+ @Override boolean eq(Type t) {
TypeMem that = (TypeMem) t; // Invariant
return _alias == that._alias && _t == that._t;
}
- @Override
- public SB print(SB sb) {
+ @Override public SB print(SB sb) {
sb.p("#");
if( _alias==0 ) return sb.p(_t._type==TTOP ? "TOP" : "BOT");
return _t.print(sb.p(_alias).p(":"));
}
- @Override
- public SB gprint(SB sb) {
+ @Override public SB gprint(SB sb) {
sb.p("#");
if( _alias==0 ) return sb.p(_t._type==TTOP ? "TOP" : "BOT");
return _t.gprint(sb.p(_alias).p(":"));
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
index b675eef5..d17cfd39 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple.type;
import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.Utils;
import java.util.ArrayList;
/**
@@ -12,9 +13,9 @@ import java.util.ArrayList;
* The distinguished *$BOT ptr represents union of *void and Null.
* The distinguished *$TOP ptr represents the dual of *$BOT.
*/
-public class TypeMemPtr extends Type {
+public class TypeMemPtr extends TypeNil {
// A TypeMemPtr is pair (obj,nil)
- // where obj is a TypeStruct, possibly TypeStruct.BOT
+ // where obj is a TypeStruct, possibly TypeStruct.BOT/TOP
// where nil is an explicit null is allowed or not
// Examples:
@@ -24,82 +25,70 @@ public class TypeMemPtr extends Type {
// (TOP ,true ) - a nil
public final TypeStruct _obj;
- public final boolean _nil;
- private TypeMemPtr(TypeStruct obj, boolean nil) {
- super(TMEMPTR);
+ private TypeMemPtr(byte nil, TypeStruct obj) {
+ super(TMEMPTR,nil);
assert obj!=null;
_obj = obj;
- _nil = nil;
}
- public static TypeMemPtr make(TypeStruct obj, boolean nil) { return new TypeMemPtr(obj, nil).intern(); }
- public static TypeMemPtr make(TypeStruct obj) { return make(obj, false); }
- public TypeMemPtr makeFrom(TypeStruct obj) { return obj==_obj ? this : make(obj, _nil); }
- public TypeMemPtr makeFrom(boolean nil) { return nil==_nil ? this : make(_obj, nil); }
+ public static TypeMemPtr make(byte nil, TypeStruct obj) { return new TypeMemPtr(nil, obj).intern(); }
+ public static TypeMemPtr make(TypeStruct obj) { return make((byte)3, obj); }
+ public TypeMemPtr makeFrom(TypeStruct obj) { return obj==_obj ? this : make(_nil, obj); }
+ @Override public TypeMemPtr makeFrom(byte nil) { return nil==_nil ? this : make(nil,_obj); }
@Override public TypeMemPtr makeRO() { return makeFrom(_obj.makeRO()); }
@Override public boolean isFinal() { return _obj.isFinal(); }
// An abstract pointer, pointing to either a Struct or an Array.
- // Can also be null or not.
- public static TypeMemPtr BOT = make(TypeStruct.BOT,true);
+ // Can also be null or not, so 4 choices {TOP,BOT} x {nil,not}
+ public static TypeMemPtr BOT = make((byte)3, TypeStruct.BOT);
public static TypeMemPtr TOP = BOT.dual();
- // An abstract null (can be Struct or Array) or not-null C void*
- public static TypeMemPtr NULLPTR = make(TypeStruct.TOP,true);
- public static TypeMemPtr VOIDPTR = NULLPTR.dual(); // A bottom mix of not-null ptrs, like C's void* but not null
+ public static TypeMemPtr NOTBOT = make((byte)2,TypeStruct.BOT);
- public static TypeMemPtr TEST= make(TypeStruct.TEST,false);
- public static void gather(ArrayList<Type> ts) { ts.add(NULLPTR); ts.add(BOT); ts.add(TEST); }
+ public static TypeMemPtr TEST= make((byte)2, TypeStruct.TEST);
+ public static void gather(ArrayList<Type> ts) { ts.add(NOTBOT); ts.add(BOT); ts.add(TEST); }
@Override
- Type xmeet(Type t) {
+ public TypeNil xmeet(Type t) {
TypeMemPtr that = (TypeMemPtr) t;
- return TypeMemPtr.make((TypeStruct)_obj.meet(that._obj), _nil | that._nil);
+ return TypeMemPtr.make(xmeet0(that), (TypeStruct)_obj.meet(that._obj));
}
@Override
- public TypeMemPtr dual() { return TypeMemPtr.make(_obj.dual(), !_nil); }
+ public TypeMemPtr dual() { return TypeMemPtr.make( dual0(), _obj.dual()); }
- @Override public TypeMemPtr glb() { return make(_obj.glb(),true ); }
- @Override public TypeMemPtr lub() { return make(_obj.lub(),false); }
+ // RHS is NIL
+ @Override Type meet0() {
+ // NOT DOING DUAL
+ return _nil==3 ? this : make((byte)3,_obj);
+ }
+
+ @Override public TypeMemPtr glb() { return make((byte)3,_obj.glb()); }
// Is forward-reference
@Override public boolean isFRef() { return _obj.isFRef(); }
- @Override public Type makeInit() { return _nil ? NULLPTR : Type.TOP; }
- @Override public Type makeZero() { return NULLPTR; }
- @Override public Type nonZero() { return VOIDPTR; }
-
- @Override public boolean isHigh() { return this==TOP; }
- @Override public boolean isConstant() { return this==NULLPTR; }
- @Override public boolean isHighOrConst() { return this==TOP || this==NULLPTR; }
@Override public int log_size() { return 2; } // (1<<2)==4-byte pointers
- @Override
- int hash() { return _obj.hashCode() ^ (_nil ? 1024 : 0); }
+ @Override int hash() { return _obj.hashCode() ^ super.hash(); }
- @Override
- boolean eq(Type t) {
+ @Override boolean eq(Type t) {
TypeMemPtr ptr = (TypeMemPtr)t; // Invariant
- return _obj == ptr._obj && _nil == ptr._nil;
- }
-
- // [void,name,MANY]*[,?]
- @Override
- public SB print(SB sb) {
- if( this== NULLPTR) return sb.p("null");
- if( this== VOIDPTR) return sb.p("*void");
- return _obj.print(sb.p("*")).p(_nil ? "?" : "");
- }
- @Override
- public SB gprint(SB sb) {
- if( this== NULLPTR) return sb.p("null");
- if( this== VOIDPTR) return sb.p("*void");
- return _obj.gprint(sb.p("*")).p(_nil ? "?" : "");
+ return _obj == ptr._obj && super.eq(ptr);
}
@Override public String str() {
- if( this== NULLPTR) return "null";
- if( this== VOIDPTR) return "*void";
- return "*"+_obj.str()+(_nil ? "?" : "");
+ if( this== NOTBOT) return "*void";
+ if( this== BOT) return "*void?";
+ return x()+"*"+_obj.str()+q();
}
+ @Override public SB print(SB sb) {
+ if( this== NOTBOT) return sb.p("*void");
+ if( this== BOT) return sb.p("*void?");
+ return _obj.print(sb.p(x()).p("*")).p(q());
+ }
+ @Override public SB gprint(SB sb) {
+ if( this== NOTBOT) return sb.p("*void");
+ if( this== BOT) return sb.p("*void?");
+ return _obj.gprint(sb.p(x()).p("*")).p(q());
+ }
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java
new file mode 100644
index 00000000..d8003d50
--- /dev/null
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java
@@ -0,0 +1,57 @@
+package com.seaofnodes.simple.type;
+
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.Utils;
+import java.util.ArrayList;
+
+/**
+ * Nil-able Scalar types
+ */
+public abstract class TypeNil extends Type {
+ // 0 = high-subclass choice nil
+ // 1 = high-subclass no nil
+ // 2 = low -subclass no nil
+ // 3 = low -subclass also nil
+ public final byte _nil;
+
+ TypeNil(byte t, byte nil ) { super(t); _nil = nil; }
+
+ public static void gather(ArrayList<Type> ts) { }
+
+ abstract TypeNil makeFrom(byte nil);
+
+ byte xmeet0(TypeNil that) { return (byte)Math.max(_nil,that._nil); }
+
+ byte dual0() { return (byte)(3-_nil); }
+
+ // RHS is NIL
+ abstract Type meet0();
+
+ // RHS is XNIL
+ Type meetX() {
+ return _nil==0 ? XNIL : (_nil<=2 ? TypePtr.NPTR : TypePtr.PTR);
+ }
+
+ Type nmeet(TypeNil tn) {
+ // Invariants: both are TypeNil subclasses and unequal classes.
+ // If this is TypePtr, we went to TypePtr.nmeet and not here.
+ // If that is TypePtr, this is not (invariant); reverse and go again.
+ if( tn instanceof TypePtr ts ) return ts.nmeet(this);
+
+ // Two mismatched TypeNil, no Scalar.
+ if( _nil==0 && tn._nil==0 ) return XNIL;
+ if( _nil<=2 && tn._nil<=2 ) return TypePtr.NPTR;
+ return TypePtr.PTR;
+ }
+
+ @Override public boolean isHigh () { return _nil <= 1; }
+ @Override public boolean isConstant () { return false; }
+ @Override public boolean isHighOrConst() { return isHigh() || isConstant(); }
+
+ final String q() { return _nil == 1 || _nil == 2 ? "" : "?"; }
+ final String x() { return isHigh() ? "~" : ""; }
+
+ int hash() { return _nil<<17; }
+
+ boolean eq(TypeNil ptr) { return _nil == ptr._nil; }
+}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypePtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypePtr.java
new file mode 100644
index 00000000..e9091c25
--- /dev/null
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypePtr.java
@@ -0,0 +1,53 @@
+package com.seaofnodes.simple.type;
+
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.Utils;
+import java.util.ArrayList;
+
+/**
+ * Represents a Scalar; a single register-sized value.
+ */
+public class TypePtr extends TypeNil {
+
+ private TypePtr(byte nil) { super(TPTR,nil); }
+
+ // An abstract pointer, pointing to either a Struct or an Array.
+ // Can also be null or not, so 4 choices {TOP,BOT} x {nil,not}
+ public static TypePtr XPTR = new TypePtr((byte)0).intern();
+ public static TypePtr XNPTR= new TypePtr((byte)1).intern();
+ public static TypePtr NPTR = new TypePtr((byte)2).intern();
+ public static TypePtr PTR = new TypePtr((byte)3).intern();
+ private static final TypePtr[] PTRS = new TypePtr[]{XPTR,XNPTR,NPTR,PTR};
+
+ public static void gather(ArrayList<Type> ts) { ts.add(PTR); ts.add(NPTR); }
+
+ TypeNil makeFrom(byte nil) { throw Utils.TODO(); }
+
+ @Override public TypeNil xmeet(Type t) {
+ TypePtr that = (TypePtr) t;
+ return PTRS[xmeet0(that)];
+ }
+
+ @Override public TypePtr dual() { return PTRS[dual0()]; }
+
+ // High scalar loses, low scalar wins
+ @Override TypeNil nmeet(TypeNil tn) {
+ if( _nil==0 ) return tn; // High scalar loses
+ if( _nil==1 ) return tn.makeFrom(xmeet0(tn)); // High scalar loses
+ if( _nil==2 ) return tn._nil==3 ? PTR : NPTR; // Low scalar wins
+ return PTR; // this
+ }
+
+
+ // RHS is NIL
+ @Override Type meet0() { return isHigh() ? NIL : PTR; }
+ // RHS is XNIL
+ // 0->xscalar, 1->nscalar, 2->nscalar, 3->scalar
+ @Override Type meetX() { return _nil==0 ? XNIL : (_nil==3 ? PTR : NPTR); }
+
+ @Override public TypePtr glb() { return PTR; }
+
+ private static final String[] STRS = new String[]{"~ptr","~nptr","nptr","ptr"};
+ @Override public String str() { return STRS[_nil]; }
+ @Override public SB print(SB sb) { return sb.p(str()); }
+}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
index c3ee5eb3..35bbe36c 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
@@ -49,7 +49,7 @@ public class TypeStruct extends Type {
// Array
public static TypeStruct makeAry(TypeInteger len, int lenAlias, Type body, int bodyAlias) {
- assert !(body instanceof TypeMemPtr tmp && !tmp._nil);
+ assert body instanceof TypeInteger || (body instanceof TypeNil tn && tn._nil==3);
return make("[" + body.str() + "]",
Field.make("#" ,len , lenAlias,true ),
Field.make("[]",body,bodyAlias,false));
@@ -58,10 +58,10 @@ public class TypeStruct extends Type {
// A pair of self-cyclic types
private static final TypeStruct S1F = makeFRef("S1");
private static final TypeStruct S2F = makeFRef("S2");
- public static final TypeStruct S1 = make("S1", Field.make("a", TypeInteger.BOT, -1, false), Field.make("s2",TypeMemPtr.make(S2F,false),-2, false) );
- private static final TypeStruct S2 = make("S2", Field.make("b", TypeFloat .BOT, -3, false), Field.make("s1",TypeMemPtr.make(S1F,false),-4, false) );
+ public static final TypeStruct S1 = make("S1", Field.make("a", TypeInteger.BOT, -1, false), Field.make("s2",TypeMemPtr.make((byte)2,S2F),-2, false) );
+ private static final TypeStruct S2 = make("S2", Field.make("b", TypeFloat .F64, -3, false), Field.make("s1",TypeMemPtr.make((byte)2,S1F),-4, false) );
- private static final TypeStruct ARY = makeAry(TypeInteger.BOT,-1,TypeFloat.BOT,-2);
+ private static final TypeStruct ARY = makeAry(TypeInteger.BOT,-1,TypeInteger.BOT,-2);
public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(BOT); ts.add(S1); ts.add(S2); ts.add(ARY); }
@@ -143,22 +143,6 @@ public class TypeStruct extends Type {
return false;
return true;
}
- @Override public TypeStruct lub() {
- if( _lub() ) return this;
- // Need to glb each field
- Field[] flds = new Field[_fields.length];
- for( int i=0; i<_fields.length; i++ )
- flds[i] = _fields[i].lub();
- return make(_name,flds);
- }
- private boolean _lub() {
- if( _fields!=null )
- for( Field f : _fields )
- if( f.lub() != f )
- return false;
- return true;
- }
-
// Is forward-reference
@Override public boolean isFRef() { return _fields==null; }
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter18/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index 88d79215..b1ca7da9 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -23,7 +23,8 @@ public class BrainFuckTest {
Parser parser = new Parser(
encoded + """
-var d = 0;
+
+int d = 0;
u8[] !output = new u8[0];
u8[] !data = new u8[100];
@@ -41,14 +42,14 @@ for( int pc = 0; pc < program#; pc++ ) {
// Output a byte; increase the output array size
var old = output;
output = new u8[output# + 1];
- for( var i = 0; i < old#; i++ )
+ for( int i = 0; i < old#; i++ )
output[i] = old[i];
output[old#] = data[d]; // Add the extra byte on the end
} else if (command == 44) {
data[d] = 42;
} else if (command == 91) {
if (data[d] == 0) {
- for( var d = 1; d > 0; ) {
+ for( int d = 1; d > 0; ) {
command = program[++pc];
if (command == 91) d++;
if (command == 93) d--;
@@ -56,7 +57,7 @@ for( int pc = 0; pc < program#; pc++ ) {
}
} else if (command == 93) {
if (data[d]) {
- for( var d = 1; d > 0; ) {
+ for( int d = 1; d > 0; ) {
command = program[--pc];
if (command == 93) d++;
if (command == 91) d--;
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter01Test.java
index f7524c17..44f1af0d 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter01Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -93,7 +93,7 @@ public class Chapter01Test {
new Parser("return 1;}").parse();
fail();
} catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
+ assertEquals("Syntax error, unexpected: }",e.getMessage());
}
}
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter03Test.java
index 4525918c..62304b38 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter03Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -1,7 +1,6 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
import org.junit.Test;
import static org.junit.Assert.*;
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index d41c83d8..435a2012 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -117,7 +117,7 @@ bar.a = 1;
return bar.a;
""");
try { parser.parse().iterate(); fail(); }
- catch( Exception e ) { assertEquals("Type null is not of declared type *Bar",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Type nil is not of declared type *Bar",e.getMessage()); }
}
@Test
@@ -143,7 +143,7 @@ bar.a = 1;
return bar.a;
""");
try { parser.parse(); fail(); }
- catch( Exception e ) { assertEquals("Type null is not of declared type *Bar", e.getMessage()); }
+ catch( Exception e ) { assertEquals("Type nil is not of declared type *Bar", e.getMessage()); }
}
@Test
@@ -156,7 +156,7 @@ if( bar ) bar.a = 1;
return bar;
""");
StopNode stop = parser.parse(false).iterate();
- assertEquals("return Phi(Region,(*void)Phi(Region,null,Bar),null);", stop.toString());
+ assertEquals("return Phi(Region,nil,Bar);", stop.toString());
}
@Test
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java
index a70a5f33..39824d39 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java
@@ -43,7 +43,7 @@ while( 1 ) {
return guess;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0));", stop.toString());
+ assertEquals("return Phi(Loop,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0f));", stop.toString());
assertEquals(3.0, Evaluator.evaluate(stop, 9));
assertEquals(1.414213562373095, Evaluator.evaluate(stop, 2));
}
@@ -56,7 +56,7 @@ flt x = arg;
return x+1==x;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return ((flt)arg==(ToFloat+1.0));", stop.toString());
+ assertEquals("return ((flt)arg==(ToFloat+1.0f));", stop.toString());
assertEquals(0L, Evaluator.evaluate(stop, 1));
}
}
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter13Test.java
index 30d9b147..a3e7c47f 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter13Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter13Test.java
@@ -87,7 +87,7 @@ N n = new N;
return n.next;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return null;", stop.toString());
+ assertEquals("return nil;", stop.toString());
}
@Test
@@ -113,7 +113,7 @@ N n = new N { next = null; }
return n.next;
""");
try { parser.parse().iterate(); fail(); }
- catch( Exception e ) { assertEquals("Type null is not of declared type *M",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Type nil is not of declared type *M",e.getMessage()); }
}
@Test
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter14Test.java
index 23c82358..f4e35fe5 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter14Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter14Test.java
@@ -158,11 +158,11 @@ return (arg | 123 ^ 456) >>> 1;
Parser parser = new Parser(
"""
flt f = arg;
-arg = f & 0;
+arg = f & 1;
return arg;
""");
try { parser.parse().iterate(); fail(); }
- catch( Exception e ) { assertEquals("Cannot '&' FltBot",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot '&' flt",e.getMessage()); }
}
@Test
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index 4e2682dc..e7dec389 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -3,9 +3,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.evaluator.Evaluator;
import com.seaofnodes.simple.node.StopNode;
import org.junit.Test;
-import org.junit.Ignore;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
public class Chapter15Test {
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter17Test.java
index 4a7e959a..9a2676d3 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter17Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter17Test.java
@@ -337,7 +337,7 @@ flt f=arg?1:1.2;
return f; // missing widening
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region,1.0,1.2);", stop.toString());
+ assertEquals("return Phi(Region,1.0f,1.2);", stop.toString());
assertEquals(1.2, Evaluator.evaluate(stop, 0));
}
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
index e39fc5d8..e9f8c367 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
@@ -11,7 +11,8 @@ public class Chapter18Test {
@Test
public void testJig() {
- Parser parser = new Parser("""
+ Parser parser = new Parser(
+"""
return 3.14;
""");
StopNode stop = parser.parse().iterate();
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java b/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java
index 61103f54..0fb0d431 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java
@@ -2,7 +2,6 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.type.*;
import org.junit.Assert;
-import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
@@ -12,19 +11,24 @@ public class TypeTest {
// Test basic properties and GLB
@Test
public void testTypeAdHoc() {
+ Assert.assertEquals( Type.BOTTOM, TypeInteger.TRUE.meet(TypeNil.NIL) );
+ Assert.assertEquals( Type.BOTTOM, TypeInteger.TOP.meet(TypeNil.NIL) );
+
+
TypeStruct s1 = TypeStruct.make("s1", new Field[]{
Field.make("a", TypeInteger.BOT,-1, false),
Field.make("b", TypeInteger.BOT,-2, false) });
TypeStruct s2 = TypeStruct.make("s2", new Field[]{
Field.make("a", TypeInteger.BOT,-3, false),
Field.make("b", TypeInteger.BOT,-4, false) });
- Assert.assertEquals(s1, s1.glb());
+ Assert.assertEquals(s1.makeRO(), s1.glb());
Assert.assertNotEquals(s1, s1.dual());
Assert.assertEquals(s1.makeRO(), s1.dual().glb());
- TypeMem m1 = TypeMem.make(1,TypeInteger.ZERO);
+ //TypeMem m1 = TypeMem.make(1,TypeInteger.ZERO);
+ TypeMem m1 = TypeMem.make(1,TypeNil.NIL);
TypeMem m2 = TypeMem.make(2,TypeInteger.U16);
- TypeMem m3 = TypeMem.make(3,TypeFloat.BOT);
+ TypeMem m3 = TypeMem.make(3,TypeFloat.F64);
TypeMem m4 = TypeMem.make(4,TypeInteger.BOT);
Assert.assertNotEquals(m1, m2);
@@ -32,47 +36,50 @@ public class TypeTest {
Assert.assertNotEquals(m3, m4);
Assert.assertEquals(TypeStruct.BOT, s1.meet(s2));
- Assert.assertEquals(TypeMem.make(0,TypeInteger.U16), m1.meet(m2));
- Assert.assertEquals(TypeMem .BOT, m2.meet(m3));
+ Assert.assertEquals(TypeMem .BOT, m1.meet(m2));
+ Assert.assertEquals(TypeMem.make(0,TypeFloat.F64), m1.meet(m3));
Assert.assertEquals(TypeMem .BOT, m3.meet(m4));
- Assert.assertEquals(TypeMem.make(1,TypeInteger.BOT), m1.glb());
- Assert.assertEquals(TypeMem.make(1,TypeInteger.ZERO), m1.dual());
+ Assert.assertEquals(m1, m1.glb());
+ //Assert.assertEquals(TypeMem.make(1,TypeInteger.ZERO), m1.dual());
+ Assert.assertEquals(TypeMem.make(1,Type.XNIL), m1.dual());
Assert.assertEquals(m4.dual(), m4.glb().dual());
- TypeMemPtr ptr1 = TypeMemPtr.make(s1);
+ TypeMemPtr ptr1 = TypeMemPtr.make((byte)2, s1);
Assert.assertEquals(s1, ptr1._obj);
- TypeMemPtr ptr2 = TypeMemPtr.make(s2);
+ TypeMemPtr ptr2 = TypeMemPtr.make((byte)2, s2);
Assert.assertEquals(s2, ptr2._obj);
- TypeMemPtr ptr1nil = TypeMemPtr.make(s1, true);
+ TypeMemPtr ptr1nil = TypeMemPtr.make(s1);
Assert.assertEquals(s1, ptr1nil._obj);
- Assert.assertTrue(ptr1nil._nil);
- Assert.assertFalse(ptr1nil._obj==null);
- TypeMemPtr ptr2nil = TypeMemPtr.make(s2, true);
+ assertEquals( 3, ptr1nil._nil );
+ Assert.assertNotNull( ptr1nil._obj );
+ TypeMemPtr ptr2nil = TypeMemPtr.make( s2);
Assert.assertEquals(s2, ptr2nil._obj);
Assert.assertNotEquals(ptr1, ptr2);
Assert.assertNotEquals(ptr1, ptr1.glb());
- Assert.assertEquals(ptr1nil, ptr1.glb());
+ Assert.assertEquals(ptr1nil.makeRO(), ptr1.glb());
Assert.assertEquals(ptr1, ptr1.dual().dual());
Assert.assertEquals(ptr1.glb().makeRO(), ptr1.dual().glb());
- Assert.assertEquals(TypeMemPtr.make(TypeStruct.BOT,true), ptr1.meet(ptr2nil));
- Assert.assertEquals(ptr1.glb(), ptr1.meet(TypeMemPtr.NULLPTR));
+ Assert.assertEquals(TypeMemPtr.make((byte)3,TypeStruct.BOT), ptr1.meet(ptr2nil));
+ //Assert.assertEquals(ptr1.glb(), ptr1.meet(TypeMemPtr.NULLPTR));
+ Assert.assertEquals(ptr1.glb(), ptr1.meet(TypeNil.NIL).makeRO());
TypeMemPtr TOP = TypeMemPtr.TOP;
- TypeMemPtr BOT = TypeMemPtr.make(TypeStruct.BOT,true );
- TypeMemPtr PTR = TypeMemPtr.make(TypeStruct.BOT,false);
- TypeMemPtr NULL = TypeMemPtr.NULLPTR;
+ TypeMemPtr BOT = TypeMemPtr.make((byte)3,TypeStruct.BOT);
+ TypeMemPtr PTR = TypeMemPtr.make((byte)2,TypeStruct.BOT);
+ //TypeMemPtr NULL = TypeMemPtr.NULLPTR;
+ Type NULL = TypeNil.NIL;
Type PTR_meet_NULL = NULL.meet(PTR);
Assert.assertEquals(BOT, PTR_meet_NULL);
Type ptr1_meet_ptr2 = ptr1.meet(ptr2);
Assert.assertEquals(PTR, ptr1_meet_ptr2);
Type NULL_join_ptr1 = NULL.join(ptr1);
- Assert.assertEquals(TOP, NULL_join_ptr1);
+ Assert.assertEquals(TypePtr.XNPTR, NULL_join_ptr1);
Type NULL_join_PTR = PTR.join(NULL);
- Assert.assertEquals(TOP, NULL_join_PTR);
+ Assert.assertEquals(TypePtr.XNPTR, NULL_join_PTR);
Type ptr1_dual = ptr1.dual();
Type nullableptr1_dual = ptr1nil.dual();
}
@@ -153,5 +160,4 @@ public class TypeTest {
assertSame(TypeStruct.S1,d1);
}
-
}
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
index 72f84fa2..ac442585 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
@@ -263,6 +263,7 @@ public class Evaluator {
private double vald(Node node) {
var v = val(node);
if (v instanceof Number n) return n.doubleValue();
+ if( v == null ) return 0;
throw new AssertionError("Not a double " + v);
}
@@ -270,7 +271,7 @@ public class Evaluator {
var type = cons.compute();
if (type instanceof TypeInteger i) return i.value();
if (type instanceof TypeFloat i) return i.value();
- assert type instanceof TypeMemPtr;
+ assert type == Type.NIL;
return null;
}
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java b/chapter18/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
index 51e39cd0..e86fb7b8 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
@@ -46,8 +46,8 @@ public class Fuzzer {
e.printStackTrace(System.out);
System.out.println("========== Seed ==========");
System.out.println(seed);
- System.out.println("========== Code ===========");
- System.out.println(script);
+ //System.out.println("========== Code ===========");
+ //System.out.println(script);
System.out.println("========= Reduced =========");
System.out.println(Reducer.reduce(script, e, reproducer));
System.out.println("===========================");
@@ -63,6 +63,10 @@ public class Fuzzer {
}
return false;
}
+ if( a==null && b == Long.valueOf(0) )
+ return false;
+ if( b==null && a == Long.valueOf(0) )
+ return false;
return true;
}