diff options
Diffstat (limited to 'chapter25/src/test/java')
21 files changed, 221 insertions, 157 deletions
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter25/src/test/java/com/seaofnodes/simple/BrainFuckTest.java index 0ebee2c4..a42ebc24 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/BrainFuckTest.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/BrainFuckTest.java @@ -61,7 +61,7 @@ val brain_fuck = { -> """; TestC.runC(src,"brain_fuck", brain_fuck, 40); - EvalRisc5 R5 = TestRisc5.build( src, "brain_fuck", 0, 28, false); + EvalRisc5 R5 = TestRisc5.build( src, "brain_fuck", 0, 25, false); int trap = R5.step(100000); assertEquals(0,trap); int ptr = (int)R5.regs[com.seaofnodes.simple.node.cpus.riscv.riscv.A0]; diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 6b237b18..0d40d871 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -65,7 +65,7 @@ else return v; """); code.parse().opto(); - assertEquals("Stop[ return Test.Vector2D; return MEM[ 2:.x=0; 3:.y=0;]; ]", code.print()); + assertEquals("Stop[ return Test.Vector2D; return MEM[ 2:.x=0; 3:.y=0;]; return Test.Vector2D; ]", code.print()); } @Test @@ -103,7 +103,7 @@ while (arg) { return bar.a; """); code.parse().opto(); - assertEquals("Stop[ return Phi(Loop,0,(Phi_a+2)); return MEM[ 2:.a=0;]; ]", code.print()); + assertEquals("Stop[ return Phi(Loop,0,(Phi_a+2)); return MEM[ 2:.a=0;]; return Test.Bar; ]", code.print()); } @Test @@ -225,7 +225,7 @@ while( i.x < i.len ) { return sum; """); code.parse().opto(); - assertEquals("Stop[ return Phi(Loop,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum)); return MEM[ 2:.x=0; 3:.len=0;]; ]", code.print()); + assertEquals("Stop[ return Phi(Loop,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum)); return MEM[ 2:.x=0; 3:.len=0;]; return Test.Iter; ]", code.print()); } @@ -244,7 +244,7 @@ while(arg) { return ret; """); code.parse().opto(); - assertEquals("Stop[ return Phi(Loop,Test.s0,Phi(Region,Test.s0,Phi_ret)); return MEM[ 2:.v0=0;]; ]", code.print()); + assertEquals("Stop[ return Phi(Loop,Test.s0,Phi(Region,Test.s0,Phi_ret)); return MEM[ 2:.v0=0;]; return Test.s0; ]", code.print()); } @Test @@ -297,7 +297,7 @@ s0 b = new s0(); return a.x * 100 + b.x * 10 + cnt; """); code.parse().iter().opto(); - assertEquals("Stop[ return 112; return MEM[ 2:___ 3:.x=1;]; ]", code.print()); + assertEquals("Stop[ return 112; return MEM[ 2:___ 3:.x=1;]; return Test.s0; ]", code.print()); } @@ -340,7 +340,7 @@ else return new s0; if(new s0.f0) return 0; """); code.parse().iter().opto().typeCheck(); - assertEquals("Stop[ return Test.s0; return MEM[ 2:.f0=0;]; ]", code.print()); + assertEquals("Stop[ return Test.s0; return MEM[ 2:.f0=0;]; return Test.s0; ]", code.print()); } @Test @@ -368,7 +368,7 @@ s0 v1 = v0; return v1; """); code.parse().opto(); - assertEquals("Stop[ return (const)Test.s0; return MEM[ 2:.f0=0;]; ]", code.print()); + assertEquals("Stop[ return (const)Test.s0; return MEM[ 2:.f0=0;]; return Test.s0; ]", code.print()); } diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter13Test.java index 8bbcf21c..fedd59ce 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter13Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter13Test.java @@ -99,7 +99,7 @@ N n = new N(new M); return n.next; """); code.parse().opto(); - assertEquals("Stop[ return (const)Test.M; return MEM[ 2:.m=0;]; return MEM[ 2:___ 3:___ 4:___ 5:.next=Parm_m(Test.N.N,*Test.M {i64 !m; }); 6:.i=0;]; return MEM[ 2:___ 3:___ 4:___ 5:___ 6:.i=0;]; ]", code.print()); + assertEquals("Stop[ return (const)Test.M; return MEM[ 2:.m=0;]; return Test.M; return MEM[ 2:___ 3:___ 4:___ 5:___ 6:.next=Parm_m(Test.N.N,*Test.M {i64 !m; }); 7:.i=0;]; return MEM[ 2:___ 3:___ 4:___ 5:___ 6:___ 7:.i=0;]; return Test.N; ]", code.print()); } @Test @@ -173,7 +173,7 @@ struct _S2 { int x; }; return (new _S1).s=new _S2; """); code.parse().opto(); - assertEquals("return _S2;", code.print()); + assertEquals("return Test._S2;", code.print()); } @Test diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java index d4790b3b..4d273aff 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java @@ -175,7 +175,7 @@ return root; """); code.parse().opto().typeCheck(); assertEquals("return Test._Tree;", code.print()); - assertEquals("Test._Tree{_kids=*Test._Tree {*[]*Test._Tree?? !_kids; }?[ Test._Tree{_kids=null},null]}", Eval2.eval(code, 0)); + assertEquals("Test._Tree{_kids=*Test._Tree {*[]*Test._Tree?[mutable]? !_kids; }?[ Test._Tree{_kids=null},null]}", Eval2.eval(code, 0)); } @Test diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java index 24daa164..faba6451 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java @@ -335,6 +335,18 @@ return arg ? 0 : arg; } @Test + public void testShortCircuitGuard() { + CodeGen code = new CodeGen(""" +struct S { int !x; }; +val get = { S s -> s.x; }; +S? !s = arg ? new S; +if( !s || !arg ) return 0; +return get(s); +"""); + code.parse().opto().typeCheck(); + } + + @Test public void testTrinary2() { CodeGen code = new CodeGen(""" struct _Bar { int x; }; @@ -395,7 +407,7 @@ struct S{}; return arg ? 7 : new S; """); try { code.parse().opto().typeCheck(); fail(); } - catch( Exception e ) { assertEquals("No common type amongst 7 and *Test.S {}",e.getMessage()); } + catch( Exception e ) { assertEquals("Cannot return generic scalar",e.getMessage()); } } // --------------------------------------------------------------- diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter18Test.java index b65e101b..dc29dafa 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter18Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter18Test.java @@ -146,7 +146,8 @@ return fcn(3); CodeGen code = new CodeGen("val _fact = { int x -> x <= 1 ? 1 : x*_fact(x-1); }; return _fact(arg);"); code.parse().opto().typeCheck(); String ir = code.print(); - assertTrue(ir.equals("Stop[ return Phi(Region,1,(arg*#2)); return Phi(Region,1,(Parm_x(_fact,(arg-1),(x-1))*#2)); ]") || + assertTrue(ir.equals("Stop[ return #2; return Phi(Region,1,(Parm_x(_fact,arg,(x-1))*#2)); ]") || + ir.equals("Stop[ return Phi(Region,1,(arg*#2)); return Phi(Region,1,(Parm_x(_fact,(arg-1),(x-1))*#2)); ]") || ir.equals("Stop[ return Phi(Region,1,(arg*Phi(Region,1,((arg-1)*#2)))); return Phi(Region,1,(Parm_x(_fact,(Sub-1),(x-1))*#2)); ]")); assertEquals( "1", Eval2.eval(code, 0)); assertEquals( "1", Eval2.eval(code, 1)); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter19Test.java index eaf76041..10c4690e 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter19Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter19Test.java @@ -58,7 +58,7 @@ val hashCode = { String self -> hashCode(new String("Hello, World!")); """; CodeGen code = new CodeGen(src).driver(Phase.LocalSched); - assertEquals("Stop[ return Phi(Region,123456789,(!=0)Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash)))); return MEM[ 2:___ 3:___ 4:.cs=Parm_s(Test.String.String,*[]u8); 5:._hashCode=0;]; return MEM[ 2:___ 3:___ 4:___ 5:._hashCode=0;]; return Phi(Region,0,1,0,1); return Phi(Region,(!=0)._hashCode,Phi(Region,123456789,(!=0)Phi(Loop,0,(((Phi_hash<<5)-Phi_hash)+.[])))); ]", code.print()); + assertEquals("Stop[ return Phi(Region,123456789,(!=0)Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash)))); return MEM[ 2:___ 3:___ 4:.cs=Parm_s(Test.String.String,*[]u8[final]); 5:._hashCode=0;]; return MEM[ 2:___ 3:___ 4:___ 5:._hashCode=0;]; return Test.String; return Phi(Region,0,1,0,1); return Phi(Region,(!=0)._hashCode,Phi(Region,123456789,(!=0)Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); ]", code.print()); assertEquals("4029215624828139541", Eval2.eval(code, 2)); } diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java index 17b0fd0a..e8a3a875 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java @@ -80,9 +80,34 @@ val _test_sqrt_noInline = { flt x -> }; flt farg = arg; return _test_sqrt_noInline(farg) + _test_sqrt_noInline(farg+2.0); """; - testCPU(src,"x86_64_v2", "SystemV",65,null); - testCPU(src,"riscv" , "SystemV",35,null); - testCPU(src,"arm" , "SystemV",35,null); + testCPU(src,"x86_64_v2", "SystemV",48,null); + testCPU(src,"riscv" , "SystemV",17,null); + testCPU(src,"arm" , "SystemV",18,null); + } + + @Test + public void testIterPrettyPrintIsLocalAndReadOnly() { + CodeGen code = new CodeGen(""" + val f_noInline = { flt x -> while(1) { if(x) return x; } }; + flt y=arg; + return f_noInline(y)+f_noInline(y+2.0); + """).driver(CodeGen.Phase.Iter); + assertNull(code._start._ltree); + int pre = code._start._pre; + + String p0 = code.toString(); + String p1 = code.toString(); + assertEquals(p0,p1); + assertNull(code._start._ltree); + assertEquals(pre,code._start._pre); + + int main0 = p0.indexOf("--- class:Test.<clinit>"); + int main1 = p0.indexOf("--- class:Test.<clinit> ----------------------",main0); + int fun0 = p0.indexOf("--- f_noInline ",main1); + int fun1 = p0.indexOf("--- f_noInline ----------------------",fun0); + assertTrue(main0 < main1 && main1 < fun0 && fun0 < fun1); + assertTrue(p0.indexOf("ToFloat",main0) < p0.indexOf("Call",main0)); + assertTrue(p0.indexOf("CallEnd",fun0) == -1 || p0.indexOf("CallEnd",fun0) > fun1); } @Test @@ -108,7 +133,7 @@ for( int i=0; i<ary#-1; i++ ) ary[i+1] += ary[i]; return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 """; - testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];"); + testCPU(src,"x86_64_v2", "SystemV",-1,"return mov(.[]);"); testCPU(src,"riscv" , "SystemV", 7,"return (add,.[],(mul,.[],1000));"); testCPU(src,"arm" , "SystemV", 5,"return (add,.[],(mul,.[],1000));"); } @@ -149,16 +174,16 @@ val _hashCodeString = { String self -> }; """; testCPU(src,"x86_64_v2", "SystemV",18,null); - testCPU(src,"riscv" , "SystemV", 5,null); - testCPU(src,"arm" , "SystemV", 4,null); + testCPU(src,"riscv" , "SystemV", 7,null); + testCPU(src,"arm" , "SystemV", 8,null); } @Test public void testCast() { String src = "struct Bar { int x; }; var b = arg ? new Bar; return b ? b.x++ + b.x++ : -1;"; testCPU(src,"x86_64_v2", "SystemV",3,null); - testCPU(src,"riscv" , "SystemV",3,null); - testCPU(src,"arm" , "SystemV",3,null); + testCPU(src,"riscv" , "SystemV",6,null); + testCPU(src,"arm" , "SystemV",6,null); } @Test diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java index e4d49e7f..6eb9a698 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -74,7 +74,7 @@ for( int i=0; i<ary#-1; i++ ) ary[i+1] += ary[i]; return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 """; - testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];"); + testCPU(src,"x86_64_v2", "SystemV",-1,"return mov(.[]);"); testCPU(src,"riscv" , "SystemV", 7,"return (add,.[],(mul,.[],1000));"); testCPU(src,"arm" , "SystemV", 5,"return (add,.[],(mul,.[],1000));"); } @@ -94,9 +94,9 @@ if (v1) { } return v0; """; - testCPU(src,"x86_64_v2", "SystemV",10,"return mov(mov(Test._S));"); + testCPU(src,"x86_64_v2", "SystemV", 9,"return mov(mov(Test._S));"); testCPU(src,"riscv" , "SystemV",10,"return mov(mov(Test._S));"); - testCPU(src,"arm" , "SystemV",10,"return mov(mov(Test._S));"); + testCPU(src,"arm" , "SystemV",11,"return mov(mov(Test._S));"); } @Test @@ -134,8 +134,8 @@ val _hashCodeString = { String self -> }; """; testCPU(src,"x86_64_v2", "SystemV",18,null); - testCPU(src,"riscv" , "SystemV", 5,null); - testCPU(src,"arm" , "SystemV", 4,null); + testCPU(src,"riscv" , "SystemV", 7,null); + testCPU(src,"arm" , "SystemV", 8,null); } @Test public void testStringExport() throws IOException { @@ -359,7 +359,7 @@ val fib = { int n -> int p1 = ps+4*8+1*8; // P2 = { age } // sizeof=8 int p2 = ps+4*8+2*8; - EvalRisc5 R5 = TestRisc5.build( src, "fcn", ps, 0, false); + EvalRisc5 R5 = TestRisc5.build( src, "fcn", ps, 2, false); R5.regs[riscv.A1] = 1; // Index 1 R5.st8(ps,3); // Length R5.st8(ps+1*8,p0); @@ -375,7 +375,7 @@ val fib = { int n -> assertEquals(17+1,R5.ld8(p1)); assertEquals(60+0,R5.ld8(p2)); - EvalArm64 A5 = TestArm64.build("fcn", src, ps, 0, false); + EvalArm64 A5 = TestArm64.build("fcn", src, ps, 2, false); A5.regs[arm.X1] = 1; // Index 1 A5.st8(ps, 3); A5.st8(ps+1*8,p0); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java index 91b8310d..68f94f12 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -60,7 +60,7 @@ _Person !p = new _Person; p.age = (arg<<17)>>17; return 0; """; - assertEquals(83, testCPUSize(src, "x86_64_v2","win64", 3 )); + assertEquals(82, testCPUSize(src, "x86_64_v2","win64", 3 )); assertEquals(96, testCPUSize(src, "riscv", "SystemV", 4 )); assertEquals(96, testCPUSize(src, "arm" , "SystemV", 4 )); @@ -88,11 +88,11 @@ return 0; int trap = R5.step(100); assertEquals(0,trap); - EvalArm64 A5 = TestArm64.build("sext_str_not_fold_away_2", src, 0, 4, false); + EvalArm64 A5 = TestArm64.build("sext_str_not_fold_away_2", src, 0, 3, false); int trap_arm = A5.step(100); assertEquals(0,trap_arm); - assertEquals(83, testCPUSize(src, "x86_64_v2","win64",3 )); + assertEquals(82, testCPUSize(src, "x86_64_v2","win64",3 )); assertEquals(96, testCPUSize(src, "riscv", "SystemV",4 )); assertEquals(96, testCPUSize(src, "arm", "SystemV",4 )); @@ -116,9 +116,9 @@ return 0; int trap_arm = A5.step(100); assertEquals(0,trap_arm); - assertEquals(71, testCPUSize(src, "x86_64_v2","win64",3 )); + assertEquals(72, testCPUSize(src, "x86_64_v2","win64",3 )); assertEquals(92, testCPUSize(src, "riscv", "SystemV",5 )); - assertEquals(92, testCPUSize(src, "arm", "SystemV",5 )); + assertEquals(92, testCPUSize(src, "arm", "SystemV",5)); // do assertEquals here } @@ -148,7 +148,7 @@ val fcn = { Person?[] ps, int x -> // exports a field with a constant fcn ptr; e int p1 = ps+4*8+1*8; // P2 = { age } // sizeof=8 int p2 = ps+4*8+2*8; - EvalRisc5 R5 = TestRisc5.build( src, "fcn", ps, 0, false); + EvalRisc5 R5 = TestRisc5.build( src, "fcn", ps, 2, false); R5.regs[riscv.A1] = 1; // Index 1 R5.st8(ps,3); // Length R5.st8(ps+1*8,p0); @@ -164,7 +164,7 @@ val fcn = { Person?[] ps, int x -> // exports a field with a constant fcn ptr; e assertEquals(17+1,R5.ld8(p1)); assertEquals(60+0,R5.ld8(p2)); - EvalArm64 A5 = TestArm64.build("fcn", src, ps, 0, false); + EvalArm64 A5 = TestArm64.build("fcn", src, ps, 2, false); A5.regs[arm.X1] = 1; // Index 1 A5.st8(ps, 3); A5.st8(ps+1*8,p0); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java index 08acfd32..3346aa51 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java @@ -86,6 +86,26 @@ return a && b ? 0 : 1; // Expected answer 0 } @Test + public void testLogicalValueSemantics() { + assertEquals("42", Eval2.eval(new CodeGen("return 7 && 42;").parse().opto(), 0)); + assertEquals("0", Eval2.eval(new CodeGen("return 0 && 42;").parse().opto(), 0)); + assertEquals("7", Eval2.eval(new CodeGen("return 7 || 42;").parse().opto(), 0)); + assertEquals("42", Eval2.eval(new CodeGen("return 0 || 42;").parse().opto(), 0)); + } + + @Test + public void testMixedScalarNotPhiPredicate() { + CodeGen code = new CodeGen(""" +struct S {}; +S? s = arg ? new S; +return !(!s || !arg) ? 1 : 0; +"""); + code.parse().opto().typeCheck(); + assertEquals("0", Eval2.eval(code, 0)); + assertEquals("1", Eval2.eval(code, 1)); + } + + @Test public void testAndPtr() throws IOException { // Todo: have one src here String src = """ @@ -97,7 +117,7 @@ return ptr && ptr.fld ? "true" : "false"; assertEquals("true", Eval2.eval(code, 0)); // Evaluate on RISC5 emulator - EvalRisc5 R5 = TestRisc5.build( src, "class:Test.<clinit>", 1, 8, false); + EvalRisc5 R5 = TestRisc5.build( src, "class:Test.<clinit>", 1, 12, false); int trap = R5.step(100); assertEquals(0,trap); int adr = (int)R5.regs[riscv.A0]; // Returns a Simple *u8[~] string @@ -105,7 +125,7 @@ return ptr && ptr.fld ? "true" : "false"; assertEquals(0x65757274,R5.ld4s(adr+4)); // "true" // Evaluate on ARM emulator - EvalArm64 arm = TestArm64.build("class:Test.<clinit>", src, 1, 8, false); + EvalArm64 arm = TestArm64.build("class:Test.<clinit>", src, 1, 12, false); trap = arm.step(100); assertEquals(0,trap); int adr2 = (int)arm.regs[0]; // Returns a Simple *u8[~] string @@ -185,13 +205,13 @@ return (a && sq_noInline(0)) TestC.runSF( src, "and3", "", 2); // Evaluate on RISC5 emulator - EvalRisc5 R5 = TestRisc5.build( src, "and3", 0, 5, false); + EvalRisc5 R5 = TestRisc5.build( src, "and3", 0, 2, false); int trap = R5.step(100); assertEquals(0,trap); assertEquals(0,R5.regs[riscv.A0]); // Evaluate on ARM emulator - EvalArm64 arm = TestArm64.build("and3", src, 0, 5, false); + EvalArm64 arm = TestArm64.build("and3", src, 0, 2, false); trap = arm.step(100); assertEquals(0,trap); assertEquals(0,arm.regs[0]); @@ -251,7 +271,7 @@ return s.skip().x; try { new CodeGen(src).parse().opto().typeCheck(); fail(); } catch( Exception e ) { // Bad error message, but basically requires a mutable 'x' field. - assertEquals("Argument #0 isa *Test._Scan {i64 x; *[]u8 buf; { *Test._Scan -> *Test._Scan {i64 !x; *[]u8 buf; {[ 5]} skip; } #[ 5]} skip; }, but must be a *Test._Scan {i64 !x; *[]u8 buf; { *Test._Scan -> *Test._Scan #[ 5]} skip; }",e.getMessage()); + assertEquals("Argument #0 isa *Test._Scan {i64 x; *[]u8[final] buf; { *Test._Scan -> *Test._Scan {i64 !x; *[]u8 buf; {[ 5]} skip; } #[ 5]} skip; }, but must be a *Test._Scan {i64 !x; *[]u8[final] buf; { *Test._Scan -> *Test._Scan #[ 5]} skip; }",e.getMessage()); } }; diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter24Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter24Test.java index fe8aaf2e..eb89dbb3 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter24Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter24Test.java @@ -62,16 +62,16 @@ return (sq_noInline(2) <= score < sq_noInline(3)) ? 0 // Expected : 1; // Error """; - TestC.runSF( src, "stacked_r_3", "", 4); + TestC.runSF( src, "stacked_r_3", "", 2); // Evaluate on RISC5 emulator - EvalRisc5 R5 = TestRisc5.build( src, "stacked_r_3", 0, 5, false); + EvalRisc5 R5 = TestRisc5.build( src, "stacked_r_3", 0, 2, false); int trap = R5.step(100); assertEquals(0,trap); assertEquals(0,R5.regs[riscv.A0]); // Evaluate on ARM emulator - EvalArm64 arm = TestArm64.build("stacked_r_3", src, 0, 5, false); + EvalArm64 arm = TestArm64.build("stacked_r_3", src, 0, 3, false); int trap_1 = arm.step(100); assertEquals(0,trap_1); assertEquals(0,arm.regs[0]); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java index 8f1c7285..b21734b4 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java @@ -18,9 +18,17 @@ import static org.junit.Assert.*; public class Chapter25Test { - private static final String SYS_MODDIR = "src/main/smp"; private static final String SYS_BLDDIR = "build/objs/lib_"+TestC.CPU_ABI; - private static final String RELEASE_SYS_BLDDIR = TestC.RELEASE_SYS_DIR; + private static final File SYS_FILE = new File(SYS_BLDDIR+"/sys.o"); + + @Test + public void testForwardConstructor() { + CodeGen code = new CodeGen("src/test/java/com/seaofnodes/simple/test_smp/forward_ctor", + "build/objs/forward_ctor_parse",null, + "m",null,123L,TypeInteger.BOT); + code.driver(CodeGen.Phase.TypeCheck); + } + @Test public void testPostfixFieldUpdate() { @@ -163,56 +171,34 @@ public class Chapter25Test { } - private File buildTestSys(boolean clean) { - if( clean ) - delELFiles(new File(SYS_BLDDIR)); - File sys_file = new File(SYS_BLDDIR+"/sys.o" ); - if( sys_file.exists() ) - return sys_file; - - // Compile SYS_MODDIR/sys.smp into SYS_BLDDIR/sys.o. Chapter25 - // compiler tests intentionally depend on this freshly built sys.o. - CodeGen code1 = new CodeGen(SYS_MODDIR, SYS_BLDDIR,null, - "sys",null,123L,TypeInteger.BOT); - code1.driver(CodeGen.Phase.Export,TestC.CPU_PORT,TestC.CALL_CONVENTION,false,false,0); - assertTrue( sys_file.exists() ); - return sys_file; - } - @Test public void testSys() { - delELFiles(new File(SYS_BLDDIR)); - - CodeGen code1 = new CodeGen(SYS_MODDIR, SYS_BLDDIR,null, - "sys",null,123L,TypeInteger.BOT); - code1.driver(CodeGen.Phase.Export,TestC.CPU_PORT,TestC.CALL_CONVENTION,false,false,0); - - // Verify produces sys.o, sys/io.o - File sys_file = new File(SYS_BLDDIR+"/sys.o" ); - assertTrue( sys_file.exists() ); + assertTrue("Missing "+SYS_FILE+"; run make tests_sys", SYS_FILE.exists()); // Can read the ELF files - ElfReader sys_elf = ElfReader.load( sys_file, null); - sys_elf.loadSimple(code1); + CodeGen code1 = new CodeGen("return 0;"); + ElfReader sys_elf = ElfReader.load(SYS_FILE, null); + sys_elf.loadPublicTypes(code1); // Elf files are sane - // Sys depends on io, libc, aryi64, aryu8 - assertEquals(6,sys_elf._deps.length); + // Sys depends on io, libc, char, collections, and array utilities. + assertEquals(10,sys_elf._deps.length); assertSame("sys/aryu8" ,sys_elf._deps[0]); - assertSame("sys/io" ,sys_elf._deps[1]); - assertSame("sys/aryi64",sys_elf._deps[2]); - assertSame("sys/Ary" ,sys_elf._deps[3]); - assertSame("sys/Scan" ,sys_elf._deps[4]); - assertSame("sys/libc" ,sys_elf._deps[5]); + assertSame("sys/char" ,sys_elf._deps[1]); + assertSame("sys/io" ,sys_elf._deps[2]); + assertSame("sys/ary" ,sys_elf._deps[3]); + assertSame("sys/aryi64",sys_elf._deps[4]); + assertSame("sys/adt/bitset",sys_elf._deps[5]); + assertSame("sys", sys_elf._deps[6]); + assertSame("sys/scan" ,sys_elf._deps[7]); + assertSame("sys/adt" ,sys_elf._deps[8]); + assertSame("sys/libc" ,sys_elf._deps[9]); assertSame("class:sys" ,sys_elf._clz._name); } @Test public void testHelloWorld() throws IOException { - File sys_file = buildTestSys(false); - assertTrue("Missing "+sys_file+"; testHelloWorld depends on testSys building it", sys_file.exists()); - String expected = "Hello, World!\n"; String prog = "return sys.io.p(\""+expected+"\") - "+expected.length()+";"; TestC.run(prog,"helloWorld",new Ary<>(new String[]{SYS_BLDDIR}), @@ -221,23 +207,16 @@ public class Chapter25Test { @Test public void testHelloWorldDriver() throws Exception { - File sys_file = new File(RELEASE_SYS_BLDDIR+"/sys.o"); - assertTrue("Missing "+sys_file+"; run make release or make tests_sys first", sys_file.exists()); - Simple.main(new String[]{"-L",RELEASE_SYS_BLDDIR,"--norun","docs/examples/A_helloWorld.smp"}); + Simple.main(new String[]{"-L",SYS_BLDDIR,"--norun","docs/examples/A_helloWorld.smp"}); } @Test public void testHelloWorldDriverLibFile() throws Exception { - File sys_file = new File(RELEASE_SYS_BLDDIR+"/sys.o"); - assertTrue("Missing "+sys_file+"; run make release or make tests_sys first", sys_file.exists()); - Simple.main(new String[]{"-L",sys_file.toString(),"docs/examples/A_helloWorld.smp"}); + Simple.main(new String[]{"-L",SYS_FILE.toString(),"docs/examples/A_helloWorld.smp"}); } @Test public void testHelloWorldNoInline() throws Exception { - File sys_file = buildTestSys(false); - assertTrue("Missing "+sys_file+"; testHelloWorldNoInline depends on testSys building it", sys_file.exists()); - String base = "helloWorldNoInline"; String expected = "Hello, World!\n"; String prog = "return sys.io.p_noInline(\""+expected+"\") - "+expected.length()+";"; @@ -250,7 +229,7 @@ public class Chapter25Test { String syms = run(new String[]{"nm",obj}); assertTrue(syms, syms.contains(" U sys.io.p_noInline")); - String out = run(new String[]{"gcc",obj,sys_file.toString(),TestC.runtimeObject(),"-lm","-g","-o",exe}); + String out = run(new String[]{"gcc",obj,SYS_FILE.toString(),TestC.runtimeObject(),"-lm","-g","-o",exe}); assertEquals("",out); String rez = run(new String[]{exe}); assertEquals(expected,rez); @@ -267,8 +246,6 @@ public class Chapter25Test { @Test public void testRedirectedRead() throws IOException { - File sys_file = buildTestSys(false); - assertTrue("Missing "+sys_file+"; testRedirectedRead depends on testSys building it", sys_file.exists()); String src = """ u8[] buf = new u8[10]; i64 ptr = buf; @@ -282,28 +259,58 @@ return rez < buf# ? 0 : sys.libc._exit(-2); @Test public void testBubbles() throws IOException { - File sys_file = buildTestSys(false); - assertTrue("Missing "+sys_file+"; testBubbles depends on testSys building it", sys_file.exists()); String src = Files.readString( Path.of("docs/examples/BubbleSort.smp")); - TestC.runArgs(src,"BubbleSort",new Ary<>(new String[]{SYS_BLDDIR}), - TestC.CALL_CONVENTION,"-17, 2, 3, 999\n",-1, - "[3, 2,-17, 999 ]"); - - String obj = "build/objs/BubbleSort.o"; - String exe = "build/objs/BubbleSort"+(TestC.OS.startsWith("Windows") ? ".exe" : ""); - Ary<String> libs = new Ary<>(new String[]{sys_file.toString()}); - assertEquals("1, 2, 3, 4, 4, 5\n", - TestC.gcc(obj,null,null,null,libs,exe,"[4, 5, 3, 1, 4, 2]")); - assertEquals("1, 2, 3, 4, 5\n", - TestC.gcc(obj,null,null,null,libs,exe,"[1, 2, 3, 4, 5]")); - assertEquals("1, 2, 3, 4, 5, 6, 7, 8, 9\n", - TestC.gcc(obj,null,null,null,libs,exe,"[9, 8, 7, 6, 5, 4, 3, 2, 1]")); + String exe = TestC.compile(src,"BubbleSort",new Ary<>(new String[]{SYS_BLDDIR}), + TestC.CALL_CONVENTION,null,null,-1); + assertEquals("[-17, 2, 3, 999]\n", + TestC.exec(exe,"[3, 2,-17, 999 ]")); + assertEquals("[1, 2, 3, 4, 4, 5]\n", + TestC.exec(exe,"[4, 5, 3, 1, 4, 2]")); + assertEquals("[1, 2, 3, 4, 5]\n", + TestC.exec(exe,"[1, 2, 3, 4, 5]")); + assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9]\n", + TestC.exec(exe,"[9, 8, 7, 6, 5, 4, 3, 2, 1]")); String usage = "Usage: please provide a list of at least two integers to sort in the format \"[1, 2, 3, 4, 5]\"\n"; - assertEquals(usage,TestC.gcc(obj,null,null,null,libs,exe)); - assertEquals(usage,TestC.gcc(obj,null,null,null,libs,exe,"")); - assertEquals(usage,TestC.gcc(obj,null,null,null,libs,exe,"[1]")); - assertEquals(usage,TestC.gcc(obj,null,null,null,libs,exe,"[4 5 3]")); + assertEquals(usage,TestC.exec(exe)); + assertEquals(usage,TestC.exec(exe,"")); + assertEquals(usage,TestC.exec(exe,"[1]")); + assertEquals(usage,TestC.exec(exe,"[4 5 3]")); } + @Test + public void testCapitalize() throws IOException { + String src = Files.readString(Path.of("docs/examples/Capitalize.smp")); + String exe = TestC.compile(src,"Capitalize",new Ary<>(new String[]{SYS_BLDDIR}), + TestC.CALL_CONVENTION,null,null,-1); + assertEquals("Hello world\n",TestC.exec(exe,"hello world")); + assertEquals("Hello World\n",TestC.exec(exe,"Hello World")); + assertEquals("123 apples\n",TestC.exec(exe,"123 apples")); + assertEquals("Usage: please provide a string\n",TestC.exec(exe)); + assertEquals("Usage: please provide a string\n",TestC.exec(exe,"")); + assertEquals("Use quotes around multiple strings.\n",TestC.exec(exe,"hello","world")); + } + + @Test + public void testDijkstra() throws IOException { + String src = Files.readString(Path.of("docs/examples/Dijkstra.smp")); + String matrix = "[0, 2, 0, 6, 0, 2, 0, 3, 8, 5, 0, 3, 0, 0, 7, 6, 8, 0, 0, 9, 0, 5, 7, 9, 0]"; + String exe = TestC.compile(src,"Dijkstra",new Ary<>(new String[]{SYS_BLDDIR}), + TestC.CALL_CONVENTION,null,null,-1); + assertEquals("2\n",TestC.exec(exe,matrix,"0","1")); + String usage = "Usage: please provide three inputs: a serialized matrix, a source node and a destination node\n"; + assertEquals("7\n",TestC.exec(exe,matrix,"0","4")); + assertEquals(usage,TestC.exec(exe)); + assertEquals(usage,TestC.exec(exe,"","","")); + assertEquals(usage,TestC.exec(exe,"[1, 0, 3, 0, 5, 1]","1","2")); + assertEquals(usage,TestC.exec(exe,"[0, 0, 0, 0]","0","1")); + } + + @Test + public void testFileIO() throws IOException { + String src = Files.readString(Path.of("docs/examples/FileIO.smp")); + String exe = TestC.compile(src,"FileIO",new Ary<>(new String[]{SYS_BLDDIR}), + TestC.CALL_CONVENTION,null,null,-1); + assertEquals("File I/O succeeded\n",TestC.exec(exe)); + } } diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Simple.java b/chapter25/src/test/java/com/seaofnodes/simple/Simple.java index 35b9b922..a5d104e7 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Simple.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Simple.java @@ -247,7 +247,7 @@ Options: if ( !TestC.CPU_PORT.equals( cpu ) || !TestC.CALL_CONVENTION.equals( abi ) ) throw bad("cannot run code on not native target"); String exe = TestC.OS.startsWith("Windows") ? outBase+".exe" : outBase; - String result = TestC.gcc(outBase+".o", null, null, true, exe); + String result = TestC.gcc(outBase+".o", null, null, "", TestC.linkObjs(externPaths), exe); System.out.print(result); } } diff --git a/chapter25/src/test/java/com/seaofnodes/simple/TestC.java b/chapter25/src/test/java/com/seaofnodes/simple/TestC.java index 2f737579..bd8a52cc 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/TestC.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/TestC.java @@ -98,6 +98,17 @@ public abstract class TestC { private static void run0( String src, String base, Ary<String> externPaths, String simple_conv, String c_conv, String cfile, String stdin, String expected, int spills, String[] programArgs ) throws IOException { + String exe = compile(src,base,externPaths,simple_conv,c_conv,cfile,spills); + + String[] execArgs = new String[programArgs.length+1]; + execArgs[0] = exe; + System.arraycopy(programArgs,0,execArgs,1,programArgs.length); + String result = execStdin(stdin, execArgs ); + assertEquals(expected,result); + } + + public static String compile( String src, String base, Ary<String> externPaths, String simple_conv, String c_conv, + String cfile, int spills ) throws IOException { // Simple file base-name example: // foo.smp -> // build/objs/foo.o - object file @@ -110,17 +121,14 @@ public abstract class TestC { CodeGen code = new CodeGen(null,"build/objs",externPaths,base,src,126L,TypeInteger.BOT); code.driver( CPU_PORT, simple_conv, false, cfile==null ); - String[] execArgs = new String[programArgs.length+1]; - execArgs[0] = exe; - System.arraycopy(programArgs,0,execArgs,1,programArgs.length); - String result = gcc(obj, c_conv, cfile, stdin, linkObjs(externPaths), execArgs ); - assertEquals(expected,result); + linkExe(obj, c_conv, cfile, linkObjs(externPaths), exe); // Allocation quality not degraded int delta = spills>>3; if( delta==0 ) delta = 1; if( spills != -1 && !CodeGen.iterSeedOverridden() ) assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + return exe; } // Link with gcc, and execute the resulting binary, returning stdout as a @@ -146,7 +154,11 @@ public abstract class TestC { } public static String gcc( String obj, String c_conv, String cfile, String stdin, Ary<String> linkObjs, String... args ) throws IOException { + linkExe(obj,c_conv,cfile,linkObjs,args[0]); + return execStdin(stdin,args); + } + public static void linkExe( String obj, String c_conv, String cfile, Ary<String> linkObjs, String exe ) throws IOException { // Compile the C program. Compiling code and constants in the low // 2Gig. Pointers are 64b BUT since always in the low 2G all the // high bits are zero - and Simple code can be emitted treating @@ -165,7 +177,7 @@ public abstract class TestC { "-lm", // Picks up 'sqrt' for newtonFloat tests to compare "-g", "-o", - args[0], + exe, }); // Calling convention for C calls, if any if( cfile!=null ) { @@ -190,6 +202,13 @@ public abstract class TestC { assertEquals( 0, exit ); //assertTrue(result.isEmpty()); // No data in error stream + } + + public static String exec( String... args ) throws IOException { + return execStdin(null,args); + } + + private static String execStdin( String stdin, String... args ) throws IOException { // Execute results ProcessBuilder smp = new ProcessBuilder(args); File stdinFile = null; @@ -204,8 +223,9 @@ public abstract class TestC { Process p = smp.start(); if( stdin==null ) p.getOutputStream().close(); + int exit; try { exit = (byte)p.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); } - result = Files.readString(stdoutFile.toPath()); + String result = Files.readString(stdoutFile.toPath()); if( stdinFile != null ) stdinFile.delete(); stdoutFile.delete(); @@ -214,7 +234,7 @@ public abstract class TestC { return result; } - private static Ary<String> linkObjs(Ary<String> externPaths) { + static Ary<String> linkObjs(Ary<String> externPaths) { if( externPaths == null ) return null; Ary<String> objs = new Ary<>(String.class); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/TypeTest.java b/chapter25/src/test/java/com/seaofnodes/simple/TypeTest.java index e881a2bf..65635afe 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/TypeTest.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/TypeTest.java @@ -7,7 +7,7 @@ import static org.junit.Assert.assertSame; public class TypeTest { - // Test basic properties and GLB + // Test basic type properties @Test public void testTypeAdHoc() { Assert.assertEquals( TypeScalar.BOT, TypeInteger.TRUE.meet(TypeNil.NIL) ); @@ -19,13 +19,8 @@ public class TypeTest { TypeStruct s2 = TypeStruct.make("s2",false, Field.make("a", TypeInteger.BOT,-3, false), Field.make("b", TypeInteger.BOT,-4, false) ); - TypeStruct x1ro = (TypeStruct)s1.makeRO(); TypeMemPtr p1 = TypeMemPtr.make(s1); - // GLB no longer forces RO - //Assert.assertEquals(x1ro, ((TypeMemPtr)p1.glb(false))._obj); Assert.assertNotEquals(s1, s1.dual()); - TypeStruct s1dglb = ((TypeMemPtr)p1.dual().glb(false))._obj; - Assert.assertTrue(x1ro.isa(s1dglb)); TypeMem m1 = TypeMem.make(2,TypeNil.NIL); TypeMem m2 = TypeMem.make(3,TypeInteger.U16); @@ -42,9 +37,7 @@ public class TypeTest { Assert.assertEquals(TypeMem.make(1,TypeScalar.BOT), m1.meet(m3)); Assert.assertEquals(scalarMemBot, ((TypeMem)m3.meet(m4)).makeFrom( XInt.FULL, XInt.FULL)); - Assert.assertEquals(TypeMem.make(2,Type.BOTTOM), m1.glb(false)); Assert.assertEquals(TypeMem.make(2,Type.XNIL,true,true,true, XInt.FULL, XInt.FULL), m1.dual()); - Assert.assertEquals(m4.dual(), m4.glb(false).dual()); TypeMemPtr ptr1 = TypeMemPtr.make(s1); Assert.assertEquals(s1, ptr1._obj); @@ -59,18 +52,8 @@ public class TypeTest { Assert.assertEquals(s2, ptr2nil._obj); Assert.assertNotEquals(ptr1, ptr2); - Type p1glb = ptr1.glb(false); - // GLB no longer forces RO - //Assert.assertNotEquals(ptr1, p1glb ); - Type p1nro = ptr1nil.makeRO(); - // GLB no longer forces RO - //Assert.assertEquals(p1nro, p1glb); - Assert.assertEquals(ptr1, ptr1.dual().dual()); - Assert.assertTrue(p1glb.makeRO().isa( ptr1.dual().glb(false))); Assert.assertEquals(TypeMemPtr.makeNullable(TypeStruct.BOT), ptr1.meet(ptr2nil)); - // GLB no longer forces RO - //Assert.assertEquals(p1glb, ptr1.meet(TypeNil.NIL).makeRO()); TypeMemPtr TOP = TypeMemPtr.TOP; TypeMemPtr BOT = TypeMemPtr.makeNullable(TypeStruct.BOT); @@ -96,9 +79,6 @@ public class TypeTest { Assert.assertTrue(s1ro.isFinal()); Assert.assertFalse(S1.isConstant()); - Type s1glb = S1.field("s2")._t.glb(false); - Type s1glb2 = S1.field("s2")._t.glb(false); - Assert.assertSame(s1glb,s1glb2); } // Test theoretical properties. @@ -178,14 +158,6 @@ public class TypeTest { } @Test - public void testGLB() { - Type[] ts = Type.gather(); - for( Type t0 : ts ) - if( !(t0 instanceof Field || t0 instanceof TypeStruct || t0 instanceof TypeTuple || t0 instanceof TypeConAry ) ) - Assert.assertTrue(t0.isa(t0.glb(false))); - } - - @Test public void testList() { TypeStruct list = TypeStruct.open("List"); TypeMemPtr plist = TypeMemPtr.makeNullable(list); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m.smp new file mode 100644 index 00000000..569f38be --- /dev/null +++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m.smp @@ -0,0 +1,2 @@ +val a = a; +val b = b; diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m/a.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m/a.smp new file mode 100644 index 00000000..97113b71 --- /dev/null +++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m/a.smp @@ -0,0 +1 @@ +val f = { -> new b(1); }; diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m/b.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m/b.smp new file mode 100644 index 00000000..43770b60 --- /dev/null +++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/forward_ctor/m/b.smp @@ -0,0 +1,4 @@ +struct b { + int x; + new b = { int y -> x = y; }; +}; diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/Ary.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/ary.smp index e3dd6140..e3dd6140 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/Ary.smp +++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/ary.smp diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp index 112a0321..e6b708a4 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp +++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp @@ -9,7 +9,7 @@ struct aryu8 { int newlen = buf# * 2; while( len+len2 >= newlen ) newlen *= 2; u8[] !buf2 = new u8[newlen]; - Ary.copy(buf2,0,buf,0,buf#); + ary.copy(buf2,0,buf,0,buf#); buf = buf2; self; }; @@ -21,10 +21,10 @@ struct aryu8 { self; }; - val addAry = { u8[~] ary -> - _grow(ary#); - Ary.copy(buf,len,ary,0,ary#); - len += ary#; + val addAry = { u8[~] xs -> + _grow(xs#); + ary.copy(buf,len,xs,0,xs#); + len += xs#; self; }; |
