summaryrefslogtreecommitdiff
path: root/chapter17
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2024-11-07 15:19:19 -0800
committerCliff Click <cliffc@acm.org>2024-11-23 09:03:20 -0800
commit6d96985f9d297f6dee9ee6f877b9986dec797d4c (patch)
tree79db56ad23fb9ab16824d82a03d0821a897c5294 /chapter17
parent2d6ee0da8228e0b53a7387c964d74b28aa58c8f3 (diff)
downloadSimple-6d96985f9d297f6dee9ee6f877b9986dec797d4c.tar.gz
Simple-6d96985f9d297f6dee9ee6f877b9986dec797d4c.zip
Support post ++ on arrays and structs
Diffstat (limited to 'chapter17')
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/Parser.java34
-rw-r--r--chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java10
-rw-r--r--chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java37
3 files changed, 67 insertions, 14 deletions
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/Parser.java b/chapter17/src/main/java/com/seaofnodes/simple/Parser.java
index 9710be30..abd70f89 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/Parser.java
@@ -761,8 +761,8 @@ public class Parser {
// Expect an identifier now
ScopeMinNode.Var n = requireLookupId("an identifier or expression");
Node rvalue = _scope.in(n).keep();
- if( matchx("++") ) _scope.update(n,new AddNode(rvalue,con( 1)).peephole());
- if( matchx("--") ) _scope.update(n,new AddNode(rvalue,con(-1)).peephole());
+ if( matchx("++") || matchx("--") )
+ _scope.update(n,new AddNode(rvalue,con( _lexer.peek(-1)=='+' ? 1 : -1)).peephole());
return rvalue.unkeep();
}
@@ -907,24 +907,24 @@ public class Parser {
// Get field type and layout offset from base type and field index fidx
Field f = base._fields[fidx]; // Field from field index
- Node off = name.equals("[]") // If field is an array body
+ Node off = (name.equals("[]") // If field is an array body
// Array index math
? new AddNode(con(base.aryBase()),new ShlNode(require(parseExpression(),"]"),con(base.aryScale())).peephole()).peephole()
// Struct field offsets are hardwired
- : con(base.offset(fidx));
+ : con(base.offset(fidx))).keep();
// Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment
if( matchOpx('=','=') ) {
Node val = parseExpression();
// Auto-truncate when storing to narrow fields
- val = zsMask(val,f._type);
- Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off, val, false);
+ val = zsMask(val,f._type).keep();
+ Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off.unkeep(), val, false);
// Arrays include control, as a proxy for a safety range check.
// Structs don't need this; they only need a NPE check which is
// done via the type system.
if( base.isAry() ) st.setDef(0,ctrl());
memAlias(f._alias, st.peephole());
- return val; // "obj.a = expr" returns the expression while updating memory
+ return val.unkeep(); // "obj.a = expr" returns the expression while updating memory
}
Node load = new LoadNode(name, f._alias, f._type.glb(), memAlias(f._alias), expr, off);
@@ -932,7 +932,23 @@ public class Parser {
// Structs don't need this; they only need a NPE check which is
// done via the type system.
if( base.isAry() ) load.setDef(0,ctrl());
- return parsePostfix(load.peephole());
+ load = load.peephole();
+
+ // ary[idx]++
+ if( matchx("++") || matchx("--") ) {
+ Node inc = new AddNode(load,con( _lexer.peek(-1)=='+' ? 1 : -1)).peephole();
+ Node val = zsMask(inc,f._type);
+ Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off, val, false);
+ // Arrays include control, as a proxy for a safety range check.
+ // Structs don't need this; they only need a NPE check which is
+ // done via the type system.
+ if( base.isAry() ) st.setDef(0,ctrl());
+ memAlias(f._alias, st.peephole());
+ // And use the original loaded value as the result
+ }
+ if( off.unkeep().isDead() ) off.kill();
+
+ return parsePostfix(load);
}
@@ -1044,6 +1060,8 @@ public class Parser {
return isEOF() ? Character.MAX_VALUE // Special value that causes parsing to terminate
: (char) _input[_position];
}
+ // Just crash if misused
+ public byte peek(int off) { return _input[_position+off]; }
private char nextChar() {
char ch = peek();
diff --git a/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index 0a48d2e7..88dccc49 100644
--- a/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -23,10 +23,8 @@ public class BrainFuckTest {
Parser parser = new Parser(
encoded + """
-int pc = 0;
-int d = 0;
-u8[] data = new u8[100];
-u8[] output = new u8[0];
+int pc = 0, d = 0;
+u8[] data = new u8[100], output = new u8[0];
while (pc < program#) {
int command = program[pc];
@@ -35,9 +33,9 @@ while (pc < program#) {
} else if (command == 60) {
d--;
} else if (command == 43) {
- data[d] = data[d] + 1;
+ data[d]++;
} else if (command == 45) {
- data[d] = data[d] - 1;
+ data[d]--;
} else if (command == 46) {
u8[] old = output;
output = new u8[output# + 1];
diff --git a/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java
index 91c275ce..45e3ef0f 100644
--- a/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java
+++ b/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java
@@ -49,6 +49,43 @@ return -arg---arg--;
assertEquals(1L, Evaluator.evaluate(stop, 0));
}
+ @Test
+ public void testInc3() {
+ Parser parser = new Parser("""
+int[] xs = new int[arg];
+xs[0]++;
+xs[1]++;
+return xs[0];
+""");
+ StopNode stop = parser.parse().iterate();
+ assertEquals("return 1;", stop.toString());
+ assertEquals(1L, Evaluator.evaluate(stop, 2));
+ }
+
+ @Test
+ public void testInc4() {
+ Parser parser = new Parser("""
+u8[] xs = new u8[1];
+xs[0]--;
+return xs[0];
+""");
+ StopNode stop = parser.parse().iterate();
+ assertEquals("return 255;", stop.toString());
+ assertEquals(255L, Evaluator.evaluate(stop, 2));
+ }
+
+ @Test
+ public void testInc5() {
+ Parser parser = new Parser("""
+struct S { u16 x; };
+S s = new S;
+s.x--;
+return s.x;
+""");
+ StopNode stop = parser.parse().iterate();
+ assertEquals("return 65535;", stop.toString());
+ assertEquals(65535L, Evaluator.evaluate(stop, 2));
+ }
@Test
public void testLinkedList2() {