summaryrefslogtreecommitdiff
path: root/graph/src
diff options
context:
space:
mode:
Diffstat (limited to 'graph/src')
-rw-r--r--graph/src/main/java/com/seaofnodes/graph/GraphCapture.java26
-rw-r--r--graph/src/main/java/com/seaofnodes/graph/GraphEvent.java16
-rw-r--r--graph/src/main/java/com/seaofnodes/graph/GraphJson.java14
-rw-r--r--graph/src/main/java/com/seaofnodes/graph/GraphObserver.java3
-rw-r--r--graph/src/main/java/com/seaofnodes/graph/GraphSnapshot.java7
5 files changed, 60 insertions, 6 deletions
diff --git a/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java b/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java
index 1a9c8c62..966dd701 100644
--- a/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java
+++ b/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java
@@ -12,8 +12,10 @@ public abstract class GraphCapture<N> extends GraphObserver<N> {
private String _comp;
private GraphSocket _server;
private final ArrayList<Peep> _peeps = new ArrayList<>();
+ private final BitSet _pre = new BitSet();
private long _next, _step;
private boolean _off = true;
+ private boolean _err;
protected GraphCapture(GraphAdapter<N> graph) { _graph = graph; }
@@ -32,8 +34,13 @@ public abstract class GraphCapture<N> extends GraphObserver<N> {
_next = _step = 0;
_server = server;
_off = false;
+ _err = false;
try {
compile(src);
+ } catch( RuntimeException e ) {
+ // Type checking already emitted its diagnostic with the final graph.
+ if( !_err ) throw e;
+ System.err.println(e);
} finally {
_off = true;
try {
@@ -68,6 +75,10 @@ public abstract class GraphCapture<N> extends GraphObserver<N> {
// Buffer until we know that this attempt (or a nested one) made progress.
// Include n explicitly: parse-time nodes need not have any uses yet.
p.pre = snap(n, true);
+ if( p.up == 0 ) {
+ _pre.clear();
+ for( var node : p.pre.nodes() ) _pre.set(node.id());
+ }
}
@Override public void after(N n, N repl, boolean applied) {
@@ -106,6 +117,13 @@ public abstract class GraphCapture<N> extends GraphObserver<N> {
emit(snap(null, false), pos(), new GraphEvent(GraphEvent.Kind.PHASE, 0, 0, phase, 0, 0, new int[0]));
}
+ @Override public void error(N node, String msg) {
+ if( _off ) return;
+ _err = true;
+ emit(snap(node, false), pos(), new GraphEvent(GraphEvent.Kind.ERROR, 0, 0,
+ phase(), _graph.ref(node), 0, new int[0], new int[0], msg));
+ }
+
private GraphEvent evt(Peep p, GraphEvent.Kind kind, int repl) {
return new GraphEvent(kind, p.id, p.up, p.phase, _graph.id(p.node), repl, p.near.stream().toArray());
}
@@ -137,6 +155,14 @@ public abstract class GraphCapture<N> extends GraphObserver<N> {
private void emit(GraphSnapshot snap, int pos, GraphEvent evt) {
if( _off ) return;
+ if( evt.up() != 0 ) {
+ // Nested peepholes can create userless results before their caller
+ // returns. These belong to the peep, not the parser's expression.
+ int[] temps = snap.nodes().stream().mapToInt(GraphSnapshot.Node::id)
+ .filter(id -> !_pre.get(id)).toArray();
+ evt = new GraphEvent(evt.kind(), evt.peep(), evt.up(), evt.phase(),
+ evt.node(), evt.repl(), evt.near(), temps);
+ }
// Assign steps on emission; attempts without progress do not consume frames.
snap = new GraphSnapshot(snap.ver(), _comp, _step++, snap.roots(), snap.scope(), snap.nodes(), snap.groups());
try {
diff --git a/graph/src/main/java/com/seaofnodes/graph/GraphEvent.java b/graph/src/main/java/com/seaofnodes/graph/GraphEvent.java
index 7d889b21..d52213c2 100644
--- a/graph/src/main/java/com/seaofnodes/graph/GraphEvent.java
+++ b/graph/src/main/java/com/seaofnodes/graph/GraphEvent.java
@@ -2,9 +2,19 @@ package com.seaofnodes.graph;
/** IDs refer to nodes in this compilation; near may include nodes since deleted. */
public record GraphEvent(Kind kind, long peep, long up, String phase,
- int node, int repl, int[] near) {
- public enum Kind { BEFORE, RETURN, APPLY, PHASE }
+ int node, int repl, int[] near, int[] temps, String msg) {
+ public enum Kind { BEFORE, RETURN, APPLY, PHASE, ERROR }
- public GraphEvent { near = near.clone(); }
+ public GraphEvent(Kind kind, long peep, long up, String phase, int node, int repl, int[] near, int[] temps) {
+ this(kind, peep, up, phase, node, repl, near, temps, null);
+ }
+
+ public GraphEvent(Kind kind, long peep, long up, String phase, int node, int repl, int[] near) {
+ this(kind, peep, up, phase, node, repl, near, new int[0]);
+ }
+
+ public GraphEvent { near = near.clone(); temps = temps.clone(); }
@Override public int[] near() { return near.clone(); }
+ // Created inside an enclosing peep; not yet returned to the parser.
+ @Override public int[] temps() { return temps.clone(); }
}
diff --git a/graph/src/main/java/com/seaofnodes/graph/GraphJson.java b/graph/src/main/java/com/seaofnodes/graph/GraphJson.java
index 004f6827..bcdd46cc 100644
--- a/graph/src/main/java/com/seaofnodes/graph/GraphJson.java
+++ b/graph/src/main/java/com/seaofnodes/graph/GraphJson.java
@@ -29,7 +29,18 @@ public class GraphJson {
if( i > 0 ) sb.append(',');
sb.append(near[i]);
}
- sb.append("]}");
+ sb.append("],\"temps\":[");
+ int[] temps = evt.temps();
+ for( int i = 0; i < temps.length; i++ ) {
+ if( i > 0 ) sb.append(',');
+ sb.append(temps[i]);
+ }
+ sb.append(']');
+ if( evt.msg() != null ) {
+ sb.append(",\"msg\":");
+ str(sb, evt.msg());
+ }
+ sb.append('}');
return sb.append('}').toString();
}
@@ -53,6 +64,7 @@ public class GraphJson {
str(sb, node.type());
sb.append(",\"kind\":");
str(sb, node.kind().name());
+ if( node.folding() ) sb.append(",\"folding\":true");
sb.append(",\"edges\":[");
var edges = node.edges();
for( int j = 0; j < edges.size(); j++ ) {
diff --git a/graph/src/main/java/com/seaofnodes/graph/GraphObserver.java b/graph/src/main/java/com/seaofnodes/graph/GraphObserver.java
index 24879fe2..4a57c816 100644
--- a/graph/src/main/java/com/seaofnodes/graph/GraphObserver.java
+++ b/graph/src/main/java/com/seaofnodes/graph/GraphObserver.java
@@ -14,6 +14,9 @@ public abstract class GraphObserver<N> {
/** A completed compiler phase. */
public abstract void phase(String phase);
+ /** A compiler diagnostic and its node, or null for an error without a node. */
+ public void error(N node, String msg) {}
+
/** A rule consulted a dependency, even if already registered or adjacent. */
public void dep(N node, N def) {}
}
diff --git a/graph/src/main/java/com/seaofnodes/graph/GraphSnapshot.java b/graph/src/main/java/com/seaofnodes/graph/GraphSnapshot.java
index b53f3211..df1e8837 100644
--- a/graph/src/main/java/com/seaofnodes/graph/GraphSnapshot.java
+++ b/graph/src/main/java/com/seaofnodes/graph/GraphSnapshot.java
@@ -21,9 +21,12 @@ public record GraphSnapshot(int ver, String comp, long step,
/** Header ID, enclosing group (zero outside), and directly owned node IDs. */
public record Group(int id, int par, int[] nodes) { }
- /** IDs are stable within one compilation. Labels and types are plain text. */
+ /** IDs are stable; labels/types are plain text. folding means pending inline cleanup. */
public record Node(int id, String label, String type, Kind kind,
- ArrayList<Edge> edges, Projection proj) {
+ ArrayList<Edge> edges, Projection proj, boolean folding) {
+ public Node(int id, String label, String type, Kind kind, ArrayList<Edge> edges, Projection proj) {
+ this(id,label,type,kind,edges,proj,false);
+ }
public Node {
edges = new ArrayList<>(edges);
}