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 Chapter15Test { @Test public void testPartialAllocationMemory() { StopNode stop = new Parser(""" struct Other { int a; int b; int c; } struct S { int x; flt y; S? next; } Other other = new Other; other.c = 7; S a = new S; a.x = arg; a.y = 1.5; S b = new S; // S's aliases are global identities, not tuple or input positions. // Bypass b's zeroing for a, preserving the unrelated Other slice. return a.x + a.y + b.x + b.y + other.c; """).parse().iterate(); assertEquals(8.5, Evaluator.evaluate(stop,0)); assertEquals(12.5, Evaluator.evaluate(stop,4)); stop = new Parser(""" struct S { int x; flt y; S? next; } S a = new S; S b = new S; S p = a; if (arg) p = b; // The memory result carries distinct int, float and pointer facts. if (p.next != null) return 99; return p.x + p.y; """).parse().iterate(); assertEquals("return 0.0;",stop.toString()); assertEquals(0.0,Evaluator.evaluate(stop,1)); } @Test public void testReadAcrossAllocation() { StopNode stop = new Parser(""" struct S { int x; } S a = new S; S b = new S; a.x = 11; b.x = 22; S p = a; if (arg) p = b; int before = p.x; S c = new S; a.x = 33; b.x = 44; // The partial input to c must not hide the read/write ordering. // p can alias either object, so node inequality cannot bypass New. return before*100 + p.x + c.x; """).parse().iterate(); assertEquals(1133L,Evaluator.evaluate(stop,0)); assertEquals(2244L,Evaluator.evaluate(stop,1)); } @Test public void testAllocationInLoop() { StopNode stop = new Parser(""" struct S { int x; flt y; S? next; } S old = new S; old.x = 7; S last = old; while (arg > 0) { S fresh = new S; fresh.x = last.x + 1; fresh.next = last; last = fresh; arg = arg - 1; } return old.x*100 + last.x; """).parse().iterate(); assertEquals(707L,Evaluator.evaluate(stop,0)); assertEquals(712L,Evaluator.evaluate(stop,5)); } @Ignore @Test public void testJig() { Parser parser = new Parser(""" return 3.14; """); StopNode stop = parser.parse().iterate(); assertEquals("return 3.14;", stop.toString()); assertEquals(3.14, Evaluator.evaluate(stop, 0)); } @Test public void testLifetime() { Parser parser = new Parser(""" u8[] b = new u8[5]; if (arg) { b[0] = b[0] + 1; } else { b[1] = b[1] * 2; } return b[0] + b[1]; """); StopNode stop = parser.parse().iterate(); assertEquals("return Phi(Region72,1,0);", stop.toString()); assertEquals(0L, Evaluator.evaluate(stop, 0)); assertEquals(1L, Evaluator.evaluate(stop, 1)); } @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().iterate(); assertEquals("return C;", stop.toString()); assertEquals("Obj@1{l=obj@1}", Evaluator.evaluate(stop, 0).toString()); } @Test public void testSafetyCheck() { Parser parser = new Parser( """ u8[] old = new u8[0]; u8[] output = new u8[1]; int i = 0; while (i < old#) { output[i] = old[i]; i = i + 1; } output[i] = 1; return output; """); StopNode stop = parser.parse().iterate(); assertEquals("return u8[];", stop.toString()); assertEquals("\u0001", Evaluator.evaluate(stop, 0).toString()); } @Test public void testBasic1() { Parser parser = new Parser( """ int[] is = new int[2]; return is[1]; """); StopNode stop = parser.parse().iterate(); assertEquals("return 0;", stop.toString()); assertEquals(0L, Evaluator.evaluate(stop, 0)); } @Test public void testBasic2() { Parser parser = new Parser( """ int[] is = new int[2]; int[] is2 = new int[2]; return is[1]; """); StopNode stop = parser.parse().iterate(); assertEquals("return 0;", stop.toString()); assertEquals(0L, Evaluator.evaluate(stop, 0)); } @Test public void testBasic3() { Parser parser = new Parser( """ int[] a = new int[2]; a[0] = 1; a[1] = 2; return a[0]; """); StopNode stop = parser.parse().iterate(); assertEquals("return 1;", stop.toString()); assertEquals(1L, Evaluator.evaluate(stop, 0)); } @Test public void testBasic4() { Parser parser = new Parser( """ struct A { int i; } A?[] a = new A?[2]; return a; """); StopNode stop = parser.parse().iterate(); assertEquals("return *A?[];", stop.toString()); assertEquals("Obj<*A?[]>{#=2,[]=[null,null]}", Evaluator.evaluate(stop, 0).toString()); } @Test public void testBasic5() { Parser parser = new Parser( """ struct S { int x; flt y; } // A new S 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]; iss[0][2] = s; // Now pull out the filled-in value, with null checks flt rez; S?[]? is = iss[arg]; if( !is ) rez = 1.2; else { S? i = is[2]; if( !i ) rez = 2.3; else rez = i.y; } return rez; """); StopNode stop = parser.parse().iterate(); assertEquals("return Phi(Region122,1.2,Phi(Region119,2.3,.y));", stop.toString()); assertEquals(3.14, Evaluator.evaluate(stop, 0)); } @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; // Double-d array of Ss. Fill in one row. 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 = 1.2; if( iss[arg] ) if( iss[arg][2] ) 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)); } @Test public void testTree() { Parser parser = new Parser( """ // Can we define a forward-reference array? struct Tree { Tree?[] _kids; } Tree root = new Tree; root._kids = new Tree?[2]; root._kids[0] = new Tree; return root; """); StopNode stop = parser.parse().iterate(); assertEquals("return Tree;", stop.toString()); assertEquals("Obj{_kids=Obj<*Tree?[]>{#=2,[]=[Obj{_kids=null},null]}}", Evaluator.evaluate(stop, 0).toString()); } @Test public void testNestedStructAddMemProj() { Parser parser = new Parser( """ struct S { int a; int[] b; } return 0; """); StopNode stop = parser.parse(); assertEquals("return 0;", stop.toString()); } @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().iterate(); assertEquals("return (.[]+(.[]*1000));", stop.toString()); assertEquals(1006L, Evaluator.evaluate(stop, 4)); } @Test 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; // Mark out the rest non-primes int i = j + j; while( i < ary# ) { ary[i] = 1; i = i + j; } j = j + 1; } // Now just collect the remaining primes while( j < arg ) { if( ary[j] == 0 ) { primes[nprimes] = j; nprimes = nprimes + 1; } j = j + 1; } // Shrink the result array to size int[] rez = new int[nprimes]; 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[] {\n # :int;\n [] :int;\n}",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