├── LICENSE ├── README.md ├── RELEASE_NOTES.md ├── pom.xml └── src ├── main └── java │ └── com │ └── paypal │ └── digraph │ └── parser │ ├── GraphEdge.java │ ├── GraphElement.java │ ├── GraphNode.java │ ├── GraphParser.java │ ├── GraphParserException.java │ └── antlr │ ├── DOT.g4 │ ├── DOTBaseListener.java │ ├── DOTLexer.java │ ├── DOTListener.java │ └── DOTParser.java └── test ├── java └── com │ └── paypal │ └── digraph │ └── parser │ ├── ParserTest.java │ └── RunAntlrTestRig.java └── resources ├── test1.dg ├── test2.dg └── test3.dg /LICENSE: -------------------------------------------------------------------------------- 1 | [BSD 3-Clause License] 2 | 3 | Copyright (c) 2017, PayPal Holdings, Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # digraph-parser 2 | 3 | Simple, standalone Java parser for digraph DSL (domain-specific language) in Graphviz DOT syntax. 4 | Available on Maven Central: http://central.maven.org/maven2/com/paypal/digraph/digraph-parser/1.0/ 5 | 6 | [![Maven Central](https://img.shields.io/badge/maven%20central-1.0-brightgreen.svg)](http://search.maven.org/#artifactdetails|com.paypal.digraph|digraph-parser|1.0|) 7 | 8 | See also 9 | * http://www.graphviz.org/ 10 | * http://www.graphviz.org/doc/info/lang.html 11 | * https://github.com/antlr/grammars-v4/tree/master/dot 12 | 13 | #### Usage 14 | ```java 15 | GraphParser parser = new GraphParser(new FileInputStream("src/test/resources/test1.dg")); 16 | Map nodes = parser.getNodes(); 17 | Map edges = parser.getEdges(); 18 | 19 | log("--- nodes:"); 20 | for (GraphNode node : nodes.values()) { 21 | log(node.getId() + " " + node.getAttributes()); 22 | } 23 | 24 | log("--- edges:"); 25 | for (GraphEdge edge : edges.values()) { 26 | log(edge.getNode1().getId() + "->" + edge.getNode2().getId() + " " + edge.getAttributes()); 27 | } 28 | ``` 29 | 30 | For following digraph the program produces output below: 31 | ``` 32 | digraph testgraph 33 | { 34 | xxx [k=v] 35 | yyy [k1=v1 k2=v2] 36 | a -> b 37 | n1 [label="Node 1"]; n2 [label="Node 2"]; 38 | n1 -> n2 [style=dotted label="A dotted edge"] 39 | n1 -> n4 40 | n2 -> n3 41 | n3 -> n5 42 | foo -> { bar baz } [ek=ev] 43 | foo -> bar [fbk=fbv] 44 | n4 -> n5 45 | bar [kk=vv] 46 | bar [kkk=vvv] 47 | } 48 | ``` 49 | 50 | ``` 51 | --- nodes: 52 | a {} 53 | b {} 54 | bar {kk=vv, kkk=vvv} 55 | baz {} 56 | foo {} 57 | n1 {label=Node 1} 58 | n2 {label=Node 2} 59 | n3 {} 60 | n4 {} 61 | n5 {} 62 | xxx {k=v} 63 | yyy {k1=v1, k2=v2} 64 | --- edges: 65 | a->b {} 66 | foo->bar {fbk=fbv, ek=ev} 67 | foo->baz {ek=ev} 68 | n1->n2 {style=dotted, label=A dotted edge} 69 | n1->n4 {} 70 | n2->n3 {} 71 | n3->n5 {} 72 | n4->n5 {} 73 | ``` 74 | 75 | #### Maven dependency 76 | ```xml 77 | 78 | com.paypal.digraph 79 | digraph-parser 80 | 1.0 81 | 82 | ``` 83 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | ### digraph-parser - release notes 2 | 3 | #### 1.0 (16-Jun-2017) 4 | 5 | * Initial open-source release (previously internal PayPal project) 6 | * Support parsing of digraph DSL in Graphviz DOT syntax 7 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.paypal.digraph 6 | digraph-parser 7 | jar 8 | 1.0 9 | digraph-parser 10 | https://github.com/paypal/digraph-parser 11 | Java parser for digraph DSL (Graphviz DOT language) 12 | 13 | 14 | 15 | BSD 3-Clause License 16 | https://opensource.org/licenses/BSD-3-Clause 17 | repo 18 | 19 | 20 | 21 | 22 | 23 | sonatype-nexus-staging 24 | http://oss.sonatype.org/service/local/staging/deploy/maven2 25 | 26 | 27 | sonatype-nexus-snapshots 28 | https://oss.sonatype.org/content/repositories/snapshots 29 | 30 | 31 | 32 | 33 | 34 | Oliver Suciu 35 | PayPal 36 | 37 | 38 | 39 | 40 | scm:git:git@github.com:paypal/digraph-parser.git 41 | scm:git:git@github.com:paypal/digraph-parser.git 42 | git@github.com:paypal/digraph-parser.git 43 | 44 | 45 | 46 | 47 | 48 | org.antlr 49 | antlr4-runtime 50 | 4.2 51 | 52 | 53 | 54 | 55 | junit 56 | junit 57 | 4.11 58 | test 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-compiler-plugin 67 | 68 | 1.5 69 | 1.5 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-jar-plugin 75 | 76 | 77 | 78 | ${project.name}-${project.version}-${maven.build.timestamp} 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-source-plugin 86 | 87 | 88 | attach-sources 89 | 90 | jar 91 | 92 | 93 | 94 | 95 | 96 | org.apache.maven.plugins 97 | maven-javadoc-plugin 98 | 99 | 100 | attach-javadoc 101 | 102 | jar 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/GraphEdge.java: -------------------------------------------------------------------------------- 1 | /* 2 | [BSD 3-Clause License] 3 | 4 | Copyright (c) 2017, PayPal Holdings, Inc. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.paypal.digraph.parser; 33 | 34 | public class GraphEdge extends GraphElement 35 | { 36 | public GraphEdge(String id, GraphNode node1, GraphNode node2) { 37 | super(id); 38 | mNode1 = node1; 39 | mNode2 = node2; 40 | } 41 | 42 | public GraphNode getNode1() { 43 | return mNode1; 44 | } 45 | 46 | public GraphNode getNode2() { 47 | return mNode2; 48 | } 49 | 50 | protected GraphNode mNode1; 51 | protected GraphNode mNode2; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/GraphElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | [BSD 3-Clause License] 3 | 4 | Copyright (c) 2017, PayPal Holdings, Inc. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.paypal.digraph.parser; 33 | 34 | import java.util.HashMap; 35 | import java.util.Map; 36 | 37 | public class GraphElement 38 | { 39 | public GraphElement(String id) { 40 | mId = id; 41 | } 42 | 43 | public void setAttribute(String key, Object value) { 44 | mAttrs.put(key, value); 45 | } 46 | 47 | public void setAttributes(Map attrs) { 48 | mAttrs.putAll(attrs); 49 | } 50 | 51 | public String getId() { 52 | return mId; 53 | } 54 | 55 | public Object getAttribute(String key) { 56 | return mAttrs.get(key); 57 | } 58 | 59 | public Map getAttributes() { 60 | return mAttrs; 61 | } 62 | 63 | public String toString() { 64 | return getClass().getSimpleName() + "-" + mId + mAttrs; 65 | } 66 | 67 | protected String mId; 68 | protected Map mAttrs = new HashMap(); 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/GraphNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | [BSD 3-Clause License] 3 | 4 | Copyright (c) 2017, PayPal Holdings, Inc. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.paypal.digraph.parser; 33 | 34 | public class GraphNode extends GraphElement 35 | { 36 | public GraphNode(String id) { 37 | super(id); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/GraphParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | [BSD 3-Clause License] 3 | 4 | Copyright (c) 2017, PayPal Holdings, Inc. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.paypal.digraph.parser; 33 | 34 | import java.io.InputStream; 35 | import java.util.BitSet; 36 | import java.util.Map; 37 | import java.util.TreeMap; 38 | import java.util.TreeSet; 39 | 40 | import org.antlr.v4.runtime.ANTLRInputStream; 41 | import org.antlr.v4.runtime.BaseErrorListener; 42 | import org.antlr.v4.runtime.CommonTokenStream; 43 | import org.antlr.v4.runtime.DefaultErrorStrategy; 44 | import org.antlr.v4.runtime.InputMismatchException; 45 | import org.antlr.v4.runtime.Parser; 46 | import org.antlr.v4.runtime.RecognitionException; 47 | import org.antlr.v4.runtime.Recognizer; 48 | import org.antlr.v4.runtime.Token; 49 | import org.antlr.v4.runtime.atn.ATNConfigSet; 50 | import org.antlr.v4.runtime.dfa.DFA; 51 | import org.antlr.v4.runtime.misc.IntervalSet; 52 | import org.antlr.v4.runtime.misc.NotNull; 53 | import org.antlr.v4.runtime.misc.Nullable; 54 | import org.antlr.v4.runtime.tree.ParseTree; 55 | import org.antlr.v4.runtime.tree.ParseTreeWalker; 56 | import org.antlr.v4.runtime.tree.TerminalNode; 57 | 58 | import com.paypal.digraph.parser.antlr.DOTBaseListener; 59 | import com.paypal.digraph.parser.antlr.DOTLexer; 60 | import com.paypal.digraph.parser.antlr.DOTParser; 61 | import com.paypal.digraph.parser.antlr.DOTParser.A_listContext; 62 | import com.paypal.digraph.parser.antlr.DOTParser.IdContext; 63 | 64 | public class GraphParser 65 | { 66 | private Map mNodeMap = new TreeMap(); 67 | private Map mEdgeMap = new TreeMap(); 68 | private String mGraphId; 69 | private String mErrMsg; 70 | 71 | public GraphParser(InputStream is) throws GraphParserException { 72 | DOTLexer lexer = null; 73 | DOTParser parser = null; 74 | try { 75 | lexer = new DOTLexer(new ANTLRInputStream(is)); 76 | lexer.addErrorListener(new ErrorListener()); 77 | 78 | parser = new DOTParser(new CommonTokenStream(lexer)); 79 | parser.setErrorHandler(new ExceptionErrorStrategy()); 80 | parser.addErrorListener(new ErrorListener()); 81 | 82 | ParseTree tree = parser.graph(); 83 | ParseTreeWalker.DEFAULT.walk(new NodeListener(), tree); 84 | ParseTreeWalker.DEFAULT.walk(new EdgeListener(), tree); 85 | } 86 | catch (Throwable t) { 87 | if (mErrMsg != null) throw new GraphParserException(mErrMsg, t); 88 | if (lexer != null) { 89 | mErrMsg = "at line " + lexer.getLine() + ":" + lexer.getCharPositionInLine(); 90 | throw new GraphParserException(mErrMsg, t); 91 | } 92 | throw new GraphParserException(t); 93 | } 94 | 95 | if (mErrMsg != null) throw new GraphParserException(mErrMsg); 96 | } 97 | 98 | public Map getNodes() { 99 | return mNodeMap; 100 | } 101 | 102 | public Map getEdges() { 103 | return mEdgeMap; 104 | } 105 | 106 | public String getGraphId() { 107 | return mGraphId; 108 | } 109 | 110 | /* 111 | * NodeListener 112 | */ 113 | private class NodeListener extends DOTBaseListener 114 | { 115 | Map nodeAttrs = new TreeMap(); 116 | 117 | /*@Override*/ 118 | public void enterGraph(@NotNull DOTParser.GraphContext ctx) { 119 | if (ctx.id() != null) mGraphId = ctx.id().getText(); 120 | } 121 | 122 | /*@Override*/ 123 | public void exitGraph(@NotNull DOTParser.GraphContext ctx) { 124 | // no-op 125 | } 126 | 127 | /*@Override*/ 128 | public void enterNode_id(@NotNull DOTParser.Node_idContext ctx) { 129 | String nodeId = ctx.id().getText(); 130 | GraphNode node = mNodeMap.get(nodeId); 131 | if (node == null) { 132 | node = new GraphNode(nodeId); 133 | mNodeMap.put(nodeId, node); 134 | } 135 | node.setAttributes(nodeAttrs); 136 | } 137 | 138 | /*@Override*/ 139 | public void exitNode_id(@NotNull DOTParser.Node_idContext ctx) { 140 | // no-op 141 | } 142 | 143 | /*@Override*/ 144 | public void enterNode_stmt(@NotNull DOTParser.Node_stmtContext ctx) { 145 | populateAttributes(ctx.attr_list(), nodeAttrs); 146 | } 147 | 148 | /*@Override*/ 149 | public void exitNode_stmt(@NotNull DOTParser.Node_stmtContext ctx) { 150 | nodeAttrs.clear(); 151 | } 152 | } 153 | 154 | /* 155 | * EdgeListener 156 | */ 157 | private class EdgeListener extends DOTBaseListener 158 | { 159 | GraphCtx graphCtx = new GraphCtx(null); 160 | EdgeCtx edgeCtx; 161 | 162 | /*@Override*/ 163 | public void enterNode_id(@NotNull DOTParser.Node_idContext ctx) { 164 | String nodeId = ctx.id().getText(); 165 | graphCtx.addNode(nodeId); 166 | } 167 | 168 | /*@Override*/ 169 | public void exitNode_id(@NotNull DOTParser.Node_idContext ctx) { 170 | // no-op 171 | } 172 | 173 | /*@Override*/ 174 | public void enterSubgraph(@NotNull DOTParser.SubgraphContext ctx) { 175 | // enter new nested subgraph ctx 176 | graphCtx = new GraphCtx(graphCtx); 177 | } 178 | 179 | /*@Override*/ 180 | public void exitSubgraph(@NotNull DOTParser.SubgraphContext ctx) { 181 | // leave nested ctx, pop previous parent ctx 182 | graphCtx = graphCtx.parent; 183 | } 184 | 185 | /*@Override*/ 186 | public void enterEdge_stmt(@NotNull DOTParser.Edge_stmtContext ctx) { 187 | // enter new nested edge ctx 188 | edgeCtx = new EdgeCtx(edgeCtx, new GraphCtx(graphCtx), new GraphCtx(graphCtx), ctx.attr_list()); 189 | graphCtx = edgeCtx.src; // point to src, next node/subgraph populates it 190 | } 191 | 192 | /*@Override*/ 193 | public void exitEdge_stmt(@NotNull DOTParser.Edge_stmtContext ctx) { 194 | addEdges(edgeCtx.src.graph, edgeCtx.dest.graph, edgeCtx.attrs); 195 | 196 | // leave nested ctx, pop previous parent ctx 197 | edgeCtx = edgeCtx.parent; 198 | graphCtx = graphCtx.parent; 199 | } 200 | 201 | /*@Override*/ 202 | public void enterEdgeop(@NotNull DOTParser.EdgeopContext ctx) { 203 | addEdges(edgeCtx.src.graph, edgeCtx.dest.graph, edgeCtx.attrs); 204 | 205 | if (edgeCtx.srcFlag) { 206 | // pointing to src, shift to populate dest 207 | graphCtx = edgeCtx.dest; 208 | edgeCtx.srcFlag = false; 209 | } 210 | else { 211 | // pointing to dest already, shift src/dest for next edgeop 212 | edgeCtx.src = edgeCtx.dest; 213 | edgeCtx.dest = new GraphCtx(graphCtx.parent); 214 | graphCtx = edgeCtx.dest; 215 | } 216 | } 217 | 218 | /*@Override*/ 219 | public void exitEdgeop(@NotNull DOTParser.EdgeopContext ctx) { 220 | // no-op 221 | } 222 | 223 | private void addEdges(NodeIdSet srcSet, NodeIdSet destSet, Map attrs) { 224 | for (String src : srcSet) { 225 | for (String dest : destSet) { 226 | addEdge(src, dest, attrs); 227 | } 228 | } 229 | } 230 | 231 | private void addEdge(String nodeId1, String nodeId2, Map attrs) { 232 | String edgeId = nodeId1 + "-" + nodeId2; 233 | GraphEdge edge = mEdgeMap.get(edgeId); 234 | if (edge == null) { 235 | GraphNode node1 = mNodeMap.get(nodeId1); 236 | GraphNode node2 = mNodeMap.get(nodeId2); 237 | edge = new GraphEdge(edgeId, node1, node2); 238 | mEdgeMap.put(edgeId, edge); 239 | } 240 | edge.setAttributes(attrs); 241 | } 242 | } 243 | 244 | /* 245 | * NodeIdSet 246 | */ 247 | private class NodeIdSet extends TreeSet 248 | { 249 | public NodeIdSet() { 250 | super(); 251 | } 252 | public NodeIdSet(NodeIdSet other) { 253 | super(other); 254 | } 255 | } 256 | 257 | /* 258 | * GraphCtx 259 | */ 260 | private class GraphCtx 261 | { 262 | GraphCtx parent; 263 | NodeIdSet graph = new NodeIdSet(); 264 | 265 | GraphCtx(GraphCtx parent) { 266 | this.parent = parent; 267 | } 268 | 269 | void addNode(String nodeId) { 270 | graph.add(nodeId); 271 | if (parent != null) parent.addNode(nodeId); 272 | } 273 | 274 | public String toString() { 275 | return graph.toString(); 276 | } 277 | } 278 | 279 | /* 280 | * EdgeCtx 281 | */ 282 | private class EdgeCtx 283 | { 284 | EdgeCtx parent; 285 | GraphCtx src; 286 | GraphCtx dest; 287 | boolean srcFlag = true; 288 | Map attrs = new TreeMap(); 289 | 290 | EdgeCtx(EdgeCtx parent, GraphCtx src, GraphCtx dest, DOTParser.Attr_listContext ctx) { 291 | this.parent = parent; 292 | this.src = src; 293 | this.dest = dest; 294 | populateAttributes(ctx, attrs); 295 | } 296 | 297 | public String toString() { 298 | return src + "->" + dest; 299 | } 300 | } 301 | 302 | /* 303 | * populateAttributes helper 304 | */ 305 | private void populateAttributes(DOTParser.Attr_listContext ctx, Map attrs) { 306 | attrs.clear(); 307 | if (ctx == null) return; 308 | 309 | for (A_listContext listCtx : ctx.a_list()) { 310 | String[] kv = {null,null}; 311 | int i = 0; 312 | for (IdContext idCtx : listCtx.id()) { 313 | TerminalNode idObj = idCtx.ID(); 314 | if (idObj == null) idObj = idCtx.NUMBER(); 315 | if (idObj == null) idObj = idCtx.STRING(); 316 | if (idObj == null) idObj = idCtx.HTML_STRING(); 317 | String text = idObj.getText(); 318 | if (idObj.getSymbol().getType() == DOTParser.STRING) { 319 | text = trimDoubleQuotes(text); 320 | text = text.replace("\\\"", "\""); 321 | } 322 | kv[i++] = text; 323 | if (i > 1) { 324 | attrs.put(kv[0], kv[1]); 325 | i = 0; 326 | } 327 | } 328 | } 329 | } 330 | 331 | private static String trimDoubleQuotes(String text) { 332 | int textLength = text.length(); 333 | if (textLength >= 2 && text.charAt(0) == '"' && text.charAt(textLength - 1) == '"') { 334 | return text.substring(1, textLength - 1); 335 | } 336 | return text; 337 | } 338 | 339 | /* 340 | * ErrorListener 341 | */ 342 | private class ErrorListener extends BaseErrorListener 343 | { 344 | public void syntaxError(@NotNull Recognizer recognizer, 345 | @Nullable Object offendingSymbol, int line, 346 | int charPositionInLine, @NotNull String msg, 347 | @Nullable RecognitionException e) 348 | { 349 | mErrMsg = "at line " + line + ":" + charPositionInLine + " " + msg; 350 | throw e; 351 | } 352 | 353 | @Override 354 | public void reportAmbiguity(@NotNull Parser recognizer, 355 | @NotNull DFA dfa, 356 | int startIndex, 357 | int stopIndex, 358 | boolean exact, 359 | @Nullable BitSet ambigAlts, 360 | @NotNull ATNConfigSet configs) 361 | { 362 | } 363 | 364 | @Override 365 | public void reportAttemptingFullContext(@NotNull Parser recognizer, 366 | @NotNull DFA dfa, 367 | int startIndex, 368 | int stopIndex, 369 | @Nullable BitSet conflictingAlts, 370 | @NotNull ATNConfigSet configs) 371 | { 372 | } 373 | 374 | @Override 375 | public void reportContextSensitivity(@NotNull Parser recognizer, 376 | @NotNull DFA dfa, 377 | int startIndex, 378 | int stopIndex, 379 | int prediction, 380 | @NotNull ATNConfigSet configs) 381 | { 382 | } 383 | } 384 | 385 | /* 386 | * ExceptionErrorStrategy 387 | */ 388 | private class ExceptionErrorStrategy extends DefaultErrorStrategy 389 | { 390 | @Override 391 | public void recover(Parser recognizer, RecognitionException e) { 392 | throw e; 393 | } 394 | 395 | @Override 396 | public void reportInputMismatch(Parser recognizer, InputMismatchException e) throws RecognitionException { 397 | String msg = "mismatched input " + getTokenErrorDisplay(e.getOffendingToken()); 398 | msg += " expecting one of " + e.getExpectedTokens().toString(recognizer.getTokenNames()); 399 | RecognitionException ex = new RecognitionException(msg, recognizer, recognizer.getInputStream(), recognizer.getContext()); 400 | ex.initCause(e); 401 | throw ex; 402 | } 403 | 404 | @Override 405 | public void reportMissingToken(Parser recognizer) { 406 | beginErrorCondition(recognizer); 407 | Token t = recognizer.getCurrentToken(); 408 | IntervalSet expecting = getExpectedTokens(recognizer); 409 | String msg = "missing " + expecting.toString(recognizer.getTokenNames()) + " at " + getTokenErrorDisplay(t); 410 | throw new RecognitionException(msg, recognizer, recognizer.getInputStream(), recognizer.getContext()); 411 | } 412 | } 413 | 414 | private static void log(Object o) { 415 | System.out.println(o); 416 | } 417 | } 418 | -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/GraphParserException.java: -------------------------------------------------------------------------------- 1 | /* 2 | [BSD 3-Clause License] 3 | 4 | Copyright (c) 2017, PayPal Holdings, Inc. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.paypal.digraph.parser; 33 | 34 | public class GraphParserException extends RuntimeException 35 | { 36 | public GraphParserException(String msg) { 37 | super(msg); 38 | } 39 | 40 | public GraphParserException(Throwable t) { 41 | super(t); 42 | } 43 | 44 | public GraphParserException(String msg, Throwable t) { 45 | super(msg, t); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/antlr/DOT.g4: -------------------------------------------------------------------------------- 1 | /* 2 | [The "BSD licence"] 3 | Copyright (c) 2013 Terence Parr 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** Derived from http://www.graphviz.org/doc/info/lang.html. 30 | Comments pulled from spec. 31 | */ 32 | grammar DOT; 33 | 34 | graph : STRICT? (GRAPH | DIGRAPH) id? '{' stmt_list '}' ; 35 | stmt_list : ( stmt ';'? )* ; 36 | stmt : node_stmt 37 | | edge_stmt 38 | | attr_stmt 39 | | id '=' id 40 | | subgraph 41 | ; 42 | attr_stmt : (GRAPH | NODE | EDGE) attr_list ; 43 | attr_list : ('[' a_list? ']')+ ; 44 | a_list : (id ('=' id)? ','?)+ ; 45 | edge_stmt : (node_id | subgraph) edgeRHS attr_list? ; 46 | edgeRHS : ( edgeop (node_id | subgraph) )+ ; 47 | edgeop : '->' | '--' ; 48 | node_stmt : node_id attr_list? ; 49 | node_id : id port? ; 50 | port : ':' id (':' id)? ; 51 | subgraph : (SUBGRAPH id?)? '{' stmt_list '}' ; 52 | id : ID 53 | | STRING 54 | | HTML_STRING 55 | | NUMBER 56 | ; 57 | 58 | // "The keywords node, edge, graph, digraph, subgraph, and strict are 59 | // case-independent" 60 | STRICT : [Ss][Tt][Rr][Ii][Cc][Tt] ; 61 | GRAPH : [Gg][Rr][Aa][Pp][Hh] ; 62 | DIGRAPH : [Dd][Ii][Gg][Rr][Aa][Pp][Hh] ; 63 | NODE : [Nn][Oo][Dd][Ee] ; 64 | EDGE : [Ee][Dd][Gg][Ee] ; 65 | SUBGRAPH : [Ss][Uu][Bb][Gg][Rr][Aa][Pp][Hh] ; 66 | 67 | /** "a numeral [-]?(.[0-9]+ | [0-9]+(.[0-9]*)? )" */ 68 | NUMBER : '-'? ('.' DIGIT+ | DIGIT+ ('.' DIGIT*)? ) ; 69 | fragment 70 | DIGIT : [0-9] ; 71 | 72 | /** "any double-quoted string ("...") possibly containing escaped quotes" */ 73 | STRING : '"' ('\\"'|.)*? '"' ; 74 | 75 | /** "Any string of alphabetic ([a-zA-Z\200-\377]) characters, underscores 76 | * ('_') or digits ([0-9]), not beginning with a digit" 77 | */ 78 | ID : LETTER (LETTER|DIGIT)*; 79 | fragment 80 | LETTER : [a-zA-Z\u0080-\u00FF_] ; 81 | 82 | /** "HTML strings, angle brackets must occur in matched pairs, and 83 | * unescaped newlines are allowed." 84 | */ 85 | HTML_STRING : '<' (TAG|~[<>])* '>' ; 86 | fragment 87 | TAG : '<' .*? '>' ; 88 | 89 | COMMENT : '/*' .*? '*/' -> skip ; 90 | LINE_COMMENT: '//' .*? '\r'? '\n' -> skip ; 91 | 92 | /** "a '#' character is considered a line output from a C preprocessor (e.g., 93 | * # 34 to indicate line 34 ) and discarded" 94 | */ 95 | PREPROC : '#' .*? '\n' -> skip ; 96 | 97 | WS : [ \t\n\r]+ -> skip ; 98 | -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/antlr/DOTBaseListener.java: -------------------------------------------------------------------------------- 1 | package com.paypal.digraph.parser.antlr; 2 | 3 | // Generated from DOT.g4 by ANTLR 4.2 4 | 5 | import org.antlr.v4.runtime.ParserRuleContext; 6 | import org.antlr.v4.runtime.misc.NotNull; 7 | import org.antlr.v4.runtime.tree.ErrorNode; 8 | import org.antlr.v4.runtime.tree.TerminalNode; 9 | 10 | /** 11 | * This class provides an empty implementation of {@link DOTListener}, 12 | * which can be extended to create a listener which only needs to handle a subset 13 | * of the available methods. 14 | */ 15 | public class DOTBaseListener implements DOTListener { 16 | /** 17 | * {@inheritDoc} 18 | * 19 | *

