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

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

commit 97a13f11460edbb51dbcde0cbff02bf210f270f7
Author: mariofusco <[email protected]>
AuthorDate: Fri Jan 14 17:19:41 2022 +0100

    add antlr4 based drl parser
---
 drools-drl/drools-drl10-parser/.gitignore          | 17 +++++
 drools-drl/drools-drl10-parser/pom.xml             | 76 ++++++++++++++++++++++
 .../src/main/antlr4/org/drools/parser/DRL.g4       | 64 ++++++++++++++++++
 .../java/org/drools/parser/DRLParserHelper.java    | 64 ++++++++++++++++++
 .../java/org/drools/parser/DRLVisitorImpl.java     | 40 ++++++++++++
 .../test/java/org/drools/parser/DRLParserTest.java | 59 +++++++++++++++++
 6 files changed, 320 insertions(+)

diff --git a/drools-drl/drools-drl10-parser/.gitignore 
b/drools-drl/drools-drl10-parser/.gitignore
new file mode 100644
index 0000000000..372e03f026
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/.gitignore
@@ -0,0 +1,17 @@
+target/
+local/
+
+# Eclipse, Netbeans and IntelliJ files
+.*
+!.gitignore
+!.github
+nbproject
+*.ipr
+*.iws
+*.iml
+
+# generated files
+dependency-reduced-pom.xml
+
+#CI
+!.ci
diff --git a/drools-drl/drools-drl10-parser/pom.xml 
b/drools-drl/drools-drl10-parser/pom.xml
new file mode 100644
index 0000000000..624344d268
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.drools</groupId>
+    <artifactId>drools-lsp</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+  </parent>
+
+  <groupId>org.drools</groupId>
+  <artifactId>drools-parser</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+
+  <name>Drools :: Parser</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.drools</groupId>
+      <artifactId>drools-drl-ast</artifactId>
+      <version>8.16.0-SNAPSHOT</version>
+    </dependency>
+
+    <!-- External dependencies -->
+    <dependency>
+      <groupId>org.antlr</groupId>
+      <artifactId>antlr4-runtime</artifactId>
+      <version>${version.org.antlr4}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.antlr</groupId>
+      <artifactId>antlr4</artifactId>
+      <version>${version.org.antlr4}</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.glassfish</groupId>
+          <artifactId>javax.json</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <!-- Tests -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${version.junit}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.antlr</groupId>
+        <artifactId>antlr4-maven-plugin</artifactId>
+        <version>${version.org.antlr4}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>antlr4</goal>
+            </goals>
+            <configuration>
+              <visitor>true</visitor>
+              <listener>false</listener>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+  </build>
+
+</project>
diff --git 
a/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRL.g4 
b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRL.g4
new file mode 100644
index 0000000000..e83e84dd5f
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRL.g4
@@ -0,0 +1,64 @@
+grammar DRL;
+
+// KEYWORDS
+
+PACKAGE : 'package';
+IMPORT : 'import';
+RULE : 'rule';
+WHEN : 'when';
+THEN : 'then';
+END : 'end';
+
+// PARSER
+
+compilationunit : packagedef? importdef* ruledef* ;
+
+packagedef : PACKAGE FQNAME SEMICOLON? ;
+
+importdef : IMPORT FQNAME (DOT STAR)? SEMICOLON? ;
+
+ruledef : RULE IDENTIFIER WHEN lhs THEN rhs END ;
+
+lhs : TEXT ;
+
+rhs : TEXT ;
+
+// LITERALS
+
+fragment DIGIT : [0-9] ;
+NUMBER         : DIGIT+ ([.,] DIGIT+)? ;
+
+fragment LOWERCASE  : [a-z] ;
+fragment UPPERCASE  : [A-Z] ;
+LETTER : (LOWERCASE | UPPERCASE | '_' | '$') ;
+
+IDENTIFIER : LETTER (LETTER | DIGIT)* ;
+FQNAME : IDENTIFIER (DOT IDENTIFIER)* ;
+
+// SEPARATORS
+
+LPAREN : '(';
+RPAREN : ')';
+LBRACE : '{';
+RBRACE : '}';
+LBRACK : '[';
+RBRACK : ']';
+COMMA : ',';
+ELIPSIS : '..';
+DOT : '.';
+COLON : ':';
+SEMICOLON : ';';
+STAR : '*';
+
+// OPERATORS
+
+EQUAL : '=';
+GT : '>';
+LT : '<';
+LE : '<=';
+GE : '>=';
+NOTEQUAL : '!=';
+
+WS : [ \t\r\n\u000C\u00A0]+ -> skip ;
+
+fragment TEXT : .+ ;
diff --git 
a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLParserHelper.java
 
