You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2022/03/09 13:06:13 UTC

[plc4x] branch develop updated: fix(codegen): Ensured the codegen works when referencing subtypes

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

cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new f64f02c  fix(codegen): Ensured the codegen works when referencing subtypes
f64f02c is described below

commit f64f02c37f7cbb3041584fe3d974da748cea2a8b
Author: cdutz <ch...@c-ware.de>
AuthorDate: Wed Mar 9 14:05:27 2022 +0100

    fix(codegen): Ensured the codegen works when referencing subtypes
---
 .../BaseFreemarkerLanguageTemplateHelper.java      | 82 ------------------
 .../plc4x/language/c/CLanguageTemplateHelper.java  | 99 +++++++++++++++++++++-
 .../templates/c/complex-type-template.h.ftlh       |  4 +-
 .../resources/templates/c/data-io-template.h.ftlh  |  4 +-
 .../resources/templates/c/enum-template.c.ftlh     |  4 +-
 .../resources/templates/c/enum-template.h.ftlh     |  4 +-
 .../src/main/resources/protocols/test/test.mspec   | 34 ++++----
 7 files changed, 119 insertions(+), 112 deletions(-)

diff --git a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
index 5910c6b..f6052be 100644
--- a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
+++ b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
@@ -96,88 +96,6 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * Methods related to type-references.
      **********************************************************************************/
 
