Skip to content

Commit

Permalink
allow to directly use node definitions in precedence operators
Browse files Browse the repository at this point in the history
like

tok . pos="NN"

instead of

tok & pos="NN" & # 1 . #2
  • Loading branch information
thomaskrause committed Nov 19, 2013
1 parent 9e8b630 commit f8f655d
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 29 deletions.
12 changes: 6 additions & 6 deletions annis-service/src/main/antlr4/annis/ql/AqlLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ DOUBLECOLON:'::';

WS : ( ' ' | '\t' | '\r' | '\n' )+ -> skip ;

ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-')*
;

VAR_DEF
: ('a'..'z'|'A'..'Z') ( '0' .. '9'|'a'..'z'|'A'..'Z')* '#'
;

REF
: '#' ( '0' .. '9'|'a'..'z'|'A'..'Z')+
;

VAR_DEF
: ('a'..'z'|'A'..'Z') ( '0' .. '9'|'a'..'z'|'A'..'Z')* '#'
;
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-')*
;

DIGITS : ('0'..'9')+;

Expand Down
15 changes: 10 additions & 5 deletions annis-service/src/main/antlr4/annis/ql/AqlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,16 @@ edgeSpec
: BRACKET_OPEN edgeAnno+ BRACKET_CLOSE
;

refOrNode
: REF # ReferenceRef
| VAR_DEF? variableExpr # ReferenceNode
;


precedence
: left=REF PRECEDENCE (layer=ID)? right=REF # DirectPrecedence
| left=REF PRECEDENCE (layer=ID)? STAR right=REF # IndirectPrecedence
| left=REF PRECEDENCE (layer=ID COMMA?)? rangeSpec right=REF #RangePrecedence
: left=refOrNode PRECEDENCE (layer=ID)? right=refOrNode # DirectPrecedence
| left=refOrNode PRECEDENCE (layer=ID)? STAR right=refOrNode # IndirectPrecedence
| left=refOrNode PRECEDENCE (layer=ID COMMA?)? rangeSpec right=refOrNode #RangePrecedence
;

dominance
Expand Down Expand Up @@ -106,8 +111,8 @@ variableExpr
;

expr
: VAR_DEF variableExpr # VariableTermExpr
| variableExpr # NoVariableTermExpr
: VAR_DEF variableExpr # NamedVariableTermExpr
| variableExpr # VariableTermExpr
| unary_linguistic_term # UnaryTermExpr
| binary_linguistic_term # BinaryTermExpr
| META DOUBLECOLON id=qName op=EQ txt=textSpec # MetaTermExpr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public QueryData parse(String aql, List<Long> corpusList)
data.setCorpusList(corpusList);
data.addMetaAnnotations(nodeListener.getMetaData());

JoinListener joinListener = new JoinListener(data, precedenceBound);
JoinListener joinListener = new JoinListener(data, precedenceBound,
nodeListener.getTokenPositionToNode());
walker.walk(joinListener, treeDNF);

if (postProcessors != null)
Expand Down
62 changes: 55 additions & 7 deletions annis-service/src/main/java/annis/ql/parser/JoinListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,17 @@
import annis.sqlgen.model.Sibling;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.Interval;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -63,17 +66,22 @@ public class JoinListener extends AqlParserBaseListener
* Each entry maps node variables to a collection of query nodes.
*/
private final Multimap<String, QueryNode>[] alternativeNodes;
/** Maps a token interval to a query nodes.
*/
private final Map<Interval, QueryNode> tokenPositionToNode;
private int alternativeIndex;

