summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2024-10-14 10:31:40 -0700
committerCliff Click <cliffc@acm.org>2024-10-21 08:52:01 -0700
commit94e557c9de68e7b3f5595d75e7330b63df76c323 (patch)
treef16fca7e4b49f82f98f73c073b7495abedafd195
parent475f66adc7c1c9f1cd479c4492999eae4c060c5b (diff)
downloadSimple-94e557c9de68e7b3f5595d75e7330b63df76c323.tar.gz
Simple-94e557c9de68e7b3f5595d75e7330b63df76c323.zip
final fields and multi defs
`int x,y;` works `int !x = 3;` works Structs defs are statements, require a trailing `;`
-rw-r--r--chapter16/docs/16-grammar.md143
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/Parser.java133
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java2
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java4
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java4
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java2
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/type/Field.java30
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/type/TypeStruct.java8
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java54
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java26
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java26
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java68
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/TypeTest.java8
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 ;
* </pre>
*/
- 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<Field> 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<String,Type> decls = _scope._decls.lastElement();
+ HashMap<String,Integer> 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
- *
- * <pre>
- * 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
- * </pre>
- * @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
+ *
+ * <pre>
+ * 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
+
+ * </pre>
+ * @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<HashMap<String, Integer>> _idxs;
+ /*
+ * Map input edge to Final bit
+ */
+ public final BitSet _finals;
+
/**
* Map variable names to declared Type
*/
- final Stack<HashMap<String, Type>> _decls;
+ public final Stack<HashMap<String, Type>> _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<String,Integer> 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/ShrNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java
index 16d78ebf..856c2114 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java
@@ -22,7 +22,9 @@ public class ShrNode 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<Type> 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());