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

tkobayas pushed a commit to branch dev-new-parser
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git


The following commit(s) were added to refs/heads/dev-new-parser by this push:
     new df9bfbd507 [incubator-kie-drools-5798] [new-parser] Ensure Descr 
properties (#5827)
df9bfbd507 is described below

commit df9bfbd507c2d2a955c959b8658148188bcd7f12
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Fri Apr 5 17:19:35 2024 +0900

    [incubator-kie-drools-5798] [new-parser] Ensure Descr properties (#5827)
    
    * [incubator-kie-drools-5798] [new-parser] Ensure Descr properties
    
    * [incubator-kie-issues#5798] Proposal
    
    * minor fix
    
    ---------
    
    Co-authored-by: Gabriele-Cardosi <[email protected]>
---
 .../drl/parser/antlr4/DescrCommonPropertyTest.java | 405 +++++++++++++++++++++
 .../org/drools/drl/parser/antlr4/DRLParser.g4      |   9 +-
 .../drools/drl/parser/antlr4/BaseDescrFactory.java |  60 +++
 .../drools/drl/parser/antlr4/DRLVisitorImpl.java   | 198 +++++-----
 .../org/drools/drl/parser/antlr4/DescrHelper.java  |  70 ++++
 5 files changed, 653 insertions(+), 89 deletions(-)

diff --git 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DescrCommonPropertyTest.java
 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DescrCommonPropertyTest.java
new file mode 100644
index 0000000000..bc3010e698
--- /dev/null
+++ 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DescrCommonPropertyTest.java
@@ -0,0 +1,405 @@
+package org.drools.drl.parser.antlr4;
+
+import org.drools.drl.ast.descr.AccumulateDescr;
+import org.drools.drl.ast.descr.AccumulateImportDescr;
+import org.drools.drl.ast.descr.AndDescr;
+import org.drools.drl.ast.descr.AnnotationDescr;
+import org.drools.drl.ast.descr.BaseDescr;
+import org.drools.drl.ast.descr.BehaviorDescr;
+import org.drools.drl.ast.descr.CollectDescr;
+import org.drools.drl.ast.descr.EntryPointDeclarationDescr;
+import org.drools.drl.ast.descr.EntryPointDescr;
+import org.drools.drl.ast.descr.EvalDescr;
+import org.drools.drl.ast.descr.ExistsDescr;
+import org.drools.drl.ast.descr.ExprConstraintDescr;
+import org.drools.drl.ast.descr.ForallDescr;
+import org.drools.drl.ast.descr.FromDescr;
+import org.drools.drl.ast.descr.FunctionDescr;
+import org.drools.drl.ast.descr.FunctionImportDescr;
+import org.drools.drl.ast.descr.GlobalDescr;
+import org.drools.drl.ast.descr.ImportDescr;
+import org.drools.drl.ast.descr.NotDescr;
+import org.drools.drl.ast.descr.OrDescr;
+import org.drools.drl.ast.descr.PackageDescr;
+import org.drools.drl.ast.descr.PatternDescr;
+import org.drools.drl.ast.descr.PatternSourceDescr;
+import org.drools.drl.ast.descr.QueryDescr;
+import org.drools.drl.ast.descr.RuleDescr;
+import org.drools.drl.ast.descr.TypeDeclarationDescr;
+import org.drools.drl.ast.descr.TypeFieldDescr;
+import org.drools.drl.ast.descr.UnitDescr;
+import org.drools.drl.ast.descr.WindowDeclarationDescr;
+import org.drools.drl.ast.descr.WindowReferenceDescr;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/*
+ * This test class is to assert Descr common properties
+ */
+class DescrCommonPropertyTest {
+
+    private DRLParserWrapper parser;
+
+    @BeforeEach
+    public void setUp() {
+        parser = new DRLParserWrapper();
+    }
+
+    @AfterEach
+    public void tearDown() {
+    }
+
+    private void assertProperties(BaseDescr descr, int startCharacter, int 
endCharacter, int line, int column, int endLine, int endColumn) {
+        assertThat(descr.getStartCharacter()).isEqualTo(startCharacter); // 
first character of the start token. character is 0-based
+        assertThat(descr.getEndCharacter()).isEqualTo(endCharacter); // last 
character of the end token. character is 0-based
+        assertThat(descr.getLine()).isEqualTo(line); // line of the start 
token. line is 1-based
+        assertThat(descr.getColumn()).isEqualTo(column); // first column of 
the start token. column is 0-based
+        assertThat(descr.getEndLine()).isEqualTo(endLine); // line of the end 
token. line is 1-based
+        assertThat(descr.getEndColumn()).isEqualTo(endColumn); // last column 
of the end token. column is 0-based
+    }
+
+    @Test
+    void packageDescr() {
+        final String source = "package foo.bar.baz";
+        final PackageDescr pkg = parser.parse(source);
+        assertProperties(pkg, 0, 18, 1, 0, 1, 18);
+    }
+
+    @Test
+    void ruleDescr() {
+        final String source = "rule \"MyRule\"\n" +
+                "  when\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        assertProperties(rule, 0, 30, 1, 0, 4, 2);
+    }
+
+    @Test
+    void unitDescr() {
+        final String source = "unit Foo;";
+        final PackageDescr pkg = parser.parse(source);
+        final UnitDescr unit = pkg.getUnit();
+        assertProperties(unit, 0, 8, 1, 0, 1, 8);
+    }
+
+    @Test
+    void queryDescr() {
+        final String source = "query \"MyQuery\"\n" +
+                "  Foo()\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final QueryDescr query = (QueryDescr) pkg.getRules().get(0);
+        assertProperties(query, 0, 26, 1, 0, 3, 2);
+    }
+
+    @Test
+    void functionDescr() {
+        final String source = "function void myFunction(String data) {\n" +
+                "  foo();\n" +
+                "}";
+        final PackageDescr pkg = parser.parse(source);
+        final FunctionDescr function = pkg.getFunctions().get(0);
+        assertProperties(function, 0, 49, 1, 0, 3, 0);
+    }
+
+    @Test
+    void globalDescr() {
+        final String source = "global java.util.List myList";
+        final PackageDescr pkg = parser.parse(source);
+        final GlobalDescr global = pkg.getGlobals().get(0);
+        assertProperties(global, 0, 27, 1, 0, 1, 27);
+    }
+
+    @Test
+    void functionImportDescr() {
+        final String source = "import function 
org.drools.core.util.DateUtils.*";
+        final PackageDescr pkg = parser.parse(source);
+        final FunctionImportDescr functionImport = 
pkg.getFunctionImports().get(0);
+        assertProperties(functionImport, 0, 47, 1, 0, 1, 47);
+    }
+
+    @Test
+    void importDescr() {
+        final String source = "import org.drools.core.util.DateUtils";
+        final PackageDescr pkg = parser.parse(source);
+        final ImportDescr importDescr = pkg.getImports().get(0);
+        assertProperties(importDescr, 0, 36, 1, 0, 1, 36);
+    }
+
+    @Test
+    void accumulateImportDescr() {
+        final String source = "import accumulate org.example.MyAccUtils.sum 
mySum";
+        final PackageDescr pkg = parser.parse(source);
+        final AccumulateImportDescr accumulateImport = 
pkg.getAccumulateImports().get(0);
+        assertProperties(accumulateImport, 0, 49, 1, 0, 1, 49);
+    }
+
+    @Test
+    void typeDeclarationDescr() {
+        final String source = "declare MyType\n" +
+                "  name : String\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final TypeDeclarationDescr typeDeclaration = 
pkg.getTypeDeclarations().get(0);
+
+        // startCharacter = 8 looks a little odd ("declare" is not included in 
the Descr), but it keeps the same as the old implementation. We may change it 
in the future.
+        assertProperties(typeDeclaration, 8, 33, 1, 8, 3, 2);
+    }
+
+    @Test
+    void entryPointDeclarationDescr() {
+        final String source = "declare entry-point MyEntryPoint\n" +
+                "  @foo( true )\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final EntryPointDeclarationDescr entryPointDeclaration = 
pkg.getEntryPointDeclarations().stream().findFirst().get();
+        assertProperties(entryPointDeclaration, 8, 50, 1, 8, 3, 2);
+    }
+
+    @Test
+    void windowDeclarationDescr() {
+        final String source = "declare window MyWindow\n" +
+                "  $s : StockTick( source == \"NYSE\" )\n" +
+                "       over window:length( 10, $s.symbol )\n" +
+                "       from entry-point stStream\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final WindowDeclarationDescr windowDeclaration = 
pkg.getWindowDeclarations().stream().findFirst().get();
+        assertProperties(windowDeclaration, 8, 139, 1, 8, 5, 2);
+    }
+
+    @Test
+    void annotationDescr() {
+        final String source = "package org.drools\n" +
+                "rule R1\n" +
+                "when\n" +
+                "  $p : Person( name == \"Mario\" ) @watch(!*, age)\n" +
+                "then\n" +
+                "end\n";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        AnnotationDescr annotation = 
rule.getLhs().getAllPatternDescr().get(0).getAnnotations().stream().findFirst().get();
+        assertProperties(annotation, 65, 79, 4, 33, 4, 47);
+    }
+
+    @Test
+    void typeFieldDescr() {
+        final String source = "declare MyType\n" +
+                "  name : String\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final TypeDeclarationDescr typeDeclaration = 
pkg.getTypeDeclarations().get(0);
+        TypeFieldDescr typeField = typeDeclaration.getFields().get("name");
+        assertProperties(typeField, 17, 29, 2, 2, 2, 14);
+    }
+
+    @Test
+    void attributeDescr() {
+        final String source = "rule R1\n" +
+                "  salience 42\n" +
+                "  agenda-group \"my_group\"\n" +
+                "  when\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        assertProperties(rule.getAttributes().get("salience"), 10, 20, 2, 2, 
2, 12);
+        assertProperties(rule.getAttributes().get("agenda-group"), 24, 46, 3, 
2, 3, 24);
+    }
+
+    @Test
+    void patternDescr() {
+        final String source = "rule R1\n" +
+                "  when\n" +
+                "    $p : Person( name == \"Mario\" )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
+        assertProperties(pattern, 19, 48, 3, 4, 3, 33);
+    }
+
+    @Test
+    void orDescr() {
+        final String source = "rule R1\n" +
+                "  when\n" +
+                "    ( $p : Person( name == \"Mario\" ) or $p : Person( name 
== \"Luigi\" ) )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        OrDescr or = (OrDescr) rule.getLhs().getDescrs().get(0);
+        assertProperties(or, 21, 84, 3, 6, 3, 69);
+    }
+
+    @Test
+    void andDescr() {
+        final String source = "rule R1\n" +
+                "  when\n" +
+                "    ( $p1 : Person( name == \"Mario\" ) and $p2 : Person( 
name == \"Luigi\" ) )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        AndDescr and = rule.getLhs();
+        assertProperties(and, 21, 87, 3, 6, 3, 72);
+    }
+
+    @Test
+    void forallDescr() {
+        final String source = "rule R1\n" +
+                "  when\n" +
+                "    forall( $p : Person( name == \"Mario\" ) )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        ForallDescr forall = (ForallDescr) rule.getLhs().getDescrs().get(0);
+        assertProperties(forall, 19, 58, 3, 4, 3, 43);
+    }
+
+    @Test
+    void accumulateDescr() {
+        final String source = "rule R1\n" +
+                "  when\n" +
+                "    accumulate( $p : Person( name == \"Mario\" ), $sum : 
sum($p.getAge()) )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
+        AccumulateDescr accumulate = (AccumulateDescr) pattern.getSource();
+        assertProperties(accumulate, 19, 87, 3, 4, 3, 72);
+    }
+
+    @Test
+    void behaviorDescr() {
+        final String source = "rule X when StockTick( symbol==\"ACME\") over 
window:length(10) then end";;
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
+        BehaviorDescr behavior = pattern.getBehaviors().get(0);
+
+        // "over" is not included in BehaviorDescr
+        assertProperties(behavior, 44, 60, 1, 44, 1, 60);
+    }
+
+    @Test
+    void fromDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    Adult( $children : children)\n" +
+                "    Child() from $children\n" +
+                "  then\n" +
+                "end";;
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(1);
+        FromDescr from = (FromDescr)  pattern.getSource();
+
+        // "from" is not included in FromDescr
+        assertProperties(from, 64, 72, 4, 17, 4, 25);
+    }
+
+    @Test
+    void collectDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    ArrayList() from collect( Person( age > 21 ) );\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
+        CollectDescr collect = (CollectDescr)  pattern.getSource();
+
+        assertProperties(collect, 35, 63, 3, 21, 3, 49);
+    }
+
+    @Test
+    void entryPointDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    StockTick() from entry-point \"stream\"\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
+        EntryPointDescr entryPoint = (EntryPointDescr) pattern.getSource();
+        assertProperties(entryPoint, 35, 54, 3, 21, 3, 40);
+    }
+
+    @Test
+    void windowReferenceDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    StockTick() from window MyWindow\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
+        WindowReferenceDescr windowReference = (WindowReferenceDescr) 
pattern.getSource();
+        assertProperties(windowReference, 35, 49, 3, 21, 3, 35);
+    }
+
+    @Test
+    void exprConstraintDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    Person( age > 21 )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
+        ExprConstraintDescr exprConstraint = (ExprConstraintDescr) 
pattern.getDescrs().get(0);
+        assertProperties(exprConstraint, 26, 33, 3, 12, 3, 19);
+    }
+
+    @Test
+    void existDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    exists( Person( age > 21 ) )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        ExistsDescr exists = (ExistsDescr) rule.getLhs().getDescrs().get(0);
+        assertProperties(exists, 18, 45, 3, 4, 3, 31);
+    }
+
+    @Test
+    void notDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    not( Person( age > 21 ) )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        NotDescr not = (NotDescr) rule.getLhs().getDescrs().get(0);
+        assertProperties(not, 18, 42, 3, 4, 3, 28);
+    }
+
+    @Test
+    void evalDescr() {
+        final String source = "rule X\n" +
+                "  when\n" +
+                "    eval( 1 + 1 == 2 )\n" +
+                "  then\n" +
+                "end";
+        final PackageDescr pkg = parser.parse(source);
+        final RuleDescr rule = pkg.getRules().get(0);
+        EvalDescr eval = (EvalDescr) rule.getLhs().getDescrs().get(0);
+        assertProperties(eval, 18, 35, 3, 4, 3, 21);
+    }
+}
diff --git 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
index 7d9dd2235f..6e975bc3fe 100644
--- 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
+++ 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
@@ -50,7 +50,8 @@ declaredef : DRL_DECLARE (
                          | entryPointDeclaration
                          | windowDeclaration
                          | typeDeclaration
-                         ) DRL_END SEMI?;
+                         )
+                         ; // DRL_END belongs to entryPointDeclaration etc.
 
 /*
  * typeDeclaration := [TYPE] qualifiedIdentifier (EXTENDS qualifiedIdentifier)?
@@ -59,15 +60,15 @@ declaredef : DRL_DECLARE (
  *                     END
  */
 
