diff options
| author | Cliff Click <cliffc@acm.org> | 2026-10-03 14:03:48 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-08 16:52:27 -0700 |
| commit | 848fcaac757a631d9300cf45d65175b16c2b0ccb (patch) | |
| tree | e988c018bd61fe22ee259dc9d3f215b373be1398 /src/test/java/com | |
| parent | 2dab7225ac9909ddeb0bd45b4f6c2ab0a50d1788 (diff) | |
| download | Simple-848fcaac757a631d9300cf45d65175b16c2b0ccb.tar.gz Simple-848fcaac757a631d9300cf45d65175b16c2b0ccb.zip | |
Chapter 17a: Mutability and Read-Only Views
Co-authored-by: Jun Kawasaki <jun784@gmail.com>
Diffstat (limited to 'src/test/java/com')
23 files changed, 373 insertions, 310 deletions
diff --git a/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/src/test/java/com/seaofnodes/simple/BrainFuckTest.java deleted file mode 100644 index 29ef8732..00000000 --- a/src/test/java/com/seaofnodes/simple/BrainFuckTest.java +++ /dev/null @@ -1,80 +0,0 @@ -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 java.nio.charset.StandardCharsets; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -public class BrainFuckTest { - - @Test - public void testBrainfuck() { - var program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.".getBytes(StandardCharsets.UTF_8); - var encoded = new StringBuilder("u8[] program = new u8[").append(program.length).append("];"); - for (int i = 0; i < program.length; i++) { - int value = program[i] & 0xFF; - encoded.append("program[").append(i).append("] = ").append(value).append(";"); - } - - Parser parser = new Parser( - encoded + """ -int pc = 0; -int d = 0; -u8[] data = new u8[100]; -u8[] output = new u8[0]; - -while (pc < program#) { - int command = program[pc]; - if (command == 62) { - d = d + 1; - } else if (command == 60) { - d = d - 1; - } else if (command == 43) { - data[d] = data[d] + 1; - } else if (command == 45) { - data[d] = data[d] - 1; - } else if (command == 46) { - u8[] old = output; - output = new u8[output# + 1]; - int i = 0; - while (i < old#) { - output[i] = old[i]; - i = i + 1; - } - output[i] = data[d]; - } else if (command == 44) { - data[d] = 42; - } else if (command == 91) { - if (data[d] == 0) { - int d = 1; - while (d > 0) { - pc = pc + 1; - command = program[pc]; - if (command == 91) d = d + 1; - if (command == 93) d = d - 1; - } - } - } else if (command == 93) { - if (data[d] != 0) { - int d = 1; - while (d > 0) { - pc = pc - 1; - command = program[pc]; - if (command == 93) d = d + 1; - if (command == 91) d = d - 1; - } - } - } - pc = pc + 1; -} -return output; - """); - StopNode stop = parser.parse().iterate(); - assertEquals("Hello World!\n", Evaluator.evaluate(stop, 0, 10000).toString()); - } -} diff --git a/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/src/test/java/com/seaofnodes/simple/Chapter01Test.java index c10dc510..f7524c17 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter01Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter01Test.java @@ -58,7 +58,7 @@ public class Chapter01Test { @Test public void testNotBad3() { // this test used to fail in chapter 1 - assertEquals("return 12;", new Parser("return --12;").parse().print()); + assertEquals("return 12;", new Parser("return - -12;").parse().print()); } @Test diff --git a/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/src/test/java/com/seaofnodes/simple/Chapter03Test.java index 609dff76..f06e5dcf 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter03Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter03Test.java @@ -59,7 +59,7 @@ public class Chapter03Test { @Test public void testBad1() { try { - new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse(); + new Parser("int a=1; int b=2; int !c=0; { int b=3; c=a+b;").parse(); fail(); } catch( RuntimeException e ) { assertEquals("Syntax error, expected }: ",e.getMessage()); diff --git a/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 14d31245..36727a8f 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -127,14 +127,14 @@ public class Chapter04Test { @Test public void testBug1() { - Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; "); + Parser parser = new Parser("int a=arg+1; int !b=a; b=1; return a+2; "); StopNode ret = parser.parse(); assertEquals("return (arg+3);", ret.print()); } @Test public void testBug2() { - Parser parser = new Parser("int a=arg+1; a=a; return a; "); + Parser parser = new Parser("int !a=arg+1; a=a; return a; "); StopNode ret = parser.parse(); assertEquals("return (arg+1);", ret.print()); } diff --git a/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/src/test/java/com/seaofnodes/simple/Chapter05Test.java index cd646126..7ea75f49 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter05Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter05Test.java @@ -17,12 +17,11 @@ if (arg == 1) a = arg+2; else { a = arg-3; - } - -return a;"""); +return a; +"""); StopNode ret = parser.parse().iterate(); - assertEquals("return Phi(Region21,(arg+2),(arg-3));", ret.toString()); + assertEquals("return Phi(Region,(arg+2),(arg-3));", ret.toString()); } @Test @@ -37,7 +36,7 @@ if (arg == 1) { } return c;""", TypeInteger.BOT); StopNode ret = parser.parse().iterate(); - assertEquals("return Phi(Region20,4,3);", ret.toString()); + assertEquals("return Phi(Region,4,3);", ret.toString()); } @Test @@ -65,7 +64,7 @@ else b=a+1; return a+b;"""); StopNode ret = parser.parse().iterate(); - assertEquals("return ((arg*2)+Phi(Region24,2,3));", ret.toString()); + assertEquals("return ((arg*2)+Phi(Region,2,3));", ret.toString()); } @Test @@ -80,7 +79,7 @@ else a=b+1; return a+b;"""); StopNode ret = parser.parse().iterate(); - assertEquals("return ((Phi(Region35,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString()); + assertEquals("return ((Phi(Region,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString()); } @Test @@ -100,7 +99,7 @@ else return a; """, TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region39,Phi(Region25,2,3),Phi(Region37,4,5));", stop.toString()); + assertEquals("return Phi(Region,Phi(Region,2,3),Phi(Region,4,5));", stop.toString()); } @Test @@ -116,7 +115,7 @@ if( arg==0 ) return arg+a+b; """, TypeInteger.BOT); StopNode stop = parser.parse(); - assertEquals("return ((arg+Phi(Region18,1,0))+Phi(Region34,2,0));", stop.toString()); + assertEquals("return ((arg+Phi(Region,1,0))+Phi(Region,2,0));", stop.toString()); } @Test @@ -130,7 +129,7 @@ if( arg==1 ) } return a;"""); StopNode ret = parser.parse().iterate(); - assertEquals("return (arg==Phi(Region20,3,2));", ret.toString()); + assertEquals("return (arg==Phi(Region,3,2));", ret.toString()); } @Test diff --git a/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/src/test/java/com/seaofnodes/simple/Chapter06Test.java index d2c46df5..50c0580d 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter06Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter06Test.java @@ -65,7 +65,7 @@ else b=5; return b;""", TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region40,42,5);", stop.toString()); + assertEquals("return Phi(Region,42,5);", stop.toString()); } @Test @@ -84,7 +84,7 @@ else b=5; return b;""", TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region33,2,5);", stop.toString()); + assertEquals("return Phi(Region,2,5);", stop.toString()); } @Test @@ -144,7 +144,7 @@ else return a; """, TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region44,3,Phi(Region42,4,5));", stop.toString()); + assertEquals("return Phi(Region,3,Phi(Region,4,5));", stop.toString()); } @Test @@ -200,7 +200,7 @@ if( arg ) { return a+b; """); StopNode ret = parser.parse().iterate(); - assertEquals("return Phi(Region29,4,1);", ret.toString()); + assertEquals("return Phi(Region,4,1);", ret.toString()); } @@ -251,7 +251,7 @@ if( arg ) { return a+b+c; """); StopNode ret = parser.parse().iterate(); - assertEquals("return (Phi(Region41,Phi(Region26,2,3),0)+Phi(Region,3,1));", ret.toString()); + assertEquals("return (Phi(Region,Phi(Region,2,3),0)+Phi(Region,3,1));", ret.toString()); } diff --git a/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/src/test/java/com/seaofnodes/simple/Chapter07Test.java index 443b0d17..ad3622c9 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter07Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter07Test.java @@ -10,14 +10,14 @@ public class Chapter07Test { @Test public void testExample() { Parser parser = new Parser( - """ - while(arg < 10) { - arg = arg + 1; - } - return arg; - """); +""" +while(arg < 10) { + arg = arg + 1; +} +return arg; +"""); StopNode stop = parser.parse(); - assertEquals("return Phi(Loop9,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return Phi(Loop,arg,(Phi_arg+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -34,7 +34,7 @@ if(arg){}else{ return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region27,1,Phi(Loop16,1,(Phi_a+1)));", stop.toString()); + assertEquals("return Phi(Region,1,Phi(Loop,1,(Phi_a+1)));", stop.toString()); } @Test @@ -54,7 +54,7 @@ while(i < arg) { return sum; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop11,0,Phi(Loop23,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString()); + assertEquals("return Phi(Loop,0,Phi(Loop,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString()); } @Test @@ -70,7 +70,7 @@ while(a < 10) { return b; """); StopNode stop = parser.parse(); - assertEquals("return Phi(Loop11,2,Phi(Region30,Phi_b,4));", stop.toString()); + assertEquals("return Phi(Loop,2,Phi(Region,Phi_b,4));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -89,7 +89,7 @@ while(a < 10) { return b; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop11,2,(Phi(Region30,Phi_b,4)+1));", stop.toString()); + assertEquals("return Phi(Loop,2,(Phi(Region,Phi_b,4)+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -106,7 +106,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse(); - assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -122,7 +122,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -135,7 +135,7 @@ while(arg) a = 2; return a; """); StopNode stop = parser.parse(); - assertEquals("return Phi(Loop10,1,2);", stop.toString()); + assertEquals("return Phi(Loop,1,2);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -148,7 +148,7 @@ while(arg) a = 2; return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,1,2);", stop.toString()); + assertEquals("return Phi(Loop,1,2);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -164,7 +164,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse(); - assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -180,7 +180,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -197,7 +197,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse(); - assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -214,7 +214,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } diff --git a/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/src/test/java/com/seaofnodes/simple/Chapter08Test.java index 89ce8313..bb3bd674 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter08Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter08Test.java @@ -23,7 +23,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region38,Phi(Region27,Phi(Loop9,arg,(Phi_arg+1)),Add),Add);", stop.toString()); + assertEquals("return Phi(Region,Phi(Region,Phi(Loop,arg,(Phi_arg+1)),Add),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); Assert.assertEquals(5L, Evaluator.evaluate(stop, 1)); Assert.assertEquals(10L, Evaluator.evaluate(stop, 6)); @@ -46,7 +46,7 @@ while(arg < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,1,Phi(Region44,Phi_a,(Phi_a+1)));", stop.toString()); + assertEquals("return Phi(Loop,1,Phi(Region,Phi_a,(Phi_a+1)));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -65,7 +65,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region36,Phi(Loop9,arg,(Phi_arg+1)),Add);", stop.toString()); + assertEquals("return Phi(Region,Phi(Loop,arg,(Phi_arg+1)),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); } @@ -81,7 +81,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region27,Phi(Loop9,arg,(Phi_arg+1)),Add);", stop.toString()); + assertEquals("return Phi(Region,Phi(Loop,arg,(Phi_arg+1)),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); } @@ -100,7 +100,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return Phi(Loop,arg,(Phi_arg+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -117,7 +117,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return Phi(Loop,arg,(Phi_arg+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -138,7 +138,7 @@ return arg; @Test public void testRegress2() { - Parser parser = new Parser("if(1) return 0; else while(arg>--arg) arg=arg+1; return 0;"); + Parser parser = new Parser("if(1) return 0; else while(arg>- -arg) arg=arg+1; return 0;"); StopNode stop = parser.parse().iterate(); assertEquals("return 0;", stop.toString()); } @@ -185,7 +185,7 @@ while(arg < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region30,Phi(Loop10,1,(Phi_a+1)),Add);", stop.toString()); + assertEquals("return Phi(Region,Phi(Loop,1,(Phi_a+1)),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); } @@ -201,7 +201,7 @@ while(1) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return (Phi(Loop10,1,Add)+1);", stop.toString()); + assertEquals("return (Phi(Loop,1,Add)+1);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode prj && prj._idx==1 ); } diff --git a/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/src/test/java/com/seaofnodes/simple/Chapter09Test.java index 49ee75a2..c31afcd6 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter09Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter09Test.java @@ -69,7 +69,7 @@ while (arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,arg,(Phi_arg+2));", stop.toString()); + assertEquals("return Phi(Loop,arg,(Phi_arg+2));", stop.toString()); Assert.assertEquals(11L, Evaluator.evaluate(stop, 1)); } @@ -86,7 +86,7 @@ while (arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop11,arg,(Phi_arg+4));", stop.toString()); + assertEquals("return Phi(Loop,arg,(Phi_arg+4));", stop.toString()); Assert.assertEquals(13L, Evaluator.evaluate(stop, 1)); } @@ -115,7 +115,7 @@ while (arg) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop17,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return 0;", stop.toString()); } @Test @@ -185,7 +185,7 @@ while(arg) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop12,0,(-(Phi_a+3)));", stop.toString()); + assertEquals("return Phi(Loop,0,(-(Phi_a+3)));", stop.toString()); } @Test @@ -283,7 +283,7 @@ return v1+v0; public void testFuzz8() { Parser parser = new Parser("while(arg) arg = arg - 1; return arg;"); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,arg,(Phi_arg-1));", stop.toString()); + assertEquals("return 0;", stop.toString()); } @Test diff --git a/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 0b8be64b..f634e421 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -25,7 +25,7 @@ public class Chapter10Test { // Issue #246: null-check guards start in Chapter 10; arrays arrive in Chapter 15. private static final String NULLABLE_POINT_SOURCE = """ struct Point { int x; }; - Point?[] points = new Point?[2]; + !Point?[] !points = new !Point?[2]; points[arg] = new Point { x = 42; }; Point? p = points[1]; """; @@ -101,7 +101,7 @@ struct Foo { int x; }; Foo? foo = null; -Bar bar = new Bar; +!Bar !bar = new Bar; bar.a = 1; bar.a = 2; return bar.a; @@ -114,7 +114,7 @@ return bar.a; public void testExample() { Parser parser = new Parser(""" struct Vector2D { int x; int y; }; -Vector2D v = new Vector2D; +!Vector2D !v = new Vector2D; v.x = 1; if (arg) v.y = 2; @@ -153,7 +153,7 @@ arg=0+new s0.0; public void testLoop() { Parser parser = new Parser(""" struct Bar { int a; }; -Bar bar = new Bar; +!Bar !bar = new Bar; while (arg) { bar.a = bar.a + 2; arg = arg + 1; @@ -161,14 +161,14 @@ while (arg) { return bar.a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop17,0,(Phi_a+2));", stop.toString()); + assertEquals("return Phi(Loop,0,(Phi_a+2));", stop.toString()); } @Test public void testIf() { Parser parser = new Parser(""" struct Bar { int a; }; -Bar bar = new Bar; +!Bar !bar = new Bar; if (arg) bar = null; bar.a = 1; return bar.a; @@ -181,7 +181,7 @@ return bar.a; public void testIf2() { Parser parser = new Parser(""" struct Bar { int a; }; -Bar? bar = null; +!Bar? !bar = null; if (arg) bar = new Bar; bar.a = 1; return bar.a; @@ -207,13 +207,13 @@ return bar.a; public void testIfOrNull() { Parser parser = new Parser(""" struct Bar { int a; }; -Bar? bar = new Bar; +!Bar? !bar = new Bar; if (arg) bar = null; if( bar ) bar.a = 1; return bar; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region38,(*void)Phi(Region24,null,Bar),null);", stop.toString()); + assertEquals("return Phi(Region,(*void)Phi(Region,null,Bar),null);", stop.toString()); } @Test @@ -221,7 +221,7 @@ return bar; Parser parser = new Parser( """ struct Bar { int a; }; -Bar? bar = new Bar; +!Bar? !bar = new Bar; if (arg) bar = null; int rez = 3; if( !bar ) rez=4; @@ -229,14 +229,14 @@ else bar.a = 1; return rez; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region44,4,3);", stop.toString()); + assertEquals("return Phi(Region,4,3);", stop.toString()); } @Test public void testWhileWithNullInside() { Parser parser = new Parser(""" struct s0 {int v0;}; -s0? v0 = new s0; +!s0? !v0 = new s0; int ret = 0; while(arg) { ret = v0.v0; @@ -257,7 +257,7 @@ struct s0 { int v0; }; s0? v1=new s0; -s0? v1; +!s0? !v1; v1=new s0; """); try { parser.parse(); fail(); } @@ -273,7 +273,7 @@ struct Iter { int x; int len; }; -Iter i = new Iter; +!Iter !i = new Iter; i.len = arg; int sum=0; while( i.x < i.len ) { @@ -283,7 +283,7 @@ while( i.x < i.len ) { return sum; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop22,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", stop.toString()); + assertEquals("return Phi(Loop,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", stop.toString()); } @@ -291,9 +291,9 @@ return sum; public void test1() { Parser parser = new Parser(""" struct s0 {int v0;}; -s0 ret = new s0; +!s0 !ret = new s0; while(arg) { - s0 v0 = new s0; + !s0 !v0 = new s0; v0.v0 = arg; arg = arg-1; if (arg==5) ret=v0; @@ -302,15 +302,15 @@ while(arg) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop17,s0,Phi(Region44,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", stop.toString()); } @Test public void test2() { Parser parser = new Parser(""" struct s0 {int v0;}; -s0 ret = new s0; -s0 v0 = new s0; +!s0 !ret = new s0; +!s0 !v0 = new s0; while(arg) { v0.v0 = arg; arg = arg-1; @@ -320,7 +320,7 @@ while(arg) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop23,s0,Phi(Region45,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", stop.toString()); } @@ -328,16 +328,16 @@ return ret; public void test3() { Parser parser = new Parser(""" struct s0 {int v0;}; -s0 ret = new s0; +!s0 !ret = new s0; while(arg < 10) { - s0 v0 = new s0; + !s0 !v0 = new s0; if (arg == 5) ret=v0; arg = arg + 1; } return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop17,s0,Phi(Region41,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", stop.toString()); } @Test @@ -407,7 +407,7 @@ s0 v1 = v0; return v1; """); StopNode stop = parser.parse().iterate(); - assertEquals("return s0;", stop.toString()); + assertEquals("return (const)s0;", stop.toString()); } @@ -456,9 +456,9 @@ return 0; @Test public void testReadBeforeStores() { var stop = new Parser(""" struct S { int x; int y; }; - S a = new S; S b = new S; + !S !a = new S; !S !b = new S; a.x = 11; b.x = 22; - S p = a; if (arg) p = b; + !S !p = a; if (arg) p = b; int before = p.x; a.y = 55; b.y = 66; a.x = 33; b.x = 44; @@ -470,7 +470,7 @@ return 0; static final String NESTED_MEMORY = """ struct S { int x; int y; int z; }; - S s = new S; + !S !s = new S; s.x = 5; s.y = 7; s.z = 11; while (arg > 0) { s.x = s.x + 1; @@ -501,7 +501,7 @@ return 0; @Test public void testMemoryAtEarlyReturns() { var stop = new Parser(""" struct S { int x; int y; int z; }; - S s = new S; + !S !s = new S; s.x = 3; s.y = 5; s.z = 7; if (arg) { s.x = 11; s.z = 13; return s; } s.y = 17; @@ -517,9 +517,9 @@ return 0; @Test public void testKeepLoadsAtMerge() { StopNode stop = new Parser(""" struct S { int x; }; - S a = new S; S b = new S; + !S !a = new S; !S !b = new S; a.x = arg; b.x = arg+1; - S p = a; S q = b; + !S !p = a; !S !q = b; if (arg<0) { p=b; q=a; } int v; if (arg>1) v=p.x; else v=q.x; @@ -535,7 +535,7 @@ return 0; @Test public void testDropStores() { StopNode stop = new Parser(""" struct S { int x; }; - S s = new S; + !S !s = new S; if (arg) s.x=arg+1; else s.x=arg+2; return s; """).parse().iterate(); @@ -547,9 +547,9 @@ return 0; @Test public void testKeepReadsBeforeWrites() { StopNode stop = new Parser(""" struct S { int x; int y; }; - S a = new S; S b = new S; + !S !a = new S; !S !b = new S; a.x=arg; b.x=arg+1; - S p=a; S q=b; + !S !p=a; !S !q=b; if (arg<0) { p=b; q=a; } int v; if (arg>1) { v=p.x; p.x=41; p.y=5; } diff --git a/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/src/test/java/com/seaofnodes/simple/Chapter11Test.java index e009c6b6..60ff05d8 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter11Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter11Test.java @@ -9,7 +9,7 @@ public class Chapter11Test { @Test public void testIndependentField() { var stop = new Parser(""" struct S { int x; int y; }; - S s = new S; + !S !s = new S; s.x = 42; while (arg > 0) { s.y = s.y + arg; arg = arg - 1; } return s.x; @@ -22,8 +22,8 @@ public class Chapter11Test { @Test public void testParallelMemoryPhis() { var stop = new Parser(""" struct S { int x; int y; int z; }; - S a = new S; S b = new S; - S p = a; if (arg) p = b; + !S !a = new S; !S !b = new S; + !S !p = a; if (arg) p = b; while (arg > 0) { a.x = p.x + arg; a.y = p.y + 2; diff --git a/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 4e34028b5..628f6211 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -24,10 +24,10 @@ return 3.14; public void testLinkedList0() { Parser parser = new Parser( """ -struct LLI { LLI? next; int i; }; -LLI? head = null; +struct LLI { !LLI? !next; int i; }; +!LLI? !head = null; while( arg ) { - LLI x = new LLI; + !LLI !x = new LLI; x.next = head; x.i = arg; head = x; @@ -43,10 +43,10 @@ return head.next.i; public void testLinkedList1() { Parser parser = new Parser( """ -struct LLI { LLI? next; int i; }; -LLI? head = null; +struct LLI { !LLI? !next; int i; }; +!LLI? !head = null; while( arg ) { - LLI x = new LLI; + !LLI !x = new LLI; x.next = head; x.i = arg; head = x; @@ -66,11 +66,11 @@ return next.i; public void testCoRecur() { Parser parser = new Parser( """ -struct int0 { int i; flt0? f; }; -struct flt0 { flt f; int0? i; }; -int0 i0 = new int0; +struct int0 { int i; !flt0? !f; }; +struct flt0 { flt f; !int0? !i; }; +!int0 !i0 = new int0; i0.i = 17; -flt0 f0 = new flt0; +!flt0 !f0 = new flt0; f0.f = 3.14; i0.f = f0; f0.i = i0; @@ -84,7 +84,7 @@ return f0.i.f.i.i; public void testNullRef0() { Parser parser = new Parser( """ -struct N { N? next; int i; }; +struct N { !N? !next; int i; }; N n = new N; return n.next; """); @@ -97,12 +97,12 @@ return n.next; Parser parser = new Parser( """ struct M { int m; }; -struct N { M next; int i; }; +struct N { !M !next; int i; }; N n = new N { next = new M; }; return n.next; """); StopNode stop = parser.parse().iterate(); - assertEquals("return M;", stop.toString()); + assertEquals("return (const)M;", stop.toString()); } @Test @@ -110,7 +110,7 @@ return n.next; Parser parser = new Parser( """ struct M { int m; }; -struct N { M next; int i; }; +struct N { !M !next; int i; }; N n = new N { next = null; } return n.next; """); @@ -122,8 +122,8 @@ return n.next; public void testNullRef3() { Parser parser = new Parser( """ -struct N { N? next; int i; }; -N n = new N; +struct N { !N? !next; int i; }; +!N !n = new N; n.i = 3.14; return n.i; """); @@ -132,9 +132,9 @@ return n.i; @Test public void testNullRef4() { - Parser parser = new Parser("-null-5/null-5"); + Parser parser = new Parser("-null-5/null-5;"); try { parser.parse().iterate(); fail(); } - catch( Exception e ) { assertEquals("Expected an identifier, found 'null'",e.getMessage()); } + catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); } } @Test public void testNullRef5() { @@ -158,7 +158,7 @@ struct S{}; public void testForwardRef0() { Parser parser = new Parser( """ -struct S1 { S2 s; }; +struct S1 { !S2? !s; }; return new S2; """); try { parser.parse().iterate(); fail(); } @@ -169,7 +169,7 @@ return new S2; public void testForwardRef1() { Parser parser = new Parser( """ -struct S1 { S2? s; }; +struct S1 { !S2? !s; }; struct S2 { int x; }; return new S1.s=new S2; """); @@ -182,9 +182,9 @@ return new S1.s=new S2; Parser parser = new Parser( """ struct I {int i;}; -struct P { I? pi; }; -P p1 = new P; -P p2 = new P; +struct P { !I? !pi; }; +!P !p1 = new P; +!P !p2 = new P; p2.pi = new I; p2.pi.i = 2; if (arg) p1 = new P; diff --git a/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/src/test/java/com/seaofnodes/simple/Chapter13Test.java index c749aba6..695777e2 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter13Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter13Test.java @@ -15,7 +15,7 @@ public class Chapter13Test { public void testFuzzer() { Parser parser = new Parser( """ -while(-----arg) { +while(---- -arg) { while(-arg) { while(-----arg*---0) { int N=--false==false<--arg; @@ -104,7 +104,7 @@ while(-----arg) { int UX=arg; while(UX<-3*arg) { UX=UX+arg/-1; - arg=-3--(-UX--47<arg==--arg==arg)/arg--UX>=-arg; + arg=-3--(-UX- -47<arg==--arg==arg)/arg- -UX>=-arg; if(---12) while(-UX) break; break; } @@ -225,9 +225,9 @@ if(arg!=62==arg) { } } arg=-arg+arg; - arg=--47+-arg<1>arg*(-arg==-arg--0>3); + arg=--47+-arg<1>arg*(-arg==-arg- -0>3); arg=(----arg)!=arg+--59; - arg=--4+arg==-(arg)-arg; + arg=- -4+arg==-(arg)-arg; } else { while(--true-----true*-25+-18>arg>=-----(-arg)---13) { @@ -325,7 +325,7 @@ while( prime <= arg ) { return primeCount; """); StopNode stop = parser.parse().iterate(); - assertEquals("Stop[ return 0; return Phi(Loop21,1,Phi(Region88,Phi_primeCount,Phi(Region82,(Phi_primeCount+1),Phi_primeCount))); ]", stop.toString()); + assertEquals("Stop[ return 0; return Phi(Loop,1,Phi(Region,Phi_primeCount,Phi(Region,(Phi_primeCount+1),Phi_primeCount))); ]", stop.toString()); assertEquals(0L, Evaluator.evaluate(stop, 1)); // No primes 1 or below assertEquals(1L, Evaluator.evaluate(stop, 2)); // 2 assertEquals(2L, Evaluator.evaluate(stop, 3)); // 2, 3 @@ -339,7 +339,7 @@ return primeCount; Parser parser = new Parser( """ struct S { int f; }; -S v=new S; +!S !v=new S; v.f = 2; int i=new S.f; i=v.f; @@ -357,9 +357,9 @@ return i; Parser parser = new Parser( """ struct S { int f; }; -S v = new S; +!S !v = new S; v.f = arg; -S t = new S; +!S !t = new S; int i = 0; if (arg) { if (arg+1) v = t; @@ -370,7 +370,7 @@ if (arg) { return i; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region48,.f,0);", stop.toString()); + assertEquals("return Phi(Region,.f,0);", stop.toString()); } @Test @@ -378,8 +378,8 @@ return i; Parser parser = new Parser( """ struct S { int f; }; -S v0 = new S; -S? v1; +!S !v0 = new S; +!S? !v1; if (arg) v1 = new S; if (v1) { v0.f = v1.f; @@ -398,7 +398,7 @@ return v0; Parser parser = new Parser( """ struct S { int f; }; -S v = new S; +!S !v = new S; v.f = arg; S t = new S; int i = v.f; @@ -415,7 +415,7 @@ return i; Parser parser = new Parser( """ struct S { int f; }; -S v = new S; +!S !v = new S; while(1) { while(arg+1) { arg=arg-1; } if (arg) break; @@ -432,14 +432,14 @@ return v; Parser parser = new Parser( """ struct s { int v; }; -s ptr=new s; +!s !ptr=new s; while( -arg ) ptr = new s; while(1) arg = arg+ptr.v; """); StopNode stop = parser.parse().iterate(); - assertEquals("Stop[ return 0; return 0; ]", stop.toString()); + assertEquals("return 0;", stop.toString()); } @Test @@ -447,7 +447,7 @@ while(1) Parser parser = new Parser( """ struct S { int f; }; -S v = new S; +!S !v = new S; S t = new S; int i = v.f; while (arg) { @@ -465,7 +465,7 @@ return i; Parser parser = new Parser( """ struct S { int f; }; -S v = new S; +!S !v = new S; S t = new S; while(arg) { arg=arg-1; @@ -477,7 +477,7 @@ while(arg) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop23,arg,Phi(Region50,.f,0));", stop.toString()); + assertEquals("return 0;", stop.toString()); } @Test @@ -485,7 +485,7 @@ return arg; Parser parser = new Parser( """ struct S { int f; }; -S v = new S; +!S !v = new S; S t = new S; if (arg) { v.f=2; @@ -503,7 +503,7 @@ return v; Parser parser = new Parser( """ struct S { int f; }; -S v = new S; +!S !v = new S; int i = arg; while (arg > 0) { int j = i/3; diff --git a/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java b/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java index c42b0154..3d92c9cf 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java +++ b/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java @@ -84,7 +84,7 @@ while( 1 ) { return guess; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0));", stop.toString()); + assertEquals("return Phi(Loop,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0));", stop.toString()); assertEquals(3.0, Evaluator.evaluate(stop, 9)); assertEquals(1.414213562373095, Evaluator.evaluate(stop, 2)); } diff --git a/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/src/test/java/com/seaofnodes/simple/Chapter14Test.java index be9b1fd4..27804a5a 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter14Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter14Test.java @@ -61,7 +61,7 @@ while( b ) b = b + 456;// Truncate return b; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,123,((Phi_b+456)&255));", stop.toString()); + assertEquals("return 0;", stop.toString()); } @Test @@ -96,7 +96,7 @@ return b; Parser parser = new Parser( """ struct Foo { u1 b; }; -Foo f = new Foo; +!Foo !f = new Foo; f.b = 123; return f.b; """); @@ -177,7 +177,7 @@ while(v1) break; return v1; """); StopNode stop = parser.parse().iterate(); - assertEquals("return (Phi(Loop17,((1<<arg)&1),0)&Phi(Loop,Shl,4294967295));", stop.toString()); + assertEquals("return Phi(Loop,(((1<<arg)&1)&Shl),0);", stop.toString()); assertEquals(1L, Evaluator.evaluate(stop, 0)); } diff --git a/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/src/test/java/com/seaofnodes/simple/Chapter15Test.java index 63bdcce7..452a1051 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter15Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter15Test.java @@ -25,8 +25,8 @@ return 3.14; public void testCyclic() { Parser parser = new Parser( """ -struct C { C? l; }; -C c = new C; +struct C { !C? !l; }; +!C !c = new C; c.l = c; return c; """); @@ -40,7 +40,7 @@ return c; Parser parser = new Parser( """ u8[] old = new u8[0]; -u8[] output = new u8[1]; +u8[] !output = new u8[1]; int i = 0; while (i < old#) { output[i] = old[i]; @@ -83,7 +83,7 @@ return is[1]; public void testBasic3() { Parser parser = new Parser( """ -int[] a = new int[2]; +int[] !a = new int[2]; a[0] = 1; a[1] = 2; return a[0]; @@ -98,7 +98,7 @@ return a[0]; Parser parser = new Parser( """ struct A { int i; }; -A?[] a = new A?[2]; +!A?[] !a = new !A?[2]; return a; """); StopNode stop = parser.parse().iterate(); @@ -112,16 +112,16 @@ return a; """ struct S { int x; flt y; }; // A new S -S s = new S; s.x=99; s.y = 3.14; +!S !s = new S; s.x=99; s.y = 3.14; // Double-d array of Ss. Fill in one row. -S?[]?[] iss = new S?[]?[2]; -iss[0] = new S?[7]; +!S?[]?[] !iss = new !S?[]?[2]; +iss[0] = new !S?[7]; iss[0][2] = s; // Now pull out the filled-in value, with null checks flt rez; -S?[]? is = iss[arg]; +!S?[]? is = iss[arg]; if( !is ) rez = 1.2; else { S? i = is[2]; @@ -131,24 +131,22 @@ else { return rez; """); StopNode stop = parser.parse().iterate(); - // Shared allocation memory prevents folding the field Store into New. - assertEquals("return Phi(Region121,1.2,Phi(Region118,2.3,.y));", stop.toString()); + assertEquals("return Phi(Region,1.2,Phi(Region,2.3,.y));", stop.toString()); assertEquals(3.14, Evaluator.evaluate(stop, 0)); assertEquals(1.2 , Evaluator.evaluate(stop, 1)); } - @Ignore @Test public void testBasic6() { Parser parser = new Parser( """ struct S { int x; flt y; }; // A new S -S s = new S; s.x=99; s.y = 3.14; +!S !s = new S; s.x=99; s.y = 3.14; // Double-d array of Ss. Fill in one row. -S?[]?[] iss = new S?[]?[2]; -iss[0] = new S?[7]; +!S?[]?[] iss = new !S?[]?[2]; +iss[0] = new !S?[7]; iss[0][2] = s; // Now pull out the filled-in value, with null checks @@ -158,9 +156,8 @@ if( iss[arg] ) rez = iss[arg][2].y; return rez; """); - StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region122,Phi(Region118,.y,1.2),1.2);", stop.toString()); - assertEquals(3.14, Evaluator.evaluate(stop, 0)); + try { parser.parse().iterate(); fail(); } + catch( Exception e ) { assertEquals("Might be null accessing '[]'",e.getMessage()); } } @Test @@ -168,9 +165,9 @@ return rez; Parser parser = new Parser( """ // Can we define a forward-reference array? -struct Tree { Tree?[]? _kids; }; -Tree root = new Tree; -root._kids = new Tree?[2]; +struct Tree { !Tree?[]? !_kids; }; +!Tree !root = new Tree; +root._kids = new !Tree?[2]; // NO BANG SO ARRAY IS OF IMMUTABLE TREES???? root._kids[0] = new Tree; return root; """); @@ -183,7 +180,7 @@ return root; public void testNestedStructAddMemProj() { Parser parser = new Parser( """ -struct S { int a; int[] b; }; +struct S { int a; int[] !b; }; return 0; """); StopNode stop = parser.parse(); @@ -194,7 +191,7 @@ return 0; public void testRollingSum() { Parser parser = new Parser( """ -int[] ary = new int[arg]; +int[] !ary = new int[arg]; // Fill [0,1,2,3,4,...] int i=0; while( i < ary# ) { @@ -218,44 +215,42 @@ return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 public void sieveOEratosthenes() { Parser parser = new Parser( """ -int[] ary = new int[arg]; -int[] primes = new int[arg]; -int nprimes = 0; -// Find primes -int j=2; -while( j*j < arg ) { - while( ary[j]==1 ) j = j + 1; - // j is now a prime - primes[nprimes] = j; nprimes = nprimes + 1; +int[] !ary = new int[arg], !primes = new int[arg]; +int nprimes = 0, p=2; +// Find primes while p^2 < arg +while( p*p < arg ) { + // skip marked non-primes + while( ary[p]==1 ) p = p + 1; + // p is now a prime + primes[nprimes] = p; nprimes = nprimes + 1; // Mark out the rest non-primes - int i = j + j; + int i = p + p; while( i < ary# ) { ary[i] = 1; - i = i + j; + i = i + p; } - j = j + 1; + p = p + 1; } -// Now just collect the remaining primes -while( j < arg ) { - if( ary[j] == 0 ) { - primes[nprimes] = j; nprimes = nprimes + 1; +// Now just collect the remaining primes, no more marking +while( p < arg ) { + if( ary[p] == 0 ) { + primes[nprimes] = p; nprimes = nprimes + 1; } - j = j + 1; + p = p + 1; } -// Shrink the result array to size -int[] rez = new int[nprimes]; -j = 0; +// Copy/shrink the result array +int[] !rez = new int[nprimes]; +int j = 0; while( j < nprimes ) { rez[j] = primes[j]; j = j + 1; } - return rez; """); StopNode stop = parser.parse().iterate(); assertEquals("return [int];", stop.toString()); Evaluator.Obj obj = (Evaluator.Obj)Evaluator.evaluate(stop, 20); - assertEquals("[int] { # :int; [] :int; }",obj.struct().toString()); + assertEquals("[int] {int #; int ![]; }",obj.struct().toString()); long nprimes = (Long)obj.fields()[0]; long[] primes = new long[]{2,3,5,7,11,13,17,19}; for( int i=0; i<nprimes; i++ ) @@ -267,8 +262,8 @@ return rez; Parser parser = new Parser( """ struct S {int i; flt f;}; -S s1 = new S; -S s2 = new S; +!S !s1 = new S; +!S !s2 = new S; s2.i = 3; s2.f = 2.0; if (arg) s1 = new S; diff --git a/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/src/test/java/com/seaofnodes/simple/Chapter16Test.java index 3d3708dc..996be2a1 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter16Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter16Test.java @@ -9,15 +9,6 @@ import static org.junit.Assert.fail; public class Chapter16Test { - @Test - public void testRequiredReference() { - for( String fields : new String[] { "int[] x;" } ) { - String src = "struct Point { "+fields+" }; Point p = new Point; p.x=p.x+1; return p;"; - try { new Parser(src).parse().iterate(); fail(fields); } - catch( Exception e ) { assertEquals("'Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); } - } - } - @Ignore @Test public void testJig() { @@ -55,9 +46,6 @@ return x+y; } - - - @Test public void testConstruct0() { Parser parser = new Parser(""" @@ -70,8 +58,6 @@ return z.x; assertEquals(3L, Evaluator.evaluate(stop, 0)); } - - @Test public void testConstruct2() { Parser parser = new Parser(""" @@ -85,16 +71,12 @@ return z.x; } - - - // Same as the Chapter13 test with the same name, but using the new - // constructor syntax @Test public void testLinkedList1() { Parser parser = new Parser( """ -struct LLI { LLI? next; int i; }; -LLI? head = null; +struct LLI { !LLI? !next; int i; }; +!LLI? !head = null; while( arg ) { head = new LLI { next=head; i=arg; }; arg = arg-1; @@ -115,13 +97,13 @@ return next.i; public void testLinkedList2() { Parser parser = new Parser( """ -struct LLI { LLI? next; int i; }; -LLI? head = null; +struct LLI { !LLI? !next; int i; }; +!LLI? !head = null; while( arg ) { head = new LLI { next=head; // Any old code in the constructor - int tmp=arg; + int !tmp=arg; while( arg > 10 ) { tmp = tmp + arg; arg = arg - 1; @@ -147,11 +129,11 @@ return next.i; Parser parser = new Parser( """ struct Square { - flt side = arg; + flt !side = arg; // Newtons approximation to the square root, computed in a constructor. // The actual allocation will copy in this result as the initial // value for 'diag'. - flt diag = arg*arg/2; + flt !diag = arg*arg/2; while( 1 ) { flt next = (side/diag + diag)/2; if( next == diag ) break; @@ -168,13 +150,13 @@ return new Square; static final String CONSTRUCTOR_MEMORY = """ struct S { int x; int y; }; struct T { int z=arg+40; }; - T t = new T; - S a = new S { x=11; y=7; }; - S b = new S { x=22; y=9; }; - S p=a; + !T !t = new T; + !S !a = new S { x=11; y=7; }; + !S !b = new S { x=22; y=9; }; + !S !p=a; if (arg) p=b; int before=p.x; - S c = new S { + !S !c = new S { x=p.x+1; { int i=0; while (i<2) { p.y=p.y+1; i=i+1; } } y=p.y; diff --git a/src/test/java/com/seaofnodes/simple/Chapter17aTest.java b/src/test/java/com/seaofnodes/simple/Chapter17aTest.java new file mode 100644 index 00000000..7d61a913 --- /dev/null +++ b/src/test/java/com/seaofnodes/simple/Chapter17aTest.java @@ -0,0 +1,107 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.evaluator.Evaluator; +import com.seaofnodes.simple.node.StopNode; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class Chapter17aTest { + + @Test + public void testFinal1() { + Parser parser = new Parser( +""" +int x=2, y=3; +if( arg ) { int x = y; x = x*x; y=x; } // Shadow final x +return y; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("return Phi(Region,9,3);", stop.toString()); + assertEquals(3L, Evaluator.evaluate(stop, 0)); + assertEquals(9L, Evaluator.evaluate(stop, 1)); + } + + @Test + public void testConstruct1() { + Parser parser = new Parser(""" +struct X { int ~x; }; +X z = new X { x=3; }; +return z.x; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("return 3;", stop.toString()); + assertEquals(3L, Evaluator.evaluate(stop, 0)); + } + + @Test + public void testStructFinal0() { + Parser parser = new Parser(""" +struct Point { int ~x, ~y; }; +Point p = new Point { x=3; y=4; }; +return p; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("return (const)Point;", stop.toString()); + assertEquals("Obj<Point>{x=3,y=4}", Evaluator.evaluate(stop, 0).toString()); + } + + @Test + public void testStructFinal1() { + Parser parser = new Parser(""" +struct Point { int x=3, y=4; }; +Point p = new Point { x=5; y=6; }; +p.x=p.x+1; +return p; +"""); + try { parser.parse().iterate(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test + public void testStructFinal2() { + Parser parser = new Parser(""" +struct Point { int x=3, y=4; }; +Point p = new Point; +p.x=p.x+1; +return p; +"""); + try { parser.parse().iterate(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test + public void testStructFinal3() { + for( String fields : new String[] { "int ~x; int ~y;", "int[] !x;", "int[] !x;" } ) { + String src = "struct Point { "+fields+" }; Point p = new Point; p.x=p.x+1; return p;"; + try { new Parser(src).parse().iterate(); fail(fields); } + catch( Exception e ) { assertEquals("'Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); } + } + } + + @Test + public void testStructFinal4() { + Parser parser = new Parser(""" +struct Point { int ~x=3; int ~y=4; }; +Point p = new Point; +p.x=p.x+1; +return p; +"""); + try { parser.parse().iterate(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test + public void testStructFinal5() { + Parser parser = new Parser(""" +struct Point { int x=3; int y=4; }; +!Point !p = new Point; +p.x=p.x+1; +return p; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("return Point;", stop.toString()); + assertEquals("Obj<Point>{x=4,y=4}", Evaluator.evaluate(stop, 0).toString()); + } + +} diff --git a/src/test/java/com/seaofnodes/simple/MutabilityTest.java b/src/test/java/com/seaofnodes/simple/MutabilityTest.java new file mode 100644 index 00000000..3442c54a --- /dev/null +++ b/src/test/java/com/seaofnodes/simple/MutabilityTest.java @@ -0,0 +1,57 @@ +package com.seaofnodes.simple; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class MutabilityTest { + private static void ok(String src, String result) { + var stop = new Parser(src).parse().iterate(); + assertEquals(result,com.seaofnodes.simple.evaluator.Evaluator.evaluate(stop,0).toString()); + } + private static void bad(String src) { + try { + new Parser(src).parse().iterate(); + } catch( RuntimeException expected ) { + String msg = expected.getMessage(); + assertTrue("Expected a permission error, got: "+expected, + msg!=null && (msg.contains("final") || msg.contains("not of declared type") || msg.contains("Cannot store"))); + return; + } + fail("Accepted forbidden write: "+src); + } + + @Test public void testIndependentBindingsAndViews() { + ok("struct P { int x; }; !P ~p=new P; p.x=7; return p.x;", "7"); + ok("struct P { int x; }; ~P !p=new P{x=3;}; p=new P{x=7;}; return p.x;", "7"); + bad("struct P { int x; }; !P ~p=new P; p=new P; return 0;"); + bad("struct P { int x; }; ~P !p=new P; p.x=7; return 0;"); + bad("int ~x=3; x=7; return x;"); + ok("int !x=3; x=7; return x;", "7"); + } + + @Test public void testDeepViewAndAliases() { + ok("struct P { int x; }; !P ~p=new P; ~P ~r=p; p.x=7; return r.x;", "7"); + bad("struct P { int x; }; struct Box { !P p; }; !P q=new P; Box b=new Box{p=q;}; b.p.x=7; return 0;"); + bad("struct P { int x; }; P p=new P; !P q=p; q.x=7; return 0;"); + bad("struct P { P? next; int x; }; !P p=new P{next=new P;}; p.next.x=7; return 0;"); + bad("struct P { !P? next; int x; }; P p=new P{next=new P;}; p.next.x=7; return 0;"); + } + + @Test public void testConstructorScope() { + ok("struct P { int ~x; }; P p=new P{if(arg) x=3; else x=7;}; return p.x;", "7"); + bad("int ~outer=1; struct P { int x; }; P p=new P{outer=7;}; return outer;"); + bad("struct P { int x; }; P p=new P{int ~local=1; local=7;}; return p.x;"); + } + + @Test public void testArrayLayers() { + bad("struct P { int x; }; !P?[] rw=new !P?[1]; P?[] ro=rw; rw[0]=new P; ro[0].x=7; return 0;"); + ok("u8[] a=new u8[2]; a[0]=7; return a[0];", "7"); + ok("struct P { int x; }; P?[] a=new P?[1]; a[0]=new P{x=7;}; return a[0].x;", "7"); + bad("struct P { int x; }; P?[] a=new P?[1]; a[0]=new P; a[0].x=7; return 0;"); + ok("struct P { int x; }; !P?[] a=new !P?[1]; a[0]=new P; a[0].x=7; return a[0].x;", "7"); + bad("u8[~] a=new u8[1]; a[0]=7; return 0;"); + ok("u8[~]?[] rows=new u8[~]?[1]; rows[0]=new u8[1]; return rows#;", "1"); + bad("u8[~]?[] rows=new u8[~]?[1]; rows[0]=new u8[1]; rows[0][0]=7; return 0;"); + bad("u8[]?[~] rows=new u8[]?[1]; rows[0]=new u8[1]; return 0;"); + } +} diff --git a/src/test/java/com/seaofnodes/simple/SchedulerTest.java b/src/test/java/com/seaofnodes/simple/SchedulerTest.java index 4b692f51..d8a22fd3 100644 --- a/src/test/java/com/seaofnodes/simple/SchedulerTest.java +++ b/src/test/java/com/seaofnodes/simple/SchedulerTest.java @@ -24,7 +24,7 @@ public class SchedulerTest { struct S { int f; } -S v=new S; +!S !v=new S; v.f = 2; int i=v.f; if (arg) v.f=1; @@ -41,7 +41,7 @@ return i; struct S { int f; }; -S v0=new S; +!S !v0=new S; if(arg) v0.f=1; return v0; """); @@ -57,7 +57,7 @@ return v0; struct S { int f; }; -S v=new S; +!S !v=new S; v.f = 2; int i=new S.f; i=v.f; diff --git a/src/test/java/com/seaofnodes/simple/TypeTest.java b/src/test/java/com/seaofnodes/simple/TypeTest.java index 6f7409cd..3fac1641 100644 --- a/src/test/java/com/seaofnodes/simple/TypeTest.java +++ b/src/test/java/com/seaofnodes/simple/TypeTest.java @@ -20,7 +20,7 @@ public class TypeTest { Field.make("b", TypeInteger.BOT,-4, false) }); Assert.assertEquals(s1, s1.glb()); Assert.assertNotEquals(s1, s1.dual()); - Assert.assertEquals(s1, s1.dual().glb()); + Assert.assertEquals(s1.makeRO(), s1.dual().glb()); TypeMem m1 = TypeMem.make(1,TypeInteger.ZERO); TypeMem m2 = TypeMem.make(2,TypeInteger.U16); @@ -54,12 +54,12 @@ public class TypeTest { Assert.assertNotEquals(ptr1, ptr2); Assert.assertNotEquals(ptr1, ptr1.glb()); - Assert.assertEquals(ptr1nil, ptr1.glb()); + Assert.assertEquals(ptr1nil.withAccess(true), ptr1.glb()); Assert.assertEquals(ptr1, ptr1.dual().dual()); - Assert.assertEquals(ptr1.glb(), ptr1.dual().glb()); - Assert.assertEquals(TypeMemPtr.make(TypeStruct.BOT,true), ptr1.meet(ptr2nil)); - Assert.assertEquals(ptr1.glb(), ptr1.meet(TypeMemPtr.NULLPTR)); + Assert.assertEquals(ptr1.glb().makeFrom(s1.dual().glb()), ptr1.dual().glb()); + Assert.assertEquals(TypeMemPtr.make(TypeStruct.BOT,true).withAccess(false), ptr1.meet(ptr2nil)); + Assert.assertEquals(ptr1nil, ptr1.meet(TypeMemPtr.NULLPTR)); TypeMemPtr TOP = TypeMemPtr.TOP; TypeMemPtr BOT = TypeMemPtr.make(TypeStruct.BOT,true ); @@ -68,7 +68,7 @@ public class TypeTest { 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); + Assert.assertEquals(PTR.withAccess(false), ptr1_meet_ptr2); Type NULL_join_ptr1 = NULL.join(ptr1); Assert.assertEquals(TOP, NULL_join_ptr1); Type NULL_join_PTR = PTR.join(NULL); @@ -79,7 +79,7 @@ public class TypeTest { // Test theoretical properties. // This is a symmetric complete bounded (ranked) lattice. - // Also the meet is commutative and associative. + // Also, the meet is commutative and associative. // The lattice has a dual (symmetric), and join is ~(~x meet ~y). // See https://en.wikipedia.org/wiki/Lattice_(order). @Test diff --git a/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java index 8b530307..0721402f 100644 --- a/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java +++ b/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java @@ -36,7 +36,7 @@ public class Evaluator { sb.append("obj@").append(cid); return id; } - if (struct._name.equals("u8[]")) { + if (struct._name.equals("[u8]")) { sb.append('"'); for (int i=struct._fields.length-1; i<fields.length; i++) { var v = fields[i]; @@ -306,6 +306,7 @@ public class Evaluator { case NewNode alloc -> alloc(alloc); case CProjNode cproj -> ((Object[])val(cproj.ctrl()))[cproj._idx]; case ProjNode proj -> ((Object[])val( proj.in(0) ))[ proj._idx]; + case ReadOnlyNode ro -> val(ro.in(1)); default -> throw new AssertionError("Unexpected node " + node); }; } diff --git a/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java b/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java index d3cbb0ee..183dcb84 100644 --- a/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java +++ b/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java @@ -479,7 +479,7 @@ public class ScriptGenerator { for (int i=0; i<fields.length; i++) { var fieldName = getRandomName(); var type = getType(true); - printIndentation().append(type.name).append(" ").append(fieldName).append(";\n"); + printIndentation().append(declType(type)).append(" !").append(fieldName).append(";\n"); fields[i] = new TypeStruct.Field(fieldName.toString(), type, struct); } indentation -= INDENTATION; @@ -676,14 +676,16 @@ public class ScriptGenerator { return 0; } - /** - * Generate a declaration statement. - * @return 0 - */ + // This generator mutates references and fields; request both permissions. + private static String declType(Type type) { + return (type instanceof TypeStruct || type instanceof TypeNullable ? "!" : "") + type.name; + } + + /** Generate a declaration statement. */ public int genDecl() { var type = getType(); var name = getVarName(); - sb.append(generateInvalid() ? getRandomName() : type.name).append(" ").append(name); + sb.append(generateInvalid() ? getRandomName() : declType(type)).append(" !").append(name); if (!(type instanceof TypeNullable) || random.nextBoolean()) { sb.append("="); genExpression(type, true); |
