diff --git a/jopa-impl/src/main/antlr4/cz/cvut/kbss/jopa/query/soql/Soql.g4 b/jopa-impl/src/main/antlr4/cz/cvut/kbss/jopa/query/soql/Soql.g4 index 4d105890b..383a8887e 100644 --- a/jopa-impl/src/main/antlr4/cz/cvut/kbss/jopa/query/soql/Soql.g4 +++ b/jopa-impl/src/main/antlr4/cz/cvut/kbss/jopa/query/soql/Soql.g4 @@ -1,48 +1,30 @@ grammar Soql; +start: querySentence EOF ; -querySentence : selectStatement whereClauseWrapper? groupByClause? orderByClause? ; +querySentence: selectStatement ; -selectStatement: typeDef params FROM tables ; +selectStatement: selectClause fromClause whereClause? groupByClause? orderByClause? ; -typeDef: SELECT ; +singleValuedObjectPathExpression: simpleSubpath DOT singleValuedObjectField ; -params: paramComma* distinctParam ; +simpleSubpath: singleValuedObjectField (DOT simpleSubpath)* ; -paramComma: distinctParam ',' ; +singleValuedObjectField: IDENTIFICATION_VARIABLE ; -distinctParam: distinct? selectedParam ; +selectClause: SELECT (DISTINCT)? selectItem (',' selectItem)* ; -selectedParam: param | count; +selectItem: selectExpression; -count: COUNT '(' param ')' ; +selectExpression: simpleSubpath | aggregateExpression ; -param: objWithAttr | objWithOutAttr ; +aggregateExpression: COUNT '(' (DISTINCT)? simpleSubpath ')'; -objWithAttr: object DOT attribute; +fromClause: FROM entityName IDENTIFICATION_VARIABLE; -objWithOutAttr: object ; +entityName: IDENTIFICATION_VARIABLE ; -distinct: DISTINCT ; - -object: IDENTIFICATION_VARIABLE ; - -attribute: IDENTIFICATION_VARIABLE ; - -joinedParams: object DOT attribute (DOT attribute)+ ; - - - -tables: tableWithName ; - -table: IDENTIFICATION_VARIABLE ; - -tableName: IDENTIFICATION_VARIABLE ; - -tableWithName: table tableName ; - - -whereClauseWrapper +whereClause : WHERE conditionalExpression ; @@ -66,38 +48,44 @@ simpleConditionalExpression ; inExpression - : whereClauseParam (NOT)? IN '('? (inItem (',' inItem)*) ')'? + : simpleSubpath (NOT)? IN '('? (inItem (',' inItem)*) ')'? ; inItem : literal - | whereClauseValue + | inputParameter ; literal - : + : STRING_LITERAL + | INT_LITERAL + | FLOAT_LITERAL + | BOOLEAN_LITERAL + | IDENTIFICATION_VARIABLE ; likeExpression - : stringExpression (NOT)? LIKE whereClauseValue + : stringExpression (NOT)? LIKE stringExpression ; memberOfExpression - : inItem (NOT)? MEMBEROF whereClauseParam + : inItem (NOT)? MEMBER OF simpleSubpath + ; + +entityExpression + : IDENTIFICATION_VARIABLE + | inputParameter ; comparisonExpression - : stringExpression COMPARISON_OPERATOR stringExpression - | simpleArithmeticExpression COMPARISON_OPERATOR simpleArithmeticExpression - | whereClauseParam COMPARISON_OPERATOR ( whereClauseParam | whereClauseValue ) + : stringExpression comparisonOperator stringExpression + | simpleArithmeticExpression comparisonOperator simpleArithmeticExpression + | entityExpression op=(EQUAL | NOT_EQUAL) ( entityExpression ) ; -whereClauseValue: (QMARK TEXT QMARK) | inputParameter ; - -whereClauseParam: param | joinedParams ; - stringExpression - : whereClauseParam + : simpleSubpath + | STRING_LITERAL | inputParameter | functionsReturningStrings ; @@ -107,7 +95,7 @@ functionsReturningStrings | 'SUBSTRING' '(' stringExpression ',' simpleArithmeticExpression ',' simpleArithmeticExpression ')' | 'LOWER' '(' stringExpression ')' | 'UPPER' '(' stringExpression ')' - | 'LANG' '(' whereClauseParam ')' + | 'LANG' '(' simpleSubpath ')' ; simpleArithmeticExpression @@ -123,7 +111,7 @@ arithmeticFactor ; arithmeticPrimary - : param + : simpleSubpath | literal | '(' simpleArithmeticExpression ')' | inputParameter @@ -138,22 +126,24 @@ functionsReturningNumerics | 'FLOOR' '(' simpleArithmeticExpression ')' ; -orderByClause: ORDERBY orderByFullFormComma orderByFullFormComma* ; - -orderByFullFormComma: orderByFullForm ','? ; - -orderByFullForm: orderByParam ORDERING? ; - -orderByParam: object DOT attribute (DOT attribute)* ; +orderByClause: ORDER BY orderByItem (',' orderByItem)* ; -groupByClause: GROUPBY groupByParamComma groupByParamComma* ; +orderByItem: singleValuedObjectPathExpression (ASC | DESC) ; -groupByParamComma: groupByParam ','? ; +groupByClause: GROUP BY groupByItem (',' groupByItem)* ; -groupByParam: object DOT attribute (DOT attribute)* ; +groupByItem: singleValuedObjectPathExpression ; inputParameter: COLON IDENTIFICATION_VARIABLE ; +comparisonOperator + : op=EQUAL + | op='>' + | op='>=' + | op='<' + | op='<=' + | op=NOT_EQUAL + ; SELECT: 'SELECT' ; @@ -169,11 +159,13 @@ AND: 'AND' ; OR: 'OR' ; -ORDERBY: 'ORDER BY' ; +BY: 'BY' ; + +OF: 'OF' ; -ORDERING: ASC | DESC ; +ORDER: 'ORDER' ; -GROUPBY: 'GROUP BY' ; +GROUP: 'GROUP' ; ASC: 'ASC' ; @@ -187,9 +179,10 @@ LIKE: 'LIKE' ; IN: 'IN' ; -MEMBEROF: 'MEMBER OF' ; +MEMBER: 'MEMBER' ; -COMPARISON_OPERATOR: '>' | '<' | '>=' | '<=' | '=' | '<>' | '!=' ; +EQUAL: '=' ; +NOT_EQUAL: '<>' | '!=' ; DOT: '.' ; @@ -197,8 +190,20 @@ QMARK: '"' ; COLON: ':' ; +TRUE: 'TRUE'; + +FALSE: 'FALSE'; + IDENTIFICATION_VARIABLE: (LOWERCASE | UPPERCASE | '_') (LOWERCASE | UPPERCASE | DIGIT | '_')* ; +STRING_LITERAL: QMARK TEXT QMARK ; + +INT_LITERAL: DIGIT+; + +FLOAT_LITERAL: DIGIT* '.' DIGIT; + +BOOLEAN_LITERAL: TRUE | FALSE; + TEXT: (LOWERCASE | UPPERCASE | DIGIT)+ ; UPPERCASE: ('A'..'Z'); @@ -207,8 +212,4 @@ LOWERCASE: ('a'..'z'); DIGIT: ('0'..'9'); -NUMBER: DIGIT+ ; - -VALUE: NUMBER ; - WHITESPACE: (' ')+ -> skip; diff --git a/jopa-impl/src/main/java/cz/cvut/kbss/jopa/query/soql/SoqlQueryListener.java b/jopa-impl/src/main/java/cz/cvut/kbss/jopa/query/soql/SoqlQueryListener.java index eeceee25e..2f3881a22 100644 --- a/jopa-impl/src/main/java/cz/cvut/kbss/jopa/query/soql/SoqlQueryListener.java +++ b/jopa-impl/src/main/java/cz/cvut/kbss/jopa/query/soql/SoqlQueryListener.java @@ -90,117 +90,71 @@ public SoqlQueryListener(MetamodelImpl metamodel) { } @Override - public void enterQuerySentence(SoqlParser.QuerySentenceContext ctx) { - } - - @Override - public void exitQuerySentence(SoqlParser.QuerySentenceContext ctx) { - this.soql = ctx.getText(); - buildSparqlQueryString(); - } - - @Override - public void enterSelectStatement(SoqlParser.SelectStatementContext ctx) { - } + public void enterStart(SoqlParser.StartContext ctx) { - @Override - public void exitSelectStatement(SoqlParser.SelectStatementContext ctx) { } @Override - public void enterParams(SoqlParser.ParamsContext ctx) { - } + public void exitStart(SoqlParser.StartContext ctx) { - @Override - public void exitParams(SoqlParser.ParamsContext ctx) { } @Override - public void enterParam(SoqlParser.ParamContext ctx) { + public void enterQuerySentence(SoqlParser.QuerySentenceContext ctx) { } @Override - public void exitParam(SoqlParser.ParamContext ctx) { + public void exitQuerySentence(SoqlParser.QuerySentenceContext ctx) { + this.soql = ctx.getText(); + buildSparqlQueryString(); } @Override - public void enterJoinedParams(SoqlParser.JoinedParamsContext ctx) { - SoqlNode firstNode = linkContextNodes(ctx); - SoqlAttribute myAttr = new SoqlAttribute(firstNode); - pushNewAttribute(myAttr); - } - - private void pushNewAttribute(SoqlAttribute myAttr) { - attributes.add(myAttr); - this.attrPointer = myAttr; - } + public void enterSelectStatement(SoqlParser.SelectStatementContext ctx) { - private void popAttribute() { - this.attrPointer = attributes.remove(attributes.size() - 1); } @Override - public void exitJoinedParams(SoqlParser.JoinedParamsContext ctx) { - } + public void exitSelectStatement(SoqlParser.SelectStatementContext ctx) { - @Override - public void enterParamComma(SoqlParser.ParamCommaContext ctx) { } @Override - public void exitParamComma(SoqlParser.ParamCommaContext ctx) { - } + public void enterSingleValuedObjectPathExpression(SoqlParser.SingleValuedObjectPathExpressionContext ctx) { - @Override - public void enterDistinctParam(SoqlParser.DistinctParamContext ctx) { } @Override - public void exitDistinctParam(SoqlParser.DistinctParamContext ctx) { - } + public void exitSingleValuedObjectPathExpression(SoqlParser.SingleValuedObjectPathExpressionContext ctx) { - @Override - public void enterSelectedParam(SoqlParser.SelectedParamContext ctx) { } @Override - public void exitSelectedParam(SoqlParser.SelectedParamContext ctx) { - if (!isSelectedParamCount) { - this.projectedVariable = ctx.getText(); + public void enterSimpleSubpath(SoqlParser.SimpleSubpathContext ctx) { + if(ctx.simpleSubpath() == null) { + return; } - } - @Override - public void enterCount(SoqlParser.CountContext ctx) { - isSelectedParamCount = true; - } + if(ctx.getChildCount() == 1) { + return; + } - @Override - public void exitCount(SoqlParser.CountContext ctx) { - this.projectedVariable = ctx.getChild(2).getText(); - } + // node was already processed by parent + if(ctx.getParent() instanceof SoqlParser.SimpleSubpathContext) { + return; + } - @Override - public void enterObject(SoqlParser.ObjectContext ctx) { - } + SoqlNode owner = linkSimpleSubpath(ctx); - @Override - public void exitObject(SoqlParser.ObjectContext ctx) { - } + // don't add top level references multiple times + if(!owner.hasChild() && objectTypes.containsKey(owner.getValue())) { + return; + } - @Override - public void enterObjWithAttr(SoqlParser.ObjWithAttrContext ctx) { - String owner = getOwnerFromParam(ctx); - String attribute = getAttributeFromParam(ctx); - // objectNode.attributeNode - SoqlNode objectNode = new AttributeNode(owner); - SoqlNode attributeNode = new AttributeNode(objectNode, attribute); - objectNode.setChild(attributeNode); - setIris(objectNode); - SoqlAttribute newAttr = new SoqlAttribute(objectNode); - if (isIdentifier(objectNode, attributeNode)) { + SoqlAttribute newAttr = new SoqlAttribute(owner); + if (owner.hasChild() && isIdentifier(owner, owner.getChild())) { this.isInObjectIdentifierExpression = true; - if (projectedVariable.equals(objectNode.getValue()) && currentPointerIsNotAttributeReference()) { + if (projectedVariable.equals(owner.getValue()) && currentPointerIsNotAttributeReference()) { attrPointer.setProjected(true); } else { newAttr.setProjected(true); @@ -211,68 +165,119 @@ public void enterObjWithAttr(SoqlParser.ObjWithAttrContext ctx) { } } - private boolean isIdentifier(SoqlNode objectNode, SoqlNode attributeNode) { - if (!objectTypes.containsKey(objectNode.getValue())) { - return false; + private SoqlNode linkSimpleSubpath(ParserRuleContext ctx) { + AttributeNode firstNode = new AttributeNode(getOwnerFromParam(ctx)); + AttributeNode currentNode = firstNode; + + while (ctx.getChildCount() == 3) { + ctx = (ParserRuleContext) ctx.getChild(2); + SoqlNode prevNode = currentNode; + currentNode = new AttributeNode(prevNode, ctx.getChild(0).getText()); + prevNode.setChild(currentNode); } - final String objectName = objectTypes.get(objectNode.getValue()); - IdentifiableEntityType entityType = getEntityType(objectName); - if (entityType == null) { - return false; + setIris(firstNode); + if (currentNode.getIri().isEmpty()) { + this.isInObjectIdentifierExpression = true; + if (projectedVariable != null && projectedVariable.equals(firstNode.getValue()) && currentPointerIsNotAttributeReference()) { + attrPointer.setProjected(true); + } } - return entityType.getIdentifier().getName().equals(attributeNode.getValue()); + return firstNode; } - private boolean currentPointerIsNotAttributeReference() { - return !attrPointer.getFirstNode().hasChild(); + @Override + public void exitSimpleSubpath(SoqlParser.SimpleSubpathContext ctx) { + } @Override - public void exitObjWithAttr(SoqlParser.ObjWithAttrContext ctx) { + public void enterSingleValuedObjectField(SoqlParser.SingleValuedObjectFieldContext ctx) { + } @Override - public void enterObjWithOutAttr(SoqlParser.ObjWithOutAttrContext ctx) { + public void exitSingleValuedObjectField(SoqlParser.SingleValuedObjectFieldContext ctx) { + } @Override - public void exitObjWithOutAttr(SoqlParser.ObjWithOutAttrContext ctx) { + public void enterSelectClause(SoqlParser.SelectClauseContext ctx) { + this.typeDef = SparqlConstants.SELECT; + + if(ctx.DISTINCT() != null) { + this.isSelectedParamDistinct = true; + } } @Override - public void enterAttribute(SoqlParser.AttributeContext ctx) { + public void exitSelectClause(SoqlParser.SelectClauseContext ctx) { + } @Override - public void exitAttribute(SoqlParser.AttributeContext ctx) { + public void enterSelectItem(SoqlParser.SelectItemContext ctx) { + } @Override - public void enterTypeDef(SoqlParser.TypeDefContext ctx) { - typeDef = ctx.getChild(0).getText(); + public void exitSelectItem(SoqlParser.SelectItemContext ctx) { + } @Override - public void exitTypeDef(SoqlParser.TypeDefContext ctx) { + public void enterSelectExpression(SoqlParser.SelectExpressionContext ctx) { + + } + + private void pushNewAttribute(SoqlAttribute myAttr) { + attributes.add(myAttr); + this.attrPointer = myAttr; + } + + private void popAttribute() { + this.attrPointer = attributes.remove(attributes.size() - 1); } @Override - public void enterDistinct(SoqlParser.DistinctContext ctx) { - if (SoqlConstants.DISTINCT.equals(ctx.getChild(0).getText())) { - isSelectedParamDistinct = true; + public void exitSelectExpression(SoqlParser.SelectExpressionContext ctx) { + if (!isSelectedParamCount) { + this.projectedVariable = ctx.getText(); } } @Override - public void exitDistinct(SoqlParser.DistinctContext ctx) { + public void enterAggregateExpression(SoqlParser.AggregateExpressionContext ctx) { + if(ctx.COUNT() != null) { + isSelectedParamCount = true; + if(ctx.DISTINCT() != null) { + isSelectedParamDistinct = true; + } + + if(ctx.simpleSubpath() != null) { + this.projectedVariable = ctx.simpleSubpath().getText(); + } + } } @Override - public void enterWhereClauseWrapper(SoqlParser.WhereClauseWrapperContext ctx) { + public void exitAggregateExpression(SoqlParser.AggregateExpressionContext ctx) { + } - @Override - public void exitWhereClauseWrapper(SoqlParser.WhereClauseWrapperContext ctx) { + private boolean isIdentifier(SoqlNode objectNode, SoqlNode attributeNode) { + if (!objectTypes.containsKey(objectNode.getValue())) { + return false; + } + final String objectName = objectTypes.get(objectNode.getValue()); + IdentifiableEntityType entityType = getEntityType(objectName); + if (entityType == null) { + return false; + } + return entityType.getIdentifier().getName().equals(attributeNode.getValue()); + } + + private boolean currentPointerIsNotAttributeReference() { + return !attrPointer.getFirstNode().hasChild(); } @Override @@ -325,7 +330,7 @@ public void exitInExpression(SoqlParser.InExpressionContext ctx) { pushNewAttribute(createSyntheticAttributeForEntityId()); } final ParseTree value = resolveInExpressionValue(ctx); - if (ctx.getChild(1).getText().equals(SoqlConstants.NOT)) { + if (ctx.NOT() != null) { attrPointer.setOperator(InOperator.notIn()); } else { attrPointer.setOperator(InOperator.in()); @@ -335,17 +340,16 @@ public void exitInExpression(SoqlParser.InExpressionContext ctx) { } private SoqlAttribute createSyntheticAttributeForEntityId() { - return new SoqlAttribute( - attrPointer.getFirstNode().hasChild() ? attrPointer.getFirstNode().getChild() : - new AttributeNode(rootVariable.substring(1))); + if(attrPointer.getFirstNode().hasChild()) { + attrPointer.getFirstNode().getChild().setChild(null); + return new SoqlAttribute(attrPointer.getFirstNode().getChild()); + } + + return new SoqlAttribute(new AttributeNode(rootVariable.substring(1))); } private ParseTree resolveInExpressionValue(SoqlParser.InExpressionContext ctx) { - final ParseTree lastToken = ctx.getChild(ctx.getChildCount() - 1); - if (")".equals(lastToken.getText())) { - return ctx.getChild(ctx.getChildCount() - 2); - } - return lastToken; + return ctx.inItem().get(ctx.inItem().size() - 1); } @Override @@ -398,6 +402,16 @@ public void exitMemberOfExpression(SoqlParser.MemberOfExpressionContext ctx) { this.isInObjectIdentifierExpression = false; } + @Override + public void enterEntityExpression(SoqlParser.EntityExpressionContext ctx) { + + } + + @Override + public void exitEntityExpression(SoqlParser.EntityExpressionContext ctx) { + + } + @Override public void enterComparisonExpression(SoqlParser.ComparisonExpressionContext ctx) { } @@ -437,58 +451,39 @@ private boolean isRootIdentifier(SoqlAttribute attribute) { } @Override - public void enterTables(SoqlParser.TablesContext ctx) { - } - - @Override - public void exitTables(SoqlParser.TablesContext ctx) { + public void enterFromClause(SoqlParser.FromClauseContext ctx) { + String entityName = ctx.entityName().getText(); + String identificationVariable = ctx.IDENTIFICATION_VARIABLE().getText(); + objectTypes.put(identificationVariable, entityName); + SoqlNode node = new AttributeNode(entityName); + setObjectIri(node); + SoqlAttribute myAttr = new SoqlAttribute(node); + pushNewAttribute(myAttr); } @Override - public void enterTable(SoqlParser.TableContext ctx) { - } + public void exitFromClause(SoqlParser.FromClauseContext ctx) { - @Override - public void exitTable(SoqlParser.TableContext ctx) { } @Override - public void enterTableName(SoqlParser.TableNameContext ctx) { - } + public void enterEntityName(SoqlParser.EntityNameContext ctx) { - @Override - public void exitTableName(SoqlParser.TableNameContext ctx) { } @Override - public void enterTableWithName(SoqlParser.TableWithNameContext ctx) { - String table = ctx.getChild(0).getChild(0).getText(); - String objectName = ctx.getChild(1).getChild(0).getText(); - objectTypes.put(objectName, table); - SoqlNode node = new AttributeNode(table); - setObjectIri(node); - SoqlAttribute myAttr = new SoqlAttribute(node); - pushNewAttribute(myAttr); - } + public void exitEntityName(SoqlParser.EntityNameContext ctx) { - @Override - public void exitTableWithName(SoqlParser.TableWithNameContext ctx) { } @Override - public void enterWhereClauseValue(SoqlParser.WhereClauseValueContext ctx) { - } + public void enterWhereClause(SoqlParser.WhereClauseContext ctx) { - @Override - public void exitWhereClauseValue(SoqlParser.WhereClauseValueContext ctx) { } @Override - public void enterWhereClauseParam(SoqlParser.WhereClauseParamContext ctx) { - } + public void exitWhereClause(SoqlParser.WhereClauseContext ctx) { - @Override - public void exitWhereClauseParam(SoqlParser.WhereClauseParamContext ctx) { } @Override @@ -573,24 +568,8 @@ public void exitOrderByClause(SoqlParser.OrderByClauseContext ctx) { } @Override - public void enterOrderByFullFormComma(SoqlParser.OrderByFullFormCommaContext ctx) { - } - - @Override - public void exitOrderByFullFormComma(SoqlParser.OrderByFullFormCommaContext ctx) { - } - - @Override - public void enterOrderByFullForm(SoqlParser.OrderByFullFormContext ctx) { - } - - @Override - public void exitOrderByFullForm(SoqlParser.OrderByFullFormContext ctx) { - } - - @Override - public void enterOrderByParam(SoqlParser.OrderByParamContext ctx) { - SoqlNode firstNode = linkContextNodes(ctx); + public void enterOrderByItem(SoqlParser.OrderByItemContext ctx) { + SoqlNode firstNode = linkObjectPathExpression(ctx); String orderingBy = getOrderingBy(ctx.getParent()); SoqlOrderParameter orderParam = new SoqlOrderParameter(firstNode, orderingBy); boolean attrSet = false; @@ -611,28 +590,21 @@ public void enterOrderByParam(SoqlParser.OrderByParamContext ctx) { } @Override - public void exitOrderByParam(SoqlParser.OrderByParamContext ctx) { + public void exitOrderByItem(SoqlParser.OrderByItemContext ctx) { } @Override public void enterGroupByClause(SoqlParser.GroupByClauseContext ctx) { - } - - @Override - public void exitGroupByClause(SoqlParser.GroupByClauseContext ctx) { - } - @Override - public void enterGroupByParamComma(SoqlParser.GroupByParamCommaContext ctx) { } @Override - public void exitGroupByParamComma(SoqlParser.GroupByParamCommaContext ctx) { + public void exitGroupByClause(SoqlParser.GroupByClauseContext ctx) { } @Override - public void enterGroupByParam(SoqlParser.GroupByParamContext ctx) { - SoqlNode firstNode = linkContextNodes(ctx); + public void enterGroupByItem(SoqlParser.GroupByItemContext ctx) { + SoqlNode firstNode = linkObjectPathExpression(ctx); SoqlGroupParameter groupParam = new SoqlGroupParameter(firstNode); boolean attrSet = false; for (SoqlAttribute attr : attributes) { @@ -651,6 +623,11 @@ public void enterGroupByParam(SoqlParser.GroupByParamContext ctx) { groupAttributes.add(groupParam); } + @Override + public void exitGroupByItem(SoqlParser.GroupByItemContext ctx) { + + } + private SoqlNode linkContextNodes(ParserRuleContext ctx) { SoqlNode firstNode = new AttributeNode(getOwnerFromParam(ctx)); SoqlNode currentNode = firstNode; @@ -667,8 +644,20 @@ private SoqlNode linkContextNodes(ParserRuleContext ctx) { return firstNode; } - @Override - public void exitGroupByParam(SoqlParser.GroupByParamContext ctx) { + private SoqlNode linkObjectPathExpression(ParserRuleContext ctx) { + SoqlNode firstNode = new AttributeNode(getOwnerFromParam(ctx)); + SoqlNode currentNode = firstNode; + for (int i = 2; i < ctx.getChild(0).getChildCount(); i += 2) { + SoqlNode prevNode = currentNode; + currentNode = new AttributeNode(prevNode, ctx.getChild(0).getChild(i).getText()); + prevNode.setChild(currentNode); + } + setIris(firstNode); + if (currentNode.getIri().isEmpty()) { + currentNode.getParent().setChild(null); + this.isInObjectIdentifierExpression = true; + } + return firstNode; } @Override @@ -681,6 +670,16 @@ public void exitInputParameter(SoqlParser.InputParameterContext ctx) { } + @Override + public void enterComparisonOperator(SoqlParser.ComparisonOperatorContext ctx) { + + } + + @Override + public void exitComparisonOperator(SoqlParser.ComparisonOperatorContext ctx) { + + } + @Override public void visitTerminal(TerminalNode terminalNode) { }