-typeDeclaration : DRL_TRAIT? name=drlQualifiedName (EXTENDS 
superTypes+=drlQualifiedName (COMMA superTypes+=drlQualifiedName)* )? 
drlAnnotation* field* ;
+typeDeclaration : DRL_TRAIT? name=drlQualifiedName (EXTENDS 
superTypes+=drlQualifiedName (COMMA superTypes+=drlQualifiedName)* )? 
drlAnnotation* field* DRL_END SEMI?;
 
 // entryPointDeclaration := ENTRY-POINT stringId annotation* END
 
-entryPointDeclaration : DRL_ENTRY_POINT name=stringId drlAnnotation* ;
+entryPointDeclaration : DRL_ENTRY_POINT name=stringId drlAnnotation* DRL_END 
SEMI?;
 
 // windowDeclaration := WINDOW ID annotation* lhsPatternBind END
 
-windowDeclaration : DRL_WINDOW name=IDENTIFIER drlAnnotation* lhsPatternBind ;
+windowDeclaration : DRL_WINDOW name=IDENTIFIER drlAnnotation* lhsPatternBind 
DRL_END SEMI?;
 
 // field := label fieldType (EQUALS_ASSIGN conditionalExpression)? annotation* 
SEMICOLON?
 
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/BaseDescrFactory.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/BaseDescrFactory.java
new file mode 100644
index 0000000000..31fe45747e
--- /dev/null
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/BaseDescrFactory.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.drools.drl.parser.antlr4;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.drools.drl.ast.descr.BaseDescr;
+
+import static 
org.drools.drl.parser.antlr4.DescrHelper.populateCommonProperties;
+
+/**
+ * Factory class for Descr instantiation.
+ */
+public class BaseDescrFactory {
+
+    private BaseDescrFactory() {
+        // Private constructor to prevent instantiation.
+    }
+
+    public static <T extends BaseDescr> Builder<T> builder(T toBuild) {
+        return new Builder<>(toBuild);
+    }
+
+    public static class Builder<T extends BaseDescr> {
+
+        T toReturn;
+
+        private Builder(T toBuild) {
+            this.toReturn = toBuild;
+        }
+
+        /**
+         * Initializes a BaseDescr instance with common properties from the 
given context.
+         * DRLVisitor implementations should always use this method to 
initialize BaseDescr instances.
+         */
+        public Builder<T> withParserRuleContext(ParserRuleContext ctx) {
+            populateCommonProperties(toReturn, ctx);
+            return this;
+        }
+
+        public T build() {
+            return toReturn;
+        }
+    }
+}
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
index 84ebe76f56..846a9bff9e 100644
--- 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
@@ -87,13 +87,14 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
      */
     @Override
     public PackageDescr visitCompilationUnit(DRLParser.CompilationUnitContext 
ctx) {
-        PackageDescr packageDescr = new PackageDescr();
+        PackageDescr packageDescr = BaseDescrFactory.builder(new 
PackageDescr())
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.packagedef() != null) {
             
packageDescr.setName(getTextWithoutErrorNode(ctx.packagedef().name));
         }
         List<BaseDescr> descrList = visitDescrChildren(ctx);
         applyChildrenDescrs(packageDescr, descrList);
