From efc81d5afc9983258db267894ce3f141962793a5 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 7 Nov 2024 16:30:43 -0800 Subject: var/val --- .../main/java/com/seaofnodes/simple/Parser.java | 16 ++++++- .../java/com/seaofnodes/simple/node/MinusNode.java | 5 ++- .../java/com/seaofnodes/simple/BrainFuckTest.java | 15 ++++--- .../java/com/seaofnodes/simple/Chapter15Test.java | 38 ++++++++-------- .../java/com/seaofnodes/simple/Chapter17Test.java | 50 ++++++++++++++++++++++ 5 files changed, 94 insertions(+), 30 deletions(-) diff --git a/chapter17/src/main/java/com/seaofnodes/simple/Parser.java b/chapter17/src/main/java/com/seaofnodes/simple/Parser.java index abd70f89..fac012a4 100644 --- a/chapter17/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter17/src/main/java/com/seaofnodes/simple/Parser.java @@ -141,6 +141,8 @@ public class Parser { put("u16" ,TypeInteger.U16); put("u32" ,TypeInteger.U32); put("u8" ,TypeInteger.U8 ); + put("val" ,Type.TOP); // Marker type, indicates type inference + put("var" ,Type.BOTTOM); // Marker type, indicates type inference }}; } @@ -422,6 +424,8 @@ public class Parser { ? Type.TOP // Else takes the default : t.makeInit(); + // "var" and "val" require an expression to infer + if( init == null ) throw errorSyntax("expression"); expr = con(init); } else if( !match("=") ) { // Something else @@ -453,6 +457,9 @@ public class Parser { Type e = expr._type; if( e instanceof TypeMemPtr tmp && tmp._obj._fields==null ) e = TYPES.get(tmp._obj._name); + // "var" and "val" use TOP and BOTTOM - but just take the expression type. + if( t==Type.TOP || t==Type.BOTTOM ) + t = expr._type.glb(); // Type is sane if( !e.isa(t) ) throw error("Type " + e.str() + " is not of declared type " + t.str()); @@ -468,7 +475,9 @@ public class Parser { /** Parse final: [!]asgn */ private Node parseFinal(Type t) { - boolean xfinal = t!=null && match("!"); + // TOP is a "val" marker - uses type inference for a "value", i.e. a final. + // BOT is a "var" marker - uses type inference for a "variable", i.e. not final + boolean xfinal = t==Type.TOP || (t!=null && match("!")); return parseAsgn(t,xfinal); } @@ -761,8 +770,11 @@ public class Parser { // Expect an identifier now ScopeMinNode.Var n = requireLookupId("an identifier or expression"); Node rvalue = _scope.in(n).keep(); - if( matchx("++") || matchx("--") ) + if( matchx("++") || matchx("--") ) { + if( n._final ) + throw error("Cannot reassign final '"+n._name+"'"); _scope.update(n,new AddNode(rvalue,con( _lexer.peek(-1)=='+' ? 1 : -1)).peephole()); + } return rvalue.unkeep(); } diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 8a2c9406..760a4274 100644 --- a/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -2,6 +2,7 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.Utils; import java.util.BitSet; @@ -22,7 +23,9 @@ public class MinusNode extends Node { public Type compute() { if( in(1)._type instanceof TypeInteger i0 ) { if( i0.isHigh() ) return TypeInteger.TOP; - return i0==TypeInteger.BOT ? TypeInteger.BOT : TypeInteger.make(-i0._max,-i0._min); + if( i0==TypeInteger.BOT || i0._min == Long.MIN_VALUE || i0._max == Long.MIN_VALUE ) + return TypeInteger.BOT; + return TypeInteger.make(-i0._max,-i0._min); } return TypeInteger.TOP.meet(in(1)._type); } diff --git a/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java index 88dccc49..abb8b834 100644 --- a/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java +++ b/chapter17/src/test/java/com/seaofnodes/simple/BrainFuckTest.java @@ -23,11 +23,12 @@ public class BrainFuckTest { Parser parser = new Parser( encoded + """ -int pc = 0, d = 0; -u8[] data = new u8[100], output = new u8[0]; +var pc = 0, d = 0; +u8[] output = new u8[0]; +val data = new u8[100]; while (pc < program#) { - int command = program[pc]; + var command = program[pc]; if (command == 62) { d++; } else if (command == 60) { @@ -37,9 +38,9 @@ while (pc < program#) { } else if (command == 45) { data[d]--; } else if (command == 46) { - u8[] old = output; + var old = output; output = new u8[output# + 1]; - int i = 0; + var i = 0; while (i < old#) output[i] = old[i++]; output[i] = data[d]; @@ -47,7 +48,7 @@ while (pc < program#) { data[d] = 42; } else if (command == 91) { if (data[d] == 0) { - int d = 1; + var d = 1; while (d > 0) { pc++; command = program[pc]; @@ -57,7 +58,7 @@ while (pc < program#) { } } else if (command == 93) { if (data[d]) { - int d = 1; + var d = 1; while (d > 0) { pc--; command = program[pc]; diff --git a/chapter17/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter17/src/test/java/com/seaofnodes/simple/Chapter15Test.java index 8161862f..4226c201 100644 --- a/chapter17/src/test/java/com/seaofnodes/simple/Chapter15Test.java +++ b/chapter17/src/test/java/com/seaofnodes/simple/Chapter15Test.java @@ -216,38 +216,36 @@ 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 +// Copy/shrink the result array int[] rez = new int[nprimes]; -j = 0; +int j = 0; while( j < nprimes ) { rez[j] = primes[j]; j = j + 1; } - return rez; """); StopNode stop = parser.parse().iterate(); diff --git a/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java index 45e3ef0f..ffb9bfc2 100644 --- a/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java +++ b/chapter17/src/test/java/com/seaofnodes/simple/Chapter17Test.java @@ -87,6 +87,16 @@ return s.x; assertEquals(65535L, Evaluator.evaluate(stop, 2)); } + @Test + public void testVar0() { + Parser parser = new Parser(""" +var d; +return d; +"""); + try { parser.parse().iterate(); fail(); } + catch( Exception e ) { assertEquals("Syntax error, expected expression: ;",e.getMessage()); } + } + @Test public void testLinkedList2() { Parser parser = new Parser(""" @@ -106,4 +116,44 @@ return sum; assertEquals(45L, Evaluator.evaluate(stop, 10)); } + @Test + public void sieveOEratosthenes() { + Parser parser = new Parser( +""" +val ary = new bool[arg], primes = new int[arg]; +var nprimes=0, p=2; +// Find primes while p^2 < arg +while( p*p < arg ) { + // skip marked non-primes + while( ary[p] ) p++; + // p is now a prime + primes[nprimes++] = p; + // Mark out the rest non-primes + int i = p + p; + while( i < ary# ) { + ary[i] = true; + i = i + p; + } + p++; +} +// Now just collect the remaining primes, no more marking +while( p++ < arg ) + if( !ary[p-1] ) + primes[nprimes++] = p-1; +// Copy/shrink the result array +var rez = new int[nprimes], j = 0; +while( j < nprimes ) + rez[j] = primes[j++]; +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()); + long nprimes = (Long)obj.fields()[0]; + long[] primes = new long[]{2,3,5,7,11,13,17,19}; + for( int i=0; i