summaryrefslogtreecommitdiff
path: root/chapter18/src
diff options
context:
space:
mode:
Diffstat (limited to 'chapter18/src')
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java4
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java20
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java1
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java40
5 files changed, 66 insertions, 9 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
index dc8f042a..f1cbf446 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
@@ -182,6 +182,8 @@ public class Parser {
Node oldctrl = ctrl().keep();
Node oldmem = _scope.mem().keep();
FunNode oldfun = _fun;
+ ScopeNode breakScope = _breakScope; _breakScope = null;
+ ScopeNode continueScope = _continueScope; _continueScope = null;
FunNode fun = _fun = (FunNode)peep(new FunNode(loc(),START,sig));
// Once the function header is available, install in linker table -
@@ -245,6 +247,8 @@ public class Parser {
// Function scope ends
_scope.pop();
_fun = oldfun;
+ _breakScope = breakScope;
+ _continueScope = continueScope;
// Reset control and memory to pre-function parsing days
ctrl(oldctrl.unkeep());
_scope.mem(oldmem.unkeep());
@@ -1021,7 +1025,7 @@ public class Parser {
if( n._final )
throw error("Cannot reassign final '"+n._name+"'");
Node expr = n.type() instanceof TypeFloat
- ? peep(new AddFNode(_scope.in(n),con(TypeFloat.constant(-1))))
+ ? peep(new AddFNode(_scope.in(n),con(TypeFloat.constant(delta))))
: zsMask(peep(new AddNode(_scope.in(n),con(delta))),n.type());
_scope.update(n,expr);
return expr;
@@ -1222,7 +1226,7 @@ public class Parser {
if( match(".") ) name = requireId();
else if( match("#") ) name = "#";
else if( match("[") ) name = "[]";
- else if( match("(") ) return require(functionCall(expr),")");
+ else if( match("(") ) return parsePostfix(require(functionCall(expr),")"));
else return expr; // No postfix
if( expr._type==Type.NIL )
@@ -1370,7 +1374,7 @@ public class Parser {
for( Node arg : args )
arg.unkeep();
// Into the call
- CallNode call = (CallNode)new CallNode(args.asAry()).peephole();
+ CallNode call = (CallNode)new CallNode(loc(), args.asAry()).peephole();
// Post-call setup
CallEndNode cend = (CallEndNode)new CallEndNode(call).peephole();
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index bf8f7455..ae968ca1 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -33,11 +33,11 @@ abstract public class BoolNode extends Node {
Type t1 = in(1)._type;
Type t2 = in(2)._type;
// Exactly equals?
+ if( t1.isHigh() || t2.isHigh() )
+ return BOOL.dual();
if( in(1)==in(2) )
// LT fails, both EQ and LE succeed
return this instanceof LT ? TypeInteger.FALSE : TypeInteger.TRUE;
- if( t1.isHigh() || t2.isHigh() )
- return BOOL.dual();
if( t1 instanceof TypeInteger i1 &&
t2 instanceof TypeInteger i2 )
return doOp(i1,i2);
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java
index 6645d69d..6963ff2b 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.CodeGen;
+import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
@@ -11,7 +12,10 @@ import java.util.BitSet;
*/
public class CallNode extends CFGNode {
- public CallNode(Node... nodes) { super(nodes); }
+ // Source location for late reported errors
+ public final Parser.Lexer _loc;
+
+ public CallNode(Parser.Lexer loc, Node... nodes) { super(nodes); _loc = loc; }
@Override
public String label() { return "Call"; }
@@ -115,4 +119,18 @@ public class CallNode extends CFGNode {
assert linked(fun);
}
+ @Override
+ public Parser.ParseException err() {
+ if( !(fptr()._type instanceof TypeFunPtr tfp) )
+ throw Utils.TODO();
+ if( !tfp.notNull() )
+ return Parser.error( "Might be null calling "+tfp, _loc);
+ // Check for args
+ for( int i=0; i<tfp.nargs(); i++ )
+ if( !arg(i+2)._type.isa(tfp.arg(i)) )
+ return Parser.error( "Argument #"+i+" isa "+arg(i+2)._type+", but must be a "+tfp.arg(i), _loc);
+
+ return null;
+ }
+
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
index 9e2cec07..4814539f 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
@@ -81,6 +81,7 @@ public class TypeFunPtr extends TypeNil {
public Type arg(int i) { return _sig._types[i]; }
public long fidxs() { return _fidxs; }
public Type ret() { return _ret; }
+ public int nargs() { return _sig._types.length; }
@Override
int hash() { return Utils.fold(_sig.hashCode() ^ _ret.hashCode() ^ _fidxs ^ super.hash()); }
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
index 75ad301e..545bb546 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
@@ -11,7 +11,9 @@ public class Chapter18Test {
public void testJig() {
CodeGen code = new CodeGen(
"""
-return 0;
+struct S { int i; };
+val newS = { int x -> return new S { i=x; }; };
+return newS(1).i;
""");
code.parse(false).opto().typeCheck().GCM();
assertEquals("return 0;", code._stop.toString());
@@ -115,7 +117,7 @@ var fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(3);
""");
code.parse().opto();
- assertEquals("Stop[ return Phi(Region,{ int -> int #1},{ int -> int #2})( 3); return (Parm_x(null,int)*x); return (Parm_x(null,int)*2); ]", code._stop.toString());
+ assertEquals("Stop[ return Phi(Region,{ int -> int #1},{ int -> int #2})( 3); return (Parm_x($fun,int)*x); return (Parm_x($fun,int)*2); ]", code._stop.toString());
assertEquals("6", Eval2.eval(code, 0));
assertEquals("9", Eval2.eval(code, 1));
}
@@ -133,9 +135,41 @@ return fcn(3);
assertEquals("24", Eval2.eval(code, 4));
}
+ @Test
+ public void testFcn6() {
+ CodeGen code = new CodeGen(
+"""
+struct S { int i; };
+val newS = { int x -> return new S { i=x; }; };
+return newS(1).i;
+""");
+ code.parse(false).opto().typeCheck().GCM();
+ assertEquals("Stop[ return .i; return S; ]", code._stop.toString());
+ assertEquals("1", Eval2.eval(code, 0));
+ }
+
+ // Function break
+ @Test
+ public void testErr1() {
+ CodeGen code = new CodeGen(
+"""
+for(;;) {
+ val f = { ->
+ break;
+ };
+ f();
+ return 2;
+}
+return 1;
+""");
+ try { code.parse().opto(); fail(); }
+ catch( Exception e ) { assertEquals("No active loop for a break or continue",e.getMessage()); }
+ }
+
+
// Mutual recursion. Fails without SCCP to lift the recursive return types.
@Ignore @Test
- public void testFcn6() {
+ public void testFcnMutRec() {
CodeGen code = new CodeGen(
"""
val is_even = { int x -> x ? is_odd (x-1) : true ; };