-        populateStartEnd(packageDescr, ctx);
         return packageDescr;
     }
 
@@ -140,46 +141,51 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public UnitDescr visitUnitdef(DRLParser.UnitdefContext ctx) {
-        UnitDescr unitDescr = new UnitDescr(ctx.name.getText());
-        populateStartEnd(unitDescr, ctx);
-        return unitDescr;
+        return BaseDescrFactory.builder(new UnitDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
     }
 
     @Override
     public GlobalDescr visitGlobaldef(DRLParser.GlobaldefContext ctx) {
-        GlobalDescr globalDescr = new 
GlobalDescr(ctx.drlIdentifier().getText(), ctx.type().getText());
-        populateStartEnd(globalDescr, ctx);
-        return globalDescr;
+        return BaseDescrFactory.builder(new 
GlobalDescr(ctx.drlIdentifier().getText(), ctx.type().getText()))
+                .withParserRuleContext(ctx)
+                .build();
     }
 
     @Override
     public ImportDescr 
visitImportStandardDef(DRLParser.ImportStandardDefContext ctx) {
         String target = ctx.drlQualifiedName().getText() + (ctx.MUL() != null 
? ".*" : "");
         if (ctx.DRL_FUNCTION() != null || ctx.STATIC() != null) {
-            FunctionImportDescr functionImportDescr = new 
FunctionImportDescr();
+            FunctionImportDescr functionImportDescr = 
BaseDescrFactory.builder(new FunctionImportDescr())
+                    .withParserRuleContext(ctx)
+                    .build();
             functionImportDescr.setTarget(target);
-            populateStartEnd(functionImportDescr, ctx);
             return functionImportDescr;
         } else {
-            ImportDescr importDescr = new ImportDescr();
+            ImportDescr importDescr = BaseDescrFactory.builder(new 
ImportDescr())
+                    .withParserRuleContext(ctx)
+                    .build();
             importDescr.setTarget(target);
-            populateStartEnd(importDescr, ctx);
             return importDescr;
         }
     }
 
     @Override
     public AccumulateImportDescr 
visitImportAccumulateDef(DRLParser.ImportAccumulateDefContext ctx) {
-        AccumulateImportDescr accumulateImportDescr = new 
AccumulateImportDescr();
+        AccumulateImportDescr accumulateImportDescr = 
BaseDescrFactory.builder(new AccumulateImportDescr())
+                .withParserRuleContext(ctx)
+                .build();
         accumulateImportDescr.setTarget(ctx.drlQualifiedName().getText());
         accumulateImportDescr.setFunctionName(ctx.IDENTIFIER().getText());
-        populateStartEnd(accumulateImportDescr, ctx);
         return accumulateImportDescr;
     }
 
     @Override
     public FunctionDescr visitFunctiondef(DRLParser.FunctiondefContext ctx) {
-        FunctionDescr functionDescr = new FunctionDescr();
+        FunctionDescr functionDescr = BaseDescrFactory.builder(new 
FunctionDescr())
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.typeTypeOrVoid() != null) {
             functionDescr.setReturnType(ctx.typeTypeOrVoid().getText());
         } else {
@@ -199,7 +205,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             });
         }
         
