You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by pi...@apache.org on 2021/01/14 06:45:34 UTC

[atlas] branch branch-2.0 updated: ATLAS-4057 : DSL Search : Support glossary terms and relationship

This is an automated email from the ASF dual-hosted git repository.

pinal pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new fc5b0de  ATLAS-4057 : DSL Search : Support glossary terms and relationship
fc5b0de is described below

commit fc5b0deb288706e6277cde8df09e1482fb3fc614
Author: Pinal <pinal-shah>
AuthorDate: Wed Dec 2 20:18:17 2020 +0530

    ATLAS-4057 : DSL Search : Support glossary terms and relationship
    
    Signed-off-by: Pinal <pinal-shah>
---
 docs/src/documents/Search/SearchAdvanced.md        |   92 +-
 .../atlas/discovery/TermSearchProcessor.java       |    1 +
 .../java/org/apache/atlas/query/DSLVisitor.java    |   40 +-
 .../apache/atlas/query/GremlinQueryComposer.java   |   55 +-
 .../org/apache/atlas/query/antlr4/AtlasDSLLexer.g4 |    3 +
 .../apache/atlas/query/antlr4/AtlasDSLLexer.java   |  486 +++++-----
 .../apache/atlas/query/antlr4/AtlasDSLLexer.tokens |   58 ++
 .../apache/atlas/query/antlr4/AtlasDSLParser.g4    |    3 +
 .../apache/atlas/query/antlr4/AtlasDSLParser.java  | 1014 ++++++++++++++------
 .../query/antlr4/AtlasDSLParserBaseVisitor.java    |    7 +
 .../atlas/query/antlr4/AtlasDSLParserListener.java |  399 ++++++++
 .../atlas/query/antlr4/AtlasDSLParserVisitor.java  |    6 +
 .../test/java/org/apache/atlas/BasicTestSetup.java |   89 +-
 .../atlas/discovery/AtlasDiscoveryServiceTest.java |    1 -
 .../org/apache/atlas/query/DSLQueriesTest.java     |   27 +-
 .../atlas/query/GremlinQueryComposerTest.java      |   38 +-
 16 files changed, 1717 insertions(+), 602 deletions(-)

diff --git a/docs/src/documents/Search/SearchAdvanced.md b/docs/src/documents/Search/SearchAdvanced.md
index 46be142..872c2be 100644
--- a/docs/src/documents/Search/SearchAdvanced.md
+++ b/docs/src/documents/Search/SearchAdvanced.md
@@ -225,6 +225,62 @@ Example: To retrieve all entities that have _Dimension_ classification.
 {`Dimension`}
 </SyntaxHighlighter>
 
+###Non Primitive attribute Filtering
+In the discussion so far we looked at where clauses with primitive types. This section will look at using properties that are non-primitive types.
+
+#### Relationship-based filtering
+In this model, the DB is modeled such that it is aware of all the Table it contains. Table on the other hand is aware of existence of the DB but is not aware of all the other _Table_ instances within the system. Each Table maintains reference of the _DB_ it belongs to.
+
+Similar structure exists within the _hive_ data model.
+
+Example: To retrieve all the instances of the _Table_ belonging to a database named 'Sales':
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`Table where db.name = "Sales"`}
+</SyntaxHighlighter>
+
+Example: To retrieve all the instances of the _Table_ belonging to a database named 'Sales' and whose column name starts with 'customer':
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`Table where db.name = "Sales" and columns.name like "customer*"`}
+</SyntaxHighlighter>
+
+The entity Column is modeled in a similar way. Each Table entity has outward edges pointing to Column entity instances corresponding to each column within the table.
+
+Example: To retrieve all the Column entities for a given Table.
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`Table where name = "time_dim" select columns`}
+</SyntaxHighlighter>
+
+The properties of each _Column_ entity type are displayed.
+
+#### Glossary Term-based Filtering
+In order to retrieve entities based on glossary term, a query would use _hasTerm_ keyword.
+
+To search for entities having a particular glossary term, user needs to add a fully qualified name. i.e _{termName}@{glossaryName}_. In case the user adds only the term name, all the entities with particular term name will be returned, irrespective of which glossary it is in.
+
+Example: To retrieve all entities of type _Table_ having glossary term _savingsAccount@Banking_, below are the possible ways.
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`from Table hasTerm "savingsAccount@Banking"
+Table hasTerm "savingsAccount@Banking"
+Table hasTerm "savingsAccount"
+Table where Table hasTerm "savingsAccount@Banking"`}
+</SyntaxHighlighter>
+
+Example: To retrieve all entities of type _Table_ having glossary term _savingsAccount@Banking_ and whose name is 'customer'.
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`from Table hasTerm "savingsAccount@Banking" and name = "customer"`}
+</SyntaxHighlighter>
+
+Example: To retrieve all entities of type _Table_ having glossary term _savingsAccount@Banking_ or tagged with 'Dimension' classification and whose column name starts with 'customer'.
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`from Table hasTerm "savingsAccount@Banking" or Table isA Dimension and (columns.name like "customer*")`}
+</SyntaxHighlighter>
+
 ### Limit & Offset Clauses
 Often a query yields large number of results. To limit the outcome of the query, the limit and offset clauses are used.
 
@@ -268,6 +324,12 @@ Example: Same results as above except that they are sorted in descending order.
 {`from Column orderby name desc`}
 </SyntaxHighlighter>
 
+Example: To retrieve the entities of type _Column_ filtered with name and associated with 'savingsAccount@Banking' glossary term, that are sorted in ascending order using the name property.
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`from Column hasTerm "savingsAccount@Banking" and name = "customer_id" orderby name asc`}
+</SyntaxHighlighter>
+
 ### Aggregate Functions
 Let's look at aggregate functions:
 
@@ -300,6 +362,13 @@ Example: To find the number of tables in a database.
 {`Table where db.name = "Reporting" select count()`}
 </SyntaxHighlighter>
 
+Example: To find the number of terms associated with particular type 'Table'.
+
+<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
+{`Table hasTerm "savingsAccount@Banking" select count() as terms`}
+</SyntaxHighlighter>
+
+
 ### The max Keyword
 Using this keyword it is possible to retrieve the maximum value of a property for an entity.
 
@@ -347,29 +416,6 @@ Example: To know the number of entities owned by each owner.
 {`Table groupby(owner) select owner, count()`}
 </SyntaxHighlighter>
 
-### Where Clause With Complex Types
-In the discussion so far we looked at where clauses with primitive types. This section will look at using properties that are non-primitive types.
-
-In this model, the DB is modeled such that it is aware of all the Table it contains. Table on the other hand is aware of existence of the DB but is not aware of all the other _Table_ instances within the system. Each Table maintains reference of the _DB_ it belongs to.
-
-Similar structure exists within the _hive_ data model.
-
-Example: To retrieve all the instances of the _Table_ belonging to a database named 'Sales':
-
-<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
-{`Table where db.name = "Sales"`}
-</SyntaxHighlighter>
-
-The entity Column is modeled in a similar way. Each Table entity has outward edges pointing to Column entity instances corresponding to each column within the table.
-
-Example: To retrieve all the Column entities for a given Table.
-
-<SyntaxHighlighter wrapLines={true} language="html" style={theme.dark}>
-{`Table where name = "time_dim" select columns`}
-</SyntaxHighlighter>
-
-The propeties of each _Column_ entity type are displayed.
-
 ### Using System Attributes
 Each type defined within Atlas gets few attributes by default. These attributes help with internal book keeping of the entities. All the system attributes are prefixed with '__' (double underscore). This helps in identifying them from other attributes.
 Following are the system attributes:
diff --git a/repository/src/main/java/org/apache/atlas/discovery/TermSearchProcessor.java b/repository/src/main/java/org/apache/atlas/discovery/TermSearchProcessor.java
index 6c48a82..d9db9bf 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/TermSearchProcessor.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/TermSearchProcessor.java
@@ -35,6 +35,7 @@ public class TermSearchProcessor extends SearchProcessor {
     public static final String ATLAS_GLOSSARY_TERM_ENTITY_TYPE            = "AtlasGlossaryTerm";
     public static final String ATLAS_GLOSSARY_TERM_ATTR_QNAME             = "qualifiedName";
     public static final String ATLAS_GLOSSARY_TERM_ATTR_ASSIGNED_ENTITIES = "assignedEntities";
+    public static final String ATLAS_GLOSSARY_TERM_ATTR_MEANINGS          = "meanings";
 
     final List<AtlasVertex> assignedEntities;
 
diff --git a/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java b/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
index 700da95..ca0b4be 100644
--- a/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
+++ b/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
@@ -24,7 +24,10 @@ import org.apache.commons.collections.CollectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
 
 public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
     private static final Logger LOG = LoggerFactory.getLogger(DSLVisitor.class);
@@ -188,6 +191,16 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
         super.visitHasClause(ctx);
     }
 