b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLParserHelper.java
new file mode 100644
index 0000000000..826517a0c2
--- /dev/null
+++ 
b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLParserHelper.java
@@ -0,0 +1,64 @@
+package org.drools.parser;
+
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.RuleContext;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.drools.drl.ast.descr.PackageDescr;
+
+public class DRLParserHelper {
+
+    public static PackageDescr parse(String drl) {
+        return parseTree2PackageDescr(createParseTree(drl));
+    }
+
+    public static ParseTree createParseTree(String drl) {
+        CharStream inputStream = CharStreams.fromString(drl);
+        DRLLexer drlLexer = new DRLLexer(inputStream);
+        CommonTokenStream commonTokenStream = new CommonTokenStream(drlLexer);
+        DRLParser drlParser = new DRLParser(commonTokenStream);
+        return drlParser.compilationunit();
+    }
+
+    public static PackageDescr parseTree2PackageDescr(ParseTree parseTree) {
+        DRLVisitorImpl visitor = new DRLVisitorImpl();
+        visitor.visit(parseTree);
+        return visitor.getPackageDescr();
+    }
+
+    public static ParseTree findNodeAtPosition(ParseTree root, int row, int 
col) {
+        for (int i = 0; i < root.getChildCount(); i++) {
+            ParseTree child = root.getChild(i);
+            Token stopToken = child instanceof TerminalNode ? 
((TerminalNode)child).getSymbol() : ((ParserRuleContext)child).getStop();
+
+            if (endsAfter(stopToken, row, col)) {
+                return findNodeAtPosition(child, row, col);
+            }
+        }
+        return root;
+    }
+
+    private static boolean endsAfter(Token token, int row, int col) {
+        if (token.getLine() != row) {
+            return token.getLine() > row;
+        }
+        int tokenLength = (token.getStopIndex() - token.getStartIndex()) + 1;
+        int lastTokenPosition = token.getCharPositionInLine() + tokenLength;
+        return lastTokenPosition >= col;
+    }
+
+    public static boolean hasParentOfType(ParseTree leaf, int type) {
+        return findParentOfType(leaf, type) != null;
+    }
+
+    public static ParseTree findParentOfType(ParseTree leaf, int type) {
+        if (leaf == null || (leaf instanceof RuleContext && ((RuleContext) 
leaf).getRuleIndex() == type)) {
+            return leaf;
+        }
+        return findParentOfType(leaf.getParent(), type);
+    }
+}
diff --git 
a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLVisitorImpl.java
 
b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLVisitorImpl.java
new file mode 100644
index 0000000000..780076b9ab
--- /dev/null
+++ 
b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLVisitorImpl.java
@@ -0,0 +1,40 @@
+package org.drools.parser;
+
+import org.drools.drl.ast.descr.ImportDescr;
+import org.drools.drl.ast.descr.PackageDescr;
+import org.drools.drl.ast.descr.RuleDescr;
+
+public class DRLVisitorImpl extends DRLBaseVisitor<Object> {
+
+    private final PackageDescr packageDescr = new PackageDescr();
+
+    @Override
+    public Object visitCompilationunit(DRLParser.CompilationunitContext ctx) {
+        return super.visitCompilationunit(ctx);
+    }
+
+    @Override
+    public Object visitPackagedef(DRLParser.PackagedefContext ctx) {
+        packageDescr.setName(ctx.FQNAME().getText());
+        return super.visitPackagedef(ctx);
+    }
+
+    @Override
+    public Object visitImportdef(DRLParser.ImportdefContext ctx) {
+        String imp = ctx.FQNAME().getText() + (ctx.STAR() != null ? ".*" : "");
+        packageDescr.addImport(new ImportDescr(imp));
+        return super.visitImportdef(ctx);
+    }
+
+    @Override
+    public Object visitRuledef(DRLParser.RuledefContext ctx) {
+        RuleDescr rule = new RuleDescr(ctx.IDENTIFIER().getText());
+        rule.setConsequence(ctx.rhs().getText());
+        packageDescr.addRule(rule);
+        return super.visitRuledef(ctx);
+    }
+
+    public PackageDescr getPackageDescr() {
+        return packageDescr;
+    }
+}
diff --git 
a/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/DRLParserTest.java
 
b/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/DRLParserTest.java
new file mode 100644
index 0000000000..4e4e27e8d7
--- /dev/null
+++ 
b/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/DRLParserTest.java
@@ -0,0 +1,59 @@
+package org.drools.parser;
+
+import org.antlr.v4.runtime.RuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.drools.drl.ast.descr.PackageDescr;
+import org.junit.Test;
+
+import static org.drools.parser.DRLParserHelper.createParseTree;
+import static org.drools.parser.DRLParserHelper.findNodeAtPosition;
+import static org.drools.parser.DRLParserHelper.findParentOfType;
+import static org.drools.parser.DRLParserHelper.parse;
+import static org.junit.Assert.assertEquals;
+
+public class DRLParserTest {
+
+    @Test
+    public void testParse() {
+        String drl =
+                "package org.test;\n" +
+                "import org.test.model.Person;\n" +
+                "rule TestRule when\n" +
+                "  $p:Person()\n" +
+                "then\n" +
+                "  System.out.println($p.getName());\n" +
+                "end\n";
+
+        PackageDescr packageDescr = parse(drl);
+        assertEquals("org.test", packageDescr.getName());
+
+        assertEquals(1, packageDescr.getImports().size());
+        assertEquals("org.test.model.Person", 
packageDescr.getImports().get(0).getTarget());
+
+        assertEquals(1, packageDescr.getRules().size());
+        assertEquals("TestRule", packageDescr.getRules().get(0).getName());
+        assertEquals("System.out.println($p.getName());", 
packageDescr.getRules().get(0).getConsequence());
+    }
+
+    @Test
+    public void testCursorPosition() {
+        String drl =
+                "package org.test;\n" +
+                "import org.test.model.Person;\n" +
+                "rule TestRule when\n" +
+                "  $p:Person()\n" +
+                "then\n" +
+                "  System.out.println($p.getName());\n" +
+                "end\n";
+
+        int row = 4;
+        int col = 7;
+
+        ParseTree parseTree = createParseTree(drl);
+        ParseTree node = findNodeAtPosition(parseTree, row, col);
+        assertEquals("Person", node.getText());
+        ParseTree lhs = findParentOfType(node, DRLParser.RULE_lhs);
+        assertEquals(DRLParser.RULE_lhs, ((RuleContext) lhs).getRuleIndex());
+        assertEquals("$p:Person()", lhs.getText());
+    }
+}


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

Reply via email to