-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#2196 Introduce major abstractions for transformation of EQL to stage…
… 1 with ANTLR
- Loading branch information
1 parent
f320df3
commit 3026851
Showing
6 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
platform-dao/src/main/java/ua/com/fielden/platform/eql/antlr/EqlCompilationResult.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package ua.com.fielden.platform.eql.antlr; | ||
|
||
import ua.com.fielden.platform.eql.stage1.conditions.Conditions1; | ||
import ua.com.fielden.platform.eql.stage1.operands.Expression1; | ||
import ua.com.fielden.platform.eql.stage1.sources.IJoinNode1; | ||
import ua.com.fielden.platform.eql.stage1.sundries.GroupBys1; | ||
import ua.com.fielden.platform.eql.stage1.sundries.OrderBys1; | ||
import ua.com.fielden.platform.eql.stage1.sundries.Yields1; | ||
import ua.com.fielden.platform.eql.stage2.sources.IJoinNode2; | ||
|
||
public sealed interface EqlCompilationResult { | ||
|
||
String description(); | ||
|
||
record Select(IJoinNode1<? extends IJoinNode2<?>> joinRoot, | ||
Conditions1 whereConditions, | ||
Yields1 yields, | ||
GroupBys1 groups, | ||
boolean yieldAll) | ||
implements EqlCompilationResult | ||
{ | ||
@Override | ||
public String description() { | ||
return "Select Query"; | ||
} | ||
} | ||
|
||
record StandaloneExpression(Expression1 model) implements EqlCompilationResult { | ||
@Override | ||
public String description() { | ||
return "Standalone Expression"; | ||
} | ||
} | ||
|
||
record StandaloneCondition(Conditions1 model) implements EqlCompilationResult { | ||
@Override | ||
public String description() { | ||
return "Standalone Condition"; | ||
} | ||
} | ||
|
||
record OrderBy(OrderBys1 model) implements EqlCompilationResult { | ||
@Override | ||
public String description() { | ||
return "Order By"; | ||
} | ||
} | ||
|
||
} |
138 changes: 138 additions & 0 deletions
138
platform-dao/src/main/java/ua/com/fielden/platform/eql/antlr/EqlCompiler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package ua.com.fielden.platform.eql.antlr; | ||
|
||
import org.antlr.v4.runtime.CommonTokenStream; | ||
import org.antlr.v4.runtime.ListTokenSource; | ||
import org.antlr.v4.runtime.RecognitionException; | ||
import org.antlr.v4.runtime.Token; | ||
import ua.com.fielden.platform.eql.antlr.tokens.PropToken; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* Compiles EQL sentences (sequences of tokens) into Stage 1 representation. | ||
* | ||
* <h3>ANTLR visitor implementation patterns</h3> | ||
* | ||
* <ol> | ||
* <li> Terminal derivation rules: context class with a {@code token} field holding the value of the concrete token. | ||
* {@snippet : | ||
* unaryComparisonOperator : | ||
* token=ISNULL | ||
* | token=ISNOTNULL ; | ||
* } | ||
* {@snippet : | ||
* class UnaryComparisonOperatorContext extends ParserRuleContext { | ||
* public Token token; | ||
* public TerminalNode ISNULL() {...} | ||
* public TerminalNode ISNOTNULL() {...} | ||
* ... | ||
* } | ||
* } | ||
* Visitor code should use the value of {@code token} to determine the actual token. | ||
* <p> | ||
* If the token is parameterised it will have a corresponding custom token type. | ||
* For example, {@code prop("a.b.c")} would be represented by an instance of {@link PropToken} carrying the specified property path. | ||
* In such cases the {@code token} field should be type-casted to the respective type. | ||
* | ||
* <li> Specialization rules: a hierarchy of context classes. | ||
* {@snippet : | ||
* condition : | ||
* predicate # PredicateCondition | ||
* | left=condition AND right=condition # AndCondition | ||
* | left=condition OR right=condition # OrCondition ; | ||
* } | ||
* {@snippet : | ||
* class ConditionContext extends ParserRuleContext {...} | ||
* class PredicateContext extends ConditionContext {...} | ||
* class AndConditionContext extends ConditionContext {...} | ||
* class OrConditionContext extends ConditionContext {...} | ||
* } | ||
* | ||
* The visitor interface will not contain an explicit visiting method for the base type ({@code ConditionContext}) | ||
* but rather will dispatch on its actual type and invoke the respective visiting method (for one of its subtypes). | ||
* | ||
* {@snippet : | ||
* // ConditionContext is not visited, but rather dispatches on its actual ype | ||
* ConditionContext cc = ..; | ||
* cc.accept(visitor); | ||
* } | ||
* | ||
* The {@code condition} rule above involves 2 different kinds of rule body: | ||
* <ol> | ||
* <li> Inlined. This kind is elegant as it results in generation of a class that directly corresponds to the body. | ||
* {@snippet : | ||
* left=condition AND right=condition # AndCondition | ||
* } | ||
* {@snippet : | ||
* class AndConditionContext extends ConditionContext { | ||
* final ConditionContext left; | ||
* final ConditionContext right; | ||
* } | ||
* } | ||
* | ||
* <li> Not inlined. This kind is the opposite of elegant as it involves an additional step of indirection. | ||
* | ||
* {@snippet : | ||
* predicate # PredicateCondition | ||
* } | ||
* {@snippet : | ||
* class PredicateConditionContext extends ConditionContext { | ||
* public PredicateContext predicate() {...} | ||
* } | ||
* } | ||
* | ||
* One consequence of this is that visitor code must implement an additional method to handle the indirection. | ||
* | ||
* {@snippet : | ||
* public Object visitPredicateCondition(PredicateConditionContext ctx) { | ||
* return ctx.predicate().accept(this); | ||
* } | ||
* } | ||
* One reason for having rule bodies that are not inlined is the ability to reuse them. | ||
* </ol> | ||
* | ||
* </ol> | ||
*/ | ||
public final class EqlCompiler { | ||
|
||
public EqlCompilationResult compile(final List<? extends Token> tokens) { | ||
final var tokenStream = new CommonTokenStream(new ListTokenSource(tokens)); | ||
final var parser = new EQLParser(tokenStream); | ||
final var visitor = new Visitor(); | ||
try { | ||
return parser.start().accept(visitor); | ||
} catch (RecognitionException e) { | ||
throw new RuntimeException("Compilation of an EQL expression failed", e); | ||
} | ||
} | ||
|
||
private static final class Visitor extends EQLBaseVisitor<EqlCompilationResult> { | ||
|
||
@Override | ||
public EqlCompilationResult visitStart(final EQLParser.StartContext ctx) { | ||
return ctx.query().accept(this); | ||
} | ||
|
||
@Override | ||
public EqlCompilationResult visitQuery_Select(final EQLParser.Query_SelectContext ctx) { | ||
return new SelectVisitor().visitQuery_Select(ctx); | ||
} | ||
|
||
@Override | ||
public EqlCompilationResult visitStandaloneExpression(final EQLParser.StandaloneExpressionContext ctx) { | ||
return new StandaloneExpressionVisitor().visitStandaloneExpression(ctx); | ||
} | ||
|
||
@Override | ||
public EqlCompilationResult visitStandaloneCondExpr(final EQLParser.StandaloneCondExprContext ctx) { | ||
return new StandaloneConditionVisitor().visitStandaloneCondExpr(ctx); | ||
} | ||
|
||
@Override | ||
public EqlCompilationResult visitOrderBy(final EQLParser.OrderByContext ctx) { | ||
return new OrderByVisitor().visitOrderBy(ctx); | ||
} | ||
|
||
} | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
platform-dao/src/main/java/ua/com/fielden/platform/eql/antlr/OrderByVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ua.com.fielden.platform.eql.antlr; | ||
|
||
final class OrderByVisitor extends EQLBaseVisitor<EqlCompilationResult.OrderBy> { | ||
|
||
@Override | ||
public EqlCompilationResult.OrderBy visitOrderBy(final EQLParser.OrderByContext ctx) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
} |
11 changes: 11 additions & 0 deletions
11
platform-dao/src/main/java/ua/com/fielden/platform/eql/antlr/SelectVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package ua.com.fielden.platform.eql.antlr; | ||
|
||
|
||
final class SelectVisitor extends EQLBaseVisitor<EqlCompilationResult.Select> { | ||
|
||
@Override | ||
public EqlCompilationResult.Select visitQuery_Select(final EQLParser.Query_SelectContext ctx) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
platform-dao/src/main/java/ua/com/fielden/platform/eql/antlr/StandaloneConditionVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ua.com.fielden.platform.eql.antlr; | ||
|
||
final class StandaloneConditionVisitor extends EQLBaseVisitor<EqlCompilationResult.StandaloneCondition> { | ||
|
||
@Override | ||
public EqlCompilationResult.StandaloneCondition visitStandaloneCondExpr(final EQLParser.StandaloneCondExprContext ctx) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
...form-dao/src/main/java/ua/com/fielden/platform/eql/antlr/StandaloneExpressionVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ua.com.fielden.platform.eql.antlr; | ||
|
||
final class StandaloneExpressionVisitor extends EQLBaseVisitor<EqlCompilationResult.StandaloneExpression> { | ||
|
||
@Override | ||
public EqlCompilationResult.StandaloneExpression visitStandaloneExpression(final EQLParser.StandaloneExpressionContext ctx) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
} |