functionDescr.setBody(getTextPreservingWhitespace(ctx.drlBlock().drlBlockStatement()));
-        populateStartEnd(functionDescr, ctx);
         return functionDescr;
     }
 
@@ -210,7 +215,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public TypeDeclarationDescr 
visitTypeDeclaration(DRLParser.TypeDeclarationContext ctx) {
-        TypeDeclarationDescr typeDeclarationDescr = new 
TypeDeclarationDescr(ctx.name.getText());
+        TypeDeclarationDescr typeDeclarationDescr = 
BaseDescrFactory.builder(new TypeDeclarationDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.DRL_TRAIT() != null) {
             typeDeclarationDescr.setTrait(true);
         }
@@ -225,30 +232,31 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         ctx.field().stream()
                 .map(this::visitField)
                 .forEach(typeDeclarationDescr::addField);
-        populateStartEnd(typeDeclarationDescr, ctx);
         return typeDeclarationDescr;
     }
 
     @Override
     public EntryPointDeclarationDescr 
visitEntryPointDeclaration(DRLParser.EntryPointDeclarationContext ctx) {
-        EntryPointDeclarationDescr entryPointDeclarationDescr = new 
EntryPointDeclarationDescr();
+        EntryPointDeclarationDescr entryPointDeclarationDescr = 
BaseDescrFactory.builder(new EntryPointDeclarationDescr())
+                .withParserRuleContext(ctx)
+                .build();
         entryPointDeclarationDescr.setEntryPointId(ctx.name.getText());
         ctx.drlAnnotation().stream()
                 .map(this::visitDrlAnnotation)
                 .forEach(entryPointDeclarationDescr::addAnnotation);
-        populateStartEnd(entryPointDeclarationDescr, ctx);
         return entryPointDeclarationDescr;
     }
 
     @Override
     public WindowDeclarationDescr 
