summaryrefslogtreecommitdiff
path: root/chapter15/src/test/java/com/seaofnodes
diff options
context:
space:
mode:
Diffstat (limited to 'chapter15/src/test/java/com/seaofnodes')
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java26
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java39
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java9
3 files changed, 68 insertions, 6 deletions
diff --git a/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index f884f18d..15465677 100644
--- a/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -21,7 +21,7 @@ return 3.14;
assertEquals(3.14, Evaluator.evaluate(stop, 0));
}
- @Ignore @Test
+ @Test
public void testBasic() {
Parser parser = new Parser(
"""
@@ -34,6 +34,30 @@ return is[1];
}
@Test
+ public void testRollingSum() {
+ Parser parser = new Parser(
+"""
+int[] ary = new int[arg];
+// Fill [0,1,2,3,4,...]
+int i=0;
+while( i < ary# ) {
+ ary[i] = i;
+ i = i+1;
+}
+// Fill [0,1,3,6,10,...]
+i=0;
+while( i < ary# - 1 ) {
+ ary[i+1] = ary[i+1] + ary[i];
+ i = i+1;
+}
+return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
+""");
+ StopNode stop = parser.parse(false).iterate(true);
+ assertEquals("return (.[]+(.[]*1000));", stop.toString());
+ assertEquals(1006L, Evaluator.evaluate(stop, 4));
+ }
+
+ @Test
public void testBad0() {
Parser parser = new Parser(
"""
diff --git a/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
index b897af7d..40d73b19 100644
--- a/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
+++ b/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
@@ -85,8 +85,21 @@ public class Evaluator {
private Object alloc(NewNode alloc) {
TypeTuple tt = alloc.compute();
TypeStruct type = ((TypeMemPtr)tt._types[1])._obj;
+ Object[] body=null;
+ if( type.isAry() ) {
+ long sz = (Long)val(alloc.in(1));
+ int base = alloc._ptr._obj.aryBase();
+ int scale = alloc._ptr._obj.aryScale();
+ long n = (sz-base)>>scale;
+ body = new Object[(int)n+1]; // Array body
+ body[0] = n; // Array length
+ } else {
+ body = new Object[type._fields.length];
+ }
Object[] mems = new Object[type._fields.length+2];
- mems[1] = new Obj(type,new Object[type._fields.length]);
+ // mems[0] is control
+ mems[1] = new Obj(type,body); // the ref
+ // mems[2+...] are memory aliases
return mems;
}
@@ -94,7 +107,17 @@ public class Evaluator {
var from = (Obj)val(load.ptr());
var off = val(load.off());
var idx = getFieldIndex(from.struct, load, (Long)off);
- return from.fields[idx];
+ if( idx==1 && from.struct.isAry() ) {
+ long len = (Long)from.fields[0];
+ int base = from.struct.aryBase();
+ int scale = from.struct.aryScale();
+ long i = ((Long)off - base)>>scale;
+ if( i < 0 || i >= len )
+ throw new RuntimeException("Array index out of bounds " + off + " <= " + len);
+ return from.fields[(int)i+1];
+
+ } else
+ return from.fields[idx];
}
private Object store(StoreNode store) {
@@ -102,7 +125,17 @@ public class Evaluator {
var off = val(store.off());
var val = val(store.val());
var idx = getFieldIndex(to.struct, store, (Long)off);
- to.fields[idx] = val;
+ if( idx==1 && to.struct.isAry() ) {
+ long len = (Long)to.fields[0];
+ int base = to.struct.aryBase();
+ int scale = to.struct.aryScale();
+ long i = ((Long)off - base)>>scale;
+ if( i < 0 || i >= len )
+ throw new RuntimeException("Array index out of bounds " + off + " <= " + len);
+ to.fields[(int)i+1] = val;
+
+ } else
+ to.fields[idx] = val;
return null;
}
diff --git a/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java b/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java
index fd8fdb8d..59c15d3f 100644
--- a/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java
+++ b/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java
@@ -155,7 +155,10 @@ public class Scheduler {
* @return true if all placed inputs are before this node.
*/
private boolean isValid(NodeData data) {
- return data.node._inputs.stream().map(i->i==null?null:d(i)).map(d->d==null||d.users>0?null:d.block).allMatch(d->d==null||dom(d, data.block)==d);
+ return data.node._inputs.stream()
+ .map(i->i==null?null:d(i))
+ .map(d->d==null||d.users>0?null:d.block)
+ .allMatch(d->d==null||dom(d, data.block)==d);
}
/**
@@ -399,7 +402,9 @@ public class Scheduler {
}
}
if (!(node instanceof ReturnNode))
- for (Node n:node._outputs) if (n!=null && n instanceof CFGNode && isCFGNodeReady(n) && d(n).block == null) queue.push(d(n));
+ for (Node n : node._outputs)
+ if(n instanceof CFGNode && isCFGNodeReady(n) && d(n).block == null)
+ queue.push(d(n));
var b = block;
for(var in:data.node._inputs) od(in).ifPresent(d->update(d, b));
}