summaryrefslogtreecommitdiff
path: root/chapter22/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'chapter22/src/main/java/com')
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/Parser.java205
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/Var.java21
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java26
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/Node.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java89
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/sys/sys.java25
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp10
7 files changed, 267 insertions, 117 deletions
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
index d7f5087d..d44ea46e 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
@@ -4,7 +4,7 @@ import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.print.GraphVisualizer;
import com.seaofnodes.simple.type.*;
-import java.text.ParseException;
+
import java.util.*;
/**
@@ -81,31 +81,11 @@ public class Parser {
ScopeNode _breakScope; // Merge all the while-breaks here
FunNode _fun; // Current function being parsed
- // Mapping from a type name to a Type. The string name matches
+ // Mapping from a primitive name to a Type. The string name matches
// `type.str()` call. No TypeMemPtrs are in here, because Simple does not
// have C-style '*ptr' references.
- public static HashMap<String, Type> TYPES;
-
- // Mapping from a type name to the constructor for a Type.
- public final HashMap<String, StructNode> INITS;
-
-
- public Parser(CodeGen code, TypeInteger arg) {
- _code = code;
- _scope = new ScopeNode();
- _continueScope = _breakScope = null;
- ZERO = con(TypeInteger.ZERO).keep();
- NIL = con(Type.NIL).keep();
- XCTRL= new XCtrlNode().peephole().keep();
- TYPES = defaultTypes();
- INITS = new HashMap<>();
- }
-
- @Override
- public String toString() { return _lexer.toString(); }
-
- public static HashMap<String, Type> defaultTypes() {
- return new HashMap<>() {{
+ public static final HashMap<String, Type> PRIMS =
+ new HashMap<>() {{
put("bool",TypeInteger.U1 );
put("byte",TypeInteger.U8 );
put("f32" ,TypeFloat .F32);
@@ -123,8 +103,25 @@ public class Parser {
put("val" ,Type.TOP); // Marker type, indicates type inference
put("var" ,Type.BOTTOM); // Marker type, indicates type inference
}};
+
+
+ // Mapping from a type name to the constructor for a Type.
+ public final HashMap<String, StructNode> INITS;
+
+
+ public Parser(CodeGen code, TypeInteger arg) {
+ _code = code;
+ _scope = new ScopeNode();
+ _continueScope = _breakScope = null;
+ ZERO = con(TypeInteger.ZERO).keep();
+ NIL = con(Type.NIL).keep();
+ XCTRL= new XCtrlNode().peephole().keep();
+ INITS = new HashMap<>();
}
+ @Override
+ public String toString() { return _lexer.toString(); }
+
// Debugging utility to find a Node by index
public Node f(int nid) { return _code.f(nid); }
@@ -132,19 +129,32 @@ public class Parser {
private <N extends Node> N ctrl(N n) { return _scope.ctrl(n); }
public void parse() {
+ _scope.define(ScopeNode.CTRL, Type.CONTROL , false, null, null);
+ _scope.define(ScopeNode.MEM0, TypeMem.BOT , false, null, null);
+ _scope.define(ScopeNode.ARG0, TypeInteger.BOT, false, null, null);
+
+ ctrl(XCTRL);
+ _scope.mem(new MemMergeNode(false));
+
+ // Parse the "sys" import
//_parse(com.seaofnodes.simple.sys.sys.SYS);
+
+ _code._stop.popUntil(0); // Delete return from parsing sys import
+
+ // Parse program text
_parse(_code._src);
+
+ // Clean up and reset
+ _scope.kill();
+ for( StructNode init : INITS.values() )
+ init.unkeep().kill();
+ INITS.clear();
+ _code._stop.peephole();
}
private void _parse(String src) {
_lexer = new Lexer(src);
_xScopes.push(_scope);
- _scope.define(ScopeNode.CTRL, Type.CONTROL , false, null, _lexer);
- _scope.define(ScopeNode.MEM0, TypeMem.BOT , false, null, _lexer);
- _scope.define(ScopeNode.ARG0, TypeInteger.BOT, false, null, _lexer);
-
- ctrl(XCTRL);
- _scope.mem(new MemMergeNode(false));
// Parse whole program, as-if function header "{ int arg -> body }"
parseFunctionBody(_code._main,loc(),"arg");
@@ -172,11 +182,6 @@ public class Parser {
// Clean up and reset
_xScopes.pop();
- _scope.kill();
- for( StructNode init : INITS.values() )
- init.unkeep().kill();
- INITS.clear();
- stop.peephole();
}
/**
@@ -212,7 +217,7 @@ public class Parser {
// Pre-call the function from Start, with worse-case arguments. This
// represents all the future, yet-to-be-parsed functions calls and
// external calls.
- _scope.push(ScopeNode.Kind.Function);
+ _scope.push(ScopeNode.Kind.Function,null);
ctrl(fun); // Scope control from function
// Private mem alias tracking per function
MemMergeNode mem = new MemMergeNode(true);
@@ -271,7 +276,7 @@ public class Parser {
*/
private Node parseBlock(ScopeNode.Kind kind) {
// Enter a new scope
- _scope.push(kind);
+ _scope.push(kind,null);
Node last = ZERO;
while (!peek('}') && !_lexer.isEOF())
last = parseStatement();
@@ -290,8 +295,7 @@ public class Parser {
* @return a {@link Node} or {@code null}
*/
private Node parseStatement() {
- if( false ) return null;
- else if (matchx("return") ) return parseReturn();
+ if( matchx("return") ) return parseReturn();
else if (matchx("if") ) return parseIf();
else if (matchx("while") ) return parseWhile();
else if (matchx("for") ) return parseFor();
@@ -339,7 +343,7 @@ public class Parser {
// }
// }
require("(");
- _scope.push(ScopeNode.Kind.Block); // Scope for the index variables
+ _scope.push(ScopeNode.Kind.Block,null); // Scope for the index variables
if( !match(";") ) // Can be empty init "for(;test;next) body"
parseDeclarationStatement(); // Non-empty init
Node rez = parseLooping(true);
@@ -406,7 +410,7 @@ public class Parser {
// Our current scope is the body Scope
ctrl(ifT.unkeep()); // set ctrl token to ifTrue projection
_scope.addGuards(ifT,pred.unkeep(),false); // Up-cast predicate
- parseStatement(); // Parse loop body
+ parseStatement().isKill(); // Parse loop body
_scope.removeGuards(ifT);
// Merge the loop bottom into other continue statements
@@ -631,7 +635,7 @@ public class Parser {
// outside the constructor need to check the final bit.
if( _scope.in(def._idx)._type!=Type.TOP && def._final &&
// Inside a constructor, final assign is OK, outside nope
- !(_scope.inCon() && def._idx >= _scope._lexSize.last()) )
+ !(_scope.inConstructor() && def._idx >= _scope._lexSize.last()) )
throw error("Cannot reassign final '"+name+"'");
// Lift expression, based on type
@@ -673,9 +677,17 @@ public class Parser {
* exprAsgn = var '=' exprAsgn | expr
*/
private Node parseDeclarationStatement() {
+ int old = pos();
Type t = type();
if( t == null )
return require(parseAsgn(),";");
+ // Ambiguous leading type then doing a type/class static field lookup.
+ // "T var" - declare a variable of type T
+ // "T.fld" - lookup field "fld" in type T
+ if( peek('.') ) {
+ pos(old);
+ return require(parseAsgn(),";");
+ }
// now parse var['=' asgnexpr] in a loop
Node n = parseDeclaration(t);
@@ -717,14 +729,17 @@ public class Parser {
t = expr._type;
if( !xfinal ) t = t.glb(); // Widen if not final
}
- if( t instanceof TypeFunPtr && expr._type instanceof TypeFunPtr tfp && tfp.isConstant() )
- _code.link(tfp)._name = name;
+ // expr is a constant function
+ if( t instanceof TypeFunPtr && expr._type instanceof TypeFunPtr tfp && tfp.isConstant() ) {
+ if( expr instanceof ExternNode ) t = expr._type; // Upgrade declared type to exact function
+ else _code.link(tfp)._name = name; // Assign debug name to Simple function
+ }
} else {
// Need an expression to infer the type.
// Also, if not-null then need an initializing expression.
// Allowed in a class def, because type/init will happen in the constructor.
- if( (inferType || (t instanceof TypeNil tn && !tn.nullable() )) && !_scope.inCon() )
+ if( (inferType || (t instanceof TypeNil tn && !tn.nullable() )) && !_scope.inDeclarationQ() )
throw errorSyntax("=expression");
// Initial value for uninitialized struct fields.
expr = switch( t ) {
@@ -759,44 +774,61 @@ public class Parser {
/**
* Parse a struct declaration, and return the following statement.
- * Only allowed in top level scope.
- * Structs cannot be redefined.
+ * Structs cannot be redefined, but can be nested.
*
- * @return The statement following the struct
+ * @return zero
*/
private Node parseStruct() {
if (_xScopes.size() > 1) throw error("struct declarations can only appear in top level scope");
+ // "struct" already parsed, so expect the struct name next.
String typeName = requireId();
- Type t = TYPES.get(typeName);
- if( t!=null && !(t instanceof TypeMemPtr tmp && tmp.isFRef() ) )
- throw error("struct '" + typeName + "' cannot be redefined");
// A Block scope parse, and inspect the scope afterward for fields.
- _scope.push(ScopeNode.Kind.Constructor);
+ _scope.push(ScopeNode.Kind.DeclarationQ,typeName);
require("{");
while (!peek('}') && !_lexer.isEOF())
- parseStatement();
+ parseStatement().isKill();
// Grab the declarations and build fields and a Struct
int lexlen = _scope._lexSize.last();
int varlen = _scope._vars._len;
- StructNode s = new StructNode();
- Ary<Field> fs = new Ary<>(Field.class);
+ StructNode inst = new StructNode();
+ StructNode clz = new StructNode();
+ Ary<Field> fs = new Ary<>(Field.class); // Struct fields
+ Ary<Field> cs = new Ary<>(Field.class); // Class fields
for( int i=lexlen; i<varlen; i++ ) {
- Var v = _scope._vars.at(i);
- if( !v.isFRef() ) { // Promote to outer scope, not defined here
- s.addDef(_scope.in(i));
- fs.push( Field.make( v._name, v.type(), _code.getALIAS(), v._final ) );
- }
+ Var v = _scope.var(i);
+ if( v.isFRef() ) continue; // Promote to outer scope, not defined here
+ var flds = v._final && v.type().isConstant() ? cs : fs;
+ var stru = v._final && v.type().isConstant() ? clz : inst;
+ // Declare field, gather field init
+ flds.push(Field.make(v._name,v.type(),_code.getALIAS(),v._final));
+ stru.addDef(_scope.in(i));
}
TypeStruct ts = s._ts = TypeStruct.make(typeName, fs.asAry());
- TYPES.put(typeName, TypeMemPtr.make(ts));
+ //PRIMS.put(typeName, TypeMemPtr.make(ts));
INITS.put(typeName,s.peephole().keep());
+
+ //String clzName = typeName + ".clz"; // Class name
+ //PRIMS.put(clzName, TypeMemPtr.make(TypeStruct.make(clzName, cs.asAry())));
// Done with struct/block scope
require("}");
require(";");
_scope.pop();
- return ZERO;
+ // Make a pointer to the class fields
+
+ // ISSUE: LOOKUP EXPECTS TO FIND INSTANCE FIELDS FOR 'NEW' OR TYPE DECLS:
+ // Vector2D v = ...;
+ // Type for 'v' includes fields 'x,y'.
+ // Whereas: Vector2D.PI lookups up via the class struct.
+ // So e.g. add a hidden " decl" field that gets the instance fields.
+ cs.push(Field.make(" decl",TypeMemPtr.make(ts),-1,true));
+
+ TypeMemPtr tclz = TypeMemPtr.make(TypeStruct.make(typeName, cs.asAry()));
+ ConstantNode nclz = con(tclz);
+ // Define the constant clazz fields
+ _scope.define(typeName,tclz, true, nclz, true, loc());
+ return nclz;
}
@@ -815,13 +847,15 @@ public class Parser {
String tname = _lexer.matchId();
if( tname==null ) return null;
- // Convert the type name to a type.
- Type t0 = TYPES.get(tname);
+ // Convert the type name to a type, either user instance type or a primitive.
+ Type t0 = _scope.lookupInstance(tname);
+ if( t0 == null ) t0 = PRIMS.get(tname);
// No new types as keywords
if( t0 == null && KEYWORDS.contains(tname) )
return posT(old1);
if( t0 == Type.BOTTOM || t0 == Type.TOP ) return t0; // var/val type inference
- Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.makeFRef(tname)) :t0; // Null: assume a forward ref type
+ // Still no type found? Assume forward reference
+ Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.makeFRef(tname)) : t0; // Null: assume a forward ref type
// Nest arrays and '?' as needed
Type t2 = t1;
while( true ) {
@@ -843,13 +877,12 @@ public class Parser {
int old2 = pos();
match("!");
String id = _lexer.matchId();
- if( !(peek(',') || peek(';') || match("->")) )
- return posT(old1);
- pos(old2); // Reset lexer to reparse
- if( id==null )
+ if( !(peek(',') || peek(';') || match("->")) || id==null )
return posT(old1); // Reset lexer to reparse
+ pos(old2); // Reset lexer to reparse
// Yes a forward ref, so declare it
- TYPES.put(tname,t1);
+ _scope.define(tname, t1, true, XCTRL, true, null);
+ // Return the (array, final) type
return t2;
}
@@ -858,14 +891,15 @@ public class Parser {
if( t instanceof TypeMemPtr tmp && tmp.notNull() )
throw error("Arrays of reference types must always be nullable");
String tname = "["+t.str()+"]";
- Type ta = TYPES.get(tname);
+ Type ta = PRIMS.get(tname);
if( ta != null ) return (TypeMemPtr)ta;
// Need make an array type.
TypeStruct ts = TypeStruct.makeAry(TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS());
assert ts.str().equals(tname);
TypeMemPtr tary = TypeMemPtr.make(ts);
- TYPES.put(tname,tary);
- return tary;
+ //PRIMS.put(tname,tary);
+ //return tary;
+ throw Utils.TODO();
}
// A function type is `{ type... -> type }` or `{ type }`.
@@ -1183,7 +1217,7 @@ public class Parser {
if( hasConstructor ) {
idx = _scope.nIns();
// Push a scope, and pre-assign all struct fields.
- _scope.push(ScopeNode.Kind.Block);
+ _scope.push(ScopeNode.Kind.Block,null);
Lexer loc = loc();
for( int i=0; i<fs.length; i++ )
_scope.define(fs[i]._fname, fs[i]._type, fs[i]._final, s.in(i)._type==Type.TOP ? con(Type.BOTTOM) : s.in(i), loc);
@@ -1282,18 +1316,24 @@ public class Parser {
throw error( "Expected "+(name=="#" || name=="[]" ? "array" : "reference")+" but found " + expr._type.str() );
}
- // Sanity check field name for existing
- TypeMemPtr tmp = (TypeMemPtr)TYPES.get(ptr._obj._name);
- if( tmp == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr + "'");
- TypeStruct base = tmp._obj;
+ // Find the field from the Type. Lookup in the base object field names.
+ TypeStruct base = ptr._obj;
+ if( base.isFRef() ) {
+ //ptr = _scope.lookupInstance(base._name);
+ //base = ptr._obj;
+ throw Utils.TODO();
+ }
int fidx = base.find(name);
- if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
+ if( fidx == -1 ) { // No such field!
+ throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
+ // TODO: ch22 allow class field lookups
+ }
// Get field type and layout offset from base type and field index fidx
Field f = base._fields[fidx]; // Field from field index
Type tf = f._type;
if( tf instanceof TypeMemPtr ftmp && ftmp.isFRef() )
- tf = ftmp.makeFrom(((TypeMemPtr)(TYPES.get(ftmp._obj._name)))._obj);
+ tf = ftmp.makeFrom(((TypeMemPtr)(PRIMS.get(ftmp._obj._name)))._obj);
// Field offset; fixed for structs, computed for arrays
Node off = (name.equals("[]") // If field is an array body
@@ -1453,8 +1493,9 @@ public class Parser {
}
// External linked constant
private Node externDecl( String ex, Type t ) {
- //return new ExternNode(t,ex).peephole();
- throw Utils.TODO();
+ if( t instanceof TypeFunPtr tfp ) // Generic TFP from type parse
+ t = _code.makeFun(tfp._sig,tfp._ret); // Get a FIDX, becomes a constant
+ return new ExternNode(t,ex).peephole();
}
/**
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/Var.java b/chapter22/src/main/java/com/seaofnodes/simple/Var.java
index e71d7ef2..154b99f4 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/Var.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/Var.java
@@ -9,28 +9,33 @@ import com.seaofnodes.simple.type.*;
public class Var {
public final String _name; // Declared name
+ // These fields are not final for forward reference late updates or
+ // promotions.
public int _idx; // index in containing scope
private Type _type; // Declared type
public boolean _final; // Final field
- public Parser.Lexer _loc; // Source location
public boolean _fref; // Forward ref
+ public final boolean _clz; // Is a Simple clazz
+ public Parser.Lexer _loc; // Source location
public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc ) {
- this(idx,name,type,xfinal,loc,false);
+ this(idx,name,type,xfinal,loc,false,false);
}
- public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc, boolean fref) {
+ public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc, boolean clz, boolean fref) {
_idx = idx;
_name = name;
_type = type;
_final = xfinal;
- _loc = loc;
_fref = fref;
+ _clz = clz;
+ _loc = loc;
}
public Type type() {
if( !_type.isFRef() ) return _type;
// Update self to no longer use the forward ref type
- Type def = Parser.TYPES.get(((TypeMemPtr)_type)._obj._name);
- return (_type=_type.meet(def));
+ //Type def = Parser.TYPES.get(((TypeMemPtr)_type)._obj._name);
+ //return (_type=_type.meet(def));
+ throw Utils.TODO();
}
public Type lazyGLB() {
Type t = type();
@@ -45,11 +50,11 @@ public class Var {
assert isFRef() && xfinal;
_type = type;
_final = true;
- _loc = loc;
_fref = false;
+ _loc = loc;
}
@Override public String toString() {
- return _type.toString()+(_final ? " ": " !")+_name;
+ return _type.toString()+(_final ? " ": " !")+(_clz?"@":"")+_name;
}
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java
new file mode 100644
index 00000000..3c3701c7
--- /dev/null
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java
@@ -0,0 +1,26 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.Parser;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.type.TypeFunPtr;
+import java.util.BitSet;
+
+/**
+ A constant with external linkage.
+ */
+
+public class ExternNode extends ConstantNode {
+ public final String _extern;
+ public ExternNode(Type t, String ex) { super(t); _extern = ex; }
+
+ @Override public String label() { return "#"+_con+":"+_extern; }
+ @Override public String glabel() { return _con.gprint(new SB().p("#")).p(":").p(_extern).toString(); }
+ @Override public String uniqueName() { return "Extern_" + _nid; }
+
+ @Override public boolean eq(Node n) { return this==n; }
+
+ @Override int hash() { return _con.hashCode(); }
+
+}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java
index c0c2e606..18a8bc14 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -239,7 +239,7 @@ public abstract class Node implements Cloneable {
// Shortcut for "popping" until n nodes. A "pop" is basically a
// setDef(last,null) followed by lowering the nIns() count.
- void popUntil(int n) {
+ public void popUntil(int n) {
unlock();
while( nIns() > n ) {
Node old_def = _inputs.pop();
@@ -255,9 +255,9 @@ public abstract class Node implements Cloneable {
* code elimination.
*/
public void kill( ) {
+ assert isUnused(); // Has no uses, so it is dead
unlock();
moveDepsToWorklist();
- assert isUnused(); // Has no uses, so it is dead
_type=null; // Flag as dead
while( nIns()>0 ) { // Set all inputs to null, recursively killing unused Nodes
Node old_def = _inputs.removeLast();
@@ -295,6 +295,10 @@ public abstract class Node implements Cloneable {
if( unkeep().isUnused() )
kill();
}
+ public void isKill() {
+ if( isUnused() )
+ kill();
+ }
// Replace self with nnn in the graph, making 'this' go dead
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 38a5d968..eda29915 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -25,9 +25,15 @@ public class ScopeNode extends MemMergeNode {
// Size of each nested lexical scope
public final Ary<Integer> _lexSize;
- // Lexical scope is one of normal Block, constructor or function
- public enum Kind { Block, Constructor, Function };
+ // Lexical scope is typed:
+ // - Block scope - basic block scoping
+ // - Constructor - struct type is defined, and here we give values to all fields
+ // - Declaration - struct is declared, final constant fields defined
+ // - Function - out-of-scope lookups restricted to final constants
+ public enum Kind { Block, Constructor, DeclarationQ, Function };
public final Ary<Kind> _kinds;
+ // Each Constructor scope is named, allowing for nested Type names
+ public final Ary<String> _tnamesQ;
// Extra guards; tested predicates and casted results
private final Ary<Node> _guards;
@@ -38,6 +44,7 @@ public class ScopeNode extends MemMergeNode {
_vars = new Ary<>(Var .class);
_lexSize= new Ary<>(Integer.class);
_kinds = new Ary<>(Kind .class);
+ _tnamesQ = new Ary<>(String .class);
_guards = new Ary<>(Node .class);
}
@@ -49,7 +56,7 @@ public class ScopeNode extends MemMergeNode {
int j=1;
for( int i=0; i<nIns(); i++ ) {
if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
- Var v = _vars.get(i);
+ Var v = _vars.at(i);
sb.append(v.type().print(new SB()));
sb.append(" ");
if( v._final ) sb.append("!");
@@ -71,6 +78,7 @@ public class ScopeNode extends MemMergeNode {
public Node ctrl() { return in(0); }
public MemMergeNode mem() { return (MemMergeNode)in(1); }
+ public Var var(int i) { return _vars.at(i); }
/**
* The ctrl of a ScopeNode is always bound to the currently active
@@ -85,20 +93,23 @@ public class ScopeNode extends MemMergeNode {
public <N extends Node> N ctrl(N n) { return setDef(0,n); }
public Node mem(Node n) { return setDef(1,n); }
- public void push(Kind kind) {
- assert _lexSize._len==_kinds._len;
+ public void push(Kind kind, String tnameQ) {
+ assert _lexSize._len==_kinds._len && _lexSize._len==_tnamesQ._len;
+ assert !(kind==Kind.DeclarationQ && tnameQ==null);
_lexSize.push(_vars.size());
_kinds .push(kind);
+ _tnamesQ .push(tnameQ);
}
// Pop a lexical scope
public void pop() {
- assert _lexSize._len==_kinds._len;
- promote();
+ assert _lexSize._len==_kinds._len && _lexSize._len==_tnamesQ._len;
+ promote(); // Promote forward references to the next outer scope
int n = _lexSize.pop();
_kinds.pop();
- popUntil(n);
- _vars.setLen(n);
+ _tnamesQ.pop();
+ popUntil(n); // Pop off inputs going out of scope
+ _vars.setLen(n); // Pop off variables going out of scope
}
@@ -107,7 +118,7 @@ public class ScopeNode extends MemMergeNode {
public void promote() {
int n = _lexSize.last();
for( int i=n; i<nIns(); i++ ) {
- Var v = _vars.at(i);
+ Var v = var(i);
if( !v.isFRef() ) continue;
if( _lexSize._len==1 )
throw Parser.error("Undefined name '" + v._name + "'",v._loc);
@@ -120,7 +131,15 @@ public class ScopeNode extends MemMergeNode {
}
- public boolean inCon() { return _kinds.last() == Kind.Constructor; }
+ public boolean inConstructor() { return _kinds.last() == Kind.Constructor; }
+ public boolean inDeclarationQ() { return _kinds.last() == Kind.DeclarationQ; }
+ // Nearest enclosing declaration scope name
+ public String declNameQ() {
+ for( int i=_lexSize._len-1; i>=0; i-- )
+ if( _kinds.at(i)==Kind.DeclarationQ )
+ return _tnamesQ.at(i);
+ return null;
+ }
// Is v outside any current function scope?
public boolean outOfFunction( Var v ) {
@@ -134,9 +153,9 @@ public class ScopeNode extends MemMergeNode {
// Find name in reverse, return an index into _vars or -1. Linear scan
// instead of hashtable, but probably doesn't matter until the scan
// typically hits many dozens of variables.
- int find( String name ) {
+ public int find( String name, boolean clz ) {
for( int i=_vars.size()-1; i>=0; i-- )
- if( _vars.at(i)._name.equals(name) )
+ if( var(i)._name.equals(name) && var(i)._clz==clz )
return i;
return -1;
}
@@ -145,10 +164,13 @@ public class ScopeNode extends MemMergeNode {
* Create a new variable name in the current scope
*/
public boolean define( String name, Type declaredType, boolean xfinal, Node init, Parser.Lexer loc ) {
+ return define(name,declaredType,xfinal,init,false,loc);
+ }
+ public boolean define( String name, Type declaredType, boolean xfinal, Node init, boolean clz, Parser.Lexer loc ) {
assert _lexSize.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory
if( _lexSize._len > 0 )
for( int i=_vars.size()-1; i>=_lexSize.last(); i-- ) {
- Var n = _vars.at(i);
+ Var n = var(i);
if( n._name.equals(name) ) {
if( !n.isFRef() ) return false; // Double define
FRefNode fref = (FRefNode)in(n._idx); // Get forward ref
@@ -157,7 +179,7 @@ public class ScopeNode extends MemMergeNode {
setDef(n._idx,fref.addDef(init)); // Set FRef to defined; tell parser also
}
}
- Var v = new Var(nIns(),name,declaredType,xfinal,loc,init==Parser.XCTRL);
+ Var v = new Var(nIns(),name,declaredType,xfinal,loc,clz,init==Parser.XCTRL);
_vars.add(v);
// Creating a forward reference
if( init==Parser.XCTRL )
@@ -179,21 +201,37 @@ public class ScopeNode extends MemMergeNode {
* @return null if not found, or the implementing Node
*/
public Var lookup( String name ) {
- int idx = find(name);
+ int idx = find(name,false);
+ // -1 is missed in all scopes, not found
+ return idx == -1 ? null : update(var(idx),null);
+ }
+
+ /**
+ * Lookup a type name and return the instance TypeMemPtr
+ *
+ * @param name of Type
+ * @return null if not found, or *instance* TypeMemPtr
+ */
+ public TypeMemPtr lookupInstance( String name ) {
+ int idx = find(name,true);
// -1 is missed in all scopes, not found
- return idx == -1 ? null : update(_vars.at(idx),null);
+ if( idx == -1 ) return null;
+ // Class types are always TMPs
+ TypeMemPtr clz = (TypeMemPtr)var(idx).type();
+ // Instance types are always TMPs
+ return (TypeMemPtr)(clz._obj.field(" decl")._type);
}
/**
- * If the name is present in any scope, then redefine else null
+ * Redefine an existing name
*
* @param name Name being redefined
* @param n The node to bind to the name
*/
public void update( String name, Node n ) {
- int idx = find(name);
+ int idx = find(name,false);
assert idx>=0;
- update(_vars.at(idx),n);
+ update(var(idx),n);
}
public Var update( Var v, Node st ) {
@@ -238,6 +276,7 @@ public class ScopeNode extends MemMergeNode {
dup._vars .addAll(_vars );
dup._lexSize.addAll(_lexSize);
dup._kinds .addAll(_kinds );
+ dup._tnamesQ .addAll(_tnamesQ );
dup._guards .addAll(_guards );
// The dup'd guards all need dup'd keepers, to keep proper accounting
// when later removing all guards
@@ -260,7 +299,7 @@ public class ScopeNode extends MemMergeNode {
for( int i=2; i<nIns(); i++ )
// For lazy phis on loops we use a sentinel
// that will trigger phi creation on update
- dup.addDef(loop && !_vars.at(i)._final ? this : in(i));
+ dup.addDef(loop && !var(i)._final ? this : in(i));
return dup;
}
@@ -286,7 +325,7 @@ public class ScopeNode extends MemMergeNode {
if( in(i) != that.in(i) ) { // No need for redundant Phis
// If we are in lazy phi mode we need to a lookup
// by name as it will trigger a phi creation
- Var v = _vars.at(i);
+ Var v = var(i);
Node lhs = this.in(this.update(v,null));
Node rhs = that.in(that.update(v,null));
setDef(i, new PhiNode(v._name, v.type(), r, lhs, rhs).peephole());
@@ -297,7 +336,7 @@ public class ScopeNode extends MemMergeNode {
// Forward refs are copied to the other side, "as if" they were there all along.
public void balanceIf( ScopeNode scope ) {
for( int i = nIns(); i < scope.nIns(); i++ ) {
- Var n = scope._vars.at(i);
+ Var n = scope.var(i);
if( n.isFRef() ) { // RHS has forward refs
_vars.add(n); // Copy to LHS
addDef(scope.in(i));
@@ -329,8 +368,8 @@ public class ScopeNode extends MemMergeNode {
// Fill in the backedge of any inserted Phis
void _endLoop( ScopeNode scope, Node back, Node exit ) {
for( int i=2; i<nIns(); i++ ) {
- if( _vars.at(i)._final ) continue; // Final vars did not get modified in the loop
- if( _vars.at(i).type().isHighOrConst() ) continue; // Cannot lift higher than a constant, so no Phi
+ if( var(i)._final ) continue; // Final vars did not get modified in the loop
+ if( var(i).type().isHighOrConst() ) continue; // Cannot lift higher than a constant, so no Phi
if( back.in(i) != scope ) {
PhiNode phi = (PhiNode)in(i);
assert phi.region()==scope.ctrl() && phi.in(2)==null;
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.java b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.java
new file mode 100644
index 00000000..399e7cb7
--- /dev/null
+++ b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.java
@@ -0,0 +1,25 @@
+package com.seaofnodes.simple.sys;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+
+/** Default included namespaces for Simple.
+
+ You can think of this as {@code #include <stdio.h>} for C or {@code import java.lang.*} for Java.
+ */
+public abstract class sys {
+
+ public static final String SYS;
+
+ static {
+ try {
+ SYS = Files.readString(Path.of("src/main/java/com/seaofnodes/simple/sys/sys.smp"));
+ }
+ catch( Exception e ) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp
new file mode 100644
index 00000000..8c470716
--- /dev/null
+++ b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp
@@ -0,0 +1,10 @@
+// -*- mode: java; -*-
+
+// top-level default import
+struct sys {
+ // libc bindings
+ struct libc {
+ /** https://www.man7.org/linux/man-pages/man2/write.2.html */
+ { i32 u8[] i32 -> i32 } write = "C";
+ };
+};