visitWindowDeclaration(DRLParser.WindowDeclarationContext ctx) {
-        WindowDeclarationDescr windowDeclarationDescr = new 
WindowDeclarationDescr();
+        WindowDeclarationDescr windowDeclarationDescr = 
BaseDescrFactory.builder(new WindowDeclarationDescr())
+                .withParserRuleContext(ctx)
+                .build();
         windowDeclarationDescr.setName(ctx.name.getText());
         ctx.drlAnnotation().stream()
                 .map(this::visitDrlAnnotation)
                 .forEach(windowDeclarationDescr::addAnnotation);
         windowDeclarationDescr.setPattern((PatternDescr) 
visitLhsPatternBind(ctx.lhsPatternBind()));
-        populateStartEnd(windowDeclarationDescr, ctx);
         return windowDeclarationDescr;
     }
 
@@ -257,7 +265,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
      */
     @Override
     public RuleDescr visitRuledef(DRLParser.RuledefContext ctx) {
-        RuleDescr ruleDescr = new 
RuleDescr(safeStripStringDelimiters(ctx.name.getText()));
+        RuleDescr ruleDescr = BaseDescrFactory.builder(new 
RuleDescr(safeStripStringDelimiters(ctx.name.getText())))
+                .withParserRuleContext(ctx)
+                .build();
 
         if (ctx.EXTENDS() != null) {
             
ruleDescr.setParentName(safeStripStringDelimiters(ctx.parentName.getText()));
@@ -274,9 +284,11 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         }
 
         if (ctx.lhs() != null) {
+            final AndDescr rootDescr = ruleDescr.getLhs();
             List<BaseDescr> lhsDescrList = visitLhs(ctx.lhs());
-            lhsDescrList.forEach(descr -> ruleDescr.getLhs().addDescr(descr));
-            slimLhsRootDescr(ruleDescr.getLhs());
+            lhsDescrList.forEach(descr -> rootDescr.addDescr(descr));
+            slimLhsRootDescr(rootDescr);
+            DescrHelper.refreshRootProperties(rootDescr);
         }
 
         if (ctx.rhs() != null) {
@@ -284,7 +296,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             
ruleDescr.setConsequence(trimThen(getTokenTextPreservingWhitespace(ctx.rhs(), 
tokenStream))); // RHS is just a text
         }
 
-        populateStartEnd(ruleDescr, ctx);
         return ruleDescr;
     }
 
