forked from jasder/antlr
initial add of graph-structured stack. some unit tests. only got singleton merge in there.
This commit is contained in:
parent
ea7037dd2d
commit
bdb2aa9d15
|
@ -0,0 +1,51 @@
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class ArrayNode extends GraphNode {
|
||||||
|
public final GraphNode[] parents;
|
||||||
|
public final String[] payloads;
|
||||||
|
|
||||||
|
public ArrayNode(SingletonNode a) {
|
||||||
|
this.parents = new GraphNode[] {a.parent};
|
||||||
|
this.payloads = new String[] {a.payload};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayNode(GraphNode[] parents, String[] payloads) {
|
||||||
|
this.parents = parents;
|
||||||
|
this.payloads = payloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ( !(o instanceof ArrayNode) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.hashCode() != o.hashCode() ) {
|
||||||
|
return false; // can't be same if hash is different
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayNode a = (ArrayNode)o;
|
||||||
|
if ( payloads.length != a.payloads.length ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<payloads.length; i++) {
|
||||||
|
if ( !payloads[i].equals(a.payloads[i]) ) return false;
|
||||||
|
if ( !parents[i].equals(a.parents[i]) ) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Arrays.toString(payloads)+":"+id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
public abstract class GraphNode {
|
||||||
|
public static final SingletonNode EMPTY = new SingletonNode(null,"$");
|
||||||
|
|
||||||
|
public static int globalNodeCount = 0;
|
||||||
|
public final int id;
|
||||||
|
|
||||||
|
public GraphNode() {
|
||||||
|
id = globalNodeCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GraphNode merge(GraphNode a, GraphNode b) { // dispatch
|
||||||
|
if ( a instanceof SingletonNode && b instanceof SingletonNode ) {
|
||||||
|
return mergeSingletons((SingletonNode) a, (SingletonNode) b);
|
||||||
|
}
|
||||||
|
if ( a instanceof SingletonNode ) {
|
||||||
|
a = new ArrayNode((SingletonNode)a);
|
||||||
|
}
|
||||||
|
if ( b instanceof SingletonNode ) {
|
||||||
|
b = new ArrayNode((SingletonNode)b);
|
||||||
|
}
|
||||||
|
return mergeArrays((ArrayNode) a, (ArrayNode) b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GraphNode mergeSingletons(SingletonNode a, SingletonNode b) {
|
||||||
|
if ( a == EMPTY ) return a;
|
||||||
|
if ( b == EMPTY ) return b;
|
||||||
|
if ( a.payload.equals(b.payload) ) {
|
||||||
|
GraphNode parent = merge(a.parent, b.parent);
|
||||||
|
if ( parent == a.parent ) return a;
|
||||||
|
if ( parent == b.parent ) return b;
|
||||||
|
// new joined parent so create new singleton pointing to it
|
||||||
|
return new SingletonNode(parent, a.payload);
|
||||||
|
}
|
||||||
|
else { // a != b payloads differ
|
||||||
|
// parents differ, join them; nothing to reuse
|
||||||
|
if ( !a.parent.equals(b.parent) ) {
|
||||||
|
ArrayNode joined =
|
||||||
|
new ArrayNode(new GraphNode[]{a.parent, b.parent},
|
||||||
|
new String[] {a.payload, b.payload});
|
||||||
|
return joined;
|
||||||
|
}
|
||||||
|
// parents are equal, pick left one as parent to reuse
|
||||||
|
GraphNode parent = a.parent;
|
||||||
|
ArrayNode joined =
|
||||||
|
new ArrayNode(new GraphNode[]{parent, parent},
|
||||||
|
new String[] {a.payload, b.payload});
|
||||||
|
return joined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GraphNode mergeArrays(ArrayNode a, ArrayNode b) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toDOT(GraphNode a) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
public class SingletonNode extends GraphNode {
|
||||||
|
public final GraphNode parent;
|
||||||
|
public final String payload;
|
||||||
|
|
||||||
|
public SingletonNode(GraphNode parent, String payload) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ( !(o instanceof SingletonNode) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.hashCode() != o.hashCode() ) {
|
||||||
|
return false; // can't be same if hash is different
|
||||||
|
}
|
||||||
|
|
||||||
|
SingletonNode s = (SingletonNode)o;
|
||||||
|
return payload.equals(s.payload) && parent.equals(s.parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return payload+":"+id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TestGraphNodes extends TestCase {
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
GraphNode.globalNodeCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testBothEmpty() {
|
||||||
|
GraphNode a = GraphNode.EMPTY;
|
||||||
|
GraphNode b = GraphNode.EMPTY;
|
||||||
|
GraphNode r = GraphNode.merge(a, b);
|
||||||
|
assertEquals("$:0", r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testLeftEmpty() {
|
||||||
|
GraphNode a = GraphNode.EMPTY;
|
||||||
|
GraphNode b = createSingleton(GraphNode.EMPTY, "b");
|
||||||
|
GraphNode r = GraphNode.merge(a, b);
|
||||||
|
assertEquals("$:0", r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testRightEmpty() {
|
||||||
|
GraphNode a = GraphNode.EMPTY;
|
||||||
|
GraphNode b = createSingleton(GraphNode.EMPTY, "b");
|
||||||
|
GraphNode r = GraphNode.merge(a, b);
|
||||||
|
assertEquals("$:0", r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testSameSingleTops() {
|
||||||
|
GraphNode a1 = createSingleton(GraphNode.EMPTY, "a");
|
||||||
|
GraphNode a2 = createSingleton(GraphNode.EMPTY, "a");
|
||||||
|
GraphNode r = GraphNode.merge(a1, a2);
|
||||||
|
assertEquals("a:1", r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testDiffSingleTops() {
|
||||||
|
GraphNode a1 = createSingleton(GraphNode.EMPTY, "a");
|
||||||
|
GraphNode a2 = createSingleton(GraphNode.EMPTY, "b");
|
||||||
|
GraphNode r = GraphNode.merge(a1, a2);
|
||||||
|
assertEquals("[a, b]:3", r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void test_ax_ax_id() {
|
||||||
|
GraphNode x = createSingleton(GraphNode.EMPTY, "x");
|
||||||
|
GraphNode a1 = createSingleton(x, "a");
|
||||||
|
GraphNode a2 = createSingleton(x, "a");
|
||||||
|
GraphNode r = GraphNode.merge(a1, a2);
|
||||||
|
assertEquals("a:2", r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void test_ax_ax_eq() {
|
||||||
|
GraphNode x1 = createSingleton(GraphNode.EMPTY, "x");
|
||||||
|
GraphNode x2 = createSingleton(GraphNode.EMPTY, "x");
|
||||||
|
GraphNode a1 = createSingleton(x1, "a");
|
||||||
|
GraphNode a2 = createSingleton(x2, "a");
|
||||||
|
GraphNode r = GraphNode.merge(a1, a2);
|
||||||
|
assertEquals("a:3", r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SingletonNode createSingleton(GraphNode parent, String payload) {
|
||||||
|
SingletonNode a = new SingletonNode(parent, payload);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue