summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXmiliaH <xmilia.hermit@gmail.com>2024-10-05 00:50:13 +0200
committerCliff Click <cliffc@acm.org>2024-10-06 08:56:22 -0700
commitf92f34f687e8d3ff194f7d42e0235e1463e3c2ef (patch)
treed1b518a8b99a8758ae94ff0e9e7ebdc20c5340b2
parentef806eefe7047c376320e9245f3e8733fdc8cd92 (diff)
downloadSimple-f92f34f687e8d3ff194f7d42e0235e1463e3c2ef.tar.gz
Simple-f92f34f687e8d3ff194f7d42e0235e1463e3c2ef.zip
Update evaluator toString for arrays
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/BrainFuckTest.java22
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java22
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java152
3 files changed, 148 insertions, 48 deletions
diff --git a/chapter15/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter15/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index a7a4966d..f7c66bda 100644
--- a/chapter15/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/chapter15/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -27,12 +27,6 @@ public class BrainFuckTest {
int pc = 0;
int d = 0;
u8[] data = new u8[100];
-int i=0;
-while(i < data#) {
- data[i] = 0;
- i = i + 1;
-}
-
u8[] output = new u8[0];
while (pc < program#) {
@@ -48,7 +42,7 @@ while (pc < program#) {
} else if (command == 46) {
u8[] old = output;
output = new u8[output# + 1];
- i = 0;
+ int i = 0;
while (i < old#) {
output[i] = old[i];
i = i + 1;
@@ -79,19 +73,9 @@ while (pc < program#) {
}
pc = pc + 1;
}
-int result = 0;
-i = 0;
-while (i < 8) {
- result = (result << 8) | output[i];
- i = i + 1;
-}
-return result;
+return output;
""");
StopNode stop = parser.parse(false).iterate(false);
- long expected = 0;
- for (byte b : "Hello Wo".getBytes(StandardCharsets.UTF_8)) {
- expected = (expected << 8) | b;
- }
- assertEquals(expected, Evaluator.evaluate(stop, 0, 10000));
+ assertEquals("Hello World!\n", Evaluator.evaluate(stop, 0, 10000).toString());
}
}
diff --git a/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index 266d8a47..dff39ba3 100644
--- a/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter15/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -24,6 +24,22 @@ return 3.14;
}
@Test
+ public void testCyclic() {
+ Parser parser = new Parser(
+"""
+struct C {
+ C? l;
+}
+C c = new C;
+c.l = c;
+return c;
+""");
+ StopNode stop = parser.parse(false).iterate(true);
+ assertEquals("return C;", stop.toString());
+ assertEquals("Obj<C>@1{l=obj@1}", Evaluator.evaluate(stop, 0).toString());
+ }
+
+ @Test
public void testSafetyCheck() {
Parser parser = new Parser(
"""
@@ -39,7 +55,7 @@ return output;
""");
StopNode stop = parser.parse(false).iterate(true);
assertEquals("return u8[];", stop.toString());
- assertEquals("Obj<u8[]> {\n #=1\n []=1\n}", Evaluator.evaluate(stop, 0).toString());
+ assertEquals("\u0001", Evaluator.evaluate(stop, 0).toString());
}
@Test
@@ -91,7 +107,7 @@ return a;
""");
StopNode stop = parser.parse(false).iterate(false);
assertEquals("return *A?[];", stop.toString());
- assertEquals("Obj<*A?[]> {\n #=2\n []=null\n}", Evaluator.evaluate(stop, 0).toString());
+ assertEquals("Obj<*A?[]>{#=2,[]=[null,null]}", Evaluator.evaluate(stop, 0).toString());
}
@Test
@@ -162,7 +178,7 @@ return root;
""");
StopNode stop = parser.parse(false).iterate(false);
assertEquals("return Tree;", stop.toString());
- assertEquals("Obj<Tree> {\n _kids=Obj<*Tree?[]> {\n #=2\n []=Obj<Tree> {\n _kids=null\n}\n}\n}", Evaluator.evaluate(stop, 0).toString());
+ assertEquals("Obj<Tree>{_kids=Obj<*Tree?[]>{#=2,[]=[Obj<Tree>{_kids=null},null]}}", Evaluator.evaluate(stop, 0).toString());
}
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 26860858..a723095c 100644
--- a/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
+++ b/chapter15/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
@@ -6,23 +6,115 @@ import com.seaofnodes.simple.type.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Objects;
+import java.util.*;
public class Evaluator {
private static final Object MEMORY = new Object();
public record Obj(TypeStruct struct, Object[] fields) {
+ private void init(IdentityHashMap<Obj, Integer> objs) {
+ var oid = objs.get(this);
+ if (oid != null) {
+ if (oid != 0) objs.put(this, 0);
+ return;
+ }
+ objs.put(this, -1);
+ for (var obj : fields) {
+ if (obj instanceof Obj o) o.init(objs);
+ }
+ }
+ private static int p(StringBuilder sb, IdentityHashMap<Obj, Integer> objs, int id, String indentation, String step, String sep, Object obj) {
+ if (obj instanceof Obj o) return o.p(sb, objs, id, indentation, step, sep);
+ sb.append(obj);
+ return id;
+ }
+ private int p(StringBuilder sb, IdentityHashMap<Obj, Integer> objs, int id, String indentation, String step, String sep) {
+ var cid = objs.get(this);
+ assert cid != null;
+ if (cid > 0) {
+ sb.append("obj@").append(cid);
+ return id;
+ }
+ if (struct._name.equals("u8[]")) {
+ sb.append('"');
+ for (int i=struct._fields.length-1; i<fields.length; i++) {
+ var v = fields[i];
+ if (v == null) v = 0;
+ assert v instanceof Number;
+ var n = ((Number)v).byteValue() & 0xFF;
+ if (n >= 0x20 && n < 0x80) {
+ if (n == 0x22 || n == 0x5C) sb.append("\\");
+ sb.append((char)n);
+ } else {
+ sb.append("\\x").append("0123456789abcdef".charAt(n >> 4)).append("0123456789abcdef".charAt(n & 0xF));
+ }
+ }
+ sb.append('"');
+ return id;
+ }
+ sb.append("Obj<").append(struct._name).append(">");
+ if (cid == 0) {
+ cid = id++;
+ objs.put(this, cid);
+ sb.append("@").append(cid);
+ }
+ sb.append("{");
+ if (struct._fields.length == 0) {
+ assert !struct.isAry();
+ sb.append("}");
+ return id;
+ }
+ String nextIndent = indentation + step;
+ int e = struct._fields.length - 1;
+ for(int i=0; i<e; i++) {
+ sb.append(nextIndent).append(struct._fields[i]._fname).append("=");
+ id = p(sb, objs, id, nextIndent, step, sep, fields[i]);
+ sb.append(sep);
+ }
+ sb.append(nextIndent).append(struct._fields[e]._fname).append("=");
+ if (struct.isAry()) {
+ sb.append("[");
+ if (fields.length > e) {
+ String innerIndent = nextIndent + step;
+ sb.append(innerIndent);
+ id = p(sb, objs, id, nextIndent, step, sep, fields[e]);
+ for (int i = e+1; i < fields.length; i++) {
+ sb.append(sep).append(innerIndent);
+ id = p(sb, objs, id, nextIndent, step, sep, fields[i]);
+ }
+ sb.append(nextIndent);
+ }
+ sb.append("]");
+ } else {
+ id = p(sb, objs, id, nextIndent, step, sep, fields[e]);
+ }
+ sb.append(indentation).append("}");
+ return id;
+ }
+ private StringBuilder p(StringBuilder sb, String indentation, String step, String sep) {
+ var objs = new IdentityHashMap<Obj, Integer>();
+ init(objs);
+ p(sb, objs, 1, indentation, step, sep);
+ return sb;
+ }
@Override
public String toString() {
- var sb = new StringBuilder();
- sb.append("Obj<").append(struct._name).append("> {");
- for(int i=0; i<struct._fields.length; i++) {
- sb.append("\n ").append(struct._fields[i]._fname).append("=").append(fields[i]);
+ if (struct._name.equals("u8[]")) {
+ var sb = new StringBuilder();
+ for (int i=struct._fields.length-1; i<fields.length; i++) {
+ var v = fields[i];
+ if (v == null) v = 0;
+ assert v instanceof Number;
+ var n = ((Number)v).byteValue() & 0xFF;
+ sb.append((char)n);
+ }
+ return sb.toString();
}
- return sb.append("\n}").toString();
+ return p(new StringBuilder(), "", "", ",").toString();
+ }
+ public String pretty() {
+ return p(new StringBuilder(), "\n", " ", "").toString();
}
}
@@ -82,19 +174,32 @@ public class Evaluator {
return in2 == 0 ? 0 : vald(div.in(1)) / in2;
}
+ private static long offToIdx(long off, TypeStruct t) {
+ off -= t.aryBase();
+ int scale = t.aryScale();
+ long mask = (1L << scale)-1;
+ assert (off & mask) == 0;
+ return off>>scale;
+ }
+
private Object alloc(NewNode alloc) {
- TypeTuple tt = alloc.compute();
- TypeStruct type = ((TypeMemPtr)tt._types[1])._obj;
+ TypeStruct type = alloc._ptr._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;
+ long n = offToIdx(sz, type);
if( n < 0 )
throw new NegativeArraySizeException(""+n);
body = new Object[(int)n+1]; // Array body
body[0] = n; // Array length
+ var c = type._fields[type._fields.length-1]._type;
+ if (c instanceof TypeInteger) {
+ for (int i=0; i<n; i++) body[i+type._fields.length-1] = 0L;
+ } else if (c instanceof TypeFloat) {
+ for (int i = 0; i < n; i++) body[i+type._fields.length-1] = 0D;
+ } else {
+ assert c instanceof TypeMemPtr;
+ }
} else {
body = new Object[type._fields.length];
}
@@ -107,16 +212,14 @@ public class Evaluator {
private Object load(LoadNode load) {
var from = (Obj)val(load.ptr());
- var off = val(load.off());
+ var off = vall(load.off());
var idx = getFieldIndex(from.struct, load, (Long)off);
- if( idx==1 && from.struct.isAry() ) {
+ if( idx==from.struct._fields.length-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;
+ long i = offToIdx(off, from.struct);
if( i < 0 || i >= len )
throw new ArrayIndexOutOfBoundsException("Array index out of bounds " + i + " < " + len);
- return from.fields[(int)i+1];
+ return from.fields[(int)i+from.struct._fields.length-1];
} else
return from.fields[idx];
@@ -124,18 +227,15 @@ public class Evaluator {
private Object store(StoreNode store) {
var to = (Obj)val(store.ptr());
- var off = val(store.off());
+ var off = vall(store.off());
var val = val(store.val());
var idx = getFieldIndex(to.struct, store, (Long)off);
- if( idx==1 && to.struct.isAry() ) {
+ if( idx==to.struct._fields.length-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;
+ long i = offToIdx(off, to.struct);
if( i < 0 || i >= len )
throw new RuntimeException("Array index out of bounds " + off + " <= " + len);
- to.fields[(int)i+1] = val;
-
+ to.fields[(int)i+to.struct._fields.length-1] = val;
} else
to.fields[idx] = val;
return null;