From 94e557c9de68e7b3f5595d75e7330b63df76c323 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 14 Oct 2024 10:31:40 -0700 Subject: final fields and multi defs `int x,y;` works `int !x = 3;` works Structs defs are statements, require a trailing `;` --- chapter16/docs/16-grammar.md | 143 +++++++++------------ .../main/java/com/seaofnodes/simple/Parser.java | 133 +++++++++++++------ .../java/com/seaofnodes/simple/node/SarNode.java | 2 + .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +++- .../java/com/seaofnodes/simple/node/ShlNode.java | 4 +- .../java/com/seaofnodes/simple/node/ShrNode.java | 4 +- .../java/com/seaofnodes/simple/node/StartNode.java | 2 +- .../java/com/seaofnodes/simple/type/Field.java | 30 +++-- .../com/seaofnodes/simple/type/TypeStruct.java | 8 +- .../java/com/seaofnodes/simple/Chapter10Test.java | 54 ++++---- .../java/com/seaofnodes/simple/Chapter11Test.java | 26 ++-- .../java/com/seaofnodes/simple/Chapter13Test.java | 26 ++-- .../java/com/seaofnodes/simple/Chapter16Test.java | 68 +++++++++- .../test/java/com/seaofnodes/simple/TypeTest.java | 8 +- 14 files changed, 326 insertions(+), 210 deletions(-) diff --git a/chapter16/docs/16-grammar.md b/chapter16/docs/16-grammar.md index a7f69133..7b611fbf 100644 --- a/chapter16/docs/16-grammar.md +++ b/chapter16/docs/16-grammar.md @@ -3,21 +3,43 @@ ```antlrv4 grammar SimpleLanguage; -program - : statement+ EOF - ; +program : block EOF ; + +block : statement+ ; + statement - : returnStatement - | structDeclaration - | declStatement - | blockStatment - | expressionStatement + : '{' block '}' + | returnStatement | ifStatement | whileStatement | breakStatement - | continueStatment + | continueStatement | metaStatement + | structDeclaration + | expressionStatement + ; + + +returnStatement : 'return' expression ';' ; + +ifStatement : 'if' '(' expression ')' statement ('else' statement)? ; + +whileStatement : 'while' '(' expression ')' statement ; + +breakStatement : 'break' ';' ; + +continueStatement : 'continue' ';' ; + +metaStatement : '#showGraph' ';' ; + +structDeclaration : 'struct' IDENTIFIER '{' block '}' ; + +expressionStatement + : type IDENTIFIER ';' + | type IDENTIFIER '=' expression ';' + | IDENTIFIER '=' expression ';' + | expression ; PRIMTYPE @@ -35,64 +57,18 @@ PRIMTYPE | 'bool' ; -field - : PRIMTYPE IDENTIFIER ';' - | structName IDENTIFIER ('?')? ';' - ; - -fields - : field+ - ; - -structDeclaration - : 'struct' IDENTIFIER '{' fields '}' - ; - -whileStatement - : 'while' '(' expression ')' statement - ; - -breakStatement - : 'break' ';' - ; - -continueStatement - : 'continue' ';' +type + : PRIMTYPE + | typeName '?'? + | typeName nestedArray+ ; -ifStatement - : 'if' '(' expression ')' statement ('else' statement)? - ; - -metaStatement - : '#showGraph' ';' - ; - -expressionStatement - : IDENTIFIER '=' expression ';' - | fieldExpression '=' expression ';' - ; - -blockStatement - : '{' statement+ '}' - ; +nestedArray : '?'? '[]'* ; -structName - : IDENTIFIER - ; +typeName : IDENTIFIER ; -declStatement - : PRIMTYPE IDENTIFIER '=' expression ';' - | structName IDENTIFIER ('?')? '=' expression ';' - ; -returnStatement - : 'return' expression ';' - ; - -expression - : bitWiseExpression - ; +expression : bitWiseExpression ; bitWiseExpression : comparisonExpression ( '&' | '|' | '^' ) comparisonExpression)* @@ -117,39 +93,40 @@ multiplicativeExpression unaryExpression : ('-') unaryExpression | '!' unaryExpression - | primaryExpression - ; - -newExpression - : 'new' IDENTIFIER blockStatement - : 'new' IDENTIFIER '[' expression ']' - ; - -fieldExpression - : primaryExpresson '.' IDENTIFIER - | primaryExpresson '[' expression ']' + | primaryExpression postAssign ; primaryExpression - : IDENTIFIER - | INTEGER_LITERAL + : INTEGER_LITERAL + | FLOAT_LITERAL + | '(' expression ')' | 'true' | 'false' | 'null' | newExpression - | '(' expression ')' - | fieldExpression + | IDENTIFIER ; -INTEGER_LITERAL - : [1-9][0-9]* - | [0] +newExpression + : 'new' IDENTIFIER [ '{' block '}' ] + | 'new' IDENTIFIER '[' expression ']' ; -IDENTIFIER - : NON_DIGIT (NON_DIGIT | DIGIT)* +postAssign : postFix [ '=' expression ] | [ '#' ]; + +postFix + : '.' IDENTIFIER postFix + | '[' expression ']' postFix + ; + + +IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; + +INTEGER_LITERAL + : [1-9]DIGIT* + | [0] ; NON_DIGIT: [a-zA-Z_]; -DEC_DIGIT: [0-9]; +DIGIT: [0-9]; ``` diff --git a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java index 728aaca7..bdd14de6 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java @@ -147,8 +147,8 @@ public class Parser { _xScopes.push(_scope); // Enter a new scope for the initial control and arguments _scope.push(); - _scope.define(ScopeNode.CTRL, Type.CONTROL , new CProjNode(START, 0, ScopeNode.CTRL).peephole()); - _scope.define(ScopeNode.ARG0, TypeInteger.BOT, new ProjNode(START, 1, ScopeNode.ARG0).peephole()); + _scope.define(ScopeNode.CTRL, Type.CONTROL , new CProjNode(START, 0, ScopeNode.CTRL).peephole(), false); + _scope.define(ScopeNode.ARG0, TypeInteger.BOT, new ProjNode(START, 1, ScopeNode.ARG0).peephole(), false); // Parse whole program parseBlock(); @@ -212,12 +212,13 @@ public class Parser { * type IDENTIFIER ; * */ - private Field parseField() { - Type t = type(); - if( t==null ) - throw errorSyntax("Requires a field type, found '"+_lexer.getAnyNextToken()+"'"); - return require(Field.make(requireId().intern(),ALIAS++,t),";"); - } + //private Field parseField() { + // Type t = type(); + // if( t==null ) + // throw errorSyntax("Requires a field type, found '"+_lexer.getAnyNextToken()+"'"); + // boolean xfinal = match("!"); + // return require(Field.make(requireId().intern(),t,ALIAS++,xfinal),";"); + //} /** * Parse a struct declaration, and return the following statement. @@ -232,20 +233,35 @@ public class Parser { Type t = TYPES.get(typeName); if( t!=null && !(t instanceof TypeMemPtr tmp && tmp._obj._fields==null) ) throw errorSyntax("struct '" + typeName + "' cannot be redefined"); - // Parse a collection of fields - ArrayList fields = new ArrayList<>(); + // A Block scope parse, and inspect the scope afterwards for fields. + _scope.push(); require("{"); - while (!peek('}') && !_lexer.isEOF()) { - Field field = parseField(); - if (fields.contains(field)) throw errorSyntax("Field '" + field + "' already defined in struct '" + typeName + "'"); - fields.add(field); - } + while (!peek('}') && !_lexer.isEOF()) + parseStatement(); require("}"); + // Grab the declarations and build fields + HashMap decls = _scope._decls.lastElement(); + HashMap idxs = _scope._idxs.lastElement(); + BitSet finals = _scope._finals; + + Field[] fs = new Field[decls.size()]; int i=0; + for( String fname : decls.keySet() ) { + int idx = idxs.get(fname); + boolean isFinal = finals.get(idx); + Type decl = decls.get(fname); + fs[i++] = Field.make(fname,decl,ALIAS++,isFinal); + if( isFinal ) throw Utils.TODO(); // Track write-once + if( _scope.in(idx)._type != decl.makeInit() ) throw Utils.TODO(); // Track non-zero init + } + // Done with scope + _scope.pop(); + // Build and install the TypeStruct - TypeStruct ts = TypeStruct.make(typeName, fields.toArray(new Field[fields.size()])); + TypeStruct ts = TypeStruct.make(typeName, fs); TYPES.put(typeName, TypeMemPtr.make(ts)); START.addMemProj(ts, _scope); // Insert memory edges - return parseStatement(); + require(";"); + return null; } /** @@ -429,43 +445,33 @@ public class Parser { return null; } - /** - * Parses an expression statement or a declaration statement where type is a struct - * - *
-     *      name;         // Error
-     * type name;         // Define name with default initial value
-     * type name = expr;  // Define name with given   initial value
-     *      name = expr;  // Reassign existing
-     *             expr   // Something else
-     * 
- * @return an expression {@link Node}, never {@code null} + /** Parse: name [=expr] */ - private Node parseExpressionStatement() { + private Node parseAsgn(Type t, boolean xfinal) { + boolean isDecl = t!=null; // Having a type is a declaration, missing one is updating a prior name int old = _lexer._position; - Type t = type(); String name = requireId(); Node expr; - if( match(";") ) { // Assign a default value - // No type and no expr is an error + if( match(";") || peek(',') ) { + // Bare "name" is not allowed if( t==null ) throw errorSyntax("expression"); expr = new ConstantNode(t.makeInit()).peephole(); - } else if( match("=") ) { // Assign "= expr;" - expr = require(parseExpression(), ";"); - } else { // Neither, so just a normal expression parse + } else if( !match("=") ) { // Something else _lexer._position = old; - return require(parseExpression(),";"); - } + return null; + } else + expr = parseExpression(); // Defining a new variable vs updating an old one - if( t != null ) { - if( _scope.define(name,t,expr) == null ) - throw error("Redefining name '" + name + "'"); - } else { + if( !isDecl ) { // Assigning over an existing name + // Lookup if( _scope.lookup(name)==null ) throw error("Undefined name '" + name + "'"); + if( _scope.lookupFinal(name) ) + throw error("Cannot reassign final '"+name+"'"); t = _scope.lookupDeclaredType(name); } + // Auto-widen int to float if( expr._type instanceof TypeInteger && t instanceof TypeFloat ) expr = new ToFloatNode(expr).peephole(); @@ -478,7 +484,50 @@ public class Parser { // Type is sane if( !e.isa(t) ) throw error("Type " + e.str() + " is not of declared type " + t.str()); - return _scope.update(name,expr); + + + if( isDecl ) { + if( _scope.define(name,t,expr,xfinal) == null ) + throw error("Redefining name '" + name + "'"); + } else + _scope.update(name,expr); + return expr; + } + + /** Parse final: [!]asgn + */ + private Node parseFinal(Type t) { + boolean xfinal = t!=null && match("!"); + return parseAsgn(t,xfinal); + } + + /** + * Parses an expression statement or a declaration statement where type is a struct + * + *
+     * type decl [, decl]*;  // Define many names with the same type
+     * asgn;                 // Assign or load a variable
+     * expr;                 // Something else
+     * name;                 // Bare name is an error
+
+     * 
+ * @return an expression {@link Node}, never {@code null} + */ + private Node parseExpressionStatement() { + Node n; + Type t = type(); + if( t != null ) { + // now parse final [, final]* + n = parseFinal(t); + while( match(",") ) + n = parseFinal(t); + + // Parse "asgn;" which is just "name = expr;" + } else if( ( n = parseAsgn(null,false)) == null ) { + // Something else + n = parseExpression(); + } + return require(n,";"); } // Parse and return a type or null. Valid types always are followed by an diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java index ba99fde8..b46a7ba7 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java @@ -23,6 +23,8 @@ public class SarNode extends Node { public Type compute() { if (in(1)._type instanceof TypeInteger i0 && in(2)._type instanceof TypeInteger i1) { + if( i0 == TypeInteger.ZERO ) + return TypeInteger.ZERO; if( i0.isConstant() && i1.isConstant() ) return TypeInteger.constant(i0.value()>>i1.value()); if( i1.isConstant() ) { diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index 877ae4a4..0e7a5e9b 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -8,7 +8,7 @@ import java.util.*; /** * The Scope node is purely a parser helper - it tracks names to nodes with a - * stack of scopes. + * stack of hashmaps. */ public class ScopeNode extends Node { @@ -24,15 +24,21 @@ public class ScopeNode extends Node { */ public final Stack> _idxs; + /* + * Map input edge to Final bit + */ + public final BitSet _finals; + /** * Map variable names to declared Type */ - final Stack> _decls; + public final Stack> _decls; // A new ScopeNode public ScopeNode() { _idxs = new Stack<>(); _decls= new Stack<>(); + _finals = new BitSet(); _type = Type.BOTTOM; } @@ -89,16 +95,21 @@ public class ScopeNode extends Node { @Override public Node idealize() { return null; } public void push() { _idxs.push(new HashMap<>()); _decls.push(new HashMap<>()); } - public void pop() { popN(_idxs.pop().size()); _decls.pop(); } + public void pop() { + popN(_idxs.pop().size()); + _finals.clear(nIns()); + _decls.pop(); + } /** * Create a new variable name in the current scope */ - public Node define( String name, Type declaredType, Node n ) { + public Node define( String name, Type declaredType, Node n, boolean xfinal ) { HashMap syms = _idxs.lastElement(); _decls.lastElement().put(name,declaredType); if( syms.put(name,nIns()) != null ) return null; // Double define + if( xfinal ) _finals.set(nIns()); // track finals return addDef(n); } @@ -156,6 +167,15 @@ public class ScopeNode extends Node { return null; } + // Return declared type for a variable + public boolean lookupFinal( String name ) { + for( int i=_idxs.size(); i>0; i-- ) { + Integer t = _idxs.get(i-1).get(name); + if( t != null ) return _finals.get(t); + } + throw Utils.TODO(); // Should not reach here + } + /** * Duplicate a ScopeNode; including all levels, up to Nodes. So this is * neither shallow (would dup the Scope but not the internal HashMap diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java index 28e6dd14..6ad81b5c 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java @@ -22,7 +22,9 @@ public class ShlNode extends Node { @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0 && - in(2)._type instanceof TypeInteger i1) { + in(2)._type instanceof TypeInteger i1 ) { + if( i0 == TypeInteger.ZERO ) + return TypeInteger.ZERO; if( i0.isConstant() && i1.isConstant() ) return TypeInteger.constant(i0.value()<>>i1.value()); } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java index 5964e19f..bbeb7fa1 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -43,7 +43,7 @@ public class StartNode extends CFGNode implements MultiNode { String name = Parser.memName(f._alias); Node n = new ProjNode(this, f._alias, name); // No 'compute' until ScopeNode gets typed n._type = args[f._alias]; - scope.define(name, tm_decl, n); + scope.define(name, tm_decl, n, false); } for (int i = 0; i < args.length; i++) if (args[i] == null) diff --git a/chapter16/src/main/java/com/seaofnodes/simple/type/Field.java b/chapter16/src/main/java/com/seaofnodes/simple/type/Field.java index 5e674132..eb49c3af 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/type/Field.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/type/Field.java @@ -12,52 +12,56 @@ public class Field extends Type { // Field name public final String _fname; - // Unique memory alias - public final int _alias; // Type of the field public final Type _type; + // Unique memory alias, not sensibly part of a "type" but very convenient here. + public final int _alias; + // Field must be written to exactly once, no more, no less + public final boolean _final; - private Field(String fname, int alias, Type type ) { + private Field(String fname, Type type, int alias, boolean xfinal ) { super(TFLD); _fname = fname; - _alias = alias; _type = type; + _alias = alias; + _final = xfinal; } // Make with existing alias - public static Field make( String fname, int alias, Type type ) { - return new Field(fname,alias,type).intern(); + public static Field make( String fname, Type type, int alias, boolean xfinal ) { + return new Field(fname,type,alias,xfinal).intern(); } - public static final Field TEST = make("test",-2,TypeInteger.ZERO); + public static final Field TEST = make("test",TypeInteger.ZERO,-2,false); public static void gather(ArrayList ts) { ts.add(TEST); } @Override Field xmeet( Type that ) { Field fld = (Field)that; // Invariant assert _fname.equals(fld._fname); assert _alias==fld._alias; - return make(_fname,_alias,_type.meet(fld._type)); + assert _final==fld._final; + return make(_fname,_type.meet(fld._type),_alias,_final); } @Override - public Field dual() { return make(_fname,_alias,_type.dual()); } + public Field dual() { return make(_fname,_type.dual(),_alias,_final); } @Override public Field glb() { - return make(_fname,_alias,_type.glb()); + return make(_fname,_type.glb(),_alias,_final); } // Override in subclasses - int hash() { return _fname.hashCode() ^ _type.hashCode() ^ _alias; } + int hash() { return _fname.hashCode() ^ _type.hashCode() ^ _alias ^ (_final ? 1024 : 0); } boolean eq(Type t) { Field f = (Field)t; - return _fname.equals(f._fname) && _alias==f._alias && _type==f._type; + return _fname.equals(f._fname) && _type==f._type && _alias==f._alias && _final==f._final; } @Override public StringBuilder print( StringBuilder sb ) { - return _type.print(sb.append(_fname).append(":").append(_alias).append(" : ")); + return _type.print(sb.append(_final?"!":"").append(_fname).append(":").append(_alias).append(" : ")); } @Override public String str() { return _fname; } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeStruct.java index abfb8a67..fbbb814f 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeStruct.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeStruct.java @@ -42,15 +42,15 @@ public class TypeStruct extends Type { public static TypeStruct makeAry(TypeInteger len, int lenAlias, Type body, int bodyAlias) { assert !(body instanceof TypeMemPtr tmp && !tmp._nil); return make(body.str() + "[]", - Field.make("#" , lenAlias,len ), - Field.make("[]",bodyAlias,body)); + Field.make("#" ,len , lenAlias,true), + Field.make("[]",body,bodyAlias,true)); } // A pair of self-cyclic types private static final TypeStruct S1F = make("S1"); private static final TypeStruct S2F = make("S2"); - public static final TypeStruct S1 = make("S1", new Field[]{ Field.make("a", -1, TypeInteger.BOT), Field.make("s2",-2,TypeMemPtr.make(S2F,false)) }); - private static final TypeStruct S2 = make("S2", new Field[]{ Field.make("b", -3, TypeFloat .BOT), Field.make("s1",-4,TypeMemPtr.make(S1F,false)) }); + public static final TypeStruct S1 = make("S1", new Field[]{ Field.make("a", TypeInteger.BOT, -1, false), Field.make("s2",TypeMemPtr.make(S2F,false),-2, false) }); + private static final TypeStruct S2 = make("S2", new Field[]{ Field.make("b", TypeFloat .BOT, -3, false), Field.make("s1",TypeMemPtr.make(S1F,false),-4, false) }); private static final TypeStruct ARY = makeAry(TypeInteger.BOT,-1,TypeFloat.BOT,-2); diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java index def9aaa6..ec6a0bb4 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -38,10 +38,10 @@ return p-r; struct Bar { int a; int b; -} +}; struct Foo { int x; -} +}; Foo? foo = null; Bar bar = new Bar; bar.a = 1; @@ -55,7 +55,7 @@ return bar.a; @Test public void testExample() { Parser parser = new Parser(""" -struct Vector2D { int x; int y; } +struct Vector2D { int x; int y; }; Vector2D v = new Vector2D; v.x = 1; if (arg) @@ -73,7 +73,7 @@ return v; Parser parser = new Parser(""" struct s0 { int v0; -} +}; s0? v1=null; int v3=v1.zAicm; """); @@ -84,7 +84,7 @@ int v3=v1.zAicm; @Test public void testBug2() { Parser parser = new Parser(""" -struct s0 { int v0; } +struct s0 { int v0; }; arg=0+new s0.0; """); try { parser.parse(); fail(); } @@ -94,7 +94,7 @@ arg=0+new s0.0; @Test public void testLoop() { Parser parser = new Parser(""" -struct Bar { int a; } +struct Bar { int a; }; Bar bar = new Bar; while (arg) { bar.a = bar.a + 2; @@ -103,13 +103,13 @@ while (arg) { return bar.a; """); StopNode stop = parser.parse(false).iterate(); - assertEquals("return Phi(Loop13,0,(Phi_a+2));", stop.toString()); + assertEquals("return Phi(Loop14,0,(Phi_a+2));", stop.toString()); } @Test public void testIf() { Parser parser = new Parser(""" -struct Bar { int a; } +struct Bar { int a; }; Bar bar = new Bar; if (arg) bar = null; bar.a = 1; @@ -122,7 +122,7 @@ return bar.a; @Test public void testIf2() { Parser parser = new Parser(""" -struct Bar { int a; } +struct Bar { int a; }; Bar? bar = null; if (arg) bar = new Bar; bar.a = 1; @@ -135,7 +135,7 @@ return bar.a; @Test public void testIf3() { Parser parser = new Parser(""" -struct Bar { int a; } +struct Bar { int a; }; Bar bar = null; if (arg) bar = null; bar.a = 1; @@ -148,21 +148,21 @@ return bar.a; @Test public void testIfOrNull() { Parser parser = new Parser(""" -struct Bar { int a; } +struct Bar { int a; }; Bar? bar = new Bar; if (arg) bar = null; if( bar ) bar.a = 1; return bar; """); StopNode stop = parser.parse(false).iterate(); - assertEquals("return Phi(Region33,(*void)Phi(Region20,null,Bar),null);", stop.toString()); + assertEquals("return Phi(Region34,(*void)Phi(Region21,null,Bar),null);", stop.toString()); } @Test public void testIfOrNull2() { Parser parser = new Parser( """ -struct Bar { int a; } +struct Bar { int a; }; Bar? bar = new Bar; if (arg) bar = null; int rez = 3; @@ -171,13 +171,13 @@ else bar.a = 1; return rez; """); StopNode stop = parser.parse(false).iterate(); - assertEquals("return Phi(Region39,4,3);", stop.toString()); + assertEquals("return Phi(Region40,4,3);", stop.toString()); } @Test public void testWhileWithNullInside() { Parser parser = new Parser(""" -struct s0 {int v0;} +struct s0 {int v0;}; s0? v0 = new s0; int ret = 0; while(arg) { @@ -197,7 +197,7 @@ return ret; Parser parser = new Parser(""" struct s0 { int v0; -} +}; s0? v1=new s0; s0? v1; v1=new s0; @@ -214,7 +214,7 @@ v1=new s0; struct Iter { int x; int len; -} +}; Iter i = new Iter; i.len = arg; int sum=0; @@ -225,7 +225,7 @@ while( i.x < i.len ) { return sum; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop18,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", stop.toString()); + assertEquals("return Phi(Loop20,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", stop.toString()); } @@ -234,7 +234,7 @@ return sum; @Test public void test1() { Parser parser = new Parser(""" -struct s0 {int v0;} +struct s0 {int v0;}; s0 ret = new s0; while(arg) { s0 v0 = new s0; @@ -246,13 +246,13 @@ while(arg) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop13,s0,Phi(Region37,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop14,s0,Phi(Region38,s0,Phi_ret));", stop.toString()); } @Test public void test2() { Parser parser = new Parser(""" -struct s0 {int v0;} +struct s0 {int v0;}; s0 ret = new s0; s0 v0 = new s0; while(arg) { @@ -264,14 +264,14 @@ while(arg) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop17,s0,Phi(Region38,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop18,s0,Phi(Region39,s0,Phi_ret));", stop.toString()); } @Test public void test3() { Parser parser = new Parser(""" -struct s0 {int v0;} +struct s0 {int v0;}; s0 ret = new s0; while(arg < 10) { s0 v0 = new s0; @@ -281,7 +281,7 @@ while(arg < 10) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop13,s0,Phi(Region35,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop14,s0,Phi(Region36,s0,Phi_ret));", stop.toString()); } @Test @@ -289,7 +289,7 @@ return ret; Parser parser = new Parser(""" struct s0 { int f0; -} +}; if(0>=0) return new s0; return new s0; int v0=null.f0; @@ -319,7 +319,7 @@ if(0) { Parser parser = new Parser(""" struct s0 { int f0; -} +}; if(0) return 0; else return new s0; if(new s0.f0) return 0; @@ -346,7 +346,7 @@ return 0; @Test public void testBug7() { Parser parser = new Parser(""" -struct s0 { int f0; } +struct s0 { int f0; }; s0 v0 = new s0; while(v0.f0) {} s0 v1 = v0; diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java index 5f9f9cac..4998d78f 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java @@ -337,7 +337,7 @@ return primeCount; public void testAntiDeps1() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v=new S; v.f = 2; int i=new S.f; @@ -355,7 +355,7 @@ return i; public void testAntiDeps2() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v = new S; v.f = arg; S t = new S; @@ -369,14 +369,14 @@ if (arg) { return i; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region40,.f,0);", stop.toString()); + assertEquals("return Phi(Region41,.f,0);", stop.toString()); } @Test public void testAntiDeps3() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v0 = new S; S? v1; if (arg) v1 = new S; @@ -396,7 +396,7 @@ return v0; public void testAntiDeps4() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v = new S; v.f = arg; S t = new S; @@ -413,7 +413,7 @@ return i; public void testAntiDeps5() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v = new S; while(1) { while(arg+1) { arg=arg-1; } @@ -430,7 +430,7 @@ return v; public void testAntiDeps6() { Parser parser = new Parser( """ -struct s { int v; } +struct s { int v; }; s ptr=new s; while( -arg ) ptr = new s; @@ -445,7 +445,7 @@ while(1) public void testAntiDeps7() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v = new S; S t = new S; int i = v.f; @@ -463,7 +463,7 @@ return i; public void testAntiDeps8() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v = new S; S t = new S; while(arg) { @@ -476,14 +476,14 @@ while(arg) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop17,arg,Phi(Region42,.f,0));", stop.toString()); + assertEquals("return Phi(Loop18,arg,Phi(Region43,.f,0));", stop.toString()); } @Test public void testAntiDeps9() { Parser parser = new Parser( """ -struct S { int f; } +struct S { int f; }; S v = new S; S t = new S; if (arg) { @@ -500,8 +500,8 @@ return v; @Test public void testExample2() { Parser parser = new Parser( - """ -struct S { int f; } +""" +struct S { int f; }; S v = new S; int i = arg; while (arg > 0) { diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java index 416aba31..a95a6155 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java @@ -23,7 +23,7 @@ return 3.14; public void testLinkedList0() { Parser parser = new Parser( """ -struct LLI { LLI? next; int i; } +struct LLI { LLI? next; int i; }; LLI? head = null; while( arg ) { LLI x = new LLI; @@ -42,7 +42,7 @@ return head.next.i; public void testLinkedList1() { Parser parser = new Parser( """ -struct LLI { LLI? next; int i; } +struct LLI { LLI? next; int i; }; LLI? head = null; while( arg ) { LLI x = new LLI; @@ -65,8 +65,8 @@ return next.i; public void testCoRecur() { Parser parser = new Parser( """ -struct int0 { int i; flt0? f; } -struct flt0 { flt f; int0? i; } +struct int0 { int i; flt0? f; }; +struct flt0 { flt f; int0? i; }; int0 i0 = new int0; i0.i = 17; flt0 f0 = new flt0; @@ -83,7 +83,7 @@ return f0.i.f.i.i; public void testNullRef0() { Parser parser = new Parser( """ -struct N { N next; int i; } +struct N { N? next; int i; }; N n = new N; return n.next; """); @@ -95,7 +95,7 @@ return n.next; public void testNullRef1() { Parser parser = new Parser( """ -struct N { N next; int i; } +struct N { N next; int i; }; N n = new N; n.next = new N; return n.next; @@ -108,7 +108,7 @@ return n.next; public void testNullRef2() { Parser parser = new Parser( """ -struct N { N next; int i; } +struct N { N next; int i; }; N n = new N; n.next = null; return n.next; @@ -121,7 +121,7 @@ return n.next; public void testNullRef3() { Parser parser = new Parser( """ -struct N { N next; int i; } +struct N { N next; int i; }; N n = new N; n.i = 3.14; return n.i; @@ -145,7 +145,7 @@ struct S{}; public void testForwardRef0() { Parser parser = new Parser( """ -struct S1 { S2 s; } +struct S1 { S2 s; }; return new S2; """); try { parser.parse().iterate(); fail(); } @@ -156,8 +156,8 @@ return new S2; public void testForwardRef1() { Parser parser = new Parser( """ -struct S1 { S2? s; } -struct S2 { int x; } +struct S1 { S2? s; }; +struct S2 { int x; }; return new S1.s=new S2; """); StopNode stop = parser.parse().iterate(); @@ -168,8 +168,8 @@ return new S1.s=new S2; public void testcheckNull() { Parser parser = new Parser( """ -struct I {int i;} -struct P {I pi;} +struct I {int i;}; +struct P {I pi;}; P p1 = new P; P p2 = new P; p2.pi = new I; diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java index d49d7ede..7adc5b10 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java @@ -10,12 +10,23 @@ import java.nio.charset.StandardCharsets; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +/** + struct S { + int x; // default init of 0 + S? x; // default init of null + int !x; // final init required in constructor + S x; // init required in constructor + int !x=17; // final init done now, not in constructor + S x = ...;// init done now, not in constructor + }; + + */ + public class Chapter16Test { @Test public void testJig() { - Parser parser = new Parser( -""" + Parser parser = new Parser(""" return 3.14; """); StopNode stop = parser.parse().iterate(); @@ -24,11 +35,60 @@ return 3.14; } @Test - public void testBasicFinal() { + public void testMulti0() { Parser parser = new Parser( """ +int x, y; +return x+y; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("return 0;", stop.toString()); + assertEquals(0L, Evaluator.evaluate(stop, 0)); + } + @Test + public void testMulti1() { + Parser parser = new Parser( +""" +int x=2, y=x+1; +return x+y; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("return 5;", stop.toString()); + assertEquals(5L, Evaluator.evaluate(stop, 0)); + } + + @Test + public void testFinal0() { + Parser parser = new Parser( +""" +int !x=2; +x=3; +return x; +"""); + try { parser.parse().iterate(); fail(); } + catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); } + } + + @Test + public void testFinal1() { + Parser parser = new Parser( +""" +int !x=2, y=3; +if( arg ) { int x = y; x = x*x; y=x; } // Shadow final x +return y; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("return Phi(Region18,9,3);", stop.toString()); + assertEquals(3L, Evaluator.evaluate(stop, 0)); + assertEquals(9L, Evaluator.evaluate(stop, 1)); + } + + + @Test + public void testStructFinal() { + Parser parser = new Parser(""" struct Point { int !x, !y; } -Point p = new P { x=3; y=4; } +Point p = new Point { x=3; y=4; } return p; """); StopNode stop = parser.parse().iterate(); diff --git a/chapter16/src/test/java/com/seaofnodes/simple/TypeTest.java b/chapter16/src/test/java/com/seaofnodes/simple/TypeTest.java index cb45a0d7..6f7409cd 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/TypeTest.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/TypeTest.java @@ -13,11 +13,11 @@ public class TypeTest { @Test public void testTypeAdHoc() { TypeStruct s1 = TypeStruct.make("s1", new Field[]{ - Field.make("a",-1, TypeInteger.BOT), - Field.make("b",-2, TypeInteger.BOT) }); + Field.make("a", TypeInteger.BOT,-1, false), + Field.make("b", TypeInteger.BOT,-2, false) }); TypeStruct s2 = TypeStruct.make("s2", new Field[]{ - Field.make("a",-3, TypeInteger.BOT), - Field.make("b",-4, TypeInteger.BOT) }); + Field.make("a", TypeInteger.BOT,-3, false), + Field.make("b", TypeInteger.BOT,-4, false) }); Assert.assertEquals(s1, s1.glb()); Assert.assertNotEquals(s1, s1.dual()); Assert.assertEquals(s1, s1.dual().glb()); -- cgit v1.2.3