package com.seaofnodes.simple; import com.seaofnodes.simple.codegen.CodeGen; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter16Test { @Test public void testJig() { CodeGen code = new CodeGen( """ return 3.14; """); code.parse().opto(); assertEquals("return 3.14;", code.print()); assertEquals("3.14", Eval2.eval(code, 0)); } @Test public void testMulti0() { CodeGen code = new CodeGen( """ int x, y; return x+y; """); code.parse().opto(); assertEquals("return 0;", code.print()); assertEquals("0", Eval2.eval(code, 0)); } @Test public void testMulti1() { CodeGen code = new CodeGen( """ int x=2, y=x+1; return x+y; """); code.parse().opto(); assertEquals("return 5;", code.print()); assertEquals("5", Eval2.eval(code, 0)); } // @Test // public void testFinal0() { // CodeGen code = new CodeGen( //""" //int !x=2; //x=3; //return x; //"""); // try { code.parse().opto(); fail(); } // catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); } // } @Test public void testFinal1() { CodeGen code = new CodeGen( """ int x=2, y=3; if( arg ) { int x = y; x = x*x; y=x; } // Shadow final x return y; """); code.parse().opto(); assertEquals("return Phi(Region,9,3);", code.print()); assertEquals("3", Eval2.eval(code, 0)); assertEquals("9", Eval2.eval(code, 1)); } @Test public void testConstruct0() { CodeGen code = new CodeGen(""" struct _X { int x=3; }; _X z = new _X; return z.x; """); code.parse().opto(); assertEquals("return 3;", code.print()); assertEquals("3", Eval2.eval(code, 0)); } @Test public void testConstruct1() { CodeGen code = new CodeGen(""" struct _X { int !x; new _X = { int xx -> x=xx; }; }; _X z = new _X(3); return z.x; """); code.parse().opto(); assertEquals("return 3;", code.print()); assertEquals("3", Eval2.eval(code, 0)); } @Test public void testConstruct2() { CodeGen code = new CodeGen(""" struct _X { int x=3; new _X = { int xx -> x=xx; }; }; _X z = new _X(4); return z.x; """); code.parse().opto(); assertEquals("return 4;", code.print()); assertEquals("4", Eval2.eval(code, 0)); } @Test public void testStructFinal0() { CodeGen code = new CodeGen(""" struct _Point { int !x, !y; new _Point = { int xx, int yy -> x=xx; y=yy; }; }; _Point p = new _Point(3,4); return p; """); code.parse().opto(); assertEquals("return (const)Test._Point;", code.print()); assertEquals("Test._Point{x=3,y=4}", Eval2.eval(code, 0)); } @Test public void testStructFinal1() { CodeGen code = new CodeGen(""" struct _Point { int x=3, y=4; new _Point = { int xx, int yy -> x=xx; y=yy; }; }; val p = new _Point(5,6); p.x++; return p; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } } @Test public void testStructFinal2() { CodeGen code = new CodeGen(""" struct _Point { int x=3, y=4; }; val p = new _Point; p.x++; return p; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } } @Test public void testStructFinal3() { CodeGen code = new CodeGen(""" struct _Point { var x; var y; }; _Point p = new _Point; p.x++; return p; """); try { code.parse().opto(); fail(); } catch( Exception e ) { assertEquals("'Test._Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); } } @Test public void testStructFinal4() { CodeGen code = new CodeGen(""" struct _Point { val x=2; val y=4; }; _Point p = new _Point; p.x++; return p; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } } @Test public void testStructFinal5() { CodeGen code = new CodeGen(""" struct _Point { var x=3; var y=4; }; _Point !p = new _Point; p.x++; return p; """); code.parse().opto(); assertEquals("return Test._Point;", code.print()); assertEquals("Test._Point{x=4,y=4}", Eval2.eval(code, 0)); } // Same as the Chapter13 test with the same name, but using the new // constructor syntax @Test public void testLinkedList1() { CodeGen code = new CodeGen( """ struct _LLI { _LLI? next; int i; new _LLI = { _LLI? n, int ii -> next=n; i=ii; }; }; _LLI? !head = null; while( arg ) { head = new _LLI(head,arg); arg = arg-1; } if( !head ) return 0; _LLI? next = head.next; if( !next ) return 1; return next.i; """); code.parse().opto(); assertEquals("return Phi(Region,1,.i,0);", code.print()); assertEquals("0", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); assertEquals("2", Eval2.eval(code, 3)); } @Test public void testLinkedList2() { CodeGen code = new CodeGen( """ struct _LLI { _LLI? next; int i; new _LLI = { _LLI? n, int a -> next=n; int !tmp=a; while( a > 10 ) { tmp = tmp + a; a = a - 1; } i=tmp; }; }; _LLI? !head = null; while( arg ) { head = new _LLI(head,arg); arg = arg-1; } if( !head ) return 0; _LLI? next = head.next; if( !next ) return 1; return next.i; """); code.parse().opto(); assertEquals("return Phi(Region,1,.i,0);", code.print()); assertEquals("0", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); assertEquals("2", Eval2.eval(code, 11)); } @Test public void testSquare() { CodeGen code = new CodeGen( """ struct _Square { 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; while( 1 ) { flt next = (side/diag + diag)/2; if( next == diag ) break; diag = next; } }; return new _Square; """); code.parse().opto(); assertEquals("return Test._Square;", code.print()); assertEquals("Test._Square{side=3.0,diag=1.7320508075688772}", Eval2.eval(code, 3)); assertEquals("Test._Square{side=4.0,diag=2.0}", Eval2.eval(code, 4)); } }