+    private void visitHasTermClause(GremlinQueryComposer gqc, HasTermClauseContext ctx) {
+        if (ctx.expr() != null) {
+            processExpr(ctx.expr(), gqc);
+        } else if (ctx.identifier() != null) {
+            gqc.addHasTerm(ctx.arithE().getText(), ctx.identifier().getText());
+        }
+        super.visitHasTermClause(ctx);
+    }
+
+
     private void inferFromClause(SingleQrySrcContext ctx) {
         if (ctx.fromExpression() != null) {
             return;
@@ -205,13 +218,30 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
         if (ctx.expr().compE() != null && ctx.expr().compE().hasClause() != null && ctx.expr().compE().hasClause().arithE() != null) {
             gremlinQueryComposer.addFrom(ctx.expr().compE().hasClause().arithE().getText());
         }
+
+        if (ctx.expr().compE() != null && ctx.expr().compE().hasTermClause() != null && ctx.expr().compE().hasTermClause().arithE() != null) {
+            gremlinQueryComposer.addFrom(ctx.expr().compE().hasTermClause().arithE().getText());
+            return;
+        }
     }
 
     private void processExpr(final ExprContext expr, GremlinQueryComposer gremlinQueryComposer) {
         if (CollectionUtils.isNotEmpty(expr.exprRight())) {
             processExprRight(expr, gremlinQueryComposer);
         } else {
-            processExpr(expr.compE(), gremlinQueryComposer);
+            GremlinQueryComposer nestedProcessor = gremlinQueryComposer.createNestedProcessor();
+            processExpr(expr.compE(), nestedProcessor);
+
+            GremlinClauseList gcl = nestedProcessor.getQueryClauses();
+            if (gcl.size() > 1) {
+                if (nestedProcessor.isPrimitive()) {
+                    nestedProcessor.remove(GremlinClause.NESTED_START);
+                    GremlinQueryComposer.GremlinClauseValue gv = gcl.get(0);
+                    gremlinQueryComposer.add(gv);
+                } else {
+                    gremlinQueryComposer.addAndClauses(Collections.singletonList(nestedProcessor.get()));
+                }
+            }
         }
     }
 
@@ -277,7 +307,7 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
     }
 
     private void processExpr(final CompEContext compE, final GremlinQueryComposer gremlinQueryComposer) {
-        if (compE != null && compE.isClause() == null && compE.hasClause() == null) {
+        if (compE != null && compE.isClause() == null && compE.hasClause() == null && compE.hasTermClause() == null) {
             ComparisonClauseContext comparisonClause = compE.comparisonClause();
 
             // The nested expression might have ANDs/ORs
@@ -315,6 +345,10 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
         if (compE != null && compE.hasClause() != null) {
             visitHasClause(gremlinQueryComposer, compE.hasClause());
         }
+
+        if (compE != null && compE.hasTermClause() != null) {
+            visitHasTermClause(gremlinQueryComposer, compE.hasTermClause());
+        }
     }
 
     private String getInClause(AtomEContext atomEContext) {
diff --git a/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java b/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
index 36b514e..87c8bd2 100644
--- a/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
+++ b/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
@@ -19,7 +19,9 @@ package org.apache.atlas.query;
 
 import com.google.common.annotations.VisibleForTesting;
 import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.discovery.TermSearchProcessor;
 import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.glossary.GlossaryUtils;
 import org.apache.atlas.model.TypeCategory;
 import org.apache.atlas.model.discovery.SearchParameters;
 import org.apache.atlas.model.typedef.AtlasStructDef;
@@ -28,7 +30,6 @@ import org.apache.atlas.type.AtlasEntityType;
 import org.apache.atlas.type.AtlasStructType;
 import org.apache.atlas.type.AtlasType;
 import org.apache.atlas.type.AtlasTypeRegistry;
-import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,7 +51,6 @@ import java.util.stream.Stream;
 
 import static org.apache.atlas.model.discovery.SearchParameters.ALL_CLASSIFICATIONS;
 import static org.apache.atlas.model.discovery.SearchParameters.NO_CLASSIFICATIONS;
-import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.IN;
 import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.OUT;
 
 public class GremlinQueryComposer {
@@ -80,6 +80,7 @@ public class GremlinQueryComposer {
     private int providedLimit  = DEFAULT_QUERY_RESULT_LIMIT;
     private int providedOffset = DEFAULT_QUERY_RESULT_OFFSET;
     private Context context;
+    private boolean isPrimitive = true;
 
     public GremlinQueryComposer(Lookup registryLookup, final AtlasDSL.QueryMetadata qmd, boolean isNestedQuery) {
         this.isNestedQuery = isNestedQuery;
@@ -170,6 +171,32 @@ public class GremlinQueryComposer {
         }
     }
 
+    public void addHasTerm(String typeName, String termName) {
+        if (!isNestedQuery) {
+            addFrom(typeName);
+        }
+
+        String qualifiedAttributeName      = GlossaryUtils.QUALIFIED_NAME_ATTR;
+        String qualifiedAttributeSeperator = String.valueOf(GlossaryUtils.invalidNameChars[0]);
+        String name                        = GlossaryUtils.NAME;
+        String operator                    = SearchParameters.Operator.EQ.toString();
+        String attributeToSearch;
+        String[] terms                     = termName.split(qualifiedAttributeSeperator);
+
+        if (terms.length > 1) {
+            attributeToSearch = TermSearchProcessor.ATLAS_GLOSSARY_TERM_ATTR_MEANINGS + GlossaryUtils.invalidNameChars[1] + qualifiedAttributeName;
+        } else {
+            termName = terms[0];
+            attributeToSearch = TermSearchProcessor.ATLAS_GLOSSARY_TERM_ATTR_MEANINGS + GlossaryUtils.invalidNameChars[1] + name;
+        }
+
+        addWhere(attributeToSearch, operator , termName);
+    }
+
+    public boolean isPrimitive(){
+        return isPrimitive;
+    }
+
     public void addWhere(String lhs, String operator, String rhs) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("addWhere(lhs={}, operator={}, rhs={})", lhs, operator, rhs);
@@ -184,6 +211,7 @@ public class GremlinQueryComposer {
             org = lhsI;
             lhsI = createInfo(lhs);
             lhsI.setTypeName(org.getTypeName());
+            isPrimitive = false;
         }
 
         if (!context.validator.isValidQualifiedName(lhsI.getQualifiedName(), lhsI.getRaw())) {
@@ -222,12 +250,6 @@ public class GremlinQueryComposer {
 
         if (org != null && org.isReferredType()) {
             add(GremlinClause.DEDUP);
-            if (org.getEdgeDirection() != null) {
-                GremlinClause gremlinClauseForEdgeLabel = org.getEdgeDirection().equals(IN) ? GremlinClause.OUT : GremlinClause.IN;
-                add(gremlinClauseForEdgeLabel, org.getEdgeLabel());
-            } else {
-                add(GremlinClause.OUT, org.getEdgeLabel());
-            }
             context.registerActive(currentType);
         }
     }
@@ -584,6 +606,19 @@ public class GremlinQueryComposer {
         queryClauses.add(gcv);
     }
 
+    public void remove(GremlinClause clause) {
+        int index = queryClauses.contains(clause);
+        if (-1 == index) {
+            return;
+        }
+
+        queryClauses.remove(index);
+    }
+
+    public GremlinClauseList getQueryClauses(){
+        return queryClauses;
+    }
+
     private void init() {
         if (!isNestedQuery) {
             add(GremlinClause.G);
@@ -652,6 +687,10 @@ public class GremlinQueryComposer {
         queryClauses.add(new GremlinClauseValue(clause, clause.get(args)));
     }
 
+    public void add(GremlinClauseValue gv) {
+        queryClauses.add(gv);
+    }
+
     private void add(int idx, GremlinClause clause, String... args) {
         queryClauses.add(idx, new GremlinClauseValue(clause, clause.get(args)));
     }
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.g4 b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.g4
index 15d1bb4..0240b13 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.g4
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.g4
@@ -139,6 +139,8 @@ K_TRUE: T R U E ;
 
 K_FALSE: F A L S E ;
 
+K_HASTERM: H A S T E R M;
+
 KEYWORD: K_LIKE
         | K_DOT
         | K_SELECT
@@ -162,6 +164,7 @@ KEYWORD: K_LIKE
         | K_DESC
         | K_ASC
         | K_COUNT
+        | K_HASTERM
         ;
 
 ID: STRING
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java
index 142b9ca..4091fe9 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java
@@ -1,6 +1,6 @@
 package org.apache.atlas.query.antlr4;
-import org.antlr.v4.runtime.CharStream;
 import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.CharStream;
 import org.antlr.v4.runtime.RuntimeMetaData;
 import org.antlr.v4.runtime.Vocabulary;
 import org.antlr.v4.runtime.VocabularyImpl;
@@ -12,7 +12,7 @@ import org.antlr.v4.runtime.dfa.DFA;
 
 @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
 public class AtlasDSLLexer extends Lexer {
-	static { RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); }
+	static { RuntimeMetaData.checkVersion("4.7.2", RuntimeMetaData.VERSION); }
 
 	protected static final DFA[] _decisionToDFA;
 	protected static final PredictionContextCache _sharedContextCache =
@@ -24,8 +24,8 @@ public class AtlasDSLLexer extends Lexer {
 		K_RBRACKET=19, K_LT=20, K_LTE=21, K_EQ=22, K_NEQ=23, K_GT=24, K_GTE=25, 
 		K_FROM=26, K_WHERE=27, K_ORDERBY=28, K_GROUPBY=29, K_LIMIT=30, K_SELECT=31, 
 		K_MAX=32, K_MIN=33, K_SUM=34, K_COUNT=35, K_OFFSET=36, K_AS=37, K_ISA=38, 
-		K_IS=39, K_HAS=40, K_ASC=41, K_DESC=42, K_TRUE=43, K_FALSE=44, KEYWORD=45, 
-		ID=46, STRING=47;
+		K_IS=39, K_HAS=40, K_ASC=41, K_DESC=42, K_TRUE=43, K_FALSE=44, K_HASTERM=45,
+		KEYWORD=46, ID=47, STRING=48;
 	public static String[] channelNames = {
 		"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
 	};
@@ -34,31 +34,41 @@ public class AtlasDSLLexer extends Lexer {
 		"DEFAULT_MODE"
 	};
 
-	public static final String[] ruleNames = {
-		"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
-		"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "DIGIT", "LETTER", 
-		"SINGLE_LINE_COMMENT", "MULTILINE_COMMENT", "WS", "NUMBER", "FLOATING_NUMBER", 
-		"BOOL", "K_COMMA", "K_PLUS", "K_MINUS", "K_STAR", "K_DIV", "K_DOT", "K_LIKE", 
-		"K_AND", "K_OR", "K_LPAREN", "K_LBRACKET", "K_RPAREN", "K_RBRACKET", "K_LT", 
-		"K_LTE", "K_EQ", "K_NEQ", "K_GT", "K_GTE", "K_FROM", "K_WHERE", "K_ORDERBY", 
-		"K_GROUPBY", "K_LIMIT", "K_SELECT", "K_MAX", "K_MIN", "K_SUM", "K_COUNT", 
-		"K_OFFSET", "K_AS", "K_ISA", "K_IS", "K_HAS", "K_ASC", "K_DESC", "K_TRUE", 
-		"K_FALSE", "KEYWORD", "ID", "STRING"
-	};
+	private static String[] makeRuleNames() {
+		return new String[] {
+			"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
+			"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "DIGIT",
+			"LETTER", "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT", "WS", "NUMBER",
+			"FLOATING_NUMBER", "BOOL", "K_COMMA", "K_PLUS", "K_MINUS", "K_STAR",
+			"K_DIV", "K_DOT", "K_LIKE", "K_AND", "K_OR", "K_LPAREN", "K_LBRACKET",
+			"K_RPAREN", "K_RBRACKET", "K_LT", "K_LTE", "K_EQ", "K_NEQ", "K_GT", "K_GTE",
+			"K_FROM", "K_WHERE", "K_ORDERBY", "K_GROUPBY", "K_LIMIT", "K_SELECT",
+			"K_MAX", "K_MIN", "K_SUM", "K_COUNT", "K_OFFSET", "K_AS", "K_ISA", "K_IS",
+			"K_HAS", "K_ASC", "K_DESC", "K_TRUE", "K_FALSE", "K_HASTERM", "KEYWORD",
+			"ID", "STRING"
+		};
+	}
+	public static final String[] ruleNames = makeRuleNames();
 
-	private static final String[] _LITERAL_NAMES = {
-		null, null, null, null, null, null, null, "','", "'+'", "'-'", "'*'", 
-		"'/'", "'.'", null, null, null, "'('", "'['", "')'", "']'"
-	};
-	private static final String[] _SYMBOLIC_NAMES = {
-		null, "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT", "WS", "NUMBER", "FLOATING_NUMBER", 
-		"BOOL", "K_COMMA", "K_PLUS", "K_MINUS", "K_STAR", "K_DIV", "K_DOT", "K_LIKE", 
-		"K_AND", "K_OR", "K_LPAREN", "K_LBRACKET", "K_RPAREN", "K_RBRACKET", "K_LT", 
-		"K_LTE", "K_EQ", "K_NEQ", "K_GT", "K_GTE", "K_FROM", "K_WHERE", "K_ORDERBY", 
-		"K_GROUPBY", "K_LIMIT", "K_SELECT", "K_MAX", "K_MIN", "K_SUM", "K_COUNT", 
-		"K_OFFSET", "K_AS", "K_ISA", "K_IS", "K_HAS", "K_ASC", "K_DESC", "K_TRUE", 
-		"K_FALSE", "KEYWORD", "ID", "STRING"
-	};
+	private static String[] makeLiteralNames() {
+		return new String[] {
+			null, null, null, null, null, null, null, "','", "'+'", "'-'", "'*'",
+			"'/'", "'.'", null, null, null, "'('", "'['", "')'", "']'"
+		};
+	}
+	private static final String[] _LITERAL_NAMES = makeLiteralNames();
+	private static String[] makeSymbolicNames() {
+		return new String[] {
+			null, "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT", "WS", "NUMBER", "FLOATING_NUMBER",
+			"BOOL", "K_COMMA", "K_PLUS", "K_MINUS", "K_STAR", "K_DIV", "K_DOT", "K_LIKE",
+			"K_AND", "K_OR", "K_LPAREN", "K_LBRACKET", "K_RPAREN", "K_RBRACKET",
+			"K_LT", "K_LTE", "K_EQ", "K_NEQ", "K_GT", "K_GTE", "K_FROM", "K_WHERE",
+			"K_ORDERBY", "K_GROUPBY", "K_LIMIT", "K_SELECT", "K_MAX", "K_MIN", "K_SUM",
+			"K_COUNT", "K_OFFSET", "K_AS", "K_ISA", "K_IS", "K_HAS", "K_ASC", "K_DESC",
+			"K_TRUE", "K_FALSE", "K_HASTERM", "KEYWORD", "ID", "STRING"
+		};
+	}
+	private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
 	public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
 
 	/**
@@ -117,7 +127,7 @@ public class AtlasDSLLexer extends Lexer {
 	public ATN getATN() { return _ATN; }
 
 	public static final String _serializedATN =
-		"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\61\u0256\b\1\4\2"+
+		"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\62\u0261\b\1\4\2"+
 		"\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+
 		"\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+
 		"\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+
@@ -126,217 +136,221 @@ public class AtlasDSLLexer extends Lexer {
 		"+\4,\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64"+
 		"\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t"+
 		"=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4"+
-		"I\tI\4J\tJ\4K\tK\4L\tL\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3\7"+
-		"\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\17\3\17"+
-		"\3\20\3\20\3\21\3\21\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3\25\3\26\3\26"+
-		"\3\27\3\27\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3\33\3\34\3\34\3\35\3\35"+
-		"\3\36\3\36\3\36\3\36\7\36\u00d6\n\36\f\36\16\36\u00d9\13\36\3\36\3\36"+
-		"\3\37\3\37\3\37\3\37\7\37\u00e1\n\37\f\37\16\37\u00e4\13\37\3\37\3\37"+
-		"\3\37\5\37\u00e9\n\37\3\37\3\37\3 \3 \7 \u00ef\n \f \16 \u00f2\13 \3 "+
-		"\6 \u00f5\n \r \16 \u00f6\5 \u00f9\n \3 \3 \3!\3!\5!\u00ff\n!\3!\3!\7"+
-		"!\u0103\n!\f!\16!\u0106\13!\3!\3!\3!\5!\u010b\n!\3!\3!\7!\u010f\n!\f!"+
-		"\16!\u0112\13!\5!\u0114\n!\3\"\3\"\5\"\u0118\n\"\3\"\6\"\u011b\n\"\r\""+
-		"\16\"\u011c\3\"\3\"\6\"\u0121\n\"\r\"\16\"\u0122\3\"\3\"\3\"\5\"\u0128"+
-		"\n\"\3\"\3\"\7\"\u012c\n\"\f\"\16\"\u012f\13\"\5\"\u0131\n\"\3#\3#\5#"+
-		"\u0135\n#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3*\3*\3*\3+\3+\3"+
-		"+\3+\3,\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\61\3\61\5\61\u015b"+
-		"\n\61\3\62\3\62\3\62\3\62\3\62\3\62\5\62\u0163\n\62\3\63\3\63\3\63\3\63"+
-		"\5\63\u0169\n\63\3\64\3\64\3\64\3\64\3\64\3\64\5\64\u0171\n\64\3\65\3"+
-		"\65\3\65\3\65\5\65\u0177\n\65\3\66\3\66\3\66\3\66\3\66\3\66\5\66\u017f"+
+		"I\tI\4J\tJ\4K\tK\4L\tL\4M\tM\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3"+
+		"\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\17"+
+		"\3\17\3\20\3\20\3\21\3\21\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3\25\3\26"+
+		"\3\26\3\27\3\27\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3\33\3\34\3\34\3\35"+
+		"\3\35\3\36\3\36\3\36\3\36\7\36\u00d8\n\36\f\36\16\36\u00db\13\36\3\36"+
+		"\3\36\3\37\3\37\3\37\3\37\7\37\u00e3\n\37\f\37\16\37\u00e6\13\37\3\37"+
+		"\3\37\3\37\5\37\u00eb\n\37\3\37\3\37\3 \3 \7 \u00f1\n \f \16 \u00f4\13"+
+		" \3 \6 \u00f7\n \r \16 \u00f8\5 \u00fb\n \3 \3 \3!\3!\5!\u0101\n!\3!\3"+
+		"!\7!\u0105\n!\f!\16!\u0108\13!\3!\3!\3!\5!\u010d\n!\3!\3!\7!\u0111\n!"+
+		"\f!\16!\u0114\13!\5!\u0116\n!\3\"\3\"\5\"\u011a\n\"\3\"\6\"\u011d\n\""+
+		"\r\"\16\"\u011e\3\"\3\"\6\"\u0123\n\"\r\"\16\"\u0124\3\"\3\"\3\"\5\"\u012a"+
+		"\n\"\3\"\3\"\7\"\u012e\n\"\f\"\16\"\u0131\13\"\5\"\u0133\n\"\3#\3#\5#"+
+		"\u0137\n#\3$\3$\3%\3%\3&\3&\3\'\3\'\3(\3(\3)\3)\3*\3*\3*\3*\3*\3+\3+\3"+
+		"+\3+\3,\3,\3,\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\61\3\61\5\61\u015d"+
+		"\n\61\3\62\3\62\3\62\3\62\3\62\3\62\5\62\u0165\n\62\3\63\3\63\3\63\3\63"+
+		"\5\63\u016b\n\63\3\64\3\64\3\64\3\64\3\64\3\64\5\64\u0173\n\64\3\65\3"+
+		"\65\3\65\3\65\5\65\u0179\n\65\3\66\3\66\3\66\3\66\3\66\3\66\5\66\u0181"+
 		"\n\66\3\67\3\67\3\67\3\67\3\67\38\38\38\38\38\38\39\39\39\39\39\39\39"+
 		"\39\3:\3:\3:\3:\3:\3:\3:\3:\3;\3;\3;\3;\3;\3;\3<\3<\3<\3<\3<\3<\3<\3="+
 		"\3=\3=\3=\3>\3>\3>\3>\3?\3?\3?\3?\3@\3@\3@\3@\3@\3@\3A\3A\3A\3A\3A\3A"+
 		"\3A\3B\3B\3B\3C\3C\3C\3C\3D\3D\3D\3E\3E\3E\3E\3F\3F\3F\3F\3G\3G\3G\3G"+
-		"\3G\3H\3H\3H\3H\3H\3I\3I\3I\3I\3I\3I\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J"+
-		"\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\3J\5J\u01fb\nJ\3K\3K\3K\3K\7K\u0201"+
-		"\nK\fK\16K\u0204\13K\3K\3K\3K\7K\u0209\nK\fK\16K\u020c\13K\3K\3K\7K\u0210"+
-		"\nK\fK\16K\u0213\13K\3K\3K\7K\u0217\nK\fK\16K\u021a\13K\3K\3K\3K\7K\u021f"+
-		"\nK\fK\16K\u0222\13K\3K\3K\3K\7K\u0227\nK\fK\16K\u022a\13K\3K\3K\7K\u022e"+
-		"\nK\fK\16K\u0231\13K\3K\3K\3K\7K\u0236\nK\fK\16K\u0239\13K\5K\u023b\n"+
-		"K\3L\3L\7L\u023f\nL\fL\16L\u0242\13L\3L\3L\3L\7L\u0247\nL\fL\16L\u024a"+
-		"\13L\3L\3L\3L\7L\u024f\nL\fL\16L\u0252\13L\3L\5L\u0255\nL\3\u00e2\2M\3"+
-		"\2\5\2\7\2\t\2\13\2\r\2\17\2\21\2\23\2\25\2\27\2\31\2\33\2\35\2\37\2!"+
-		"\2#\2%\2\'\2)\2+\2-\2/\2\61\2\63\2\65\2\67\29\2;\3=\4?\5A\6C\7E\bG\tI"+
-		"\nK\13M\fO\rQ\16S\17U\20W\21Y\22[\23]\24_\25a\26c\27e\30g\31i\32k\33m"+
-		"\34o\35q\36s\37u w!y\"{#}$\177%\u0081&\u0083\'\u0085(\u0087)\u0089*\u008b"+
-		"+\u008d,\u008f-\u0091.\u0093/\u0095\60\u0097\61\3\2#\4\2CCcc\4\2DDdd\4"+
-		"\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2IIii\4\2JJjj\4\2KKkk\4\2LLll\4\2MMm"+
-		"m\4\2NNnn\4\2OOoo\4\2PPpp\4\2QQqq\4\2RRrr\4\2SSss\4\2TTtt\4\2UUuu\4\2"+
-		"VVvv\4\2WWww\4\2XXxx\4\2YYyy\4\2ZZzz\4\2[[{{\4\2\\\\||\3\2\62;\5\2C\\"+
-		"aac|\4\2\f\f\17\17\5\2\13\f\17\17\"\"\3\2$$\3\2))\3\2bb\2\u0281\2;\3\2"+
-		"\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2"+
-		"\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U"+
-		"\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2"+
-		"\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2"+
-		"\2o\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{"+
-		"\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085"+
-		"\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2"+
-		"\2\2\u008f\3\2\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097"+
-		"\3\2\2\2\3\u0099\3\2\2\2\5\u009b\3\2\2\2\7\u009d\3\2\2\2\t\u009f\3\2\2"+
-		"\2\13\u00a1\3\2\2\2\r\u00a3\3\2\2\2\17\u00a5\3\2\2\2\21\u00a7\3\2\2\2"+
-		"\23\u00a9\3\2\2\2\25\u00ab\3\2\2\2\27\u00ad\3\2\2\2\31\u00af\3\2\2\2\33"+
-		"\u00b1\3\2\2\2\35\u00b3\3\2\2\2\37\u00b5\3\2\2\2!\u00b7\3\2\2\2#\u00b9"+
-		"\3\2\2\2%\u00bb\3\2\2\2\'\u00bd\3\2\2\2)\u00bf\3\2\2\2+\u00c1\3\2\2\2"+
-		"-\u00c3\3\2\2\2/\u00c5\3\2\2\2\61\u00c7\3\2\2\2\63\u00c9\3\2\2\2\65\u00cb"+
-		"\3\2\2\2\67\u00cd\3\2\2\29\u00cf\3\2\2\2;\u00d1\3\2\2\2=\u00dc\3\2\2\2"+
-		"?\u00f8\3\2\2\2A\u00fe\3\2\2\2C\u0117\3\2\2\2E\u0134\3\2\2\2G\u0136\3"+
-		"\2\2\2I\u0138\3\2\2\2K\u013a\3\2\2\2M\u013c\3\2\2\2O\u013e\3\2\2\2Q\u0140"+
-		"\3\2\2\2S\u0142\3\2\2\2U\u0147\3\2\2\2W\u014b\3\2\2\2Y\u014e\3\2\2\2["+
-		"\u0150\3\2\2\2]\u0152\3\2\2\2_\u0154\3\2\2\2a\u015a\3\2\2\2c\u0162\3\2"+
-		"\2\2e\u0168\3\2\2\2g\u0170\3\2\2\2i\u0176\3\2\2\2k\u017e\3\2\2\2m\u0180"+
-		"\3\2\2\2o\u0185\3\2\2\2q\u018b\3\2\2\2s\u0193\3\2\2\2u\u019b\3\2\2\2w"+
-		"\u01a1\3\2\2\2y\u01a8\3\2\2\2{\u01ac\3\2\2\2}\u01b0\3\2\2\2\177\u01b4"+
-		"\3\2\2\2\u0081\u01ba\3\2\2\2\u0083\u01c1\3\2\2\2\u0085\u01c4\3\2\2\2\u0087"+
-		"\u01c8\3\2\2\2\u0089\u01cb\3\2\2\2\u008b\u01cf\3\2\2\2\u008d\u01d3\3\2"+
-		"\2\2\u008f\u01d8\3\2\2\2\u0091\u01dd\3\2\2\2\u0093\u01fa\3\2\2\2\u0095"+
-		"\u023a\3\2\2\2\u0097\u0254\3\2\2\2\u0099\u009a\t\2\2\2\u009a\4\3\2\2\2"+
-		"\u009b\u009c\t\3\2\2\u009c\6\3\2\2\2\u009d\u009e\t\4\2\2\u009e\b\3\2\2"+
-		"\2\u009f\u00a0\t\5\2\2\u00a0\n\3\2\2\2\u00a1\u00a2\t\6\2\2\u00a2\f\3\2"+
-		"\2\2\u00a3\u00a4\t\7\2\2\u00a4\16\3\2\2\2\u00a5\u00a6\t\b\2\2\u00a6\20"+
-		"\3\2\2\2\u00a7\u00a8\t\t\2\2\u00a8\22\3\2\2\2\u00a9\u00aa\t\n\2\2\u00aa"+
-		"\24\3\2\2\2\u00ab\u00ac\t\13\2\2\u00ac\26\3\2\2\2\u00ad\u00ae\t\f\2\2"+
-		"\u00ae\30\3\2\2\2\u00af\u00b0\t\r\2\2\u00b0\32\3\2\2\2\u00b1\u00b2\t\16"+
-		"\2\2\u00b2\34\3\2\2\2\u00b3\u00b4\t\17\2\2\u00b4\36\3\2\2\2\u00b5\u00b6"+
-		"\t\20\2\2\u00b6 \3\2\2\2\u00b7\u00b8\t\21\2\2\u00b8\"\3\2\2\2\u00b9\u00ba"+
-		"\t\22\2\2\u00ba$\3\2\2\2\u00bb\u00bc\t\23\2\2\u00bc&\3\2\2\2\u00bd\u00be"+
-		"\t\24\2\2\u00be(\3\2\2\2\u00bf\u00c0\t\25\2\2\u00c0*\3\2\2\2\u00c1\u00c2"+
-		"\t\26\2\2\u00c2,\3\2\2\2\u00c3\u00c4\t\27\2\2\u00c4.\3\2\2\2\u00c5\u00c6"+
-		"\t\30\2\2\u00c6\60\3\2\2\2\u00c7\u00c8\t\31\2\2\u00c8\62\3\2\2\2\u00c9"+
-		"\u00ca\t\32\2\2\u00ca\64\3\2\2\2\u00cb\u00cc\t\33\2\2\u00cc\66\3\2\2\2"+
-		"\u00cd\u00ce\t\34\2\2\u00ce8\3\2\2\2\u00cf\u00d0\t\35\2\2\u00d0:\3\2\2"+
-		"\2\u00d1\u00d2\7/\2\2\u00d2\u00d3\7/\2\2\u00d3\u00d7\3\2\2\2\u00d4\u00d6"+
-		"\n\36\2\2\u00d5\u00d4\3\2\2\2\u00d6\u00d9\3\2\2\2\u00d7\u00d5\3\2\2\2"+
-		"\u00d7\u00d8\3\2\2\2\u00d8\u00da\3\2\2\2\u00d9\u00d7\3\2\2\2\u00da\u00db"+
-		"\b\36\2\2\u00db<\3\2\2\2\u00dc\u00dd\7\61\2\2\u00dd\u00de\7,\2\2\u00de"+
-		"\u00e2\3\2\2\2\u00df\u00e1\13\2\2\2\u00e0\u00df\3\2\2\2\u00e1\u00e4\3"+
-		"\2\2\2\u00e2\u00e3\3\2\2\2\u00e2\u00e0\3\2\2\2\u00e3\u00e8\3\2\2\2\u00e4"+
-		"\u00e2\3\2\2\2\u00e5\u00e6\7,\2\2\u00e6\u00e9\7\61\2\2\u00e7\u00e9\7\2"+
-		"\2\3\u00e8\u00e5\3\2\2\2\u00e8\u00e7\3\2\2\2\u00e9\u00ea\3\2\2\2\u00ea"+
-		"\u00eb\b\37\2\2\u00eb>\3\2\2\2\u00ec\u00f0\7\"\2\2\u00ed\u00ef\7\"\2\2"+
-		"\u00ee\u00ed\3\2\2\2\u00ef\u00f2\3\2\2\2\u00f0\u00ee\3\2\2\2\u00f0\u00f1"+
-		"\3\2\2\2\u00f1\u00f9\3\2\2\2\u00f2\u00f0\3\2\2\2\u00f3\u00f5\t\37\2\2"+
-		"\u00f4\u00f3\3\2\2\2\u00f5\u00f6\3\2\2\2\u00f6\u00f4\3\2\2\2\u00f6\u00f7"+
-		"\3\2\2\2\u00f7\u00f9\3\2\2\2\u00f8\u00ec\3\2\2\2\u00f8\u00f4\3\2\2\2\u00f9"+
-		"\u00fa\3\2\2\2\u00fa\u00fb\b \2\2\u00fb@\3\2\2\2\u00fc\u00ff\5I%\2\u00fd"+
-		"\u00ff\5K&\2\u00fe\u00fc\3\2\2\2\u00fe\u00fd\3\2\2\2\u00fe\u00ff\3\2\2"+
-		"\2\u00ff\u0100\3\2\2\2\u0100\u0104\5\67\34\2\u0101\u0103\5\67\34\2\u0102"+
-		"\u0101\3\2\2\2\u0103\u0106\3\2\2\2\u0104\u0102\3\2\2\2\u0104\u0105\3\2"+
-		"\2\2\u0105\u0113\3\2\2\2\u0106\u0104\3\2\2\2\u0107\u010a\5\13\6\2\u0108"+
-		"\u010b\5I%\2\u0109\u010b\5K&\2\u010a\u0108\3\2\2\2\u010a\u0109\3\2\2\2"+
-		"\u010a\u010b\3\2\2\2\u010b\u010c\3\2\2\2\u010c\u0110\5\67\34\2\u010d\u010f"+
-		"\5\67\34\2\u010e\u010d\3\2\2\2\u010f\u0112\3\2\2\2\u0110\u010e\3\2\2\2"+
-		"\u0110\u0111\3\2\2\2\u0111\u0114\3\2\2\2\u0112\u0110\3\2\2\2\u0113\u0107"+
-		"\3\2\2\2\u0113\u0114\3\2\2\2\u0114B\3\2\2\2\u0115\u0118\5I%\2\u0116\u0118"+
-		"\5K&\2\u0117\u0115\3\2\2\2\u0117\u0116\3\2\2\2\u0117\u0118\3\2\2\2\u0118"+
-		"\u011a\3\2\2\2\u0119\u011b\5\67\34\2\u011a\u0119\3\2\2\2\u011b\u011c\3"+
-		"\2\2\2\u011c\u011a\3\2\2\2\u011c\u011d\3\2\2\2\u011d\u011e\3\2\2\2\u011e"+
-		"\u0120\5Q)\2\u011f\u0121\5\67\34\2\u0120\u011f\3\2\2\2\u0121\u0122\3\2"+
-		"\2\2\u0122\u0120\3\2\2\2\u0122\u0123\3\2\2\2\u0123\u0130\3\2\2\2\u0124"+
-		"\u0127\5\13\6\2\u0125\u0128\5I%\2\u0126\u0128\5K&\2\u0127\u0125\3\2\2"+
-		"\2\u0127\u0126\3\2\2\2\u0127\u0128\3\2\2\2\u0128\u0129\3\2\2\2\u0129\u012d"+
-		"\5\67\34\2\u012a\u012c\5\67\34\2\u012b\u012a\3\2\2\2\u012c\u012f\3\2\2"+
-		"\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2\2\2\u012e\u0131\3\2\2\2\u012f\u012d"+
-		"\3\2\2\2\u0130\u0124\3\2\2\2\u0130\u0131\3\2\2\2\u0131D\3\2\2\2\u0132"+
-		"\u0135\5\u008fH\2\u0133\u0135\5\u0091I\2\u0134\u0132\3\2\2\2\u0134\u0133"+
-		"\3\2\2\2\u0135F\3\2\2\2\u0136\u0137\7.\2\2\u0137H\3\2\2\2\u0138\u0139"+
-		"\7-\2\2\u0139J\3\2\2\2\u013a\u013b\7/\2\2\u013bL\3\2\2\2\u013c\u013d\7"+
-		",\2\2\u013dN\3\2\2\2\u013e\u013f\7\61\2\2\u013fP\3\2\2\2\u0140\u0141\7"+
-		"\60\2\2\u0141R\3\2\2\2\u0142\u0143\5\31\r\2\u0143\u0144\5\23\n\2\u0144"+
-		"\u0145\5\27\f\2\u0145\u0146\5\13\6\2\u0146T\3\2\2\2\u0147\u0148\5\3\2"+
-		"\2\u0148\u0149\5\35\17\2\u0149\u014a\5\t\5\2\u014aV\3\2\2\2\u014b\u014c"+
-		"\5\37\20\2\u014c\u014d\5%\23\2\u014dX\3\2\2\2\u014e\u014f\7*\2\2\u014f"+
-		"Z\3\2\2\2\u0150\u0151\7]\2\2\u0151\\\3\2\2\2\u0152\u0153\7+\2\2\u0153"+
-		"^\3\2\2\2\u0154\u0155\7_\2\2\u0155`\3\2\2\2\u0156\u015b\7>\2\2\u0157\u0158"+
-		"\5\31\r\2\u0158\u0159\5)\25\2\u0159\u015b\3\2\2\2\u015a\u0156\3\2\2\2"+
-		"\u015a\u0157\3\2\2\2\u015bb\3\2\2\2\u015c\u015d\7>\2\2\u015d\u0163\7?"+
-		"\2\2\u015e\u015f\5\31\r\2\u015f\u0160\5)\25\2\u0160\u0161\5\13\6\2\u0161"+
-		"\u0163\3\2\2\2\u0162\u015c\3\2\2\2\u0162\u015e\3\2\2\2\u0163d\3\2\2\2"+
-		"\u0164\u0169\7?\2\2\u0165\u0166\5\13\6\2\u0166\u0167\5#\22\2\u0167\u0169"+
-		"\3\2\2\2\u0168\u0164\3\2\2\2\u0168\u0165\3\2\2\2\u0169f\3\2\2\2\u016a"+
-		"\u016b\7#\2\2\u016b\u0171\7?\2\2\u016c\u016d\5\35\17\2\u016d\u016e\5\13"+
-		"\6\2\u016e\u016f\5#\22\2\u016f\u0171\3\2\2\2\u0170\u016a\3\2\2\2\u0170"+
-		"\u016c\3\2\2\2\u0171h\3\2\2\2\u0172\u0177\7@\2\2\u0173\u0174\5\17\b\2"+
-		"\u0174\u0175\5)\25\2\u0175\u0177\3\2\2\2\u0176\u0172\3\2\2\2\u0176\u0173"+
-		"\3\2\2\2\u0177j\3\2\2\2\u0178\u0179\7@\2\2\u0179\u017f\7?\2\2\u017a\u017b"+
-		"\5\17\b\2\u017b\u017c\5)\25\2\u017c\u017d\5\13\6\2\u017d\u017f\3\2\2\2"+
-		"\u017e\u0178\3\2\2\2\u017e\u017a\3\2\2\2\u017fl\3\2\2\2\u0180\u0181\5"+
-		"\r\7\2\u0181\u0182\5%\23\2\u0182\u0183\5\37\20\2\u0183\u0184\5\33\16\2"+
-		"\u0184n\3\2\2\2\u0185\u0186\5/\30\2\u0186\u0187\5\21\t\2\u0187\u0188\5"+
-		"\13\6\2\u0188\u0189\5%\23\2\u0189\u018a\5\13\6\2\u018ap\3\2\2\2\u018b"+
-		"\u018c\5\37\20\2\u018c\u018d\5%\23\2\u018d\u018e\5\t\5\2\u018e\u018f\5"+
-		"\13\6\2\u018f\u0190\5%\23\2\u0190\u0191\5\5\3\2\u0191\u0192\5\63\32\2"+
-		"\u0192r\3\2\2\2\u0193\u0194\5\17\b\2\u0194\u0195\5%\23\2\u0195\u0196\5"+
-		"\37\20\2\u0196\u0197\5+\26\2\u0197\u0198\5!\21\2\u0198\u0199\5\5\3\2\u0199"+
-		"\u019a\5\63\32\2\u019at\3\2\2\2\u019b\u019c\5\31\r\2\u019c\u019d\5\23"+
-		"\n\2\u019d\u019e\5\33\16\2\u019e\u019f\5\23\n\2\u019f\u01a0\5)\25\2\u01a0"+
-		"v\3\2\2\2\u01a1\u01a2\5\'\24\2\u01a2\u01a3\5\13\6\2\u01a3\u01a4\5\31\r"+
-		"\2\u01a4\u01a5\5\13\6\2\u01a5\u01a6\5\7\4\2\u01a6\u01a7\5)\25\2\u01a7"+
-		"x\3\2\2\2\u01a8\u01a9\5\33\16\2\u01a9\u01aa\5\3\2\2\u01aa\u01ab\5\61\31"+
-		"\2\u01abz\3\2\2\2\u01ac\u01ad\5\33\16\2\u01ad\u01ae\5\23\n\2\u01ae\u01af"+
-		"\5\35\17\2\u01af|\3\2\2\2\u01b0\u01b1\5\'\24\2\u01b1\u01b2\5+\26\2\u01b2"+
-		"\u01b3\5\33\16\2\u01b3~\3\2\2\2\u01b4\u01b5\5\7\4\2\u01b5\u01b6\5\37\20"+
-		"\2\u01b6\u01b7\5+\26\2\u01b7\u01b8\5\35\17\2\u01b8\u01b9\5)\25\2\u01b9"+
-		"\u0080\3\2\2\2\u01ba\u01bb\5\37\20\2\u01bb\u01bc\5\r\7\2\u01bc\u01bd\5"+
-		"\r\7\2\u01bd\u01be\5\'\24\2\u01be\u01bf\5\13\6\2\u01bf\u01c0\5)\25\2\u01c0"+
-		"\u0082\3\2\2\2\u01c1\u01c2\5\3\2\2\u01c2\u01c3\5\'\24\2\u01c3\u0084\3"+
-		"\2\2\2\u01c4\u01c5\5\23\n\2\u01c5\u01c6\5\'\24\2\u01c6\u01c7\5\3\2\2\u01c7"+
-		"\u0086\3\2\2\2\u01c8\u01c9\5\23\n\2\u01c9\u01ca\5\'\24\2\u01ca\u0088\3"+
-		"\2\2\2\u01cb\u01cc\5\21\t\2\u01cc\u01cd\5\3\2\2\u01cd\u01ce\5\'\24\2\u01ce"+
-		"\u008a\3\2\2\2\u01cf\u01d0\5\3\2\2\u01d0\u01d1\5\'\24\2\u01d1\u01d2\5"+
-		"\7\4\2\u01d2\u008c\3\2\2\2\u01d3\u01d4\5\t\5\2\u01d4\u01d5\5\13\6\2\u01d5"+
-		"\u01d6\5\'\24\2\u01d6\u01d7\5\7\4\2\u01d7\u008e\3\2\2\2\u01d8\u01d9\5"+
-		")\25\2\u01d9\u01da\5%\23\2\u01da\u01db\5+\26\2\u01db\u01dc\5\13\6\2\u01dc"+
-		"\u0090\3\2\2\2\u01dd\u01de\5\r\7\2\u01de\u01df\5\3\2\2\u01df\u01e0\5\31"+
-		"\r\2\u01e0\u01e1\5\'\24\2\u01e1\u01e2\5\13\6\2\u01e2\u0092\3\2\2\2\u01e3"+
-		"\u01fb\5S*\2\u01e4\u01fb\5Q)\2\u01e5\u01fb\5w<\2\u01e6\u01fb\5\u0083B"+
-		"\2\u01e7\u01fb\5\u0089E\2\u01e8\u01fb\5\u0087D\2\u01e9\u01fb\5\u0085C"+
-		"\2\u01ea\u01fb\5o8\2\u01eb\u01fb\5u;\2\u01ec\u01fb\5\u008fH\2\u01ed\u01fb"+
-		"\5\u0091I\2\u01ee\u01fb\5U+\2\u01ef\u01fb\5W,\2\u01f0\u01fb\5s:\2\u01f1"+
-		"\u01fb\5q9\2\u01f2\u01fb\5}?\2\u01f3\u01fb\5{>\2\u01f4\u01fb\5y=\2\u01f5"+
-		"\u01fb\5\u0081A\2\u01f6\u01fb\5m\67\2\u01f7\u01fb\5\u008dG\2\u01f8\u01fb"+
-		"\5\u008bF\2\u01f9\u01fb\5\177@\2\u01fa\u01e3\3\2\2\2\u01fa\u01e4\3\2\2"+
-		"\2\u01fa\u01e5\3\2\2\2\u01fa\u01e6\3\2\2\2\u01fa\u01e7\3\2\2\2\u01fa\u01e8"+
-		"\3\2\2\2\u01fa\u01e9\3\2\2\2\u01fa\u01ea\3\2\2\2\u01fa\u01eb\3\2\2\2\u01fa"+
-		"\u01ec\3\2\2\2\u01fa\u01ed\3\2\2\2\u01fa\u01ee\3\2\2\2\u01fa\u01ef\3\2"+
-		"\2\2\u01fa\u01f0\3\2\2\2\u01fa\u01f1\3\2\2\2\u01fa\u01f2\3\2\2\2\u01fa"+
-		"\u01f3\3\2\2\2\u01fa\u01f4\3\2\2\2\u01fa\u01f5\3\2\2\2\u01fa\u01f6\3\2"+
-		"\2\2\u01fa\u01f7\3\2\2\2\u01fa\u01f8\3\2\2\2\u01fa\u01f9\3\2\2\2\u01fb"+
-		"\u0094\3\2\2\2\u01fc\u023b\5\u0097L\2\u01fd\u0202\59\35\2\u01fe\u0201"+
-		"\59\35\2\u01ff\u0201\5\67\34\2\u0200\u01fe\3\2\2\2\u0200\u01ff\3\2\2\2"+
-		"\u0201\u0204\3\2\2\2\u0202\u0200\3\2\2\2\u0202\u0203\3\2\2\2\u0203\u023b"+
-		"\3\2\2\2\u0204\u0202\3\2\2\2\u0205\u020a\59\35\2\u0206\u0209\59\35\2\u0207"+
-		"\u0209\5\67\34\2\u0208\u0206\3\2\2\2\u0208\u0207\3\2\2\2\u0209\u020c\3"+
-		"\2\2\2\u020a\u0208\3\2\2\2\u020a\u020b\3\2\2\2\u020b\u020d\3\2\2\2\u020c"+
-		"\u020a\3\2\2\2\u020d\u0211\5\u0093J\2\u020e\u0210\5\u0093J\2\u020f\u020e"+
-		"\3\2\2\2\u0210\u0213\3\2\2\2\u0211\u020f\3\2\2\2\u0211\u0212\3\2\2\2\u0212"+
-		"\u023b\3\2\2\2\u0213\u0211\3\2\2\2\u0214\u0218\5\u0093J\2\u0215\u0217"+
-		"\5\u0093J\2\u0216\u0215\3\2\2\2\u0217\u021a\3\2\2\2\u0218\u0216\3\2\2"+
-		"\2\u0218\u0219\3\2\2\2\u0219\u021b\3\2\2\2\u021a\u0218\3\2\2\2\u021b\u0220"+
-		"\59\35\2\u021c\u021f\59\35\2\u021d\u021f\5\67\34\2\u021e\u021c\3\2\2\2"+
-		"\u021e\u021d\3\2\2\2\u021f\u0222\3\2\2\2\u0220\u021e\3\2\2\2\u0220\u0221"+
-		"\3\2\2\2\u0221\u023b\3\2\2\2\u0222\u0220\3\2\2\2\u0223\u0228\59\35\2\u0224"+
-		"\u0227\59\35\2\u0225\u0227\5\67\34\2\u0226\u0224\3\2\2\2\u0226\u0225\3"+
-		"\2\2\2\u0227\u022a\3\2\2\2\u0228\u0226\3\2\2\2\u0228\u0229\3\2\2\2\u0229"+
-		"\u022b\3\2\2\2\u022a\u0228\3\2\2\2\u022b\u022f\5\u0093J\2\u022c\u022e"+
-		"\5\u0093J\2\u022d\u022c\3\2\2\2\u022e\u0231\3\2\2\2\u022f\u022d\3\2\2"+
-		"\2\u022f\u0230\3\2\2\2\u0230\u0232\3\2\2\2\u0231\u022f\3\2\2\2\u0232\u0237"+
-		"\59\35\2\u0233\u0236\59\35\2\u0234\u0236\5\67\34\2\u0235\u0233\3\2\2\2"+
-		"\u0235\u0234\3\2\2\2\u0236\u0239\3\2\2\2\u0237\u0235\3\2\2\2\u0237\u0238"+
-		"\3\2\2\2\u0238\u023b\3\2\2\2\u0239\u0237\3\2\2\2\u023a\u01fc\3\2\2\2\u023a"+
-		"\u01fd\3\2\2\2\u023a\u0205\3\2\2\2\u023a\u0214\3\2\2\2\u023a\u0223\3\2"+
-		"\2\2\u023b\u0096\3\2\2\2\u023c\u0240\7$\2\2\u023d\u023f\n \2\2\u023e\u023d"+
-		"\3\2\2\2\u023f\u0242\3\2\2\2\u0240\u023e\3\2\2\2\u0240\u0241\3\2\2\2\u0241"+
-		"\u0243\3\2\2\2\u0242\u0240\3\2\2\2\u0243\u0255\7$\2\2\u0244\u0248\7)\2"+
-		"\2\u0245\u0247\n!\2\2\u0246\u0245\3\2\2\2\u0247\u024a\3\2\2\2\u0248\u0246"+
-		"\3\2\2\2\u0248\u0249\3\2\2\2\u0249\u024b\3\2\2\2\u024a\u0248\3\2\2\2\u024b"+
-		"\u0255\7)\2\2\u024c\u0250\7b\2\2\u024d\u024f\n\"\2\2\u024e\u024d\3\2\2"+
-		"\2\u024f\u0252\3\2\2\2\u0250\u024e\3\2\2\2\u0250\u0251\3\2\2\2\u0251\u0253"+
-		"\3\2\2\2\u0252\u0250\3\2\2\2\u0253\u0255\7b\2\2\u0254\u023c\3\2\2\2\u0254"+
-		"\u0244\3\2\2\2\u0254\u024c\3\2\2\2\u0255\u0098\3\2\2\2.\2\u00d7\u00e2"+
-		"\u00e8\u00f0\u00f6\u00f8\u00fe\u0104\u010a\u0110\u0113\u0117\u011c\u0122"+
-		"\u0127\u012d\u0130\u0134\u015a\u0162\u0168\u0170\u0176\u017e\u01fa\u0200"+
-		"\u0202\u0208\u020a\u0211\u0218\u021e\u0220\u0226\u0228\u022f\u0235\u0237"+
-		"\u023a\u0240\u0248\u0250\u0254\3\2\3\2";
+		"\3G\3H\3H\3H\3H\3H\3I\3I\3I\3I\3I\3I\3J\3J\3J\3J\3J\3J\3J\3J\3K\3K\3K"+
+		"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\5K\u0206"+
+		"\nK\3L\3L\3L\3L\7L\u020c\nL\fL\16L\u020f\13L\3L\3L\3L\7L\u0214\nL\fL\16"+
+		"L\u0217\13L\3L\3L\7L\u021b\nL\fL\16L\u021e\13L\3L\3L\7L\u0222\nL\fL\16"+
+		"L\u0225\13L\3L\3L\3L\7L\u022a\nL\fL\16L\u022d\13L\3L\3L\3L\7L\u0232\n"+
+		"L\fL\16L\u0235\13L\3L\3L\7L\u0239\nL\fL\16L\u023c\13L\3L\3L\3L\7L\u0241"+
+		"\nL\fL\16L\u0244\13L\5L\u0246\nL\3M\3M\7M\u024a\nM\fM\16M\u024d\13M\3"+
+		"M\3M\3M\7M\u0252\nM\fM\16M\u0255\13M\3M\3M\3M\7M\u025a\nM\fM\16M\u025d"+
+		"\13M\3M\5M\u0260\nM\3\u00e4\2N\3\2\5\2\7\2\t\2\13\2\r\2\17\2\21\2\23\2"+
+		"\25\2\27\2\31\2\33\2\35\2\37\2!\2#\2%\2\'\2)\2+\2-\2/\2\61\2\63\2\65\2"+
+		"\67\29\2;\3=\4?\5A\6C\7E\bG\tI\nK\13M\fO\rQ\16S\17U\20W\21Y\22[\23]\24"+
+		"_\25a\26c\27e\30g\31i\32k\33m\34o\35q\36s\37u w!y\"{#}$\177%\u0081&\u0083"+
+		"\'\u0085(\u0087)\u0089*\u008b+\u008d,\u008f-\u0091.\u0093/\u0095\60\u0097"+
+		"\61\u0099\62\3\2#\4\2CCcc\4\2DDdd\4\2EEee\4\2FFff\4\2GGgg\4\2HHhh\4\2"+
+		"IIii\4\2JJjj\4\2KKkk\4\2LLll\4\2MMmm\4\2NNnn\4\2OOoo\4\2PPpp\4\2QQqq\4"+
+		"\2RRrr\4\2SSss\4\2TTtt\4\2UUuu\4\2VVvv\4\2WWww\4\2XXxx\4\2YYyy\4\2ZZz"+
+		"z\4\2[[{{\4\2\\\\||\3\2\62;\5\2C\\aac|\4\2\f\f\17\17\5\2\13\f\17\17\""+
+		"\"\3\2$$\3\2))\3\2bb\2\u028d\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2"+
+		"\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2"+
+		"O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3"+
+		"\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2"+
+		"\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2"+
+		"u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2"+
+		"\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087\3\2\2\2\2\u0089"+
+		"\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2\2\2\2\u0091\3\2\2"+
+		"\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097\3\2\2\2\2\u0099\3\2\2\2\3\u009b"+
+		"\3\2\2\2\5\u009d\3\2\2\2\7\u009f\3\2\2\2\t\u00a1\3\2\2\2\13\u00a3\3\2"+
+		"\2\2\r\u00a5\3\2\2\2\17\u00a7\3\2\2\2\21\u00a9\3\2\2\2\23\u00ab\3\2\2"+
+		"\2\25\u00ad\3\2\2\2\27\u00af\3\2\2\2\31\u00b1\3\2\2\2\33\u00b3\3\2\2\2"+
+		"\35\u00b5\3\2\2\2\37\u00b7\3\2\2\2!\u00b9\3\2\2\2#\u00bb\3\2\2\2%\u00bd"+
+		"\3\2\2\2\'\u00bf\3\2\2\2)\u00c1\3\2\2\2+\u00c3\3\2\2\2-\u00c5\3\2\2\2"+
+		"/\u00c7\3\2\2\2\61\u00c9\3\2\2\2\63\u00cb\3\2\2\2\65\u00cd\3\2\2\2\67"+
+		"\u00cf\3\2\2\29\u00d1\3\2\2\2;\u00d3\3\2\2\2=\u00de\3\2\2\2?\u00fa\3\2"+
+		"\2\2A\u0100\3\2\2\2C\u0119\3\2\2\2E\u0136\3\2\2\2G\u0138\3\2\2\2I\u013a"+
+		"\3\2\2\2K\u013c\3\2\2\2M\u013e\3\2\2\2O\u0140\3\2\2\2Q\u0142\3\2\2\2S"+
+		"\u0144\3\2\2\2U\u0149\3\2\2\2W\u014d\3\2\2\2Y\u0150\3\2\2\2[\u0152\3\2"+
+		"\2\2]\u0154\3\2\2\2_\u0156\3\2\2\2a\u015c\3\2\2\2c\u0164\3\2\2\2e\u016a"+
+		"\3\2\2\2g\u0172\3\2\2\2i\u0178\3\2\2\2k\u0180\3\2\2\2m\u0182\3\2\2\2o"+
+		"\u0187\3\2\2\2q\u018d\3\2\2\2s\u0195\3\2\2\2u\u019d\3\2\2\2w\u01a3\3\2"+
+		"\2\2y\u01aa\3\2\2\2{\u01ae\3\2\2\2}\u01b2\3\2\2\2\177\u01b6\3\2\2\2\u0081"+
+		"\u01bc\3\2\2\2\u0083\u01c3\3\2\2\2\u0085\u01c6\3\2\2\2\u0087\u01ca\3\2"+
+		"\2\2\u0089\u01cd\3\2\2\2\u008b\u01d1\3\2\2\2\u008d\u01d5\3\2\2\2\u008f"+
+		"\u01da\3\2\2\2\u0091\u01df\3\2\2\2\u0093\u01e5\3\2\2\2\u0095\u0205\3\2"+
+		"\2\2\u0097\u0245\3\2\2\2\u0099\u025f\3\2\2\2\u009b\u009c\t\2\2\2\u009c"+
+		"\4\3\2\2\2\u009d\u009e\t\3\2\2\u009e\6\3\2\2\2\u009f\u00a0\t\4\2\2\u00a0"+
+		"\b\3\2\2\2\u00a1\u00a2\t\5\2\2\u00a2\n\3\2\2\2\u00a3\u00a4\t\6\2\2\u00a4"+
+		"\f\3\2\2\2\u00a5\u00a6\t\7\2\2\u00a6\16\3\2\2\2\u00a7\u00a8\t\b\2\2\u00a8"+
+		"\20\3\2\2\2\u00a9\u00aa\t\t\2\2\u00aa\22\3\2\2\2\u00ab\u00ac\t\n\2\2\u00ac"+
+		"\24\3\2\2\2\u00ad\u00ae\t\13\2\2\u00ae\26\3\2\2\2\u00af\u00b0\t\f\2\2"+
+		"\u00b0\30\3\2\2\2\u00b1\u00b2\t\r\2\2\u00b2\32\3\2\2\2\u00b3\u00b4\t\16"+
+		"\2\2\u00b4\34\3\2\2\2\u00b5\u00b6\t\17\2\2\u00b6\36\3\2\2\2\u00b7\u00b8"+
+		"\t\20\2\2\u00b8 \3\2\2\2\u00b9\u00ba\t\21\2\2\u00ba\"\3\2\2\2\u00bb\u00bc"+
+		"\t\22\2\2\u00bc$\3\2\2\2\u00bd\u00be\t\23\2\2\u00be&\3\2\2\2\u00bf\u00c0"+
+		"\t\24\2\2\u00c0(\3\2\2\2\u00c1\u00c2\t\25\2\2\u00c2*\3\2\2\2\u00c3\u00c4"+
+		"\t\26\2\2\u00c4,\3\2\2\2\u00c5\u00c6\t\27\2\2\u00c6.\3\2\2\2\u00c7\u00c8"+
+		"\t\30\2\2\u00c8\60\3\2\2\2\u00c9\u00ca\t\31\2\2\u00ca\62\3\2\2\2\u00cb"+
+		"\u00cc\t\32\2\2\u00cc\64\3\2\2\2\u00cd\u00ce\t\33\2\2\u00ce\66\3\2\2\2"+
+		"\u00cf\u00d0\t\34\2\2\u00d08\3\2\2\2\u00d1\u00d2\t\35\2\2\u00d2:\3\2\2"+
+		"\2\u00d3\u00d4\7/\2\2\u00d4\u00d5\7/\2\2\u00d5\u00d9\3\2\2\2\u00d6\u00d8"+
+		"\n\36\2\2\u00d7\u00d6\3\2\2\2\u00d8\u00db\3\2\2\2\u00d9\u00d7\3\2\2\2"+
+		"\u00d9\u00da\3\2\2\2\u00da\u00dc\3\2\2\2\u00db\u00d9\3\2\2\2\u00dc\u00dd"+
+		"\b\36\2\2\u00dd<\3\2\2\2\u00de\u00df\7\61\2\2\u00df\u00e0\7,\2\2\u00e0"+
+		"\u00e4\3\2\2\2\u00e1\u00e3\13\2\2\2\u00e2\u00e1\3\2\2\2\u00e3\u00e6\3"+
+		"\2\2\2\u00e4\u00e5\3\2\2\2\u00e4\u00e2\3\2\2\2\u00e5\u00ea\3\2\2\2\u00e6"+
+		"\u00e4\3\2\2\2\u00e7\u00e8\7,\2\2\u00e8\u00eb\7\61\2\2\u00e9\u00eb\7\2"+
+		"\2\3\u00ea\u00e7\3\2\2\2\u00ea\u00e9\3\2\2\2\u00eb\u00ec\3\2\2\2\u00ec"+
+		"\u00ed\b\37\2\2\u00ed>\3\2\2\2\u00ee\u00f2\7\"\2\2\u00ef\u00f1\7\"\2\2"+
+		"\u00f0\u00ef\3\2\2\2\u00f1\u00f4\3\2\2\2\u00f2\u00f0\3\2\2\2\u00f2\u00f3"+
+		"\3\2\2\2\u00f3\u00fb\3\2\2\2\u00f4\u00f2\3\2\2\2\u00f5\u00f7\t\37\2\2"+
+		"\u00f6\u00f5\3\2\2\2\u00f7\u00f8\3\2\2\2\u00f8\u00f6\3\2\2\2\u00f8\u00f9"+
+		"\3\2\2\2\u00f9\u00fb\3\2\2\2\u00fa\u00ee\3\2\2\2\u00fa\u00f6\3\2\2\2\u00fb"+
+		"\u00fc\3\2\2\2\u00fc\u00fd\b \2\2\u00fd@\3\2\2\2\u00fe\u0101\5I%\2\u00ff"+
+		"\u0101\5K&\2\u0100\u00fe\3\2\2\2\u0100\u00ff\3\2\2\2\u0100\u0101\3\2\2"+
+		"\2\u0101\u0102\3\2\2\2\u0102\u0106\5\67\34\2\u0103\u0105\5\67\34\2\u0104"+
+		"\u0103\3\2\2\2\u0105\u0108\3\2\2\2\u0106\u0104\3\2\2\2\u0106\u0107\3\2"+
+		"\2\2\u0107\u0115\3\2\2\2\u0108\u0106\3\2\2\2\u0109\u010c\5\13\6\2\u010a"+
+		"\u010d\5I%\2\u010b\u010d\5K&\2\u010c\u010a\3\2\2\2\u010c\u010b\3\2\2\2"+
+		"\u010c\u010d\3\2\2\2\u010d\u010e\3\2\2\2\u010e\u0112\5\67\34\2\u010f\u0111"+
+		"\5\67\34\2\u0110\u010f\3\2\2\2\u0111\u0114\3\2\2\2\u0112\u0110\3\2\2\2"+
+		"\u0112\u0113\3\2\2\2\u0113\u0116\3\2\2\2\u0114\u0112\3\2\2\2\u0115\u0109"+
+		"\3\2\2\2\u0115\u0116\3\2\2\2\u0116B\3\2\2\2\u0117\u011a\5I%\2\u0118\u011a"+
+		"\5K&\2\u0119\u0117\3\2\2\2\u0119\u0118\3\2\2\2\u0119\u011a\3\2\2\2\u011a"+
+		"\u011c\3\2\2\2\u011b\u011d\5\67\34\2\u011c\u011b\3\2\2\2\u011d\u011e\3"+
+		"\2\2\2\u011e\u011c\3\2\2\2\u011e\u011f\3\2\2\2\u011f\u0120\3\2\2\2\u0120"+
+		"\u0122\5Q)\2\u0121\u0123\5\67\34\2\u0122\u0121\3\2\2\2\u0123\u0124\3\2"+
+		"\2\2\u0124\u0122\3\2\2\2\u0124\u0125\3\2\2\2\u0125\u0132\3\2\2\2\u0126"+
+		"\u0129\5\13\6\2\u0127\u012a\5I%\2\u0128\u012a\5K&\2\u0129\u0127\3\2\2"+
+		"\2\u0129\u0128\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u012b\3\2\2\2\u012b\u012f"+
+		"\5\67\34\2\u012c\u012e\5\67\34\2\u012d\u012c\3\2\2\2\u012e\u0131\3\2\2"+
+		"\2\u012f\u012d\3\2\2\2\u012f\u0130\3\2\2\2\u0130\u0133\3\2\2\2\u0131\u012f"+
+		"\3\2\2\2\u0132\u0126\3\2\2\2\u0132\u0133\3\2\2\2\u0133D\3\2\2\2\u0134"+
+		"\u0137\5\u008fH\2\u0135\u0137\5\u0091I\2\u0136\u0134\3\2\2\2\u0136\u0135"+
+		"\3\2\2\2\u0137F\3\2\2\2\u0138\u0139\7.\2\2\u0139H\3\2\2\2\u013a\u013b"+
+		"\7-\2\2\u013bJ\3\2\2\2\u013c\u013d\7/\2\2\u013dL\3\2\2\2\u013e\u013f\7"+
+		",\2\2\u013fN\3\2\2\2\u0140\u0141\7\61\2\2\u0141P\3\2\2\2\u0142\u0143\7"+
+		"\60\2\2\u0143R\3\2\2\2\u0144\u0145\5\31\r\2\u0145\u0146\5\23\n\2\u0146"+
+		"\u0147\5\27\f\2\u0147\u0148\5\13\6\2\u0148T\3\2\2\2\u0149\u014a\5\3\2"+
+		"\2\u014a\u014b\5\35\17\2\u014b\u014c\5\t\5\2\u014cV\3\2\2\2\u014d\u014e"+
+		"\5\37\20\2\u014e\u014f\5%\23\2\u014fX\3\2\2\2\u0150\u0151\7*\2\2\u0151"+
+		"Z\3\2\2\2\u0152\u0153\7]\2\2\u0153\\\3\2\2\2\u0154\u0155\7+\2\2\u0155"+
+		"^\3\2\2\2\u0156\u0157\7_\2\2\u0157`\3\2\2\2\u0158\u015d\7>\2\2\u0159\u015a"+
+		"\5\31\r\2\u015a\u015b\5)\25\2\u015b\u015d\3\2\2\2\u015c\u0158\3\2\2\2"+
+		"\u015c\u0159\3\2\2\2\u015db\3\2\2\2\u015e\u015f\7>\2\2\u015f\u0165\7?"+
+		"\2\2\u0160\u0161\5\31\r\2\u0161\u0162\5)\25\2\u0162\u0163\5\13\6\2\u0163"+
+		"\u0165\3\2\2\2\u0164\u015e\3\2\2\2\u0164\u0160\3\2\2\2\u0165d\3\2\2\2"+
+		"\u0166\u016b\7?\2\2\u0167\u0168\5\13\6\2\u0168\u0169\5#\22\2\u0169\u016b"+
+		"\3\2\2\2\u016a\u0166\3\2\2\2\u016a\u0167\3\2\2\2\u016bf\3\2\2\2\u016c"+
+		"\u016d\7#\2\2\u016d\u0173\7?\2\2\u016e\u016f\5\35\17\2\u016f\u0170\5\13"+
+		"\6\2\u0170\u0171\5#\22\2\u0171\u0173\3\2\2\2\u0172\u016c\3\2\2\2\u0172"+
+		"\u016e\3\2\2\2\u0173h\3\2\2\2\u0174\u0179\7@\2\2\u0175\u0176\5\17\b\2"+
+		"\u0176\u0177\5)\25\2\u0177\u0179\3\2\2\2\u0178\u0174\3\2\2\2\u0178\u0175"+
+		"\3\2\2\2\u0179j\3\2\2\2\u017a\u017b\7@\2\2\u017b\u0181\7?\2\2\u017c\u017d"+
+		"\5\17\b\2\u017d\u017e\5)\25\2\u017e\u017f\5\13\6\2\u017f\u0181\3\2\2\2"+
+		"\u0180\u017a\3\2\2\2\u0180\u017c\3\2\2\2\u0181l\3\2\2\2\u0182\u0183\5"+
+		"\r\7\2\u0183\u0184\5%\23\2\u0184\u0185\5\37\20\2\u0185\u0186\5\33\16\2"+
+		"\u0186n\3\2\2\2\u0187\u0188\5/\30\2\u0188\u0189\5\21\t\2\u0189\u018a\5"+
+		"\13\6\2\u018a\u018b\5%\23\2\u018b\u018c\5\13\6\2\u018cp\3\2\2\2\u018d"+
+		"\u018e\5\37\20\2\u018e\u018f\5%\23\2\u018f\u0190\5\t\5\2\u0190\u0191\5"+
+		"\13\6\2\u0191\u0192\5%\23\2\u0192\u0193\5\5\3\2\u0193\u0194\5\63\32\2"+
+		"\u0194r\3\2\2\2\u0195\u0196\5\17\b\2\u0196\u0197\5%\23\2\u0197\u0198\5"+
+		"\37\20\2\u0198\u0199\5+\26\2\u0199\u019a\5!\21\2\u019a\u019b\5\5\3\2\u019b"+
+		"\u019c\5\63\32\2\u019ct\3\2\2\2\u019d\u019e\5\31\r\2\u019e\u019f\5\23"+
+		"\n\2\u019f\u01a0\5\33\16\2\u01a0\u01a1\5\23\n\2\u01a1\u01a2\5)\25\2\u01a2"+
+		"v\3\2\2\2\u01a3\u01a4\5\'\24\2\u01a4\u01a5\5\13\6\2\u01a5\u01a6\5\31\r"+
+		"\2\u01a6\u01a7\5\13\6\2\u01a7\u01a8\5\7\4\2\u01a8\u01a9\5)\25\2\u01a9"+
+		"x\3\2\2\2\u01aa\u01ab\5\33\16\2\u01ab\u01ac\5\3\2\2\u01ac\u01ad\5\61\31"+
+		"\2\u01adz\3\2\2\2\u01ae\u01af\5\33\16\2\u01af\u01b0\5\23\n\2\u01b0\u01b1"+
+		"\5\35\17\2\u01b1|\3\2\2\2\u01b2\u01b3\5\'\24\2\u01b3\u01b4\5+\26\2\u01b4"+
+		"\u01b5\5\33\16\2\u01b5~\3\2\2\2\u01b6\u01b7\5\7\4\2\u01b7\u01b8\5\37\20"+
+		"\2\u01b8\u01b9\5+\26\2\u01b9\u01ba\5\35\17\2\u01ba\u01bb\5)\25\2\u01bb"+
+		"\u0080\3\2\2\2\u01bc\u01bd\5\37\20\2\u01bd\u01be\5\r\7\2\u01be\u01bf\5"+
+		"\r\7\2\u01bf\u01c0\5\'\24\2\u01c0\u01c1\5\13\6\2\u01c1\u01c2\5)\25\2\u01c2"+
+		"\u0082\3\2\2\2\u01c3\u01c4\5\3\2\2\u01c4\u01c5\5\'\24\2\u01c5\u0084\3"+
+		"\2\2\2\u01c6\u01c7\5\23\n\2\u01c7\u01c8\5\'\24\2\u01c8\u01c9\5\3\2\2\u01c9"+
+		"\u0086\3\2\2\2\u01ca\u01cb\5\23\n\2\u01cb\u01cc\5\'\24\2\u01cc\u0088\3"+
+		"\2\2\2\u01cd\u01ce\5\21\t\2\u01ce\u01cf\5\3\2\2\u01cf\u01d0\5\'\24\2\u01d0"+
+		"\u008a\3\2\2\2\u01d1\u01d2\5\3\2\2\u01d2\u01d3\5\'\24\2\u01d3\u01d4\5"+
+		"\7\4\2\u01d4\u008c\3\2\2\2\u01d5\u01d6\5\t\5\2\u01d6\u01d7\5\13\6\2\u01d7"+
+		"\u01d8\5\'\24\2\u01d8\u01d9\5\7\4\2\u01d9\u008e\3\2\2\2\u01da\u01db\5"+
+		")\25\2\u01db\u01dc\5%\23\2\u01dc\u01dd\5+\26\2\u01dd\u01de\5\13\6\2\u01de"+
+		"\u0090\3\2\2\2\u01df\u01e0\5\r\7\2\u01e0\u01e1\5\3\2\2\u01e1\u01e2\5\31"+
+		"\r\2\u01e2\u01e3\5\'\24\2\u01e3\u01e4\5\13\6\2\u01e4\u0092\3\2\2\2\u01e5"+
+		"\u01e6\5\21\t\2\u01e6\u01e7\5\3\2\2\u01e7\u01e8\5\'\24\2\u01e8\u01e9\5"+
+		")\25\2\u01e9\u01ea\5\13\6\2\u01ea\u01eb\5%\23\2\u01eb\u01ec\5\33\16\2"+
+		"\u01ec\u0094\3\2\2\2\u01ed\u0206\5S*\2\u01ee\u0206\5Q)\2\u01ef\u0206\5"+
+		"w<\2\u01f0\u0206\5\u0083B\2\u01f1\u0206\5\u0089E\2\u01f2\u0206\5\u0087"+
+		"D\2\u01f3\u0206\5\u0085C\2\u01f4\u0206\5o8\2\u01f5\u0206\5u;\2\u01f6\u0206"+
+		"\5\u008fH\2\u01f7\u0206\5\u0091I\2\u01f8\u0206\5U+\2\u01f9\u0206\5W,\2"+
+		"\u01fa\u0206\5s:\2\u01fb\u0206\5q9\2\u01fc\u0206\5}?\2\u01fd\u0206\5{"+
+		">\2\u01fe\u0206\5y=\2\u01ff\u0206\5\u0081A\2\u0200\u0206\5m\67\2\u0201"+
+		"\u0206\5\u008dG\2\u0202\u0206\5\u008bF\2\u0203\u0206\5\177@\2\u0204\u0206"+
+		"\5\u0093J\2\u0205\u01ed\3\2\2\2\u0205\u01ee\3\2\2\2\u0205\u01ef\3\2\2"+
+		"\2\u0205\u01f0\3\2\2\2\u0205\u01f1\3\2\2\2\u0205\u01f2\3\2\2\2\u0205\u01f3"+
+		"\3\2\2\2\u0205\u01f4\3\2\2\2\u0205\u01f5\3\2\2\2\u0205\u01f6\3\2\2\2\u0205"+
+		"\u01f7\3\2\2\2\u0205\u01f8\3\2\2\2\u0205\u01f9\3\2\2\2\u0205\u01fa\3\2"+
+		"\2\2\u0205\u01fb\3\2\2\2\u0205\u01fc\3\2\2\2\u0205\u01fd\3\2\2\2\u0205"+
+		"\u01fe\3\2\2\2\u0205\u01ff\3\2\2\2\u0205\u0200\3\2\2\2\u0205\u0201\3\2"+
+		"\2\2\u0205\u0202\3\2\2\2\u0205\u0203\3\2\2\2\u0205\u0204\3\2\2\2\u0206"+
+		"\u0096\3\2\2\2\u0207\u0246\5\u0099M\2\u0208\u020d\59\35\2\u0209\u020c"+
+		"\59\35\2\u020a\u020c\5\67\34\2\u020b\u0209\3\2\2\2\u020b\u020a\3\2\2\2"+
+		"\u020c\u020f\3\2\2\2\u020d\u020b\3\2\2\2\u020d\u020e\3\2\2\2\u020e\u0246"+
+		"\3\2\2\2\u020f\u020d\3\2\2\2\u0210\u0215\59\35\2\u0211\u0214\59\35\2\u0212"+
+		"\u0214\5\67\34\2\u0213\u0211\3\2\2\2\u0213\u0212\3\2\2\2\u0214\u0217\3"+
+		"\2\2\2\u0215\u0213\3\2\2\2\u0215\u0216\3\2\2\2\u0216\u0218\3\2\2\2\u0217"+
+		"\u0215\3\2\2\2\u0218\u021c\5\u0095K\2\u0219\u021b\5\u0095K\2\u021a\u0219"+
+		"\3\2\2\2\u021b\u021e\3\2\2\2\u021c\u021a\3\2\2\2\u021c\u021d\3\2\2\2\u021d"+
+		"\u0246\3\2\2\2\u021e\u021c\3\2\2\2\u021f\u0223\5\u0095K\2\u0220\u0222"+
+		"\5\u0095K\2\u0221\u0220\3\2\2\2\u0222\u0225\3\2\2\2\u0223\u0221\3\2\2"+
+		"\2\u0223\u0224\3\2\2\2\u0224\u0226\3\2\2\2\u0225\u0223\3\2\2\2\u0226\u022b"+
+		"\59\35\2\u0227\u022a\59\35\2\u0228\u022a\5\67\34\2\u0229\u0227\3\2\2\2"+
+		"\u0229\u0228\3\2\2\2\u022a\u022d\3\2\2\2\u022b\u0229\3\2\2\2\u022b\u022c"+
+		"\3\2\2\2\u022c\u0246\3\2\2\2\u022d\u022b\3\2\2\2\u022e\u0233\59\35\2\u022f"+
+		"\u0232\59\35\2\u0230\u0232\5\67\34\2\u0231\u022f\3\2\2\2\u0231\u0230\3"+
+		"\2\2\2\u0232\u0235\3\2\2\2\u0233\u0231\3\2\2\2\u0233\u0234\3\2\2\2\u0234"+
+		"\u0236\3\2\2\2\u0235\u0233\3\2\2\2\u0236\u023a\5\u0095K\2\u0237\u0239"+
+		"\5\u0095K\2\u0238\u0237\3\2\2\2\u0239\u023c\3\2\2\2\u023a\u0238\3\2\2"+
+		"\2\u023a\u023b\3\2\2\2\u023b\u023d\3\2\2\2\u023c\u023a\3\2\2\2\u023d\u0242"+
+		"\59\35\2\u023e\u0241\59\35\2\u023f\u0241\5\67\34\2\u0240\u023e\3\2\2\2"+
+		"\u0240\u023f\3\2\2\2\u0241\u0244\3\2\2\2\u0242\u0240\3\2\2\2\u0242\u0243"+
+		"\3\2\2\2\u0243\u0246\3\2\2\2\u0244\u0242\3\2\2\2\u0245\u0207\3\2\2\2\u0245"+
+		"\u0208\3\2\2\2\u0245\u0210\3\2\2\2\u0245\u021f\3\2\2\2\u0245\u022e\3\2"+
+		"\2\2\u0246\u0098\3\2\2\2\u0247\u024b\7$\2\2\u0248\u024a\n \2\2\u0249\u0248"+
+		"\3\2\2\2\u024a\u024d\3\2\2\2\u024b\u0249\3\2\2\2\u024b\u024c\3\2\2\2\u024c"+
+		"\u024e\3\2\2\2\u024d\u024b\3\2\2\2\u024e\u0260\7$\2\2\u024f\u0253\7)\2"+
+		"\2\u0250\u0252\n!\2\2\u0251\u0250\3\2\2\2\u0252\u0255\3\2\2\2\u0253\u0251"+
+		"\3\2\2\2\u0253\u0254\3\2\2\2\u0254\u0256\3\2\2\2\u0255\u0253\3\2\2\2\u0256"+
+		"\u0260\7)\2\2\u0257\u025b\7b\2\2\u0258\u025a\n\"\2\2\u0259\u0258\3\2\2"+
+		"\2\u025a\u025d\3\2\2\2\u025b\u0259\3\2\2\2\u025b\u025c\3\2\2\2\u025c\u025e"+
+		"\3\2\2\2\u025d\u025b\3\2\2\2\u025e\u0260\7b\2\2\u025f\u0247\3\2\2\2\u025f"+
+		"\u024f\3\2\2\2\u025f\u0257\3\2\2\2\u0260\u009a\3\2\2\2.\2\u00d9\u00e4"+
+		"\u00ea\u00f2\u00f8\u00fa\u0100\u0106\u010c\u0112\u0115\u0119\u011e\u0124"+
+		"\u0129\u012f\u0132\u0136\u015c\u0164\u016a\u0172\u0178\u0180\u0205\u020b"+
+		"\u020d\u0213\u0215\u021c\u0223\u0229\u022b\u0231\u0233\u023a\u0240\u0242"+
+		"\u0245\u024b\u0253\u025b\u025f\3\2\3\2";
 	public static final ATN _ATN =
 		new ATNDeserializer().deserialize(_serializedATN.toCharArray());
 	static {
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.tokens b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.tokens
new file mode 100644
index 0000000..7b662b5
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.tokens
@@ -0,0 +1,58 @@
+SINGLE_LINE_COMMENT=1
+MULTILINE_COMMENT=2
+WS=3
+NUMBER=4
+FLOATING_NUMBER=5
+BOOL=6
+K_COMMA=7
+K_PLUS=8
+K_MINUS=9
+K_STAR=10
+K_DIV=11
+K_DOT=12
+K_LIKE=13
+K_AND=14
+K_OR=15
+K_LPAREN=16
+K_LBRACKET=17
+K_RPAREN=18
+K_RBRACKET=19
+K_LT=20
+K_LTE=21
+K_EQ=22
+K_NEQ=23
+K_GT=24
+K_GTE=25
+K_FROM=26
+K_WHERE=27
+K_ORDERBY=28
+K_GROUPBY=29
+K_LIMIT=30
+K_SELECT=31
+K_MAX=32
+K_MIN=33
+K_SUM=34
+K_COUNT=35
+K_OFFSET=36
+K_AS=37
+K_ISA=38
+K_IS=39
+K_HAS=40
+K_ASC=41
+K_DESC=42
+K_TRUE=43
+K_FALSE=44
+K_HASTERM=45
+KEYWORD=46
+ID=47
+STRING=48
+','=7
+'+'=8
+'-'=9
+'*'=10
+'/'=11
+'.'=12
+'('=16
+'['=17
+')'=18
+']'=19
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4 b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4
index f1c1060..4bdf479 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4
@@ -50,6 +50,8 @@ comparisonClause: arithE operator arithE ;
 
 isClause: arithE (K_ISA | K_IS) identifier ;
 
+hasTermClause: arithE K_HASTERM (identifier | expr );
+
 hasClause: arithE K_HAS identifier ;
 
 countClause: K_COUNT K_LPAREN K_RPAREN ;
@@ -70,6 +72,7 @@ compE: comparisonClause
     | maxClause
     | minClause
     | sumClause
+    | hasTermClause
     ;
 
 expr: compE exprRight* ;
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.java b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.java
index 6b33edb..04f602c 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.java
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.java
@@ -10,7 +10,7 @@ import java.util.ArrayList;
 
 @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
 public class AtlasDSLParser extends Parser {
-	static { RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); }
+	static { RuntimeMetaData.checkVersion("4.7.2", RuntimeMetaData.VERSION); }
 
 	protected static final DFA[] _decisionToDFA;
 	protected static final PredictionContextCache _sharedContextCache =
@@ -22,44 +22,53 @@ public class AtlasDSLParser extends Parser {
 		K_RBRACKET=19, K_LT=20, K_LTE=21, K_EQ=22, K_NEQ=23, K_GT=24, K_GTE=25, 
 		K_FROM=26, K_WHERE=27, K_ORDERBY=28, K_GROUPBY=29, K_LIMIT=30, K_SELECT=31, 
 		K_MAX=32, K_MIN=33, K_SUM=34, K_COUNT=35, K_OFFSET=36, K_AS=37, K_ISA=38, 
-		K_IS=39, K_HAS=40, K_ASC=41, K_DESC=42, K_TRUE=43, K_FALSE=44, KEYWORD=45, 
-		ID=46, STRING=47;
+		K_IS=39, K_HAS=40, K_ASC=41, K_DESC=42, K_TRUE=43, K_FALSE=44, K_HASTERM=45,
+		KEYWORD=46, ID=47, STRING=48;
 	public static final int
 		RULE_identifier = 0, RULE_operator = 1, RULE_sortOrder = 2, RULE_valueArray = 3, 
 		RULE_literal = 4, RULE_limitClause = 5, RULE_offsetClause = 6, RULE_atomE = 7, 
 		RULE_multiERight = 8, RULE_multiE = 9, RULE_arithERight = 10, RULE_arithE = 11, 
-		RULE_comparisonClause = 12, RULE_isClause = 13, RULE_hasClause = 14, RULE_countClause = 15, 
-		RULE_maxClause = 16, RULE_minClause = 17, RULE_sumClause = 18, RULE_exprRight = 19, 
-		RULE_compE = 20, RULE_expr = 21, RULE_limitOffset = 22, RULE_selectExpression = 23, 
-		RULE_selectExpr = 24, RULE_aliasExpr = 25, RULE_orderByExpr = 26, RULE_fromSrc = 27, 
-		RULE_whereClause = 28, RULE_fromExpression = 29, RULE_fromClause = 30, 
-		RULE_selectClause = 31, RULE_singleQrySrc = 32, RULE_groupByExpression = 33, 
-		RULE_commaDelimitedQueries = 34, RULE_spaceDelimitedQueries = 35, RULE_querySrc = 36, 
-		RULE_query = 37;
-	public static final String[] ruleNames = {
-		"identifier", "operator", "sortOrder", "valueArray", "literal", "limitClause", 
-		"offsetClause", "atomE", "multiERight", "multiE", "arithERight", "arithE", 
-		"comparisonClause", "isClause", "hasClause", "countClause", "maxClause", 
-		"minClause", "sumClause", "exprRight", "compE", "expr", "limitOffset", 
-		"selectExpression", "selectExpr", "aliasExpr", "orderByExpr", "fromSrc", 
-		"whereClause", "fromExpression", "fromClause", "selectClause", "singleQrySrc", 
-		"groupByExpression", "commaDelimitedQueries", "spaceDelimitedQueries", 
-		"querySrc", "query"
-	};
-
-	private static final String[] _LITERAL_NAMES = {
-		null, null, null, null, null, null, null, "','", "'+'", "'-'", "'*'", 
-		"'/'", "'.'", null, null, null, "'('", "'['", "')'", "']'"
-	};
-	private static final String[] _SYMBOLIC_NAMES = {
-		null, "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT", "WS", "NUMBER", "FLOATING_NUMBER", 
-		"BOOL", "K_COMMA", "K_PLUS", "K_MINUS", "K_STAR", "K_DIV", "K_DOT", "K_LIKE", 
-		"K_AND", "K_OR", "K_LPAREN", "K_LBRACKET", "K_RPAREN", "K_RBRACKET", "K_LT", 
-		"K_LTE", "K_EQ", "K_NEQ", "K_GT", "K_GTE", "K_FROM", "K_WHERE", "K_ORDERBY", 
-		"K_GROUPBY", "K_LIMIT", "K_SELECT", "K_MAX", "K_MIN", "K_SUM", "K_COUNT", 
-		"K_OFFSET", "K_AS", "K_ISA", "K_IS", "K_HAS", "K_ASC", "K_DESC", "K_TRUE", 
-		"K_FALSE", "KEYWORD", "ID", "STRING"
-	};
+		RULE_comparisonClause = 12, RULE_isClause = 13, RULE_hasTermClause = 14,
+		RULE_hasClause = 15, RULE_countClause = 16, RULE_maxClause = 17, RULE_minClause = 18,
+		RULE_sumClause = 19, RULE_exprRight = 20, RULE_compE = 21, RULE_expr = 22,
+		RULE_limitOffset = 23, RULE_selectExpression = 24, RULE_selectExpr = 25,
+		RULE_aliasExpr = 26, RULE_orderByExpr = 27, RULE_fromSrc = 28, RULE_whereClause = 29,
+		RULE_fromExpression = 30, RULE_fromClause = 31, RULE_selectClause = 32,
+		RULE_singleQrySrc = 33, RULE_groupByExpression = 34, RULE_commaDelimitedQueries = 35,
+		RULE_spaceDelimitedQueries = 36, RULE_querySrc = 37, RULE_query = 38;
+	private static String[] makeRuleNames() {
+		return new String[] {
+			"identifier", "operator", "sortOrder", "valueArray", "literal", "limitClause",
+			"offsetClause", "atomE", "multiERight", "multiE", "arithERight", "arithE",
+			"comparisonClause", "isClause", "hasTermClause", "hasClause", "countClause",
+			"maxClause", "minClause", "sumClause", "exprRight", "compE", "expr",
+			"limitOffset", "selectExpression", "selectExpr", "aliasExpr", "orderByExpr",
+			"fromSrc", "whereClause", "fromExpression", "fromClause", "selectClause",
+			"singleQrySrc", "groupByExpression", "commaDelimitedQueries", "spaceDelimitedQueries",
+			"querySrc", "query"
+		};
+	}
+	public static final String[] ruleNames = makeRuleNames();
+
+	private static String[] makeLiteralNames() {
+		return new String[] {
+			null, null, null, null, null, null, null, "','", "'+'", "'-'", "'*'",
+			"'/'", "'.'", null, null, null, "'('", "'['", "')'", "']'"
+		};
+	}
+	private static final String[] _LITERAL_NAMES = makeLiteralNames();
+	private static String[] makeSymbolicNames() {
+		return new String[] {
+			null, "SINGLE_LINE_COMMENT", "MULTILINE_COMMENT", "WS", "NUMBER", "FLOATING_NUMBER",
+			"BOOL", "K_COMMA", "K_PLUS", "K_MINUS", "K_STAR", "K_DIV", "K_DOT", "K_LIKE",
+			"K_AND", "K_OR", "K_LPAREN", "K_LBRACKET", "K_RPAREN", "K_RBRACKET",
+			"K_LT", "K_LTE", "K_EQ", "K_NEQ", "K_GT", "K_GTE", "K_FROM", "K_WHERE",
+			"K_ORDERBY", "K_GROUPBY", "K_LIMIT", "K_SELECT", "K_MAX", "K_MIN", "K_SUM",
+			"K_COUNT", "K_OFFSET", "K_AS", "K_ISA", "K_IS", "K_HAS", "K_ASC", "K_DESC",
+			"K_TRUE", "K_FALSE", "K_HASTERM", "KEYWORD", "ID", "STRING"
+		};
+	}
+	private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
 	public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
 
 	/**
@@ -109,6 +118,7 @@ public class AtlasDSLParser extends Parser {
 		super(input);
 		_interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
 	}
+
 	public static class IdentifierContext extends ParserRuleContext {
 		public TerminalNode ID() { return getToken(AtlasDSLParser.ID, 0); }
 		public IdentifierContext(ParserRuleContext parent, int invokingState) {
@@ -116,6 +126,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_identifier; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterIdentifier(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitIdentifier(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitIdentifier(this);
 			else return visitor.visitChildren(this);
@@ -128,7 +146,7 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(76);
+			setState(78);
 			match(ID);
 			}
 		}
@@ -156,6 +174,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_operator; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterOperator(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitOperator(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitOperator(this);
 			else return visitor.visitChildren(this);
@@ -169,7 +195,7 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(78);
+			setState(80);
 			_la = _input.LA(1);
 			if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << K_LIKE) | (1L << K_LT) | (1L << K_LTE) | (1L << K_EQ) | (1L << K_NEQ) | (1L << K_GT) | (1L << K_GTE))) != 0)) ) {
 			_errHandler.recoverInline(this);
@@ -200,6 +226,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_sortOrder; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterSortOrder(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitSortOrder(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitSortOrder(this);
 			else return visitor.visitChildren(this);
@@ -213,7 +247,7 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(80);
+			setState(82);
 			_la = _input.LA(1);
 			if ( !(_la==K_ASC || _la==K_DESC) ) {
 			_errHandler.recoverInline(this);
@@ -252,6 +286,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_valueArray; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterValueArray(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitValueArray(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitValueArray(this);
 			else return visitor.visitChildren(this);
@@ -265,27 +307,27 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(82);
+			setState(84);
 			match(K_LBRACKET);
-			setState(83);
+			setState(85);
 			match(ID);
-			setState(88);
+			setState(90);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			while (_la==K_COMMA) {
 				{
 				{
-				setState(84);
+				setState(86);
 				match(K_COMMA);
-				setState(85);
+				setState(87);
 				match(ID);
 				}
 				}
-				setState(90);
+				setState(92);
 				_errHandler.sync(this);
 				_la = _input.LA(1);
 			}
-			setState(91);
+			setState(93);
 			match(K_RBRACKET);
 			}
 		}
@@ -313,6 +355,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_literal; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterLiteral(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitLiteral(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitLiteral(this);
 			else return visitor.visitChildren(this);
@@ -323,27 +373,27 @@ public class AtlasDSLParser extends Parser {
 		LiteralContext _localctx = new LiteralContext(_ctx, getState());
 		enterRule(_localctx, 8, RULE_literal);
 		try {
-			setState(100);
+			setState(102);
 			_errHandler.sync(this);
 			switch (_input.LA(1)) {
 			case BOOL:
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(93);
+				setState(95);
 				match(BOOL);
 				}
 				break;
 			case NUMBER:
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(94);
+				setState(96);
 				match(NUMBER);
 				}
 				break;
 			case FLOATING_NUMBER:
 				enterOuterAlt(_localctx, 3);
 				{
-				setState(95);
+				setState(97);
 				match(FLOATING_NUMBER);
 				}
 				break;
@@ -351,18 +401,18 @@ public class AtlasDSLParser extends Parser {
 			case ID:
 				enterOuterAlt(_localctx, 4);
 				{
-				setState(98);
+				setState(100);
 				_errHandler.sync(this);
 				switch (_input.LA(1)) {
 				case ID:
 					{
-					setState(96);
+					setState(98);
 					match(ID);
 					}
 					break;
 				case K_LBRACKET:
 					{
-					setState(97);
+					setState(99);
 					valueArray();
 					}
 					break;
@@ -394,6 +444,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_limitClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterLimitClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitLimitClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitLimitClause(this);
 			else return visitor.visitChildren(this);
@@ -406,9 +464,9 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(102);
+			setState(104);
 			match(K_LIMIT);
-			setState(103);
+			setState(105);
 			match(NUMBER);
 			}
 		}
@@ -431,6 +489,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_offsetClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterOffsetClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitOffsetClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitOffsetClause(this);
 			else return visitor.visitChildren(this);
@@ -443,9 +509,9 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(105);
+			setState(107);
 			match(K_OFFSET);
-			setState(106);
+			setState(108);
 			match(NUMBER);
 			}
 		}
@@ -477,6 +543,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_atomE; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterAtomE(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitAtomE(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitAtomE(this);
 			else return visitor.visitChildren(this);
@@ -487,7 +561,7 @@ public class AtlasDSLParser extends Parser {
 		AtomEContext _localctx = new AtomEContext(_ctx, getState());
 		enterRule(_localctx, 14, RULE_atomE);
 		try {
-			setState(116);
+			setState(118);
 			_errHandler.sync(this);
 			switch (_input.LA(1)) {
 			case NUMBER:
@@ -497,18 +571,18 @@ public class AtlasDSLParser extends Parser {
 			case ID:
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(110);
+				setState(112);
 				_errHandler.sync(this);
 				switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) {
 				case 1:
 					{
-					setState(108);
+					setState(110);
 					identifier();
 					}
 					break;
 				case 2:
 					{
-					setState(109);
+					setState(111);
 					literal();
 					}
 					break;
@@ -518,11 +592,11 @@ public class AtlasDSLParser extends Parser {
 			case K_LPAREN:
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(112);
+				setState(114);
 				match(K_LPAREN);
-				setState(113);
+				setState(115);
 				expr();
-				setState(114);
+				setState(116);
 				match(K_RPAREN);
 				}
 				break;
@@ -552,6 +626,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_multiERight; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterMultiERight(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitMultiERight(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitMultiERight(this);
 			else return visitor.visitChildren(this);
@@ -565,7 +647,7 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(118);
+			setState(120);
 			_la = _input.LA(1);
 			if ( !(_la==K_STAR || _la==K_DIV) ) {
 			_errHandler.recoverInline(this);
@@ -575,7 +657,7 @@ public class AtlasDSLParser extends Parser {
 				_errHandler.reportMatch(this);
 				consume();
 			}
-			setState(119);
+			setState(121);
 			atomE();
 			}
 		}
@@ -605,6 +687,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_multiE; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterMultiE(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitMultiE(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitMultiE(this);
 			else return visitor.visitChildren(this);
@@ -618,19 +708,19 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(121);
+			setState(123);
 			atomE();
-			setState(125);
+			setState(127);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			while (_la==K_STAR || _la==K_DIV) {
 				{
 				{
-				setState(122);
+				setState(124);
 				multiERight();
 				}
 				}
-				setState(127);
+				setState(129);
 				_errHandler.sync(this);
 				_la = _input.LA(1);
 			}
@@ -658,6 +748,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_arithERight; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterArithERight(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitArithERight(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitArithERight(this);
 			else return visitor.visitChildren(this);
@@ -671,7 +769,7 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(128);
+			setState(130);
 			_la = _input.LA(1);
 			if ( !(_la==K_PLUS || _la==K_MINUS) ) {
 			_errHandler.recoverInline(this);
@@ -681,7 +779,7 @@ public class AtlasDSLParser extends Parser {
 				_errHandler.reportMatch(this);
 				consume();
 			}
-			setState(129);
+			setState(131);
 			multiE();
 			}
 		}
@@ -711,6 +809,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_arithE; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterArithE(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitArithE(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitArithE(this);
 			else return visitor.visitChildren(this);
@@ -724,19 +830,19 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(131);
+			setState(133);
 			multiE();
-			setState(135);
+			setState(137);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			while (_la==K_PLUS || _la==K_MINUS) {
 				{
 				{
-				setState(132);
+				setState(134);
 				arithERight();
 				}
 				}
-				setState(137);
+				setState(139);
 				_errHandler.sync(this);
 				_la = _input.LA(1);
 			}
@@ -768,6 +874,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_comparisonClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterComparisonClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitComparisonClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitComparisonClause(this);
 			else return visitor.visitChildren(this);
@@ -780,11 +894,11 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(138);
+			setState(140);
 			arithE();
-			setState(139);
+			setState(141);
 			operator();
-			setState(140);
+			setState(142);
 			arithE();
 			}
 		}
@@ -813,6 +927,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_isClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterIsClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitIsClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitIsClause(this);
 			else return visitor.visitChildren(this);
@@ -826,9 +948,9 @@ public class AtlasDSLParser extends Parser {
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(142);
+			setState(144);
 			arithE();
-			setState(143);
+			setState(145);
 			_la = _input.LA(1);
 			if ( !(_la==K_ISA || _la==K_IS) ) {
 			_errHandler.recoverInline(this);
@@ -838,7 +960,7 @@ public class AtlasDSLParser extends Parser {
 				_errHandler.reportMatch(this);
 				consume();
 			}
-			setState(144);
+			setState(146);
 			identifier();
 			}
 		}
@@ -853,6 +975,75 @@ public class AtlasDSLParser extends Parser {
 		return _localctx;
 	}
 
+	public static class HasTermClauseContext extends ParserRuleContext {
+		public ArithEContext arithE() {
+			return getRuleContext(ArithEContext.class,0);
+		}
+		public TerminalNode K_HASTERM() { return getToken(AtlasDSLParser.K_HASTERM, 0); }
+		public IdentifierContext identifier() {
+			return getRuleContext(IdentifierContext.class,0);
+		}
+		public ExprContext expr() {
+			return getRuleContext(ExprContext.class,0);
+		}
+		public HasTermClauseContext(ParserRuleContext parent, int invokingState) {
+			super(parent, invokingState);
+		}
+		@Override public int getRuleIndex() { return RULE_hasTermClause; }
+		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterHasTermClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitHasTermClause(this);
+		}
+		@Override
+		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
+			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitHasTermClause(this);
+			else return visitor.visitChildren(this);
+		}
+	}
+
+	public final HasTermClauseContext hasTermClause() throws RecognitionException {
+		HasTermClauseContext _localctx = new HasTermClauseContext(_ctx, getState());
+		enterRule(_localctx, 28, RULE_hasTermClause);
+		try {
+			enterOuterAlt(_localctx, 1);
+			{
+			setState(148);
+			arithE();
+			setState(149);
+			match(K_HASTERM);
+			setState(152);
+			_errHandler.sync(this);
+			switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) {
+			case 1:
+				{
+				setState(150);
+				identifier();
+				}
+				break;
+			case 2:
+				{
+				setState(151);
+				expr();
+				}
+				break;
+			}
+			}
+		}
+		catch (RecognitionException re) {
+			_localctx.exception = re;
+			_errHandler.reportError(this, re);
+			_errHandler.recover(this, re);
+		}
+		finally {
+			exitRule();
+		}
+		return _localctx;
+	}
+
 	public static class HasClauseContext extends ParserRuleContext {
 		public ArithEContext arithE() {
 			return getRuleContext(ArithEContext.class,0);
@@ -866,6 +1057,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_hasClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterHasClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitHasClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitHasClause(this);
 			else return visitor.visitChildren(this);
@@ -874,15 +1073,15 @@ public class AtlasDSLParser extends Parser {
 
 	public final HasClauseContext hasClause() throws RecognitionException {
 		HasClauseContext _localctx = new HasClauseContext(_ctx, getState());
-		enterRule(_localctx, 28, RULE_hasClause);
+		enterRule(_localctx, 30, RULE_hasClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(146);
+			setState(154);
 			arithE();
-			setState(147);
+			setState(155);
 			match(K_HAS);
-			setState(148);
+			setState(156);
 			identifier();
 			}
 		}
@@ -906,6 +1105,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_countClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterCountClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitCountClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitCountClause(this);
 			else return visitor.visitChildren(this);
@@ -914,15 +1121,15 @@ public class AtlasDSLParser extends Parser {
 
 	public final CountClauseContext countClause() throws RecognitionException {
 		CountClauseContext _localctx = new CountClauseContext(_ctx, getState());
-		enterRule(_localctx, 30, RULE_countClause);
+		enterRule(_localctx, 32, RULE_countClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(150);
+			setState(158);
 			match(K_COUNT);
-			setState(151);
+			setState(159);
 			match(K_LPAREN);
-			setState(152);
+			setState(160);
 			match(K_RPAREN);
 			}
 		}
@@ -949,6 +1156,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_maxClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterMaxClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitMaxClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitMaxClause(this);
 			else return visitor.visitChildren(this);
@@ -957,17 +1172,17 @@ public class AtlasDSLParser extends Parser {
 
 	public final MaxClauseContext maxClause() throws RecognitionException {
 		MaxClauseContext _localctx = new MaxClauseContext(_ctx, getState());
-		enterRule(_localctx, 32, RULE_maxClause);
+		enterRule(_localctx, 34, RULE_maxClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(154);
+			setState(162);
 			match(K_MAX);
-			setState(155);
+			setState(163);
 			match(K_LPAREN);
-			setState(156);
+			setState(164);
 			expr();
-			setState(157);
+			setState(165);
 			match(K_RPAREN);
 			}
 		}
@@ -994,6 +1209,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_minClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterMinClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitMinClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitMinClause(this);
 			else return visitor.visitChildren(this);
@@ -1002,17 +1225,17 @@ public class AtlasDSLParser extends Parser {
 
 	public final MinClauseContext minClause() throws RecognitionException {
 		MinClauseContext _localctx = new MinClauseContext(_ctx, getState());
-		enterRule(_localctx, 34, RULE_minClause);
+		enterRule(_localctx, 36, RULE_minClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(159);
+			setState(167);
 			match(K_MIN);
-			setState(160);
+			setState(168);
 			match(K_LPAREN);
-			setState(161);
+			setState(169);
 			expr();
-			setState(162);
+			setState(170);
 			match(K_RPAREN);
 			}
 		}
@@ -1039,6 +1262,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_sumClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterSumClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitSumClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitSumClause(this);
 			else return visitor.visitChildren(this);
@@ -1047,17 +1278,17 @@ public class AtlasDSLParser extends Parser {
 
 	public final SumClauseContext sumClause() throws RecognitionException {
 		SumClauseContext _localctx = new SumClauseContext(_ctx, getState());
-		enterRule(_localctx, 36, RULE_sumClause);
+		enterRule(_localctx, 38, RULE_sumClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(164);
+			setState(172);
 			match(K_SUM);
-			setState(165);
+			setState(173);
 			match(K_LPAREN);
-			setState(166);
+			setState(174);
 			expr();
-			setState(167);
+			setState(175);
 			match(K_RPAREN);
 			}
 		}
@@ -1083,6 +1314,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_exprRight; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterExprRight(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitExprRight(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitExprRight(this);
 			else return visitor.visitChildren(this);
@@ -1091,12 +1330,12 @@ public class AtlasDSLParser extends Parser {
 
 	public final ExprRightContext exprRight() throws RecognitionException {
 		ExprRightContext _localctx = new ExprRightContext(_ctx, getState());
-		enterRule(_localctx, 38, RULE_exprRight);
+		enterRule(_localctx, 40, RULE_exprRight);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(169);
+			setState(177);
 			_la = _input.LA(1);
 			if ( !(_la==K_AND || _la==K_OR) ) {
 			_errHandler.recoverInline(this);
@@ -1106,7 +1345,7 @@ public class AtlasDSLParser extends Parser {
 				_errHandler.reportMatch(this);
 				consume();
 			}
-			setState(170);
+			setState(178);
 			compE();
 			}
 		}
@@ -1146,11 +1385,22 @@ public class AtlasDSLParser extends Parser {
 		public SumClauseContext sumClause() {
 			return getRuleContext(SumClauseContext.class,0);
 		}
+		public HasTermClauseContext hasTermClause() {
+			return getRuleContext(HasTermClauseContext.class,0);
+		}
 		public CompEContext(ParserRuleContext parent, int invokingState) {
 			super(parent, invokingState);
 		}
 		@Override public int getRuleIndex() { return RULE_compE; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterCompE(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitCompE(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitCompE(this);
 			else return visitor.visitChildren(this);
@@ -1159,67 +1409,74 @@ public class AtlasDSLParser extends Parser {
 
 	public final CompEContext compE() throws RecognitionException {
 		CompEContext _localctx = new CompEContext(_ctx, getState());
-		enterRule(_localctx, 40, RULE_compE);
+		enterRule(_localctx, 42, RULE_compE);
 		try {
-			setState(180);
+			setState(189);
 			_errHandler.sync(this);
-			switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) {
+			switch ( getInterpreter().adaptivePredict(_input,8,_ctx) ) {
 			case 1:
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(172);
+				setState(180);
 				comparisonClause();
 				}
 				break;
 			case 2:
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(173);
+				setState(181);
 				isClause();
 				}
 				break;
 			case 3:
 				enterOuterAlt(_localctx, 3);
 				{
-				setState(174);
+				setState(182);
 				hasClause();
 				}
 				break;
 			case 4:
 				enterOuterAlt(_localctx, 4);
 				{
-				setState(175);
+				setState(183);
 				arithE();
 				}
 				break;
 			case 5:
 				enterOuterAlt(_localctx, 5);
 				{
-				setState(176);
+				setState(184);
 				countClause();
 				}
 				break;
 			case 6:
 				enterOuterAlt(_localctx, 6);
 				{
-				setState(177);
+				setState(185);
 				maxClause();
 				}
 				break;
 			case 7:
 				enterOuterAlt(_localctx, 7);
 				{
-				setState(178);
+				setState(186);
 				minClause();
 				}
 				break;
 			case 8:
 				enterOuterAlt(_localctx, 8);
 				{
-				setState(179);
+				setState(187);
 				sumClause();
 				}
 				break;
+			case 9:
+				enterOuterAlt(_localctx, 9);
+				{
+				setState(188);
+				hasTermClause();
+				}
+				break;
 			}
 		}
 		catch (RecognitionException re) {
@@ -1248,6 +1505,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_expr; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterExpr(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitExpr(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitExpr(this);
 			else return visitor.visitChildren(this);
@@ -1256,26 +1521,28 @@ public class AtlasDSLParser extends Parser {
 
 	public final ExprContext expr() throws RecognitionException {
 		ExprContext _localctx = new ExprContext(_ctx, getState());
-		enterRule(_localctx, 42, RULE_expr);
-		int _la;
+		enterRule(_localctx, 44, RULE_expr);
 		try {
+			int _alt;
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(182);
+			setState(191);
 			compE();
-			setState(186);
+			setState(195);
 			_errHandler.sync(this);
-			_la = _input.LA(1);
-			while (_la==K_AND || _la==K_OR) {
-				{
-				{
-				setState(183);
-				exprRight();
-				}
+			_alt = getInterpreter().adaptivePredict(_input,9,_ctx);
+			while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
+				if ( _alt==1 ) {
+					{
+					{
+					setState(192);
+					exprRight();
+					}
+					}
 				}
-				setState(188);
+				setState(197);
 				_errHandler.sync(this);
-				_la = _input.LA(1);
+				_alt = getInterpreter().adaptivePredict(_input,9,_ctx);
 			}
 			}
 		}
@@ -1302,6 +1569,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_limitOffset; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterLimitOffset(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitLimitOffset(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitLimitOffset(this);
 			else return visitor.visitChildren(this);
@@ -1310,19 +1585,19 @@ public class AtlasDSLParser extends Parser {
 
 	public final LimitOffsetContext limitOffset() throws RecognitionException {
 		LimitOffsetContext _localctx = new LimitOffsetContext(_ctx, getState());
-		enterRule(_localctx, 44, RULE_limitOffset);
+		enterRule(_localctx, 46, RULE_limitOffset);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(189);
+			setState(198);
 			limitClause();
-			setState(191);
+			setState(200);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			if (_la==K_OFFSET) {
 				{
-				setState(190);
+				setState(199);
 				offsetClause();
 				}
 			}
@@ -1353,6 +1628,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_selectExpression; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterSelectExpression(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitSelectExpression(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitSelectExpression(this);
 			else return visitor.visitChildren(this);
@@ -1361,21 +1644,21 @@ public class AtlasDSLParser extends Parser {
 
 	public final SelectExpressionContext selectExpression() throws RecognitionException {
 		SelectExpressionContext _localctx = new SelectExpressionContext(_ctx, getState());
-		enterRule(_localctx, 46, RULE_selectExpression);
+		enterRule(_localctx, 48, RULE_selectExpression);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(193);
+			setState(202);
 			expr();
-			setState(196);
+			setState(205);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			if (_la==K_AS) {
 				{
-				setState(194);
+				setState(203);
 				match(K_AS);
-				setState(195);
+				setState(204);
 				identifier();
 				}
 			}
@@ -1409,6 +1692,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_selectExpr; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterSelectExpr(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitSelectExpr(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitSelectExpr(this);
 			else return visitor.visitChildren(this);
@@ -1417,26 +1708,26 @@ public class AtlasDSLParser extends Parser {
 
 	public final SelectExprContext selectExpr() throws RecognitionException {
 		SelectExprContext _localctx = new SelectExprContext(_ctx, getState());
-		enterRule(_localctx, 48, RULE_selectExpr);
+		enterRule(_localctx, 50, RULE_selectExpr);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(198);
+			setState(207);
 			selectExpression();
-			setState(203);
+			setState(212);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			while (_la==K_COMMA) {
 				{
 				{
-				setState(199);
+				setState(208);
 				match(K_COMMA);
-				setState(200);
+				setState(209);
 				selectExpression();
 				}
 				}
-				setState(205);
+				setState(214);
 				_errHandler.sync(this);
 				_la = _input.LA(1);
 			}
@@ -1469,6 +1760,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_aliasExpr; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterAliasExpr(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitAliasExpr(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitAliasExpr(this);
 			else return visitor.visitChildren(this);
@@ -1477,29 +1776,29 @@ public class AtlasDSLParser extends Parser {
 
 	public final AliasExprContext aliasExpr() throws RecognitionException {
 		AliasExprContext _localctx = new AliasExprContext(_ctx, getState());
-		enterRule(_localctx, 50, RULE_aliasExpr);
+		enterRule(_localctx, 52, RULE_aliasExpr);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(208);
+			setState(217);
 			_errHandler.sync(this);
-			switch ( getInterpreter().adaptivePredict(_input,12,_ctx) ) {
+			switch ( getInterpreter().adaptivePredict(_input,13,_ctx) ) {
 			case 1:
 				{
-				setState(206);
+				setState(215);
 				identifier();
 				}
 				break;
 			case 2:
 				{
-				setState(207);
+				setState(216);
 				literal();
 				}
 				break;
 			}
-			setState(210);
+			setState(219);
 			match(K_AS);
-			setState(211);
+			setState(220);
 			identifier();
 			}
 		}
@@ -1527,6 +1826,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_orderByExpr; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterOrderByExpr(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitOrderByExpr(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitOrderByExpr(this);
 			else return visitor.visitChildren(this);
@@ -1535,21 +1842,21 @@ public class AtlasDSLParser extends Parser {
 
 	public final OrderByExprContext orderByExpr() throws RecognitionException {
 		OrderByExprContext _localctx = new OrderByExprContext(_ctx, getState());
-		enterRule(_localctx, 52, RULE_orderByExpr);
+		enterRule(_localctx, 54, RULE_orderByExpr);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(213);
+			setState(222);
 			match(K_ORDERBY);
-			setState(214);
+			setState(223);
 			expr();
-			setState(216);
+			setState(225);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			if (_la==K_ASC || _la==K_DESC) {
 				{
-				setState(215);
+				setState(224);
 				sortOrder();
 				}
 			}
@@ -1582,6 +1889,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_fromSrc; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterFromSrc(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitFromSrc(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitFromSrc(this);
 			else return visitor.visitChildren(this);
@@ -1590,33 +1905,33 @@ public class AtlasDSLParser extends Parser {
 
 	public final FromSrcContext fromSrc() throws RecognitionException {
 		FromSrcContext _localctx = new FromSrcContext(_ctx, getState());
-		enterRule(_localctx, 54, RULE_fromSrc);
+		enterRule(_localctx, 56, RULE_fromSrc);
 		try {
-			setState(223);
+			setState(232);
 			_errHandler.sync(this);
-			switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) {
+			switch ( getInterpreter().adaptivePredict(_input,16,_ctx) ) {
 			case 1:
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(218);
+				setState(227);
 				aliasExpr();
 				}
 				break;
 			case 2:
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(221);
+				setState(230);
 				_errHandler.sync(this);
-				switch ( getInterpreter().adaptivePredict(_input,14,_ctx) ) {
+				switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) {
 				case 1:
 					{
-					setState(219);
+					setState(228);
 					identifier();
 					}
 					break;
 				case 2:
 					{
-					setState(220);
+					setState(229);
 					literal();
 					}
 					break;
@@ -1646,6 +1961,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_whereClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterWhereClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitWhereClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitWhereClause(this);
 			else return visitor.visitChildren(this);
@@ -1654,13 +1977,13 @@ public class AtlasDSLParser extends Parser {
 
 	public final WhereClauseContext whereClause() throws RecognitionException {
 		WhereClauseContext _localctx = new WhereClauseContext(_ctx, getState());
-		enterRule(_localctx, 56, RULE_whereClause);
+		enterRule(_localctx, 58, RULE_whereClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(225);
+			setState(234);
 			match(K_WHERE);
-			setState(226);
+			setState(235);
 			expr();
 			}
 		}
@@ -1687,6 +2010,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_fromExpression; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterFromExpression(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitFromExpression(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitFromExpression(this);
 			else return visitor.visitChildren(this);
@@ -1695,18 +2026,18 @@ public class AtlasDSLParser extends Parser {
 
 	public final FromExpressionContext fromExpression() throws RecognitionException {
 		FromExpressionContext _localctx = new FromExpressionContext(_ctx, getState());
-		enterRule(_localctx, 58, RULE_fromExpression);
+		enterRule(_localctx, 60, RULE_fromExpression);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(228);
+			setState(237);
 			fromSrc();
-			setState(230);
+			setState(239);
 			_errHandler.sync(this);
-			switch ( getInterpreter().adaptivePredict(_input,16,_ctx) ) {
+			switch ( getInterpreter().adaptivePredict(_input,17,_ctx) ) {
 			case 1:
 				{
-				setState(229);
+				setState(238);
 				whereClause();
 				}
 				break;
@@ -1734,6 +2065,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_fromClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterFromClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitFromClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitFromClause(this);
 			else return visitor.visitChildren(this);
@@ -1742,13 +2081,13 @@ public class AtlasDSLParser extends Parser {
 
 	public final FromClauseContext fromClause() throws RecognitionException {
 		FromClauseContext _localctx = new FromClauseContext(_ctx, getState());
-		enterRule(_localctx, 60, RULE_fromClause);
+		enterRule(_localctx, 62, RULE_fromClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(232);
+			setState(241);
 			match(K_FROM);
-			setState(233);
+			setState(242);
 			fromExpression();
 			}
 		}
@@ -1773,6 +2112,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_selectClause; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterSelectClause(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitSelectClause(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitSelectClause(this);
 			else return visitor.visitChildren(this);
@@ -1781,13 +2128,13 @@ public class AtlasDSLParser extends Parser {
 
 	public final SelectClauseContext selectClause() throws RecognitionException {
 		SelectClauseContext _localctx = new SelectClauseContext(_ctx, getState());
-		enterRule(_localctx, 62, RULE_selectClause);
+		enterRule(_localctx, 64, RULE_selectClause);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(235);
+			setState(244);
 			match(K_SELECT);
-			setState(236);
+			setState(245);
 			selectExpr();
 			}
 		}
@@ -1820,6 +2167,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_singleQrySrc; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterSingleQrySrc(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitSingleQrySrc(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitSingleQrySrc(this);
 			else return visitor.visitChildren(this);
@@ -1828,36 +2183,36 @@ public class AtlasDSLParser extends Parser {
 
 	public final SingleQrySrcContext singleQrySrc() throws RecognitionException {
 		SingleQrySrcContext _localctx = new SingleQrySrcContext(_ctx, getState());
-		enterRule(_localctx, 64, RULE_singleQrySrc);
+		enterRule(_localctx, 66, RULE_singleQrySrc);
 		try {
-			setState(242);
+			setState(251);
 			_errHandler.sync(this);
-			switch ( getInterpreter().adaptivePredict(_input,17,_ctx) ) {
+			switch ( getInterpreter().adaptivePredict(_input,18,_ctx) ) {
 			case 1:
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(238);
+				setState(247);
 				fromClause();
 				}
 				break;
 			case 2:
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(239);
+				setState(248);
 				whereClause();
 				}
 				break;
 			case 3:
 				enterOuterAlt(_localctx, 3);
 				{
-				setState(240);
+				setState(249);
 				fromExpression();
 				}
 				break;
 			case 4:
 				enterOuterAlt(_localctx, 4);
 				{
-				setState(241);
+				setState(250);
 				expr();
 				}
 				break;
@@ -1886,6 +2241,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_groupByExpression; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterGroupByExpression(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitGroupByExpression(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitGroupByExpression(this);
 			else return visitor.visitChildren(this);
@@ -1894,17 +2257,17 @@ public class AtlasDSLParser extends Parser {
 
 	public final GroupByExpressionContext groupByExpression() throws RecognitionException {
 		GroupByExpressionContext _localctx = new GroupByExpressionContext(_ctx, getState());
-		enterRule(_localctx, 66, RULE_groupByExpression);
+		enterRule(_localctx, 68, RULE_groupByExpression);
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(244);
+			setState(253);
 			match(K_GROUPBY);
-			setState(245);
+			setState(254);
 			match(K_LPAREN);
-			setState(246);
+			setState(255);
 			selectExpr();
-			setState(247);
+			setState(256);
 			match(K_RPAREN);
 			}
 		}
@@ -1935,6 +2298,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_commaDelimitedQueries; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterCommaDelimitedQueries(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitCommaDelimitedQueries(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitCommaDelimitedQueries(this);
 			else return visitor.visitChildren(this);
@@ -1943,26 +2314,26 @@ public class AtlasDSLParser extends Parser {
 
 	public final CommaDelimitedQueriesContext commaDelimitedQueries() throws RecognitionException {
 		CommaDelimitedQueriesContext _localctx = new CommaDelimitedQueriesContext(_ctx, getState());
-		enterRule(_localctx, 68, RULE_commaDelimitedQueries);
+		enterRule(_localctx, 70, RULE_commaDelimitedQueries);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(249);
+			setState(258);
 			singleQrySrc();
-			setState(254);
+			setState(263);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			while (_la==K_COMMA) {
 				{
 				{
-				setState(250);
+				setState(259);
 				match(K_COMMA);
-				setState(251);
+				setState(260);
 				singleQrySrc();
 				}
 				}
-				setState(256);
+				setState(265);
 				_errHandler.sync(this);
 				_la = _input.LA(1);
 			}
@@ -1991,6 +2362,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_spaceDelimitedQueries; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterSpaceDelimitedQueries(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitSpaceDelimitedQueries(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitSpaceDelimitedQueries(this);
 			else return visitor.visitChildren(this);
@@ -1999,24 +2378,24 @@ public class AtlasDSLParser extends Parser {
 
 	public final SpaceDelimitedQueriesContext spaceDelimitedQueries() throws RecognitionException {
 		SpaceDelimitedQueriesContext _localctx = new SpaceDelimitedQueriesContext(_ctx, getState());
-		enterRule(_localctx, 70, RULE_spaceDelimitedQueries);
+		enterRule(_localctx, 72, RULE_spaceDelimitedQueries);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(257);
+			setState(266);
 			singleQrySrc();
-			setState(261);
+			setState(270);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << NUMBER) | (1L << FLOATING_NUMBER) | (1L << BOOL) | (1L << K_LPAREN) | (1L << K_LBRACKET) | (1L << K_FROM) | (1L << K_WHERE) | (1L << K_MAX) | (1L << K_MIN) | (1L << K_SUM) | (1L << K_COUNT) | (1L << ID))) != 0)) {
 				{
 				{
-				setState(258);
+				setState(267);
 				singleQrySrc();
 				}
 				}
-				setState(263);
+				setState(272);
 				_errHandler.sync(this);
 				_la = _input.LA(1);
 			}
@@ -2045,6 +2424,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_querySrc; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterQuerySrc(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitQuerySrc(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitQuerySrc(this);
 			else return visitor.visitChildren(this);
@@ -2053,22 +2440,22 @@ public class AtlasDSLParser extends Parser {
 
 	public final QuerySrcContext querySrc() throws RecognitionException {
 		QuerySrcContext _localctx = new QuerySrcContext(_ctx, getState());
-		enterRule(_localctx, 72, RULE_querySrc);
+		enterRule(_localctx, 74, RULE_querySrc);
 		try {
-			setState(266);
+			setState(275);
 			_errHandler.sync(this);
-			switch ( getInterpreter().adaptivePredict(_input,20,_ctx) ) {
+			switch ( getInterpreter().adaptivePredict(_input,21,_ctx) ) {
 			case 1:
 				enterOuterAlt(_localctx, 1);
 				{
-				setState(264);
+				setState(273);
 				commaDelimitedQueries();
 				}
 				break;
 			case 2:
 				enterOuterAlt(_localctx, 2);
 				{
-				setState(265);
+				setState(274);
 				spaceDelimitedQueries();
 				}
 				break;
@@ -2107,6 +2494,14 @@ public class AtlasDSLParser extends Parser {
 		}
 		@Override public int getRuleIndex() { return RULE_query; }
 		@Override
+		public void enterRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).enterQuery(this);
+		}
+		@Override
+		public void exitRule(ParseTreeListener listener) {
+			if ( listener instanceof AtlasDSLParserListener ) ((AtlasDSLParserListener)listener).exitQuery(this);
+		}
+		@Override
 		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 			if ( visitor instanceof AtlasDSLParserVisitor ) return ((AtlasDSLParserVisitor<? extends T>)visitor).visitQuery(this);
 			else return visitor.visitChildren(this);
@@ -2115,54 +2510,54 @@ public class AtlasDSLParser extends Parser {
 
 	public final QueryContext query() throws RecognitionException {
 		QueryContext _localctx = new QueryContext(_ctx, getState());
-		enterRule(_localctx, 74, RULE_query);
+		enterRule(_localctx, 76, RULE_query);
 		int _la;
 		try {
 			enterOuterAlt(_localctx, 1);
 			{
-			setState(268);
+			setState(277);
 			querySrc();
-			setState(270);
+			setState(279);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			if (_la==K_GROUPBY) {
 				{
-				setState(269);
+				setState(278);
 				groupByExpression();
 				}
 			}
 
-			setState(273);
+			setState(282);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			if (_la==K_SELECT) {
 				{
-				setState(272);
+				setState(281);
 				selectClause();
 				}
 			}
 
-			setState(276);
+			setState(285);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			if (_la==K_ORDERBY) {
 				{
-				setState(275);
+				setState(284);
 				orderByExpr();
 				}
 			}
 
-			setState(279);
+			setState(288);
 			_errHandler.sync(this);
 			_la = _input.LA(1);
 			if (_la==K_LIMIT) {
 				{
-				setState(278);
+				setState(287);
 				limitOffset();
 				}
 			}
 
-			setState(281);
+			setState(290);
 			match(EOF);
 			}
 		}
@@ -2178,99 +2573,102 @@ public class AtlasDSLParser extends Parser {
 	}
 
 	public static final String _serializedATN =
-		"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\61\u011e\4\2\t\2"+
+		"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\62\u0127\4\2\t\2"+
 		"\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
 		"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
 		"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
 		"\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+
-		"\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\3\2\3\2\3\3\3\3\3\4\3\4\3"+
-		"\5\3\5\3\5\3\5\7\5Y\n\5\f\5\16\5\\\13\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6\5"+
-		"\6e\n\6\5\6g\n\6\3\7\3\7\3\7\3\b\3\b\3\b\3\t\3\t\5\tq\n\t\3\t\3\t\3\t"+
-		"\3\t\5\tw\n\t\3\n\3\n\3\n\3\13\3\13\7\13~\n\13\f\13\16\13\u0081\13\13"+
-		"\3\f\3\f\3\f\3\r\3\r\7\r\u0088\n\r\f\r\16\r\u008b\13\r\3\16\3\16\3\16"+
-		"\3\16\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\22"+
-		"\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24"+
-		"\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\26\5\26\u00b7\n\26"+
-		"\3\27\3\27\7\27\u00bb\n\27\f\27\16\27\u00be\13\27\3\30\3\30\5\30\u00c2"+
-		"\n\30\3\31\3\31\3\31\5\31\u00c7\n\31\3\32\3\32\3\32\7\32\u00cc\n\32\f"+
-		"\32\16\32\u00cf\13\32\3\33\3\33\5\33\u00d3\n\33\3\33\3\33\3\33\3\34\3"+
-		"\34\3\34\5\34\u00db\n\34\3\35\3\35\3\35\5\35\u00e0\n\35\5\35\u00e2\n\35"+
-		"\3\36\3\36\3\36\3\37\3\37\5\37\u00e9\n\37\3 \3 \3 \3!\3!\3!\3\"\3\"\3"+
-		"\"\3\"\5\"\u00f5\n\"\3#\3#\3#\3#\3#\3$\3$\3$\7$\u00ff\n$\f$\16$\u0102"+
-		"\13$\3%\3%\7%\u0106\n%\f%\16%\u0109\13%\3&\3&\5&\u010d\n&\3\'\3\'\5\'"+
-		"\u0111\n\'\3\'\5\'\u0114\n\'\3\'\5\'\u0117\n\'\3\'\5\'\u011a\n\'\3\'\3"+
-		"\'\3\'\2\2(\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\66"+
-		"8:<>@BDFHJL\2\b\4\2\17\17\26\33\3\2+,\3\2\f\r\3\2\n\13\3\2()\3\2\20\21"+
-		"\2\u011a\2N\3\2\2\2\4P\3\2\2\2\6R\3\2\2\2\bT\3\2\2\2\nf\3\2\2\2\fh\3\2"+
-		"\2\2\16k\3\2\2\2\20v\3\2\2\2\22x\3\2\2\2\24{\3\2\2\2\26\u0082\3\2\2\2"+
-		"\30\u0085\3\2\2\2\32\u008c\3\2\2\2\34\u0090\3\2\2\2\36\u0094\3\2\2\2 "+
-		"\u0098\3\2\2\2\"\u009c\3\2\2\2$\u00a1\3\2\2\2&\u00a6\3\2\2\2(\u00ab\3"+
-		"\2\2\2*\u00b6\3\2\2\2,\u00b8\3\2\2\2.\u00bf\3\2\2\2\60\u00c3\3\2\2\2\62"+
-		"\u00c8\3\2\2\2\64\u00d2\3\2\2\2\66\u00d7\3\2\2\28\u00e1\3\2\2\2:\u00e3"+
-		"\3\2\2\2<\u00e6\3\2\2\2>\u00ea\3\2\2\2@\u00ed\3\2\2\2B\u00f4\3\2\2\2D"+
-		"\u00f6\3\2\2\2F\u00fb\3\2\2\2H\u0103\3\2\2\2J\u010c\3\2\2\2L\u010e\3\2"+
-		"\2\2NO\7\60\2\2O\3\3\2\2\2PQ\t\2\2\2Q\5\3\2\2\2RS\t\3\2\2S\7\3\2\2\2T"+
-		"U\7\23\2\2UZ\7\60\2\2VW\7\t\2\2WY\7\60\2\2XV\3\2\2\2Y\\\3\2\2\2ZX\3\2"+
-		"\2\2Z[\3\2\2\2[]\3\2\2\2\\Z\3\2\2\2]^\7\25\2\2^\t\3\2\2\2_g\7\b\2\2`g"+
-		"\7\6\2\2ag\7\7\2\2be\7\60\2\2ce\5\b\5\2db\3\2\2\2dc\3\2\2\2eg\3\2\2\2"+
-		"f_\3\2\2\2f`\3\2\2\2fa\3\2\2\2fd\3\2\2\2g\13\3\2\2\2hi\7 \2\2ij\7\6\2"+
-		"\2j\r\3\2\2\2kl\7&\2\2lm\7\6\2\2m\17\3\2\2\2nq\5\2\2\2oq\5\n\6\2pn\3\2"+
-		"\2\2po\3\2\2\2qw\3\2\2\2rs\7\22\2\2st\5,\27\2tu\7\24\2\2uw\3\2\2\2vp\3"+
-		"\2\2\2vr\3\2\2\2w\21\3\2\2\2xy\t\4\2\2yz\5\20\t\2z\23\3\2\2\2{\177\5\20"+
-		"\t\2|~\5\22\n\2}|\3\2\2\2~\u0081\3\2\2\2\177}\3\2\2\2\177\u0080\3\2\2"+
-		"\2\u0080\25\3\2\2\2\u0081\177\3\2\2\2\u0082\u0083\t\5\2\2\u0083\u0084"+
-		"\5\24\13\2\u0084\27\3\2\2\2\u0085\u0089\5\24\13\2\u0086\u0088\5\26\f\2"+
-		"\u0087\u0086\3\2\2\2\u0088\u008b\3\2\2\2\u0089\u0087\3\2\2\2\u0089\u008a"+
-		"\3\2\2\2\u008a\31\3\2\2\2\u008b\u0089\3\2\2\2\u008c\u008d\5\30\r\2\u008d"+
-		"\u008e\5\4\3\2\u008e\u008f\5\30\r\2\u008f\33\3\2\2\2\u0090\u0091\5\30"+
-		"\r\2\u0091\u0092\t\6\2\2\u0092\u0093\5\2\2\2\u0093\35\3\2\2\2\u0094\u0095"+
-		"\5\30\r\2\u0095\u0096\7*\2\2\u0096\u0097\5\2\2\2\u0097\37\3\2\2\2\u0098"+
-		"\u0099\7%\2\2\u0099\u009a\7\22\2\2\u009a\u009b\7\24\2\2\u009b!\3\2\2\2"+
-		"\u009c\u009d\7\"\2\2\u009d\u009e\7\22\2\2\u009e\u009f\5,\27\2\u009f\u00a0"+
-		"\7\24\2\2\u00a0#\3\2\2\2\u00a1\u00a2\7#\2\2\u00a2\u00a3\7\22\2\2\u00a3"+
-		"\u00a4\5,\27\2\u00a4\u00a5\7\24\2\2\u00a5%\3\2\2\2\u00a6\u00a7\7$\2\2"+
-		"\u00a7\u00a8\7\22\2\2\u00a8\u00a9\5,\27\2\u00a9\u00aa\7\24\2\2\u00aa\'"+
-		"\3\2\2\2\u00ab\u00ac\t\7\2\2\u00ac\u00ad\5*\26\2\u00ad)\3\2\2\2\u00ae"+
-		"\u00b7\5\32\16\2\u00af\u00b7\5\34\17\2\u00b0\u00b7\5\36\20\2\u00b1\u00b7"+
-		"\5\30\r\2\u00b2\u00b7\5 \21\2\u00b3\u00b7\5\"\22\2\u00b4\u00b7\5$\23\2"+
-		"\u00b5\u00b7\5&\24\2\u00b6\u00ae\3\2\2\2\u00b6\u00af\3\2\2\2\u00b6\u00b0"+
-		"\3\2\2\2\u00b6\u00b1\3\2\2\2\u00b6\u00b2\3\2\2\2\u00b6\u00b3\3\2\2\2\u00b6"+
-		"\u00b4\3\2\2\2\u00b6\u00b5\3\2\2\2\u00b7+\3\2\2\2\u00b8\u00bc\5*\26\2"+
-		"\u00b9\u00bb\5(\25\2\u00ba\u00b9\3\2\2\2\u00bb\u00be\3\2\2\2\u00bc\u00ba"+
-		"\3\2\2\2\u00bc\u00bd\3\2\2\2\u00bd-\3\2\2\2\u00be\u00bc\3\2\2\2\u00bf"+
-		"\u00c1\5\f\7\2\u00c0\u00c2\5\16\b\2\u00c1\u00c0\3\2\2\2\u00c1\u00c2\3"+
-		"\2\2\2\u00c2/\3\2\2\2\u00c3\u00c6\5,\27\2\u00c4\u00c5\7\'\2\2\u00c5\u00c7"+
-		"\5\2\2\2\u00c6\u00c4\3\2\2\2\u00c6\u00c7\3\2\2\2\u00c7\61\3\2\2\2\u00c8"+
-		"\u00cd\5\60\31\2\u00c9\u00ca\7\t\2\2\u00ca\u00cc\5\60\31\2\u00cb\u00c9"+
-		"\3\2\2\2\u00cc\u00cf\3\2\2\2\u00cd\u00cb\3\2\2\2\u00cd\u00ce\3\2\2\2\u00ce"+
-		"\63\3\2\2\2\u00cf\u00cd\3\2\2\2\u00d0\u00d3\5\2\2\2\u00d1\u00d3\5\n\6"+
-		"\2\u00d2\u00d0\3\2\2\2\u00d2\u00d1\3\2\2\2\u00d3\u00d4\3\2\2\2\u00d4\u00d5"+
-		"\7\'\2\2\u00d5\u00d6\5\2\2\2\u00d6\65\3\2\2\2\u00d7\u00d8\7\36\2\2\u00d8"+
-		"\u00da\5,\27\2\u00d9\u00db\5\6\4\2\u00da\u00d9\3\2\2\2\u00da\u00db\3\2"+
-		"\2\2\u00db\67\3\2\2\2\u00dc\u00e2\5\64\33\2\u00dd\u00e0\5\2\2\2\u00de"+
-		"\u00e0\5\n\6\2\u00df\u00dd\3\2\2\2\u00df\u00de\3\2\2\2\u00e0\u00e2\3\2"+
-		"\2\2\u00e1\u00dc\3\2\2\2\u00e1\u00df\3\2\2\2\u00e29\3\2\2\2\u00e3\u00e4"+
-		"\7\35\2\2\u00e4\u00e5\5,\27\2\u00e5;\3\2\2\2\u00e6\u00e8\58\35\2\u00e7"+
-		"\u00e9\5:\36\2\u00e8\u00e7\3\2\2\2\u00e8\u00e9\3\2\2\2\u00e9=\3\2\2\2"+
-		"\u00ea\u00eb\7\34\2\2\u00eb\u00ec\5<\37\2\u00ec?\3\2\2\2\u00ed\u00ee\7"+
-		"!\2\2\u00ee\u00ef\5\62\32\2\u00efA\3\2\2\2\u00f0\u00f5\5> \2\u00f1\u00f5"+
-		"\5:\36\2\u00f2\u00f5\5<\37\2\u00f3\u00f5\5,\27\2\u00f4\u00f0\3\2\2\2\u00f4"+
-		"\u00f1\3\2\2\2\u00f4\u00f2\3\2\2\2\u00f4\u00f3\3\2\2\2\u00f5C\3\2\2\2"+
-		"\u00f6\u00f7\7\37\2\2\u00f7\u00f8\7\22\2\2\u00f8\u00f9\5\62\32\2\u00f9"+
-		"\u00fa\7\24\2\2\u00faE\3\2\2\2\u00fb\u0100\5B\"\2\u00fc\u00fd\7\t\2\2"+
-		"\u00fd\u00ff\5B\"\2\u00fe\u00fc\3\2\2\2\u00ff\u0102\3\2\2\2\u0100\u00fe"+
-		"\3\2\2\2\u0100\u0101\3\2\2\2\u0101G\3\2\2\2\u0102\u0100\3\2\2\2\u0103"+
-		"\u0107\5B\"\2\u0104\u0106\5B\"\2\u0105\u0104\3\2\2\2\u0106\u0109\3\2\2"+
-		"\2\u0107\u0105\3\2\2\2\u0107\u0108\3\2\2\2\u0108I\3\2\2\2\u0109\u0107"+
-		"\3\2\2\2\u010a\u010d\5F$\2\u010b\u010d\5H%\2\u010c\u010a\3\2\2\2\u010c"+
-		"\u010b\3\2\2\2\u010dK\3\2\2\2\u010e\u0110\5J&\2\u010f\u0111\5D#\2\u0110"+
-		"\u010f\3\2\2\2\u0110\u0111\3\2\2\2\u0111\u0113\3\2\2\2\u0112\u0114\5@"+
-		"!\2\u0113\u0112\3\2\2\2\u0113\u0114\3\2\2\2\u0114\u0116\3\2\2\2\u0115"+
-		"\u0117\5\66\34\2\u0116\u0115\3\2\2\2\u0116\u0117\3\2\2\2\u0117\u0119\3"+
-		"\2\2\2\u0118\u011a\5.\30\2\u0119\u0118\3\2\2\2\u0119\u011a\3\2\2\2\u011a"+
-		"\u011b\3\2\2\2\u011b\u011c\7\2\2\3\u011cM\3\2\2\2\33Zdfpv\177\u0089\u00b6"+
-		"\u00bc\u00c1\u00c6\u00cd\u00d2\u00da\u00df\u00e1\u00e8\u00f4\u0100\u0107"+
-		"\u010c\u0110\u0113\u0116\u0119";
+		"\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\3\2\3\2\3\3\3\3\3\4"+
+		"\3\4\3\5\3\5\3\5\3\5\7\5[\n\5\f\5\16\5^\13\5\3\5\3\5\3\6\3\6\3\6\3\6\3"+
+		"\6\5\6g\n\6\5\6i\n\6\3\7\3\7\3\7\3\b\3\b\3\b\3\t\3\t\5\ts\n\t\3\t\3\t"+
+		"\3\t\3\t\5\ty\n\t\3\n\3\n\3\n\3\13\3\13\7\13\u0080\n\13\f\13\16\13\u0083"+
+		"\13\13\3\f\3\f\3\f\3\r\3\r\7\r\u008a\n\r\f\r\16\r\u008d\13\r\3\16\3\16"+
+		"\3\16\3\16\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\5\20\u009b\n\20\3\21"+
+		"\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\24\3\24"+
+		"\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\27\3\27\3\27"+
+		"\3\27\3\27\3\27\3\27\3\27\3\27\5\27\u00c0\n\27\3\30\3\30\7\30\u00c4\n"+
+		"\30\f\30\16\30\u00c7\13\30\3\31\3\31\5\31\u00cb\n\31\3\32\3\32\3\32\5"+
+		"\32\u00d0\n\32\3\33\3\33\3\33\7\33\u00d5\n\33\f\33\16\33\u00d8\13\33\3"+
+		"\34\3\34\5\34\u00dc\n\34\3\34\3\34\3\34\3\35\3\35\3\35\5\35\u00e4\n\35"+
+		"\3\36\3\36\3\36\5\36\u00e9\n\36\5\36\u00eb\n\36\3\37\3\37\3\37\3 \3 \5"+
+		" \u00f2\n \3!\3!\3!\3\"\3\"\3\"\3#\3#\3#\3#\5#\u00fe\n#\3$\3$\3$\3$\3"+
+		"$\3%\3%\3%\7%\u0108\n%\f%\16%\u010b\13%\3&\3&\7&\u010f\n&\f&\16&\u0112"+
+		"\13&\3\'\3\'\5\'\u0116\n\'\3(\3(\5(\u011a\n(\3(\5(\u011d\n(\3(\5(\u0120"+
+		"\n(\3(\5(\u0123\n(\3(\3(\3(\2\2)\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36"+
+		" \"$&(*,.\60\62\64\668:<>@BDFHJLN\2\b\4\2\17\17\26\33\3\2+,\3\2\f\r\3"+
+		"\2\n\13\3\2()\3\2\20\21\2\u0124\2P\3\2\2\2\4R\3\2\2\2\6T\3\2\2\2\bV\3"+
+		"\2\2\2\nh\3\2\2\2\fj\3\2\2\2\16m\3\2\2\2\20x\3\2\2\2\22z\3\2\2\2\24}\3"+
+		"\2\2\2\26\u0084\3\2\2\2\30\u0087\3\2\2\2\32\u008e\3\2\2\2\34\u0092\3\2"+
+		"\2\2\36\u0096\3\2\2\2 \u009c\3\2\2\2\"\u00a0\3\2\2\2$\u00a4\3\2\2\2&\u00a9"+
+		"\3\2\2\2(\u00ae\3\2\2\2*\u00b3\3\2\2\2,\u00bf\3\2\2\2.\u00c1\3\2\2\2\60"+
+		"\u00c8\3\2\2\2\62\u00cc\3\2\2\2\64\u00d1\3\2\2\2\66\u00db\3\2\2\28\u00e0"+
+		"\3\2\2\2:\u00ea\3\2\2\2<\u00ec\3\2\2\2>\u00ef\3\2\2\2@\u00f3\3\2\2\2B"+
+		"\u00f6\3\2\2\2D\u00fd\3\2\2\2F\u00ff\3\2\2\2H\u0104\3\2\2\2J\u010c\3\2"+
+		"\2\2L\u0115\3\2\2\2N\u0117\3\2\2\2PQ\7\61\2\2Q\3\3\2\2\2RS\t\2\2\2S\5"+
+		"\3\2\2\2TU\t\3\2\2U\7\3\2\2\2VW\7\23\2\2W\\\7\61\2\2XY\7\t\2\2Y[\7\61"+
+		"\2\2ZX\3\2\2\2[^\3\2\2\2\\Z\3\2\2\2\\]\3\2\2\2]_\3\2\2\2^\\\3\2\2\2_`"+
+		"\7\25\2\2`\t\3\2\2\2ai\7\b\2\2bi\7\6\2\2ci\7\7\2\2dg\7\61\2\2eg\5\b\5"+
+		"\2fd\3\2\2\2fe\3\2\2\2gi\3\2\2\2ha\3\2\2\2hb\3\2\2\2hc\3\2\2\2hf\3\2\2"+
+		"\2i\13\3\2\2\2jk\7 \2\2kl\7\6\2\2l\r\3\2\2\2mn\7&\2\2no\7\6\2\2o\17\3"+
+		"\2\2\2ps\5\2\2\2qs\5\n\6\2rp\3\2\2\2rq\3\2\2\2sy\3\2\2\2tu\7\22\2\2uv"+
+		"\5.\30\2vw\7\24\2\2wy\3\2\2\2xr\3\2\2\2xt\3\2\2\2y\21\3\2\2\2z{\t\4\2"+
+		"\2{|\5\20\t\2|\23\3\2\2\2}\u0081\5\20\t\2~\u0080\5\22\n\2\177~\3\2\2\2"+
+		"\u0080\u0083\3\2\2\2\u0081\177\3\2\2\2\u0081\u0082\3\2\2\2\u0082\25\3"+
+		"\2\2\2\u0083\u0081\3\2\2\2\u0084\u0085\t\5\2\2\u0085\u0086\5\24\13\2\u0086"+
+		"\27\3\2\2\2\u0087\u008b\5\24\13\2\u0088\u008a\5\26\f\2\u0089\u0088\3\2"+
+		"\2\2\u008a\u008d\3\2\2\2\u008b\u0089\3\2\2\2\u008b\u008c\3\2\2\2\u008c"+
+		"\31\3\2\2\2\u008d\u008b\3\2\2\2\u008e\u008f\5\30\r\2\u008f\u0090\5\4\3"+
+		"\2\u0090\u0091\5\30\r\2\u0091\33\3\2\2\2\u0092\u0093\5\30\r\2\u0093\u0094"+
+		"\t\6\2\2\u0094\u0095\5\2\2\2\u0095\35\3\2\2\2\u0096\u0097\5\30\r\2\u0097"+
+		"\u009a\7/\2\2\u0098\u009b\5\2\2\2\u0099\u009b\5.\30\2\u009a\u0098\3\2"+
+		"\2\2\u009a\u0099\3\2\2\2\u009b\37\3\2\2\2\u009c\u009d\5\30\r\2\u009d\u009e"+
+		"\7*\2\2\u009e\u009f\5\2\2\2\u009f!\3\2\2\2\u00a0\u00a1\7%\2\2\u00a1\u00a2"+
+		"\7\22\2\2\u00a2\u00a3\7\24\2\2\u00a3#\3\2\2\2\u00a4\u00a5\7\"\2\2\u00a5"+
+		"\u00a6\7\22\2\2\u00a6\u00a7\5.\30\2\u00a7\u00a8\7\24\2\2\u00a8%\3\2\2"+
+		"\2\u00a9\u00aa\7#\2\2\u00aa\u00ab\7\22\2\2\u00ab\u00ac\5.\30\2\u00ac\u00ad"+
+		"\7\24\2\2\u00ad\'\3\2\2\2\u00ae\u00af\7$\2\2\u00af\u00b0\7\22\2\2\u00b0"+
+		"\u00b1\5.\30\2\u00b1\u00b2\7\24\2\2\u00b2)\3\2\2\2\u00b3\u00b4\t\7\2\2"+
+		"\u00b4\u00b5\5,\27\2\u00b5+\3\2\2\2\u00b6\u00c0\5\32\16\2\u00b7\u00c0"+
+		"\5\34\17\2\u00b8\u00c0\5 \21\2\u00b9\u00c0\5\30\r\2\u00ba\u00c0\5\"\22"+
+		"\2\u00bb\u00c0\5$\23\2\u00bc\u00c0\5&\24\2\u00bd\u00c0\5(\25\2\u00be\u00c0"+
+		"\5\36\20\2\u00bf\u00b6\3\2\2\2\u00bf\u00b7\3\2\2\2\u00bf\u00b8\3\2\2\2"+
+		"\u00bf\u00b9\3\2\2\2\u00bf\u00ba\3\2\2\2\u00bf\u00bb\3\2\2\2\u00bf\u00bc"+
+		"\3\2\2\2\u00bf\u00bd\3\2\2\2\u00bf\u00be\3\2\2\2\u00c0-\3\2\2\2\u00c1"+
+		"\u00c5\5,\27\2\u00c2\u00c4\5*\26\2\u00c3\u00c2\3\2\2\2\u00c4\u00c7\3\2"+
+		"\2\2\u00c5\u00c3\3\2\2\2\u00c5\u00c6\3\2\2\2\u00c6/\3\2\2\2\u00c7\u00c5"+
+		"\3\2\2\2\u00c8\u00ca\5\f\7\2\u00c9\u00cb\5\16\b\2\u00ca\u00c9\3\2\2\2"+
+		"\u00ca\u00cb\3\2\2\2\u00cb\61\3\2\2\2\u00cc\u00cf\5.\30\2\u00cd\u00ce"+
+		"\7\'\2\2\u00ce\u00d0\5\2\2\2\u00cf\u00cd\3\2\2\2\u00cf\u00d0\3\2\2\2\u00d0"+
+		"\63\3\2\2\2\u00d1\u00d6\5\62\32\2\u00d2\u00d3\7\t\2\2\u00d3\u00d5\5\62"+
+		"\32\2\u00d4\u00d2\3\2\2\2\u00d5\u00d8\3\2\2\2\u00d6\u00d4\3\2\2\2\u00d6"+
+		"\u00d7\3\2\2\2\u00d7\65\3\2\2\2\u00d8\u00d6\3\2\2\2\u00d9\u00dc\5\2\2"+
+		"\2\u00da\u00dc\5\n\6\2\u00db\u00d9\3\2\2\2\u00db\u00da\3\2\2\2\u00dc\u00dd"+
+		"\3\2\2\2\u00dd\u00de\7\'\2\2\u00de\u00df\5\2\2\2\u00df\67\3\2\2\2\u00e0"+
+		"\u00e1\7\36\2\2\u00e1\u00e3\5.\30\2\u00e2\u00e4\5\6\4\2\u00e3\u00e2\3"+
+		"\2\2\2\u00e3\u00e4\3\2\2\2\u00e49\3\2\2\2\u00e5\u00eb\5\66\34\2\u00e6"+
+		"\u00e9\5\2\2\2\u00e7\u00e9\5\n\6\2\u00e8\u00e6\3\2\2\2\u00e8\u00e7\3\2"+
+		"\2\2\u00e9\u00eb\3\2\2\2\u00ea\u00e5\3\2\2\2\u00ea\u00e8\3\2\2\2\u00eb"+
+		";\3\2\2\2\u00ec\u00ed\7\35\2\2\u00ed\u00ee\5.\30\2\u00ee=\3\2\2\2\u00ef"+
+		"\u00f1\5:\36\2\u00f0\u00f2\5<\37\2\u00f1\u00f0\3\2\2\2\u00f1\u00f2\3\2"+
+		"\2\2\u00f2?\3\2\2\2\u00f3\u00f4\7\34\2\2\u00f4\u00f5\5> \2\u00f5A\3\2"+
+		"\2\2\u00f6\u00f7\7!\2\2\u00f7\u00f8\5\64\33\2\u00f8C\3\2\2\2\u00f9\u00fe"+
+		"\5@!\2\u00fa\u00fe\5<\37\2\u00fb\u00fe\5> \2\u00fc\u00fe\5.\30\2\u00fd"+
+		"\u00f9\3\2\2\2\u00fd\u00fa\3\2\2\2\u00fd\u00fb\3\2\2\2\u00fd\u00fc\3\2"+
+		"\2\2\u00feE\3\2\2\2\u00ff\u0100\7\37\2\2\u0100\u0101\7\22\2\2\u0101\u0102"+
+		"\5\64\33\2\u0102\u0103\7\24\2\2\u0103G\3\2\2\2\u0104\u0109\5D#\2\u0105"+
+		"\u0106\7\t\2\2\u0106\u0108\5D#\2\u0107\u0105\3\2\2\2\u0108\u010b\3\2\2"+
+		"\2\u0109\u0107\3\2\2\2\u0109\u010a\3\2\2\2\u010aI\3\2\2\2\u010b\u0109"+
+		"\3\2\2\2\u010c\u0110\5D#\2\u010d\u010f\5D#\2\u010e\u010d\3\2\2\2\u010f"+
+		"\u0112\3\2\2\2\u0110\u010e\3\2\2\2\u0110\u0111\3\2\2\2\u0111K\3\2\2\2"+
+		"\u0112\u0110\3\2\2\2\u0113\u0116\5H%\2\u0114\u0116\5J&\2\u0115\u0113\3"+
+		"\2\2\2\u0115\u0114\3\2\2\2\u0116M\3\2\2\2\u0117\u0119\5L\'\2\u0118\u011a"+
+		"\5F$\2\u0119\u0118\3\2\2\2\u0119\u011a\3\2\2\2\u011a\u011c\3\2\2\2\u011b"+
+		"\u011d\5B\"\2\u011c\u011b\3\2\2\2\u011c\u011d\3\2\2\2\u011d\u011f\3\2"+
+		"\2\2\u011e\u0120\58\35\2\u011f\u011e\3\2\2\2\u011f\u0120\3\2\2\2\u0120"+
+		"\u0122\3\2\2\2\u0121\u0123\5\60\31\2\u0122\u0121\3\2\2\2\u0122\u0123\3"+
+		"\2\2\2\u0123\u0124\3\2\2\2\u0124\u0125\7\2\2\3\u0125O\3\2\2\2\34\\fhr"+
+		"x\u0081\u008b\u009a\u00bf\u00c5\u00ca\u00cf\u00d6\u00db\u00e3\u00e8\u00ea"+
+		"\u00f1\u00fd\u0109\u0110\u0115\u0119\u011c\u011f\u0122";
 	public static final ATN _ATN =
 		new ATNDeserializer().deserialize(_serializedATN.toCharArray());
 	static {
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserBaseVisitor.java b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserBaseVisitor.java
index 3139d43..15d8416 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserBaseVisitor.java
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserBaseVisitor.java
@@ -114,6 +114,13 @@ public class AtlasDSLParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
 	 * <p>The default implementation returns the result of calling
 	 * {@link #visitChildren} on {@code ctx}.</p>
 	 */
+	@Override public T visitHasTermClause(AtlasDSLParser.HasTermClauseContext ctx) { return visitChildren(ctx); }
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>The default implementation returns the result of calling
+	 * {@link #visitChildren} on {@code ctx}.</p>
+	 */
 	@Override public T visitHasClause(AtlasDSLParser.HasClauseContext ctx) { return visitChildren(ctx); }
 	/**
 	 * {@inheritDoc}
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserListener.java b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserListener.java
new file mode 100644
index 0000000..92f04fc
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserListener.java
@@ -0,0 +1,399 @@
+package org.apache.atlas.query.antlr4;
+import org.antlr.v4.runtime.tree.ParseTreeListener;
+
+/**
+ * This interface defines a complete listener for a parse tree produced by
+ * {@link AtlasDSLParser}.
+ */
+public interface AtlasDSLParserListener extends ParseTreeListener {
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#identifier}.
+	 * @param ctx the parse tree
+	 */
+	void enterIdentifier(AtlasDSLParser.IdentifierContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#identifier}.
+	 * @param ctx the parse tree
+	 */
+	void exitIdentifier(AtlasDSLParser.IdentifierContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#operator}.
+	 * @param ctx the parse tree
+	 */
+	void enterOperator(AtlasDSLParser.OperatorContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#operator}.
+	 * @param ctx the parse tree
+	 */
+	void exitOperator(AtlasDSLParser.OperatorContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#sortOrder}.
+	 * @param ctx the parse tree
+	 */
+	void enterSortOrder(AtlasDSLParser.SortOrderContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#sortOrder}.
+	 * @param ctx the parse tree
+	 */
+	void exitSortOrder(AtlasDSLParser.SortOrderContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#valueArray}.
+	 * @param ctx the parse tree
+	 */
+	void enterValueArray(AtlasDSLParser.ValueArrayContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#valueArray}.
+	 * @param ctx the parse tree
+	 */
+	void exitValueArray(AtlasDSLParser.ValueArrayContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#literal}.
+	 * @param ctx the parse tree
+	 */
+	void enterLiteral(AtlasDSLParser.LiteralContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#literal}.
+	 * @param ctx the parse tree
+	 */
+	void exitLiteral(AtlasDSLParser.LiteralContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#limitClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterLimitClause(AtlasDSLParser.LimitClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#limitClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitLimitClause(AtlasDSLParser.LimitClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#offsetClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterOffsetClause(AtlasDSLParser.OffsetClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#offsetClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitOffsetClause(AtlasDSLParser.OffsetClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#atomE}.
+	 * @param ctx the parse tree
+	 */
+	void enterAtomE(AtlasDSLParser.AtomEContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#atomE}.
+	 * @param ctx the parse tree
+	 */
+	void exitAtomE(AtlasDSLParser.AtomEContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#multiERight}.
+	 * @param ctx the parse tree
+	 */
+	void enterMultiERight(AtlasDSLParser.MultiERightContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#multiERight}.
+	 * @param ctx the parse tree
+	 */
+	void exitMultiERight(AtlasDSLParser.MultiERightContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#multiE}.
+	 * @param ctx the parse tree
+	 */
+	void enterMultiE(AtlasDSLParser.MultiEContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#multiE}.
+	 * @param ctx the parse tree
+	 */
+	void exitMultiE(AtlasDSLParser.MultiEContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#arithERight}.
+	 * @param ctx the parse tree
+	 */
+	void enterArithERight(AtlasDSLParser.ArithERightContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#arithERight}.
+	 * @param ctx the parse tree
+	 */
+	void exitArithERight(AtlasDSLParser.ArithERightContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#arithE}.
+	 * @param ctx the parse tree
+	 */
+	void enterArithE(AtlasDSLParser.ArithEContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#arithE}.
+	 * @param ctx the parse tree
+	 */
+	void exitArithE(AtlasDSLParser.ArithEContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#comparisonClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterComparisonClause(AtlasDSLParser.ComparisonClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#comparisonClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitComparisonClause(AtlasDSLParser.ComparisonClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#isClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterIsClause(AtlasDSLParser.IsClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#isClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitIsClause(AtlasDSLParser.IsClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#hasTermClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterHasTermClause(AtlasDSLParser.HasTermClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#hasTermClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitHasTermClause(AtlasDSLParser.HasTermClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#hasClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterHasClause(AtlasDSLParser.HasClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#hasClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitHasClause(AtlasDSLParser.HasClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#countClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterCountClause(AtlasDSLParser.CountClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#countClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitCountClause(AtlasDSLParser.CountClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#maxClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterMaxClause(AtlasDSLParser.MaxClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#maxClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitMaxClause(AtlasDSLParser.MaxClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#minClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterMinClause(AtlasDSLParser.MinClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#minClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitMinClause(AtlasDSLParser.MinClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#sumClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterSumClause(AtlasDSLParser.SumClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#sumClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitSumClause(AtlasDSLParser.SumClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#exprRight}.
+	 * @param ctx the parse tree
+	 */
+	void enterExprRight(AtlasDSLParser.ExprRightContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#exprRight}.
+	 * @param ctx the parse tree
+	 */
+	void exitExprRight(AtlasDSLParser.ExprRightContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#compE}.
+	 * @param ctx the parse tree
+	 */
+	void enterCompE(AtlasDSLParser.CompEContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#compE}.
+	 * @param ctx the parse tree
+	 */
+	void exitCompE(AtlasDSLParser.CompEContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#expr}.
+	 * @param ctx the parse tree
+	 */
+	void enterExpr(AtlasDSLParser.ExprContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#expr}.
+	 * @param ctx the parse tree
+	 */
+	void exitExpr(AtlasDSLParser.ExprContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#limitOffset}.
+	 * @param ctx the parse tree
+	 */
+	void enterLimitOffset(AtlasDSLParser.LimitOffsetContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#limitOffset}.
+	 * @param ctx the parse tree
+	 */
+	void exitLimitOffset(AtlasDSLParser.LimitOffsetContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#selectExpression}.
+	 * @param ctx the parse tree
+	 */
+	void enterSelectExpression(AtlasDSLParser.SelectExpressionContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#selectExpression}.
+	 * @param ctx the parse tree
+	 */
+	void exitSelectExpression(AtlasDSLParser.SelectExpressionContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#selectExpr}.
+	 * @param ctx the parse tree
+	 */
+	void enterSelectExpr(AtlasDSLParser.SelectExprContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#selectExpr}.
+	 * @param ctx the parse tree
+	 */
+	void exitSelectExpr(AtlasDSLParser.SelectExprContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#aliasExpr}.
+	 * @param ctx the parse tree
+	 */
+	void enterAliasExpr(AtlasDSLParser.AliasExprContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#aliasExpr}.
+	 * @param ctx the parse tree
+	 */
+	void exitAliasExpr(AtlasDSLParser.AliasExprContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#orderByExpr}.
+	 * @param ctx the parse tree
+	 */
+	void enterOrderByExpr(AtlasDSLParser.OrderByExprContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#orderByExpr}.
+	 * @param ctx the parse tree
+	 */
+	void exitOrderByExpr(AtlasDSLParser.OrderByExprContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#fromSrc}.
+	 * @param ctx the parse tree
+	 */
+	void enterFromSrc(AtlasDSLParser.FromSrcContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#fromSrc}.
+	 * @param ctx the parse tree
+	 */
+	void exitFromSrc(AtlasDSLParser.FromSrcContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#whereClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterWhereClause(AtlasDSLParser.WhereClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#whereClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitWhereClause(AtlasDSLParser.WhereClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#fromExpression}.
+	 * @param ctx the parse tree
+	 */
+	void enterFromExpression(AtlasDSLParser.FromExpressionContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#fromExpression}.
+	 * @param ctx the parse tree
+	 */
+	void exitFromExpression(AtlasDSLParser.FromExpressionContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#fromClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterFromClause(AtlasDSLParser.FromClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#fromClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitFromClause(AtlasDSLParser.FromClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#selectClause}.
+	 * @param ctx the parse tree
+	 */
+	void enterSelectClause(AtlasDSLParser.SelectClauseContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#selectClause}.
+	 * @param ctx the parse tree
+	 */
+	void exitSelectClause(AtlasDSLParser.SelectClauseContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#singleQrySrc}.
+	 * @param ctx the parse tree
+	 */
+	void enterSingleQrySrc(AtlasDSLParser.SingleQrySrcContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#singleQrySrc}.
+	 * @param ctx the parse tree
+	 */
+	void exitSingleQrySrc(AtlasDSLParser.SingleQrySrcContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#groupByExpression}.
+	 * @param ctx the parse tree
+	 */
+	void enterGroupByExpression(AtlasDSLParser.GroupByExpressionContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#groupByExpression}.
+	 * @param ctx the parse tree
+	 */
+	void exitGroupByExpression(AtlasDSLParser.GroupByExpressionContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#commaDelimitedQueries}.
+	 * @param ctx the parse tree
+	 */
+	void enterCommaDelimitedQueries(AtlasDSLParser.CommaDelimitedQueriesContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#commaDelimitedQueries}.
+	 * @param ctx the parse tree
+	 */
+	void exitCommaDelimitedQueries(AtlasDSLParser.CommaDelimitedQueriesContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#spaceDelimitedQueries}.
+	 * @param ctx the parse tree
+	 */
+	void enterSpaceDelimitedQueries(AtlasDSLParser.SpaceDelimitedQueriesContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#spaceDelimitedQueries}.
+	 * @param ctx the parse tree
+	 */
+	void exitSpaceDelimitedQueries(AtlasDSLParser.SpaceDelimitedQueriesContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#querySrc}.
+	 * @param ctx the parse tree
+	 */
+	void enterQuerySrc(AtlasDSLParser.QuerySrcContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#querySrc}.
+	 * @param ctx the parse tree
+	 */
+	void exitQuerySrc(AtlasDSLParser.QuerySrcContext ctx);
+	/**
+	 * Enter a parse tree produced by {@link AtlasDSLParser#query}.
+	 * @param ctx the parse tree
+	 */
+	void enterQuery(AtlasDSLParser.QueryContext ctx);
+	/**
+	 * Exit a parse tree produced by {@link AtlasDSLParser#query}.
+	 * @param ctx the parse tree
+	 */
+	void exitQuery(AtlasDSLParser.QueryContext ctx);
+}
\ No newline at end of file
diff --git a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserVisitor.java b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserVisitor.java
index a1a727c..a999cce 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserVisitor.java
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParserVisitor.java
@@ -94,6 +94,12 @@ public interface AtlasDSLParserVisitor<T> extends ParseTreeVisitor<T> {
 	 */
 	T visitIsClause(AtlasDSLParser.IsClauseContext ctx);
 	/**
+	 * Visit a parse tree produced by {@link AtlasDSLParser#hasTermClause}.
+	 * @param ctx the parse tree
+	 * @return the visitor result
+	 */
+	T visitHasTermClause(AtlasDSLParser.HasTermClauseContext ctx);
+	/**
 	 * Visit a parse tree produced by {@link AtlasDSLParser#hasClause}.
 	 * @param ctx the parse tree
 	 * @return the visitor result
diff --git a/repository/src/test/java/org/apache/atlas/BasicTestSetup.java b/repository/src/test/java/org/apache/atlas/BasicTestSetup.java
index d733c16..4be0940 100644
--- a/repository/src/test/java/org/apache/atlas/BasicTestSetup.java
+++ b/repository/src/test/java/org/apache/atlas/BasicTestSetup.java
@@ -31,6 +31,7 @@ import org.apache.atlas.repository.store.graph.AtlasEntityStore;
 import org.apache.atlas.repository.store.graph.v2.AtlasEntityStream;
 import org.apache.atlas.store.AtlasTypeDefStore;
 import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.commons.lang.StringUtils;
 
 import javax.inject.Inject;
 import java.io.IOException;
@@ -67,6 +68,8 @@ public abstract class BasicTestSetup extends AtlasTestBase {
     // Glossary type //
     public static final String SALES_GLOSSARY = "salesGlossary";
     public static final String SALES_TERM     = "salesTerm";
+    public static final String MODERNTRADE_TERM = "modernTrade";
+    public static final String ECOMMERCE_TERM   = "ecommerce";
 
     @Inject
     protected AtlasTypeRegistry typeRegistry;
@@ -80,10 +83,15 @@ public abstract class BasicTestSetup extends AtlasTestBase {
     private boolean baseLoaded = false;
     private EntityMutationResponse hiveEntities;
 
+    private AtlasEntity timeDim;
+    private AtlasEntity productDim;
+    private AtlasEntity loggingFactMonthly;
+
     protected void setupTestData() {
         loadBaseModels();
         loadHiveDataset();
         loadEmployeeDataset();
+        assignGlossary();
     }
 
     private void loadBaseModels() {
@@ -180,7 +188,7 @@ public abstract class BasicTestSetup extends AtlasTestBase {
         sd = storageDescriptor("hdfs://host:8000/apps/warehouse/sales", "TextInputFormat", "TextOutputFormat", true, ImmutableList.of(column("time_id", "int", "time id")));
         entities.add(sd);
 
-        AtlasEntity timeDim = table("time_dim", "time dimension table", salesDB, sd, "John Doe", "External", timeDimColumns,
+        timeDim = table("time_dim", "time dimension table", salesDB, sd, "John Doe", "External", timeDimColumns,
                                     DIMENSION_CLASSIFICATION);
         entities.add(timeDim);
 
@@ -241,7 +249,7 @@ public abstract class BasicTestSetup extends AtlasTestBase {
         sd = storageDescriptor("hdfs://host:8000/apps/warehouse/sales", "TextInputFormat", "TextOutputFormat", true, ImmutableList.of(column("time_id", "int", "time id")));
         entities.add(sd);
 
-        AtlasEntity productDim =
+        productDim =
                 table("product_dim", "product dimension table", salesDB, sd, "John Doe 2", "Managed", productDimColumns,
                       DIMENSION_CLASSIFICATION);
         entities.add(productDim);
@@ -281,7 +289,7 @@ public abstract class BasicTestSetup extends AtlasTestBase {
         sd = storageDescriptor("hdfs://host:8000/apps/warehouse/sales", "TextInputFormat", "TextOutputFormat", true, ImmutableList.of(column("time_id", "int", "time id")));
         entities.add(sd);
 
-        AtlasEntity loggingFactMonthly =
+        loggingFactMonthly =
                 table("logging_fact_monthly_mv", "logging fact monthly materialized view", logDB, sd, "Tim ETL 2",
                       "Managed", logFactColumns, LOGDATA_CLASSIFICATION);
         entities.add(loggingFactMonthly);
@@ -486,22 +494,67 @@ public abstract class BasicTestSetup extends AtlasTestBase {
         return filterCriteria;
     }
 
-    public void assignGlossary() throws AtlasBaseException {
-        AtlasGlossary glossary = new AtlasGlossary();
-        glossary.setName(SALES_GLOSSARY);
-        glossary = glossaryService.createGlossary(glossary);
-
-        AtlasGlossaryTerm term = new AtlasGlossaryTerm();
-        term.setAnchor(new AtlasGlossaryHeader(glossary.getGuid()));
-        term.setName(SALES_TERM);
-        term = glossaryService.createTerm(term);
-
-        List<AtlasRelatedObjectId> guids = hiveEntities.getCreatedEntities().stream().filter(e -> e.getTypeName().equals(HIVE_TABLE_TYPE))
-                .map(p -> {AtlasRelatedObjectId obj = new AtlasRelatedObjectId();
-                            obj.setGuid(p.getGuid());
-                            obj.setTypeName(p.getTypeName()); return obj;}).collect(Collectors.toList());
+    public void assignGlossary() {
+        try {
+            AtlasGlossary glossary = new AtlasGlossary();
+            glossary.setName(SALES_GLOSSARY);
+            glossary = glossaryService.createGlossary(glossary);
+
+            AtlasGlossaryTerm term = new AtlasGlossaryTerm();
+            term.setAnchor(new AtlasGlossaryHeader(glossary.getGuid()));
+            term.setName(SALES_TERM);
+            term = glossaryService.createTerm(term);
+
+            AtlasGlossaryTerm modernTrade = new AtlasGlossaryTerm();
+            modernTrade.setAnchor(new AtlasGlossaryHeader(glossary.getGuid()));
+            modernTrade.setName(MODERNTRADE_TERM);
+            modernTrade = glossaryService.createTerm(modernTrade);
+
+            AtlasGlossaryTerm ecomm = new AtlasGlossaryTerm();
+            ecomm.setAnchor(new AtlasGlossaryHeader(glossary.getGuid()));
+            ecomm.setName(ECOMMERCE_TERM);
+            ecomm = glossaryService.createTerm(ecomm);
+
+            List<AtlasRelatedObjectId> guids = new ArrayList<>();
+            List<AtlasRelatedObjectId> mordernTradeGuids = new ArrayList<>();
+            List<AtlasRelatedObjectId> ecomGuid = new ArrayList<>();
+
+            for (AtlasEntityHeader p : hiveEntities.getCreatedEntities()) {
+                if (StringUtils.equals(p.getTypeName(), HIVE_TABLE_TYPE)) {
+                    AtlasRelatedObjectId obj = new AtlasRelatedObjectId();
+                    obj.setGuid(p.getGuid());
+                    obj.setTypeName(p.getTypeName());
+                    guids.add(obj);
+
+                    if (p.getAttribute("name").equals(timeDim.getAttribute("name"))) {
+                        timeDim.setGuid(p.getGuid());
+                        AtlasRelatedObjectId obj1 = new AtlasRelatedObjectId();
+                        obj1.setGuid(p.getGuid());
+                        obj1.setTypeName(p.getTypeName());
+                        mordernTradeGuids.add(obj1);
+                    } else if (p.getAttribute("name").equals(productDim.getAttribute("name"))) {
+                        productDim.setGuid(p.getGuid());
+                        AtlasRelatedObjectId obj2 = new AtlasRelatedObjectId();
+                        obj2.setGuid(p.getGuid());
+                        obj2.setTypeName(p.getTypeName());
+                        ecomGuid.add(obj2);
+                    } else if (p.getAttribute("name").equals(loggingFactMonthly.getAttribute("name"))) {
+                        loggingFactMonthly.setGuid(p.getGuid());
+                        AtlasRelatedObjectId obj3 = new AtlasRelatedObjectId();
+                        obj3.setGuid(p.getGuid());
+                        obj3.setTypeName(p.getTypeName());
+                        mordernTradeGuids.add(obj3);
+                    }
+                }
+            }
+
+            glossaryService.assignTermToEntities(term.getGuid(), guids);
+            glossaryService.assignTermToEntities(modernTrade.getGuid(), mordernTradeGuids);
+            glossaryService.assignTermToEntities(ecomm.getGuid(), ecomGuid);
+        } catch (AtlasBaseException e) {
+            fail("Failed to assign glossary term");
+        }
 
-        glossaryService.assignTermToEntities(term.getGuid(), guids);
     }
 
 }
diff --git a/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java b/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java
index 1839e76..0da60d3 100644
--- a/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java
+++ b/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java
@@ -54,7 +54,6 @@ public class AtlasDiscoveryServiceTest extends BasicTestSetup {
         ApplicationProperties.get().setProperty(ApplicationProperties.ENABLE_FREETEXT_SEARCH_CONF, true);
         setupTestData();
         createDimensionalTaggedEntity("sales");
-        assignGlossary();
     }
 
     /*  TermSearchProcessor(TSP),
diff --git a/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java b/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java
index 3bb3b07..958c428 100644
--- a/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java
+++ b/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java
@@ -199,6 +199,28 @@ public class DSLQueriesTest extends BasicTestSetup {
         assertSearchResult(searchResult2, expected, query);
     }
 
+    @DataProvider(name = "glossaryTermQueries")
+    private Object[][] glossaryTermQueries() {
+        return new Object[][]{
+                {"hive_table hasTerm modernTrade",2},
+                {"hive_table hasTerm \"modernTrade@salesGlossary\"",2},
+                {"hive_table hasTerm \"modernTrade@salesGlossary\" where hive_table.name = \"time_dim\"",1},
+                {"hive_table hasTerm \"modernTrade@salesGlossary\" select name",2},
+                {"hive_table hasTerm \"modernTrade@salesGlossary\" limit 1",1},
+                {"hive_table hasTerm \"modernTrade@salesGlossary\" or hive_table hasTerm \"ecommerce@salesGlossary\"",3},
+                {"hive_table hasTerm \"modernTrade@salesGlossary\" and hive_table isA Dimension",1},
+                {"hive_table hasTerm \"modernTrade@salesGlossary\" and db.name = \"Sales\" or (hive_table.name = \"sales_fact_monthly_mv\")",2},
+                {"hive_table where hive_table hasTerm \"modernTrade@salesGlossary\"",2},
+                {"hive_table where (name = \"product_dim\" and hive_table hasTerm \"ecommerce@salesGlossary\")",1}
+        };
+    }
+
+    @Test(dataProvider = "glossaryTermQueries")
+    public void glossaryTerm(String query, int expected) throws AtlasBaseException {
+        queryAssert(query, expected, DEFAULT_LIMIT, 0);
+        queryAssert(query.replace("where", " "), expected, DEFAULT_LIMIT, 0);
+    }
+
     @DataProvider(name = "basicProvider")
     private Object[][] basicQueries() {
         return new Object[][]{
@@ -323,6 +345,7 @@ public class DSLQueriesTest extends BasicTestSetup {
                 {"hive_table isa Dimension limit 2 offset 1", 2},
                 {"hive_table isa Dimension limit 3 offset 1", 3},
                 {"hive_table where db.name='Sales' and db.clusterName='cl1'", 4},
+                {"hive_table where name = 'sales_fact_monthly_mv' and db.name = 'Reporting' and columns.name = 'sales'",1},
 
                 {"hive_column where hive_column isa PII", 4},
                 {"hive_column where hive_column isa PII limit 5", 4},
@@ -624,7 +647,9 @@ public class DSLQueriesTest extends BasicTestSetup {
                 {"hive_table select db.name, columns"}, // Can't select more than one referred attribute
                 {"hive_table select owner, columns"}, // Can't select a mix of immediate attribute and referred entity
                 {"hive_table select owner, db.name"}, // Same as above
-                {"hive_order"} // From src should be an Entity or Classification
+                {"hive_order"}, // From src should be an Entity or Classification
+                {"hive_table hasTerm modernTrade@salesGlossary"},//should be encoded with double quotes
+
         };
     }
 
diff --git a/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java b/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java
index 487cf27..6c69855 100644
--- a/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java
+++ b/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java
@@ -31,6 +31,7 @@ import org.apache.commons.lang.StringUtils;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.IN;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -187,7 +188,7 @@ public class GremlinQueryComposerTest {
         verify("Table where owner like \"*Tab_*\"",
                 "g.V().has('__typeName', 'Table').has('Table.owner', org.janusgraph.core.attribute.Text.textRegex(\".*Tab_.*\")).dedup().limit(25).toList()");
         verify("from Table where (db.name = \"Reporting\")",
-                "g.V().has('__typeName', 'Table').out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup().in('__Table.db').dedup().limit(25).toList()");
+                "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup()).dedup().limit(25).toList()");
     }
 
     @Test
@@ -311,7 +312,7 @@ public class GremlinQueryComposerTest {
                 {"hive_db where hive_db.name='Reporting' and hive_db.createTime < '2017-12-12T02:35:58.440Z'",
                         "g.V().has('__typeName', 'hive_db').and(__.has('hive_db.name', eq('Reporting')),__.has('hive_db.createTime', lt('1513046158440'))).dedup().limit(25).toList()"},
                 {"Table where db.name='Sales' and db.clusterName='cl1'",
-                        "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq('Sales')).dedup().in('__Table.db'),__.out('__Table.db').has('DB.clusterName', eq('cl1')).dedup().in('__Table.db')).dedup().limit(25).toList()"},
+                        "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq('Sales')).dedup(),__.out('__Table.db').has('DB.clusterName', eq('cl1')).dedup()).dedup().limit(25).toList()"},
         };
     }
 
@@ -322,6 +323,23 @@ public class GremlinQueryComposerTest {
     }
 
     @Test
+    public void glossaryTermQueries() {
+        verify("Table hasTerm sales", "g.V().has('__typeName', 'Table')." +
+                "and(__.in('r:AtlasGlossarySemanticAssignment')." +
+                "has('AtlasGlossaryTerm.name', eq('sales')).dedup())." +
+                "dedup().limit(25).toList()");
+        verify("Table hasTerm \"sales@glossary\"", "g.V().has('__typeName', 'Table')." +
+                "and(__.in('r:AtlasGlossarySemanticAssignment')." +
+                "has('AtlasGlossaryTerm.qualifiedName', eq(\"sales@glossary\")).dedup())." +
+                "dedup().limit(25).toList()");
+        verify("Table hasTerm \"sales@glossary\" and owner = \"fetl\"","g.V().has('__typeName', 'Table')." +
+                "and(__.in('r:AtlasGlossarySemanticAssignment').has('AtlasGlossaryTerm.qualifiedName', eq(\"sales@glossary\")).dedup()" +
+                ",__.has('Table.owner', eq(\"fetl\")))." +
+                "dedup().limit(25).toList()");
+    }
+
+
+    @Test
     public void keywordsInWhereClause() {
         verify("Table as t where t has name and t isa Dimension",
                 "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.outE('classifiedAs').has('__name', within('Dimension')).outV()).dedup().limit(25).toList()");
@@ -355,7 +373,7 @@ public class GremlinQueryComposerTest {
     public void whereComplexAndSelect() {
         String exSel = "def f(r){ t=[['name']];  r.each({t.add([" +
                 "it.property('Table.name').isPresent() ? it.value('Table.name') : \"\"])}); t.unique(); }";
-        String exMain = "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup().in('__Table.db'),__.has('Table.name', eq(\"sales_fact\"))).dedup().limit(25).toList()";
+        String exMain = "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup(),__.has('Table.name', eq(\"sales_fact\"))).dedup().limit(25).toList()";
         verify("Table where db.name = \"Reporting\" and name =\"sales_fact\" select name", getExpected(exSel, exMain));
         verify("Table where db.name = \"Reporting\" and name =\"sales_fact\"", exMain);
     }
@@ -501,12 +519,17 @@ public class GremlinQueryComposerTest {
                 return "__Table.columns";
             if (attributeName.equalsIgnoreCase("db"))
                 return "__Table.db";
+            if (attributeName.equalsIgnoreCase("meanings"))
+                return "r:AtlasGlossarySemanticAssignment";
             else
                 return "__DB.Table";
         }
 
         @Override
         public AtlasRelationshipEdgeDirection getRelationshipEdgeDirection(GremlinQueryComposer.Context context, String attributeName) {
+            if (attributeName.equalsIgnoreCase("meanings")){
+                return IN;
+            }
             return OUT;
         }
 
@@ -522,6 +545,7 @@ public class GremlinQueryComposerTest {
                     (context.getActiveTypeName().equals("Table") && attributeName.equals("__guid")) ||
                     (context.getActiveTypeName().equals("Table") && attributeName.equals("__state")) ||
                     (context.getActiveTypeName().equals("Table") && attributeName.equals("partitionSize")) ||
+                    (context.getActiveTypeName().equals("Table") && attributeName.equals("meanings")) ||
                     (context.getActiveTypeName().equals("hive_db") && attributeName.equals("name")) ||
                     (context.getActiveTypeName().equals("hive_db") && attributeName.equals("owner")) ||
                     (context.getActiveTypeName().equals("hive_db") && attributeName.equals("createTime")) ||
@@ -529,7 +553,9 @@ public class GremlinQueryComposerTest {
                     (context.getActiveTypeName().equals("DB") && attributeName.equals("owner")) ||
                     (context.getActiveTypeName().equals("DB") && attributeName.equals("clusterName")) ||
                     (context.getActiveTypeName().equals("Asset") && attributeName.equals("name")) ||
-                    (context.getActiveTypeName().equals("Asset") && attributeName.equals("owner"));
+                    (context.getActiveTypeName().equals("Asset") && attributeName.equals("owner")) ||
+                    (context.getActiveTypeName().equals("AtlasGlossaryTerm") && attributeName.equals("name")) ||
+                    (context.getActiveTypeName().equals("AtlasGlossaryTerm") && attributeName.equals("qualifiedName"));
         }
 
         @Override
@@ -566,6 +592,10 @@ public class GremlinQueryComposerTest {
                 return "Column";
             }
 
+            if(context.getActiveTypeName().equals("Table") && item.equals("meanings")) {
+                return "AtlasGlossaryTerm";
+            }
+
             if(context.getActiveTypeName().equals(item)) {
                 return null;
             }