package com.seaofnodes.simple; import com.seaofnodes.simple.evaluator.Evaluator; import com.seaofnodes.simple.node.StopNode; import com.seaofnodes.simple.type.TypeStruct; import com.seaofnodes.simple.type.TypeMemPtr; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; public class Chapter12Test { @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 testLinkedList0() { Parser parser = new Parser( """ struct LLI { LLI? next; int i; } LLI? head = null; while( arg ) { LLI x = new LLI; x.next = head; x.i = arg; head = x; arg = arg-1; } return head.next.i; """); try { parser.parse().iterate(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'i'",e.getMessage()); } } @Test public void testLinkedList1() { Parser parser = new Parser( """ struct LLI { LLI? next; int i; } LLI? head = null; while( arg ) { LLI x = new LLI; x.next = head; x.i = arg; head = x; arg = arg-1; } if( !head ) return 0; LLI? next = head.next; if( next==null ) return 1; return next.i; """); StopNode stop = parser.parse().iterate(); assertEquals("Stop[ return 0; return 1; return .i; ]", stop.toString()); assertEquals(2L, Evaluator.evaluate(stop, 3)); } @Test public void testCoRecur() { Parser parser = new Parser( """ struct int0 { int i; flt0? f; } struct flt0 { flt f; int0? i; } int0 i0 = new int0; i0.i = 17; flt0 f0 = new flt0; f0.f = 3.14; i0.f = f0; f0.i = i0; return f0.i.f.i.i; """); StopNode stop = parser.parse().iterate(); assertEquals("return 17;", stop.toString()); } @Test public void testNullRef0() { Parser parser = new Parser( """ struct N { N next; int i; } N n = new N; return n.next; """); StopNode stop = parser.parse().iterate(); assertEquals("return null;", stop.toString()); } @Test public void testNullRef1() { Parser parser = new Parser( """ struct N { N next; int i; } N n = new N; n.next = new N; return n.next; """); StopNode stop = parser.parse().iterate(); assertEquals("return new N;", stop.toString()); } @Test public void testNullRef2() { Parser parser = new Parser( """ struct N { N next; int i; } N n = new N; n.next = null; return n.next; """); try { parser.parse().iterate(); fail(); } catch( Exception e ) { assertEquals("Cannot store null into field *N next",e.getMessage()); } } @Test public void testNullRef3() { Parser parser = new Parser( """ struct N { N next; int i; } N n = new N; n.i = 3.14; return n.i; """); assertEquals("3",com.seaofnodes.simple.evaluator.Evaluator.evaluate(parser.parse().iterate(),0).toString()); } @Test public void testNullRef4() { Parser parser = new Parser("-null-5/null-5"); try { parser.parse().iterate(); fail(); } catch( Exception e ) { assertEquals("Expected an identifier, found 'null'",e.getMessage()); } } @Test public void testNullRef5() { Parser parser = new Parser("return null+42;"); try { parser.parse().iterate(); fail(); } catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); } } @Test public void testEmpty() { Parser parser = new Parser( """ struct S{}; """); StopNode stop = parser.parse().iterate(); assertEquals("return 0;", stop.toString()); assertEquals(0L, Evaluator.evaluate(stop, 0)); } @Test public void testForwardRef0() { Parser parser = new Parser( """ struct S1 { S2 s; } return new S2; """); try { parser.parse().iterate(); fail(); } catch( Exception e ) { assertEquals("Unknown struct type 'S2'",e.getMessage()); } } @Test public void testForwardRef1() { Parser parser = new Parser( """ struct S1 { S2? s; } struct S2 { int x; } return new S1.s=new S2; """); StopNode stop = parser.parse().iterate(); assertEquals("return new S1;", stop.toString()); } @Test public void testcheckNull() { Parser parser = new Parser( """ struct I {int i;} 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; return p1.pi.i + 1; """); try { parser.parse().iterate(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'i'",e.getMessage()); } } @Test public void testShallowRecursiveType() { new Parser("struct LLI { LLI? next; int i; } return 0;").parse().iterate(); TypeStruct l1 = (TypeStruct)Parser.TYPES.get("LLI"); TypeStruct l0 = ((TypeMemPtr)l1._fields[0]._type)._obj; assertEquals("LLI", l0._name); assertNull(l0._fields); assertEquals(2, l1._fields.length); assertSame(l0, l1.meet(l0)); assertSame(l0, l0.dual()); assertSame(l0, l0.glb()); } @Test public void testUnusedForwardReference() { StopNode stop = new Parser("struct Holder { Missing? ref; } Holder h = new Holder; return h.ref;") .parse().iterate(); assertEquals("return null;", stop.toString()); assertNull(((TypeStruct)Parser.TYPES.get("Missing"))._fields); } }