The default implementation does nothing.

20 | */ 21 | /*@Override*/ public void enterAttr_stmt(@NotNull DOTParser.Attr_stmtContext ctx) { } 22 | /** 23 | * {@inheritDoc} 24 | * 25 | *

The default implementation does nothing.

26 | */ 27 | /*@Override*/ public void exitAttr_stmt(@NotNull DOTParser.Attr_stmtContext ctx) { } 28 | 29 | /** 30 | * {@inheritDoc} 31 | * 32 | *

The default implementation does nothing.

33 | */ 34 | /*@Override*/ public void enterPort(@NotNull DOTParser.PortContext ctx) { } 35 | /** 36 | * {@inheritDoc} 37 | * 38 | *

The default implementation does nothing.

39 | */ 40 | /*@Override*/ public void exitPort(@NotNull DOTParser.PortContext ctx) { } 41 | 42 | /** 43 | * {@inheritDoc} 44 | * 45 | *

The default implementation does nothing.

46 | */ 47 | /*@Override*/ public void enterEdgeop(@NotNull DOTParser.EdgeopContext ctx) { } 48 | /** 49 | * {@inheritDoc} 50 | * 51 | *

The default implementation does nothing.

52 | */ 53 | /*@Override*/ public void exitEdgeop(@NotNull DOTParser.EdgeopContext ctx) { } 54 | 55 | /** 56 | * {@inheritDoc} 57 | * 58 | *

The default implementation does nothing.

59 | */ 60 | /*@Override*/ public void enterStmt_list(@NotNull DOTParser.Stmt_listContext ctx) { } 61 | /** 62 | * {@inheritDoc} 63 | * 64 | *

The default implementation does nothing.

65 | */ 66 | /*@Override*/ public void exitStmt_list(@NotNull DOTParser.Stmt_listContext ctx) { } 67 | 68 | /** 69 | * {@inheritDoc} 70 | * 71 | *

The default implementation does nothing.

72 | */ 73 | /*@Override*/ public void enterStmt(@NotNull DOTParser.StmtContext ctx) { } 74 | /** 75 | * {@inheritDoc} 76 | * 77 | *

The default implementation does nothing.

78 | */ 79 | /*@Override*/ public void exitStmt(@NotNull DOTParser.StmtContext ctx) { } 80 | 81 | /** 82 | * {@inheritDoc} 83 | * 84 | *

The default implementation does nothing.

85 | */ 86 | /*@Override*/ public void enterEdgeRHS(@NotNull DOTParser.EdgeRHSContext ctx) { } 87 | /** 88 | * {@inheritDoc} 89 | * 90 | *

The default implementation does nothing.

91 | */ 92 | /*@Override*/ public void exitEdgeRHS(@NotNull DOTParser.EdgeRHSContext ctx) { } 93 | 94 | /** 95 | * {@inheritDoc} 96 | * 97 | *

The default implementation does nothing.

98 | */ 99 | /*@Override*/ public void enterNode_id(@NotNull DOTParser.Node_idContext ctx) { } 100 | /** 101 | * {@inheritDoc} 102 | * 103 | *

The default implementation does nothing.

104 | */ 105 | /*@Override*/ public void exitNode_id(@NotNull DOTParser.Node_idContext ctx) { } 106 | 107 | /** 108 | * {@inheritDoc} 109 | * 110 | *

The default implementation does nothing.

111 | */ 112 | /*@Override*/ public void enterId(@NotNull DOTParser.IdContext ctx) { } 113 | /** 114 | * {@inheritDoc} 115 | * 116 | *

The default implementation does nothing.

117 | */ 118 | /*@Override*/ public void exitId(@NotNull DOTParser.IdContext ctx) { } 119 | 120 | /** 121 | * {@inheritDoc} 122 | * 123 | *

The default implementation does nothing.

124 | */ 125 | /*@Override*/ public void enterSubgraph(@NotNull DOTParser.SubgraphContext ctx) { } 126 | /** 127 | * {@inheritDoc} 128 | * 129 | *

The default implementation does nothing.

130 | */ 131 | /*@Override*/ public void exitSubgraph(@NotNull DOTParser.SubgraphContext ctx) { } 132 | 133 | /** 134 | * {@inheritDoc} 135 | * 136 | *

The default implementation does nothing.

137 | */ 138 | /*@Override*/ public void enterGraph(@NotNull DOTParser.GraphContext ctx) { } 139 | /** 140 | * {@inheritDoc} 141 | * 142 | *

The default implementation does nothing.

143 | */ 144 | /*@Override*/ public void exitGraph(@NotNull DOTParser.GraphContext ctx) { } 145 | 146 | /** 147 | * {@inheritDoc} 148 | * 149 | *

The default implementation does nothing.

150 | */ 151 | /*@Override*/ public void enterA_list(@NotNull DOTParser.A_listContext ctx) { } 152 | /** 153 | * {@inheritDoc} 154 | * 155 | *

The default implementation does nothing.

156 | */ 157 | /*@Override*/ public void exitA_list(@NotNull DOTParser.A_listContext ctx) { } 158 | 159 | /** 160 | * {@inheritDoc} 161 | * 162 | *

The default implementation does nothing.

163 | */ 164 | /*@Override*/ public void enterAttr_list(@NotNull DOTParser.Attr_listContext ctx) { } 165 | /** 166 | * {@inheritDoc} 167 | * 168 | *

The default implementation does nothing.

169 | */ 170 | /*@Override*/ public void exitAttr_list(@NotNull DOTParser.Attr_listContext ctx) { } 171 | 172 | /** 173 | * {@inheritDoc} 174 | * 175 | *

The default implementation does nothing.

176 | */ 177 | /*@Override*/ public void enterEdge_stmt(@NotNull DOTParser.Edge_stmtContext ctx) { } 178 | /** 179 | * {@inheritDoc} 180 | * 181 | *

The default implementation does nothing.

182 | */ 183 | /*@Override*/ public void exitEdge_stmt(@NotNull DOTParser.Edge_stmtContext ctx) { } 184 | 185 | /** 186 | * {@inheritDoc} 187 | * 188 | *

The default implementation does nothing.

189 | */ 190 | /*@Override*/ public void enterNode_stmt(@NotNull DOTParser.Node_stmtContext ctx) { } 191 | /** 192 | * {@inheritDoc} 193 | * 194 | *

The default implementation does nothing.

195 | */ 196 | /*@Override*/ public void exitNode_stmt(@NotNull DOTParser.Node_stmtContext ctx) { } 197 | 198 | /** 199 | * {@inheritDoc} 200 | * 201 | *

The default implementation does nothing.

202 | */ 203 | /*@Override*/ public void enterEveryRule(@NotNull ParserRuleContext ctx) { } 204 | /** 205 | * {@inheritDoc} 206 | * 207 | *

The default implementation does nothing.

208 | */ 209 | /*@Override*/ public void exitEveryRule(@NotNull ParserRuleContext ctx) { } 210 | /** 211 | * {@inheritDoc} 212 | * 213 | *

The default implementation does nothing.

214 | */ 215 | /*@Override*/ public void visitTerminal(@NotNull TerminalNode node) { } 216 | /** 217 | * {@inheritDoc} 218 | * 219 | *

The default implementation does nothing.

220 | */ 221 | /*@Override*/ public void visitErrorNode(@NotNull ErrorNode node) { } 222 | } -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/antlr/DOTLexer.java: -------------------------------------------------------------------------------- 1 | package com.paypal.digraph.parser.antlr; 2 | 3 | // Generated from DOT.g4 by ANTLR 4.2 4 | import org.antlr.v4.runtime.Lexer; 5 | import org.antlr.v4.runtime.CharStream; 6 | import org.antlr.v4.runtime.Token; 7 | import org.antlr.v4.runtime.TokenStream; 8 | import org.antlr.v4.runtime.*; 9 | import org.antlr.v4.runtime.atn.*; 10 | import org.antlr.v4.runtime.dfa.DFA; 11 | import org.antlr.v4.runtime.misc.*; 12 | 13 | @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) 14 | public class DOTLexer extends Lexer { 15 | protected static final DFA[] _decisionToDFA; 16 | protected static final PredictionContextCache _sharedContextCache = 17 | new PredictionContextCache(); 18 | public static final int 19 | T__9=1, T__8=2, T__7=3, T__6=4, T__5=5, T__4=6, T__3=7, T__2=8, T__1=9, 20 | T__0=10, STRICT=11, GRAPH=12, DIGRAPH=13, NODE=14, EDGE=15, SUBGRAPH=16, 21 | NUMBER=17, STRING=18, ID=19, HTML_STRING=20, COMMENT=21, LINE_COMMENT=22, 22 | PREPROC=23, WS=24; 23 | public static String[] modeNames = { 24 | "DEFAULT_MODE" 25 | }; 26 | 27 | public static final String[] tokenNames = { 28 | "", 29 | "']'", "'->'", "'{'", "','", "'['", "':'", "'--'", "'='", "'}'", "';'", 30 | "STRICT", "GRAPH", "DIGRAPH", "NODE", "EDGE", "SUBGRAPH", "NUMBER", "STRING", 31 | "ID", "HTML_STRING", "COMMENT", "LINE_COMMENT", "PREPROC", "WS" 32 | }; 33 | public static final String[] ruleNames = { 34 | "T__9", "T__8", "T__7", "T__6", "T__5", "T__4", "T__3", "T__2", "T__1", 35 | "T__0", "STRICT", "GRAPH", "DIGRAPH", "NODE", "EDGE", "SUBGRAPH", "NUMBER", 36 | "DIGIT", "STRING", "ID", "LETTER", "HTML_STRING", "TAG", "COMMENT", "LINE_COMMENT", 37 | "PREPROC", "WS" 38 | }; 39 | 40 | 41 | public DOTLexer(CharStream input) { 42 | super(input); 43 | _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); 44 | } 45 | 46 | @Override 47 | public String getGrammarFileName() { return "DOT.g4"; } 48 | 49 | @Override 50 | public String[] getTokenNames() { return tokenNames; } 51 | 52 | @Override 53 | public String[] getRuleNames() { return ruleNames; } 54 | 55 | @Override 56 | public String getSerializedATN() { return _serializedATN; } 57 | 58 | @Override 59 | public String[] getModeNames() { return modeNames; } 60 | 61 | @Override 62 | public ATN getATN() { return _ATN; } 63 | 64 | public static final String _serializedATN = 65 | "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\32\u00ea\b\1\4\2"+ 66 | "\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+ 67 | "\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+ 68 | "\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+ 69 | "\t\31\4\32\t\32\4\33\t\33\4\34\t\34\3\2\3\2\3\3\3\3\3\3\3\4\3\4\3\5\3"+ 70 | "\5\3\6\3\6\3\7\3\7\3\b\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\f\3"+ 71 | "\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16\3\16\3"+ 72 | "\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3"+ 73 | "\21\3\21\3\21\3\21\3\21\3\21\3\21\3\22\5\22y\n\22\3\22\3\22\6\22}\n\22"+ 74 | "\r\22\16\22~\3\22\6\22\u0082\n\22\r\22\16\22\u0083\3\22\3\22\7\22\u0088"+ 75 | "\n\22\f\22\16\22\u008b\13\22\5\22\u008d\n\22\5\22\u008f\n\22\3\23\3\23"+ 76 | "\3\24\3\24\3\24\3\24\7\24\u0097\n\24\f\24\16\24\u009a\13\24\3\24\3\24"+ 77 | "\3\25\3\25\3\25\7\25\u00a1\n\25\f\25\16\25\u00a4\13\25\3\26\3\26\3\27"+ 78 | "\3\27\3\27\7\27\u00ab\n\27\f\27\16\27\u00ae\13\27\3\27\3\27\3\30\3\30"+ 79 | "\7\30\u00b4\n\30\f\30\16\30\u00b7\13\30\3\30\3\30\3\31\3\31\3\31\3\31"+ 80 | "\7\31\u00bf\n\31\f\31\16\31\u00c2\13\31\3\31\3\31\3\31\3\31\3\31\3\32"+ 81 | "\3\32\3\32\3\32\7\32\u00cd\n\32\f\32\16\32\u00d0\13\32\3\32\5\32\u00d3"+ 82 | "\n\32\3\32\3\32\3\32\3\32\3\33\3\33\7\33\u00db\n\33\f\33\16\33\u00de\13"+ 83 | "\33\3\33\3\33\3\33\3\33\3\34\6\34\u00e5\n\34\r\34\16\34\u00e6\3\34\3\34"+ 84 | "\7\u0098\u00b5\u00c0\u00ce\u00dc\2\35\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21"+ 85 | "\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\2\'\24)\25+\2-\26"+ 86 | "/\2\61\27\63\30\65\31\67\32\3\2\25\4\2UUuu\4\2VVvv\4\2TTtt\4\2KKkk\4\2"+ 87 | "EEee\4\2IIii\4\2CCcc\4\2RRrr\4\2JJjj\4\2FFff\4\2PPpp\4\2QQqq\4\2GGgg\4"+ 88 | "\2WWww\4\2DDdd\3\2\62;\6\2C\\aac|\u0082\u0101\4\2>>@@\5\2\13\f\17\17\""+ 89 | "\"\u00f8\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2"+ 90 | "\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27"+ 91 | "\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2"+ 92 | "\2\2#\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2-\3\2\2\2\2\61\3\2\2\2\2\63\3\2"+ 93 | "\2\2\2\65\3\2\2\2\2\67\3\2\2\2\39\3\2\2\2\5;\3\2\2\2\7>\3\2\2\2\t@\3\2"+ 94 | "\2\2\13B\3\2\2\2\rD\3\2\2\2\17F\3\2\2\2\21I\3\2\2\2\23K\3\2\2\2\25M\3"+ 95 | "\2\2\2\27O\3\2\2\2\31V\3\2\2\2\33\\\3\2\2\2\35d\3\2\2\2\37i\3\2\2\2!n"+ 96 | "\3\2\2\2#x\3\2\2\2%\u0090\3\2\2\2\'\u0092\3\2\2\2)\u009d\3\2\2\2+\u00a5"+ 97 | "\3\2\2\2-\u00a7\3\2\2\2/\u00b1\3\2\2\2\61\u00ba\3\2\2\2\63\u00c8\3\2\2"+ 98 | "\2\65\u00d8\3\2\2\2\67\u00e4\3\2\2\29:\7_\2\2:\4\3\2\2\2;<\7/\2\2<=\7"+ 99 | "@\2\2=\6\3\2\2\2>?\7}\2\2?\b\3\2\2\2@A\7.\2\2A\n\3\2\2\2BC\7]\2\2C\f\3"+ 100 | "\2\2\2DE\7<\2\2E\16\3\2\2\2FG\7/\2\2GH\7/\2\2H\20\3\2\2\2IJ\7?\2\2J\22"+ 101 | "\3\2\2\2KL\7\177\2\2L\24\3\2\2\2MN\7=\2\2N\26\3\2\2\2OP\t\2\2\2PQ\t\3"+ 102 | "\2\2QR\t\4\2\2RS\t\5\2\2ST\t\6\2\2TU\t\3\2\2U\30\3\2\2\2VW\t\7\2\2WX\t"+ 103 | "\4\2\2XY\t\b\2\2YZ\t\t\2\2Z[\t\n\2\2[\32\3\2\2\2\\]\t\13\2\2]^\t\5\2\2"+ 104 | "^_\t\7\2\2_`\t\4\2\2`a\t\b\2\2ab\t\t\2\2bc\t\n\2\2c\34\3\2\2\2de\t\f\2"+ 105 | "\2ef\t\r\2\2fg\t\13\2\2gh\t\16\2\2h\36\3\2\2\2ij\t\16\2\2jk\t\13\2\2k"+ 106 | "l\t\7\2\2lm\t\16\2\2m \3\2\2\2no\t\2\2\2op\t\17\2\2pq\t\20\2\2qr\t\7\2"+ 107 | "\2rs\t\4\2\2st\t\b\2\2tu\t\t\2\2uv\t\n\2\2v\"\3\2\2\2wy\7/\2\2xw\3\2\2"+ 108 | "\2xy\3\2\2\2y\u008e\3\2\2\2z|\7\60\2\2{}\5%\23\2|{\3\2\2\2}~\3\2\2\2~"+ 109 | "|\3\2\2\2~\177\3\2\2\2\177\u008f\3\2\2\2\u0080\u0082\5%\23\2\u0081\u0080"+ 110 | "\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0081\3\2\2\2\u0083\u0084\3\2\2\2\u0084"+ 111 | "\u008c\3\2\2\2\u0085\u0089\7\60\2\2\u0086\u0088\5%\23\2\u0087\u0086\3"+ 112 | "\2\2\2\u0088\u008b\3\2\2\2\u0089\u0087\3\2\2\2\u0089\u008a\3\2\2\2\u008a"+ 113 | "\u008d\3\2\2\2\u008b\u0089\3\2\2\2\u008c\u0085\3\2\2\2\u008c\u008d\3\2"+ 114 | "\2\2\u008d\u008f\3\2\2\2\u008ez\3\2\2\2\u008e\u0081\3\2\2\2\u008f$\3\2"+ 115 | "\2\2\u0090\u0091\t\21\2\2\u0091&\3\2\2\2\u0092\u0098\7$\2\2\u0093\u0094"+ 116 | "\7^\2\2\u0094\u0097\7$\2\2\u0095\u0097\13\2\2\2\u0096\u0093\3\2\2\2\u0096"+ 117 | "\u0095\3\2\2\2\u0097\u009a\3\2\2\2\u0098\u0099\3\2\2\2\u0098\u0096\3\2"+ 118 | "\2\2\u0099\u009b\3\2\2\2\u009a\u0098\3\2\2\2\u009b\u009c\7$\2\2\u009c"+ 119 | "(\3\2\2\2\u009d\u00a2\5+\26\2\u009e\u00a1\5+\26\2\u009f\u00a1\5%\23\2"+ 120 | "\u00a0\u009e\3\2\2\2\u00a0\u009f\3\2\2\2\u00a1\u00a4\3\2\2\2\u00a2\u00a0"+ 121 | "\3\2\2\2\u00a2\u00a3\3\2\2\2\u00a3*\3\2\2\2\u00a4\u00a2\3\2\2\2\u00a5"+ 122 | "\u00a6\t\22\2\2\u00a6,\3\2\2\2\u00a7\u00ac\7>\2\2\u00a8\u00ab\5/\30\2"+ 123 | "\u00a9\u00ab\n\23\2\2\u00aa\u00a8\3\2\2\2\u00aa\u00a9\3\2\2\2\u00ab\u00ae"+ 124 | "\3\2\2\2\u00ac\u00aa\3\2\2\2\u00ac\u00ad\3\2\2\2\u00ad\u00af\3\2\2\2\u00ae"+ 125 | "\u00ac\3\2\2\2\u00af\u00b0\7@\2\2\u00b0.\3\2\2\2\u00b1\u00b5\7>\2\2\u00b2"+ 126 | "\u00b4\13\2\2\2\u00b3\u00b2\3\2\2\2\u00b4\u00b7\3\2\2\2\u00b5\u00b6\3"+ 127 | "\2\2\2\u00b5\u00b3\3\2\2\2\u00b6\u00b8\3\2\2\2\u00b7\u00b5\3\2\2\2\u00b8"+ 128 | "\u00b9\7@\2\2\u00b9\60\3\2\2\2\u00ba\u00bb\7\61\2\2\u00bb\u00bc\7,\2\2"+ 129 | "\u00bc\u00c0\3\2\2\2\u00bd\u00bf\13\2\2\2\u00be\u00bd\3\2\2\2\u00bf\u00c2"+ 130 | "\3\2\2\2\u00c0\u00c1\3\2\2\2\u00c0\u00be\3\2\2\2\u00c1\u00c3\3\2\2\2\u00c2"+ 131 | "\u00c0\3\2\2\2\u00c3\u00c4\7,\2\2\u00c4\u00c5\7\61\2\2\u00c5\u00c6\3\2"+ 132 | "\2\2\u00c6\u00c7\b\31\2\2\u00c7\62\3\2\2\2\u00c8\u00c9\7\61\2\2\u00c9"+ 133 | "\u00ca\7\61\2\2\u00ca\u00ce\3\2\2\2\u00cb\u00cd\13\2\2\2\u00cc\u00cb\3"+ 134 | "\2\2\2\u00cd\u00d0\3\2\2\2\u00ce\u00cf\3\2\2\2\u00ce\u00cc\3\2\2\2\u00cf"+ 135 | "\u00d2\3\2\2\2\u00d0\u00ce\3\2\2\2\u00d1\u00d3\7\17\2\2\u00d2\u00d1\3"+ 136 | "\2\2\2\u00d2\u00d3\3\2\2\2\u00d3\u00d4\3\2\2\2\u00d4\u00d5\7\f\2\2\u00d5"+ 137 | "\u00d6\3\2\2\2\u00d6\u00d7\b\32\2\2\u00d7\64\3\2\2\2\u00d8\u00dc\7%\2"+ 138 | "\2\u00d9\u00db\13\2\2\2\u00da\u00d9\3\2\2\2\u00db\u00de\3\2\2\2\u00dc"+ 139 | "\u00dd\3\2\2\2\u00dc\u00da\3\2\2\2\u00dd\u00df\3\2\2\2\u00de\u00dc\3\2"+ 140 | "\2\2\u00df\u00e0\7\f\2\2\u00e0\u00e1\3\2\2\2\u00e1\u00e2\b\33\2\2\u00e2"+ 141 | "\66\3\2\2\2\u00e3\u00e5\t\24\2\2\u00e4\u00e3\3\2\2\2\u00e5\u00e6\3\2\2"+ 142 | "\2\u00e6\u00e4\3\2\2\2\u00e6\u00e7\3\2\2\2\u00e7\u00e8\3\2\2\2\u00e8\u00e9"+ 143 | "\b\34\2\2\u00e98\3\2\2\2\25\2x~\u0083\u0089\u008c\u008e\u0096\u0098\u00a0"+ 144 | "\u00a2\u00aa\u00ac\u00b5\u00c0\u00ce\u00d2\u00dc\u00e6\3\b\2\2"; 145 | public static final ATN _ATN = 146 | new ATNDeserializer().deserialize(_serializedATN.toCharArray()); 147 | static { 148 | _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; 149 | for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { 150 | _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/antlr/DOTListener.java: -------------------------------------------------------------------------------- 1 | package com.paypal.digraph.parser.antlr; 2 | 3 | // Generated from DOT.g4 by ANTLR 4.2 4 | import org.antlr.v4.runtime.misc.NotNull; 5 | import org.antlr.v4.runtime.tree.ParseTreeListener; 6 | 7 | /** 8 | * This interface defines a complete listener for a parse tree produced by 9 | * {@link DOTParser}. 10 | */ 11 | public interface DOTListener extends ParseTreeListener { 12 | /** 13 | * Enter a parse tree produced by {@link DOTParser#attr_stmt}. 14 | * @param ctx the parse tree 15 | */ 16 | void enterAttr_stmt(@NotNull DOTParser.Attr_stmtContext ctx); 17 | /** 18 | * Exit a parse tree produced by {@link DOTParser#attr_stmt}. 19 | * @param ctx the parse tree 20 | */ 21 | void exitAttr_stmt(@NotNull DOTParser.Attr_stmtContext ctx); 22 | 23 | /** 24 | * Enter a parse tree produced by {@link DOTParser#port}. 25 | * @param ctx the parse tree 26 | */ 27 | void enterPort(@NotNull DOTParser.PortContext ctx); 28 | /** 29 | * Exit a parse tree produced by {@link DOTParser#port}. 30 | * @param ctx the parse tree 31 | */ 32 | void exitPort(@NotNull DOTParser.PortContext ctx); 33 | 34 | /** 35 | * Enter a parse tree produced by {@link DOTParser#edgeop}. 36 | * @param ctx the parse tree 37 | */ 38 | void enterEdgeop(@NotNull DOTParser.EdgeopContext ctx); 39 | /** 40 | * Exit a parse tree produced by {@link DOTParser#edgeop}. 41 | * @param ctx the parse tree 42 | */ 43 | void exitEdgeop(@NotNull DOTParser.EdgeopContext ctx); 44 | 45 | /** 46 | * Enter a parse tree produced by {@link DOTParser#stmt_list}. 47 | * @param ctx the parse tree 48 | */ 49 | void enterStmt_list(@NotNull DOTParser.Stmt_listContext ctx); 50 | /** 51 | * Exit a parse tree produced by {@link DOTParser#stmt_list}. 52 | * @param ctx the parse tree 53 | */ 54 | void exitStmt_list(@NotNull DOTParser.Stmt_listContext ctx); 55 | 56 | /** 57 | * Enter a parse tree produced by {@link DOTParser#stmt}. 58 | * @param ctx the parse tree 59 | */ 60 | void enterStmt(@NotNull DOTParser.StmtContext ctx); 61 | /** 62 | * Exit a parse tree produced by {@link DOTParser#stmt}. 63 | * @param ctx the parse tree 64 | */ 65 | void exitStmt(@NotNull DOTParser.StmtContext ctx); 66 | 67 | /** 68 | * Enter a parse tree produced by {@link DOTParser#edgeRHS}. 69 | * @param ctx the parse tree 70 | */ 71 | void enterEdgeRHS(@NotNull DOTParser.EdgeRHSContext ctx); 72 | /** 73 | * Exit a parse tree produced by {@link DOTParser#edgeRHS}. 74 | * @param ctx the parse tree 75 | */ 76 | void exitEdgeRHS(@NotNull DOTParser.EdgeRHSContext ctx); 77 | 78 | /** 79 | * Enter a parse tree produced by {@link DOTParser#node_id}. 80 | * @param ctx the parse tree 81 | */ 82 | void enterNode_id(@NotNull DOTParser.Node_idContext ctx); 83 | /** 84 | * Exit a parse tree produced by {@link DOTParser#node_id}. 85 | * @param ctx the parse tree 86 | */ 87 | void exitNode_id(@NotNull DOTParser.Node_idContext ctx); 88 | 89 | /** 90 | * Enter a parse tree produced by {@link DOTParser#id}. 91 | * @param ctx the parse tree 92 | */ 93 | void enterId(@NotNull DOTParser.IdContext ctx); 94 | /** 95 | * Exit a parse tree produced by {@link DOTParser#id}. 96 | * @param ctx the parse tree 97 | */ 98 | void exitId(@NotNull DOTParser.IdContext ctx); 99 | 100 | /** 101 | * Enter a parse tree produced by {@link DOTParser#subgraph}. 102 | * @param ctx the parse tree 103 | */ 104 | void enterSubgraph(@NotNull DOTParser.SubgraphContext ctx); 105 | /** 106 | * Exit a parse tree produced by {@link DOTParser#subgraph}. 107 | * @param ctx the parse tree 108 | */ 109 | void exitSubgraph(@NotNull DOTParser.SubgraphContext ctx); 110 | 111 | /** 112 | * Enter a parse tree produced by {@link DOTParser#graph}. 113 | * @param ctx the parse tree 114 | */ 115 | void enterGraph(@NotNull DOTParser.GraphContext ctx); 116 | /** 117 | * Exit a parse tree produced by {@link DOTParser#graph}. 118 | * @param ctx the parse tree 119 | */ 120 | void exitGraph(@NotNull DOTParser.GraphContext ctx); 121 | 122 | /** 123 | * Enter a parse tree produced by {@link DOTParser#a_list}. 124 | * @param ctx the parse tree 125 | */ 126 | void enterA_list(@NotNull DOTParser.A_listContext ctx); 127 | /** 128 | * Exit a parse tree produced by {@link DOTParser#a_list}. 129 | * @param ctx the parse tree 130 | */ 131 | void exitA_list(@NotNull DOTParser.A_listContext ctx); 132 | 133 | /** 134 | * Enter a parse tree produced by {@link DOTParser#attr_list}. 135 | * @param ctx the parse tree 136 | */ 137 | void enterAttr_list(@NotNull DOTParser.Attr_listContext ctx); 138 | /** 139 | * Exit a parse tree produced by {@link DOTParser#attr_list}. 140 | * @param ctx the parse tree 141 | */ 142 | void exitAttr_list(@NotNull DOTParser.Attr_listContext ctx); 143 | 144 | /** 145 | * Enter a parse tree produced by {@link DOTParser#edge_stmt}. 146 | * @param ctx the parse tree 147 | */ 148 | void enterEdge_stmt(@NotNull DOTParser.Edge_stmtContext ctx); 149 | /** 150 | * Exit a parse tree produced by {@link DOTParser#edge_stmt}. 151 | * @param ctx the parse tree 152 | */ 153 | void exitEdge_stmt(@NotNull DOTParser.Edge_stmtContext ctx); 154 | 155 | /** 156 | * Enter a parse tree produced by {@link DOTParser#node_stmt}. 157 | * @param ctx the parse tree 158 | */ 159 | void enterNode_stmt(@NotNull DOTParser.Node_stmtContext ctx); 160 | /** 161 | * Exit a parse tree produced by {@link DOTParser#node_stmt}. 162 | * @param ctx the parse tree 163 | */ 164 | void exitNode_stmt(@NotNull DOTParser.Node_stmtContext ctx); 165 | } -------------------------------------------------------------------------------- /src/main/java/com/paypal/digraph/parser/antlr/DOTParser.java: -------------------------------------------------------------------------------- 1 | package com.paypal.digraph.parser.antlr; 2 | 3 | // Generated from DOT.g4 by ANTLR 4.2 4 | import org.antlr.v4.runtime.atn.*; 5 | import org.antlr.v4.runtime.dfa.DFA; 6 | import org.antlr.v4.runtime.*; 7 | import org.antlr.v4.runtime.misc.*; 8 | import org.antlr.v4.runtime.tree.*; 9 | 10 | 11 | import java.util.List; 12 | import java.util.Iterator; 13 | import java.util.ArrayList; 14 | 15 | @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) 16 | public class DOTParser extends Parser { 17 | protected static final DFA[] _decisionToDFA; 18 | protected static final PredictionContextCache _sharedContextCache = 19 | new PredictionContextCache(); 20 | public static final int 21 | T__9=1, T__8=2, T__7=3, T__6=4, T__5=5, T__4=6, T__3=7, T__2=8, T__1=9, 22 | T__0=10, STRICT=11, GRAPH=12, DIGRAPH=13, NODE=14, EDGE=15, SUBGRAPH=16, 23 | NUMBER=17, STRING=18, ID=19, HTML_STRING=20, COMMENT=21, LINE_COMMENT=22, 24 | PREPROC=23, WS=24; 25 | public static final String[] tokenNames = { 26 | "", "']'", "'->'", "'{'", "','", "'['", "':'", "'--'", "'='", 27 | "'}'", "';'", "STRICT", "GRAPH", "DIGRAPH", "NODE", "EDGE", "SUBGRAPH", 28 | "NUMBER", "STRING", "ID", "HTML_STRING", "COMMENT", "LINE_COMMENT", "PREPROC", 29 | "WS" 30 | }; 31 | public static final int 32 | RULE_graph = 0, RULE_stmt_list = 1, RULE_stmt = 2, RULE_attr_stmt = 3, 33 | RULE_attr_list = 4, RULE_a_list = 5, RULE_edge_stmt = 6, RULE_edgeRHS = 7, 34 | RULE_edgeop = 8, RULE_node_stmt = 9, RULE_node_id = 10, RULE_port = 11, 35 | RULE_subgraph = 12, RULE_id = 13; 36 | public static final String[] ruleNames = { 37 | "graph", "stmt_list", "stmt", "attr_stmt", "attr_list", "a_list", "edge_stmt", 38 | "edgeRHS", "edgeop", "node_stmt", "node_id", "port", "subgraph", "id" 39 | }; 40 | 41 | @Override 42 | public String getGrammarFileName() { return "DOT.g4"; } 43 | 44 | @Override 45 | public String[] getTokenNames() { return tokenNames; } 46 | 47 | @Override 48 | public String[] getRuleNames() { return ruleNames; } 49 | 50 | @Override 51 | public String getSerializedATN() { return _serializedATN; } 52 | 53 | @Override 54 | public ATN getATN() { return _ATN; } 55 | 56 | public DOTParser(TokenStream input) { 57 | super(input); 58 | _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); 59 | } 60 | public static class GraphContext extends ParserRuleContext { 61 | public TerminalNode DIGRAPH() { return getToken(DOTParser.DIGRAPH, 0); } 62 | public TerminalNode GRAPH() { return getToken(DOTParser.GRAPH, 0); } 63 | public IdContext id() { 64 | return getRuleContext(IdContext.class,0); 65 | } 66 | public Stmt_listContext stmt_list() { 67 | return getRuleContext(Stmt_listContext.class,0); 68 | } 69 | public TerminalNode STRICT() { return getToken(DOTParser.STRICT, 0); } 70 | public GraphContext(ParserRuleContext parent, int invokingState) { 71 | super(parent, invokingState); 72 | } 73 | @Override public int getRuleIndex() { return RULE_graph; } 74 | @Override 75 | public void enterRule(ParseTreeListener listener) { 76 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterGraph(this); 77 | } 78 | @Override 79 | public void exitRule(ParseTreeListener listener) { 80 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitGraph(this); 81 | } 82 | } 83 | 84 | public final GraphContext graph() throws RecognitionException { 85 | GraphContext _localctx = new GraphContext(_ctx, getState()); 86 | enterRule(_localctx, 0, RULE_graph); 87 | int _la; 88 | try { 89 | enterOuterAlt(_localctx, 1); 90 | { 91 | setState(29); 92 | _la = _input.LA(1); 93 | if (_la==STRICT) { 94 | { 95 | setState(28); match(STRICT); 96 | } 97 | } 98 | 99 | setState(31); 100 | _la = _input.LA(1); 101 | if ( !(_la==GRAPH || _la==DIGRAPH) ) { 102 | _errHandler.recoverInline(this); 103 | } 104 | consume(); 105 | setState(33); 106 | _la = _input.LA(1); 107 | if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << NUMBER) | (1L << STRING) | (1L << ID) | (1L << HTML_STRING))) != 0)) { 108 | { 109 | setState(32); id(); 110 | } 111 | } 112 | 113 | setState(35); match(3); 114 | setState(36); stmt_list(); 115 | setState(37); match(9); 116 | } 117 | } 118 | catch (RecognitionException re) { 119 | _localctx.exception = re; 120 | _errHandler.reportError(this, re); 121 | _errHandler.recover(this, re); 122 | } 123 | finally { 124 | exitRule(); 125 | } 126 | return _localctx; 127 | } 128 | 129 | public static class Stmt_listContext extends ParserRuleContext { 130 | public StmtContext stmt(int i) { 131 | return getRuleContext(StmtContext.class,i); 132 | } 133 | public List stmt() { 134 | return getRuleContexts(StmtContext.class); 135 | } 136 | public Stmt_listContext(ParserRuleContext parent, int invokingState) { 137 | super(parent, invokingState); 138 | } 139 | @Override public int getRuleIndex() { return RULE_stmt_list; } 140 | @Override 141 | public void enterRule(ParseTreeListener listener) { 142 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterStmt_list(this); 143 | } 144 | @Override 145 | public void exitRule(ParseTreeListener listener) { 146 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitStmt_list(this); 147 | } 148 | } 149 | 150 | public final Stmt_listContext stmt_list() throws RecognitionException { 151 | Stmt_listContext _localctx = new Stmt_listContext(_ctx, getState()); 152 | enterRule(_localctx, 2, RULE_stmt_list); 153 | int _la; 154 | try { 155 | enterOuterAlt(_localctx, 1); 156 | { 157 | setState(45); 158 | _errHandler.sync(this); 159 | _la = _input.LA(1); 160 | while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << 3) | (1L << GRAPH) | (1L << NODE) | (1L << EDGE) | (1L << SUBGRAPH) | (1L << NUMBER) | (1L << STRING) | (1L << ID) | (1L << HTML_STRING))) != 0)) { 161 | { 162 | { 163 | setState(39); stmt(); 164 | setState(41); 165 | _la = _input.LA(1); 166 | if (_la==10) { 167 | { 168 | setState(40); match(10); 169 | } 170 | } 171 | 172 | } 173 | } 174 | setState(47); 175 | _errHandler.sync(this); 176 | _la = _input.LA(1); 177 | } 178 | } 179 | } 180 | catch (RecognitionException re) { 181 | _localctx.exception = re; 182 | _errHandler.reportError(this, re); 183 | _errHandler.recover(this, re); 184 | } 185 | finally { 186 | exitRule(); 187 | } 188 | return _localctx; 189 | } 190 | 191 | public static class StmtContext extends ParserRuleContext { 192 | public SubgraphContext subgraph() { 193 | return getRuleContext(SubgraphContext.class,0); 194 | } 195 | public List id() { 196 | return getRuleContexts(IdContext.class); 197 | } 198 | public Attr_stmtContext attr_stmt() { 199 | return getRuleContext(Attr_stmtContext.class,0); 200 | } 201 | public Edge_stmtContext edge_stmt() { 202 | return getRuleContext(Edge_stmtContext.class,0); 203 | } 204 | public Node_stmtContext node_stmt() { 205 | return getRuleContext(Node_stmtContext.class,0); 206 | } 207 | public IdContext id(int i) { 208 | return getRuleContext(IdContext.class,i); 209 | } 210 | public StmtContext(ParserRuleContext parent, int invokingState) { 211 | super(parent, invokingState); 212 | } 213 | @Override public int getRuleIndex() { return RULE_stmt; } 214 | @Override 215 | public void enterRule(ParseTreeListener listener) { 216 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterStmt(this); 217 | } 218 | @Override 219 | public void exitRule(ParseTreeListener listener) { 220 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitStmt(this); 221 | } 222 | } 223 | 224 | public final StmtContext stmt() throws RecognitionException { 225 | StmtContext _localctx = new StmtContext(_ctx, getState()); 226 | enterRule(_localctx, 4, RULE_stmt); 227 | try { 228 | setState(56); 229 | switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) { 230 | case 1: 231 | enterOuterAlt(_localctx, 1); 232 | { 233 | setState(48); node_stmt(); 234 | } 235 | break; 236 | 237 | case 2: 238 | enterOuterAlt(_localctx, 2); 239 | { 240 | setState(49); edge_stmt(); 241 | } 242 | break; 243 | 244 | case 3: 245 | enterOuterAlt(_localctx, 3); 246 | { 247 | setState(50); attr_stmt(); 248 | } 249 | break; 250 | 251 | case 4: 252 | enterOuterAlt(_localctx, 4); 253 | { 254 | setState(51); id(); 255 | setState(52); match(8); 256 | setState(53); id(); 257 | } 258 | break; 259 | 260 | case 5: 261 | enterOuterAlt(_localctx, 5); 262 | { 263 | setState(55); subgraph(); 264 | } 265 | break; 266 | } 267 | } 268 | catch (RecognitionException re) { 269 | _localctx.exception = re; 270 | _errHandler.reportError(this, re); 271 | _errHandler.recover(this, re); 272 | } 273 | finally { 274 | exitRule(); 275 | } 276 | return _localctx; 277 | } 278 | 279 | public static class Attr_stmtContext extends ParserRuleContext { 280 | public TerminalNode GRAPH() { return getToken(DOTParser.GRAPH, 0); } 281 | public TerminalNode EDGE() { return getToken(DOTParser.EDGE, 0); } 282 | public TerminalNode NODE() { return getToken(DOTParser.NODE, 0); } 283 | public Attr_listContext attr_list() { 284 | return getRuleContext(Attr_listContext.class,0); 285 | } 286 | public Attr_stmtContext(ParserRuleContext parent, int invokingState) { 287 | super(parent, invokingState); 288 | } 289 | @Override public int getRuleIndex() { return RULE_attr_stmt; } 290 | @Override 291 | public void enterRule(ParseTreeListener listener) { 292 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterAttr_stmt(this); 293 | } 294 | @Override 295 | public void exitRule(ParseTreeListener listener) { 296 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitAttr_stmt(this); 297 | } 298 | } 299 | 300 | public final Attr_stmtContext attr_stmt() throws RecognitionException { 301 | Attr_stmtContext _localctx = new Attr_stmtContext(_ctx, getState()); 302 | enterRule(_localctx, 6, RULE_attr_stmt); 303 | int _la; 304 | try { 305 | enterOuterAlt(_localctx, 1); 306 | { 307 | setState(58); 308 | _la = _input.LA(1); 309 | if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << GRAPH) | (1L << NODE) | (1L << EDGE))) != 0)) ) { 310 | _errHandler.recoverInline(this); 311 | } 312 | consume(); 313 | setState(59); attr_list(); 314 | } 315 | } 316 | catch (RecognitionException re) { 317 | _localctx.exception = re; 318 | _errHandler.reportError(this, re); 319 | _errHandler.recover(this, re); 320 | } 321 | finally { 322 | exitRule(); 323 | } 324 | return _localctx; 325 | } 326 | 327 | public static class Attr_listContext extends ParserRuleContext { 328 | public A_listContext a_list(int i) { 329 | return getRuleContext(A_listContext.class,i); 330 | } 331 | public List a_list() { 332 | return getRuleContexts(A_listContext.class); 333 | } 334 | public Attr_listContext(ParserRuleContext parent, int invokingState) { 335 | super(parent, invokingState); 336 | } 337 | @Override public int getRuleIndex() { return RULE_attr_list; } 338 | @Override 339 | public void enterRule(ParseTreeListener listener) { 340 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterAttr_list(this); 341 | } 342 | @Override 343 | public void exitRule(ParseTreeListener listener) { 344 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitAttr_list(this); 345 | } 346 | } 347 | 348 | public final Attr_listContext attr_list() throws RecognitionException { 349 | Attr_listContext _localctx = new Attr_listContext(_ctx, getState()); 350 | enterRule(_localctx, 8, RULE_attr_list); 351 | int _la; 352 | try { 353 | enterOuterAlt(_localctx, 1); 354 | { 355 | setState(66); 356 | _errHandler.sync(this); 357 | _la = _input.LA(1); 358 | do { 359 | { 360 | { 361 | setState(61); match(5); 362 | setState(63); 363 | _la = _input.LA(1); 364 | if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << NUMBER) | (1L << STRING) | (1L << ID) | (1L << HTML_STRING))) != 0)) { 365 | { 366 | setState(62); a_list(); 367 | } 368 | } 369 | 370 | setState(65); match(1); 371 | } 372 | } 373 | setState(68); 374 | _errHandler.sync(this); 375 | _la = _input.LA(1); 376 | } while ( _la==5 ); 377 | } 378 | } 379 | catch (RecognitionException re) { 380 | _localctx.exception = re; 381 | _errHandler.reportError(this, re); 382 | _errHandler.recover(this, re); 383 | } 384 | finally { 385 | exitRule(); 386 | } 387 | return _localctx; 388 | } 389 | 390 | public static class A_listContext extends ParserRuleContext { 391 | public List id() { 392 | return getRuleContexts(IdContext.class); 393 | } 394 | public IdContext id(int i) { 395 | return getRuleContext(IdContext.class,i); 396 | } 397 | public A_listContext(ParserRuleContext parent, int invokingState) { 398 | super(parent, invokingState); 399 | } 400 | @Override public int getRuleIndex() { return RULE_a_list; } 401 | @Override 402 | public void enterRule(ParseTreeListener listener) { 403 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterA_list(this); 404 | } 405 | @Override 406 | public void exitRule(ParseTreeListener listener) { 407 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitA_list(this); 408 | } 409 | } 410 | 411 | public final A_listContext a_list() throws RecognitionException { 412 | A_listContext _localctx = new A_listContext(_ctx, getState()); 413 | enterRule(_localctx, 10, RULE_a_list); 414 | int _la; 415 | try { 416 | enterOuterAlt(_localctx, 1); 417 | { 418 | setState(78); 419 | _errHandler.sync(this); 420 | _la = _input.LA(1); 421 | do { 422 | { 423 | { 424 | setState(70); id(); 425 | setState(73); 426 | _la = _input.LA(1); 427 | if (_la==8) { 428 | { 429 | setState(71); match(8); 430 | setState(72); id(); 431 | } 432 | } 433 | 434 | setState(76); 435 | _la = _input.LA(1); 436 | if (_la==4) { 437 | { 438 | setState(75); match(4); 439 | } 440 | } 441 | 442 | } 443 | } 444 | setState(80); 445 | _errHandler.sync(this); 446 | _la = _input.LA(1); 447 | } while ( (((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << NUMBER) | (1L << STRING) | (1L << ID) | (1L << HTML_STRING))) != 0) ); 448 | } 449 | } 450 | catch (RecognitionException re) { 451 | _localctx.exception = re; 452 | _errHandler.reportError(this, re); 453 | _errHandler.recover(this, re); 454 | } 455 | finally { 456 | exitRule(); 457 | } 458 | return _localctx; 459 | } 460 | 461 | public static class Edge_stmtContext extends ParserRuleContext { 462 | public SubgraphContext subgraph() { 463 | return getRuleContext(SubgraphContext.class,0); 464 | } 465 | public Node_idContext node_id() { 466 | return getRuleContext(Node_idContext.class,0); 467 | } 468 | public EdgeRHSContext edgeRHS() { 469 | return getRuleContext(EdgeRHSContext.class,0); 470 | } 471 | public Attr_listContext attr_list() { 472 | return getRuleContext(Attr_listContext.class,0); 473 | } 474 | public Edge_stmtContext(ParserRuleContext parent, int invokingState) { 475 | super(parent, invokingState); 476 | } 477 | @Override public int getRuleIndex() { return RULE_edge_stmt; } 478 | @Override 479 | public void enterRule(ParseTreeListener listener) { 480 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterEdge_stmt(this); 481 | } 482 | @Override 483 | public void exitRule(ParseTreeListener listener) { 484 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitEdge_stmt(this); 485 | } 486 | } 487 | 488 | public final Edge_stmtContext edge_stmt() throws RecognitionException { 489 | Edge_stmtContext _localctx = new Edge_stmtContext(_ctx, getState()); 490 | enterRule(_localctx, 12, RULE_edge_stmt); 491 | int _la; 492 | try { 493 | enterOuterAlt(_localctx, 1); 494 | { 495 | setState(84); 496 | switch (_input.LA(1)) { 497 | case NUMBER: 498 | case STRING: 499 | case ID: 500 | case HTML_STRING: 501 | { 502 | setState(82); node_id(); 503 | } 504 | break; 505 | case 3: 506 | case SUBGRAPH: 507 | { 508 | setState(83); subgraph(); 509 | } 510 | break; 511 | default: 512 | throw new NoViableAltException(this); 513 | } 514 | setState(86); edgeRHS(); 515 | setState(88); 516 | _la = _input.LA(1); 517 | if (_la==5) { 518 | { 519 | setState(87); attr_list(); 520 | } 521 | } 522 | 523 | } 524 | } 525 | catch (RecognitionException re) { 526 | _localctx.exception = re; 527 | _errHandler.reportError(this, re); 528 | _errHandler.recover(this, re); 529 | } 530 | finally { 531 | exitRule(); 532 | } 533 | return _localctx; 534 | } 535 | 536 | public static class EdgeRHSContext extends ParserRuleContext { 537 | public List subgraph() { 538 | return getRuleContexts(SubgraphContext.class); 539 | } 540 | public Node_idContext node_id(int i) { 541 | return getRuleContext(Node_idContext.class,i); 542 | } 543 | public SubgraphContext subgraph(int i) { 544 | return getRuleContext(SubgraphContext.class,i); 545 | } 546 | public EdgeopContext edgeop(int i) { 547 | return getRuleContext(EdgeopContext.class,i); 548 | } 549 | public List edgeop() { 550 | return getRuleContexts(EdgeopContext.class); 551 | } 552 | public List node_id() { 553 | return getRuleContexts(Node_idContext.class); 554 | } 555 | public EdgeRHSContext(ParserRuleContext parent, int invokingState) { 556 | super(parent, invokingState); 557 | } 558 | @Override public int getRuleIndex() { return RULE_edgeRHS; } 559 | @Override 560 | public void enterRule(ParseTreeListener listener) { 561 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterEdgeRHS(this); 562 | } 563 | @Override 564 | public void exitRule(ParseTreeListener listener) { 565 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitEdgeRHS(this); 566 | } 567 | } 568 | 569 | public final EdgeRHSContext edgeRHS() throws RecognitionException { 570 | EdgeRHSContext _localctx = new EdgeRHSContext(_ctx, getState()); 571 | enterRule(_localctx, 14, RULE_edgeRHS); 572 | int _la; 573 | try { 574 | enterOuterAlt(_localctx, 1); 575 | { 576 | setState(95); 577 | _errHandler.sync(this); 578 | _la = _input.LA(1); 579 | do { 580 | { 581 | { 582 | setState(90); edgeop(); 583 | setState(93); 584 | switch (_input.LA(1)) { 585 | case NUMBER: 586 | case STRING: 587 | case ID: 588 | case HTML_STRING: 589 | { 590 | setState(91); node_id(); 591 | } 592 | break; 593 | case 3: 594 | case SUBGRAPH: 595 | { 596 | setState(92); subgraph(); 597 | } 598 | break; 599 | default: 600 | throw new NoViableAltException(this); 601 | } 602 | } 603 | } 604 | setState(97); 605 | _errHandler.sync(this); 606 | _la = _input.LA(1); 607 | } while ( _la==2 || _la==7 ); 608 | } 609 | } 610 | catch (RecognitionException re) { 611 | _localctx.exception = re; 612 | _errHandler.reportError(this, re); 613 | _errHandler.recover(this, re); 614 | } 615 | finally { 616 | exitRule(); 617 | } 618 | return _localctx; 619 | } 620 | 621 | public static class EdgeopContext extends ParserRuleContext { 622 | public EdgeopContext(ParserRuleContext parent, int invokingState) { 623 | super(parent, invokingState); 624 | } 625 | @Override public int getRuleIndex() { return RULE_edgeop; } 626 | @Override 627 | public void enterRule(ParseTreeListener listener) { 628 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterEdgeop(this); 629 | } 630 | @Override 631 | public void exitRule(ParseTreeListener listener) { 632 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitEdgeop(this); 633 | } 634 | } 635 | 636 | public final EdgeopContext edgeop() throws RecognitionException { 637 | EdgeopContext _localctx = new EdgeopContext(_ctx, getState()); 638 | enterRule(_localctx, 16, RULE_edgeop); 639 | int _la; 640 | try { 641 | enterOuterAlt(_localctx, 1); 642 | { 643 | setState(99); 644 | _la = _input.LA(1); 645 | if ( !(_la==2 || _la==7) ) { 646 | _errHandler.recoverInline(this); 647 | } 648 | consume(); 649 | } 650 | } 651 | catch (RecognitionException re) { 652 | _localctx.exception = re; 653 | _errHandler.reportError(this, re); 654 | _errHandler.recover(this, re); 655 | } 656 | finally { 657 | exitRule(); 658 | } 659 | return _localctx; 660 | } 661 | 662 | public static class Node_stmtContext extends ParserRuleContext { 663 | public Node_idContext node_id() { 664 | return getRuleContext(Node_idContext.class,0); 665 | } 666 | public Attr_listContext attr_list() { 667 | return getRuleContext(Attr_listContext.class,0); 668 | } 669 | public Node_stmtContext(ParserRuleContext parent, int invokingState) { 670 | super(parent, invokingState); 671 | } 672 | @Override public int getRuleIndex() { return RULE_node_stmt; } 673 | @Override 674 | public void enterRule(ParseTreeListener listener) { 675 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterNode_stmt(this); 676 | } 677 | @Override 678 | public void exitRule(ParseTreeListener listener) { 679 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitNode_stmt(this); 680 | } 681 | } 682 | 683 | public final Node_stmtContext node_stmt() throws RecognitionException { 684 | Node_stmtContext _localctx = new Node_stmtContext(_ctx, getState()); 685 | enterRule(_localctx, 18, RULE_node_stmt); 686 | int _la; 687 | try { 688 | enterOuterAlt(_localctx, 1); 689 | { 690 | setState(101); node_id(); 691 | setState(103); 692 | _la = _input.LA(1); 693 | if (_la==5) { 694 | { 695 | setState(102); attr_list(); 696 | } 697 | } 698 | 699 | } 700 | } 701 | catch (RecognitionException re) { 702 | _localctx.exception = re; 703 | _errHandler.reportError(this, re); 704 | _errHandler.recover(this, re); 705 | } 706 | finally { 707 | exitRule(); 708 | } 709 | return _localctx; 710 | } 711 | 712 | public static class Node_idContext extends ParserRuleContext { 713 | public PortContext port() { 714 | return getRuleContext(PortContext.class,0); 715 | } 716 | public IdContext id() { 717 | return getRuleContext(IdContext.class,0); 718 | } 719 | public Node_idContext(ParserRuleContext parent, int invokingState) { 720 | super(parent, invokingState); 721 | } 722 | @Override public int getRuleIndex() { return RULE_node_id; } 723 | @Override 724 | public void enterRule(ParseTreeListener listener) { 725 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterNode_id(this); 726 | } 727 | @Override 728 | public void exitRule(ParseTreeListener listener) { 729 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitNode_id(this); 730 | } 731 | } 732 | 733 | public final Node_idContext node_id() throws RecognitionException { 734 | Node_idContext _localctx = new Node_idContext(_ctx, getState()); 735 | enterRule(_localctx, 20, RULE_node_id); 736 | int _la; 737 | try { 738 | enterOuterAlt(_localctx, 1); 739 | { 740 | setState(105); id(); 741 | setState(107); 742 | _la = _input.LA(1); 743 | if (_la==6) { 744 | { 745 | setState(106); port(); 746 | } 747 | } 748 | 749 | } 750 | } 751 | catch (RecognitionException re) { 752 | _localctx.exception = re; 753 | _errHandler.reportError(this, re); 754 | _errHandler.recover(this, re); 755 | } 756 | finally { 757 | exitRule(); 758 | } 759 | return _localctx; 760 | } 761 | 762 | public static class PortContext extends ParserRuleContext { 763 | public List id() { 764 | return getRuleContexts(IdContext.class); 765 | } 766 | public IdContext id(int i) { 767 | return getRuleContext(IdContext.class,i); 768 | } 769 | public PortContext(ParserRuleContext parent, int invokingState) { 770 | super(parent, invokingState); 771 | } 772 | @Override public int getRuleIndex() { return RULE_port; } 773 | @Override 774 | public void enterRule(ParseTreeListener listener) { 775 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterPort(this); 776 | } 777 | @Override 778 | public void exitRule(ParseTreeListener listener) { 779 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitPort(this); 780 | } 781 | } 782 | 783 | public final PortContext port() throws RecognitionException { 784 | PortContext _localctx = new PortContext(_ctx, getState()); 785 | enterRule(_localctx, 22, RULE_port); 786 | int _la; 787 | try { 788 | enterOuterAlt(_localctx, 1); 789 | { 790 | setState(109); match(6); 791 | setState(110); id(); 792 | setState(113); 793 | _la = _input.LA(1); 794 | if (_la==6) { 795 | { 796 | setState(111); match(6); 797 | setState(112); id(); 798 | } 799 | } 800 | 801 | } 802 | } 803 | catch (RecognitionException re) { 804 | _localctx.exception = re; 805 | _errHandler.reportError(this, re); 806 | _errHandler.recover(this, re); 807 | } 808 | finally { 809 | exitRule(); 810 | } 811 | return _localctx; 812 | } 813 | 814 | public static class SubgraphContext extends ParserRuleContext { 815 | public IdContext id() { 816 | return getRuleContext(IdContext.class,0); 817 | } 818 | public TerminalNode SUBGRAPH() { return getToken(DOTParser.SUBGRAPH, 0); } 819 | public Stmt_listContext stmt_list() { 820 | return getRuleContext(Stmt_listContext.class,0); 821 | } 822 | public SubgraphContext(ParserRuleContext parent, int invokingState) { 823 | super(parent, invokingState); 824 | } 825 | @Override public int getRuleIndex() { return RULE_subgraph; } 826 | @Override 827 | public void enterRule(ParseTreeListener listener) { 828 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterSubgraph(this); 829 | } 830 | @Override 831 | public void exitRule(ParseTreeListener listener) { 832 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitSubgraph(this); 833 | } 834 | } 835 | 836 | public final SubgraphContext subgraph() throws RecognitionException { 837 | SubgraphContext _localctx = new SubgraphContext(_ctx, getState()); 838 | enterRule(_localctx, 24, RULE_subgraph); 839 | int _la; 840 | try { 841 | enterOuterAlt(_localctx, 1); 842 | { 843 | setState(119); 844 | _la = _input.LA(1); 845 | if (_la==SUBGRAPH) { 846 | { 847 | setState(115); match(SUBGRAPH); 848 | setState(117); 849 | _la = _input.LA(1); 850 | if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << NUMBER) | (1L << STRING) | (1L << ID) | (1L << HTML_STRING))) != 0)) { 851 | { 852 | setState(116); id(); 853 | } 854 | } 855 | 856 | } 857 | } 858 | 859 | setState(121); match(3); 860 | setState(122); stmt_list(); 861 | setState(123); match(9); 862 | } 863 | } 864 | catch (RecognitionException re) { 865 | _localctx.exception = re; 866 | _errHandler.reportError(this, re); 867 | _errHandler.recover(this, re); 868 | } 869 | finally { 870 | exitRule(); 871 | } 872 | return _localctx; 873 | } 874 | 875 | public static class IdContext extends ParserRuleContext { 876 | public TerminalNode ID() { return getToken(DOTParser.ID, 0); } 877 | public TerminalNode NUMBER() { return getToken(DOTParser.NUMBER, 0); } 878 | public TerminalNode HTML_STRING() { return getToken(DOTParser.HTML_STRING, 0); } 879 | public TerminalNode STRING() { return getToken(DOTParser.STRING, 0); } 880 | public IdContext(ParserRuleContext parent, int invokingState) { 881 | super(parent, invokingState); 882 | } 883 | @Override public int getRuleIndex() { return RULE_id; } 884 | @Override 885 | public void enterRule(ParseTreeListener listener) { 886 | if ( listener instanceof DOTListener ) ((DOTListener)listener).enterId(this); 887 | } 888 | @Override 889 | public void exitRule(ParseTreeListener listener) { 890 | if ( listener instanceof DOTListener ) ((DOTListener)listener).exitId(this); 891 | } 892 | } 893 | 894 | public final IdContext id() throws RecognitionException { 895 | IdContext _localctx = new IdContext(_ctx, getState()); 896 | enterRule(_localctx, 26, RULE_id); 897 | int _la; 898 | try { 899 | enterOuterAlt(_localctx, 1); 900 | { 901 | setState(125); 902 | _la = _input.LA(1); 903 | if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << NUMBER) | (1L << STRING) | (1L << ID) | (1L << HTML_STRING))) != 0)) ) { 904 | _errHandler.recoverInline(this); 905 | } 906 | consume(); 907 | } 908 | } 909 | catch (RecognitionException re) { 910 | _localctx.exception = re; 911 | _errHandler.reportError(this, re); 912 | _errHandler.recover(this, re); 913 | } 914 | finally { 915 | exitRule(); 916 | } 917 | return _localctx; 918 | } 919 | 920 | public static final String _serializedATN = 921 | "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\32\u0082\4\2\t\2"+ 922 | "\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+ 923 | "\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\3\2\5\2 \n\2\3\2\3\2\5\2$\n"+ 924 | "\2\3\2\3\2\3\2\3\2\3\3\3\3\5\3,\n\3\7\3.\n\3\f\3\16\3\61\13\3\3\4\3\4"+ 925 | "\3\4\3\4\3\4\3\4\3\4\3\4\5\4;\n\4\3\5\3\5\3\5\3\6\3\6\5\6B\n\6\3\6\6\6"+ 926 | "E\n\6\r\6\16\6F\3\7\3\7\3\7\5\7L\n\7\3\7\5\7O\n\7\6\7Q\n\7\r\7\16\7R\3"+ 927 | "\b\3\b\5\bW\n\b\3\b\3\b\5\b[\n\b\3\t\3\t\3\t\5\t`\n\t\6\tb\n\t\r\t\16"+ 928 | "\tc\3\n\3\n\3\13\3\13\5\13j\n\13\3\f\3\f\5\fn\n\f\3\r\3\r\3\r\3\r\5\r"+ 929 | "t\n\r\3\16\3\16\5\16x\n\16\5\16z\n\16\3\16\3\16\3\16\3\16\3\17\3\17\3"+ 930 | "\17\2\2\20\2\4\6\b\n\f\16\20\22\24\26\30\32\34\2\6\3\2\16\17\4\2\16\16"+ 931 | "\20\21\4\2\4\4\t\t\3\2\23\26\u0089\2\37\3\2\2\2\4/\3\2\2\2\6:\3\2\2\2"+ 932 | "\b<\3\2\2\2\nD\3\2\2\2\fP\3\2\2\2\16V\3\2\2\2\20a\3\2\2\2\22e\3\2\2\2"+ 933 | "\24g\3\2\2\2\26k\3\2\2\2\30o\3\2\2\2\32y\3\2\2\2\34\177\3\2\2\2\36 \7"+ 934 | "\r\2\2\37\36\3\2\2\2\37 \3\2\2\2 !\3\2\2\2!#\t\2\2\2\"$\5\34\17\2#\"\3"+ 935 | "\2\2\2#$\3\2\2\2$%\3\2\2\2%&\7\5\2\2&\'\5\4\3\2\'(\7\13\2\2(\3\3\2\2\2"+ 936 | ")+\5\6\4\2*,\7\f\2\2+*\3\2\2\2+,\3\2\2\2,.\3\2\2\2-)\3\2\2\2.\61\3\2\2"+ 937 | "\2/-\3\2\2\2/\60\3\2\2\2\60\5\3\2\2\2\61/\3\2\2\2\62;\5\24\13\2\63;\5"+ 938 | "\16\b\2\64;\5\b\5\2\65\66\5\34\17\2\66\67\7\n\2\2\678\5\34\17\28;\3\2"+ 939 | "\2\29;\5\32\16\2:\62\3\2\2\2:\63\3\2\2\2:\64\3\2\2\2:\65\3\2\2\2:9\3\2"+ 940 | "\2\2;\7\3\2\2\2<=\t\3\2\2=>\5\n\6\2>\t\3\2\2\2?A\7\7\2\2@B\5\f\7\2A@\3"+ 941 | "\2\2\2AB\3\2\2\2BC\3\2\2\2CE\7\3\2\2D?\3\2\2\2EF\3\2\2\2FD\3\2\2\2FG\3"+ 942 | "\2\2\2G\13\3\2\2\2HK\5\34\17\2IJ\7\n\2\2JL\5\34\17\2KI\3\2\2\2KL\3\2\2"+ 943 | "\2LN\3\2\2\2MO\7\6\2\2NM\3\2\2\2NO\3\2\2\2OQ\3\2\2\2PH\3\2\2\2QR\3\2\2"+ 944 | "\2RP\3\2\2\2RS\3\2\2\2S\r\3\2\2\2TW\5\26\f\2UW\5\32\16\2VT\3\2\2\2VU\3"+ 945 | "\2\2\2WX\3\2\2\2XZ\5\20\t\2Y[\5\n\6\2ZY\3\2\2\2Z[\3\2\2\2[\17\3\2\2\2"+ 946 | "\\_\5\22\n\2]`\5\26\f\2^`\5\32\16\2_]\3\2\2\2_^\3\2\2\2`b\3\2\2\2a\\\3"+ 947 | "\2\2\2bc\3\2\2\2ca\3\2\2\2cd\3\2\2\2d\21\3\2\2\2ef\t\4\2\2f\23\3\2\2\2"+ 948 | "gi\5\26\f\2hj\5\n\6\2ih\3\2\2\2ij\3\2\2\2j\25\3\2\2\2km\5\34\17\2ln\5"+ 949 | "\30\r\2ml\3\2\2\2mn\3\2\2\2n\27\3\2\2\2op\7\b\2\2ps\5\34\17\2qr\7\b\2"+ 950 | "\2rt\5\34\17\2sq\3\2\2\2st\3\2\2\2t\31\3\2\2\2uw\7\22\2\2vx\5\34\17\2"+ 951 | "wv\3\2\2\2wx\3\2\2\2xz\3\2\2\2yu\3\2\2\2yz\3\2\2\2z{\3\2\2\2{|\7\5\2\2"+ 952 | "|}\5\4\3\2}~\7\13\2\2~\33\3\2\2\2\177\u0080\t\5\2\2\u0080\35\3\2\2\2\25"+ 953 | "\37#+/:AFKNRVZ_cimswy"; 954 | public static final ATN _ATN = 955 | new ATNDeserializer().deserialize(_serializedATN.toCharArray()); 956 | static { 957 | _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; 958 | for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { 959 | _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); 960 | } 961 | } 962 | } -------------------------------------------------------------------------------- /src/test/java/com/paypal/digraph/parser/ParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | [BSD 3-Clause License] 3 | 4 | Copyright (c) 2017, PayPal Holdings, Inc. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.paypal.digraph.parser; 33 | 34 | import java.io.FileInputStream; 35 | import java.util.Map; 36 | 37 | import org.antlr.v4.runtime.ANTLRFileStream; 38 | import org.antlr.v4.runtime.BailErrorStrategy; 39 | import org.antlr.v4.runtime.CommonTokenStream; 40 | import org.antlr.v4.runtime.tree.ParseTree; 41 | import org.antlr.v4.runtime.tree.ParseTreeWalker; 42 | import org.junit.Assert; 43 | import org.junit.Test; 44 | 45 | import com.paypal.digraph.parser.antlr.DOTBaseListener; 46 | import com.paypal.digraph.parser.antlr.DOTLexer; 47 | import com.paypal.digraph.parser.antlr.DOTParser; 48 | 49 | public class ParserTest 50 | { 51 | @Test 52 | public void testGraphParserUsage() { 53 | log("--- testGraphParserUsage ---"); 54 | 55 | try { 56 | GraphParser parser = new GraphParser(new FileInputStream("src/test/resources/test1.dg")); 57 | Map nodes = parser.getNodes(); 58 | Map edges = parser.getEdges(); 59 | 60 | log("--- nodes:"); 61 | for (GraphNode node : nodes.values()) { 62 | log(node.getId() + " " + node.getAttributes()); 63 | } 64 | 65 | log("--- edges:"); 66 | for (GraphEdge edge : edges.values()) { 67 | log(edge.getNode1().getId() + "->" + edge.getNode2().getId() + " " + edge.getAttributes()); 68 | } 69 | } 70 | catch (Exception e) { 71 | e.printStackTrace(); 72 | log(e); 73 | } 74 | } 75 | 76 | @Test 77 | public void testGraphParser() { 78 | log("--- testGraphParser ---"); 79 | 80 | try { 81 | String fname = "src/test/resources/test1.dg"; 82 | log("--- " + fname); 83 | 84 | GraphParser parser = new GraphParser(new FileInputStream(fname)); 85 | log(parser.getNodes()); 86 | log(parser.getEdges()); 87 | 88 | String nodeStr = "{a=GraphNode-a{}, b=GraphNode-b{}, bar=GraphNode-bar{kk=vv, kkk=vvv}, baz=GraphNode-baz{}, foo=GraphNode-foo{}, n1=GraphNode-n1{label=Node 1}, n2=GraphNode-n2{label=Node 2}, n3=GraphNode-n3{}, n4=GraphNode-n4{}, n5=GraphNode-n5{}, xxx=GraphNode-xxx{k=v}, yyy=GraphNode-yyy{k1=v1, k2=v2}}"; 89 | String edgeStr = "{a-b=GraphEdge-a-b{}, foo-bar=GraphEdge-foo-bar{fbk=fbv, ek=ev}, foo-baz=GraphEdge-foo-baz{ek=ev}, n1-n2=GraphEdge-n1-n2{style=dotted, label=A dotted edge}, n1-n4=GraphEdge-n1-n4{}, n2-n3=GraphEdge-n2-n3{}, n3-n5=GraphEdge-n3-n5{}, n4-n5=GraphEdge-n4-n5{}}"; 90 | 91 | Assert.assertEquals("testgraph", parser.getGraphId()); 92 | Assert.assertEquals(nodeStr, parser.getNodes().toString()); 93 | Assert.assertEquals(edgeStr, parser.getEdges().toString()); 94 | } 95 | catch (Exception e) { 96 | e.printStackTrace(); 97 | log(e); 98 | } 99 | 100 | try { 101 | String fname = "src/test/resources/test2.dg"; 102 | log("--- " + fname); 103 | 104 | GraphParser parser = new GraphParser(new FileInputStream(fname)); 105 | log(parser.getNodes()); 106 | log(parser.getEdges()); 107 | 108 | String nodeStr = "{01=GraphNode-01{}, 02=GraphNode-02{}, 03=GraphNode-03{}, 04=GraphNode-04{}, 05=GraphNode-05{}, 06=GraphNode-06{}, 07=GraphNode-07{}, 1=GraphNode-1{}, 11=GraphNode-11{}, 12=GraphNode-12{}, 13=GraphNode-13{}, 14=GraphNode-14{}, 15=GraphNode-15{}, 16=GraphNode-16{}, 17=GraphNode-17{}, 2=GraphNode-2{}, 21=GraphNode-21{}, 22=GraphNode-22{}, 23=GraphNode-23{}, 24=GraphNode-24{}, 25=GraphNode-25{}, 26=GraphNode-26{}, 27=GraphNode-27{}, 3=GraphNode-3{}, 4=GraphNode-4{}, a=GraphNode-a{}, a1=GraphNode-a1{}, a2=GraphNode-a2{}, aa=GraphNode-aa{}, b=GraphNode-b{}, b1=GraphNode-b1{}, b2=GraphNode-b2{}, bb=GraphNode-bb{}, c=GraphNode-c{}, c1=GraphNode-c1{}, c2=GraphNode-c2{}, cc=GraphNode-cc{}, d=GraphNode-d{}, d1=GraphNode-d1{}, d2=GraphNode-d2{}, dd=GraphNode-dd{}, e=GraphNode-e{}, ee=GraphNode-ee{}, f=GraphNode-f{}, ff=GraphNode-ff{}, m1=GraphNode-m1{}, m2=GraphNode-m2{}, n1=GraphNode-n1{}, n2=GraphNode-n2{}}"; 109 | String edgeStr = "{01-02=GraphEdge-01-02{}, 02-03=GraphEdge-02-03{}, 03-04=GraphEdge-03-04{}, 03-05=GraphEdge-03-05{}, 04-06=GraphEdge-04-06{}, 05-06=GraphEdge-05-06{}, 06-07=GraphEdge-06-07{}, 1-2=GraphEdge-1-2{}, 1-3=GraphEdge-1-3{}, 1-4=GraphEdge-1-4{}, 11-12=GraphEdge-11-12{}, 12-13=GraphEdge-12-13{}, 13-14=GraphEdge-13-14{}, 13-15=GraphEdge-13-15{}, 14-15=GraphEdge-14-15{}, 14-16=GraphEdge-14-16{}, 15-16=GraphEdge-15-16{}, 16-17=GraphEdge-16-17{}, 2-3=GraphEdge-2-3{}, 2-4=GraphEdge-2-4{}, 21-22=GraphEdge-21-22{label=test}, 22-23=GraphEdge-22-23{label=test}, 23-24=GraphEdge-23-24{label=test}, 23-25=GraphEdge-23-25{label=test}, 24-25=GraphEdge-24-25{label=xxx}, 24-26=GraphEdge-24-26{label=test}, 25-26=GraphEdge-25-26{label=test}, 26-27=GraphEdge-26-27{label=test}, 3-4=GraphEdge-3-4{}, a-c=GraphEdge-a-c{}, a-d=GraphEdge-a-d{}, a1-b1=GraphEdge-a1-b1{}, a1-c1=GraphEdge-a1-c1{}, a1-m1=GraphEdge-a1-m1{}, a1-n1=GraphEdge-a1-n1{}, a2-b2=GraphEdge-a2-b2{}, a2-c2=GraphEdge-a2-c2{}, a2-m2=GraphEdge-a2-m2{}, a2-n2=GraphEdge-a2-n2{}, aa-cc=GraphEdge-aa-cc{}, aa-dd=GraphEdge-aa-dd{}, aa-ee=GraphEdge-aa-ee{}, aa-ff=GraphEdge-aa-ff{}, b-c=GraphEdge-b-c{}, b-d=GraphEdge-b-d{}, b1-c1=GraphEdge-b1-c1{}, b1-d1=GraphEdge-b1-d1{}, b2-c2=GraphEdge-b2-c2{}, b2-d2=GraphEdge-b2-d2{}, bb-cc=GraphEdge-bb-cc{}, bb-dd=GraphEdge-bb-dd{}, bb-ee=GraphEdge-bb-ee{}, bb-ff=GraphEdge-bb-ff{}, c-e=GraphEdge-c-e{}, c-f=GraphEdge-c-f{}, c1-d1=GraphEdge-c1-d1{}, c1-m1=GraphEdge-c1-m1{}, c1-n1=GraphEdge-c1-n1{}, c2-d2=GraphEdge-c2-d2{}, c2-m2=GraphEdge-c2-m2{}, c2-n2=GraphEdge-c2-n2{}, cc-ee=GraphEdge-cc-ee{}, cc-ff=GraphEdge-cc-ff{}, d-e=GraphEdge-d-e{}, d-f=GraphEdge-d-f{}, dd-ee=GraphEdge-dd-ee{}, dd-ff=GraphEdge-dd-ff{}, m1-d1=GraphEdge-m1-d1{}, m2-d2=GraphEdge-m2-d2{}, m2-n2=GraphEdge-m2-n2{}, n1-d1=GraphEdge-n1-d1{}, n2-d2=GraphEdge-n2-d2{}}"; 110 | 111 | Assert.assertEquals(nodeStr, parser.getNodes().toString()); 112 | Assert.assertEquals(edgeStr, parser.getEdges().toString()); 113 | } 114 | catch (Exception e) { 115 | e.printStackTrace(); 116 | log(e); 117 | } 118 | 119 | try { 120 | String fname = "src/test/resources/test3.dg"; 121 | log("--- " + fname); 122 | 123 | GraphParser parser = new GraphParser(new FileInputStream(fname)); 124 | log(parser.getNodes()); 125 | log(parser.getEdges()); 126 | 127 | String nodeStr = "{01=GraphNode-01{}, 02=GraphNode-02{}, 03=GraphNode-03{}, 04=GraphNode-04{}, 05=GraphNode-05{}, 06=GraphNode-06{}, 07=GraphNode-07{}, 08=GraphNode-08{}, 11=GraphNode-11{}, 12=GraphNode-12{}, 13=GraphNode-13{}, 15=GraphNode-15{}, 16=GraphNode-16{}, 17=GraphNode-17{}, 18=GraphNode-18{}, 21=GraphNode-21{}, 22=GraphNode-22{}, 23=GraphNode-23{}, 24=GraphNode-24{}, 25=GraphNode-25{}, 26=GraphNode-26{}, 27=GraphNode-27{}}"; 128 | String edgeStr = "{01-02=GraphEdge-01-02{}, 01-03=GraphEdge-01-03{}, 01-04=GraphEdge-01-04{}, 01-05=GraphEdge-01-05{}, 01-06=GraphEdge-01-06{}, 01-07=GraphEdge-01-07{}, 02-03=GraphEdge-02-03{}, 02-04=GraphEdge-02-04{}, 02-05=GraphEdge-02-05{}, 02-06=GraphEdge-02-06{}, 02-07=GraphEdge-02-07{}, 03-08=GraphEdge-03-08{}, 04-05=GraphEdge-04-05{}, 04-06=GraphEdge-04-06{}, 04-08=GraphEdge-04-08{}, 05-08=GraphEdge-05-08{}, 06-08=GraphEdge-06-08{}, 07-08=GraphEdge-07-08{}, 11-12=GraphEdge-11-12{}, 11-15=GraphEdge-11-15{}, 11-16=GraphEdge-11-16{}, 11-17=GraphEdge-11-17{}, 11-18=GraphEdge-11-18{}, 12-13=GraphEdge-12-13{}, 12-15=GraphEdge-12-15{}, 12-16=GraphEdge-12-16{}, 12-17=GraphEdge-12-17{}, 12-18=GraphEdge-12-18{}, 13-15=GraphEdge-13-15{}, 13-16=GraphEdge-13-16{}, 13-17=GraphEdge-13-17{}, 13-18=GraphEdge-13-18{}, 15-16=GraphEdge-15-16{}, 21-22=GraphEdge-21-22{}, 21-25=GraphEdge-21-25{}, 21-26=GraphEdge-21-26{}, 21-27=GraphEdge-21-27{}, 22-23=GraphEdge-22-23{}, 22-25=GraphEdge-22-25{}, 22-26=GraphEdge-22-26{}, 22-27=GraphEdge-22-27{}, 23-24=GraphEdge-23-24{}, 23-25=GraphEdge-23-25{}, 23-26=GraphEdge-23-26{}, 23-27=GraphEdge-23-27{}, 24-25=GraphEdge-24-25{}, 24-26=GraphEdge-24-26{}, 24-27=GraphEdge-24-27{}, 25-26=GraphEdge-25-26{}, 26-27=GraphEdge-26-27{}}"; 129 | 130 | Assert.assertEquals(nodeStr, parser.getNodes().toString()); 131 | Assert.assertEquals(edgeStr, parser.getEdges().toString()); 132 | } 133 | catch (Exception e) { 134 | e.printStackTrace(); 135 | log(e); 136 | } 137 | } 138 | 139 | @Test 140 | public void testAntlrParser() throws Exception { 141 | log("--- testAntlrParser ---"); 142 | 143 | try { 144 | String fname = "src/test/resources/test1.dg"; 145 | log("--- " + fname); 146 | 147 | DOTLexer lexer = new DOTLexer(new ANTLRFileStream(fname)); 148 | DOTParser parser = new DOTParser(new CommonTokenStream(lexer)); 149 | parser.setErrorHandler(new BailErrorStrategy()); 150 | ParseTree tree = parser.graph(); 151 | log(tree.toStringTree(parser)); 152 | ParseTreeWalker.DEFAULT.walk(new DOTBaseListener(), tree); 153 | } 154 | catch (Exception e) { 155 | e.printStackTrace(); 156 | log(e); 157 | } 158 | 159 | try { 160 | String fname = "src/test/resources/test2.dg"; 161 | log("--- " + fname); 162 | 163 | DOTLexer lexer = new DOTLexer(new ANTLRFileStream(fname)); 164 | DOTParser parser = new DOTParser(new CommonTokenStream(lexer)); 165 | parser.setErrorHandler(new BailErrorStrategy()); 166 | ParseTree tree = parser.graph(); 167 | log(tree.toStringTree(parser)); 168 | ParseTreeWalker.DEFAULT.walk(new DOTBaseListener(), tree); 169 | } 170 | catch (Exception e) { 171 | e.printStackTrace(); 172 | log(e); 173 | } 174 | 175 | try { 176 | String fname = "src/test/resources/test3.dg"; 177 | log("--- " + fname); 178 | 179 | DOTLexer lexer = new DOTLexer(new ANTLRFileStream(fname)); 180 | DOTParser parser = new DOTParser(new CommonTokenStream(lexer)); 181 | parser.setErrorHandler(new BailErrorStrategy()); 182 | ParseTree tree = parser.graph(); 183 | log(tree.toStringTree(parser)); 184 | ParseTreeWalker.DEFAULT.walk(new DOTBaseListener(), tree); 185 | } 186 | catch (Exception e) { 187 | e.printStackTrace(); 188 | log(e); 189 | } 190 | } 191 | 192 | public static void log(Object o) { 193 | System.out.println(o); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/test/java/com/paypal/digraph/parser/RunAntlrTestRig.java: -------------------------------------------------------------------------------- 1 | /* 2 | [BSD 3-Clause License] 3 | 4 | Copyright (c) 2017, PayPal Holdings, Inc. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.paypal.digraph.parser; 33 | 34 | import org.antlr.v4.runtime.misc.TestRig; 35 | 36 | public class RunAntlrTestRig 37 | { 38 | public static void main(String[] args) throws Exception { 39 | String grammarName = "com.paypal.digraph.parser.antlr.DOT"; 40 | String startRuleName = "graph"; 41 | 42 | String[] testArgs1 = {grammarName, startRuleName, "-tree", "src/test/resources/test3.dg"}; 43 | TestRig.main(testArgs1); 44 | 45 | String[] testArgs2 = {grammarName, startRuleName, "-gui", "src/test/resources/test3.dg"}; 46 | TestRig.main(testArgs2); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/resources/test1.dg: -------------------------------------------------------------------------------- 1 | digraph testgraph 2 | { 3 | xxx [k=v] 4 | yyy [k1=v1 k2=v2] 5 | a -> b 6 | n1 [label="Node 1"]; n2 [label="Node 2"]; 7 | n1 -> n2 [style=dotted label="A dotted edge"] 8 | n1 -> n4 9 | n2 -> n3 10 | n3 -> n5 11 | foo -> { bar baz } [ek=ev] 12 | foo -> bar [fbk=fbv] 13 | n4 -> n5 14 | bar [kk=vv] 15 | bar [kkk=vvv] 16 | } 17 | -------------------------------------------------------------------------------- /src/test/resources/test2.dg: -------------------------------------------------------------------------------- 1 | digraph 2 | { 3 | {1->2} -> {3->4} 4 | 5 | 01->02->03->{04 05}->06->07 6 | 11->12->13->{14->15}->16->17 7 | 8 | 21->22->23->{24->25 [label=xxx]}->26->27 [label=test] 9 | 10 | {a b} -> {c d} -> {e f} 11 | {aa bb} -> {{cc dd} -> {ee ff}} 12 | 13 | a1->{b1->c1->{m1 n1}}->d1 14 | a2->{b2->c2->{m2->n2}}->d2 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/test3.dg: -------------------------------------------------------------------------------- 1 | digraph 2 | { 3 | 01->02 4 | {01 02} -> {03 04->{05 06} 07} -> 08 5 | {11->12->13} -> {15->16 17 18} 6 | {21->22->23->24} -> {25->26->27} 7 | } 8 | --------------------------------------------------------------------------------