blob: bb56d6552818f03cda0070511df532876724cfcf [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 Bingel3fa584b2014-12-17 13:35:43 +000025import de.ids_mannheim.korap.query.serialize.util.Antlr4DescriptiveErrorListener;
Joachim Bingeldc03c002014-04-17 13:40:40 +000026import de.ids_mannheim.korap.util.QueryException;
27
28/**
Joachim Bingelc8a28e42014-04-24 15:06:42 +000029 * Map representation of ANNIS QL syntax tree as returned by ANTLR
Joachim Bingeldc03c002014-04-17 13:40:40 +000030 * @author joachim
31 *
32 */
Joachim Bingelc8a28e42014-04-24 15:06:42 +000033public class AqlTree extends Antlr4AbstractSyntaxTree {
Joachim Bingelc63f7812014-07-30 09:12:25 +000034 private static Logger log = LoggerFactory.getLogger(AqlTree.class);
Joachim Bingeldc03c002014-04-17 13:40:40 +000035 /**
Joachim Bingeldc03c002014-04-17 13:40:40 +000036 * Flag that indicates whether token fields or meta fields are currently being processed
37 */
38 boolean inMeta = false;
39 /**
Joachim Bingel949e3a82014-06-16 13:20:43 +000040 * Keeps track of operands that are to be integrated into yet uncreated objects.
41 */
42 LinkedList<LinkedHashMap<String,Object>> operandStack = new LinkedList<LinkedHashMap<String,Object>>();
43 /**
Joachim Bingelc8a28e42014-04-24 15:06:42 +000044 * Keeps track of explicitly (by #-var definition) or implicitly (number as reference) introduced entities (for later reference by #-operator)
45 */
Joachim Bingelab1aff42014-12-16 16:38:00 +000046 Map<String, LinkedHashMap<String,Object>> nodeVariables = new LinkedHashMap<String, LinkedHashMap<String,Object>>();
Joachim Bingelc8a28e42014-04-24 15:06:42 +000047 /**
48 * Counter for variable definitions.
49 */
50 Integer variableCounter = 1;
51 /**
Joachim Bingeldc03c002014-04-17 13:40:40 +000052 * Marks the currently active token in order to know where to add flags (might already have been taken away from token stack).
53 */
54 LinkedHashMap<String,Object> curToken = new LinkedHashMap<String,Object>();
Joachim Bingel75038792014-05-19 15:12:23 +000055 /**
56 * Keeps track of operands lists that are to be serialised in an inverted
57 * order (e.g. the IN() operator) compared to their AST representation.
58 */
59 private LinkedList<ArrayList<Object>> invertedOperandsLists = new LinkedList<ArrayList<Object>>();
Joachim Bingel77ac5cb2014-04-22 14:03:28 +000060 /**
Joachim Bingelfc428812014-06-18 14:50:14 +000061 * Keeps track of operation:class numbers.
62 */
63 int classCounter = 0;
64 /**
Joachim Bingel9c3ddb92014-06-23 13:49:58 +000065 * Keeps track of numers of relations processed (important when dealing with multiple predications).
66 */
67 int relationCounter = 0;
68 /**
Joachim Bingel019ba5c2014-04-28 14:59:04 +000069 * 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
70 * but are to be integrated into the AqlTree at a later point (namely as operands of the respective group). Therefore, store references to these
71 * nodes here and exclude the operands from being written into the query map individually.
72 */
73 private LinkedList<String> operandOnlyNodeRefs = new LinkedList<String>();
Joachim Bingel1846c8c2014-07-08 14:13:31 +000074 private List<ParseTree> globalLingTermNodes = new ArrayList<ParseTree>();
Joachim Bingel9c3ddb92014-06-23 13:49:58 +000075 private int totalRelationCount;
Joachim Bingel1846c8c2014-07-08 14:13:31 +000076 /**
77 * 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
78 * spans to refer back to previously established classes for entities.
79 */
Joachim Bingelb001d192014-06-25 11:34:36 +000080 private LinkedHashMap<String, Integer> refClassMapping = new LinkedHashMap<String, Integer>();
Joachim Bingel9c3ddb92014-06-23 13:49:58 +000081 private LinkedHashMap<String, Integer> nodeReferencesTotal = new LinkedHashMap<String, Integer>();
82 private LinkedHashMap<String, Integer> nodeReferencesProcessed = new LinkedHashMap<String, Integer>();
Joachim Bingel1846c8c2014-07-08 14:13:31 +000083
Joachim Bingeldc03c002014-04-17 13:40:40 +000084 /**
85 *
86 * @param tree The syntax tree as returned by ANTLR
87 * @param parser The ANTLR parser instance that generated the parse tree
88 */
89 public AqlTree(String query) {
Joachim Bingeldc03c002014-04-17 13:40:40 +000090 try {
91 process(query);
92 } catch (QueryException e) {
93 e.printStackTrace();
94 }
95 System.out.println(">>> "+requestMap.get("query")+" <<<");
96 }
97
Joachim Bingeldc03c002014-04-17 13:40:40 +000098 @Override
99 public void process(String query) throws QueryException {
100 ParseTree tree = parseAnnisQuery(query);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000101 if (this.parser != null) {
102 super.parser = this.parser;
103 } else {
104 throw new NullPointerException("Parser has not been instantiated!");
105 }
Joachim Bingel75038792014-05-19 15:12:23 +0000106 log.info("Processing Annis query.");
Joachim Bingele3fe3672014-12-17 18:35:58 +0000107 if (tree != null) {
108 log.debug("ANTLR parse tree: "+tree.toStringTree(parser));
109 processNode(tree);
Joachim Bingelab1aff42014-12-16 16:38:00 +0000110 }
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 }
Joachim Bingelab1aff42014-12-16 16:38:00 +0000180 System.err.println(nodeVariables);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000181 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000182
Joachim Bingelc89952e2014-06-06 12:08:42 +0000183 if (nodeCat.equals("unary_linguistic_term")) {
Joachim Bingelca4944e2014-06-13 13:55:10 +0000184 LinkedHashMap<String, Object> unaryOperator = parseUnaryOperator(node);
185 String reference = node.getChild(0).toStringTree(parser).substring(1);
Joachim Bingelab1aff42014-12-16 16:38:00 +0000186 LinkedHashMap<String, Object> object = nodeVariables.get(reference);
Joachim Bingelca4944e2014-06-13 13:55:10 +0000187 object.putAll(unaryOperator);
Joachim Bingelc89952e2014-06-06 12:08:42 +0000188 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000189
Joachim Bingelc89952e2014-06-06 12:08:42 +0000190 if (nodeCat.equals("n_ary_linguistic_term")) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000191 processN_ary_linguistic_term(node);
Joachim Bingeldc03c002014-04-17 13:40:40 +0000192 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000193
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000194 if (nodeCat.equals("variableExpr")) {
Joachim Bingelab1aff42014-12-16 16:38:00 +0000195 processVariableExpr(node);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000196 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000197
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000198 objectsToPop.push(stackedObjects);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000199
Joachim Bingeldc03c002014-04-17 13:40:40 +0000200 /*
201 ****************************************************************
202 ****************************************************************
203 * recursion until 'request' node (root of tree) is processed *
204 ****************************************************************
205 ****************************************************************
206 */
207 for (int i=0; i<node.getChildCount(); i++) {
208 ParseTree child = node.getChild(i);
209 processNode(child);
210 }
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000211
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000212 /*
213 **************************************************************
214 * Stuff that happens after processing the children of a node *
215 **************************************************************
216 */
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000217 if (!objectsToPop.isEmpty()) {
218 for (int i=0; i<objectsToPop.pop(); i++) {
219 objectStack.pop();
220 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000221 }
Joachim Bingeldc03c002014-04-17 13:40:40 +0000222 openNodeCats.pop();
Joachim Bingeldc03c002014-04-17 13:40:40 +0000223 }
224
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000225
226
Joachim Bingelab1aff42014-12-16 16:38:00 +0000227 private LinkedHashMap<String, Object> processVariableExpr(ParseTree node) {
228 // simplex word or complex assignment (like qname = textSpec)?
229 String firstChildNodeCat = getNodeCat(node.getChild(0));
230 LinkedHashMap<String, Object> object = null;
231 if (firstChildNodeCat.equals("node")) {
232 object = makeSpan();
233 } else if (firstChildNodeCat.equals("tok")) {
234 object = makeToken();
235 if (node.getChildCount() > 1) { // empty tokens do not wrap a term
236 LinkedHashMap<String, Object> term = makeTerm();
237 term.put("layer", "orth");
238 object.put("wrap", term);
239 }
240 } else if (firstChildNodeCat.equals("qName")) { // only (foundry/)?layer specified
241 // may be token or span, depending on indicated layer! (e.g. cnx/cat=NP vs mate/pos=NN)
242 // TODO generalize the list below -> look up layers associated with tokens rather than spans somewhere
243 HashMap<String, Object> qNameParse = parseQNameNode(node.getChild(0));
244 if (Arrays.asList(new String[]{"p", "lemma", "m", "orth"}).contains(qNameParse.get("layer"))) {
245 object = makeToken();
246 LinkedHashMap<String, Object> term = makeTerm();
247 object.put("wrap", term);
248 term.putAll(qNameParse);
249 } else {
250 object = makeSpan();
251 object.putAll(qNameParse);
252 }
253 } else if (firstChildNodeCat.equals("textSpec")) {
254 object = makeToken();
255 LinkedHashMap<String, Object> term = makeTerm();
256 object.put("wrap", term);
257 term.put("layer", "orth");
258 term.putAll(parseTextSpec(node.getChild(0)));
259 }
260
261 if (node.getChildCount() == 3) { // (foundry/)?layer=key specification
262 if (object.get("@type").equals("korap:token")) {
263 HashMap<String, Object> term = (HashMap<String, Object>) object.get("wrap");
264 term.putAll(parseTextSpec(node.getChild(2)));
265 term.put("match", parseMatchOperator(getFirstChildWithCat(node, "eqOperator")));
266 } else {
267 object.putAll(parseTextSpec(node.getChild(2)));
268 object.put("match", parseMatchOperator(getFirstChildWithCat(node, "eqOperator")));
269 }
270 }
271
272 if (object != null) {
273// if (! operandOnlyNodeRefs.contains(variableCounter.toString())) {
274// putIntoSuperObject(object);
275// }
276 if (! getNodeCat(node.getParent().getParent()).equals("n_ary_linguistic_term")) {
277 putIntoSuperObject(object);
278 }
279 ParseTree parentsFirstChild = node.getParent().getChild(0);
280 if (getNodeCat(parentsFirstChild).endsWith("#")) {
281 nodeVariables.put(getNodeCat(parentsFirstChild).replaceAll("#", ""), object);
282 }
283 nodeVariables.put(variableCounter.toString(), object);
284 variableCounter++;
285 }
286 return object;
287 }
288
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000289 /**
290 * Processes an operand node, creating a map for the operand containing all its information
Joachim Bingelab1aff42014-12-16 16:38:00 +0000291 * given in the node definition (referenced via '#'). If this node has been referred to and used earlier,
292 * a reference is created in its place.
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000293 * The operand will be wrapped in a class group if necessary.
Joachim Bingelab1aff42014-12-16 16:38:00 +0000294 * @param operandNode
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000295 * @return A map object with the appropriate CQLF representation of the operand
296 */
Joachim Bingelab1aff42014-12-16 16:38:00 +0000297 private LinkedHashMap<String, Object> retrieveOperand(ParseTree operandNode) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000298 LinkedHashMap<String, Object> operand = null;
Joachim Bingelab1aff42014-12-16 16:38:00 +0000299 if (!getNodeCat(operandNode.getChild(0)).equals("variableExpr")) {
300 String ref = operandNode.getChild(0).toStringTree(parser).substring(1);
301 operand = nodeVariables.get(ref);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000302 if (nodeReferencesTotal.get(ref) > 1) {
303 if (nodeReferencesProcessed.get(ref)==0) {
304 refClassMapping.put(ref, classCounter);
305 operand = wrapInClass(operand, classCounter++);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000306 } else if (nodeReferencesProcessed.get(ref)>0 && nodeReferencesTotal.get(ref)>1) {
307 try {
308 operand = wrapInReference(operandStack.pop(), refClassMapping.get(ref));
309 } catch (NoSuchElementException e) {
310 operand = makeReference(refClassMapping.get(ref));
311 }
312 }
Joachim Bingelab1aff42014-12-16 16:38:00 +0000313 nodeReferencesProcessed.put(ref, nodeReferencesProcessed.get(ref)+1);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000314 }
Joachim Bingelab1aff42014-12-16 16:38:00 +0000315 } else {
316 operand = processVariableExpr(operandNode.getChild(0));
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000317 }
318 return operand;
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000319 }
320
321 @SuppressWarnings("unchecked")
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000322 private void processN_ary_linguistic_term(ParseTree node) {
323 relationCounter++;
324 // get operator and determine type of group (sequence/treeRelation/relation/...)
325 // It's possible in Annis QL to concatenate operators, so there may be several operators under one n_ary_linguistic_term node.
326 // Counter 'i' will iteratively point to all operator nodes (odd-numbered) under this node.
327 for (int i=1; i<node.getChildCount(); i = i+2) {
328 ParseTree operandTree1 = node.getChild(i-1);
329 ParseTree operandTree2 = node.getChild(i+1);
330 String reltype = getNodeCat(node.getChild(i).getChild(0));
331
332 LinkedHashMap<String,Object> group = null;
333 ArrayList<Object> operands = null;
334 // Retrieve operands.
335 LinkedHashMap<String, Object> operand1 = retrieveOperand(operandTree1);
336 LinkedHashMap<String, Object> operand2 = retrieveOperand(operandTree2);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000337 // 'Proper' n_ary_linguistic_operators receive a considerably different serialisation than 'commonparent' and 'commonancestor'.
338 // For the latter cases, a dummy span is introduced and declared as a span class that has a dominance relation towards
339 // the two operands, one after the other, thus resulting in two nested relations! A Poliqarp+ equivalent for A $ B would be
340 // contains(focus(1:contains({1:<>},A)), B).
341 // This is modeled here...
342 if (reltype.equals("commonparent") || reltype.equals("commonancestor")) {
343 // make an (outer) group and an inner group containing the dummy node or previous relations
344 group = makeGroup("relation");
345 LinkedHashMap<String,Object> innerGroup = makeGroup("relation");
Joachim Bingel62892412014-08-06 15:18:59 +0000346 LinkedHashMap<String,Object> relation = makeRelation();
347 LinkedHashMap<String,Object> term = makeTerm();
348 term.put("layer", "c");
349 relation.put("wrap", term);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000350 // commonancestor is an indirect commonparent relation
Joachim Bingele6d73b12014-09-30 15:34:59 +0000351 if (reltype.equals("commonancestor")) relation.put("boundary", makeBoundary(1, null));
Joachim Bingel62892412014-08-06 15:18:59 +0000352 group.put("relation", relation);
353 innerGroup.put("relation", relation);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000354 // Get operands list before possible re-assignment of 'group' (see following 'if')
355 ArrayList<Object> outerOperands = (ArrayList<Object>) group.get("operands");
356 ArrayList<Object> innerOperands = (ArrayList<Object>) innerGroup.get("operands");
357 // for lowest level, add the underspecified node as first operand and wrap it in a class group
358 if (i == 1) {
359 innerOperands.add(wrapInClass(makeSpan(), classCounter));
360 // add the first operand and wrap the whole group in a focusing reference
361 innerOperands.add(operand1);
362 innerGroup = wrapInReference(innerGroup, classCounter);
363 outerOperands.add(innerGroup);
364 } else {
365 outerOperands.add(operandStack.pop());
366 }
367 // Lookahead: if next operator is not commonparent or commonancestor, wrap in class for accessibility
368 if (i < node.getChildCount()-2 && !getNodeCat(node.getChild(i+2).getChild(0)).startsWith("common")) {
369 operand2 = wrapInClass(operand2, ++classCounter);
370 }
371 outerOperands.add(operand2);
372
373 // Wrap in another reference object in case other relations are following
374 if (i < node.getChildCount()-2) {
375 group = wrapInReference(group, classCounter);
376 }
Joachim Bingel62892412014-08-06 15:18:59 +0000377 // All other n-ary linguistic relations have special 'relation' attributes defined in CQLF and can be
378 // handled more easily...
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000379 } else {
380 LinkedHashMap<String, Object> operatorGroup = parseOperatorNode(node.getChild(i).getChild(0));
381 String groupType;
382 try {
383 groupType = (String) operatorGroup.get("groupType");
384 } catch (ClassCastException | NullPointerException n) {
385 groupType = "relation";
386 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000387 if (groupType.equals("relation") || groupType.equals("treeRelation")) {
Joachim Bingele6d73b12014-09-30 15:34:59 +0000388 group = makeGroup(groupType);
Joachim Bingel62892412014-08-06 15:18:59 +0000389 LinkedHashMap<String, Object> relation = new LinkedHashMap<String, Object>();
390 putAllButGroupType(relation, operatorGroup);
Joachim Bingel62892412014-08-06 15:18:59 +0000391 group.put("relation", relation);
Joachim Bingele6d73b12014-09-30 15:34:59 +0000392 } else if (groupType.equals("sequence")) {
393 group = makeGroup(groupType);
394 putAllButGroupType(group, operatorGroup);
395 } else if (groupType.equals("position")) {
396 group = new LinkedHashMap<String,Object>();
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000397 putAllButGroupType(group, operatorGroup);
398 }
Joachim Bingele6d73b12014-09-30 15:34:59 +0000399
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000400 // Get operands list before possible re-assignment of 'group' (see following 'if')
401 operands = (ArrayList<Object>) group.get("operands");
Joachim Bingel755ada92014-12-16 13:55:37 +0000402
403 ParseTree leftChildSpec = getFirstChildWithCat(node.getChild(i).getChild(0), "@l");
404 ParseTree rightChildSpec = getFirstChildWithCat(node.getChild(i).getChild(0), "@r");
Joachim Bingelab1aff42014-12-16 16:38:00 +0000405 if (leftChildSpec != null || rightChildSpec != null) {
Joachim Bingel755ada92014-12-16 13:55:37 +0000406 String frame = (leftChildSpec!=null) ? "frames:startswith" : "frames:endswith";
407 LinkedHashMap<String,Object> positionGroup = makePosition(new String[]{frame}, null);
408 operand2 = wrapInClass(operand2, ++classCounter);
409 ((ArrayList<Object>) positionGroup.get("operands")).add(group);
410 ((ArrayList<Object>) positionGroup.get("operands")).add(makeReference(classCounter,true));
411 group = positionGroup;
412 }
413
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000414 // Wrap in reference object in case other relations are following
415 if (i < node.getChildCount()-2) {
416 group = wrapInReference(group, classCounter);
417 }
418
419 // Inject operands.
420 // -> Case distinction:
421 if (node.getChildCount()==3) {
422 // Things are easy when there's just one operator (thus 3 children incl. operands)...
423 if (operand1 != null) operands.add(operand1);
424 if (operand2 != null) operands.add(operand2);
425 } else {
Joachim Bingel66472b82014-12-04 16:00:05 +0000426 // ... but things get a little more complicated here. The AST is of this form: (operand1 operator1 operand2 operator2 operand3 operator3 ...)
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000427 // but we'll have to serialize it in a nested, binary way: (((operand1 operator1 operand2) operator2 operand3) operator3 ...)
428 // the following code will do just that:
429 if (i == 1) {
430 // for the first operator, include both operands
431 if (operand1 != null) operands.add(operand1);
432 if (operand2 != null) operands.add(wrapInClass(operand2, classCounter++));
433 // Don't put this into the super object directly but store on operandStack
434 // (because this group will have to be an operand of a subsequent operator)
435 operandStack.push(group);
436 // for all subsequent operators, only take the 2nd operand (first was already added by previous operator)
437 } else if (i < node.getChildCount()-2) {
438 // for all intermediate operators, include other previous groups and 2nd operand. Store this on the operandStack, too.
439 if (operand2 != null) operands.add(wrapInClass(operand2, classCounter++));
440 operands.add(0, operandStack.pop());
441 operandStack.push(group);
442 } else if (i == node.getChildCount()-2) {
443 // This is the last operator. Include 2nd operand only
444 if (operand2 != null) operands.add(operand2);
445 }
446 }
447 }
448 // Final step: decide what to do with the 'group' object, depending on whether all relations have been processed
449 if (i == node.getChildCount()-2 && relationCounter == totalRelationCount) {
450 putIntoSuperObject(group);
451 if (!operandStack.isEmpty()) {
452 operands.add(0, operandStack.pop());
453 }
454 objectStack.push(group);
455 stackedObjects++;
456 } else {
457 operandStack.push(group);
458 }
459 }
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000460 }
461
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000462
463
Joachim Bingelca4944e2014-06-13 13:55:10 +0000464 /**
465 * Parses a unary_linguistic_operator node. Possible operators are: root, arity, tokenarity.
466 * Operators are embedded into a korap:term, in turn wrapped by an 'attr' property in a korap:span.
467 * @param node The unary_linguistic_operator node
468 * @return A map containing the attr key, to be inserted into korap:span
469 */
470 private LinkedHashMap<String, Object> parseUnaryOperator(ParseTree node) {
471 LinkedHashMap<String, Object> attr = new LinkedHashMap<String, Object>();
472 LinkedHashMap<String, Object> term = makeTerm();
473 String op = node.getChild(1).toStringTree(parser).substring(1);
474 if (op.equals("arity") || op.equals("tokenarity")) {
475 LinkedHashMap<String, Object> boundary = boundaryFromRangeSpec(node.getChild(3), false);
476 term.put(op, boundary);
477 } else {
478 term.put(op, true);
479 }
Joachim Bingelca4944e2014-06-13 13:55:10 +0000480 attr.put("attr", term);
481 return attr;
482 }
483
Joachim Bingel66472b82014-12-04 16:00:05 +0000484 @SuppressWarnings("unchecked")
Joachim Bingeleee549e2014-04-29 11:15:37 +0000485 private LinkedHashMap<String, Object> parseOperatorNode(ParseTree operatorNode) {
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000486 LinkedHashMap<String, Object> relation = null;
Joachim Bingeleee549e2014-04-29 11:15:37 +0000487 String operator = getNodeCat(operatorNode);
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000488 // DOMINANCE
Joachim Bingeleee549e2014-04-29 11:15:37 +0000489 if (operator.equals("dominance")) {
Joachim Bingel62892412014-08-06 15:18:59 +0000490 relation = makeRelation();
Joachim Bingel13421ef2014-05-07 16:22:58 +0000491 relation.put("groupType", "relation");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000492 ParseTree qName = getFirstChildWithCat(operatorNode, "qName");
Joachim Bingel66472b82014-12-04 16:00:05 +0000493 ParseTree edgeSpecNode = getFirstChildWithCat(operatorNode, "edgeSpec");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000494 ParseTree star = getFirstChildWithCat(operatorNode, "*");
495 ParseTree rangeSpec = getFirstChildWithCat(operatorNode, "rangeSpec");
Joachim Bingel62892412014-08-06 15:18:59 +0000496 LinkedHashMap<String,Object> term = makeTerm();
497 term.put("layer", "c");
Joachim Bingel62892412014-08-06 15:18:59 +0000498 if (qName != null) term = parseQNameNode(qName);
Joachim Bingel66472b82014-12-04 16:00:05 +0000499 if (edgeSpecNode != null) {
500 LinkedHashMap<String,Object> edgeSpec = parseEdgeSpec(edgeSpecNode);
501 String edgeSpecType = (String) edgeSpec.get("@type");
502 if (edgeSpecType.equals("korap:termGroup")) {
503 ((ArrayList<Object>) edgeSpec.get("operands")).add(term);
504 term = edgeSpec;
505 } else {
506 term = makeTermGroup("and");
507 ArrayList<Object> termGroupOperands = (ArrayList<Object>) term.get("operands");
508 termGroupOperands.add(edgeSpec);
509 LinkedHashMap<String,Object> constTerm = makeTerm();
510 constTerm.put("layer", "c");
511 termGroupOperands.add(constTerm);
512 }
513 }
Joachim Bingel62892412014-08-06 15:18:59 +0000514 if (star != null) relation.put("boundary", makeBoundary(0, null));
Joachim Bingel86195a52014-07-08 14:29:48 +0000515 if (rangeSpec != null) relation.put("boundary", boundaryFromRangeSpec(rangeSpec));
Joachim Bingel62892412014-08-06 15:18:59 +0000516 relation.put("wrap", term);
Joachim Bingeleee549e2014-04-29 11:15:37 +0000517 }
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000518 else if (operator.equals("pointing")) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000519 // String reltype = operatorNode.getChild(1).toStringTree(parser);
Joachim Bingel62892412014-08-06 15:18:59 +0000520 relation = makeRelation();
Joachim Bingel13421ef2014-05-07 16:22:58 +0000521 relation.put("groupType", "relation");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000522 ParseTree qName = getFirstChildWithCat(operatorNode, "qName");
523 ParseTree edgeSpec = getFirstChildWithCat(operatorNode, "edgeSpec");
524 ParseTree star = getFirstChildWithCat(operatorNode, "*");
525 ParseTree rangeSpec = getFirstChildWithCat(operatorNode, "rangeSpec");
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000526 // if (qName != null) relation.putAll(parseQNameNode(qName));
Joachim Bingel62892412014-08-06 15:18:59 +0000527 LinkedHashMap<String,Object> term = makeTerm();
528 if (qName != null) term.putAll(parseQNameNode(qName));
529 if (edgeSpec != null) term.putAll(parseEdgeSpec(edgeSpec));
Joachim Bingele6d73b12014-09-30 15:34:59 +0000530 if (star != null) relation.put("boundary", makeBoundary(0, null));
Joachim Bingel86195a52014-07-08 14:29:48 +0000531 if (rangeSpec != null) relation.put("boundary", boundaryFromRangeSpec(rangeSpec));
Joachim Bingel62892412014-08-06 15:18:59 +0000532 relation.put("wrap", term);
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000533 }
534 else if (operator.equals("precedence")) {
Joachim Bingel13421ef2014-05-07 16:22:58 +0000535 relation = new LinkedHashMap<String, Object>();
536 relation.put("groupType", "sequence");
537 ParseTree rangeSpec = getFirstChildWithCat(operatorNode, "rangeSpec");
538 ParseTree star = getFirstChildWithCat(operatorNode, "*");
539 ArrayList<Object> distances = new ArrayList<Object>();
540 if (star != null) {
Joachim Bingel687e4d42014-07-30 09:34:18 +0000541 distances.add(makeDistance("w", 0, null));
Joachim Bingel13421ef2014-05-07 16:22:58 +0000542 relation.put("distances", distances);
543 }
544 if (rangeSpec != null) {
545 distances.add(parseDistance(rangeSpec));
546 relation.put("distances", distances);
547 }
548 relation.put("inOrder", true);
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000549 }
550 else if (operator.equals("spanrelation")) {
Joachim Bingele6d73b12014-09-30 15:34:59 +0000551// relation = makeGroup("position");
552// relation.put("groupType", "position");
Joachim Bingel75038792014-05-19 15:12:23 +0000553 String reltype = operatorNode.getChild(0).toStringTree(parser);
Joachim Bingele6d73b12014-09-30 15:34:59 +0000554 String[] frames = new String[]{};
Joachim Bingel75038792014-05-19 15:12:23 +0000555 switch (reltype) {
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000556 case "_=_":
Joachim Bingel6b491c22014-10-21 08:35:18 +0000557 frames = new String[]{"frames:matches"};
Joachim Bingele6d73b12014-09-30 15:34:59 +0000558 break;
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000559 case "_l_":
Joachim Bingel6b491c22014-10-21 08:35:18 +0000560 frames = new String[]{"frames:startswith"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000561 break;
562 case "_r_":
Joachim Bingel6b491c22014-10-21 08:35:18 +0000563 frames = new String[]{"frames:endswith"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000564 break;
565 case "_i_":
Joachim Bingel6b491c22014-10-21 08:35:18 +0000566 frames = new String[]{"frames:contains"};break;
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000567 case "_o_":
Joachim Bingel6b491c22014-10-21 08:35:18 +0000568 frames = new String[]{"frames:overlapsLeft", "frames:overlapsRight"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000569 break;
570 case "_ol_":
Joachim Bingel6b491c22014-10-21 08:35:18 +0000571 frames = new String[]{"frames:overlapsLeft"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000572 break;
573 case "_or_":
Joachim Bingel6b491c22014-10-21 08:35:18 +0000574 frames = new String[]{"frames:overlapsRight"};
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000575 break;
Joachim Bingel75038792014-05-19 15:12:23 +0000576 }
Joachim Bingele6d73b12014-09-30 15:34:59 +0000577// relation.put("frames", frames);
578// relation.put("sharedClasses", sharedClasses);
Joachim Bingel6b491c22014-10-21 08:35:18 +0000579 relation = makePosition(frames, new String[]{});
Joachim Bingele6d73b12014-09-30 15:34:59 +0000580 relation.put("groupType", "position");
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000581 }
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000582 else if (operator.equals("identity")) {
Joachim Bingel66472b82014-12-04 16:00:05 +0000583 //TODO since ANNIS v. 3.1.6
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000584 }
585 else if (operator.equals("equalvalue")) {
Joachim Bingel66472b82014-12-04 16:00:05 +0000586 //TODO since ANNIS v. 3.1.6
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000587 }
588 else if (operator.equals("notequalvalue")) {
Joachim Bingel66472b82014-12-04 16:00:05 +0000589 //TODO since ANNIS v. 3.1.6
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000590 }
591 return relation;
592 }
593
Joachim Bingelceb79062014-09-22 11:50:37 +0000594 @SuppressWarnings("unchecked")
Joachim Bingel62892412014-08-06 15:18:59 +0000595 private LinkedHashMap<String,Object> parseEdgeSpec(ParseTree edgeSpec) {
596 List<ParseTree> annos = getChildrenWithCat(edgeSpec, "edgeAnno");
597 if (annos.size() == 1) return parseEdgeAnno(annos.get(0));
598 else {
599 LinkedHashMap<String,Object> termGroup = makeTermGroup("and");
600 ArrayList<Object> operands = (ArrayList<Object>) termGroup.get("operands");
601 for (ParseTree anno : annos) {
602 operands.add(parseEdgeAnno(anno));
603 }
604 return termGroup;
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000605 }
Joachim Bingeleee549e2014-04-29 11:15:37 +0000606 }
607
Joachim Bingel66472b82014-12-04 16:00:05 +0000608 private LinkedHashMap<String, Object> parseEdgeAnno(ParseTree edgeAnnoSpec) {
Joachim Bingeleee549e2014-04-29 11:15:37 +0000609 LinkedHashMap<String, Object> edgeAnno = new LinkedHashMap<String, Object>();
Joachim Bingela07b8e72014-05-09 15:06:07 +0000610 edgeAnno.put("@type", "korap:term");
Joachim Bingel66472b82014-12-04 16:00:05 +0000611 ParseTree textSpecNode = getFirstChildWithCat(edgeAnnoSpec, "textSpec");
612 ParseTree layerNode = getFirstChildWithCat(edgeAnnoSpec, "layer");
613 ParseTree foundryNode = getFirstChildWithCat(edgeAnnoSpec, "foundry");
614 ParseTree matchOperatorNode = getFirstChildWithCat(edgeAnnoSpec, "eqOperator");
Joachim Bingel639df9c2014-05-12 15:27:00 +0000615 if (foundryNode!=null) edgeAnno.put("foundry", foundryNode.getChild(0).toStringTree(parser));
616 if (layerNode!=null) edgeAnno.put("layer", layerNode.getChild(0).toStringTree(parser));
Joachim Bingeleee549e2014-04-29 11:15:37 +0000617 edgeAnno.putAll(parseTextSpec(textSpecNode));
618 edgeAnno.put("match", parseMatchOperator(matchOperatorNode));
619 return edgeAnno;
620 }
621
Joachim Bingela07b8e72014-05-09 15:06:07 +0000622 private LinkedHashMap<String, Object> boundaryFromRangeSpec(ParseTree rangeSpec) {
Joachim Bingelca4944e2014-06-13 13:55:10 +0000623 return boundaryFromRangeSpec(rangeSpec, true);
624 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000625
Joachim Bingelca4944e2014-06-13 13:55:10 +0000626 private LinkedHashMap<String, Object> boundaryFromRangeSpec(ParseTree rangeSpec, boolean expandToMax) {
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000627 Integer min = Integer.parseInt(rangeSpec.getChild(0).toStringTree(parser));
Joachim Bingelca4944e2014-06-13 13:55:10 +0000628 Integer max = min;
Joachim Bingel687e4d42014-07-30 09:34:18 +0000629 if (expandToMax) max = null;
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000630 if (rangeSpec.getChildCount()==3)
631 max = Integer.parseInt(rangeSpec.getChild(2).toStringTree(parser));
632 return makeBoundary(min, max);
633 }
Joachim Bingela07b8e72014-05-09 15:06:07 +0000634
Joachim Bingel13421ef2014-05-07 16:22:58 +0000635 private LinkedHashMap<String, Object> parseDistance(ParseTree rangeSpec) {
636 Integer min = Integer.parseInt(rangeSpec.getChild(0).toStringTree(parser));
Joachim Bingel687e4d42014-07-30 09:34:18 +0000637 Integer max = null;
Joachim Bingel13421ef2014-05-07 16:22:58 +0000638 if (rangeSpec.getChildCount()==3)
639 max = Integer.parseInt(rangeSpec.getChild(2).toStringTree(parser));
640 return makeDistance("w", min, max);
641 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000642
Joachim Bingeleee549e2014-04-29 11:15:37 +0000643 private LinkedHashMap<String, Object> parseTextSpec(ParseTree node) {
644 LinkedHashMap<String, Object> term = new LinkedHashMap<String, Object>();
Joachim Bingel019ba5c2014-04-28 14:59:04 +0000645 if (hasChild(node, "regex")) {
646 term.put("type", "type:regex");
647 term.put("key", node.getChild(0).getChild(0).toStringTree(parser).replaceAll("/", ""));
648 } else {
649 term.put("key", node.getChild(1).toStringTree(parser));
650 }
651 term.put("match", "match:eq");
652 return term;
653 }
654
Joachim Bingeldc03c002014-04-17 13:40:40 +0000655 /**
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000656 * Parses the match operator (= or !=)
Joachim Bingeldc03c002014-04-17 13:40:40 +0000657 * @param node
658 * @return
659 */
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000660 private String parseMatchOperator(ParseTree node) {
Joachim Bingel66472b82014-12-04 16:00:05 +0000661 if (node.getChildCount()>0) {
662 return node.getChild(0).toStringTree(parser).equals("=") ? "match:eq" : "match:ne";
663 }
664 return null;
Joachim Bingeldc03c002014-04-17 13:40:40 +0000665 }
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000666
667 private LinkedHashMap<String, Object> parseQNameNode(ParseTree node) {
668 LinkedHashMap<String, Object> fields = new LinkedHashMap<String, Object>();
Joachim Bingeld4ae5fd2014-04-29 15:00:16 +0000669 ParseTree layerNode = getFirstChildWithCat(node, "layer");
670 ParseTree foundryNode = getFirstChildWithCat(node, "foundry");
671 if (foundryNode != null) fields.put("foundry", foundryNode.getChild(0).toStringTree(parser));
Joachim Bingel66472b82014-12-04 16:00:05 +0000672 String layer = layerNode.getChild(0).toStringTree(parser);
673 if (layer.equals("pos")) layer = "p";
674 if (layer.equals("cat")) layer = "c";
675 fields.put("layer", layer);
Joachim Bingelc8a28e42014-04-24 15:06:42 +0000676 return fields;
677 }
678
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000679 private void putIntoSuperObject(LinkedHashMap<String, Object> object) {
680 putIntoSuperObject(object, 0);
681 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000682
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000683 @SuppressWarnings({ "unchecked" })
684 private void putIntoSuperObject(LinkedHashMap<String, Object> object, int objStackPosition) {
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000685 if (objectStack.size()>objStackPosition) {
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000686 ArrayList<Object> topObjectOperands = (ArrayList<Object>) objectStack.get(objStackPosition).get("operands");
Joachim Bingel75038792014-05-19 15:12:23 +0000687 if (!invertedOperandsLists.contains(topObjectOperands)) {
688 topObjectOperands.add(object);
689 } else {
690 topObjectOperands.add(0, object);
691 }
Joachim Bingel77ac5cb2014-04-22 14:03:28 +0000692 } else {
693 requestMap.put("query", object);
694 }
695 }
Joachim Bingel9c3ddb92014-06-23 13:49:58 +0000696
Joachim Bingel13421ef2014-05-07 16:22:58 +0000697 private void putAllButGroupType(Map<String, Object> container, Map<String, Object> input) {
698 for (String key : input.keySet()) {
699 if (!key.equals("groupType")) {
700 container.put(key, input.get(key));
701 }
702 }
703 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000704
Joachim Bingel3fa584b2014-12-17 13:35:43 +0000705 private ParserRuleContext parseAnnisQuery (String query) throws QueryException {
706 Lexer lexer = new AqlLexer((CharStream)null);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000707 ParserRuleContext tree = null;
Joachim Bingel3fa584b2014-12-17 13:35:43 +0000708 Antlr4DescriptiveErrorListener errorListener = new Antlr4DescriptiveErrorListener(query);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000709 // Like p. 111
710 try {
Joachim Bingeldc03c002014-04-17 13:40:40 +0000711
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000712 // Tokenize input data
Joachim Bingel3fa584b2014-12-17 13:35:43 +0000713 ANTLRInputStream input = new ANTLRInputStream(query);
714 lexer.setInputStream(input);
715 CommonTokenStream tokens = new CommonTokenStream(lexer);
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000716 parser = new AqlParser(tokens);
Joachim Bingeldc03c002014-04-17 13:40:40 +0000717
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000718 // Don't throw out erroneous stuff
719 parser.setErrorHandler(new BailErrorStrategy());
Joachim Bingel3fa584b2014-12-17 13:35:43 +0000720 lexer.removeErrorListeners();
721 lexer.addErrorListener(errorListener);
722 parser.removeErrorListeners();
723 parser.addErrorListener(errorListener);
Joachim Bingeldc03c002014-04-17 13:40:40 +0000724
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000725 // Get starting rule from parser
726 Method startRule = AqlParser.class.getMethod("start");
727 tree = (ParserRuleContext) startRule.invoke(parser, (Object[])null);
728 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000729 // Some things went wrong ...
730 catch (Exception e) {
Joachim Bingele3fe3672014-12-17 18:35:58 +0000731 log.error("Could not parse query. Please make sure it is well-formed.");
732 log.error(errorListener.generateFullErrorMsg().toString());
733 addError(errorListener.generateFullErrorMsg());
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000734 }
Joachim Bingel1846c8c2014-07-08 14:13:31 +0000735 return tree;
736 }
Joachim Bingel761d1c12014-12-17 14:02:40 +0000737}