You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by jf...@apache.org on 2019/05/25 14:20:17 UTC

[plc4x] 01/02: [CODE-GEN] Several fixes and play around with ser / deser.

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

jfeinauer pushed a commit to branch feature/code-gen-julian
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit b24ee1c42fef1eafcfdc59b7e7dff7ec1dc9320e
Author: Julian Feinauer <j....@pragmaticminds.de>
AuthorDate: Fri May 24 14:52:00 2019 +0200

    [CODE-GEN] Several fixes and play around with ser / deser.
---
 pom.xml                                            |   7 +
 sandbox/plc4x-maven-plugin/pom.xml                 |   8 ++
 .../plugins/codegenerator/parser/ClassBuilder.java | 147 +++++++++++++++++++++
 .../parser/MessageFormatListener.java              |  11 +-
 .../codegenerator/parser/MessageFormatParser.java  | 112 +++++++++++++++-
 sandbox/pom.xml                                    |   1 +
 6 files changed, 280 insertions(+), 6 deletions(-)

diff --git a/pom.xml b/pom.xml
index d14ea55..17f70fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -751,6 +751,13 @@
 
             <!-- Temporary Python virtualenv files-->
             <exclude>**/venv/**</exclude>
+
+            <!-- Exclude antlr4 files?! -->
+            <exclude>**/*.g4</exclude>
+
+
+            <!-- (Temporary) Exclude spec files (from Chris) -->
+            <exclude>**/*.spec</exclude>
           </excludes>
         </configuration>
       </plugin>
diff --git a/sandbox/plc4x-maven-plugin/pom.xml b/sandbox/plc4x-maven-plugin/pom.xml
index ad9e8ca..d1a8121 100644
--- a/sandbox/plc4x-maven-plugin/pom.xml
+++ b/sandbox/plc4x-maven-plugin/pom.xml
@@ -213,6 +213,14 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>8</source>
+          <target>8</target>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
diff --git a/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/ClassBuilder.java b/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/ClassBuilder.java
new file mode 100644
index 0000000..079fd4a
--- /dev/null
+++ b/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/ClassBuilder.java
@@ -0,0 +1,147 @@
+package org.apache.plc4x.plugins.codegenerator.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Util to Define Classes based on the {@link org.apache.plc4x.codegen.ast.Expressions} API.
+ *
+ * @author julian
+ */
+public class ClassBuilder {
+
+    private String className;
+    private final List<ConstantField> constants = new ArrayList<>();
+    private final List<VariableField> fields = new ArrayList<>();
+    // TODO constructor call??
+    private String parent;
+
+    public ClassBuilder() {
+    }
+
+    public ClassBuilder withName(String name) {
+        className = name;
+        return this;
+    }
+
+    public ClassBuilder withConstant(String name, String type, Object value) {
+        this.constants.add(new ConstantField(name, type, value));
+        return this;
+    }
+
+    public ClassBuilder withConstant(String name, String type, Object value, Documentation docu) {
+        this.constants.add(new ConstantField(name, type, value, docu));
+        return this;
+    }
+
+    public ClassBuilder withField(String name, String type) {
+        this.fields.add(new VariableField(name, type));
+        return this;
+    }
+
+    public ClassBuilder withField(String name, String type, Documentation docu) {
+        this.fields.add(new VariableField(name, type, Optional.empty(), docu));
+        return this;
+    }
+
+    public ClassBuilder withField(String name, String type, Object initialValue, Documentation docu) {
+        this.fields.add(new VariableField(name, type, Optional.of(initialValue), docu));
+        return this;
+    }
+
+    public ClassBuilder withParent(String parent) {
+        this.parent = parent;
+        return this;
+    }
+
+    @Override public String toString() {
+        return "ClassBuilder{" +
+            "className='" + className + '\'' +
+            ", constants=" + constants +
+            ", fields=" + fields +
+            ", parent='" + parent + '\'' +
+            '}';
+    }
+
+    // Regular "java" fields
+    public static class VariableField {
+
+        private final String name;
+        private final String type;
+        private final Optional<Object> initialValue;
+        private final Documentation documentation;
+
+        public VariableField(String name, String type) {
+            this(name, type, Optional.empty(), null);
+        }
+
+        public VariableField(String name, String type, Optional<Object> initialValue) {
+            this(name, type, initialValue, null);
+        }
+
+        public VariableField(String name, String type, Optional<Object> initialValue, Documentation documentation) {
+            this.name = name;
+            this.type = type;
+            this.initialValue = initialValue;
+            this.documentation = documentation;
+        }
+
+        @Override public String toString() {
+            return "VariableField{" +
+                "name='" + name + '\'' +
+                ", type='" + type + '\'' +
+                ", initialValue=" + initialValue +
+                ", documentation=" + documentation +
+                '}';
+        }
+    }
+
+    // Consts
+    public static class ConstantField {
+
+        private final String name;
+        private final String type;
+        private final Object value;
+        private final Documentation documentation;
+
+        public ConstantField(String name, String type, Object value) {
+            this(name, type, value, null);
+        }
+
+        public ConstantField(String name, String type, Object value, Documentation documentation) {
+            this.name = name;
+            this.type = type;
+            this.value = value;
+            this.documentation = documentation;
+        }
+
+        @Override public String toString() {
+            return "ConstantField{" +
+                "name='" + name + '\'' +
+                ", type='" + type + '\'' +
+                ", value=" + value +
+                ", documentation=" + documentation +
+                '}';
+        }
+    }
+
+    /**
+     * Documentation for a declaration
+     */
+    public static class Documentation {
+
+        private final String text;
+
+        public Documentation(String text) {
+            this.text = text;
+        }
+
+        @Override public String toString() {
+            return "Documentation{" +
+                "text='" + text + '\'' +
+                '}';
+        }
+    }
+
+}
diff --git a/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java b/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java
index e0d0d01..c0211bc 100644
--- a/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java
+++ b/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java
@@ -72,7 +72,7 @@ public class MessageFormatListener extends ImaginaryBaseListener {
     @Override
     public void enterArrayField(ImaginaryParser.ArrayFieldContext ctx) {
         String typeName = ctx.type.getText();
-        String name = ctx.name.id.getText();
+        String name = ctx.name.IDENTIFIER().getText();
         ArrayField.LengthType lengthType;
         if(ctx.lengthType.K_COUNT() != null) {
             lengthType = ArrayField.LengthType.COUNT;
@@ -87,7 +87,8 @@ public class MessageFormatListener extends ImaginaryBaseListener {
     @Override
     public void enterConstField(ImaginaryParser.ConstFieldContext ctx) {
         SimpleType type = new SimpleType(ctx.type.getText());
-        String expected = ctx.expected.getText();
+        // TODO use a visitor or something to get this without TICKs
+        String expected = ctx.expected.expr.getText();
         Field field = new ConstField(type, expected);
         parserContexts.peek().add(field);
     }
@@ -115,7 +116,7 @@ public class MessageFormatListener extends ImaginaryBaseListener {
     @Override
     public void enterSimpleField(ImaginaryParser.SimpleFieldContext ctx) {
         SimpleType type = new SimpleType(ctx.type.getText());
-        String name = ctx.name.getText();
+        String name = ctx.name.IDENTIFIER().getText();
         Field field = new SimpleField(type, name);
         parserContexts.peek().add(field);
     }
@@ -123,7 +124,7 @@ public class MessageFormatListener extends ImaginaryBaseListener {
     @Override
     public void enterImplicitField(ImaginaryParser.ImplicitFieldContext ctx) {
         SimpleType type = new SimpleType(ctx.type.getText());
-        String serializationExpression = ctx.serializationExpression.getText();
+        String serializationExpression = ctx.serializationExpression.innerExpression().getText();
         Field field = new ImplicitField(type, serializationExpression);
         parserContexts.peek().add(field);
     }
@@ -131,7 +132,7 @@ public class MessageFormatListener extends ImaginaryBaseListener {
     @Override
     public void enterOptionalField(ImaginaryParser.OptionalFieldContext ctx) {
         SimpleType type = new SimpleType(ctx.type.getText());
-        String name = ctx.name.getText();
+        String name = ctx.name.IDENTIFIER().getText();
         String conditionExpression = ctx.condition.expr.getText();
         Field field = new OptionalField(type, name, conditionExpression);
         parserContexts.peek().add(field);
diff --git a/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatParser.java b/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatParser.java
index df88a0a..9fa4f3c 100644
--- a/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatParser.java
+++ b/sandbox/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatParser.java
@@ -23,18 +23,64 @@ import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.apache.plc4x.codegen.ast.ClassDeclaration;
+import org.apache.plc4x.codegen.ast.CodeWriter;
+import org.apache.plc4x.codegen.ast.Expressions;
+import org.apache.plc4x.codegen.ast.Generator;
+import org.apache.plc4x.codegen.ast.JavaGenerator;
+import org.apache.plc4x.codegen.ast.Primitive;
+import org.apache.plc4x.codegen.ast.TypeDefinition;
+import org.apache.plc4x.codegen.util.PojoFactory;
 import org.apache.plc4x.codegenerator.parser.imaginary.ImaginaryLexer;
 import org.apache.plc4x.codegenerator.parser.imaginary.ImaginaryParser;
 import org.apache.plc4x.plugins.codegenerator.model.ComplexType;
+import org.apache.plc4x.plugins.codegenerator.model.DiscriminatedComplexType;
 import org.apache.plc4x.plugins.codegenerator.model.Type;
+import org.apache.plc4x.plugins.codegenerator.model.fields.ArrayField;
+import org.apache.plc4x.plugins.codegenerator.model.fields.ConstField;
+import org.apache.plc4x.plugins.codegenerator.model.fields.DiscriminatorField;
+import org.apache.plc4x.plugins.codegenerator.model.fields.Field;
+import org.apache.plc4x.plugins.codegenerator.model.fields.ImplicitField;
+import org.apache.plc4x.plugins.codegenerator.model.fields.OptionalField;
+import org.apache.plc4x.plugins.codegenerator.model.fields.SimpleField;
+import org.apache.plc4x.plugins.codegenerator.model.fields.SwitchField;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 public class MessageFormatParser {
 
+    /**
+     * Turns parsed field into POJO Field.
+     * @param field
+     * @return
+     */
+    private static PojoFactory.Field fieldTranslator(Field field) {
+        if (field instanceof SimpleField) {
+            final String name = ((SimpleField) field).getName();
+            final Type type = ((SimpleField) field).getType();
+            return new PojoFactory.Field(Expressions.typeOf(type.getName()), name);
+        } else if (field instanceof ConstField) {
+            final Type type = ((ConstField) field).getType();
+            final Object value = ((ConstField) field).getReferenceValue();
+            return new PojoFactory.Field(Expressions.typeOf(type.getName()), "const_" + value);
+        } else if (field instanceof ImplicitField) {
+            final Type type = ((ImplicitField) field).getType();
+            final String expr = ((ImplicitField) field).getSerializationExpression();
+            return new PojoFactory.Field(Expressions.typeOf(type.getName()), "implicit_" + expr);
+        } else if (field instanceof OptionalField) {
+            final Type type = ((OptionalField) field).getType();
+            final String name = ((OptionalField) field).getName();
+            final String expr = ((OptionalField) field).getConditionExpression();
+            return new PojoFactory.Field(Expressions.typeOf(type.getName()), name + "?" + expr);
+        }
+        return new PojoFactory.Field(Primitive.VOID, "UNKNOWN_FIELD");
+    }
+
     public List<Type> parse(InputStream source) {
         try {
             ImaginaryLexer lexer = new ImaginaryLexer(CharStreams.fromStream(source));
@@ -45,7 +91,71 @@ public class MessageFormatParser {
             MessageFormatListener listener = new MessageFormatListener();
             walker.walk(listener, tree);
             Map<String, ComplexType> complexTypes = listener.getComplexTypes();
-            System.out.println(complexTypes);
+            // System.out.println(complexTypes);
+            // Do a Pojo for everyone
+            final PojoFactory factory = new PojoFactory();
+            final List<ClassBuilder> classes = new ArrayList<>();
+            for (Map.Entry<String, ComplexType> entry : complexTypes.entrySet()) {
+                final CodeWriter writer = new CodeWriter(4);
+                final Generator generator = new JavaGenerator(writer);
+                System.out.println("// ----------------------");
+                System.out.println("//    " + entry.getKey() + "   ");
+                System.out.println("// ----------------------");
+
+                // Old Approach
+                final ComplexType type = entry.getValue();
+                final List<PojoFactory.Field> fields = type.getFields().stream()
+                    .map(MessageFormatParser::fieldTranslator)
+                    .collect(Collectors.toList());
+                final PojoFactory.PojoDescription pojoDesc = new PojoFactory.PojoDescription(entry.getKey(), fields);
+                final ClassDeclaration classDeclaration = factory.create(pojoDesc);
+                classDeclaration.write(generator);
+                // Output POJO
+                // System.out.println(writer.getCode());
+
+                // New Approach
+                final ClassBuilder classBuilder = new ClassBuilder();
+                classes.add(classBuilder);
+
+                classBuilder.withName(entry.getKey());
+                int constCount = 1;
+                int implicitCount = 1;
+                for (Field field : type.getFields()) {
+                    if (field instanceof ArrayField) {
+                        // do nothing
+                        System.out.println("Skipping Array field...");
+                    } else if (field instanceof ConstField) {
+                        classBuilder.withConstant("CONST_" + constCount++, ((ConstField) field).getType().getName(), ((ConstField) field).getReferenceValue(), new ClassBuilder.Documentation("Constant expression"));
+                    } else if (field instanceof SimpleField) {
+                        classBuilder.withField(((SimpleField) field).getName(), ((SimpleField) field).getType().getName(), new ClassBuilder.Documentation("Simple Field..."));
+                    } else if (field instanceof ImplicitField) {
+                        classBuilder.withField("implicit" + implicitCount, ((ImplicitField) field).getType().getName(), ((ImplicitField) field).getSerializationExpression(), new ClassBuilder.Documentation("Implicitly defined field"));
+                    } else if (field instanceof DiscriminatorField) {
+                        classBuilder.withField(((DiscriminatorField) field).getName(), ((DiscriminatorField) field).getType().getName(), new ClassBuilder.Documentation("Discriminator Field..."));
+                    } else if (field instanceof SwitchField) {
+                        // Now do all "subtypes"
+                        for (DiscriminatedComplexType aCase : ((SwitchField) field).getCases()) {
+                            final ClassBuilder childBuilder = new ClassBuilder();
+                            classes.add(childBuilder);
+                            childBuilder.withName(aCase.getName());
+                            childBuilder.withParent(entry.getKey());
+
+                        }
+                    } else if (field instanceof OptionalField) {
+                        classBuilder.withField(((OptionalField) field).getName(), ((OptionalField) field).getType().getName(),
+                            new ClassBuilder.Documentation("Optional field\n" + ((OptionalField) field).getConditionExpression()));
+                    } else {
+                        throw new RuntimeException("Fields of class " + field.getClass().getSimpleName() + " are not implemented yet!");
+                    }
+                }
+
+                // System.out.println(classBuilder.toString());
+            }
+
+            // Now print all Classes
+            for (ClassBuilder aClass : classes) {
+                System.out.println(aClass.toString());
+            }
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 424d01d..e4149dc 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -39,6 +39,7 @@
     <module>dynamic-driver-knxnet-ip</module>
     <module>dynamic-driver-s7</module>
     <module>code-gen</module>
+    <module>plc4x-maven-plugin</module>
   </modules>
 
 </project>
\ No newline at end of file