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 /** 39 * TODO add class description 40 * @uml 41 * Represents the result of matching a {@link ParseTree} against a tree pattern. 42 */ 43 class ParseTreeMatch 44 { 45 46 /** 47 * @uml 48 * This is the backing field for {@link #getTree()}. 49 */ 50 public ParseTree tree; 51 52 /** 53 * @uml 54 * This is the backing field for {@link #getPattern()}. 55 */ 56 private ParseTreePattern pattern; 57 58 /** 59 * @uml 60 * This is the backing field for {@link #getLabels()}. 61 */ 62 private ParseTree[][string] labels; 63 64 /** 65 * @uml 66 * This is the backing field for {@link #getMismatchedNode()}. 67 */ 68 private ParseTree mismatchedNode; 69 70 /** 71 * @uml 72 * Constructs a new instance of {@link ParseTreeMatch} from the specified 73 * parse tree and pattern. 74 * 75 * @param tree The parse tree to match against the pattern. 76 * @param pattern The parse tree pattern. 77 * @param labels A mapping from label names to collections of 78 * {@link ParseTree} objects located by the tree pattern matching process. 79 * @param mismatchedNode The first node which failed to match the tree 80 * pattern during the matching process. 81 * 82 * @exception IllegalArgumentException if {@code tree} is {@code null} 83 * @exception IllegalArgumentException if {@code pattern} is {@code null} 84 * @exception IllegalArgumentException if {@code labels} is {@code null} 85 */ 86 public this(ParseTree tree, ParseTreePattern pattern, ParseTree[][string] labels, ParseTree mismatchedNode) 87 { 88 if (tree is null) { 89 throw new IllegalArgumentException("tree cannot be null"); 90 } 91 if (pattern is null) { 92 throw new IllegalArgumentException("pattern cannot be null"); 93 } 94 if (labels is null) { 95 throw new IllegalArgumentException("labels cannot be null"); 96 } 97 this.tree = tree; 98 this.pattern = pattern; 99 this.labels = labels; 100 this.mismatchedNode = mismatchedNode; 101 } 102 103 /** 104 * @uml 105 * Get the last node associated with a specific {@code label}. 106 * 107 * <p>For example, for pattern {@code <id:ID>}, {@code get("id")} returns the 108 * node matched for that {@code ID}. If more than one node 109 * matched the specified label, only the last is returned. If there is 110 * no node associated with the label, this returns {@code null}.</p> 111 * 112 * <p>Pattern tags like {@code <ID>} and {@code <expr>} without labels are 113 * considered to be labeled with {@code ID} and {@code expr}, respectively.</p> 114 * 115 * @param label The label to check. 116 * 117 * @return The last {@link ParseTree} to match a tag with the specified 118 * label, or {@code null} if no parse tree matched a tag with the label. 119 */ 120 public ParseTree get(string label) 121 { 122 ParseTree[] parseTrees = labels[label]; 123 if (parseTrees is null || parseTrees.length == 0) { 124 return null; 125 } 126 return parseTrees[parseTrees.length-1]; // return last if multiple 127 } 128 129 /** 130 * @uml 131 * Return all nodes matching a rule or token tag with the specified label. 132 * * 133 * <p>If the {@code label} is the name of a parser rule or token in the 134 * grammar, the resulting list will contain both the parse trees matching 135 * rule or tags explicitly labeled with the label and the complete set of 136 * parse trees matching the labeled and unlabeled tags in the pattern for 137 * the parser rule or token. For example, if {@code label} is {@code "foo"}, 138 * the result will contain <em>all</em> of the following.</p> 139 * 140 * <ul> 141 * <li>Parse tree nodes matching tags of the form {@code <foo:anyRuleName>} and 142 * {@code <foo:AnyTokenName>}.</li> 143 * <li>Parse tree nodes matching tags of the form {@code <anyLabel:foo>}.</li> 144 * <li>Parse tree nodes matching tags of the form {@code <foo>}.</li> 145 * </ul> 146 * 147 * @param label The label. 148 * 149 * @return A collection of all {@link ParseTree} nodes matching tags with 150 * the specified {@code label}. If no nodes matched the label, an empty list 151 * is returned. 152 */ 153 public ParseTree[] getAll(string label) 154 { 155 ParseTree[] nodes = labels[label]; 156 if (nodes is null) { 157 ParseTree[] empty; 158 return empty; 159 } 160 return nodes; 161 } 162 163 /** 164 * @uml 165 * Return a mapping from label → [list of nodes]. 166 * 167 * <p>The map includes special entries corresponding to the names of rules and 168 * tokens referenced in tags in the original pattern. For additional 169 * information, see the description of {@link #getAll(String)}.</p> 170 * 171 * @return A mapping from labels to parse tree nodes. If the parse tree 172 * pattern did not contain any rule or token tags, this map will be empty. 173 */ 174 public ParseTree[][string] getLabels() 175 { 176 return labels; 177 } 178 179 /** 180 * @uml 181 * Get the node at which we first detected a mismatch. 182 * 183 * @return the node at which we first detected a mismatch, or {@code null} 184 * if the match was successful. 185 */ 186 public ParseTree getMismatchedNode() 187 { 188 return mismatchedNode; 189 } 190 191 /** 192 * @uml 193 * Gets a value indicating whether the match operation succeeded. 194 * 195 * @return {@code true} if the match operation succeeded; otherwise, 196 * {@code false}. 197 */ 198 public bool succeeded() 199 { 200 return mismatchedNode is null; 201 } 202 203 /** 204 * @uml 205 * Get the tree pattern we are matching against. 206 * 207 * @return The tree pattern we are matching against. 208 */ 209 public ParseTreePattern getPattern() 210 { 211 return pattern; 212 } 213 214 /** 215 * @uml 216 * Get the parse tree we are trying to match to a pattern. 217 * 218 * @return The {@link ParseTree} we are trying to match to a pattern. 219 */ 220 public ParseTree getTree() 221 { 222 return tree; 223 } 224 225 /** 226 * @uml 227 * @override 228 */ 229 public override string toString() 230 { 231 return format("Match %s; found %d labels", 232 succeeded() ? "succeeded" : "failed", 233 getLabels().length); 234 } 235 236 }