From 6d96985f9d297f6dee9ee6f877b9986dec797d4c Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 7 Nov 2024 15:19:19 -0800 Subject: Support post ++ on arrays and structs --- .../main/java/com/seaofnodes/simple/Parser.java | 34 +++++++++++++++----- .../java/com/seaofnodes/simple/BrainFuckTest.java | 10 +++--- .../java/com/seaofnodes/simple/Chapter17Test.java | 37 ++++++++++++++++++++++ 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() { -- cgit v1.2.3