blob: 747b52ff73fb753a0de23f2becdcf58eb670404f [file] [log] [blame]
Joachim Bingeldc03c002014-04-17 13:40:40 +00001package de.ids_mannheim.korap.query.serialize;
2
3import java.lang.reflect.Method;
4import java.util.ArrayList;
Joachim Bingel7ee07862014-04-28 15:22:41 +00005import java.util.Arrays;
Joachim Bingel019ba5c2014-04-28 14:59:04 +00006import java.util.HashMap;
Joachim Bingeldc03c002014-04-17 13:40:40 +00007import java.util.LinkedHashMap;
8import java.util.LinkedList;
9import java.util.List;
10import java.util.Map;
Joachim Bingelfb9d5fd2014-06-25 09:32:43 +000011import java.util.NoSuchElementException;
Joachim Bingeldc03c002014-04-17 13:40:40 +000012
13import org.antlr.v4.runtime.ANTLRInputStream;
14import org.antlr.v4.runtime.BailErrorStrategy;
15import org.antlr.v4.runtime.CharStream;
16import org.antlr.v4.runtime.CommonTokenStream;
17import org.antlr.v4.runtime.Lexer;
Joachim Bingeldc03c002014-04-17 13:40:40 +000018import org.antlr.v4.runtime.ParserRuleContext;
Joachim Bingeldc03c002014-04-17 13:40:40 +000019import org.antlr.v4.runtime.tree.ParseTree;
Joachim Bingel75038792014-05-19 15:12:23 +000020import org.slf4j.LoggerFactory;
Joachim Bingelc63f7812014-07-30 09:12:25 +000021import org.slf4j.Logger;
Joachim Bingeldc03c002014-04-17 13:40:40 +000022
23import de.ids_mannheim.korap.query.annis.AqlLexer;
24import de.ids_mannheim.korap.query.annis.AqlParser;
Joachim Bingeldc03c002014-04-17 13:40:40 +000025import de.ids_mannheim.korap.util.QueryException;
26
27/**
Joachim Bingelc8a28e42014-04-24 15:06:42 +000028 * Map representation of ANNIS QL syntax tree as returned by ANTLR
Joachim Bingeldc03c002014-04-17 13:40:40 +000029 * @author joachim
30 *
31 */
Joachim Bingelc8a28e42014-04-24 15:06:42 +000032public class AqlTree extends Antlr4AbstractSyntaxTree {
Joachim Bingelc63f7812014-07-30 09:12:25 +000033 private static Logger log = LoggerFactory.getLogger(AqlTree.class);
Joachim Bingeldc03c002014-04-17 13:40:40 +000034 /**
Joachim Bingeldc03c002014-04-17 13:40:40 +000035 * Flag that indicates whether token fields or meta fields are currently being processed
36 */
37 boolean inMeta = false;
38 /**
Joachim Bingel949e3a82014-06-16 13:20:43 +000039 * Keeps track of operands that are to be integrated into yet uncreated objects.
40 */
41 LinkedList<LinkedHashMap<String,Object>> operandStack = new LinkedList<LinkedHashMap<String,Object>>();
42 /**
Joachim Bingelc8a28e42014-04-24 15:06:42 +000043 * Keeps track of explicitly (by #-var definition) or implicitly (number as reference) introduced entities (for later reference by #-operator)
44 */
Joachim Bingelca4944e2014-06-13 13:55:10 +000045 Map<String, LinkedHashMap<String,Object>> variableReferences = new LinkedHashMap<String, LinkedHashMap<String,Object>>();
Joachim Bingelc8a28e42014-04-24 15:06:42 +000046 /**
47 * Counter for variable definitions.
48 */
49 Integer variableCounter = 1;
50 /**
Joachim Bingeldc03c002014-04-17 13:40:40 +000051 * Marks the currently active token in order to know where to add flags (might already have been taken away from token stack).
52 */
53 LinkedHashMap<String,Object> curToken = new LinkedHashMap<String,Object>();
Joachim Bingel75038792014-05-19 15:12:23 +000054 /**
55 * Keeps track of operands lists that are to be serialised in an inverted
56 * order (e.g. the IN() operator) compared to their AST representation.
57 */
58 private LinkedList<ArrayList<Object>> invertedOperandsLists = new LinkedList<ArrayList<Object>>();
Joachim Bingel77ac5cb2014-04-22 14:03:28 +000059 /**
Joachim Bingelfc428812014-06-18 14:50:14 +000060 * Keeps track of operation:class numbers.
61 */
62 int classCounter = 0;
63 /**
Joachim Bingel9c3ddb92014-06-23 13:49:58 +000064 * Keeps track of numers of relations processed (important when dealing with multiple predications).
65 */
66 int relationCounter = 0;
67 /**
Joachim Bingel019ba5c2014-04-28 14:59:04 +000068 * Keeps track of references to nodes that are operands of groups (e.g. tree relations). Those nodes appear on the top level of the parse tree
69 * but are to be integrated into the AqlTree at a later point (namely as operands of the respective group). Therefore, store references to these
70 * nodes here and exclude the operands from being written into the query map individually.
71 */
72 private LinkedList<String> operandOnlyNodeRefs = new LinkedList<String>();
Joachim Bingel1846c8c2014-07-08 14:13:31 +000073 private List<ParseTree> globalLingTermNodes = new ArrayList<ParseTree>();
Joachim Bingel9c3ddb92014-06-23 13:49:58 +000074 private int totalRelationCount;
Joachim Bingel1846c8c2014-07-08 14:13:31 +000075 /**
76 * Keeps a record of reference-class-mapping, i.e. which 'class' has been assigned to which #n reference. This is important when introducing korap:reference
77 * spans to refer back to previously established classes for entities.
78 */
Joachim Bingelb001d192014-06-25 11:34:36 +000079 private LinkedHashMap<String, Integer> refClassMapping = new LinkedHashMap<String, Integer>();
Joachim Bingel9c3ddb92014-06-23 13:49:58 +000080 private LinkedHashMap<String, Integer> nodeReferencesTotal = new LinkedHashMap<String, Integer>();
81 private LinkedHashMap<String, Integer> nodeReferencesProcessed = new LinkedHashMap<String, Integer>();
Joachim Bingel1846c8c2014-07-08 14:13:31 +000082
Joachim Bingeldc03c002014-04-17 13:40:40 +000083 /**
84 *
85 * @param tree The syntax tree as returned by ANTLR
86 * @param parser The ANTLR parser instance that generated the parse tree
87 */
88 public AqlTree(String query) {
Joachim Bingeldc03c002014-04-17 13:40:40 +000089 try {
90 process(query);
91 } catch (QueryException e) {
92 e.printStackTrace();
93 }
94 System.out.println(">>> "+requestMap.get("query")+" <<<");
95 }
96
Joachim Bingeldc03c002014-04-17 13:40:40 +000097 @Override
98 public void process(String query) throws QueryException {
99 ParseTree tree = parseAnnisQuery(query);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000100 if (this.parser != null) {
101 super.parser = this.parser;
102 } else {
103 throw new NullPointerException("Parser has not been instantiated!");
104 }
Joachim Bingel75038792014-05-19 15:12:23 +0000105 log.info("Processing Annis query.");
Joachim Bingelca4944e2014-06-13 13:55:10 +0000106 log.info("AST is: "+tree.toStringTree(parser));
Joachim Bingeldc03c002014-04-17 13:40:40 +0000107 System.out.println("Processing Annis QL");
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000108 if (verbose) System.out.println(tree.toStringTree(parser));
Joachim Bingeldc03c002014-04-17 13:40:40 +0000109 processNode(tree);
Joachim Bingel75038792014-05-19 15:12:23 +0000110 log.info(requestMap.toString());
Joachim Bingeldc03c002014-04-17 13:40:40 +0000111 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000112
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000113 @SuppressWarnings("unchecked")
Joachim Bingeldc03c002014-04-17 13:40:40 +0000114 private void processNode(ParseTree node) {
115 // Top-down processing
116 if (visited.contains(node)) return;
117 else visited.add(node);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000118
Joachim Bingeldc03c002014-04-17 13:40:40 +0000119 String nodeCat = getNodeCat(node);
120 openNodeCats.push(nodeCat);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000121
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000122 stackedObjects = 0;
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000123
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000124 if (verbose) {
125 System.err.println(" "+objectStack);
126 System.out.println(openNodeCats);
127 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000128
129 /*
130 ****************************************************************
131 ****************************************************************
132 * Processing individual node categories *
133 ****************************************************************
134 ****************************************************************
135 */
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000136 if (nodeCat.equals("exprTop")) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000137 List<ParseTree> andTopExprs = getChildrenWithCat(node, "andTopExpr");
138 if (andTopExprs.size() > 1) {
139 LinkedHashMap<String, Object> topOr = makeGroup("or");
140 requestMap.put("query", topOr);
141 objectStack.push(topOr);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000142 }
143 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000144
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000145 if (nodeCat.equals("andTopExpr")) {
Joachim Bingel75038792014-05-19 15:12:23 +0000146 // Before processing any child expr node, check if it has one or more "*ary_linguistic_term" nodes.
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000147 // Those nodes may use references to earlier established operand nodes.
148 // Those operand nodes are not to be included into the query map individually but
149 // naturally as operands of the relations/groups introduced by the
Joachim Bingel75038792014-05-19 15:12:23 +0000150 // *node. For that purpose, this section mines all used references
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000151 // and stores them in a list for later reference.
152 for (ParseTree exprNode : getChildrenWithCat(node,"expr")) {
Joachim Bingelfc428812014-06-18 14:50:14 +0000153 // Pre-process any 'variableExpr' such that the variableReferences map can be filled
154 List<ParseTree> definitionNodes = new ArrayList<ParseTree>();
155 definitionNodes.addAll(getChildrenWithCat(exprNode, "variableExpr"));
156 for (ParseTree definitionNode : definitionNodes) {
157 processNode(definitionNode);
158 }
159 // Then, mine all relations between nodes
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000160 List<ParseTree> lingTermNodes = new ArrayList<ParseTree>();
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000161 lingTermNodes.addAll(getChildrenWithCat(exprNode, "n_ary_linguistic_term"));
Joachim Bingelc89952e2014-06-06 12:08:42 +0000162 globalLingTermNodes.addAll(lingTermNodes);
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000163 totalRelationCount = globalLingTermNodes.size();
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000164 // Traverse refOrNode nodes under *ary_linguistic_term nodes and extract references
165 for (ParseTree lingTermNode : lingTermNodes) {
166 for (ParseTree refOrNode : getChildrenWithCat(lingTermNode, "refOrNode")) {
Joachim Bingel75038792014-05-19 15:12:23 +0000167 String refOrNodeString = refOrNode.getChild(0).toStringTree(parser);
168 if (refOrNodeString.startsWith("#")) {
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000169 String ref = refOrNode.getChild(0).toStringTree(parser).substring(1);
170 if (nodeReferencesTotal.containsKey(ref)) {
171 nodeReferencesTotal.put(ref, nodeReferencesTotal.get(ref)+1);
172 } else {
173 nodeReferencesTotal.put(ref, 1);
174 nodeReferencesProcessed.put(ref, 0);
175 }
Joachim Bingel75038792014-05-19 15:12:23 +0000176 }
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000177 }
178 }
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000179 }
180 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000181
Joachim Bingelc89952e2014-06-06 12:08:42 +0000182 if (nodeCat.equals("unary_linguistic_term")) {
Joachim Bingelca4944e2014-06-13 13:55:10 +0000183 LinkedHashMap<String, Object> unaryOperator = parseUnaryOperator(node);
184 String reference = node.getChild(0).toStringTree(parser).substring(1);
185 LinkedHashMap<String, Object> object = variableReferences.get(reference);
186 object.putAll(unaryOperator);
Joachim Bingelc89952e2014-06-06 12:08:42 +0000187 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000188
Joachim Bingelc89952e2014-06-06 12:08:42 +0000189 if (nodeCat.equals("n_ary_linguistic_term")) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000190 processN_ary_linguistic_term(node);
Joachim Bingeldc03c002014-04-17 13:40:40 +0000191 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000192
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000193 if (nodeCat.equals("variableExpr")) {
194 // simplex word or complex assignment (like qname = textSpec)?
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000195 String firstChildNodeCat = getNodeCat(node.getChild(0));
196 LinkedHashMap<String, Object> object = null;
197 if (firstChildNodeCat.equals("node")) {
198 object = makeSpan();
199 } else if (firstChildNodeCat.equals("tok")) {
200 object = makeToken();
Joachim Bingelc9c0cf92014-10-02 12:03:59 +0000201 if (node.getChildCount() > 1) { // empty tokens do not wrap a term
202 LinkedHashMap<String, Object> term = makeTerm();
203 term.put("layer", "orth");
204 object.put("wrap", term);
205 }
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000206 } else if (firstChildNodeCat.equals("qName")) { // only (foundry/)?layer specified
Joachim Bingel7ee07862014-04-28 15:22:41 +0000207 // may be token or span, depending on indicated layer! (e.g. cnx/cat=NP or mate/pos=NN)
208 HashMap<String, Object> qNameParse = parseQNameNode(node.getChild(0));
209 if (Arrays.asList(new String[]{"pos", "lemma", "morph", "tok"}).contains(qNameParse.get("layer"))) {
210 object = makeToken();
211 LinkedHashMap<String, Object> term = makeTerm();
212 object.put("wrap", term);
213 term.putAll(qNameParse);
214 } else {
215 object = makeSpan();
216 object.putAll(qNameParse);
217 }
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000218 } else if (firstChildNodeCat.equals("textSpec")) {
219 object = makeToken();
220 LinkedHashMap<String, Object> term = makeTerm();
221 object.put("wrap", term);
Joachim Bingelb6d67812014-08-13 11:37:09 +0000222 term.put("layer", "orth");
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000223 term.putAll(parseTextSpec(node.getChild(0)));
224 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000225
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000226 if (node.getChildCount() == 3) { // (foundry/)?layer=key specification
Joachim Bingel7ee07862014-04-28 15:22:41 +0000227 if (object.get("@type").equals("korap:token")) {
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000228 HashMap<String, Object> term = (HashMap<String, Object>) object.get("wrap");
229 term.putAll(parseTextSpec(node.getChild(2)));
230 term.put("match", parseMatchOperator(node.getChild(1)));
231 } else {
232 object.putAll(parseTextSpec(node.getChild(2)));
233 object.put("match", parseMatchOperator(node.getChild(1)));
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000234 }
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000235 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000236
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000237 if (object != null) {
Joachim Bingel75038792014-05-19 15:12:23 +0000238 if (! operandOnlyNodeRefs.contains(variableCounter.toString())) {
239 putIntoSuperObject(object);
Joachim Bingel75038792014-05-19 15:12:23 +0000240 }
Joachim Bingele6d73b12014-09-30 15:34:59 +0000241 ParseTree parentsFirstChild = node.getParent().getChild(0);
242 if (getNodeCat(parentsFirstChild).endsWith("#")) {
243 variableReferences.put(getNodeCat(parentsFirstChild).replaceAll("#", ""), object);
244 }
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000245 variableReferences.put(variableCounter.toString(), object);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000246 variableCounter++;
Joachim Bingele6d73b12014-09-30 15:34:59 +0000247 System.out.println(variableReferences);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000248 }
249 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000250
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000251 objectsToPop.push(stackedObjects);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000252
Joachim Bingeldc03c002014-04-17 13:40:40 +0000253 /*
254 ****************************************************************
255 ****************************************************************
256 * recursion until 'request' node (root of tree) is processed *
257 ****************************************************************
258 ****************************************************************
259 */
260 for (int i=0; i<node.getChildCount(); i++) {
261 ParseTree child = node.getChild(i);
262 processNode(child);
263 }
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000264
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000265 /*
266 **************************************************************
267 * Stuff that happens after processing the children of a node *
268 **************************************************************
269 */
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000270 if (!objectsToPop.isEmpty()) {
271 for (int i=0; i<objectsToPop.pop(); i++) {
272 objectStack.pop();
273 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000274 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000275 openNodeCats.pop();
Joachim Bingeldc03c002014-04-17 13:40:40 +0000276 }
277
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000278
279
280 /**
281 * Processes an operand node, creating a map for the operand containing all its information
282 * given in the node definition (referenced via '#'). If this node has been referred to and used earlier,
283 * a korap:reference is created in its place.
284 * The operand will be wrapped in a class group if necessary.
285 * @param operandTree
286 * @return A map object with the appropriate CQLF representation of the operand
287 */
288 private LinkedHashMap<String, Object> retrieveOperand(ParseTree operandTree) {
289 LinkedHashMap<String, Object> operand = null;
290 if (!getNodeCat(operandTree.getChild(0)).equals("variableExpr")) {
291 String ref = operandTree.getChild(0).toStringTree(parser).substring(1);
292 operand = variableReferences.get(ref);
293 if (nodeReferencesTotal.get(ref) > 1) {
294 if (nodeReferencesProcessed.get(ref)==0) {
295 refClassMapping.put(ref, classCounter);
296 operand = wrapInClass(operand, classCounter++);
297 nodeReferencesProcessed.put(ref, nodeReferencesProcessed.get(ref)+1);
298 } else if (nodeReferencesProcessed.get(ref)>0 && nodeReferencesTotal.get(ref)>1) {
299 try {
300 operand = wrapInReference(operandStack.pop(), refClassMapping.get(ref));
301 } catch (NoSuchElementException e) {
302 operand = makeReference(refClassMapping.get(ref));
303 }
304 }
305 }
306 }
307 return operand;
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000308 }
309
310 @SuppressWarnings("unchecked")
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000311 private void processN_ary_linguistic_term(ParseTree node) {
312 relationCounter++;
313 // get operator and determine type of group (sequence/treeRelation/relation/...)
314 // It's possible in Annis QL to concatenate operators, so there may be several operators under one n_ary_linguistic_term node.
315 // Counter 'i' will iteratively point to all operator nodes (odd-numbered) under this node.
316 for (int i=1; i<node.getChildCount(); i = i+2) {
317 ParseTree operandTree1 = node.getChild(i-1);
318 ParseTree operandTree2 = node.getChild(i+1);
319 String reltype = getNodeCat(node.getChild(i).getChild(0));
320
321 LinkedHashMap<String,Object> group = null;
322 ArrayList<Object> operands = null;
323 // Retrieve operands.
324 LinkedHashMap<String, Object> operand1 = retrieveOperand(operandTree1);
325 LinkedHashMap<String, Object> operand2 = retrieveOperand(operandTree2);
326
327 // 'Proper' n_ary_linguistic_operators receive a considerably different serialisation than 'commonparent' and 'commonancestor'.
328 // For the latter cases, a dummy span is introduced and declared as a span class that has a dominance relation towards
329 // the two operands, one after the other, thus resulting in two nested relations! A Poliqarp+ equivalent for A $ B would be
330 // contains(focus(1:contains({1:<>},A)), B).
331 // This is modeled here...
332 if (reltype.equals("commonparent") || reltype.equals("commonancestor")) {
333 // make an (outer) group and an inner group containing the dummy node or previous relations
334 group = makeGroup("relation");
335 LinkedHashMap<String,Object> innerGroup = makeGroup("relation");
Joachim Bingel62892412014-08-06 15:18:59 +0000336 LinkedHashMap<String,Object> relation = makeRelation();
337 LinkedHashMap<String,Object> term = makeTerm();
338 term.put("layer", "c");
339 relation.put("wrap", term);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000340 // commonancestor is an indirect commonparent relation
Joachim Bingele6d73b12014-09-30 15:34:59 +0000341 if (reltype.equals("commonancestor")) relation.put("boundary", makeBoundary(1, null));
Joachim Bingel62892412014-08-06 15:18:59 +0000342 group.put("relation", relation);
343 innerGroup.put("relation", relation);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000344 // Get operands list before possible re-assignment of 'group' (see following 'if')
345 ArrayList<Object> outerOperands = (ArrayList<Object>) group.get("operands");
346 ArrayList<Object> innerOperands = (ArrayList<Object>) innerGroup.get("operands");
347 // for lowest level, add the underspecified node as first operand and wrap it in a class group
348 if (i == 1) {
349 innerOperands.add(wrapInClass(makeSpan(), classCounter));
350 // add the first operand and wrap the whole group in a focusing reference
351 innerOperands.add(operand1);
352 innerGroup = wrapInReference(innerGroup, classCounter);
353 outerOperands.add(innerGroup);
354 } else {
355 outerOperands.add(operandStack.pop());
356 }
357 // Lookahead: if next operator is not commonparent or commonancestor, wrap in class for accessibility
358 if (i < node.getChildCount()-2 && !getNodeCat(node.getChild(i+2).getChild(0)).startsWith("common")) {
359 operand2 = wrapInClass(operand2, ++classCounter);
360 }
361 outerOperands.add(operand2);
362
363 // Wrap in another reference object in case other relations are following
364 if (i < node.getChildCount()-2) {
365 group = wrapInReference(group, classCounter);
366 }
Joachim Bingel62892412014-08-06 15:18:59 +0000367 // All other n-ary linguistic relations have special 'relation' attributes defined in CQLF and can be
368 // handled more easily...
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000369 } else {
370 LinkedHashMap<String, Object> operatorGroup = parseOperatorNode(node.getChild(i).getChild(0));
371 String groupType;
372 try {
373 groupType = (String) operatorGroup.get("groupType");
374 } catch (ClassCastException | NullPointerException n) {
375 groupType = "relation";
376 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000377 if (groupType.equals("relation") || groupType.equals("treeRelation")) {
Joachim Bingele6d73b12014-09-30 15:34:59 +0000378 group = makeGroup(groupType);
Joachim Bingel62892412014-08-06 15:18:59 +0000379 LinkedHashMap<String, Object> relation = new LinkedHashMap<String, Object>();
380 putAllButGroupType(relation, operatorGroup);
381 System.err.println(relation);
382 group.put("relation", relation);
Joachim Bingele6d73b12014-09-30 15:34:59 +0000383 } else if (groupType.equals("sequence")) {
384 group = makeGroup(groupType);
385 putAllButGroupType(group, operatorGroup);
386 } else if (groupType.equals("position")) {
387 group = new LinkedHashMap<String,Object>();
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000388 putAllButGroupType(group, operatorGroup);
389 }
Joachim Bingele6d73b12014-09-30 15:34:59 +0000390
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000391 // Get operands list before possible re-assignment of 'group' (see following 'if')
392 operands = (ArrayList<Object>) group.get("operands");
393 // Wrap in reference object in case other relations are following
394 if (i < node.getChildCount()-2) {
395 group = wrapInReference(group, classCounter);
396 }
397
398 // Inject operands.
399 // -> Case distinction:
400 if (node.getChildCount()==3) {
401 // Things are easy when there's just one operator (thus 3 children incl. operands)...
402 if (operand1 != null) operands.add(operand1);
403 if (operand2 != null) operands.add(operand2);
404 } else {
405 // ... but things get a little more complicated here. The AST is of this form: (operand1 operator 1 operand2 operator2 operand3 operator3 ...)
406 // but we'll have to serialize it in a nested, binary way: (((operand1 operator1 operand2) operator2 operand3) operator3 ...)
407 // the following code will do just that:
408 if (i == 1) {
409 // for the first operator, include both operands
410 if (operand1 != null) operands.add(operand1);
411 if (operand2 != null) operands.add(wrapInClass(operand2, classCounter++));
412 // Don't put this into the super object directly but store on operandStack
413 // (because this group will have to be an operand of a subsequent operator)
414 operandStack.push(group);
415 // for all subsequent operators, only take the 2nd operand (first was already added by previous operator)
416 } else if (i < node.getChildCount()-2) {
417 // for all intermediate operators, include other previous groups and 2nd operand. Store this on the operandStack, too.
418 if (operand2 != null) operands.add(wrapInClass(operand2, classCounter++));
419 operands.add(0, operandStack.pop());
420 operandStack.push(group);
421 } else if (i == node.getChildCount()-2) {
422 // This is the last operator. Include 2nd operand only
423 if (operand2 != null) operands.add(operand2);
424 }
425 }
426 }
427 // Final step: decide what to do with the 'group' object, depending on whether all relations have been processed
428 if (i == node.getChildCount()-2 && relationCounter == totalRelationCount) {
429 putIntoSuperObject(group);
430 if (!operandStack.isEmpty()) {
431 operands.add(0, operandStack.pop());
432 }
433 objectStack.push(group);
434 stackedObjects++;
435 } else {
436 operandStack.push(group);
437 }
438 }
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000439 }
440
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000441
442
Joachim Bingelca4944e2014-06-13 13:55:10 +0000443 /**
444 * Parses a unary_linguistic_operator node. Possible operators are: root, arity, tokenarity.
445 * Operators are embedded into a korap:term, in turn wrapped by an 'attr' property in a korap:span.
446 * @param node The unary_linguistic_operator node
447 * @return A map containing the attr key, to be inserted into korap:span
448 */
449 private LinkedHashMap<String, Object> parseUnaryOperator(ParseTree node) {
450 LinkedHashMap<String, Object> attr = new LinkedHashMap<String, Object>();
451 LinkedHashMap<String, Object> term = makeTerm();
452 String op = node.getChild(1).toStringTree(parser).substring(1);
453 if (op.equals("arity") || op.equals("tokenarity")) {
454 LinkedHashMap<String, Object> boundary = boundaryFromRangeSpec(node.getChild(3), false);
455 term.put(op, boundary);
456 } else {
457 term.put(op, true);
458 }
Joachim Bingelca4944e2014-06-13 13:55:10 +0000459 attr.put("attr", term);
460 return attr;
461 }
462
Joachim Bingeleee549e2014-04-29 11:15:37 +0000463 private LinkedHashMap<String, Object> parseOperatorNode(ParseTree operatorNode) {
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000464 LinkedHashMap<String, Object> relation = null;
Joachim Bingeleee549e2014-04-29 11:15:37 +0000465 String operator = getNodeCat(operatorNode);
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000466 // DOMINANCE
Joachim Bingeleee549e2014-04-29 11:15:37 +0000467 if (operator.equals("dominance")) {
Joachim Bingel62892412014-08-06 15:18:59 +0000468 relation = makeRelation();
Joachim Bingel13421ef2014-05-07 16:22:58 +0000469 relation.put("groupType", "relation");
Joachim Bingeleee549e2014-04-29 11:15:37 +0000470 ParseTree leftChildSpec = getFirstChildWithCat(operatorNode, "@l");
471 ParseTree rightChildSpec = getFirstChildWithCat(operatorNode, "@r");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000472 ParseTree qName = getFirstChildWithCat(operatorNode, "qName");
Joachim Bingeleee549e2014-04-29 11:15:37 +0000473 ParseTree edgeSpec = getFirstChildWithCat(operatorNode, "edgeSpec");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000474 ParseTree star = getFirstChildWithCat(operatorNode, "*");
475 ParseTree rangeSpec = getFirstChildWithCat(operatorNode, "rangeSpec");
Joachim Bingel62892412014-08-06 15:18:59 +0000476 LinkedHashMap<String,Object> term = makeTerm();
477 term.put("layer", "c");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000478 if (leftChildSpec != null) relation.put("index", 0);
479 if (rightChildSpec != null) relation.put("index", -1);
Joachim Bingel62892412014-08-06 15:18:59 +0000480 if (qName != null) term = parseQNameNode(qName);
481 if (edgeSpec != null) term.putAll(parseEdgeSpec(edgeSpec));
482 if (star != null) relation.put("boundary", makeBoundary(0, null));
Joachim Bingel86195a52014-07-08 14:29:48 +0000483 if (rangeSpec != null) relation.put("boundary", boundaryFromRangeSpec(rangeSpec));
Joachim Bingel62892412014-08-06 15:18:59 +0000484 relation.put("wrap", term);
Joachim Bingeleee549e2014-04-29 11:15:37 +0000485 }
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000486 else if (operator.equals("pointing")) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000487 // String reltype = operatorNode.getChild(1).toStringTree(parser);
Joachim Bingel62892412014-08-06 15:18:59 +0000488 relation = makeRelation();
Joachim Bingel13421ef2014-05-07 16:22:58 +0000489 relation.put("groupType", "relation");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000490 ParseTree qName = getFirstChildWithCat(operatorNode, "qName");
491 ParseTree edgeSpec = getFirstChildWithCat(operatorNode, "edgeSpec");
492 ParseTree star = getFirstChildWithCat(operatorNode, "*");
493 ParseTree rangeSpec = getFirstChildWithCat(operatorNode, "rangeSpec");
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000494 // if (qName != null) relation.putAll(parseQNameNode(qName));
Joachim Bingel62892412014-08-06 15:18:59 +0000495 LinkedHashMap<String,Object> term = makeTerm();
496 if (qName != null) term.putAll(parseQNameNode(qName));
497 if (edgeSpec != null) term.putAll(parseEdgeSpec(edgeSpec));
Joachim Bingele6d73b12014-09-30 15:34:59 +0000498 if (star != null) relation.put("boundary", makeBoundary(0, null));
Joachim Bingel86195a52014-07-08 14:29:48 +0000499 if (rangeSpec != null) relation.put("boundary", boundaryFromRangeSpec(rangeSpec));
Joachim Bingel62892412014-08-06 15:18:59 +0000500 relation.put("wrap", term);
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000501 }
502 else if (operator.equals("precedence")) {
Joachim Bingel13421ef2014-05-07 16:22:58 +0000503 relation = new LinkedHashMap<String, Object>();
504 relation.put("groupType", "sequence");
505 ParseTree rangeSpec = getFirstChildWithCat(operatorNode, "rangeSpec");
506 ParseTree star = getFirstChildWithCat(operatorNode, "*");
507 ArrayList<Object> distances = new ArrayList<Object>();
508 if (star != null) {
Joachim Bingel687e4d42014-07-30 09:34:18 +0000509 distances.add(makeDistance("w", 0, null));
Joachim Bingel13421ef2014-05-07 16:22:58 +0000510 relation.put("distances", distances);
511 }
512 if (rangeSpec != null) {
513 distances.add(parseDistance(rangeSpec));
514 relation.put("distances", distances);
515 }
516 relation.put("inOrder", true);
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000517 }
518 else if (operator.equals("spanrelation")) {
Joachim Bingele6d73b12014-09-30 15:34:59 +0000519// relation = makeGroup("position");
520// relation.put("groupType", "position");
Joachim Bingel75038792014-05-19 15:12:23 +0000521 String reltype = operatorNode.getChild(0).toStringTree(parser);
Joachim Bingele6d73b12014-09-30 15:34:59 +0000522 String[] frames = new String[]{};
523 String[] sharedClasses = new String[]{"sharedClasses:includes"};
Joachim Bingel75038792014-05-19 15:12:23 +0000524 switch (reltype) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000525 case "_=_":
Joachim Bingele6d73b12014-09-30 15:34:59 +0000526 frames = new String[]{"frame:matches"};
527 sharedClasses = new String[]{"sharedClasses:equals"};
528 break;
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000529 case "_l_":
Joachim Bingele6d73b12014-09-30 15:34:59 +0000530 frames = new String[]{"frame:startswith"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000531 break;
532 case "_r_":
Joachim Bingele6d73b12014-09-30 15:34:59 +0000533 frames = new String[]{"frame:endswith"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000534 break;
535 case "_i_":
Joachim Bingele6d73b12014-09-30 15:34:59 +0000536 frames = new String[]{"frame:contains"};break;
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000537 case "_o_":
Joachim Bingele6d73b12014-09-30 15:34:59 +0000538 frames = new String[]{"frame:overlapsLeft", "frame:overlapsRight"};
539 sharedClasses = new String[]{"sharedClasses:intersects"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000540 break;
541 case "_ol_":
Joachim Bingele6d73b12014-09-30 15:34:59 +0000542 frames = new String[]{"frame:overlapsLeft"};
543 sharedClasses = new String[]{"sharedClasses:intersects"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000544 break;
545 case "_or_":
Joachim Bingele6d73b12014-09-30 15:34:59 +0000546 frames = new String[]{"frame:overlapsRight"};
547 sharedClasses = new String[]{"sharedClasses:intersects"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000548 break;
Joachim Bingel75038792014-05-19 15:12:23 +0000549 }
Joachim Bingele6d73b12014-09-30 15:34:59 +0000550// relation.put("frames", frames);
551// relation.put("sharedClasses", sharedClasses);
552 relation = makePosition(frames, sharedClasses);
553 relation.put("groupType", "position");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000554 }
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000555 else if (operator.equals("identity")) {
Joachim Bingelc89952e2014-06-06 12:08:42 +0000556 //TODO
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000557 }
558 else if (operator.equals("equalvalue")) {
Joachim Bingelc89952e2014-06-06 12:08:42 +0000559 //TODO
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000560 }
561 else if (operator.equals("notequalvalue")) {
Joachim Bingelc89952e2014-06-06 12:08:42 +0000562 //TODO
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000563 }
564 return relation;
565 }
566
Joachim Bingelceb79062014-09-22 11:50:37 +0000567 @SuppressWarnings("unchecked")
Joachim Bingel62892412014-08-06 15:18:59 +0000568 private LinkedHashMap<String,Object> parseEdgeSpec(ParseTree edgeSpec) {
569 List<ParseTree> annos = getChildrenWithCat(edgeSpec, "edgeAnno");
570 if (annos.size() == 1) return parseEdgeAnno(annos.get(0));
571 else {
572 LinkedHashMap<String,Object> termGroup = makeTermGroup("and");
573 ArrayList<Object> operands = (ArrayList<Object>) termGroup.get("operands");
574 for (ParseTree anno : annos) {
575 operands.add(parseEdgeAnno(anno));
576 }
577 return termGroup;
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000578 }
Joachim Bingeleee549e2014-04-29 11:15:37 +0000579 }
580
581 private LinkedHashMap<String, Object> parseEdgeAnno(
582 ParseTree edgeAnnoSpec) {
583 LinkedHashMap<String, Object> edgeAnno = new LinkedHashMap<String, Object>();
Joachim Bingela07b8e72014-05-09 15:06:07 +0000584 edgeAnno.put("@type", "korap:term");
Joachim Bingel639df9c2014-05-12 15:27:00 +0000585 ParseTree qNameNode = edgeAnnoSpec.getChild(0);
Joachim Bingeleee549e2014-04-29 11:15:37 +0000586 ParseTree matchOperatorNode = edgeAnnoSpec.getChild(1);
587 ParseTree textSpecNode = edgeAnnoSpec.getChild(2);
Joachim Bingel639df9c2014-05-12 15:27:00 +0000588 ParseTree layerNode = getFirstChildWithCat(qNameNode, "layer");
589 ParseTree foundryNode = getFirstChildWithCat(qNameNode, "foundry");
590 if (foundryNode!=null) edgeAnno.put("foundry", foundryNode.getChild(0).toStringTree(parser));
591 if (layerNode!=null) edgeAnno.put("layer", layerNode.getChild(0).toStringTree(parser));
Joachim Bingeleee549e2014-04-29 11:15:37 +0000592 edgeAnno.putAll(parseTextSpec(textSpecNode));
593 edgeAnno.put("match", parseMatchOperator(matchOperatorNode));
594 return edgeAnno;
595 }
596
Joachim Bingela07b8e72014-05-09 15:06:07 +0000597 private LinkedHashMap<String, Object> boundaryFromRangeSpec(ParseTree rangeSpec) {
Joachim Bingelca4944e2014-06-13 13:55:10 +0000598 return boundaryFromRangeSpec(rangeSpec, true);
599 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000600
Joachim Bingelca4944e2014-06-13 13:55:10 +0000601 private LinkedHashMap<String, Object> boundaryFromRangeSpec(ParseTree rangeSpec, boolean expandToMax) {
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000602 Integer min = Integer.parseInt(rangeSpec.getChild(0).toStringTree(parser));
Joachim Bingelca4944e2014-06-13 13:55:10 +0000603 Integer max = min;
Joachim Bingel687e4d42014-07-30 09:34:18 +0000604 if (expandToMax) max = null;
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000605 if (rangeSpec.getChildCount()==3)
606 max = Integer.parseInt(rangeSpec.getChild(2).toStringTree(parser));
607 return makeBoundary(min, max);
608 }
Joachim Bingela07b8e72014-05-09 15:06:07 +0000609
Joachim Bingel13421ef2014-05-07 16:22:58 +0000610 private LinkedHashMap<String, Object> parseDistance(ParseTree rangeSpec) {
611 Integer min = Integer.parseInt(rangeSpec.getChild(0).toStringTree(parser));
Joachim Bingel687e4d42014-07-30 09:34:18 +0000612 Integer max = null;
Joachim Bingel13421ef2014-05-07 16:22:58 +0000613 if (rangeSpec.getChildCount()==3)
614 max = Integer.parseInt(rangeSpec.getChild(2).toStringTree(parser));
615 return makeDistance("w", min, max);
616 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000617
Joachim Bingeleee549e2014-04-29 11:15:37 +0000618 private LinkedHashMap<String, Object> parseTextSpec(ParseTree node) {
619 LinkedHashMap<String, Object> term = new LinkedHashMap<String, Object>();
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000620 if (hasChild(node, "regex")) {
621 term.put("type", "type:regex");
622 term.put("key", node.getChild(0).getChild(0).toStringTree(parser).replaceAll("/", ""));
623 } else {
624 term.put("key", node.getChild(1).toStringTree(parser));
625 }
626 term.put("match", "match:eq");
627 return term;
628 }
629
Joachim Bingeldc03c002014-04-17 13:40:40 +0000630 /**
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000631 * Parses the match operator (= or !=)
Joachim Bingeldc03c002014-04-17 13:40:40 +0000632 * @param node
633 * @return
634 */
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000635 private String parseMatchOperator(ParseTree node) {
636 return node.toStringTree(parser).equals("=") ? "match:eq" : "match:ne";
Joachim Bingeldc03c002014-04-17 13:40:40 +0000637 }
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000638
639 private LinkedHashMap<String, Object> parseQNameNode(ParseTree node) {
640 LinkedHashMap<String, Object> fields = new LinkedHashMap<String, Object>();
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000641 ParseTree layerNode = getFirstChildWithCat(node, "layer");
642 ParseTree foundryNode = getFirstChildWithCat(node, "foundry");
643 if (foundryNode != null) fields.put("foundry", foundryNode.getChild(0).toStringTree(parser));
644 fields.put("layer", layerNode.getChild(0).toStringTree(parser));
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000645 return fields;
646 }
647
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000648 private void putIntoSuperObject(LinkedHashMap<String, Object> object) {
649 putIntoSuperObject(object, 0);
650 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000651
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000652 @SuppressWarnings({ "unchecked" })
653 private void putIntoSuperObject(LinkedHashMap<String, Object> object, int objStackPosition) {
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000654 if (objectStack.size()>objStackPosition) {
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000655 ArrayList<Object> topObjectOperands = (ArrayList<Object>) objectStack.get(objStackPosition).get("operands");
Joachim Bingel75038792014-05-19 15:12:23 +0000656 if (!invertedOperandsLists.contains(topObjectOperands)) {
657 topObjectOperands.add(object);
658 } else {
659 topObjectOperands.add(0, object);
660 }
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000661 } else {
662 requestMap.put("query", object);
663 }
664 }
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000665
Joachim Bingel13421ef2014-05-07 16:22:58 +0000666 private void putAllButGroupType(Map<String, Object> container, Map<String, Object> input) {
667 for (String key : input.keySet()) {
668 if (!key.equals("groupType")) {
669 container.put(key, input.get(key));
670 }
671 }
672 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000673
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000674 private ParserRuleContext parseAnnisQuery (String p) throws QueryException {
Joachim Bingeldc03c002014-04-17 13:40:40 +0000675 Lexer poliqarpLexer = new AqlLexer((CharStream)null);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000676 ParserRuleContext tree = null;
677 // Like p. 111
678 try {
Joachim Bingeldc03c002014-04-17 13:40:40 +0000679
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000680 // Tokenize input data
681 ANTLRInputStream input = new ANTLRInputStream(p);
682 poliqarpLexer.setInputStream(input);
683 CommonTokenStream tokens = new CommonTokenStream(poliqarpLexer);
684 parser = new AqlParser(tokens);
Joachim Bingeldc03c002014-04-17 13:40:40 +0000685
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000686 // Don't throw out erroneous stuff
687 parser.setErrorHandler(new BailErrorStrategy());
688 parser.removeErrorListeners();
Joachim Bingeldc03c002014-04-17 13:40:40 +0000689
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000690 // Get starting rule from parser
691 Method startRule = AqlParser.class.getMethod("start");
692 tree = (ParserRuleContext) startRule.invoke(parser, (Object[])null);
693 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000694
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000695 // Some things went wrong ...
696 catch (Exception e) {
697 log.error(e.getMessage());
698 System.err.println( e.getMessage() );
699 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000700
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000701 if (tree == null) {
702 log.error("Could not parse query. Make sure it is correct ANNIS QL syntax.");
703 throw new QueryException("Could not parse query. Make sure it is correct ANNIS QL syntax.");
704 }
705
706 // Return the generated tree
707 return tree;
708 }
709
Joachim Bingeldc03c002014-04-17 13:40:40 +0000710 public static void main(String[] args) {
711 /*
712 * For testing
713 */
714 String[] queries = new String[] {
Joachim Bingelaaabb722014-09-24 14:29:10 +0000715// "cat=\"NP\" & cat=\"VP\" & #1 $ #2 ",
716// "Haus",
717// "lemma=\"Haus\"",
718// "Katze=\"Hund\"",
719// "cnx/c=\"NP\"",
720// "cat=\"NP\"",
721// "node & node & #1 .+ #2",
722// " #1 > #2 & cnx/cat=\"VP\" & cnx/cat=\"NP\"",
723// "\"Mann\" & node & #2 >[cat=\"NP\"] #1",
724// "node & node & #2 ->coref[val=\"true\"] #1",
725// "cat=\"NP\" & cat=\"VP\" & cat=\"PP\" & #1 $ #2 > #3",
726// "tok=\"Mann\" & tok=\"geht\" & #1 .* #2",
727// "\"Sonne\"",
Joachim Bingele6d73b12014-09-30 15:34:59 +0000728// "\"so\" & ( \"nicht\" | \"doch\" ) & #1 .1,6 #2",
729//
730// "NP#cat=\"NP\" & PP1#cat=\"PP\" . PP2#cat=\"PP\" & #NP > #PP1 & #NP > #PP2 ",
731// "cat=\"NP\" > cat=\"VP\" & #1 _l_ #2",
732// "cat=\"NP\" > cat=\"VP\" & #1 . tok=\"foo\"",
733 "cat=\"NP\" & cat=\"VP\" & #1 > #2 & #1 _l_ #2",
Joachim Bingelc9c0cf92014-10-02 12:03:59 +0000734 "tok"
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000735 };
736 // AqlTree.verbose=true;
Joachim Bingeldc03c002014-04-17 13:40:40 +0000737 for (String q : queries) {
738 try {
739 System.out.println(q);
Joachim Bingeldc03c002014-04-17 13:40:40 +0000740 AqlTree at = new AqlTree(q);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000741 System.out.println(at.parseAnnisQuery(q).toStringTree(at.parser));
Joachim Bingeldc03c002014-04-17 13:40:40 +0000742 System.out.println();
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000743
Joachim Bingeldc03c002014-04-17 13:40:40 +0000744 } catch (NullPointerException | QueryException npe) {
745 npe.printStackTrace();
746 }
747 }
748 }
749
750}