/**
* Constructor.
* @param data The {@link QueryData} containing the already parsed nodes.
* @param precedenceBound maximal range of precedence
* @param tokenPositionToNode maps a token interval to a query nodes
*/
public JoinListener(QueryData data, int precedenceBound)
public JoinListener(QueryData data, int precedenceBound, Map<Interval, QueryNode> tokenPositionToNode)
{
this.precedenceBound = precedenceBound;
this.alternativeNodes = new Multimap[data.getAlternatives().size()];
this.tokenPositionToNode = tokenPositionToNode;

int i=0;
for(List<QueryNode> alternative : data.getAlternatives())
Expand Down Expand Up @@ -143,8 +151,8 @@ public void enterTokenArityTerm(AqlParser.TokenArityTermContext ctx)
public void enterDirectPrecedence(
AqlParser.DirectPrecedenceContext ctx)
{
Collection<QueryNode> nodesLeft = nodesByRef(ctx.left);
Collection<QueryNode> nodesRight = nodesByRef(ctx.right);
Collection<QueryNode> nodesLeft = nodes(ctx.left);
Collection<QueryNode> nodesRight = nodes(ctx.right);
Preconditions.checkArgument(!nodesLeft.isEmpty(), errorLHS("precendence")
+ ": " + ctx.getText());
Preconditions.checkArgument(!nodesRight.isEmpty(), errorRHS("precendence")
Expand All @@ -164,12 +172,13 @@ public void enterDirectPrecedence(
}
}


@Override
public void enterIndirectPrecedence(
AqlParser.IndirectPrecedenceContext ctx)
{
Collection<QueryNode> nodesLeft = nodesByRef(ctx.left);
Collection<QueryNode> nodesRight = nodesByRef(ctx.right);
Collection<QueryNode> nodesLeft = nodes(ctx.left);
Collection<QueryNode> nodesRight = nodes(ctx.right);
Preconditions.checkArgument(!nodesLeft.isEmpty(), errorLHS("precendence")
+ ": " + ctx.getText());
Preconditions.checkNotNull(!nodesRight.isEmpty(), errorRHS("precendence")
Expand Down Expand Up @@ -201,8 +210,8 @@ public void enterIndirectPrecedence(
@Override
public void enterRangePrecedence(AqlParser.RangePrecedenceContext ctx)
{
Collection<QueryNode> nodesLeft = nodesByRef(ctx.left);
Collection<QueryNode> nodesRight = nodesByRef(ctx.right);
Collection<QueryNode> nodesLeft = nodes(ctx.left);
Collection<QueryNode> nodesRight = nodes(ctx.right);
Preconditions.checkNotNull(!nodesLeft.isEmpty(), errorLHS("precendence")
+ ": " + ctx.getText());
Preconditions.checkArgument(!nodesRight.isEmpty(), errorRHS("precendence")
Expand Down Expand Up @@ -573,6 +582,45 @@ private LinkedList<QueryAnnotation> fromEdgeAnnotation(
return annos;
}

private Collection<QueryNode> nodes(AqlParser.RefOrNodeContext ctx)
{
if(ctx instanceof AqlParser.ReferenceNodeContext)
{
return nodesByDef((AqlParser.ReferenceNodeContext) ctx);
}
else if(ctx instanceof AqlParser.ReferenceRefContext)
{
return nodesByRef(((AqlParser.ReferenceRefContext) ctx).REF().getSymbol());
}
else
{
return new LinkedList<QueryNode>();
}
}

private Collection<QueryNode> nodesByDef(AqlParser.ReferenceNodeContext ctx)
{
if(ctx.VAR_DEF() == null)
{
QueryNode result = tokenPositionToNode.get(ctx.variableExpr().getSourceInterval());
if(result == null)
{
return new LinkedList<QueryNode>();
}
else
{
return Lists.newArrayList(result);
}
}
else
{
String varDefText = ctx.VAR_DEF().getText();
// remove trailing #
varDefText = varDefText.substring(0, varDefText.length()-1);
return alternativeNodes[alternativeIndex].get(varDefText);
}
}

private Collection<QueryNode> nodesByRef(Token ref)
{
return alternativeNodes[alternativeIndex].get("" + ref.getText().substring(1));
Expand Down
44 changes: 35 additions & 9 deletions annis-service/src/main/java/annis/ql/parser/QueryNodeListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class QueryNodeListener extends AqlParserBaseListener
private String lastVariableDefinition = null;

private final Multimap<String, QueryNode> localNodes = HashMultimap.create();
private final Map<Interval, Long> tokenposition2NodeID = Maps.newHashMap();
private final Map<Interval, QueryNode> tokenPositionToNode = Maps.newHashMap();

private final List<QueryAnnotation> metaData = new ArrayList<QueryAnnotation>();

Expand Down Expand Up @@ -162,7 +162,7 @@ public void enterMetaTermExpr(AqlParser.MetaTermExprContext ctx)
}

@Override
public void enterVariableTermExpr(AqlParser.VariableTermExprContext ctx)
public void enterNamedVariableTermExpr(AqlParser.NamedVariableTermExprContext ctx)
{
lastVariableDefinition = null;
if(ctx != null)
Expand All @@ -179,6 +179,28 @@ public void enterVariableTermExpr(AqlParser.VariableTermExprContext ctx)
}
}
}

@Override
public void enterReferenceNode(AqlParser.ReferenceNodeContext ctx)
{
if(ctx != null && ctx.VAR_DEF() != null)
{
lastVariableDefinition = null;

String text = ctx.VAR_DEF().getText();
// remove the trailing "#"
if(text.endsWith("#"))
{
lastVariableDefinition = text.substring(0, text.length()-1);
}
else
{
lastVariableDefinition = text;
}

}
}




Expand Down Expand Up @@ -215,14 +237,10 @@ else if (txt instanceof AqlParser.RegexTextSpecContext)
return null;
}

private Collection<QueryNode> nodesByRef(Token ref)
{
return localNodes.get("" + ref.getText().substring(1));
}

private QueryNode newNode(ParserRuleContext ctx)
{
Long existingID = tokenposition2NodeID.get(ctx.getSourceInterval());
QueryNode existingNode = tokenPositionToNode.get(ctx.getSourceInterval());
Long existingID = existingNode == null ? null : existingNode.getId();

if(existingID == null)
{
Expand All @@ -242,9 +260,17 @@ private QueryNode newNode(ParserRuleContext ctx)

currentAlternative.add(n);
localNodes.put(n.getVariable(), n);
tokenposition2NodeID.put(ctx.getSourceInterval(), n.getId());
tokenPositionToNode.put(ctx.getSourceInterval(), n);

return n;
}

public Map<Interval, QueryNode> getTokenPositionToNode()
{
return tokenPositionToNode;
}




}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">

<util:map id="exampleSyntaxTrees">
<entry key="tok=/abc/ . right#pos">
<value><![CDATA[tok=/abc/ & right#pos & #1 . #right]]>
</value>
</entry>
<!--
<entry key="node &amp; (#1:root | #1:arity=2)">
<value><![CDATA[
Expand Down
2 changes: 1 addition & 1 deletion annis-service/src/test/java/annis/ql/parser/TestQuery.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/das/ & ( (cat=/NP/ & #1 . #2) | (/Haus/ & #1 . #3 ))
tok=/abc/ . right#pos

0 comments on commit f8f655d

Please sign in to comment.