@@ -307,7 +318,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public QueryDescr visitQuerydef(DRLParser.QuerydefContext ctx) {
-        QueryDescr queryDescr = new 
QueryDescr(safeStripStringDelimiters(ctx.name.getText()));
+        QueryDescr queryDescr = BaseDescrFactory.builder(new 
QueryDescr(safeStripStringDelimiters(ctx.name.getText())))
+                .withParserRuleContext(ctx)
+                .build();
 
         DRLParser.ParametersContext parametersContext = ctx.parameters();
         if (parametersContext != null) {
@@ -327,13 +340,14 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
         slimLhsRootDescr(queryDescr.getLhs());
 
-        populateStartEnd(queryDescr, ctx);
         return queryDescr;
     }
 
     @Override
     public AnnotationDescr visitDrlAnnotation(DRLParser.DrlAnnotationContext 
ctx) {
-        AnnotationDescr annotationDescr = new 
AnnotationDescr(ctx.name.getText());
+        AnnotationDescr annotationDescr = BaseDescrFactory.builder(new 
AnnotationDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.drlElementValue() != null) {
             
annotationDescr.setValue(getTextPreservingWhitespace(ctx.drlElementValue())); 
// single value
         } else if (ctx.drlElementValuePairs() != null) {
@@ -342,13 +356,14 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             // A chunk that is neither a single value nor a list of key-value 
pairs. For example `!*, age` in `@watch(!*, age)`.
             annotationDescr.setValue(getTextPreservingWhitespace(ctx.chunk()));
         }
-        populateStartEnd(annotationDescr, ctx);
         return annotationDescr;
     }
 
     @Override
     public TypeFieldDescr visitField(DRLParser.FieldContext ctx) {
-        TypeFieldDescr typeFieldDescr = new TypeFieldDescr();
+        TypeFieldDescr typeFieldDescr = BaseDescrFactory.builder(new 
TypeFieldDescr())
+                .withParserRuleContext(ctx)
+                .build();
         typeFieldDescr.setFieldName(ctx.label().drlIdentifier().getText());
         typeFieldDescr.setPattern(new PatternDescr(ctx.type().getText()));
         if (ctx.ASSIGN() != null) {
@@ -357,7 +372,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         ctx.drlAnnotation().stream()
                 .map(this::visitDrlAnnotation)
                 .forEach(typeFieldDescr::addAnnotation);
-        populateStartEnd(typeFieldDescr, ctx);
         return typeFieldDescr;
     }
 
@@ -371,40 +385,44 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public AttributeDescr 
visitExpressionAttribute(DRLParser.ExpressionAttributeContext ctx) {
-        AttributeDescr attributeDescr = new AttributeDescr(ctx.name.getText());
+        AttributeDescr attributeDescr = BaseDescrFactory.builder(new 
AttributeDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         
attributeDescr.setValue(getTextPreservingWhitespace(ctx.conditionalOrExpression()));
         attributeDescr.setType(AttributeDescr.Type.EXPRESSION);
-        populateStartEnd(attributeDescr, ctx);
         return attributeDescr;
     }
 
     @Override
     public AttributeDescr 
visitBooleanAttribute(DRLParser.BooleanAttributeContext ctx) {
-        AttributeDescr attributeDescr = new AttributeDescr(ctx.name.getText());
+        AttributeDescr attributeDescr = BaseDescrFactory.builder(new 
AttributeDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         attributeDescr.setValue(ctx.BOOL_LITERAL() != null ? 
ctx.BOOL_LITERAL().getText() : "true");
         attributeDescr.setType(AttributeDescr.Type.BOOLEAN);
-        populateStartEnd(attributeDescr, ctx);
         return attributeDescr;
     }
 
     @Override
     public AttributeDescr 
visitStringAttribute(DRLParser.StringAttributeContext ctx) {
-        AttributeDescr attributeDescr = new AttributeDescr(ctx.name.getText());
+        AttributeDescr attributeDescr = BaseDescrFactory.builder(new 
AttributeDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         
attributeDescr.setValue(unescapeJava(safeStripStringDelimiters(ctx.DRL_STRING_LITERAL().getText())));
         attributeDescr.setType(AttributeDescr.Type.STRING);
-        populateStartEnd(attributeDescr, ctx);
         return attributeDescr;
     }
 
     @Override
     public AttributeDescr 
visitStringListAttribute(DRLParser.StringListAttributeContext ctx) {
-        AttributeDescr attributeDescr = new AttributeDescr(ctx.name.getText());
+        AttributeDescr attributeDescr = BaseDescrFactory.builder(new 
AttributeDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         List<String> valueList = ctx.DRL_STRING_LITERAL().stream()
                 .map(ParseTree::getText)
                 .collect(Collectors.toList());
         attributeDescr.setValue(createStringList(valueList));
         attributeDescr.setType(AttributeDescr.Type.LIST);
-        populateStartEnd(attributeDescr, ctx);
         return attributeDescr;
     }
 
@@ -423,7 +441,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public AttributeDescr 
visitIntOrChunkAttribute(DRLParser.IntOrChunkAttributeContext ctx) {
-        AttributeDescr attributeDescr = new AttributeDescr(ctx.name.getText());
+        AttributeDescr attributeDescr = BaseDescrFactory.builder(new 
AttributeDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.DECIMAL_LITERAL() != null) {
             attributeDescr.setValue(ctx.DECIMAL_LITERAL().getText());
             attributeDescr.setType(AttributeDescr.Type.NUMBER);
@@ -431,13 +451,14 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             attributeDescr.setValue(getTextPreservingWhitespace(ctx.chunk()));
             attributeDescr.setType(AttributeDescr.Type.EXPRESSION);
         }
-        populateStartEnd(attributeDescr, ctx);
         return attributeDescr;
     }
 
     @Override
     public AttributeDescr 
visitDurationAttribute(DRLParser.DurationAttributeContext ctx) {
-        AttributeDescr attributeDescr = new AttributeDescr(ctx.name.getText());
+        AttributeDescr attributeDescr = BaseDescrFactory.builder(new 
AttributeDescr(ctx.name.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.DECIMAL_LITERAL() != null) {
             attributeDescr.setValue(ctx.DECIMAL_LITERAL().getText());
             attributeDescr.setType(AttributeDescr.Type.NUMBER);
@@ -445,7 +466,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             
attributeDescr.setValue(unescapeJava(safeStripStringDelimiters(ctx.TIME_INTERVAL().getText())));
             attributeDescr.setType(AttributeDescr.Type.EXPRESSION);
         }
-        populateStartEnd(attributeDescr, ctx);
         return attributeDescr;
     }
 
@@ -485,11 +505,14 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             patternDescr.setIdentifier(ctx.unif().IDENTIFIER().getText());
             patternDescr.setUnification(true);
         }
+        DescrHelper.refreshPatternDescrProperties(patternDescr, ctx);
         return patternDescr;
     }
 
     private OrDescr 
getOrDescrWithMultiplePatternDescr(DRLParser.LhsPatternBindContext ctx) {
-        OrDescr orDescr = new OrDescr();
+        OrDescr orDescr = BaseDescrFactory.builder(new OrDescr())
+                .withParserRuleContext(ctx)
+                .build();
         List<BaseDescr> descrList = visitDescrChildren(ctx);
         descrList.stream()
                 .filter(PatternDescr.class::isInstance)
@@ -501,7 +524,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
                     orDescr.addDescr(patternDescr);
                 });
 
-        populateStartEnd(orDescr, ctx);
         return orDescr;
     }
 
@@ -510,7 +532,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
      */
     @Override
     public PatternDescr visitLhsPattern(DRLParser.LhsPatternContext ctx) {
-        PatternDescr patternDescr = new PatternDescr(ctx.objectType.getText());
+        PatternDescr patternDescr = BaseDescrFactory.builder(new 
PatternDescr(ctx.objectType.getText()))
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.QUESTION() != null) {
             patternDescr.setQuery(true);
         }
@@ -523,8 +547,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             patternDescr.setSource(patternSourceDescr);
         }
 
-        populateStartEnd(patternDescr, ctx);
-
         
ctx.drlAnnotation().stream().map(this::visitDrlAnnotation).forEach(patternDescr::addAnnotation);
         List<ExprConstraintDescr> constraintDescrList = 
visitConstraints(ctx.positionalConstraints(), ctx.constraints());
         constraintDescrList.forEach(descr -> addToPatternDescr(patternDescr, 
descr));
@@ -538,15 +560,18 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public ForallDescr visitLhsForall(DRLParser.LhsForallContext ctx) {
-        ForallDescr forallDescr = new ForallDescr();
+        ForallDescr forallDescr = BaseDescrFactory.builder(new ForallDescr())
+                .withParserRuleContext(ctx)
+                .build();
         visitDescrChildren(ctx).forEach(forallDescr::addDescr);
-        populateStartEnd(forallDescr, ctx);
         return forallDescr;
     }
 
     @Override
     public PatternDescr visitLhsAccumulate(DRLParser.LhsAccumulateContext ctx) 
{
-        AccumulateDescr accumulateDescr = new AccumulateDescr();
+        AccumulateDescr accumulateDescr = BaseDescrFactory.builder(new 
AccumulateDescr())
+                .withParserRuleContext(ctx)
+                .build();
         accumulateDescr.setInput(visitLhsAndDef(ctx.lhsAndDef()));
 
         // accumulate function
@@ -559,41 +584,45 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         List<ExprConstraintDescr> constraintDescrList = 
visitConstraints(ctx.constraints());
         constraintDescrList.forEach(patternDescr::addConstraint);
 
-        populateStartEnd(accumulateDescr, ctx);
         return patternDescr;
     }
 
     @Override
     public BehaviorDescr visitPatternFilter(DRLParser.PatternFilterContext 
ctx) {
-        BehaviorDescr behaviorDescr = new BehaviorDescr();
+        BehaviorDescr behaviorDescr = BaseDescrFactory.builder(new 
BehaviorDescr())
+                .withParserRuleContext(ctx)
+                .build();
         behaviorDescr.setType(ctx.DRL_WINDOW().getText());
         behaviorDescr.setSubType(ctx.IDENTIFIER().getText());
         List<DRLParser.DrlExpressionContext> drlExpressionContexts = 
ctx.expressionList().drlExpression();
         List<String> parameters = 
drlExpressionContexts.stream().map(Antlr4ParserStringUtils::getTextPreservingWhitespace).collect(Collectors.toList());
         behaviorDescr.setParameters(parameters);
-        populateStartEnd(behaviorDescr, ctx);
         return behaviorDescr;
     }
 
     @Override
     public FromDescr visitFromExpression(DRLParser.FromExpressionContext ctx) {
-        FromDescr fromDescr = new FromDescr();
+        FromDescr fromDescr = BaseDescrFactory.builder(new FromDescr())
+                .withParserRuleContext(ctx)
+                .build();
         fromDescr.setDataSource(new 
MVELExprDescr(getTextPreservingWhitespace(ctx)));
-        populateStartEnd(fromDescr, ctx);
         return fromDescr;
     }
 
     @Override
     public CollectDescr visitFromCollect(DRLParser.FromCollectContext ctx) {
-        CollectDescr collectDescr = new CollectDescr();
+        CollectDescr collectDescr = BaseDescrFactory.builder(new 
CollectDescr())
+                .withParserRuleContext(ctx)
+                .build();
         collectDescr.setInputPattern((PatternDescr) 
visitLhsPatternBind(ctx.lhsPatternBind()));
-        populateStartEnd(collectDescr, ctx);
         return collectDescr;
     }
 
     @Override
     public AccumulateDescr visitFromAccumulate(DRLParser.FromAccumulateContext 
ctx) {
-        AccumulateDescr accumulateDescr = new AccumulateDescr();
+        AccumulateDescr accumulateDescr = BaseDescrFactory.builder(new 
AccumulateDescr())
+                .withParserRuleContext(ctx)
+                .build();
         accumulateDescr.setInput(visitLhsAndDef(ctx.lhsAndDef()));
         if (ctx.DRL_INIT() != null) {
             // inline custom accumulate
@@ -607,7 +636,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             // accumulate function
             
accumulateDescr.addFunction(visitAccumulateFunction(ctx.accumulateFunction()));
         }
-        populateStartEnd(accumulateDescr, ctx);
         return accumulateDescr;
     }
 
@@ -621,12 +649,16 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public EntryPointDescr visitFromEntryPoint(DRLParser.FromEntryPointContext 
ctx) {
-        return new 
EntryPointDescr(safeStripStringDelimiters(ctx.stringId().getText()));
+        return BaseDescrFactory.builder(new 
EntryPointDescr(safeStripStringDelimiters(ctx.stringId().getText())))
+                .withParserRuleContext(ctx)
+                .build();
     }
 
     @Override
     public WindowReferenceDescr visitFromWindow(DRLParser.FromWindowContext 
ctx) {
-        return new WindowReferenceDescr(ctx.IDENTIFIER().getText());
+        return BaseDescrFactory.builder(new 
WindowReferenceDescr(ctx.IDENTIFIER().getText()))
+                .withParserRuleContext(ctx)
+                .build();
     }
 
     /**
@@ -678,9 +710,10 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         // get a simple constraint as String
         String constraint = visitConstraintChildren(ctx);
         if (!constraint.isEmpty()) {
-            ExprConstraintDescr constraintDescr = new 
ExprConstraintDescr(constraint);
+            ExprConstraintDescr constraintDescr = BaseDescrFactory.builder(new 
ExprConstraintDescr(constraint))
+                .withParserRuleContext(ctx)
+                .build();
             constraintDescr.setType(ExprConstraintDescr.Type.NAMED);
-            populateStartEnd(constraintDescr, ctx);
             descrList.add(constraintDescr);
             return descrList;
         }
@@ -711,7 +744,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
 
     @Override
     public ExistsDescr visitLhsExists(DRLParser.LhsExistsContext ctx) {
-        ExistsDescr existsDescr = new ExistsDescr();
+        ExistsDescr existsDescr = BaseDescrFactory.builder(new ExistsDescr())
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.lhsExpression() != null) {
             // exists( A() or B() )
             List<BaseDescr> baseDescrs = visitDescrChildren(ctx);
@@ -725,13 +760,14 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             BaseDescr descr = visitLhsPatternBind(ctx.lhsPatternBind());
             existsDescr.addDescr(descr);
         }
-        populateStartEnd(existsDescr, ctx);
         return existsDescr;
     }
 
     @Override
     public NotDescr visitLhsNot(DRLParser.LhsNotContext ctx) {
-        NotDescr notDescr = new NotDescr();
+        NotDescr notDescr = BaseDescrFactory.builder(new NotDescr())
+                .withParserRuleContext(ctx)
+                .build();
         if (ctx.lhsExpression() != null) {
             // not ( A() or B() )
             List<BaseDescr> baseDescrs = visitDescrChildren(ctx);
@@ -745,15 +781,14 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             BaseDescr descr = visitLhsPatternBind(ctx.lhsPatternBind());
             notDescr.addDescr(descr);
         }
-        populateStartEnd(notDescr, ctx);
         return notDescr;
     }
 
     @Override
     public EvalDescr visitLhsEval(DRLParser.LhsEvalContext ctx) {
-        EvalDescr evalDescr = new 
EvalDescr(getTextPreservingWhitespace(ctx.conditionalOrExpression()));
-        populateStartEnd(evalDescr, ctx);
-        return evalDescr;
+        return BaseDescrFactory.builder(new 
EvalDescr(getTextPreservingWhitespace(ctx.conditionalOrExpression())))
+                .withParserRuleContext(ctx)
+                .build();
     }
 
     @Override
@@ -770,7 +805,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             // Avoid nested OrDescr
             return descrList.get(0).getDescr();
         } else {
-            OrDescr orDescr = new OrDescr();
+            OrDescr orDescr = BaseDescrFactory.builder(new OrDescr())
+                .withParserRuleContext(ctx)
+                .build();
             // For example, in case of A() or B() or C(),
             // Parser creates AST like this:
             //  lhsOr
@@ -781,7 +818,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             // So, we need to flatten it so that OrDescr has A(), B() and C() 
as children.
             List<BaseDescr> flattenedDescrs = flattenOrDescr(descrList);
             flattenedDescrs.forEach(orDescr::addDescr);
-            populateStartEnd(orDescr, ctx);
             return orDescr;
         }
     }
@@ -813,7 +849,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             // Avoid nested AndDescr
             return descrList.get(0).getDescr();
         } else {
-            AndDescr andDescr = new AndDescr();
+            AndDescr andDescr = BaseDescrFactory.builder(new AndDescr())
+                .withParserRuleContext(ctx)
+                .build();
             // For example, in case of A() and B() and C(),
             // Parser creates AST like this:
             //  lhsAnd
@@ -824,7 +862,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             // So, we need to flatten it so that AndDescr has A(), B() and C() 
as children.
             List<BaseDescr> flattenedDescrs = flattenAndDescr(descrList);
             flattenedDescrs.forEach(andDescr::addDescr);
-            populateStartEnd(andDescr, ctx);
             return andDescr;
         }
     }
@@ -854,15 +891,6 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         return visitDescrChildren(ctx).get(0); // lhsUnary has only one child
     }
 
-    private void populateStartEnd(BaseDescr descr, ParserRuleContext ctx) {
-        descr.setStartCharacter(ctx.getStart().getStartIndex());
-        // TODO: Current DRL6Parser adds +1 for EndCharacter but it doesn't 
look reasonable. At the moment, I don't add. Instead, I fix unit tests.
-        //       I will revisit if this is the right approach.
-        descr.setEndCharacter(ctx.getStop().getStopIndex());
-        descr.setLocation(ctx.getStart().getLine(), 
ctx.getStart().getCharPositionInLine());
-        descr.setEndLocation(ctx.getStop().getLine(), 
ctx.getStop().getCharPositionInLine());
-    }
-
     /**
      * This is a special version of visitChildren().
      * This collects children BaseDescr objects and returns them as a list.
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DescrHelper.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DescrHelper.java
new file mode 100644
index 0000000000..9cdc65b94d
--- /dev/null
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DescrHelper.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.drools.drl.parser.antlr4;
+
+import java.util.List;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.drools.drl.ast.descr.AndDescr;
+import org.drools.drl.ast.descr.BaseDescr;
+import org.drools.drl.ast.descr.PatternDescr;
+
+/**
+ * Helper class for Descr manipulation.
+ */
+public class DescrHelper {
+
+    private DescrHelper() {
+        // Private constructor to prevent instantiation.
+    }
+
+    public static <T extends BaseDescr> T populateCommonProperties(T descr, 
ParserRuleContext ctx) {
+        descr.setStartCharacter(ctx.getStart().getStartIndex());
+        // TODO: Current DRL6Parser adds +1 for EndCharacter but it doesn't 
look reasonable. At the moment, I don't add. Instead, I fix unit tests.
+        //       I will revisit if this is the right approach.
+        descr.setEndCharacter(ctx.getStop().getStopIndex());
+        descr.setLocation(ctx.getStart().getLine(), 
ctx.getStart().getCharPositionInLine());
+        descr.setEndLocation(ctx.getStop().getLine(), 
ctx.getStop().getCharPositionInLine() + ctx.getStop().getText().length() - 1); 
// last column of the end token
+        return descr;
+    }
+
+    /**
+     * LHS rootDescr requires special handling for properties, because it 
rearranges its children.
+     */
+    public static AndDescr refreshRootProperties(AndDescr descr) {
+        List<BaseDescr> childDescrs = descr.getDescrs();
+        if (childDescrs.isEmpty()) {
+            return descr;
+        }
+        BaseDescr firstChild = childDescrs.get(0);
+        BaseDescr lastChild = childDescrs.get(childDescrs.size() - 1);
+        descr.setStartCharacter(firstChild.getStartCharacter());
+        descr.setEndCharacter(lastChild.getEndCharacter());
+        descr.setLocation(firstChild.getLine(), firstChild.getColumn());
+        descr.setEndLocation(lastChild.getEndLine(), lastChild.getEndColumn());
+        return descr;
+    }
+
+    /**
+     * PatternDescr requires special handling for properties, because it 
should be updated with PatternBindContext. e.g. label
+     */
+    public static PatternDescr refreshPatternDescrProperties(PatternDescr 
descr, DRLParser.LhsPatternBindContext ctx) {
+        return populateCommonProperties(descr, ctx);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to