Fixed Annis regex bug #47.

Change-Id: Idc9fae545afab7f6c32c766b3c2e04aafcb731ac
diff --git a/Changes b/Changes
index d545ba6..1e5f91d 100644
--- a/Changes
+++ b/Changes
@@ -1,7 +1,9 @@
-0.28 2017-11-21 
+0.28 2017-11-22 
 	- Added some enums for koral:operation (margaretha)
 	- Fixed node serialization of Annis QL containing lemma (margaretha)
 	- Added serialization for Annis keyword "lemma" (margaretha)
+	- Removed version from FCSQL processor (margaretha)
+	- Fixed Annis regex bug regarding slash after foundry (margaretha)
 	
 0.27 2017-09-12
 	- Changed Cosmas2 wildcards serialization as regex (margaretha)  
diff --git a/src/main/antlr/annis/AqlLexer.g4 b/src/main/antlr/annis/AqlLexer.g4
index b90d183..5b9da30 100644
--- a/src/main/antlr/annis/AqlLexer.g4
+++ b/src/main/antlr/annis/AqlLexer.g4
@@ -62,6 +62,11 @@
 SLASH:'/';
 QMARK : '?';
 
+ID :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-')*;
+//ID :	('a'..'z'|'A'..'Z'|'_'|'['|']') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-'|'['|']')*;
+
+FOUNDRY : ID SLASH;
+
 /*
  * Regular expressions (delimited by slashes in Annis)
  */
@@ -89,13 +94,8 @@
 :	'#' ( '0' .. '9'|'a'..'z'|'A'..'Z')+
 ;
 
-ID :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-')*;
-//ID :	('a'..'z'|'A'..'Z'|'_'|'['|']') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-'|'['|']')*;
-
 DIGITS : ('0'..'9')+;
 
-
-
 //START_TEXT_REGEX : '/' -> pushMode(IN_REGEX);
 START_TEXT_PLAIN:'"' -> pushMode(IN_TEXT);
 
diff --git a/src/main/antlr/annis/AqlParser.g4 b/src/main/antlr/annis/AqlParser.g4
index f510979..f26eb9b 100644
--- a/src/main/antlr/annis/AqlParser.g4
+++ b/src/main/antlr/annis/AqlParser.g4
@@ -54,14 +54,15 @@
 ;
 
 qName
-:	(foundry '/')? layer
+: foundry layer
+| layer
 ;
 
 edgeType
 : ID;
 
 edgeAnno
-:	((foundry '/')? (layer COLON)? key eqOperator)? textSpec
+: ((foundry layer? COLON)? key eqOperator)? textSpec
 ;
 
 edgeSpec
@@ -141,7 +142,8 @@
 ;
 
 foundry
-: ID;
+: FOUNDRY
+| ID;
 
 layer
 : ID;
@@ -178,8 +180,8 @@
 expr
 : varDef variableExpr # NamedVariableTermExpr
 | variableExpr # VariableTermExpr
-|	unary_linguistic_term # UnaryTermExpr
-|	n_ary_linguistic_term # BinaryTermExpr
+| unary_linguistic_term # UnaryTermExpr
+| n_ary_linguistic_term # BinaryTermExpr
 | META DOUBLECOLON id=qName op=EQ txt=textSpec # MetaTermExpr
 ;
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java b/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java
index 660235c..cc45e09 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java
@@ -18,6 +18,7 @@
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.Lexer;
 import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -1246,8 +1247,13 @@
         Map<String, Object> fields = new HashMap<String, Object>();
         ParseTree layerNode = getFirstChildWithCat(node, "layer");
         ParseTree foundryNode = getFirstChildWithCat(node, "foundry");
-        if (foundryNode != null)
-            fields.put("foundry", foundryNode.getChild(0).toStringTree(parser));
+        if (foundryNode != null){
+            String foundry = foundryNode.getChild(0).toStringTree(parser);
+            if (foundry.endsWith("/")){
+                foundry = foundry.substring(0, foundry.length()-1);
+            }
+            fields.put("foundry", foundry);
+        }
         String layer = layerNode.getChild(0).toStringTree(parser);
         if (layer.equals("pos")){
             layer = "p";
diff --git a/src/test/java/de/ids_mannheim/korap/query/test/annis/QnameWithRegexTest.java b/src/test/java/de/ids_mannheim/korap/query/test/annis/QnameWithRegexTest.java
new file mode 100644
index 0000000..0b4cd67
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/query/test/annis/QnameWithRegexTest.java
@@ -0,0 +1,41 @@
+package de.ids_mannheim.korap.query.test.annis;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import de.ids_mannheim.korap.query.serialize.QuerySerializer;
+
+public class QnameWithRegexTest {
+    private String query;
+
+    private QuerySerializer qs = new QuerySerializer();
+    private ObjectMapper mapper = new ObjectMapper();
+    private JsonNode res;
+
+    @Test
+    public void testRegex ()
+            throws JsonProcessingException, IOException {
+        query = "p = /V.*/";
+        qs.setQuery(query, "annis");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("p", res.at("/query/wrap/layer").asText());
+        assertEquals("V.*", res.at("/query/wrap/key").asText());
+    }
+
+    @Test
+    public void testRegexWithFoundry () throws JsonProcessingException, IOException {
+        query = "tt/p = /V.*/";
+        qs.setQuery(query, "annis");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("tt", res.at("/query/wrap/foundry").asText());
+        assertEquals("p", res.at("/query/wrap/layer").asText());
+        assertEquals("V.*", res.at("/query/wrap/key").asText());
+    }
+}