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 025ff72228 [incubator-kie-drools-5792] [new-parser] improve 
drools-drl-parser-tests (#5855)
025ff72228 is described below

commit 025ff7222873f66e78731e27c12f87101103891f
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Tue Apr 23 17:50:08 2024 +0900

    [incubator-kie-drools-5792] [new-parser] improve drools-drl-parser-tests 
(#5855)
    
    * [incubator-kie-drools-5854] [new-parser] improve drools-drl-parser-testsa 
to test with old and new parsers
    - Old and new parser coverage using 2 surefire test executions
    - Fixed Descr common property issues to keep backward compatibility
    - A few test cases remaining without backward compatibility ("Backward 
Compatibility Notes" left) because the old parser seems to be wrong.
    - A few expr test cases remaining without backward compatibility ("Backward 
Compatibility Notes" left). Error code/message don't seem to be important. Also 
the new parser ones are better.
    
    * Update 
drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/LexerHelper.java
    
    Co-authored-by: Jiří Locker <[email protected]>
    
    * - removed unused import
    
    ---------
    
    Co-authored-by: Jiří Locker <[email protected]>
---
 drools-drl/drools-drl-parser-tests/pom.xml         |  38 ++
 .../drl/parser/antlr4/DRLExprParserTest.java       |  91 +++--
 .../drools/drl/parser/antlr4/DRLParserTest.java    |   3 +
 .../drl/parser/antlr4/DescrCommonPropertyTest.java | 197 ++++++----
 .../drools/drl/parser/antlr4/DescrDumperTest.java  |   3 +-
 .../drl/parser/antlr4/MiscDRLParserTest.java       | 422 ++++++++++++---------
 .../drools/drl/parser/antlr4/ParserTestUtils.java  |  35 ++
 .../org/drools/drl/parser/antlr4/DRLLexer.g4       |   9 +-
 .../org/drools/drl/parser/antlr4/DRLParser.g4      |  30 +-
 .../main/java/org/drools/drl/parser/DrlParser.java |   4 +-
 .../drools/drl/parser/antlr4/DRLVisitorImpl.java   |   9 +-
 .../org/drools/drl/parser/antlr4/DescrHelper.java  |  48 ++-
 .../org/drools/drl/parser/antlr4/LexerHelper.java  | 161 ++++++++
 .../org/drools/drl/parser/antlr4/ParserHelper.java |   2 +-
 14 files changed, 745 insertions(+), 307 deletions(-)

diff --git a/drools-drl/drools-drl-parser-tests/pom.xml 
b/drools-drl/drools-drl-parser-tests/pom.xml
index 4f3a19c812..1e26095a3b 100644
--- a/drools-drl/drools-drl-parser-tests/pom.xml
+++ b/drools-drl/drools-drl-parser-tests/pom.xml
@@ -83,4 +83,42 @@
         </dependency>
     </dependencies>
 
+    <profiles>
+        <profile>
+            <id>default</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <!-- override default-test for new parser -->
+                                <id>default-test</id>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        
<drools.drl.antlr4.parser.enabled>true</drools.drl.antlr4.parser.enabled>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>old-parser-test</id>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        
<drools.drl.antlr4.parser.enabled>false</drools.drl.antlr4.parser.enabled>
+                                    </systemPropertyVariables>
+                                </configuration>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLExprParserTest.java
 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLExprParserTest.java
index 3f3b256dd5..30a316e24b 100644
--- 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLExprParserTest.java
+++ 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLExprParserTest.java
@@ -30,6 +30,8 @@ import org.drools.drl.ast.descr.ConnectiveType;
 import org.drools.drl.ast.descr.ConstraintConnectiveDescr;
 import org.drools.drl.ast.descr.RelationalExprDescr;
 import org.drools.drl.parser.DrlExprParser;
+import org.drools.drl.parser.DrlExprParserFactory;
+import org.drools.drl.parser.DrlParser;
 import org.drools.drl.parser.DroolsParserException;
 import org.drools.drl.parser.impl.Operator;
 import org.junit.jupiter.api.AfterEach;
@@ -49,17 +51,17 @@ public class DRLExprParserTest {
     DrlExprParser parser;
 
     @BeforeEach
-    public void setUp() throws Exception {
-        this.parser = new Drl6ExprParserAntlr4(LanguageLevelOption.DRL6);
+    public void setUp() {
+        this.parser = 
DrlExprParserFactory.getDrlExprParser(LanguageLevelOption.DRL6);
     }
 
     @AfterEach
-    public void tearDown() throws Exception {
+    public void tearDown() {
         this.parser = null;
     }
 
     @Test
-    public void testSimpleExpression() throws Exception {
+    public void testSimpleExpression() {
         String source = "a > b";
         ConstraintConnectiveDescr result = parser.parse( source );
         
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
@@ -387,13 +389,26 @@ public class DRLExprParserTest {
         assertThat(parser.hasErrors()).isTrue();
         assertThat(parser.getErrors()).hasSize(1);
         DroolsParserException exception = parser.getErrors().get(0);
-        assertThat(exception.getErrorCode()).isEqualTo("ERR 102");
-        assertThat(exception.getLineNumber()).isEqualTo(1);
-        assertThat(exception.getColumn()).isEqualTo(1);
-        assertThat(exception.getOffset()).isEqualTo(1);
-        assertThat(exception.getMessage())
-                .startsWithIgnoringCase("[ERR 102] Line 1:1 mismatched input 
'<EOF>' expecting ")
-                .contains("TIME_INTERVAL", "DRL_STRING_LITERAL", "?/", 
"boolean", "byte", "char", "double", "float", "int", "long", "new", "short", 
"super", "DECIMAL_LITERAL", "HEX_LITERAL", "FLOAT_LITERAL", "BOOL_LITERAL", 
"STRING_LITERAL", "null", "(", "[", ".", "<", "!", "~", "++", "--", "+", "-", 
"*", "/", "IDENTIFIER");
+
+        // Backward Compatibility Notes:
+        //   Antlr4 gives a different error code/message from antlr3 for this 
case.
+        //   Backward compatibility doesn't seem to be required in this case.
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            assertThat(exception.getErrorCode()).isEqualTo("ERR 102");
+            assertThat(exception.getLineNumber()).isEqualTo(1);
+            assertThat(exception.getColumn()).isEqualTo(1);
+            assertThat(exception.getOffset()).isEqualTo(1);
+            assertThat(exception.getMessage())
+                    .startsWithIgnoringCase("[ERR 102] Line 1:1 mismatched 
input '<EOF>' expecting ")
+                    .contains("TIME_INTERVAL", "DRL_STRING_LITERAL", "?/", 
"boolean", "byte", "char", "double", "float", "int", "long", "new", "short", 
"super", "DECIMAL_LITERAL", "HEX_LITERAL", "FLOAT_LITERAL", "BOOL_LITERAL", 
"STRING_LITERAL", "null", "(", "[", ".", "<", "!", "~", "++", "--", "+", "-", 
"*", "/", "IDENTIFIER");
+        } else {
+            assertThat(exception.getErrorCode()).isEqualTo("ERR 101");
+            assertThat(exception.getLineNumber()).isEqualTo(1);
+            assertThat(exception.getColumn()).isEqualTo(1);
+            assertThat(exception.getOffset()).isEqualTo(1);
+            assertThat(exception.getMessage())
+                    .isEqualToIgnoringCase("[ERR 101] Line 1:1 no viable 
alternative at input '<eof>'");
+        }
     }
 
     @Test
@@ -403,26 +418,48 @@ public class DRLExprParserTest {
         assertThat(parser.hasErrors()).isTrue();
         assertThat(parser.getErrors()).hasSize(1);
         DroolsParserException exception = parser.getErrors().get(0);
-        assertThat(exception.getErrorCode()).isEqualTo("ERR 109");
-        assertThat(exception.getLineNumber()).isEqualTo(1);
-        assertThat(exception.getColumn()).isEqualTo(3);
-        assertThat(exception.getOffset()).isEqualTo(3);
-        assertThat(exception.getMessage())
-                .startsWithIgnoringCase("[ERR 109] Line 1:3 extraneous input 
';' expecting ")
-                .contains("TIME_INTERVAL", "DRL_STRING_LITERAL", "?/", 
"boolean", "byte", "char", "double", "float", "int", "long", "new", "short", 
"super", "DECIMAL_LITERAL", "HEX_LITERAL", "FLOAT_LITERAL", "BOOL_LITERAL", 
"STRING_LITERAL", "null", "(", "[", ".", "<", "!", "~", "++", "--", "+", "-", 
"*", "/", "IDENTIFIER");
+
+        // Backward Compatibility Notes:
+        //   Antlr4 gives a different error code/message from antlr3 for this 
case.
+        //   Backward compatibility doesn't seem to be required in this case.
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            assertThat(exception.getErrorCode()).isEqualTo("ERR 109");
+            assertThat(exception.getLineNumber()).isEqualTo(1);
+            assertThat(exception.getColumn()).isEqualTo(3);
+            assertThat(exception.getOffset()).isEqualTo(3);
+            assertThat(exception.getMessage())
+                    .startsWithIgnoringCase("[ERR 109] Line 1:3 extraneous 
input ';' expecting ")
+                    .contains("TIME_INTERVAL", "DRL_STRING_LITERAL", "?/", 
"boolean", "byte", "char", "double", "float", "int", "long", "new", "short", 
"super", "DECIMAL_LITERAL", "HEX_LITERAL", "FLOAT_LITERAL", "BOOL_LITERAL", 
"STRING_LITERAL", "null", "(", "[", ".", "<", "!", "~", "++", "--", "+", "-", 
"*", "/", "IDENTIFIER");
+        } else {
+            assertThat(exception.getErrorCode()).isEqualTo("ERR 101");
+            assertThat(exception.getLineNumber()).isEqualTo(1);
+            assertThat(exception.getColumn()).isEqualTo(3);
+            assertThat(exception.getOffset()).isEqualTo(3);
+            assertThat(exception.getMessage())
+                    .isEqualToIgnoringCase("[ERR 101] Line 1:3 no viable 
alternative at input ';'");
+        }
     }
+
     @Test
     public void testNoViableAlt() {
         String source = "x.int";
         parser.parse(source);
-        assertThat(parser.hasErrors()).isTrue();
-        assertThat(parser.getErrors()).hasSize(1);
-        DroolsParserException exception = parser.getErrors().get(0);
-        assertThat(exception.getErrorCode()).isEqualTo("ERR 101");
-        assertThat(exception.getLineNumber()).isEqualTo(1);
-        assertThat(exception.getColumn()).isEqualTo(2);
-        assertThat(exception.getOffset()).isEqualTo(2);
-        assertThat(exception.getMessage())
-                .isEqualToIgnoringCase("[ERR 101] Line 1:2 no viable 
alternative at input '.int'");
+
+        // Backward Compatibility Notes:
+        //   Old expr parser (DRL6Expressions) allows this expression because 
it's too tolerant (fail at runtime anyway).
+        //   Backward compatibility doesn't seem to be required in this case. 
(But we may align with the old tolerant behavior.)
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            assertThat(parser.hasErrors()).isTrue();
+            assertThat(parser.getErrors()).hasSize(1);
+            DroolsParserException exception = parser.getErrors().get(0);
+            assertThat(exception.getErrorCode()).isEqualTo("ERR 101");
+            assertThat(exception.getLineNumber()).isEqualTo(1);
+            assertThat(exception.getColumn()).isEqualTo(2);
+            assertThat(exception.getOffset()).isEqualTo(2);
+            assertThat(exception.getMessage())
+                    .isEqualToIgnoringCase("[ERR 101] Line 1:2 no viable 
alternative at input '.int'");
+        } else {
+            assertThat(parser.hasErrors()).isFalse();
+        }
     }
 }
diff --git 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLParserTest.java
 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLParserTest.java
index 8aecc0fb05..f792effd23 100644
--- 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLParserTest.java
+++ 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DRLParserTest.java
@@ -17,6 +17,9 @@ import static 
org.drools.drl.parser.antlr4.DRLParserHelper.computeTokenIndex;
 import static org.drools.drl.parser.antlr4.DRLParserHelper.createDrlParser;
 import static org.drools.drl.parser.antlr4.DRLParserHelper.parse;
 
+/**
+ * This test class is specific to new antlr4 parser.
+ */
 class DRLParserTest {
 
     private static final String drl =
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
index bc3010e698..25c51ca9b7 100644
--- 
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
@@ -1,3 +1,21 @@
+/**
+ * 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
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.drools.drl.ast.descr.AccumulateDescr;
@@ -22,7 +40,6 @@ 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;
@@ -30,7 +47,8 @@ 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.drools.drl.parser.DrlParser;
+import org.drools.drl.parser.DroolsParserException;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -41,15 +59,21 @@ import static org.assertj.core.api.Assertions.assertThat;
  */
 class DescrCommonPropertyTest {
 
-    private DRLParserWrapper parser;
+    private DrlParser parser;
 
     @BeforeEach
     public void setUp() {
-        parser = new DRLParserWrapper();
+        parser = ParserTestUtils.getParser();
     }
 
-    @AfterEach
-    public void tearDown() {
+    private PackageDescr parseAndGetPackageDescr(String drl) {
+        try {
+            PackageDescr pkg =  parser.parse(null, drl);
+            
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+            return pkg;
+        } catch (DroolsParserException e) {
+            throw new RuntimeException(e);
+        }
     }
 
     private void assertProperties(BaseDescr descr, int startCharacter, int 
endCharacter, int line, int column, int endLine, int endColumn) {
@@ -64,8 +88,8 @@ class DescrCommonPropertyTest {
     @Test
     void packageDescr() {
         final String source = "package foo.bar.baz";
-        final PackageDescr pkg = parser.parse(source);
-        assertProperties(pkg, 0, 18, 1, 0, 1, 18);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
+        assertProperties(pkg, 0, 19, 1, 0, 1, 18);
     }
 
     @Test
@@ -74,17 +98,18 @@ class DescrCommonPropertyTest {
                 "  when\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
-        assertProperties(rule, 0, 30, 1, 0, 4, 2);
+        assertProperties(rule, 0, 31, 1, 0, 4, 2);
     }
 
     @Test
     void unitDescr() {
-        final String source = "unit Foo;";
-        final PackageDescr pkg = parser.parse(source);
+        final String source = "package abc;\n" +
+                "unit Foo;";
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final UnitDescr unit = pkg.getUnit();
-        assertProperties(unit, 0, 8, 1, 0, 1, 8);
+        assertProperties(unit, 13, 22, 2, 0, 2, 8);
     }
 
     @Test
@@ -92,9 +117,9 @@ class DescrCommonPropertyTest {
         final String source = "query \"MyQuery\"\n" +
                 "  Foo()\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final QueryDescr query = (QueryDescr) pkg.getRules().get(0);
-        assertProperties(query, 0, 26, 1, 0, 3, 2);
+        assertProperties(query, 0, 27, 1, 0, 3, 2);
     }
 
     @Test
@@ -102,41 +127,41 @@ class DescrCommonPropertyTest {
         final String source = "function void myFunction(String data) {\n" +
                 "  foo();\n" +
                 "}";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final FunctionDescr function = pkg.getFunctions().get(0);
-        assertProperties(function, 0, 49, 1, 0, 3, 0);
+        assertProperties(function, 0, 50, 1, 0, 3, 0);
     }
 
     @Test
     void globalDescr() {
         final String source = "global java.util.List myList";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final GlobalDescr global = pkg.getGlobals().get(0);
-        assertProperties(global, 0, 27, 1, 0, 1, 27);
+        assertProperties(global, 0, 28, 1, 0, 1, 27);
     }
 
     @Test
     void functionImportDescr() {
         final String source = "import function 
org.drools.core.util.DateUtils.*";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final FunctionImportDescr functionImport = 
pkg.getFunctionImports().get(0);
-        assertProperties(functionImport, 0, 47, 1, 0, 1, 47);
+        assertProperties(functionImport, 0, 48, 1, 0, 1, 47);
     }
 
     @Test
     void importDescr() {
         final String source = "import org.drools.core.util.DateUtils";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final ImportDescr importDescr = pkg.getImports().get(0);
-        assertProperties(importDescr, 0, 36, 1, 0, 1, 36);
+        assertProperties(importDescr, 0, 37, 1, 0, 1, 36);
     }
 
     @Test
     void accumulateImportDescr() {
         final String source = "import accumulate org.example.MyAccUtils.sum 
mySum";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final AccumulateImportDescr accumulateImport = 
pkg.getAccumulateImports().get(0);
-        assertProperties(accumulateImport, 0, 49, 1, 0, 1, 49);
+        assertProperties(accumulateImport, 0, 50, 1, 0, 1, 49);
     }
 
     @Test
@@ -144,11 +169,11 @@ class DescrCommonPropertyTest {
         final String source = "declare MyType\n" +
                 "  name : String\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+        assertProperties(typeDeclaration, 8, 34, 1, 8, 3, 2);
     }
 
     @Test
@@ -156,9 +181,9 @@ class DescrCommonPropertyTest {
         final String source = "declare entry-point MyEntryPoint\n" +
                 "  @foo( true )\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final EntryPointDeclarationDescr entryPointDeclaration = 
pkg.getEntryPointDeclarations().stream().findFirst().get();
-        assertProperties(entryPointDeclaration, 8, 50, 1, 8, 3, 2);
+        assertProperties(entryPointDeclaration, 8, 51, 1, 8, 3, 2);
     }
 
     @Test
@@ -168,9 +193,9 @@ class DescrCommonPropertyTest {
                 "       over window:length( 10, $s.symbol )\n" +
                 "       from entry-point stStream\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final WindowDeclarationDescr windowDeclaration = 
pkg.getWindowDeclarations().stream().findFirst().get();
-        assertProperties(windowDeclaration, 8, 139, 1, 8, 5, 2);
+        assertProperties(windowDeclaration, 8, 140, 1, 8, 5, 2);
     }
 
     @Test
@@ -181,10 +206,10 @@ class DescrCommonPropertyTest {
                 "  $p : Person( name == \"Mario\" ) @watch(!*, age)\n" +
                 "then\n" +
                 "end\n";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+        assertProperties(annotation, 65, 80, 4, 33, 4, 47);
     }
 
     @Test
@@ -192,10 +217,17 @@ class DescrCommonPropertyTest {
         final String source = "declare MyType\n" +
                 "  name : String\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final TypeDeclarationDescr typeDeclaration = 
pkg.getTypeDeclarations().get(0);
         TypeFieldDescr typeField = typeDeclaration.getFields().get("name");
-        assertProperties(typeField, 17, 29, 2, 2, 2, 14);
+        // Backward Compatibility Notes:
+        //   The old DRL6Parser uses only the attribute value token for common 
properties (seem to be wrong), so startCharacter and column are different 
between old and new parser.
+        //   Backward compatibility doesn't seem to be required in this case.
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            assertProperties(typeField, 17, 30, 2, 2, 2, 14);
+        } else {
+            assertProperties(typeField, 24, 30, 2, 9, 2, 14);
+        }
     }
 
     @Test
@@ -206,10 +238,19 @@ class DescrCommonPropertyTest {
                 "  when\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+
+        // Backward Compatibility Notes:
+        //   The old DRL6Parser uses only the attribute value token for common 
properties (seem to be wrong), so startCharacter and column are different 
between old and new parser.
+        //   Backward compatibility doesn't seem to be required in this case. 
(If do it, the code would be unnecessarily complicated.)
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            assertProperties(rule.getAttributes().get("salience"), 10, 21, 2, 
2, 2, 12);
+            assertProperties(rule.getAttributes().get("agenda-group"), 24, 47, 
3, 2, 3, 24);
+        } else {
+            assertProperties(rule.getAttributes().get("salience"), 19, 21, 2, 
11, 2, 12);
+            assertProperties(rule.getAttributes().get("agenda-group"), 37, 47, 
3, 15, 3, 24);
+        }
     }
 
     @Test
@@ -219,10 +260,10 @@ class DescrCommonPropertyTest {
                 "    $p : Person( name == \"Mario\" )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
         PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get(0);
-        assertProperties(pattern, 19, 48, 3, 4, 3, 33);
+        assertProperties(pattern, 19, 49, 3, 4, 3, 33);
     }
 
     @Test
@@ -232,10 +273,10 @@ class DescrCommonPropertyTest {
                 "    ( $p : Person( name == \"Mario\" ) or $p : Person( name 
== \"Luigi\" ) )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
         OrDescr or = (OrDescr) rule.getLhs().getDescrs().get(0);
-        assertProperties(or, 21, 84, 3, 6, 3, 69);
+        assertProperties(or, 21, 85, 3, 6, 3, 69);
     }
 
     @Test
@@ -245,10 +286,10 @@ class DescrCommonPropertyTest {
                 "    ( $p1 : Person( name == \"Mario\" ) and $p2 : Person( 
name == \"Luigi\" ) )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
         AndDescr and = rule.getLhs();
-        assertProperties(and, 21, 87, 3, 6, 3, 72);
+        assertProperties(and, 19, 90, 3, 4, 3, 74);
     }
 
     @Test
@@ -258,10 +299,10 @@ class DescrCommonPropertyTest {
                 "    forall( $p : Person( name == \"Mario\" ) )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
         ForallDescr forall = (ForallDescr) rule.getLhs().getDescrs().get(0);
-        assertProperties(forall, 19, 58, 3, 4, 3, 43);
+        assertProperties(forall, 19, 59, 3, 4, 3, 43);
     }
 
     @Test
@@ -271,23 +312,23 @@ class DescrCommonPropertyTest {
                 "    accumulate( $p : Person( name == \"Mario\" ), $sum : 
sum($p.getAge()) )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+        assertProperties(accumulate, 19, 88, 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 PackageDescr pkg = parseAndGetPackageDescr(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);
+        assertProperties(behavior, 44, 61, 1, 44, 1, 60);
     }
 
     @Test
@@ -298,13 +339,20 @@ class DescrCommonPropertyTest {
                 "    Child() from $children\n" +
                 "  then\n" +
                 "end";;
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+        // Backward Compatibility Notes:
+        //   The old DRL6Parser doesn't populate common properties of 
FromDescr (seem to be wrong).
+        //   Backward compatibility doesn't seem to be required in this case.
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            // "from" is not included in FromDescr
+            assertProperties(from, 64, 73, 4, 17, 4, 25);
+        } else {
+            assertProperties(from, -1, -1, -1, -1, -1, -1);
+        }
     }
 
     @Test
@@ -314,12 +362,12 @@ class DescrCommonPropertyTest {
                 "    ArrayList() from collect( Person( age > 21 ) );\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+        assertProperties(collect, 35, 64, 3, 21, 3, 49);
     }
 
     @Test
@@ -329,11 +377,19 @@ class DescrCommonPropertyTest {
                 "    StockTick() from entry-point \"stream\"\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+
+        // Backward Compatibility Notes:
+        //   The old DRL6Parser doesn't populate common properties of 
EntryPointDescr (seem to be wrong).
+        //   Backward compatibility doesn't seem to be required in this case.
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            assertProperties(entryPoint, 35, 55, 3, 21, 3, 40);
+        } else {
+            assertProperties(entryPoint, -1, -1, -1, -1, -1, -1);
+        }
     }
 
     @Test
@@ -343,11 +399,18 @@ class DescrCommonPropertyTest {
                 "    StockTick() from window MyWindow\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+        // Backward Compatibility Notes:
+        //   The old DRL6Parser doesn't populate common properties of 
WindowReferenceDescr (seem to be wrong).
+        //   Backward compatibility doesn't seem to be required in this case.
+        if (DrlParser.ANTLR4_PARSER_ENABLED) {
+            assertProperties(windowReference, 35, 50, 3, 21, 3, 35);
+        } else {
+            assertProperties(windowReference, -1, -1, -1, -1, -1, -1);
+        }
     }
 
     @Test
@@ -357,11 +420,11 @@ class DescrCommonPropertyTest {
                 "    Person( age > 21 )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(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);
+        assertProperties(exprConstraint, 26, 33, 3, 12, 3, 18);
     }
 
     @Test
@@ -371,10 +434,10 @@ class DescrCommonPropertyTest {
                 "    exists( Person( age > 21 ) )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
         ExistsDescr exists = (ExistsDescr) rule.getLhs().getDescrs().get(0);
-        assertProperties(exists, 18, 45, 3, 4, 3, 31);
+        assertProperties(exists, 18, 46, 3, 4, 3, 31);
     }
 
     @Test
@@ -384,10 +447,10 @@ class DescrCommonPropertyTest {
                 "    not( Person( age > 21 ) )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
         NotDescr not = (NotDescr) rule.getLhs().getDescrs().get(0);
-        assertProperties(not, 18, 42, 3, 4, 3, 28);
+        assertProperties(not, 18, 43, 3, 4, 3, 28);
     }
 
     @Test
@@ -397,9 +460,9 @@ class DescrCommonPropertyTest {
                 "    eval( 1 + 1 == 2 )\n" +
                 "  then\n" +
                 "end";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         final RuleDescr rule = pkg.getRules().get(0);
         EvalDescr eval = (EvalDescr) rule.getLhs().getDescrs().get(0);
-        assertProperties(eval, 18, 35, 3, 4, 3, 21);
+        assertProperties(eval, 18, 36, 3, 4, 3, 21);
     }
 }
diff --git 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DescrDumperTest.java
 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DescrDumperTest.java
index ab644f7daf..1d038907c8 100644
--- 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DescrDumperTest.java
+++ 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/DescrDumperTest.java
@@ -26,6 +26,7 @@ import org.drools.drl.ast.descr.AtomicExprDescr;
 import org.drools.drl.ast.descr.BindingDescr;
 import org.drools.drl.ast.descr.ConstraintConnectiveDescr;
 import org.drools.drl.parser.DrlExprParser;
+import org.drools.drl.parser.DrlExprParserFactory;
 import org.drools.mvel.evaluators.MatchesEvaluatorsDefinition;
 import org.drools.mvel.evaluators.SetEvaluatorsDefinition;
 import org.junit.jupiter.api.BeforeEach;
@@ -358,7 +359,7 @@ public class DescrDumperTest {
     }
 
     public ConstraintConnectiveDescr parse( final String constraint ) {
-        DrlExprParser parser = new 
Drl6ExprParserAntlr4(LanguageLevelOption.DRL6);
+        DrlExprParser parser = 
DrlExprParserFactory.getDrlExprParser(LanguageLevelOption.DRL6);
         ConstraintConnectiveDescr result = parser.parse( constraint );
         
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
 
diff --git 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
index 14c30ca67c..e617a4dfb4 100644
--- 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
+++ 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
@@ -2,6 +2,8 @@ package org.drools.drl.parser.antlr4;
 
 import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -42,6 +44,8 @@ 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.WindowDeclarationDescr;
+import org.drools.drl.parser.DrlParser;
+import org.drools.drl.parser.DroolsParserException;
 import org.drools.drl.parser.impl.Operator;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -57,19 +61,20 @@ import static org.assertj.core.api.Assertions.assertThat;
  */
 class MiscDRLParserTest {
 
-    private DRLParserWrapper parser;
+    private DrlParser parser;
 
     @BeforeEach
     public void setUp() {
-        parser = new DRLParserWrapper();
+        parser = ParserTestUtils.getParser();
     }
 
-    @AfterEach
-    public void tearDown() {
-    }
-
-    private String readResource(final String filename) throws Exception {
-        Path path = Paths.get(getClass().getResource(filename).toURI());
+    private String readResource(final String filename) {
+        Path path;
+        try {
+            path = Paths.get(getClass().getResource(filename).toURI());
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e);
+        }
         final StringBuilder sb = new StringBuilder();
         try (BufferedReader br = Files.newBufferedReader(path, 
StandardCharsets.UTF_8)) {
             for (String line; (line = br.readLine()) != null; ) {
@@ -77,67 +82,82 @@ class MiscDRLParserTest {
                 sb.append("\n");
             }
         } catch (IOException e) {
-            e.printStackTrace();
+            throw new UncheckedIOException(e);
         }
         return sb.toString();
     }
 
+    private PackageDescr parseAndGetPackageDescr(String drl) {
+        try {
+            PackageDescr pkg =  parser.parse(null, drl);
+            
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+            return pkg;
+        } catch (DroolsParserException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private PackageDescr parseAndGetPackageDescrWithoutErrorCheck(String drl) {
+        try {
+            return parser.parse(null, drl);
+        } catch (DroolsParserException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private RuleDescr parseAndGetFirstRuleDescr(String drl) {
-        PackageDescr pkg = parser.parse(drl);
-        
assertThat(parser.hasErrors()).as(parser.getErrorMessages().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(drl);
         assertThat(pkg.getRules()).isNotEmpty();
         return pkg.getRules().get(0);
     }
 
-    private RuleDescr parseAndGetFirstRuleDescrFromFile(String filename) 
throws Exception {
-        return parseAndGetFirstRuleDescr(readResource(filename));
+    private PackageDescr parseAndGetPackageDescrFromFile(String filename) {
+        return parseAndGetPackageDescr(readResource(filename));
     }
 
-    private PackageDescr parseAndGetPackageDescrFromFile(String filename) 
throws Exception {
-        return parser.parse(readResource(filename));
+    private RuleDescr parseAndGetFirstRuleDescrFromFile(String filename) {
+        return parseAndGetFirstRuleDescr(readResource(filename));
     }
 
     private QueryDescr parseAndGetFirstQueryDescr(String drl) {
-        PackageDescr pkg = parser.parse(drl);
-        
assertThat(parser.hasErrors()).as(parser.getErrorMessages().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(drl);
         assertThat(pkg.getRules()).isNotEmpty();
         Optional<QueryDescr> optQuery = 
pkg.getRules().stream().filter(QueryDescr.class::isInstance).map(QueryDescr.class::cast).findFirst();
         assertThat(optQuery).isPresent();
         return optQuery.get();
     }
 
-    private QueryDescr parseAndGetFirstQueryDescrFromFile(String filename) 
throws Exception {
+    private QueryDescr parseAndGetFirstQueryDescrFromFile(String filename) {
         return parseAndGetFirstQueryDescr(readResource(filename));
     }
 
     @Test
     void parse_validPackage() {
         final String source = "package foo.bar.baz";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = parseAndGetPackageDescr(source);
         assertThat(pkg.getName()).isEqualTo("foo.bar.baz");
     }
 
     @Test
     void parse_packageWithErrorNode() {
         final String source = "package 12 foo.bar.baz";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = 
parseAndGetPackageDescrWithoutErrorCheck(source);
         assertThat(parser.hasErrors()).isTrue();
-        assertThat(pkg.getName()).isEqualTo("foo.bar.baz");
+        assertThat(pkg).isNull();
     }
 
     @Test
     void parse_packageWithAllErrorNode() {
         final String source = "package 12 12312 231";
-        final PackageDescr pkg = parser.parse(source);
+        final PackageDescr pkg = 
parseAndGetPackageDescrWithoutErrorCheck(source);
         assertThat(parser.hasErrors()).isTrue();
-        assertThat(pkg.getName()).isEmpty();
+        assertThat(pkg).isNull();
     }
 
     @Test
     void parse_import() {
         final String source = "package foo; import com.foo.Bar; import 
com.foo.Baz;";
-        PackageDescr pkg = parser.parse(source);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg =parseAndGetPackageDescr(source);
         assertThat(pkg.getName()).isEqualTo("foo");
         assertThat(pkg.getImports()).hasSize(2);
         ImportDescr impdescr = pkg.getImports().get(0);
@@ -158,26 +178,25 @@ class MiscDRLParserTest {
                 "import function java.lang.Math.min;\n" +
                 "import foo.bar.*\n" +
                 "import baz.Baz";
-        PackageDescr pkg = parser.parse(source);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
         assertThat(pkg.getName()).isEqualTo("foo");
         assertThat(pkg.getImports()).hasSize(2);
         ImportDescr impdescr = pkg.getImports().get(0);
         assertThat(impdescr.getTarget()).isEqualTo("foo.bar.*");
         
assertThat(impdescr.getStartCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()));
 
-        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()) + ("import " + impdescr.getTarget()).length() - 1);
+        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()) + ("import " + impdescr.getTarget()).length());
 
         impdescr = pkg.getImports().get(1);
         assertThat(impdescr.getTarget()).isEqualTo("baz.Baz");
         
assertThat(impdescr.getStartCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()));
-        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()) + ("import " + impdescr.getTarget()).length() - 1);
+        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()) + ("import " + impdescr.getTarget()).length());
 
         assertThat(pkg.getFunctionImports()).hasSize(2);
         impdescr = pkg.getFunctionImports().get(0);
         assertThat(impdescr.getTarget()).isEqualTo("java.lang.Math.max");
         
assertThat(impdescr.getStartCharacter()).isEqualTo(source.indexOf("import 
function " + impdescr.getTarget()));
-        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import 
function " + impdescr.getTarget()) + ("import function " + 
impdescr.getTarget()).length() - 1);
+        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import 
function " + impdescr.getTarget()) + ("import function " + 
impdescr.getTarget()).length());
 
         impdescr = pkg.getFunctionImports().get(1);
         assertThat(impdescr.getTarget()).isEqualTo("java.lang.Math.min");
@@ -191,15 +210,14 @@ class MiscDRLParserTest {
                 "import com.foo.Bar\n" +
                 "global java.util.List<java.util.Map<String,Integer>> 
aList;\n" +
                 "global Integer aNumber";
-        PackageDescr pkg = parser.parse(source);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
         assertThat(pkg.getName()).isEqualTo("foo.bar.baz");
         assertThat(pkg.getImports()).hasSize(1);
 
         ImportDescr impdescr = pkg.getImports().get(0);
         assertThat(impdescr.getTarget()).isEqualTo("com.foo.Bar");
         
assertThat(impdescr.getStartCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()));
-        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()) + ("import " + impdescr.getTarget()).length() - 1);
+        
assertThat(impdescr.getEndCharacter()).isEqualTo(source.indexOf("import " + 
impdescr.getTarget()) + ("import " + impdescr.getTarget()).length());
 
         assertThat(pkg.getGlobals()).hasSize(2);
 
@@ -215,13 +233,13 @@ class MiscDRLParserTest {
         assertThat(global.getIdentifier()).isEqualTo("aNumber");
         
assertThat(global.getStartCharacter()).isEqualTo(source.indexOf("global " + 
global.getType()));
         assertThat(global.getEndCharacter()).isEqualTo(source.indexOf("global 
" + global.getType() + " " + global.getIdentifier()) +
-                                                               ("global " + 
global.getType() + " " + global.getIdentifier()).length() - 1);
+                                                               ("global " + 
global.getType() + " " + global.getIdentifier()).length());
     }
 
     @Test
     void parse_globalWithOrWithoutSemi() throws Exception {
         String source = readResource("globals.drl");
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         assertThat(pkg.getRules()).hasSize(1);
 
@@ -242,7 +260,7 @@ class MiscDRLParserTest {
     @Test
     void parse_functionImportWithNotExist() throws Exception {
         String source = readResource("test_FunctionImport.drl");
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         assertThat(pkg.getFunctionImports()).hasSize(2);
 
@@ -265,9 +283,7 @@ class MiscDRLParserTest {
                 "\n" +
                 "     o.addError(\"Invalid customer id\"); \n" +
                 "end \n";
-        PackageDescr pkg = parser.parse(source);
-
-        
assertThat(parser.hasErrors()).as(parser.getErrorMessages().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule.getName()).isEqualTo("Invalid customer id");
@@ -291,8 +307,7 @@ class MiscDRLParserTest {
                 " System.err.println(\"Invalid customer id found!\"); \n" +
                 " o.addError(\"Invalid customer id\"); \n" +
                 "end \n";
-        PackageDescr pkg = parser.parse(source);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule.getName()).isEqualTo("XYZ");
@@ -311,13 +326,11 @@ class MiscDRLParserTest {
                 " System.err.println(\"Invalid customer id found!\"); \n" +
                 " o.addError(\"Invalid customer id\"); \n" +
                 "end \n";
-        PackageDescr pkg = parser.parse(source);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule.getName()).isEqualTo("XYZ");
 
-        assertThat(parser.hasErrors()).isFalse();
         PatternDescr number = (PatternDescr) rule.getLhs().getDescrs().get(1);
 
         assertThat(((FromDescr) 
number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1,
 2, 3].sublist(1, 2)");
@@ -333,14 +346,11 @@ class MiscDRLParserTest {
                 " System.err.println(\"Invalid customer id found!\"); \n" +
                 " o.addError(\"Invalid customer id\"); \n" +
                 "end \n";
-        PackageDescr pkg = parser.parse(source);
-
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule.getName()).isEqualTo("XYZ");
 
-        assertThat(parser.hasErrors()).isFalse();
         PatternDescr number = (PatternDescr) rule.getLhs().getDescrs().get(1);
         assertThat(((FromDescr) 
number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1,
 2, 3][1]");
     }
@@ -352,7 +362,7 @@ class MiscDRLParserTest {
                 " o: Order( ) \n" +
                 " then \n" +
                 " System.err.println(\"Invalid customer id found!\"); \n";
-        parser.parse(source);
+        parseAndGetPackageDescrWithoutErrorCheck(source);
         assertThat(parser.hasErrors()).isTrue();
     }
 
@@ -367,8 +377,7 @@ class MiscDRLParserTest {
                 "    then \n" +
                 "        System.out.println( \"Rule: A and (B or C or D) 
Fired. pdo1: \" + pdo1 +  \" pdo2: \"+ pdo2); \n" +
                 "end\n";
-        PackageDescr pkg = parser.parse(source);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         AndDescr lhs = rule.getLhs();
@@ -387,7 +396,7 @@ class MiscDRLParserTest {
     @Test
     void parse_compatibleRestriction() {
         String source = "package com.sample  rule test  when  Test( ( text == 
null || text2 matches \"\" ) )  then  end";
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         assertThat(pkg.getName()).isEqualTo("com.sample");
         RuleDescr rule = pkg.getRules().get(0);
@@ -399,7 +408,7 @@ class MiscDRLParserTest {
     @Test
     void parse_simpleConstraint() {
         String source = "package com.sample  rule test  when  Cheese( type == 
'stilton', price > 10 )  then  end";
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         assertThat(pkg.getName()).isEqualTo("com.sample");
         RuleDescr rule = pkg.getRules().get(0);
@@ -417,7 +426,7 @@ class MiscDRLParserTest {
     @Test
     void parse_stringEscapes() {
         String source = "package com.sample  rule test  when  Cheese( type 
matches \"\\..*\\\\.\" )  then  end";
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
         assertThat(pkg.getName()).isEqualTo("com.sample");
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule.getName()).isEqualTo("test");
@@ -433,7 +442,7 @@ class MiscDRLParserTest {
     @Test
     void parse_dialectWithSingleQuotation() {
         final String source = "dialect 'mvel'";
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
         AttributeDescr attr = pkg.getAttributes().get(0);
         assertThat(attr.getName()).isEqualTo("dialect");
         assertThat(attr.getValue()).isEqualTo("mvel");
@@ -442,7 +451,7 @@ class MiscDRLParserTest {
     @Test
     void parse_dialectWithDoubleQuotation() {
         final String source = "dialect \"mvel\"";
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
         AttributeDescr attr = pkg.getAttributes().get(0);
         assertThat(attr.getName()).isEqualTo("dialect");
         assertThat(attr.getValue()).isEqualTo("mvel");
@@ -451,11 +460,13 @@ class MiscDRLParserTest {
     @Test
     void parse_emptyRuleWithoutWhen() throws Exception {
         String source = readResource("empty_rule.drl"); // without WHEN
-        parser.parse(source);
+        RuleDescr ruleDescr = parseAndGetFirstRuleDescr(source);
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isTrue();
+        assertThat(ruleDescr).isNotNull();
 
-        // Note : RuleParserTest.testEmptyRule allows this DRL, but I think is 
doesn't make sense to pass this DRL
+        assertThat(ruleDescr.getName()).isEqualTo("empty");
+        assertThat(ruleDescr.getLhs()).isNotNull();
+        assertThat(ruleDescr.getConsequence()).isNotNull();
     }
 
     @Test
@@ -465,17 +476,15 @@ class MiscDRLParserTest {
         // Note: eol_funny_business.drl is modified from the one under 
drools-test-coverage to be more realistic.
         // e.g. "package" is not allowed in a package value in Java, so it 
doesn't make sense to test. (Right to raise a parser error)
 
-        PackageDescr pkg = parser.parse(source);
-
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
-
+        PackageDescr pkg = parseAndGetPackageDescr(source);
+        
         assertThat(pkg.getRules()).hasSize(1);
     }
 
     @Test
     void parse_ternaryExpression() throws Exception {
         String source = readResource("ternary_expression.drl");
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         final RuleDescr rule = pkg.getRules().get(0);
         assertThat(pkg.getRules()).hasSize(1);
@@ -491,7 +500,7 @@ class MiscDRLParserTest {
         // new String[3] {"a","b","c"} is invalid in Java (Cannot define 
dimension expressions when an array initializer is provided)
         // , so it doesn't make sense to test. (Right to raise a parser error)
 
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         assertThat(pkg.getName()).isEqualTo("foo");
         assertThat(pkg.getRules()).hasSize(1);
@@ -510,9 +519,8 @@ class MiscDRLParserTest {
     @Test
     void parse_almostEmptyRule() throws Exception {
         String source = readResource("almost_empty_rule.drl");
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
         assertThat(pkg).isNotNull();
 
         RuleDescr rule = pkg.getRules().get(0);
@@ -525,9 +533,7 @@ class MiscDRLParserTest {
     @Test
     void parse_quotedStringNameRule() throws Exception {
         String source = readResource("quoted_string_name_rule.drl");
-        PackageDescr pkg = parser.parse(source);
-
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule).isNotNull();
@@ -540,9 +546,7 @@ class MiscDRLParserTest {
     @Test
     void parse_noLoop() throws Exception {
         String source = readResource("no-loop.drl");
-        PackageDescr pkg = parser.parse(source);
-
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule).isNotNull();
@@ -556,9 +560,7 @@ class MiscDRLParserTest {
     @Test
     void parse_autofocus() throws Exception {
         String source = readResource("autofocus.drl");
-        PackageDescr pkg = parser.parse(source);
-
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule).isNotNull();
@@ -572,9 +574,9 @@ class MiscDRLParserTest {
     @Test
     void parse_ruleFlowGroup() throws Exception {
         String source = readResource("ruleflowgroup.drl");
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
+
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule).isNotNull();
@@ -588,12 +590,12 @@ class MiscDRLParserTest {
     @Test
     void parse_consequenceWithDeclaration() throws Exception {
         String source = readResource("declaration-in-consequence.drl");
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         // Note : Removed "i\i;" from the original 
declaration-in-consequence.drl under drools-test-coverage
         // because it's not a valid java expression and doesn't make sense to 
test. (Right to raise a parser error)
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         RuleDescr rule = pkg.getRules().get(0);
         assertThat(rule).isNotNull();
@@ -619,10 +621,10 @@ class MiscDRLParserTest {
     @Test
     void parse_or() {
         final String text = "rule X when Person(age < 42, 
location==\"atlanta\") \nor\nPerson(name==\"bob\") then end";
-        PackageDescr pkg = parser.parse(text);
+        PackageDescr pkg = parseAndGetPackageDescr(text);
         RuleDescr rule = pkg.getRules().get(0);
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         assertThat(rule).isNotNull();
 
@@ -634,10 +636,10 @@ class MiscDRLParserTest {
     @Test
     void parse_lhsWithStringQuotes() {
         final String text = "rule X when Person( location==\"atlanta\\\"\") 
then end\n";
-        PackageDescr pkg = parser.parse(text);
+        PackageDescr pkg = parseAndGetPackageDescr(text);
         RuleDescr rule = pkg.getRules().get(0);
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         assertThat(rule).isNotNull();
 
@@ -650,9 +652,9 @@ class MiscDRLParserTest {
     @Test
     void parse_lhsWithStringQuotesEscapeChars() {
         final String text = "rule X when Cheese( $x: type, type == 
\"s\\tti\\\"lto\\nn\" ) then end\n";
-        PackageDescr pkg = parser.parse(text);
+        PackageDescr pkg = parseAndGetPackageDescr(text);
         RuleDescr rule = pkg.getRules().get(0);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         assertThat(rule).isNotNull();
 
@@ -702,9 +704,9 @@ class MiscDRLParserTest {
     @Test
     void parse_emptyPattern() throws Exception {
         String source = readResource("test_EmptyPattern.drl");
-        PackageDescr pkg = parser.parse(source);
+        PackageDescr pkg = parseAndGetPackageDescr(source);
+
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
 
         assertThat(pkg.getRules()).hasSize(1);
         final RuleDescr ruleDescr = pkg.getRules().get(0);
@@ -913,7 +915,7 @@ class MiscDRLParserTest {
         PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                          
"test_CommentLineNumbersInConsequence.drl" );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         final String rhs = (String) ((RuleDescr) pkg.getRules().get( 0 
)).getConsequence();
         String expected = "\\s*//woot$\\s*first;$\\s*$\\s*//$\\s*$\\s*/\\* 
lala$\\s*$\\s*\\*/$\\s*second;$\\s*";
@@ -926,7 +928,7 @@ class MiscDRLParserTest {
         final RuleDescr rule = parseAndGetFirstRuleDescrFromFile(
                                                           
"lhs_semicolon_delim.drl" );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         assertThat(rule).isNotNull();
 
@@ -977,7 +979,7 @@ class MiscDRLParserTest {
         final RuleDescr rule = parseAndGetFirstRuleDescrFromFile(
                                                           "rule_not.drl" );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         assertThat(rule).isNotNull();
         assertThat(rule.getName()).isEqualTo("simple_rule");
@@ -1003,7 +1005,7 @@ class MiscDRLParserTest {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                
"not_exist_with_brackets.drl" );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         final RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
 
@@ -1430,7 +1432,7 @@ class MiscDRLParserTest {
                 "     (Foo(x == 1) and Bar(x == 2)) or (Foo(x == 3) or Bar(x 
== 4))\n" +
                 "  then\n" +
                 "end";
-        PackageDescr pkg = parser.parse(drl);
+        PackageDescr pkg = parseAndGetPackageDescr(drl);
 
         assertThat(pkg.getRules()).hasSize(1);
         final RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
@@ -1462,7 +1464,7 @@ class MiscDRLParserTest {
                 "     (Foo(x == 1) or Bar(x == 2)) and (Foo(x == 3) and Bar(x 
== 4))\n" +
                 "  then\n" +
                 "end";
-        PackageDescr pkg = parser.parse(drl);
+        PackageDescr pkg = parseAndGetPackageDescr(drl);
 
         assertThat(pkg.getRules()).hasSize(1);
         final RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
@@ -1491,7 +1493,7 @@ class MiscDRLParserTest {
                 "     (Foo(x == 1) and (Bar(x == 2) or Foo(x == 3))) or (Bar(x 
== 4) or (Foo(x == 5) and Bar(x == 6)))\n" +
                 "  then\n" +
                 "end";
-        PackageDescr pkg = parser.parse(drl);
+        PackageDescr pkg = parseAndGetPackageDescr(drl);
 
         assertThat(pkg.getRules()).hasSize(1);
         final RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
@@ -1531,7 +1533,7 @@ class MiscDRLParserTest {
                 "     (A() or (B() or C() or (D() and E())))\n" +
                 "  then\n" +
                 "end";
-        PackageDescr pkg = parser.parse(drl);
+        PackageDescr pkg = parseAndGetPackageDescr(drl);
 
         assertThat(pkg.getRules()).hasSize(1);
         final RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
@@ -1566,7 +1568,7 @@ class MiscDRLParserTest {
                 "     exists(A() or (B() or C() or (D() and E())))\n" +
                 "  then\n" +
                 "end";
-        PackageDescr pkg = parser.parse(drl);
+        PackageDescr pkg = parseAndGetPackageDescr(drl);
 
         assertThat(pkg.getRules()).hasSize(1);
         final RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
@@ -1770,7 +1772,7 @@ class MiscDRLParserTest {
     public void parse_Attributes2() throws Exception {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                
"rule_attributes2.drl" );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         List<RuleDescr> rules = pkg.getRules();
         assertThat(rules.size()).isEqualTo(3);
@@ -1813,10 +1815,10 @@ class MiscDRLParserTest {
     public void parse_AttributeRefract() throws Exception {
         final String source = "rule Test refract when Person() then end";
 
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  source );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
         RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
 
         assertThat(rule.getName()).isEqualTo("Test");
@@ -1893,7 +1895,7 @@ class MiscDRLParserTest {
     public void parse_Calendars2() throws Exception {
         final RuleDescr rule = parseAndGetFirstRuleDescrFromFile(
                                                           
"rule_calendars_attribute2.drl" );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
         assertThat(rule.getName()).isEqualTo("simple_rule");
         assertThat((String) 
rule.getConsequence()).isEqualToIgnoringWhitespace( "bar();");
 
@@ -1981,7 +1983,7 @@ class MiscDRLParserTest {
     public void parse_ExtraLhsNewline() throws Exception {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                        "extra_lhs_newline.drl" );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
     }
 
     @Test
@@ -2068,7 +2070,7 @@ class MiscDRLParserTest {
     public void parse_EvalWithNewline() throws Exception {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                  
"eval_with_newline.drl");
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
     }
 
     @Test
@@ -2401,7 +2403,7 @@ class MiscDRLParserTest {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                "semicolon.drl" 
);
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         assertThat(pkg.getName()).isEqualTo("org.drools.mvel.compiler");
         assertThat(pkg.getGlobals().size()).isEqualTo(1);
@@ -2559,7 +2561,7 @@ class MiscDRLParserTest {
                 "          $a1 : average( $price ) )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                        drl );
 
         assertThat(pkg.getRules().size()).isEqualTo(1);
@@ -2591,7 +2593,7 @@ class MiscDRLParserTest {
                 "                        average( $price ) )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                        drl );
 
         assertThat(pkg.getRules().size()).isEqualTo(1);
@@ -2625,7 +2627,7 @@ class MiscDRLParserTest {
                 "          $v2 : baz2( $price ) )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                        drl );
 
         assertThat(pkg.getAccumulateImports().size()).isEqualTo(2);
@@ -2799,7 +2801,7 @@ class MiscDRLParserTest {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                
"pluggable_operators.drl" );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         assertThat(pkg.getRules().size()).isEqualTo(1);
         final RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
@@ -2845,7 +2847,7 @@ class MiscDRLParserTest {
     public void parse_RuleMetadata() throws Exception {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                
"Rule_with_Metadata.drl" );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         // @fooAttribute(barValue)
         // @fooAtt2(barVal2)
@@ -2863,7 +2865,7 @@ class MiscDRLParserTest {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                
"Rule_with_Extends.drl" );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         RuleDescr rule = pkg.getRules().get( 0 );
         assertThat(rule.getParentName() != null).isTrue();
@@ -2883,7 +2885,7 @@ class MiscDRLParserTest {
     public void parse_TypeDeclarationWithFields() throws Exception {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                                
"declare_type_with_fields.drl" );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         List<TypeDeclarationDescr> td = pkg.getTypeDeclarations();
         assertThat(td.size()).isEqualTo(3);
@@ -2933,7 +2935,7 @@ class MiscDRLParserTest {
     public void parenthesesOneLevelNestWithThreeSiblings() throws Exception {
         final PackageDescr pkg = parseAndGetPackageDescrFromFile( 
"Rule_with_nested_LHS.drl" );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         RuleDescr rule = pkg.getRules().get( 0 );
         assertThat(rule.getName()).isEqualTo("test");
@@ -2974,9 +2976,9 @@ class MiscDRLParserTest {
     public void parse_EntryPoint() throws Exception {
         final String text = "rule X when StockTick( symbol==\"ACME\") from 
entry-point StreamA then end";
 
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  text );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         RuleDescr rule = pkg.getRules().get( 0 );
         PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get( 0 
);
@@ -2994,9 +2996,9 @@ class MiscDRLParserTest {
     public void parse_EntryPoint2() throws Exception {
         final String text = "rule X when StockTick( symbol==\"ACME\") from 
entry-point \"StreamA\" then end";
 
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  text );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         RuleDescr rule = pkg.getRules().get( 0 );
         PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get( 0 
);
@@ -3014,8 +3016,8 @@ class MiscDRLParserTest {
     public void parse_SlidingWindow() throws Exception {
         final String text = "rule X when StockTick( symbol==\"ACME\") over 
window:length(10) then end";
 
-        PackageDescr pkg = parser.parse( text );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr( text );
+
 
         RuleDescr rule = pkg.getRules().get( 0 );
         PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get( 0 
);
@@ -3037,10 +3039,10 @@ class MiscDRLParserTest {
     public void parse_RuleOldSyntax1() throws Exception {
         final String source = "rule \"Test\" when ( not $r 
:LiteralRestriction( operator == Operator.EQUAL ) ) then end";
 
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  source );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
         RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
 
         assertThat(rule.getName()).isEqualTo("Test");
@@ -3058,10 +3060,10 @@ class MiscDRLParserTest {
     public void parse_RuleOldSyntax2() throws Exception {
         final String source = "rule \"Test\" when ( $r :LiteralRestriction( 
operator == Operator.EQUAL ) ) then end";
 
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  source );
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
         RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
 
         assertThat(rule.getName()).isEqualTo("Test");
@@ -3079,7 +3081,7 @@ class MiscDRLParserTest {
         PackageDescr pkg = parseAndGetPackageDescrFromFile(
                                                          "type_with_meta.drl" 
);
 
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         final List<TypeDeclarationDescr> declarations = 
pkg.getTypeDeclarations();
 
@@ -3142,7 +3144,7 @@ class MiscDRLParserTest {
         final String text = "rule X when Cheese() from $cheesery ?person( 
\"Mark\", 42; ) then end";
         RuleDescr rule = parseAndGetFirstRuleDescr(
                                             text );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get( 0 
);
         assertThat(pattern.getObjectType()).isEqualTo("Cheese");
@@ -3162,7 +3164,7 @@ class MiscDRLParserTest {
         final String text = "rule X when Cheese() from (isFull ? $cheesery : 
$market) ?person( \"Mark\", 42; ) then end";
         RuleDescr rule = parseAndGetFirstRuleDescr(
                                             text );
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
 
         PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get( 0 
);
         assertThat(pattern.getObjectType()).isEqualTo("Cheese");
@@ -3341,7 +3343,7 @@ class MiscDRLParserTest {
                 "    @source(\"jndi://queues/events\")\n" +
                 "    @foo( true )\n" +
                 "end";
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  text );
 
         assertThat(pkg.getName()).isEqualTo("org.drools");
@@ -3364,7 +3366,7 @@ class MiscDRLParserTest {
                 "        over window:length( 10, $s.symbol )\n" +
                 "        from entry-point stStream\n" +
                 "end";
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  text );
 
         assertThat(pkg.getName()).isEqualTo("org.drools");
@@ -3399,7 +3401,7 @@ class MiscDRLParserTest {
                 "    StockTick() from window Y\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr pkg = parser.parse(
+        PackageDescr pkg = parseAndGetPackageDescr(
                                                  text );
 
         assertThat(pkg.getName()).isEqualTo("org.drools");
@@ -3425,7 +3427,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 "    System.out.println($s.endsWith(\"xyz\"));\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text );
+        PackageDescr packageDescr = parseAndGetPackageDescr(text );
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         
assertThat(ruleDescr.getConsequence().toString()).isEqualToIgnoringWhitespace("System.out.println($s.endsWith(\"xyz\"));");
@@ -3440,7 +3442,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 "    int end = 10;\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text );
+        PackageDescr packageDescr = parseAndGetPackageDescr(text );
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         
assertThat(ruleDescr.getConsequence().toString()).isEqualToIgnoringWhitespace("int
 end = 10;");
@@ -3455,7 +3457,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 "    int rule = 10;\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text );
+        PackageDescr packageDescr = parseAndGetPackageDescr(text );
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         
assertThat(ruleDescr.getConsequence().toString()).isEqualToIgnoringWhitespace("int
 rule = 10;");
@@ -3469,7 +3471,7 @@ class MiscDRLParserTest {
                 "    $s : String()\n" +
                 "then\n" +
                 "    delete($s);end\n"; // no space after semicolon
-        PackageDescr packageDescr = parser.parse(text );
+        PackageDescr packageDescr = parseAndGetPackageDescr(text );
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         
assertThat(ruleDescr.getConsequence().toString()).isEqualToIgnoringWhitespace("delete($s);");
@@ -3483,7 +3485,7 @@ class MiscDRLParserTest {
                 "    $p : Person()\n" +
                 "then\n" +
                 "    modify($p) { setAge(2) }end\n"; // no space after right 
brace
-        PackageDescr packageDescr = parser.parse(text );
+        PackageDescr packageDescr = parseAndGetPackageDescr(text );
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         
assertThat(ruleDescr.getConsequence().toString()).isEqualToIgnoringWhitespace("modify($p)
 { setAge(2) }");
@@ -3497,12 +3499,86 @@ class MiscDRLParserTest {
                 "    $p : Person()\n" +
                 "then\n" +
                 "    retract($p)end\n"; // no space after right parenthesis
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         
assertThat(ruleDescr.getConsequence().toString()).isEqualToIgnoringWhitespace("retract($p)");
     }
 
+    @Test
+    void endAndRuleInSameLine() {
+        final String text = "package org.drools\n" +
+                "rule R1\n" +
+                "when\n" +
+                "    $p : Person()\n" +
+                "then\n" +
+                "    retract($p)\n" +
+                "end rule R2 when Person() then end"; // 'rule' after 'end' in 
the same line
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
+        List<RuleDescr> ruleDescrList = packageDescr.getRules();
+        assertThat(ruleDescrList).hasSize(2);
+        assertThat(ruleDescrList.get(0).getName()).isEqualTo("R1");
+        assertThat(ruleDescrList.get(1).getName()).isEqualTo("R2");
+    }
+
+    @Test
+    void endAndAttributeAndRuleInSameLine() {
+        final String text = "package org.drools\n" +
+                "rule R1\n" +
+                "when\n" +
+                "    $p : Person()\n" +
+                "then\n" +
+                "    retract($p)\n" +
+                "end no-loop true rule R2 when Person() then end"; // 'end', 
attribute, 'rule' in the same line
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
+        List<RuleDescr> ruleDescrList = packageDescr.getRules();
+        assertThat(ruleDescrList).hasSize(2);
+        assertThat(ruleDescrList.get(0).getName()).isEqualTo("R1");
+        assertThat(ruleDescrList.get(1).getName()).isEqualTo("R2");
+        
assertThat(packageDescr.getAttributes().get(0).getName()).isEqualTo("no-loop"); 
// package level attribute
+    }
+
+    @Test
+    void endAndSingleLineCommentAndRule() {
+        final String text = "package org.drools\n" +
+                "rule R1\n" +
+                "when\n" +
+                "    $p : Person()\n" +
+                "then\n" +
+                "    retract($p)\n" +
+                "end\n" +
+                "// comment\n" +
+                "rule R2 when Person() then end";
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
+        List<RuleDescr> ruleDescrList = packageDescr.getRules();
+        assertThat(ruleDescrList).hasSize(2);
+        assertThat(ruleDescrList.get(0).getName()).isEqualTo("R1");
+        assertThat(ruleDescrList.get(1).getName()).isEqualTo("R2");
+    }
+
+    @Test
+    void endAndMultiLineCommentAndRule() {
+        final String text = "package org.drools\n" +
+                "rule R1\n" +
+                "when\n" +
+                "    $p : Person()\n" +
+                "then\n" +
+                "    retract($p)\n" +
+                "end\n" +
+                "/* comment\n" +
+                "comment */\n" +
+                "rule R2 when Person() then end";
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
+        List<RuleDescr> ruleDescrList = packageDescr.getRules();
+        assertThat(ruleDescrList).hasSize(2);
+        assertThat(ruleDescrList.get(0).getName()).isEqualTo("R1");
+        assertThat(ruleDescrList.get(1).getName()).isEqualTo("R2");
+    }
+
     @Test
     void singleQuoteInRhsWithSpace() {
         String consequence = getResultConsequence("    System.out.println( 
'singleQuoteInRhs' );\n");
@@ -3535,7 +3611,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 rhs +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         return ruleDescr.getConsequence().toString();
@@ -3551,7 +3627,7 @@ class MiscDRLParserTest {
                 "    retract($p);\n" +
                 "end\n";
 
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
 
@@ -3588,7 +3664,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 "end\n";
 
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         AndDescr lhs = ruleDescr.getLhs();
@@ -3620,7 +3696,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 "end\n";
 
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         AndDescr lhs = ruleDescr.getLhs();
@@ -3637,7 +3713,7 @@ class MiscDRLParserTest {
                 "    $p : Person(address!.city == $city)\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         
assertThat(constraintDescr.toString()).isEqualToIgnoringWhitespace("address!.city
 == $city");
     }
@@ -3650,7 +3726,7 @@ class MiscDRLParserTest {
                 "    $p : Person(address!.city!.startsWith(\"M\"))\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         
assertThat(constraintDescr.toString()).isEqualToIgnoringWhitespace("address!.city!.startsWith(\"M\")");
     }
@@ -3663,7 +3739,7 @@ class MiscDRLParserTest {
                 "    $p : Person( $containsL : address!.city.contains(\"L\") 
)\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         
assertThat(constraintDescr.toString()).isEqualToIgnoringWhitespace("$containsL 
: address!.city.contains(\"L\")");
     }
@@ -3676,7 +3752,7 @@ class MiscDRLParserTest {
                 "    $p : Person( address.(city.startsWith(\"I\") && 
city.length() == 5  ) )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         assertThat(constraintDescr.toString())
                 .as("prefix should be appended to each element")
@@ -3691,7 +3767,7 @@ class MiscDRLParserTest {
                 "    $p : Person( address!.(city!.startsWith(\"I\") && 
city!.length() == 5  ) )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         assertThat(constraintDescr.toString())
                 .as("prefix should be appended to each element")
@@ -3701,8 +3777,8 @@ class MiscDRLParserTest {
     @Test
     public void functionWithStringLiteral() {
         final String text = "function String star(String s) { return \"*\"; }";
-        PackageDescr packageDescr = parser.parse(text);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
 
         FunctionDescr function = packageDescr.getFunctions().get( 0 );
 
@@ -3716,8 +3792,8 @@ class MiscDRLParserTest {
     @Test
     public void functionWithStringLiteralAddition() {
         final String text = "function String addStar(String s) { return s + 
\"*\"; }";
-        PackageDescr packageDescr = parser.parse(text);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
 
         FunctionDescr function = packageDescr.getFunctions().get( 0 );
 
@@ -3734,8 +3810,8 @@ class MiscDRLParserTest {
                 "    String result = s + \"*\";\n" +
                 "    return result;\n" +
                 "}";
-        PackageDescr packageDescr = parser.parse(text);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
 
         FunctionDescr function = packageDescr.getFunctions().get( 0 );
 
@@ -3754,8 +3830,8 @@ class MiscDRLParserTest {
                 "    $p : Person( name == \"Mario\" ) @watch(!*, age)\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
+
 
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         PatternDescr patternDescr = (PatternDescr) 
ruleDescr.getLhs().getDescrs().get(0);
@@ -3773,7 +3849,7 @@ class MiscDRLParserTest {
                 "    $p : Person() from new Person(\"John\", 30)\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         PatternDescr patternDescr = (PatternDescr) 
ruleDescr.getLhs().getDescrs().get(0);
         FromDescr fromDescr = (FromDescr) patternDescr.getSource();
@@ -3788,8 +3864,7 @@ class MiscDRLParserTest {
                 "    @expires( value = 2s, policy = TIME_SOFT )\n" +
                 "end";
 
-        PackageDescr packageDescr = parser.parse(text);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
 
         AnnotationDescr annotationDescr = packageDescr
                 .getTypeDeclarations().get(0)
@@ -3807,7 +3882,7 @@ class MiscDRLParserTest {
                 " $man: Man( /wife/children[age > 10] )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         assertThat(constraintDescr.toString())
                 .isEqualToIgnoringWhitespace("/wife/children[age > 10]");
@@ -3827,7 +3902,7 @@ class MiscDRLParserTest {
                 " Man( /wife[$age : age] )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         assertThat(constraintDescr.toString())
                 .isEqualToIgnoringWhitespace("/wife[$age : age]");
@@ -3840,7 +3915,7 @@ class MiscDRLParserTest {
                 " Man( $toy: /wife/children[age > 10]/toys )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         assertThat(constraintDescr.toString())
                 .isEqualToIgnoringWhitespace("$toy: /wife/children[age > 
10]/toys");
@@ -3854,7 +3929,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 "end\n";
 
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         assertThat(constraintDescr.toString())
                 .isEqualToIgnoringWhitespace("$toy: /wife/children/toys[ 
name.length == ../name.length ]");
@@ -3868,7 +3943,7 @@ class MiscDRLParserTest {
                 "then\n" +
                 "end\n";
 
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         assertThat(constraintDescr.toString())
                 .isEqualToIgnoringWhitespace("/wife[$age : age] && age > 
$age");
@@ -3882,7 +3957,7 @@ class MiscDRLParserTest {
                 "  $a : ICA( someB#ICB.onlyConcrete() == \"Hello\" )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         
assertThat(constraintDescr.toString()).isEqualToIgnoringWhitespace("someB#ICB.onlyConcrete()
 == \"Hello\"");
     }
@@ -3895,7 +3970,7 @@ class MiscDRLParserTest {
                 "  $a : ICA( someB#ICB.someC#ICC.onlyConcrete() == \"Hello\" 
)\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         
assertThat(constraintDescr.toString()).isEqualToIgnoringWhitespace("someB#ICB.someC#ICC.onlyConcrete()
 == \"Hello\"");
     }
@@ -3908,7 +3983,7 @@ class MiscDRLParserTest {
                 "  $o : Object( this#Person.name == \"Mark\" )\n" +
                 "then\n" +
                 "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         ExprConstraintDescr constraintDescr = 
getFirstExprConstraintDescr(packageDescr);
         
assertThat(constraintDescr.toString()).isEqualToIgnoringWhitespace("this#Person.name
 == \"Mark\"");
     }
@@ -3987,8 +4062,7 @@ class MiscDRLParserTest {
     public void traitExtendsMultiple() throws Exception {
         final String source = "declare trait FatherTrait extends 
com.sample.ParentTrait, UncleTrait, org.test.GrandParentTrait end";
 
-        PackageDescr pkg = parser.parse(source);
-        
assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+        PackageDescr pkg = parseAndGetPackageDescr(source);
 
         final List<TypeDeclarationDescr> declarations = 
pkg.getTypeDeclarations();
 
@@ -4034,13 +4108,13 @@ class MiscDRLParserTest {
                 "then[FoundMark]\n" +
                 "  $r.addValue(\"Found \" + $p1.getName());\n" +
                 "end";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
         assertThat(namedConsequenceDescr.getName()).isEqualTo("FoundMark");
 
-        
assertThat(ruleDescr.getConsequence().toString()).isEqualTo("$r.addValue($p2.getName()
 + \" is older than \" + $p1.getName());");
-        
assertThat(ruleDescr.getNamedConsequences().get("FoundMark").toString()).isEqualTo("$r.addValue(\"Found
 \" + $p1.getName());");
+        
assertThat(ruleDescr.getConsequence().toString().trim()).isEqualTo("$r.addValue($p2.getName()
 + \" is older than \" + $p1.getName());");
+        
assertThat(ruleDescr.getNamedConsequences().get("FoundMark").toString().trim()).isEqualTo("$r.addValue(\"Found
 \" + $p1.getName());");
     }
 
     @Test
@@ -4057,7 +4131,7 @@ class MiscDRLParserTest {
                         "then[t2]\n" +
                         "    results.add( $a.getType().toUpperCase() );\n" +
                         "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(1);
         
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
@@ -4079,7 +4153,7 @@ class MiscDRLParserTest {
                         "then[t2]\n" +
                         "    results.add( $a.getType().toUpperCase() );\n" +
                         "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(1);
         
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
@@ -4101,7 +4175,7 @@ class MiscDRLParserTest {
                         "then[t2]\n" +
                         "    results.add( $a.getType().toUpperCase() );\n" +
                         "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(1);
         
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
@@ -4124,7 +4198,7 @@ class MiscDRLParserTest {
                         "then[FoundMark]\n" +
                         "  $r.addValue(\"Found \" + $p1.getName());\n" +
                         "end";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
         assertThat(namedConsequenceDescr.getName()).isEqualTo("FoundMark");
@@ -4143,7 +4217,7 @@ class MiscDRLParserTest {
                         "then[FoundMark]\n" +
                         "  $r.addValue(\"NotFound \" + $p1.getName());\n" +
                         "end";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
         assertThat(namedConsequenceDescr.getName()).isEqualTo("NotFoundMark");
@@ -4163,7 +4237,7 @@ class MiscDRLParserTest {
                         "then[t2]\n" +
                         "    results.add( $a.getType().toUpperCase() );\n" +
                         "end\n";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(2);
         
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
@@ -4184,7 +4258,7 @@ class MiscDRLParserTest {
                         "then[FoundMark]\n" +
                         "  $r.addValue(\"Found \" + $p1.getName());\n" +
                         "end";
-        PackageDescr packageDescr = parser.parse(text);
+        PackageDescr packageDescr = parseAndGetPackageDescr(text);
         RuleDescr ruleDescr = packageDescr.getRules().get(0);
         NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
         
assertThat(namedConsequenceDescr.getName()).isEqualTo("FoundMarkOrMario");
diff --git 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/ParserTestUtils.java
 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/ParserTestUtils.java
new file mode 100644
index 0000000000..f0d1f854d2
--- /dev/null
+++ 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/ParserTestUtils.java
@@ -0,0 +1,35 @@
+/**
+ * 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.drools.drl.parser.DrlParser;
+
+public class ParserTestUtils {
+
+    private ParserTestUtils() {
+        // It is a utility class, so it should not be instantiated.
+    }
+
+    /**
+     * Returns a DrlParser which encapsulates an old or new parser depending 
on system property
+     */
+    public static DrlParser getParser() {
+        return new DrlParser();
+    }
+}
diff --git 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
index 631d2a49a1..52716591ad 100644
--- 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
+++ 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
@@ -12,6 +12,10 @@ import JavaLexer;
         }
         return input;
     }
+
+    public boolean isRhsDrlEnd() {
+        return new LexerHelper(_input).isRhsDrlEnd();
+    }
 }
 
 /////////////////
@@ -164,7 +168,8 @@ DrlUnicodeEscape
 
 mode RHS;
 RHS_WS : [ \t\r\n\u000C]+ -> channel(HIDDEN);
-DRL_RHS_END : 'end' [ \t]* SEMI? [ \t]* ('\n' | '\r\n' | EOF) 
{setText("end");} -> popMode;
+//DRL_RHS_END : 'end' [ \t]* SEMI? [ \t]* ('\n' | '\r\n' | EOF) { 
setText("end"); } -> popMode;
+DRL_RHS_END : {isRhsDrlEnd()}? DRL_END -> popMode;
 
 RHS_STRING_LITERAL
       // cannot reuse DRL_STRING_LITERAL because Actions are ignored in 
referenced rules
@@ -184,4 +189,4 @@ RHS_CHUNK
     | RBRACE
     | COMMA
     | SEMI
-    ;
+    ;
\ No newline at end of file
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 f4358ccf70..2bc5e37f5e 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
@@ -17,24 +17,24 @@ import DRL6Expressions, JavaParser;
 compilationUnit : packagedef? unitdef? drlStatementdef* ;
 
 drlStatementdef
-    : importdef
-    | globaldef
-    | declaredef
-    | ruledef
-    | attributes
-    | functiondef
-    | querydef
+    : importdef SEMI?
+    | globaldef SEMI?
+    | declaredef SEMI?
+    | ruledef SEMI?
+    | attributes SEMI?
+    | functiondef SEMI?
+    | querydef SEMI?
     ;
 
 packagedef : PACKAGE name=drlQualifiedName SEMI? ;
 
 unitdef : DRL_UNIT name=drlQualifiedName SEMI? ;
 
-importdef : IMPORT (DRL_FUNCTION|STATIC)? drlQualifiedName (DOT MUL)? SEMI?    
     #importStandardDef
-          | IMPORT (DRL_ACCUMULATE|DRL_ACC) drlQualifiedName IDENTIFIER SEMI?  
     #importAccumulateDef
+importdef : IMPORT (DRL_FUNCTION|STATIC)? drlQualifiedName (DOT MUL)?          
#importStandardDef
+          | IMPORT (DRL_ACCUMULATE|DRL_ACC) drlQualifiedName IDENTIFIER        
#importAccumulateDef
           ;
 
-globaldef : DRL_GLOBAL type drlIdentifier SEMI? ;
+globaldef : DRL_GLOBAL type drlIdentifier ;
 
 /**
  * declare := DECLARE
@@ -60,15 +60,15 @@ declaredef : DRL_DECLARE (
  *                     END
  */
 
-typeDeclaration : DRL_TRAIT? name=drlQualifiedName (EXTENDS 
superTypes+=drlQualifiedName (COMMA superTypes+=drlQualifiedName)* )? 
drlAnnotation* field* DRL_END SEMI?;
+typeDeclaration : DRL_TRAIT? name=drlQualifiedName (EXTENDS 
superTypes+=drlQualifiedName (COMMA superTypes+=drlQualifiedName)* )? 
drlAnnotation* field* DRL_END ;
 
 // entryPointDeclaration := ENTRY-POINT stringId annotation* END
 
-entryPointDeclaration : DRL_ENTRY_POINT name=stringId drlAnnotation* DRL_END 
SEMI?;
+entryPointDeclaration : DRL_ENTRY_POINT name=stringId drlAnnotation* DRL_END ;
 
 // windowDeclaration := WINDOW ID annotation* lhsPatternBind END
 
-windowDeclaration : DRL_WINDOW name=IDENTIFIER drlAnnotation* lhsPatternBind 
DRL_END SEMI?;
+windowDeclaration : DRL_WINDOW name=IDENTIFIER drlAnnotation* lhsPatternBind 
DRL_END ;
 
 // field := label fieldType (EQUALS_ASSIGN conditionalExpression)? annotation* 
SEMICOLON?
 
@@ -76,11 +76,11 @@ field : label type (ASSIGN 
initExpr=conditionalOrExpression)? drlAnnotation* SEM
 
 // rule := RULE stringId (EXTENDS stringId)? annotation* attributes? lhs? rhs 
END
 
-ruledef : DRL_RULE name=stringId (EXTENDS parentName=stringId)? drlAnnotation* 
attributes? lhs rhs DRL_RHS_END ;
+ruledef : DRL_RULE name=stringId (EXTENDS parentName=stringId)? drlAnnotation* 
attributes? lhs? rhs DRL_RHS_END ;
 
 // query := QUERY stringId parameters? annotation* lhsExpression END
 
-querydef : DRL_QUERY name=stringId parameters? drlAnnotation* lhsExpression+ 
DRL_END SEMI?;
+querydef : DRL_QUERY name=stringId parameters? drlAnnotation* lhsExpression+ 
DRL_END ;
 
 // parameters := LEFT_PAREN ( parameter ( COMMA parameter )* )? RIGHT_PAREN
 parameters : LPAREN ( parameter ( COMMA parameter )* )? RPAREN ;
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/DrlParser.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/DrlParser.java
index 4bad571401..5e6fb78c6f 100644
--- 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/DrlParser.java
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/DrlParser.java
@@ -60,7 +60,9 @@ public class DrlParser {
     private Resource                resource              = null;
 
     public static final String ANTLR4_PARSER_ENABLED_PROPERTY = 
"drools.drl.antlr4.parser.enabled";
-    public static final boolean ANTLR4_PARSER_ENABLED = 
Boolean.parseBoolean(System.getProperty(ANTLR4_PARSER_ENABLED_PROPERTY, 
"true")); // default is true
+
+    // TODO: temporarily removed 'final' for testing purposes. This should be 
final
+    public static boolean ANTLR4_PARSER_ENABLED = 
Boolean.parseBoolean(System.getProperty(ANTLR4_PARSER_ENABLED_PROPERTY, 
"true")); // default is true
 
     public static final LanguageLevelOption DEFAULT_LANGUAGE_LEVEL = 
LanguageLevelOption.DRL6;
     private final LanguageLevelOption languageLevel;
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 526aaddf24..83452cdc43 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
@@ -148,6 +148,11 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
                 .build();
     }
 
+    @Override
+    public BaseDescr visitDrlStatementdef(DRLParser.DrlStatementdefContext 
ctx) {
+        return visitDescrChildren(ctx).get(0); // only one child. Ignore 
SEMICOLON
+    }
+
     @Override
     public GlobalDescr visitGlobaldef(DRLParser.GlobaldefContext ctx) {
         return BaseDescrFactory.builder(new 
GlobalDescr(ctx.drlIdentifier().getText(), ctx.type().getText()))
@@ -290,7 +295,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             List<BaseDescr> lhsDescrList = visitLhs(ctx.lhs());
             lhsDescrList.forEach(descr -> rootDescr.addDescr(descr));
             slimLhsRootDescr(rootDescr);
-            DescrHelper.refreshRootProperties(rootDescr);
+            DescrHelper.populateCommonProperties(rootDescr, 
ctx.lhs().lhsExpression());
+        } else {
+            ruleDescr.setLhs(new AndDescr());
         }
 
         if (ctx.rhs() != null) {
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
index 9cdc65b94d..b091b8f588 100644
--- 
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
@@ -21,8 +21,11 @@ package org.drools.drl.parser.antlr4;
 import java.util.List;
 
 import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.TerminalNode;
 import org.drools.drl.ast.descr.AndDescr;
+import org.drools.drl.ast.descr.AttributeDescr;
 import org.drools.drl.ast.descr.BaseDescr;
+import org.drools.drl.ast.descr.ExprConstraintDescr;
 import org.drools.drl.ast.descr.PatternDescr;
 
 /**
@@ -35,29 +38,38 @@ public class DescrHelper {
     }
 
     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
+
+        if (descr instanceof ExprConstraintDescr) {
+            // Backward Compatibility Notes:
+            //   Old DRL6Parser.constraint() has slightly different behavior 
for ExprConstraintDescr. Keep it for backward compatibility
+            //   When we will update LanguageLevel, we can align this with 
other Descr.
+            descr.setStartCharacter(ctx.getStart().getStartIndex());
+            descr.setEndCharacter(ctx.getStop().getStopIndex());
+            descr.setLocation(ctx.getStart().getLine(), 
ctx.getStart().getCharPositionInLine());
+            descr.setEndLocation(ctx.getStop().getLine(), 
ctx.getStop().getCharPositionInLine());
+        } else {
+            descr.setStartCharacter(ctx.getStart().getStartIndex());
+            // Backward Compatibility Notes:
+            //   Old DRL6Parser adds +1 for EndCharacter (except 
ExprConstraintDescr). This new parser follows the same to keep the backward 
compatibility.
+            //   However, it doesn't look reasonable. When we will update 
LanguageLevel, we can remove this +1.
+            descr.setEndCharacter(ctx.getStop().getStopIndex() + 1);
+            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()) {
+    public static <T extends BaseDescr> T populateCommonProperties(T descr, 
List<? extends ParserRuleContext> ctxList) {
+        if (ctxList.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());
+        ParserRuleContext firstCtx = ctxList.get(0);
+        ParserRuleContext lastCtx = ctxList.get(ctxList.size() - 1);
+
+        descr.setStartCharacter(firstCtx.getStart().getStartIndex());
+        descr.setEndCharacter(lastCtx.getStop().getStopIndex() + 1);
+        descr.setLocation(firstCtx.getStart().getLine(), 
firstCtx.getStart().getCharPositionInLine());
+        descr.setEndLocation(lastCtx.getStop().getLine(), 
lastCtx.getStop().getCharPositionInLine() + 
lastCtx.getStop().getText().length() - 1); // last column of the end token
         return descr;
     }
 
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/LexerHelper.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/LexerHelper.java
new file mode 100644
index 0000000000..479eebce85
--- /dev/null
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/LexerHelper.java
@@ -0,0 +1,161 @@
+/**
+ * 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.CharStream;
+import org.antlr.v4.runtime.IntStream;
+import org.drools.drl.parser.lang.DroolsSoftKeywords;
+
+/**
+ * Helper class for lexer. It requires instance creation to keep track of the 
lookahead counter.
+ */
+public class LexerHelper {
+
+    private static final List<Character> semiAndWS = List.of(';', ' ', '\t', 
'\n', '\r');
+    private static final List<String> statementKeywordsList = 
List.of(ParserHelper.statementKeywords);
+    private static final List<String> attributeKeywordsList = 
List.of(DroolsSoftKeywords.SALIENCE,
+                                                                      
DroolsSoftKeywords.ENABLED,
+                                                                      
DroolsSoftKeywords.NO + "-" + DroolsSoftKeywords.LOOP,
+                                                                      
DroolsSoftKeywords.AUTO + "-" + DroolsSoftKeywords.FOCUS,
+                                                                      
DroolsSoftKeywords.LOCK + "-" + DroolsSoftKeywords.ON + "-" + 
DroolsSoftKeywords.ACTIVE,
+                                                                      
DroolsSoftKeywords.AGENDA + "-" + DroolsSoftKeywords.GROUP,
+                                                                      
DroolsSoftKeywords.ACTIVATION + "-" + DroolsSoftKeywords.GROUP,
+                                                                      
DroolsSoftKeywords.RULEFLOW + "-" + DroolsSoftKeywords.GROUP,
+                                                                      
DroolsSoftKeywords.DATE + "-" + DroolsSoftKeywords.EFFECTIVE,
+                                                                      
DroolsSoftKeywords.DATE + "-" + DroolsSoftKeywords.EXPIRES,
+                                                                      
DroolsSoftKeywords.DIALECT,
+                                                                      
DroolsSoftKeywords.CALENDARS,
+                                                                      
DroolsSoftKeywords.TIMER,
+                                                                      
DroolsSoftKeywords.DURATION,
+                                                                      
DroolsSoftKeywords.REFRACT,
+                                                                      
DroolsSoftKeywords.DIRECT);
+
+    private final CharStream input;
+    private int lookAheadCounter;
+
+    public LexerHelper(CharStream input) {
+        this.input = input;
+        this.lookAheadCounter = 1;
+    }
+
+    /**
+     * Determine if the current token is the end of a RHS DRL by lookahead.
+     * 1. 'end'
+     * 2. skip semi, WS, and comment
+     * 3. next token should be EOF or statement or attribute keyword
+     *
+     * TODO: This method is low-level and may be too complex in order to keep 
backward compatibility.
+     *       This could be refactored by going back to a parser rather than 
the lexer island mode.
+     */
+    boolean isRhsDrlEnd() {
+        if (!validateDrlEnd()) {
+            return false;
+        }
+        skipSemiAndWSAndComment();
+
+        return validateEOForNextStatement();
+    }
+
+    private boolean validateDrlEnd() {
+        return captureNextToken().equals(DroolsSoftKeywords.END);
+    }
+
+    private String captureNextToken() {
+        StringBuilder sb = new StringBuilder();
+        while (true) {
+            int la = input.LA(lookAheadCounter);
+            if (semiAndWS.contains((char) la) || la == IntStream.EOF) {
+                break;
+            }
+            sb.append((char) la);
+            lookAheadCounter++;
+        }
+        return sb.toString(); // never null
+    }
+
+    private void skipSemiAndWSAndComment() {
+        do {
+            // skip semi and WS, and repeat that so long as it's followed by a 
valid and skipped comment
+            skipSemiAndWS();
+        } while (skipComment());
+    }
+
+    private void skipSemiAndWS() {
+        while (true) {
+            int la = input.LA(lookAheadCounter);
+            if (!semiAndWS.contains((char) la)) {
+                break;
+            }
+            lookAheadCounter++;
+        }
+    }
+
+    // if comment is found, skip it and return true
+    private boolean skipComment() {
+        boolean skipped = false;
+        // skip single line comment
+        int la1 = input.LA(lookAheadCounter);
+        int la2 = input.LA(lookAheadCounter + 1);
+        if (la1 == '/' && la2 == '/') {
+            // skip single line comment
+            skipSingleLineComment();
+            skipped = true;
+        } else if (la1 == '/' && la2 == '*') {
+            // skip multi line comment
+            skipMultiLineComment();
+            skipped = true;
+        }
+
+        return skipped;
+    }
+
+    private void skipSingleLineComment() {
+        while (true) {
+            int la = input.LA(lookAheadCounter);
+            if (la == '\n' || la == IntStream.EOF) { // this can handle `\r\n` 
as well
+                break;
+            }
+            lookAheadCounter++;
+        }
+    }
+
+    private void skipMultiLineComment() {
+        while (true) {
+            int la = input.LA(lookAheadCounter);
+            if (la == IntStream.EOF) {
+                break;
+            }
+            if (la == '*' && input.LA(lookAheadCounter + 1) == '/') {
+                lookAheadCounter += 2;
+                break;
+            }
+            lookAheadCounter++;
+        }
+    }
+
+    private boolean validateEOForNextStatement() {
+        if (input.LA(lookAheadCounter) == IntStream.EOF) {
+            return true;
+        }
+        String nextToken = captureNextToken();
+        return statementKeywordsList.contains(nextToken) || 
attributeKeywordsList.contains(nextToken);
+    }
+}
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
index 504233edee..fed7024c20 100644
--- 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
@@ -91,7 +91,7 @@ import org.kie.internal.builder.conf.LanguageLevelOption;
  * by the DRL parser
  */
 public class ParserHelper {
-    public final String[]                             statementKeywords        
= new String[]{
+    public static final String[]                      statementKeywords        
= new String[]{
                                                                                
DroolsSoftKeywords.PACKAGE,
                                                                                
DroolsSoftKeywords.UNIT,
                                                                                
DroolsSoftKeywords.IMPORT,


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

Reply via email to