summaryrefslogtreecommitdiff
path: root/chapter25/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src/main/java')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/print/JSViewer.java24
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java30
2 files changed, 34 insertions, 20 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/print/JSViewer.java b/chapter25/src/main/java/com/seaofnodes/simple/print/JSViewer.java
index 156f1fe9..a9f6bfd4 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/print/JSViewer.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/print/JSViewer.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.print;
+import com.seaofnodes.graph.GraphJson;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
@@ -11,8 +12,10 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.net.URI;
import java.util.Collection;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;
+import java.util.UUID;
import static com.seaofnodes.simple.codegen.CodeGen.CODE;
public class JSViewer implements AutoCloseable {
@@ -28,7 +31,9 @@ public class JSViewer implements AutoCloseable {
// WebSocket to the browser for display
static SimpleWebSocket SERVER;
- static int N; // Dot frames
+ static long N; // Snapshot step within this compilation
+ static String COMP;
+ static final SimpleGraphAdapter GRAPH = new SimpleGraphAdapter();
JSViewer() throws Exception {
// Launch server; handshake
@@ -60,6 +65,7 @@ public class JSViewer implements AutoCloseable {
System.out.println(src);
try {
N=0;
+ COMP = UUID.randomUUID().toString();
// Use parser scope, xscope when building views
CodeGen code = new CodeGen(src);
SHOW = true;
@@ -93,10 +99,19 @@ public class JSViewer implements AutoCloseable {
return;
boolean midParse = CODE._phase == CodeGen.Phase.Parse;
Stack<ScopeNode> xScopes = midParse ? CODE.P._xScopes : null;
+ var roots = new ArrayList<Node>();
+ roots.add(CODE._stop);
+ if( midParse ) {
+ roots.add(CODE.P._scope);
+ roots.addAll(xScopes);
+ }
+ long step = N++;
+ var snap = GRAPH.snap(COMP, step, roots.toArray(Node[]::new));
+ int pos = midParse ? CODE.P.pos() : -1;
Collection<Node> all = GraphVisualizer.findAll(xScopes, CODE._stop, midParse ? CODE.P._scope: null);
SB sb = new SB();
- sb.p("digraph view_").p(N++).p(" {\n").ii();
+ sb.p("digraph view_").p(step).p(" {\n").ii();
if( midParse )
sb.i().p("// POS: ").p(CODE.P.pos()).nl();
@@ -139,11 +154,10 @@ public class JSViewer implements AutoCloseable {
sb.p("}\n").di();
- // Tell client another DOT frame
+ // Send the model and its current DOT rendering as one playback frame.
String dot = sb.toString();
- System.out.println(dot);
try {
- SERVER.put(dot);
+ SERVER.put(GraphJson.frame(snap, pos, dot));
} catch( IOException ioe ) {
try { SERVER.close();} catch( IOException ignored ){}
}
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java b/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java
index d7fa8bf2..ae500879 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java
@@ -139,7 +139,7 @@ class SimpleWebSocket extends ServerSocket {
for( int i=0; i<len; i++ )
_str[i] = (byte)(rawget() ^ _key[i & 3]);
- return new String(_str,0,len);
+ return new String(_str,0,len,StandardCharsets.UTF_8);
}
// Client closes
case 8: return null;
@@ -155,24 +155,24 @@ class SimpleWebSocket extends ServerSocket {
}
}
- // Classic put to browser client. No encoding.
+ // Server text frames are UTF-8 and unmasked.
public void put(String msg) throws IOException {
- int len = msg.length();
+ byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
+ int len = bytes.length;
+ _out.write(129); // FIN, opcode 1 - whole text message
if( len <= 125 ) {
- _out.write(129); // FIN, opcode 1 - whole text message
_out.write(len);
- for( int i=0; i<msg.length(); i++ )
- _out.write(msg.charAt(i));
- return;
+ } else if( len <= 65535 ) {
+ _out.write(126);
+ _out.write(len>>>8);
+ _out.write(len&255);
+ } else {
+ _out.write(127);
+ for( int shift = 56; shift >= 0; shift -= 8 )
+ _out.write((int)((long)len >>> shift) & 255);
}
- if( len > 65535 )
- throw Utils.TODO("MOAR LENGTH");
- _out.write(129); // FIN, opcode 1 - whole text message
- _out.write(126); // Length is 16b
- _out.write(len>>>8);
- _out.write(len&255);
- for( int i=0; i<msg.length(); i++ )
- _out.write(msg.charAt(i));
+ _out.write(bytes);
+ _out.flush();
}
@Override public void close() throws IOException {