-    /**
-     * Helper for collecting referenced non simple types as these usually need to be
-     * imported in some way.
-     *
-     * @return Collection of all non simple type references used in fields or enum constants.
-     */
-    public Collection<String> getNonSimpleTypeReferences() {
-        return getNonSimpleTypeReferences(thisType);
-    }
-
-    /**
-     * Helper for collecting referenced non simple types as these usually need to be
-     * imported in some way.
-     *
-     * @param baseType the base type we want to get the type references from
-     * @return collection of non simple type references used in the type.
-     */
-    public Collection<String> getNonSimpleTypeReferences(TypeDefinition baseType) {
-        return getNonSimpleTypeReferences(baseType, new HashSet<>());
-    }
-
-    public Collection<String> getNonSimpleTypeReferences(TypeDefinition baseType, Set<String> nonSimpleTypeReferences) {
-        // We add ourselves to avoid a stackoverflow
-        nonSimpleTypeReferences.add(baseType.getName());
-        // If this is a subtype of a discriminated type, we have to add a reference to the parent type.
-        if (baseType.isDiscriminatedComplexTypeDefinition()) {
-            DiscriminatedComplexTypeDefinition discriminatedComplexTypeDefinition = baseType.asDiscriminatedComplexTypeDefinition().orElseThrow();
-            if (!discriminatedComplexTypeDefinition.isAbstract()) {
-                String typeReferenceName = discriminatedComplexTypeDefinition.getParentType().orElseThrow().getName();
-                nonSimpleTypeReferences.add(typeReferenceName);
-            }
-        }
-        // If it's a complex type definition, add all the types referenced by any property fields
-        // (Includes any types referenced by sub-types in case this is a discriminated type parent)
-        if (baseType.isComplexTypeDefinition()) {
-            ComplexTypeDefinition complexTypeDefinition = baseType.asComplexTypeDefinition().orElseThrow();
-            for (Field field : complexTypeDefinition.getFields()) {
-                if (field.isPropertyField()) {
-                    PropertyField propertyField = field.asPropertyField().orElseThrow();
-                    TypeReference typeReference = propertyField.getType();
-                    if (typeReference.isArrayTypeReference()) {
-                        typeReference = typeReference.asArrayTypeReference().orElseThrow().getElementTypeReference();
-                    }
-                    if (typeReference.isNonSimpleTypeReference()) {
-                        NonSimpleTypeReference nonSimpleTypeReference = typeReference.asNonSimpleTypeReference().orElseThrow();
-                        nonSimpleTypeReferences.add(nonSimpleTypeReference.getName());
-                    }
-                } else if (field.isSwitchField()) {
-                    SwitchField switchField = field.asSwitchField().orElseThrow();
-                    for (DiscriminatedComplexTypeDefinition switchCase : switchField.getCases()) {
-                        if (nonSimpleTypeReferences.contains(switchCase.getName())) {
-                            continue;
-                        }
-                        nonSimpleTypeReferences.addAll(getNonSimpleTypeReferences(switchCase, nonSimpleTypeReferences));
-                    }
-                }
-            }
-        } else if (baseType.isEnumTypeDefinition()) {// In case this is an enum type, we have to check all the constant types.
-            EnumTypeDefinition enumTypeDefinition = baseType.asEnumTypeDefinition().orElseThrow();
-            for (String constantName : enumTypeDefinition.getConstantNames()) {
-                final TypeReference constantType = enumTypeDefinition.getConstantType(constantName);
-                if (constantType.isNonSimpleTypeReference()) {
-                    NonSimpleTypeReference nonSimpleTypeReference = constantType.asNonSimpleTypeReference().orElseThrow();
-                    nonSimpleTypeReferences.add(nonSimpleTypeReference.getName());
-                }
-            }
-        }
-        // If the type has any parser arguments, these have to be checked too.
-        baseType.getParserArguments().ifPresent(arguments -> arguments.stream()
-            .map(Argument::getType)
-            .map(TypeReferenceConversions::asNonSimpleTypeReference)
-            .filter(Optional::isPresent)
-            .map(Optional::get)
-            .map(NonSimpleTypeReference::getName)
-            .forEach(nonSimpleTypeReferences::add)
-        );
-
-        // We remove ourselves to avoid a stackoverflow
-        nonSimpleTypeReferences.remove(baseType.getName());
-        return nonSimpleTypeReferences;
-    }
-
     protected EnumTypeDefinition getEnumTypeDefinition(TypeReference typeReference) {
         NonSimpleTypeReference nonSimpleTypeReference = typeReference.asNonSimpleTypeReference().orElseThrow(
             () -> new FreemarkerException("type reference for enum types must be of type non simple type"));
diff --git a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
index 45eb9be..45e68fc 100644
--- a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
+++ b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
@@ -118,11 +118,20 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         if (field.asArrayField().map(ArrayField::getLoopExpression).map(Term::isFixedValueExpression).orElse(false)) {
             return "plc4c_list";
         }
-        TypedField typedField = field.asTypedField().orElseThrow(IllegalStateException::new);
+        TypedField typedField = field.asTypedField().orElseThrow();
         TypeReference typeReference = typedField.getType();
-        if (typeReference.isNonSimpleTypeReference()) {
-            if (typeReference.asNonSimpleTypeReference().orElseThrow().getTypeDefinition() instanceof DataIoTypeDefinition) {
-                return "plc4c_data*";
+        if (typeReference.isDataIoTypeReference()) {
+            return "plc4c_data*";
+        }
+        // If we reference a complex type subtype, we need to return a reference
+        // to the parent as in C the subtypes don't actually exist.
+        if (typeReference.isComplexTypeReference()) {
+            final ComplexTypeReference complexTypeReference = typeReference.asComplexTypeReference().orElseThrow();
+            if (complexTypeReference.getTypeDefinition().isDiscriminatedChildTypeDefinition()) {
+                final DiscriminatedComplexTypeDefinition discriminatedComplexTypeDefinition = complexTypeReference.getTypeDefinition().asDiscriminatedComplexTypeDefinition().orElseThrow();
+                if(discriminatedComplexTypeDefinition.getParentType().isPresent()) {
+                    return getCTypeName(discriminatedComplexTypeDefinition.getParentType().orElseThrow().asComplexTypeDefinition().orElseThrow().getName());
+                }
             }
         }
         return getLanguageTypeNameForTypeReference(typeReference);
@@ -1209,4 +1218,86 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         return getCTypeName(enumName) + "_" + enumConstant;
     }
 
+    /**
+     * Helper for collecting referenced non simple types as these usually need to be
+     * imported in some way.
+     *
+     * @return Collection of all non simple type references used in fields or enum constants.
+     */
+    public Collection<String> getTypeNamesForImportStatements() {
+        return getTypeNamesForImportStatements(thisType);
+    }
+
+    /**
+     * Helper for collecting referenced non simple types as these usually need to be
+     * imported in some way.
+     *
+     * @param baseType the base type we want to get the type references from
+     * @return collection of non simple type references used in the type.
+     */
+    public Collection<String> getTypeNamesForImportStatements(TypeDefinition baseType) {
+        return getTypeNamesForImportStatements(baseType, new HashSet<>());
+    }
+
+    public Collection<String> getTypeNamesForImportStatements(TypeDefinition baseType, Set<String> nonSimpleTypeReferences) {
+        // We add ourselves to avoid a stackoverflow
+        nonSimpleTypeReferences.add(baseType.getName());
+        // If it's a complex type definition, add all the types referenced by any property fields
+        // (Includes any types referenced by subtypes in case this is a discriminated type parent)
+        if (baseType.isComplexTypeDefinition()) {
+            ComplexTypeDefinition complexTypeDefinition = baseType.asComplexTypeDefinition().orElseThrow();
+            for (Field field : complexTypeDefinition.getFields()) {
+                if (field.isPropertyField()) {
+                    PropertyField propertyField = field.asPropertyField().orElseThrow();
+                    TypeReference typeReference = propertyField.getType();
+                    if (typeReference.isArrayTypeReference()) {
+                        typeReference = typeReference.asArrayTypeReference().orElseThrow().getElementTypeReference();
+                    }
+                    if (typeReference.isNonSimpleTypeReference()) {
+                        NonSimpleTypeReference nonSimpleTypeReference = typeReference.asNonSimpleTypeReference().orElseThrow();
+                        if(nonSimpleTypeReference.getTypeDefinition().isDiscriminatedComplexTypeDefinition()) {
+                            final Optional<DiscriminatedComplexTypeDefinition> discriminatedComplexTypeDefinition = nonSimpleTypeReference.getTypeDefinition().asDiscriminatedComplexTypeDefinition();
+                            if(discriminatedComplexTypeDefinition.orElseThrow().isDiscriminatedChildTypeDefinition()) {
+                                final ComplexTypeDefinition complexTypeDefinition1 = discriminatedComplexTypeDefinition.orElseThrow().getParentType().orElseThrow();
+                                nonSimpleTypeReferences.add(complexTypeDefinition1.getName());
+                            }
+                        } else {
+                            nonSimpleTypeReferences.add(nonSimpleTypeReference.getTypeDefinition().getName());
+                        }
+                    }
+                } else if (field.isSwitchField()) {
+                    SwitchField switchField = field.asSwitchField().orElseThrow();
+                    for (DiscriminatedComplexTypeDefinition switchCase : switchField.getCases()) {
+                        if (nonSimpleTypeReferences.contains(switchCase.getName())) {
+                            continue;
+                        }
+                        nonSimpleTypeReferences.addAll(getTypeNamesForImportStatements(switchCase, nonSimpleTypeReferences));
+                    }
+                }
+            }
+        } else if (baseType.isEnumTypeDefinition()) {// In case this is an enum type, we have to check all the constant types.
+            EnumTypeDefinition enumTypeDefinition = baseType.asEnumTypeDefinition().orElseThrow();
+            for (String constantName : enumTypeDefinition.getConstantNames()) {
+                final TypeReference constantType = enumTypeDefinition.getConstantType(constantName);
+                if (constantType.isNonSimpleTypeReference()) {
+                    NonSimpleTypeReference nonSimpleTypeReference = constantType.asNonSimpleTypeReference().orElseThrow();
+                    nonSimpleTypeReferences.add(nonSimpleTypeReference.getName());
+                }
+            }
+        }
+        // If the type has any parser arguments, these have to be checked too.
+        baseType.getParserArguments().ifPresent(arguments -> arguments.stream()
+            .map(Argument::getType)
+            .map(TypeReferenceConversions::asNonSimpleTypeReference)
+            .filter(Optional::isPresent)
+            .map(Optional::get)
+            .map(NonSimpleTypeReference::getName)
+            .forEach(nonSimpleTypeReferences::add)
+        );
+
+        // We remove ourselves to avoid a stackoverflow
+        nonSimpleTypeReferences.remove(baseType.getName());
+        return nonSimpleTypeReferences;
+    }
+
 }
diff --git a/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh b/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh
index c1a65af..eb80a73 100644
--- a/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh
@@ -59,8 +59,8 @@
 <#--
     Add any import statements for partent-types, complex types used in properties or parser arguments.
 -->
-<#if helper.getNonSimpleTypeReferences()?has_content>
-    <#list helper.getNonSimpleTypeReferences() as typeReference>
+<#if helper.getTypeNamesForImportStatements()?has_content>
+    <#list helper.getTypeNamesForImportStatements() as typeReference>
 #include "${helper.camelCaseToSnakeCase(typeReference)}.h"
     </#list>
 </#if>
diff --git a/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh b/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh
index 687a312..75ddd0b 100644
--- a/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh
@@ -58,8 +58,8 @@ ${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase
 <#--
     Add any import statements for partent-types, complex types used in properties or parser arguments.
 -->
-<#if helper.getNonSimpleTypeReferences()?has_content>
-    <#list helper.getNonSimpleTypeReferences() as typeReference>
+<#if helper.getTypeNamesForImportStatements()?has_content>
+    <#list helper.getTypeNamesForImportStatements() as typeReference>
 #include "${helper.camelCaseToSnakeCase(typeReference)}.h"
     </#list>
 </#if>
diff --git a/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh b/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh
index 62ba4e2..ea2e347 100644
--- a/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh
@@ -48,8 +48,8 @@ ${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(t
 <#--
     Add any import statements for partent-types, complex types used in properties or parser arguments.
 -->
-<#if helper.getNonSimpleTypeReferences()?has_content>
-    <#list helper.getNonSimpleTypeReferences() as typeReference>
+<#if helper.getTypeNamesForImportStatements()?has_content>
+    <#list helper.getTypeNamesForImportStatements() as typeReference>
 #include "${helper.camelCaseToSnakeCase(typeReference)}.h"
     </#list>
 </#if>
diff --git a/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh b/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh
index b3d6e66..da8f7a3 100644
--- a/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh
@@ -53,8 +53,8 @@ ${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase
 <#--
     Add any import statements for partent-types, complex types used in properties or parser arguments.
 -->
-<#if helper.getNonSimpleTypeReferences()?has_content>
-    <#list helper.getNonSimpleTypeReferences() as typeReference>
+<#if helper.getTypeNamesForImportStatements()?has_content>
+    <#list helper.getTypeNamesForImportStatements() as typeReference>
 #include "${helper.camelCaseToSnakeCase(typeReference)}.h"
     </#list>
 </#if>
diff --git a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
index 010c02c..1f2c2c4 100644
--- a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
+++ b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
@@ -336,25 +336,23 @@
 
 
 //Test to check if we can include concrete types as fields. Doesn't work in any language at the moment.
-// TODO: Check why this is commented out
-//[discriminatedType SimpleDiscriminatedType
-//    [discriminator uint 8 discr]
-//    [typeSwitch discr
-//        ['0x00' SimpleDiscriminatedTypeA
-//            [simple        AnotherSimpleDiscriminatedTypeA simpA]
-//        ]
-//    ]
-//]
+[discriminatedType SimpleDiscriminatedType
+    [discriminator uint 8 discr]
+    [typeSwitch discr
+        ['0x00' SimpleDiscriminatedTypeA
+            [simple        AnotherSimpleDiscriminatedTypeA simpA]
+        ]
+    ]
+]
 
-// TODO: Check why this is commented out
-//[discriminatedType AnotherSimpleDiscriminatedType
-//    [discriminator uint 8 discr]
-//    [typeSwitch discr
-//        ['0x00' AnotherSimpleDiscriminatedTypeA
-//            [simple        uint 8 simpA]
-//        ]
-//    ]
-//]
+[discriminatedType AnotherSimpleDiscriminatedType
+    [discriminator uint 8 discr]
+    [typeSwitch discr
+        ['0x00' AnotherSimpleDiscriminatedTypeA
+            [simple        uint 8 simpA]
+        ]
+    ]
+]
 
 ////////////////////////////////////////////////////////////////
 // Enumerated Type Tests