1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2013 Terence Parr 4 * Copyright (c) 2013 Sam Harwell 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 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 module antlr.v4.runtime.tree.pattern.ParseTreeMatch; 32 33 import std.format; 34 import antlr.v4.runtime.IllegalArgumentException; 35 import antlr.v4.runtime.tree.ParseTree; 36 import antlr.v4.runtime.tree.pattern.ParseTreePattern; 37 38 // Class ParseTreeMatch 39 /** 40 * TODO add class description 41 * @uml 42 * Represents the result of matching a {@link ParseTree} against a tree pattern. 43 */ 44 class ParseTreeMatch 45 { 46 47 /** 48 * @uml 49 * This is the backing field for {@link #getTree()}. 50 */ 51 public ParseTree tree; 52 53 /** 54 * @uml 55 * This is the backing field for {@link #getPattern()}. 56 */ 57 private ParseTreePattern pattern; 58 59 /** 60 * @uml 61 * This is the backing field for {@link #getLabels()}. 62 */ 63 private ParseTree[][string] labels; 64 65 /** 66 * @uml 67 * This is the backing field for {@link #getMismatchedNode()}. 68 */ 69 private ParseTree mismatchedNode; 70 71 /** 72 * @uml 73 * Constructs a new instance of {@link ParseTreeMatch} from the specified 74 * parse tree and pattern. 75 * 76 * @param tree The parse tree to match against the pattern. 77 * @param pattern The parse tree pattern. 78 * @param labels A mapping from label names to collections of 79 * {@link ParseTree} objects located by the tree pattern matching process. 80 * @param mismatchedNode The first node which failed to match the tree 81 * pattern during the matching process. 82 * 83 * @exception IllegalArgumentException if {@code tree} is {@code null} 84 * @exception IllegalArgumentException if {@code pattern} is {@code null} 85 * @exception IllegalArgumentException if {@code labels} is {@code null} 86 */ 87 public this(ParseTree tree, ParseTreePattern pattern, ParseTree[][string] labels, ParseTree mismatchedNode) 88 { 89 if (tree is null) { 90 throw new IllegalArgumentException("tree cannot be null"); 91 } 92 if (pattern is null) { 93 throw new IllegalArgumentException("pattern cannot be null"); 94 } 95 if (labels is null) { 96 throw new IllegalArgumentException("labels cannot be null"); 97 } 98 this.tree = tree; 99 this.pattern = pattern; 100 this.labels = labels; 101 this.mismatchedNode = mismatchedNode; 102 } 103 104 /** 105 * @uml 106 * Get the last node associated with a specific {@code label}. 107 * 108 * <p>For example, for pattern {@code <id:ID>}, {@code get("id")} returns the 109 * node matched for that {@code ID}. If more than one node 110 * matched the specified label, only the last is returned. If there is 111 * no node associated with the label, this returns {@code null}.</p> 112 * 113 * <p>Pattern tags like {@code <ID>} and {@code <expr>} without labels are 114 * considered to be labeled with {@code ID} and {@code expr}, respectively.</p> 115 * 116 * @param label The label to check. 117 * 118 * @return The last {@link ParseTree} to match a tag with the specified 119 * label, or {@code null} if no parse tree matched a tag with the label. 120 */ 121 public ParseTree get(string label) 122 { 123 ParseTree[] parseTrees = labels[label]; 124 if (parseTrees is null || parseTrees.length == 0) { 125 return null; 126 } 127 return parseTrees[parseTrees.length-1]; // return last if multiple 128 } 129 130 /** 131 * @uml 132 * Return all nodes matching a rule or token tag with the specified label. 133 * * 134 * <p>If the {@code label} is the name of a parser rule or token in the 135 * grammar, the resulting list will contain both the parse trees matching 136 * rule or tags explicitly labeled with the label and the complete set of 137 * parse trees matching the labeled and unlabeled tags in the pattern for 138 * the parser rule or token. For example, if {@code label} is {@code "foo"}, 139 * the result will contain <em>all</em> of the following.</p> 140 * 141 * <ul> 142 * <li>Parse tree nodes matching tags of the form {@code <foo:anyRuleName>} and 143 * {@code <foo:AnyTokenName>}.</li> 144 * <li>Parse tree nodes matching tags of the form {@code <anyLabel:foo>}.</li> 145 * <li>Parse tree nodes matching tags of the form {@code <foo>}.</li> 146 * </ul> 147 * 148 * @param label The label. 149 * 150 * @return A collection of all {@link ParseTree} nodes matching tags with 151 * the specified {@code label}. If no nodes matched the label, an empty list 152 * is returned. 153 */ 154 public ParseTree[] getAll(string label) 155 { 156 ParseTree[] nodes = labels[label]; 157 if (nodes is null) { 158 ParseTree[] empty; 159 return empty; 160 } 161 return nodes; 162 } 163 164 /** 165 * @uml 166 * Return a mapping from label → [list of nodes]. 167 * 168 * <p>The map includes special entries corresponding to the names of rules and 169 * tokens referenced in tags in the original pattern. For additional 170 * information, see the description of {@link #getAll(String)}.</p> 171 * 172 * @return A mapping from labels to parse tree nodes. If the parse tree 173 * pattern did not contain any rule or token tags, this map will be empty. 174 */ 175 public ParseTree[][string] getLabels() 176 { 177 return labels; 178 } 179 180 /** 181 * @uml 182 * Get the node at which we first detected a mismatch. 183 * 184 * @return the node at which we first detected a mismatch, or {@code null} 185 * if the match was successful. 186 */ 187 public ParseTree getMismatchedNode() 188 { 189 return mismatchedNode; 190 } 191 192 /** 193 * @uml 194 * Gets a value indicating whether the match operation succeeded. 195 * 196 * @return {@code true} if the match operation succeeded; otherwise, 197 * {@code false}. 198 */ 199 public bool succeeded() 200 { 201 return mismatchedNode is null; 202 } 203 204 /** 205 * @uml 206 * Get the tree pattern we are matching against. 207 * 208 * @return The tree pattern we are matching against. 209 */ 210 public ParseTreePattern getPattern() 211 { 212 return pattern; 213 } 214 215 /** 216 * @uml 217 * Get the parse tree we are trying to match to a pattern. 218 * 219 * @return The {@link ParseTree} we are trying to match to a pattern. 220 */ 221 public ParseTree getTree() 222 { 223 return tree; 224 } 225 226 /** 227 * @uml 228 * @override 229 */ 230 public override string toString() 231 { 232 return format("Match %s; found %d labels", 233 succeeded() ? "succeeded" : "failed", 234 getLabels().length); 235 } 236 237 }