You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/09/27 20:24:55 UTC

[plc4x] branch develop updated: refactor(code-gen): cleanup interfaces

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

sruehl 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 8499434  refactor(code-gen): cleanup interfaces
8499434 is described below

commit 84994340c026bb865a980004ba0ffe0d28c1add4
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Mon Sep 27 22:21:41 2021 +0200

    refactor(code-gen): cleanup interfaces
    
    + deprecated a bunch of functions on the *Helper classes which can now be called on the objects directly
    + moved code to the FreemarkerLanguageTemplateHelper
    + Adapted templates to the changed generator API: no more random nulls. Use Optional where values can be optional.
    + Use convenience cast methods in templates
    + Tracer now properly checks for true
    + Tracer now can un-trace expressions in case they are used in maps
    + Added defautlt methods to interfaces to navigate in an OOP manner
    + Added Optionals where values are optional
    + Added null check contraints
    + much more...
---
 .../BaseFreemarkerLanguageTemplateHelper.java      | 799 +++++++++++----------
 .../FreemarkerLanguageTemplateHelper.java          |  18 +
 .../codegenerator/protocol/freemarker/Tracer.java  |  15 +-
 .../plc4x/language/c/CLanguageTemplateHelper.java  | 279 +++----
 .../resources/templates/c/data-io-template.c.ftlh  | 136 ++--
 .../resources/templates/c/data-io-template.h.ftlh  |   9 +-
 .../resources/templates/c/enum-template.c.ftlh     |  15 +-
 .../resources/templates/c/enum-template.h.ftlh     |   3 +
 .../resources/templates/c/pojo-template.c.ftlh     | 199 ++---
 .../resources/templates/c/pojo-template.h.ftlh     |  21 +-
 .../language/go/GoLanguageTemplateHelper.java      | 301 ++++----
 .../templates/go/data-io-template.go.ftlh          | 103 ++-
 .../resources/templates/go/enum-template.go.ftlh   |  11 +-
 .../resources/templates/go/model-template.go.ftlh  | 453 ++++++------
 .../templates/go/parser-factory-template.go.ftlh   |  23 +-
 .../go/xml-parser-factory-template.go.ftlh         |  25 +-
 .../language/java/JavaLanguageTemplateHelper.java  | 104 +--
 .../templates/java/data-io-template.java.ftlh      | 218 +++---
 .../templates/java/enum-template.java.ftlh         |   2 +-
 .../resources/templates/java/io-template.java.ftlh | 409 +++++------
 .../templates/java/pojo-template.java.ftlh         |  71 +-
 .../mspec/expression/ExpressionStringListener.java |  51 +-
 .../definitions/DefaultComplexTypeDefinition.java  |   5 +-
 .../definitions/DefaultDataIoTypeDefinition.java   |  16 +-
 .../DefaultDiscriminatedComplexTypeDefinition.java |   9 +-
 .../definitions/DefaultEnumTypeDefinition.java     |  19 +-
 .../mspec/model/definitions/DefaultEnumValue.java  |  13 +-
 .../model/definitions/DefaultTypeDefinition.java   |  24 +-
 .../mspec/model/fields/DefaultAbstractField.java   |  16 +-
 .../mspec/model/fields/DefaultArrayField.java      |  20 +-
 .../mspec/model/fields/DefaultAssertField.java     |  19 +-
 .../mspec/model/fields/DefaultChecksumField.java   |  17 +-
 .../mspec/model/fields/DefaultConstField.java      |  17 +-
 .../model/fields/DefaultDiscriminatorField.java    |  15 +-
 .../mspec/model/fields/DefaultEnumField.java       |  21 +-
 .../language/mspec/model/fields/DefaultField.java  |   6 +-
 .../mspec/model/fields/DefaultImplicitField.java   |  17 +-
 .../model/fields/DefaultManualArrayField.java      |  27 +-
 .../mspec/model/fields/DefaultManualField.java     |  22 +-
 .../mspec/model/fields/DefaultOptionalField.java   |  18 +-
 .../mspec/model/fields/DefaultPaddingField.java    |  20 +-
 .../mspec/model/fields/DefaultReservedField.java   |  15 +-
 .../mspec/model/fields/DefaultSimpleField.java     |  16 +-
 .../mspec/model/fields/DefaultSwitchField.java     |  17 +-
 .../mspec/model/fields/DefaultTaggedField.java     |  12 +-
 .../mspec/model/fields/DefaultUnknownField.java    |  13 +-
 .../mspec/model/fields/DefaultVirtualField.java    |  17 +-
 .../language/mspec/model/fields/TryField.java      |  28 -
 .../mspec/parser/MessageFormatListener.java        | 103 +--
 .../expression/ExpressionStringParserTest.java     |   9 +-
 .../mspec/parser/MessageFormatParserTest.java      |   5 +
 .../src/test/resources/mspec.example2              | 449 ++++++++++++
 .../generated-sources/modbus/include/modbus_pdu.h  |   1 -
 plc4c/generated-sources/modbus/src/modbus_pdu.c    | 138 ++--
 plc4c/generated-sources/s7/include/cotp_packet.h   |   1 -
 .../generated-sources/s7/include/cotp_parameter.h  |   1 -
 plc4c/generated-sources/s7/include/s7_address.h    |   1 -
 .../s7/include/s7_data_alarm_message.h             |   3 +-
 plc4c/generated-sources/s7/include/s7_message.h    |   1 -
 plc4c/generated-sources/s7/include/s7_parameter.h  |   1 -
 .../s7/include/s7_parameter_user_data_item.h       |   1 -
 plc4c/generated-sources/s7/include/s7_payload.h    |   1 -
 .../s7/include/s7_payload_user_data_item.h         |   7 +-
 .../s7/include/s7_var_request_parameter_item.h     |   1 -
 .../generated-sources/s7/include/transport_size.h  |   1 -
 plc4c/generated-sources/s7/src/cotp_packet.c       |  18 +-
 plc4c/generated-sources/s7/src/cotp_parameter.c    |  12 +-
 plc4c/generated-sources/s7/src/s7_address.c        |   2 +-
 .../s7/src/s7_data_alarm_message.c                 |  12 +-
 plc4c/generated-sources/s7/src/s7_message.c        |  10 +-
 plc4c/generated-sources/s7/src/s7_parameter.c      |  20 +-
 .../s7/src/s7_parameter_user_data_item.c           |   2 +-
 plc4c/generated-sources/s7/src/s7_payload.c        |  14 +-
 .../s7/src/s7_payload_user_data_item.c             |  80 +--
 .../s7/src/s7_var_request_parameter_item.c         |   2 +-
 plc4c/generated-sources/s7/src/transport_size.c    |   1 -
 plc4c/spi/src/system.c                             |   2 +-
 77 files changed, 2624 insertions(+), 1979 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 bca0e61..a274ed9 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
@@ -27,14 +27,15 @@ import org.apache.plc4x.plugins.codegenerator.types.references.*;
 import org.apache.plc4x.plugins.codegenerator.types.terms.*;
 
 import java.util.*;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 public abstract class BaseFreemarkerLanguageTemplateHelper implements FreemarkerLanguageTemplateHelper {
 
-    private final TypeDefinition thisType;
-    private final String protocolName;
-    private final String flavorName;
-    private final Map<String, TypeDefinition> types;
+    protected final TypeDefinition thisType;
+    protected final String protocolName;
+    protected final String flavorName;
+    protected final Map<String, TypeDefinition> types;
 
     // In mspec we are using some virtual virtual fields that are useful for code generation.
     // As they should be shared over all language template implementations,
@@ -92,10 +93,6 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         this.types = types;
     }
 
-    protected TypeDefinition getThisTypeDefinition() {
-        return thisType;
-    }
-
     public String getProtocolName() {
         return protocolName;
     }
@@ -109,8 +106,10 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     }
 
     public List<TypeDefinition> getComplexTypeRootDefinitions() {
-        return types.values().stream().filter(typeDefinition -> (typeDefinition instanceof ComplexTypeDefinition) &&
-            !(typeDefinition instanceof DiscriminatedComplexTypeDefinition)).collect(Collectors.toList());
+        return types.values().stream()
+            .filter(ComplexTypeDefinition.class::isInstance)
+            .filter(typeDefinition -> !(typeDefinition instanceof DiscriminatedComplexTypeDefinition))
+            .collect(Collectors.toList());
     }
 
     protected static Map<String, SimpleTypeReference> getBuiltInFieldTypes() {
@@ -118,52 +117,46 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     }
 
     /* *********************************************************************************
-     * Methods that are language-dependent.
-     **********************************************************************************/
-
-    public abstract String getLanguageTypeNameForField(Field field);
-
-    public abstract String getLanguageTypeNameForTypeReference(TypeReference typeReference);
-
-    public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference) {
-        return getReadBufferReadMethodCall(simpleTypeReference, null, null);
-    }
-
-    public abstract String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString, TypedField field);
-
-    public abstract String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName, TypedField field);
-
-    public abstract String getNullValueForTypeReference(TypeReference typeReference);
-
-    /* *********************************************************************************
      * Methods related to type-references.
      **********************************************************************************/
 
     /**
      * @param typeReference type reference
      * @return true if the given type reference is a simple type reference.
+     * @deprecated use method of {@link TypeReference}
      */
+    @Deprecated
     public boolean isSimpleTypeReference(TypeReference typeReference) {
-        return typeReference instanceof SimpleTypeReference;
+        if (typeReference == null) {
+            return false;
+        }
+        return typeReference.isSimpleTypeReference();
     }
 
     /**
      * @param typeReference type reference
      * @return true if the given type reference is a byte based type reference.
+     * @deprecated use method of {@link TypeReference}
      */
+    @Deprecated
     public boolean isByteBased(TypeReference typeReference) {
-        if (!isSimpleTypeReference(typeReference)) {
+        if (typeReference == null) {
             return false;
         }
-        return ((SimpleTypeReference) typeReference).getBaseType() == SimpleTypeReference.SimpleBaseType.BYTE;
+        return typeReference.isByteBased();
     }
 
     /**
      * @param typeReference type reference
      * @return true if the given type reference is a complex type reference.
+     * @deprecated use method of {@link TypeReference}
      */
+    @Deprecated
     public boolean isComplexTypeReference(TypeReference typeReference) {
-        return typeReference instanceof ComplexTypeReference;
+        if (typeReference == null) {
+            return false;
+        }
+        return typeReference.isComplexTypeReference();
     }
 
     public boolean isEnumTypeReference(TypeReference typeReference) {
@@ -173,8 +166,15 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return getTypeDefinitionForTypeReference(typeReference) instanceof EnumTypeDefinition;
     }
 
+    /**
+     * @deprecated use method of {@link TypeReference}
+     */
+    @Deprecated
     public boolean isStringTypeReference(TypeReference typeReference) {
-        return typeReference instanceof StringTypeReference;
+        if (typeReference == null) {
+            return false;
+        }
+        return typeReference.isStringTypeReference();
     }
 
     /**
@@ -231,8 +231,9 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
                 }
             }
         } else if (baseType instanceof EnumTypeDefinition) {// In case this is an enum type, we have to check all the constant types.
-            for (String constantName : ((EnumTypeDefinition) baseType).getConstantNames()) {
-                final TypeReference constantType = ((EnumTypeDefinition) thisType).getConstantType(constantName);
+            EnumTypeDefinition enumTypeDefinition = (EnumTypeDefinition) baseType;
+            for (String constantName : enumTypeDefinition.getConstantNames()) {
+                final TypeReference constantType = enumTypeDefinition.getConstantType(constantName);
                 if (constantType instanceof ComplexTypeReference) {
                     ComplexTypeReference complexTypeReference = (ComplexTypeReference) constantType;
                     complexTypeReferences.add(complexTypeReference.getName());
@@ -240,14 +241,14 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             }
         }
         // If the type has any parser arguments, these have to be checked too.
-        if (baseType.getParserArguments() != null) {
-            for (Argument parserArgument : baseType.getParserArguments()) {
-                if (parserArgument.getType() instanceof ComplexTypeReference) {
-                    ComplexTypeReference complexTypeReference = (ComplexTypeReference) parserArgument.getType();
-                    complexTypeReferences.add(complexTypeReference.getName());
-                }
-            }
-        }
+        baseType.getParserArguments().ifPresent(arguments -> arguments.stream()
+            .map(Argument::getType)
+            .map(TypeReferenceConversions::asComplexTypeReference)
+            .filter(Optional::isPresent)
+            .map(Optional::get)
+            .map(ComplexTypeReference::getName)
+            .forEach(complexTypeReferences::add)
+        );
 
         // We remove ourselves to avoid a stackoverflow
         complexTypeReferences.remove(baseType.getName());
@@ -255,7 +256,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     }
 
     /**
-     * Little helper to return the type of a given property.
+     * Little helper to return the {@link TypeReference} of a given property.
      *
      * @param baseType     base type definition that contains the given property.
      * @param propertyName name of the property
@@ -271,8 +272,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             .filter(propertyField -> propertyField.getName().equals(propertyName))
             .findFirst();
         if (propertyFieldOptional.isPresent()) {
-            final PropertyField propertyField = propertyFieldOptional.get();
-            return Optional.of(propertyField.getType());
+            return propertyFieldOptional.map(PropertyField::getType);
         }
         // Check if the expression is a ImplicitField
         final Optional<ImplicitField> implicitFieldOptional = baseType.getFields().stream()
@@ -281,8 +281,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             .filter(implicitField -> implicitField.getName().equals(propertyName))
             .findFirst();
         if (implicitFieldOptional.isPresent()) {
-            final ImplicitField implicitField = implicitFieldOptional.get();
-            return Optional.of(implicitField.getType());
+            return implicitFieldOptional.map(ImplicitField::getType);
         }
         // Check if the expression is a VirtualField
         final Optional<VirtualField> virtualFieldOptional = baseType.getFields().stream()
@@ -291,18 +290,16 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             .filter(virtualField -> virtualField.getName().equals(propertyName))
             .findFirst();
         if (virtualFieldOptional.isPresent()) {
-            final VirtualField virtualField = virtualFieldOptional.get();
-            return Optional.of(virtualField.getType());
+            return virtualFieldOptional.map(VirtualField::getType);
         }
         // Check if the expression root is referencing an argument
-        if (baseType.getParserArguments() != null) {
-            final Optional<Argument> argumentOptional = Arrays.stream(baseType.getParserArguments())
-                .filter(argument -> argument.getName().equals(propertyName))
-                .findFirst();
-            if (argumentOptional.isPresent()) {
-                final Argument argument = argumentOptional.get();
-                return Optional.of(argument.getType());
-            }
+        final Optional<Argument> argumentOptional = baseType.getParserArguments()
+            .orElse(Collections.emptyList())
+            .stream()
+            .filter(argument -> argument.getName().equals(propertyName))
+            .findFirst();
+        if (argumentOptional.isPresent()) {
+            return argumentOptional.map(Argument::getType);
         }
         // Check if the expression is a DiscriminatorField
         // This is a more theoretical case where the expression is referencing a discriminator value of the current type
@@ -312,8 +309,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             .filter(discriminatorField -> discriminatorField.getName().equals(propertyName))
             .findFirst();
         if (discriminatorFieldOptional.isPresent()) {
-            final DiscriminatorField discriminatorField = discriminatorFieldOptional.get();
-            return Optional.of(discriminatorField.getType());
+            return discriminatorFieldOptional.map(DiscriminatorField::getType);
         }
         return Optional.empty();
     }
@@ -346,8 +342,10 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      **********************************************************************************/
 
     public boolean hasFieldOfType(String fieldTypeName) {
-        if (getThisTypeDefinition() instanceof ComplexTypeDefinition) {
-            return ((ComplexTypeDefinition) getThisTypeDefinition()).getFields().stream().anyMatch(field -> field.getTypeName().equals(fieldTypeName));
+        if (thisType instanceof ComplexTypeDefinition) {
+            ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) this.thisType;
+            return complexTypeDefinition.getFields().stream()
+                .anyMatch(field -> field.getTypeName().equals(fieldTypeName));
         }
         return false;
     }
@@ -369,56 +367,86 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return true;
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public Field getFieldForNameFromCurrentOrParent(String fieldName) {
-        if (!(getThisTypeDefinition() instanceof ComplexTypeDefinition)) {
+        if (!(thisType instanceof ComplexTypeDefinition)) {
             return null;
         }
-        return getAllPropertyFields((ComplexTypeDefinition) getThisTypeDefinition(), fieldName);
-    }
-
-    public PropertyField getAllPropertyFields(ComplexTypeDefinition complexTypeDefinition, String fieldName) {
-        return complexTypeDefinition.getAllPropertyFields()
-            .stream()
-            .filter(propertyField -> propertyField.getName().equals(fieldName))
-            .findFirst()
-            .orElse(null);
+        ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) this.thisType;
+        return complexTypeDefinition.getPropertyFieldFromThisOrParentByName(fieldName).orElse(null);
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public Field getFieldForNameFromCurrent(String fieldName) {
-        if (!(getThisTypeDefinition() instanceof ComplexTypeDefinition)) {
+        if (!(thisType instanceof ComplexTypeDefinition)) {
             return null;
         }
-        return getPropertyField((ComplexTypeDefinition) getThisTypeDefinition(), fieldName);
-    }
-
-    public PropertyField getPropertyField(ComplexTypeDefinition complexTypeDefinition, String fieldName) {
-        return complexTypeDefinition.getPropertyFields()
-            .stream()
-            .filter(propertyField -> propertyField.getName().equals(fieldName))
-            .findFirst()
-            .orElse(null);
+        ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) this.thisType;
+        return complexTypeDefinition.getPropertyFieldByName(fieldName).orElse(null);
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isAbstractField(Field field) {
-        return field instanceof AbstractField;
+        if (field == null) {
+            return false;
+        }
+        return field.isAbstractField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isArrayField(Field field) {
-        return field instanceof ArrayField;
+        if (field == null) {
+            return false;
+        }
+        return field.isArrayField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isChecksumField(Field field) {
-        return field instanceof ChecksumField;
+        if (field == null) {
+            return false;
+        }
+        return field.isChecksumField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isConstField(Field field) {
-        return field instanceof ConstField;
+        if (field == null) {
+            return false;
+        }
+        return field.isConstField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isDiscriminatorField(Field field) {
-        return field instanceof DiscriminatorField;
+        if (field == null) {
+            return false;
+        }
+        return field.isDiscriminatorField();
     }
 
+    // TODO: check or describe why a instanceOf EnumField is not sufficient here
     public boolean isEnumField(Field field) {
         if (!(field instanceof TypedField)) {
             return false;
@@ -432,164 +460,248 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return typeDefinition instanceof EnumTypeDefinition;
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isImplicitField(Field field) {
-        return field instanceof ImplicitField;
+        if (field == null) {
+            return false;
+        }
+        return field.isImplicitField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isManualArrayField(Field field) {
-        return field instanceof ManualArrayField;
+        if (field == null) {
+            return false;
+        }
+        return field.isManualArrayField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isNamedField(Field field) {
-        return field instanceof NamedField;
+        if (field == null) {
+            return false;
+        }
+        return field.isNamedField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isOptionalField(Field field) {
-        return field instanceof OptionalField;
+        if (field == null) {
+            return false;
+        }
+        return field.isOptionalField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isPaddingField(Field field) {
-        return field instanceof PaddingField;
+        if (field == null) {
+            return false;
+        }
+        return field.isPaddingField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isPropertyField(Field field) {
-        return field instanceof PropertyField;
+        if (field == null) {
+            return false;
+        }
+        return field.isPropertyField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isReservedField(Field field) {
-        return field instanceof ReservedField;
+        if (field == null) {
+            return false;
+        }
+        return field.isReservedField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isSimpleField(Field field) {
-        return field instanceof SimpleField;
+        if (field == null) {
+            return false;
+        }
+        return field.isSimpleField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isSwitchField(Field field) {
-        return field instanceof SwitchField;
+        if (field == null) {
+            return false;
+        }
+        return field.isSwitchField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isTypedField(Field field) {
-        return field instanceof TypedField;
+        if (field == null) {
+            return false;
+        }
+        return field.isTypedField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isVirtualField(Field field) {
-        return field instanceof VirtualField;
+        if (field == null) {
+            return false;
+        }
+        return field.isVirtualField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isCountArrayField(Field field) {
-        if (field instanceof ArrayField) {
-            ArrayField arrayField = (ArrayField) field;
-            return arrayField.getLoopType() == ArrayField.LoopType.COUNT;
-        }
-        if (field instanceof ManualArrayField) {
-            ManualArrayField arrayField = (ManualArrayField) field;
-            return arrayField.getLoopType() == ManualArrayField.LoopType.COUNT;
+        if (field == null) {
+            return false;
         }
-        return false;
+        return field.isCountArrayField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isLengthArrayField(Field field) {
-        if (field instanceof ArrayField) {
-            ArrayField arrayField = (ArrayField) field;
-            return arrayField.getLoopType() == ArrayField.LoopType.LENGTH;
-        }
-        if (field instanceof ManualArrayField) {
-            ManualArrayField arrayField = (ManualArrayField) field;
-            return arrayField.getLoopType() == ManualArrayField.LoopType.LENGTH;
+        if (field == null) {
+            return false;
         }
-        return false;
+        return field.isLengthArrayField();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isTerminatedArrayField(Field field) {
-        if (field instanceof ArrayField) {
-            ArrayField arrayField = (ArrayField) field;
-            return arrayField.getLoopType() == ArrayField.LoopType.TERMINATED;
-        }
-        if (field instanceof ManualArrayField) {
-            ManualArrayField arrayField = (ManualArrayField) field;
-            return arrayField.getLoopType() == ManualArrayField.LoopType.TERMINATED;
+        if (field == null) {
+            return false;
         }
-        return false;
+        return field.isTerminatedArrayField();
     }
 
     /**
-     * @return switch field of the current base type.
+     * @deprecated use field method.
      */
+    @Deprecated
     public SwitchField getSwitchField() {
-        return getSwitchField(thisType);
-    }
-
-    /**
-     * @return switch field of the provided base type.
-     */
-    protected SwitchField getSwitchField(TypeDefinition typeDefinition) {
-        if (!(typeDefinition instanceof ComplexTypeDefinition)) {
+        if (!(thisType instanceof ComplexTypeDefinition)) {
             return null;
         }
-        ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) typeDefinition;
-        // Sebastian would be proud of me ;-)
-        return (SwitchField) complexTypeDefinition.getFields().stream()
-            .filter(SwitchField.class::isInstance)
-            .findFirst()
-            .orElse(null);
+        ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) this.thisType;
+        return complexTypeDefinition.getSwitchField().orElse(null);
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public Collection<Field> getPropertyAndSwitchFields() {
-        return getPropertyAndSwitchFields(thisType);
-    }
-
-    public Collection<Field> getPropertyAndSwitchFields(TypeDefinition typeDefinition) {
         if (!(thisType instanceof ComplexTypeDefinition)) {
             return Collections.emptyList();
         }
-        return ((ComplexTypeDefinition) thisType).getFields().stream()
-            .filter(field -> (field instanceof PropertyField) || (field instanceof SwitchField))
-            .collect(Collectors.toList());
+        return ((ComplexTypeDefinition) thisType).getPropertyAndSwitchFields();
     }
 
     /* *********************************************************************************
      * Methods related to type-definitions.
      **********************************************************************************/
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isDiscriminatedParentTypeDefinition() {
-        return isDiscriminatedParentTypeDefinition(thisType);
+        if (thisType == null) {
+            return false;
+        }
+        return thisType.isDiscriminatedParentTypeDefinition();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isDiscriminatedParentTypeDefinition(TypeDefinition typeDefinition) {
-        return (typeDefinition instanceof ComplexTypeDefinition) && ((ComplexTypeDefinition) typeDefinition).isAbstract();
+        if (typeDefinition == null) {
+            return false;
+        }
+        return typeDefinition.isDiscriminatedParentTypeDefinition();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isDiscriminatedChildTypeDefinition() {
-        return isDiscriminatedChildTypeDefinition(thisType);
+        if (thisType == null) {
+            return false;
+        }
+        return thisType.isDiscriminatedChildTypeDefinition();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public boolean isDiscriminatedChildTypeDefinition(TypeDefinition typeDefinition) {
-        return (typeDefinition instanceof DiscriminatedComplexTypeDefinition) && !((ComplexTypeDefinition) typeDefinition).isAbstract();
+        if (typeDefinition == null) {
+            return false;
+        }
+        return typeDefinition.isDiscriminatedChildTypeDefinition();
     }
 
     public TypeDefinition getTypeDefinitionForTypeReference(TypeReference typeReference) {
         if (!isComplexTypeReference(typeReference)) {
             throw new FreemarkerException("Type reference must be a complex type reference");
         }
-        return getTypeDefinitions().get(((ComplexTypeReference) typeReference).getName());
+        ComplexTypeReference complexTypeReference = (ComplexTypeReference) typeReference;
+        return getTypeDefinitions().get(complexTypeReference.getName());
     }
 
     /**
-     * @return list of sub-types for the current base type or an empty collection, if there are none
+     * @deprecated use field method.
      */
+    @Deprecated
     public List<DiscriminatedComplexTypeDefinition> getSubTypeDefinitions() {
-        return getSubTypeDefinitions(thisType);
-    }
-
-    /**
-     * @return list of sub-types for a given type definition or an empty collection, if there are none
-     */
-    public List<DiscriminatedComplexTypeDefinition> getSubTypeDefinitions(TypeDefinition type) {
-        SwitchField switchField = getSwitchField(type);
-        if (switchField != null) {
-            return switchField.getCases();
+        if (!(thisType instanceof ComplexTypeDefinition)) {
+            return Collections.emptyList();
         }
-        return Collections.emptyList();
+        return ((ComplexTypeDefinition) thisType).getSubTypeDefinitions();
     }
 
     /* *********************************************************************************
@@ -597,30 +709,14 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      **********************************************************************************/
 
     /**
-     * Check if the expression doesn't reference any variables.
-     * If this is the case, the expression can be evaluated at code-generation time.
-     *
-     * @param term term
-     * @return true if it doesn't reference any variable literals.
+     * @deprecated use field method.
      */
+    @Deprecated
     protected boolean isFixedValueExpression(Term term) {
-        if (term instanceof VariableLiteral) {
+        if (term == null) {
             return false;
         }
-        if (term instanceof UnaryTerm) {
-            UnaryTerm unaryTerm = (UnaryTerm) term;
-            return isFixedValueExpression(unaryTerm.getA());
-        }
-        if (term instanceof BinaryTerm) {
-            BinaryTerm binaryTerm = (BinaryTerm) term;
-            return isFixedValueExpression(binaryTerm.getA()) && isFixedValueExpression(binaryTerm.getB());
-        }
-        if (term instanceof TernaryTerm) {
-            TernaryTerm ternaryTerm = (TernaryTerm) term;
-            return isFixedValueExpression(ternaryTerm.getA()) && isFixedValueExpression(ternaryTerm.getB()) &&
-                isFixedValueExpression(ternaryTerm.getC());
-        }
-        return true;
+        return term.isFixedValueExpression();
     }
 
     protected int evaluateFixedValueExpression(Term term) {
@@ -628,30 +724,15 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return (int) expression.evaluate();
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     protected String toString(Term term) {
-        if (term instanceof NullLiteral) {
-            return "null";
-        }
-        if (term instanceof BooleanLiteral) {
-            return Boolean.toString(((BooleanLiteral) term).getValue());
-        }
-        if (term instanceof NumericLiteral) {
-            return ((NumericLiteral) term).getNumber().toString();
-        }
-        if (term instanceof StringLiteral) {
-            return "\"" + ((StringLiteral) term).getValue() + "\"";
-        }
-        if (term instanceof UnaryTerm) {
-            return ((UnaryTerm) term).getOperation() + toString(((UnaryTerm) term).getA());
-        }
-        if (term instanceof BinaryTerm) {
-            return toString(((BinaryTerm) term).getA()) + ((BinaryTerm) term).getOperation() + toString(((BinaryTerm) term).getB());
+        if (term == null) {
+            return "";
         }
-        if (term instanceof TernaryTerm) {
-            return "(" + toString(((TernaryTerm) term).getA()) + ") ? (" + toString(((TernaryTerm) term).getB()) +
-                ") : (" + toString(((TernaryTerm) term).getC()) + ")";
-        }
-        return "";
+        return term.stringRepresentation();
     }
 
     /* *********************************************************************************
@@ -666,13 +747,13 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         Optional<TypeReference> type = getTypeReferenceForProperty(parentType, variableLiteral.getName());
         // If we found something but there's a "rest" left, we got to use the type we
         // found in this level, get that type's definition and continue from there.
-        if (type.isPresent() && (variableLiteral.getChild() != null)) {
+        if (type.isPresent() && (variableLiteral.getChild().isPresent())) {
             TypeReference typeReference = type.get();
             if (typeReference instanceof ComplexTypeReference) {
                 ComplexTypeReference complexTypeReference = (ComplexTypeReference) typeReference;
                 final TypeDefinition typeDefinition = this.types.get(complexTypeReference.getName());
                 if (typeDefinition instanceof ComplexTypeDefinition) {
-                    return getDiscriminatorType((ComplexTypeDefinition) typeDefinition, variableLiteral.getChild());
+                    return getDiscriminatorType((ComplexTypeDefinition) typeDefinition, variableLiteral.getChild().get());
                 }
             }
         }
@@ -680,121 +761,36 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     }
 
     /**
-     * Get an ordered list of generated names for the discriminators.
-     * These names can be used to access the type definitions as well as well as the values.
-     *
-     * @return list of symbolic names for the discriminators.
+     * @deprecated use field method.
      */
+    @Deprecated
     public List<String> getDiscriminatorNames() {
-        return getDiscriminatorNames(thisType);
-    }
-
-    /**
-     * Get an ordered list of generated names for the discriminators.
-     * These names can be used to access the type definitions as well as well as the values.
-     *
-     * @param baseType the type to get the discriminator Names from
-     *
-     * @return list of symbolic names for the discriminators.
-     */
-    public List<String> getDiscriminatorNames(TypeDefinition baseType) {
-        if (baseType.getParentType() != null) {
-            baseType = baseType.getParentType();
-        }
-        final SwitchField switchField = getSwitchField(baseType);
-        List<String> discriminatorNames = new ArrayList<>();
-        if (switchField != null) {
-            for (Term discriminatorExpression : switchField.getDiscriminatorExpressions()) {
-                discriminatorNames.add(getDiscriminatorName(discriminatorExpression));
-            }
+        if (thisType == null) {
+            return Collections.emptyList();
         }
-        return discriminatorNames;
+        return thisType.getDiscriminatorNames();
     }
 
     /**
-     * Check if there's any field with the given name.
-     * This is required to suppress the generation of a discriminator field
-     * in case a named field is providing the information.
-     *
-     * @param discriminatorName name of the discriminator name
-     * @return true if a field with the given name already exists in the same type.
+     * @deprecated use field method.
      */
+    @Deprecated
     public boolean isNonDiscriminatorField(String discriminatorName) {
-        return ((ComplexTypeDefinition) thisType).getAllPropertyFields().stream()
-            .anyMatch(field -> !(field instanceof DiscriminatorField) && field.getName().equals(discriminatorName));
-    }
-
-    /**
-     * Check if there's any field with the given name.
-     * This is required to suppress the generation of a virtual field
-     * in case a discriminated field is providing the information.
-     *
-     * @param discriminatorName name of the virtual name
-     * @return true if a field with the given name already exists in the same type.
-     */
-    public boolean isDiscriminatorField(String discriminatorName) {
-        return isDiscriminatorField(thisType, discriminatorName);
-    }
-
-    /**
-     * Check if there's any field with the given name.
-     * This is required to suppress the generation of a virtual field
-     * in case a discriminated field is providing the information.
-     *
-     * @param discriminatorName name of the virtual name
-     * @return true if a field with the given name already exists in the same type.
-     */
-    public boolean isDiscriminatorField(TypeDefinition typeDefinition, String discriminatorName) {
-        List<String> names = getDiscriminatorNames(typeDefinition);
-        if (names != null) {
-            return names.stream()
-                .anyMatch(field -> field.equals(discriminatorName));
+        if (!(thisType instanceof ComplexTypeDefinition)) {
+            throw new ClassCastException(thisType + " not a" + ComplexTypeDefinition.class.getName());
         }
-        return false;
+        return ((ComplexTypeDefinition) thisType).isNonDiscriminatorField(discriminatorName);
     }
 
     /**
-     * Converts a given discriminator description into a symbolic name.
-     *
-     * @param discriminatorExpression discriminator expression
-     * @return name
+     * @deprecated use field method.
      */
-    public String getDiscriminatorName(Term discriminatorExpression) {
-        if (discriminatorExpression instanceof Literal) {
-            Literal literal = (Literal) discriminatorExpression;
-            if (literal instanceof NullLiteral) {
-                return "null";
-            } else if (literal instanceof BooleanLiteral) {
-                return Boolean.toString(((BooleanLiteral) literal).getValue());
-            } else if (literal instanceof NumericLiteral) {
-                return ((NumericLiteral) literal).getNumber().toString();
-            } else if (literal instanceof StringLiteral) {
-                return ((StringLiteral) literal).getValue();
-            } else if (literal instanceof VariableLiteral) {
-                VariableLiteral variableLiteral = (VariableLiteral) literal;
-                return getVariableLiteralName(variableLiteral);
-            }
-        } else if (discriminatorExpression instanceof UnaryTerm) {
-            UnaryTerm unaryTerm = (UnaryTerm) discriminatorExpression;
-            return getDiscriminatorName(unaryTerm.getA());
-        } else if (discriminatorExpression instanceof BinaryTerm) {
-            BinaryTerm binaryTerm = (BinaryTerm) discriminatorExpression;
-            return getDiscriminatorName(binaryTerm.getA()) + "_" + getDiscriminatorName(binaryTerm.getB());
-        } else if (discriminatorExpression instanceof TernaryTerm) {
-            TernaryTerm ternaryTerm = (TernaryTerm) discriminatorExpression;
-            return getDiscriminatorName(ternaryTerm.getA()) + "_" + getDiscriminatorName(ternaryTerm.getB())
-                + "_" + getDiscriminatorName(ternaryTerm.getC());
-        }
-        return "";
-    }
-
-    private String getVariableLiteralName(VariableLiteral variableLiteral) {
-        String rest = "";
-        if (variableLiteral.getChild() != null) {
-            rest = getVariableLiteralName(variableLiteral.getChild());
-            rest = rest.substring(0, 1).toUpperCase() + rest.substring(1);
+    @Deprecated
+    public boolean isDiscriminatorField(String discriminatorName) {
+        if (thisType == null) {
+            return false;
         }
-        return variableLiteral.getName() + rest;
+        return thisType.isDiscriminatorField(discriminatorName);
     }
 
     /**
@@ -811,63 +807,41 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             parentType = (ComplexTypeDefinition) thisType;
         }
         // Get the typeSwitch field from that.
-        final SwitchField switchField = getSwitchField(parentType);
+        // TODO: map
+        final SwitchField switchField = parentType.getSwitchField().orElse(null);
         if (switchField == null) {
             return Collections.emptyMap();
         }
         Map<String, TypeReference> discriminatorTypes = new TreeMap<>();
         for (Term discriminatorExpression : switchField.getDiscriminatorExpressions()) {
             // Get some symbolic name we can use.
-            String discriminatorName = getDiscriminatorName(discriminatorExpression);
+            String discriminatorName = discriminatorExpression.getDiscriminatorName();
             Optional<TypeReference> discriminatorType = getDiscriminatorType(parentType, discriminatorExpression);
             discriminatorTypes.put(discriminatorName, discriminatorType.orElse(null));
         }
         return discriminatorTypes;
     }
 
+    /**
+     * @deprecated use field method.
+     */
+    @Deprecated
     public Map<String, String> getDiscriminatorValues(TypeDefinition type) {
         if (!(type instanceof DiscriminatedComplexTypeDefinition)) {
             return Collections.emptyMap();
         }
-        DiscriminatedComplexTypeDefinition switchType = (DiscriminatedComplexTypeDefinition) type;
-        final List<String> discriminatorNames = getDiscriminatorNames();
-        final Map<String, String> discriminatorValues = new LinkedHashMap<>();
-        for (int i = 0; i < discriminatorNames.size(); i++) {
-            String discriminatorValue;
-            if (i < switchType.getDiscriminatorValues().length) {
-                discriminatorValue = switchType.getDiscriminatorValues()[i];
-            } else {
-                discriminatorValue = null;
-            }
-            discriminatorValues.put(discriminatorNames.get(i), discriminatorValue);
-        }
-        return discriminatorValues;
+        return ((DiscriminatedComplexTypeDefinition) type).getDiscriminatorMap();
     }
 
     /**
-     * Get a list of the values for every discriminator name for every discriminated type.
-     *
-     * @return Map mapping discriminator names to discriminator values for every discriminated type.
+     * @deprecated use field method.
      */
+    @Deprecated
     public Map<String, Map<String, String>> getDiscriminatorValues() {
-        // Get the parent type (Which contains the typeSwitch field)
-        ComplexTypeDefinition parentType;
-        if (thisType instanceof DiscriminatedComplexTypeDefinition) {
-            parentType = (ComplexTypeDefinition) thisType.getParentType();
-        } else {
-            parentType = (ComplexTypeDefinition) thisType;
-        }
-        // Get the typeSwitch field from that.
-        final SwitchField switchField = getSwitchField(parentType);
-        if (switchField == null) {
+        if (thisType == null) {
             return Collections.emptyMap();
         }
-        // Build a map containing the named discriminator values for every case of the typeSwitch.
-        Map<String, Map<String, String>> discriminatorTypes = new LinkedHashMap<>();
-        for (DiscriminatedComplexTypeDefinition switchCase : switchField.getCases()) {
-            discriminatorTypes.put(switchCase.getName(), getDiscriminatorValues(switchCase));
-        }
-        return discriminatorTypes;
+        return thisType.getDiscriminatorCaseToKeyValueMap();
     }
 
     public TypeReference getArgumentType(TypeReference typeReference, int index) {
@@ -879,10 +853,11 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             throw new FreemarkerException("Could not find definition of complex type " + complexTypeReference.getName());
         }
         TypeDefinition complexTypeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
-        if (complexTypeDefinition.getParserArguments().length <= index) {
-            throw new FreemarkerException("Type " + complexTypeReference.getName() + " specifies too few parser arguments. Available:" + complexTypeDefinition.getParserArguments().length + " index:" + index);
+        List<Argument> parserArguments = complexTypeDefinition.getParserArguments().orElseThrow(() -> new FreemarkerException("No parser arguments present"));
+        if (parserArguments.size() <= index) {
+            throw new FreemarkerException("Type " + complexTypeReference.getName() + " specifies too few parser arguments. Available:" + parserArguments.size() + " index:" + index);
         }
-        return complexTypeDefinition.getParserArguments()[index].getType();
+        return parserArguments.get(index).getType();
     }
 
     /**
@@ -891,7 +866,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
      * @param arguments list of all arguments.
      * @return list of arguments that are used during serialization.
      */
-    public List<Argument> getSerializerArguments(Argument[] arguments) {
+    public List<Argument> getSerializerArguments(List<Argument> arguments) {
         if (arguments == null) {
             return Collections.emptyList();
         }
@@ -904,7 +879,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return serializerArguments;
     }
 
-    public List<Term> getSerializerTerms(Term[] terms) {
+    public List<Term> getSerializerTerms(List<Term> terms) {
         if (terms == null) {
             return Collections.emptyList();
         }
@@ -917,7 +892,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return serializerTerms;
     }
 
-    public boolean hasLastItemTerm(Term[] terms) {
+    public boolean hasLastItemTerm(List<Term> terms) {
         if (terms == null) {
             return false;
         }
@@ -930,6 +905,10 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     }
 
     public boolean discriminatorValueNeedsStringEqualityCheck(Term term) {
+        return discriminatorValueNeedsStringEqualityCheck(term, thisType);
+    }
+
+    public boolean discriminatorValueNeedsStringEqualityCheck(Term term, TypeDefinition typeDefinition) {
         if (!(term instanceof VariableLiteral)) {
             return false;
         }
@@ -940,22 +919,29 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
             return false;
         }
 
-        if (getThisTypeDefinition() instanceof ComplexTypeDefinition) {
-            Field referencedField = ((ComplexTypeDefinition) getThisTypeDefinition()).getFields().stream().filter(field -> ((field instanceof NamedField) && ((NamedField) field).getName().equals(variableLiteral.getName()))).findFirst().orElse(null);
-            if (referencedField instanceof TypedField
-                && ((TypedField) referencedField).getType() instanceof StringTypeReference) {
+        if (typeDefinition instanceof ComplexTypeDefinition) {
+            ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) typeDefinition;
+            boolean needsStringEquals = complexTypeDefinition.getFields().stream()
+                .filter(NamedField.class::isInstance)
+                .filter(field -> ((NamedField) field).getName().equals(variableLiteral.getName()))
+                .filter(TypedField.class::isInstance)
+                .map(TypedField.class::cast)
+                .map(TypedField::getType)
+                .map(StringTypeReference.class::isInstance)
+                .findFirst()
+                .orElse(false);
+            if (needsStringEquals) {
                 return true;
             }
         }
-        if (getThisTypeDefinition().getParserArguments() != null) {
-            for (Argument parserArgument : getThisTypeDefinition().getParserArguments()) {
-                if (parserArgument.getName().equals(variableLiteral.getName())
-                    && parserArgument.getType() instanceof StringTypeReference) {
-                    return true;
-                }
-            }
-        }
-        return false;
+        return typeDefinition.getParserArguments()
+            .orElse(Collections.emptyList())
+            .stream()
+            .filter(argument -> argument.getName().equals(variableLiteral.getName()))
+            .map(Argument::getType)
+            .map(StringTypeReference.class::isInstance)
+            .findFirst()
+            .orElse(false);
     }
 
     public boolean isEnumExpression(String expression) {
@@ -967,7 +953,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return (typeDefinition instanceof EnumTypeDefinition);
     }
 
-    public Collection<EnumValue> getUniqueEnumValues(EnumValue[] enumValues) {
+    public Collection<EnumValue> getUniqueEnumValues(List<EnumValue> enumValues) {
         Map<String, EnumValue> filteredEnumValues = new TreeMap<>();
         for (EnumValue enumValue : enumValues) {
             if (!filteredEnumValues.containsKey(enumValue.getValue())) {
@@ -977,20 +963,21 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return filteredEnumValues.values();
     }
 
-    public Collection<EnumValue> getEnumValuesForUniqueConstantValues(EnumValue[] enumValues, String constantName) {
+    public Collection<EnumValue> getEnumValuesForUniqueConstantValues(List<EnumValue> enumValues, String constantName) {
         Map<String, EnumValue> filteredEnumValues = new TreeMap<>();
         for (EnumValue enumValue : enumValues) {
-            if (!filteredEnumValues.containsKey(enumValue.getConstant(constantName))) {
-                filteredEnumValues.put(enumValue.getConstant(constantName), enumValue);
+            String key = enumValue.getConstant(constantName).orElseThrow(() -> new FreemarkerException("No constant name " + constantName + " found in enum value" + enumValue));
+            if (!filteredEnumValues.containsKey(key)) {
+                filteredEnumValues.put(key, enumValue);
             }
         }
         return filteredEnumValues.values();
     }
 
-    public Collection<EnumValue> getEnumValuesForConstantValue(EnumValue[] enumValues, String constantName, String constantValue) {
+    public Collection<EnumValue> getEnumValuesForConstantValue(List<EnumValue> enumValues, String constantName, String constantValue) {
         List<EnumValue> filteredEnumValues = new ArrayList<>();
         for (EnumValue enumValue : enumValues) {
-            if (enumValue.getConstant(constantName).equals(constantValue)) {
+            if (enumValue.getConstant(constantName).orElseThrow(() -> new FreemarkerException("No constant name " + constantName + " found in enum value" + enumValue)).equals(constantValue)) {
                 filteredEnumValues.add(enumValue);
             }
         }
@@ -1010,13 +997,24 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     /**
      * Confirms if a variable is an implicit variable. These need to be handled differently when serializing and parsing.
      *
-     * @param vl The variable to search for.
+     * @param variableLiteral The variable to search for.
      * @return boolean returns true if the variable's name is an implicit field
      */
-    protected boolean isVariableLiteralImplicitField(VariableLiteral vl) {
+    protected boolean isVariableLiteralImplicitField(VariableLiteral variableLiteral) {
+        return isVariableLiteralImplicitField(variableLiteral, thisType);
+    }
+
+    /**
+     * Confirms if a variable is an implicit variable. These need to be handled differently when serializing and parsing.
+     *
+     * @param variableLiteral The variable to search for.
+     * @param typeDefinition  Type definition to check
+     * @return boolean returns true if the variable's name is an implicit field
+     */
+    protected boolean isVariableLiteralImplicitField(VariableLiteral variableLiteral, TypeDefinition typeDefinition) {
         List<Field> fields = null;
-        if (thisType instanceof ComplexTypeDefinition) {
-            ComplexTypeDefinition complexType = (ComplexTypeDefinition) getThisTypeDefinition();
+        if (typeDefinition instanceof ComplexTypeDefinition) {
+            ComplexTypeDefinition complexType = (ComplexTypeDefinition) typeDefinition;
             fields = complexType.getFields();
         }
         if (fields == null) {
@@ -1025,7 +1023,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         for (Field field : fields) {
             if (field.getTypeName().equals(IMPLICIT)) {
                 ImplicitField implicitField = (ImplicitField) field;
-                if (vl.getName().equals(implicitField.getName())) {
+                if (variableLiteral.getName().equals(implicitField.getName())) {
                     return true;
                 }
             }
@@ -1036,13 +1034,24 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     /**
      * Confirms if a variable is an virtual variable. These need to be handled differently when serializing and parsing.
      *
-     * @param vl The variable to search for.
+     * @param variableLiteral The variable to search for.
+     * @return boolean returns true if the variable's name is an virtual field
+     */
+    protected boolean isVariableLiteralVirtualField(VariableLiteral variableLiteral) {
+        return isVariableLiteralVirtualField(variableLiteral, thisType);
+    }
+
+    /**
+     * Confirms if a variable is an virtual variable. These need to be handled differently when serializing and parsing.
+     *
+     * @param variableLiteral The variable to search for.
+     * @param typeDefinition  Type definition to check
      * @return boolean returns true if the variable's name is an virtual field
      */
-    protected boolean isVariableLiteralVirtualField(VariableLiteral vl) {
+    protected boolean isVariableLiteralVirtualField(VariableLiteral variableLiteral, TypeDefinition typeDefinition) {
         List<Field> fields = new ArrayList<>();
-        if (thisType instanceof ComplexTypeDefinition) {
-            ComplexTypeDefinition complexType = (ComplexTypeDefinition) getThisTypeDefinition();
+        if (typeDefinition instanceof ComplexTypeDefinition) {
+            ComplexTypeDefinition complexType = (ComplexTypeDefinition) typeDefinition;
             fields.addAll(complexType.getFields());
             if (complexType.getParentType() != null) {
                 fields.addAll(((ComplexTypeDefinition) complexType.getParentType()).getFields());
@@ -1051,7 +1060,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         for (Field field : fields) {
             if (field.getTypeName().equals(VIRTUAL)) {
                 VirtualField virtualField = (VirtualField) field;
-                if (vl.getName().equals(virtualField.getName())) {
+                if (variableLiteral.getName().equals(virtualField.getName())) {
                     return true;
                 }
             }
@@ -1060,15 +1069,26 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     }
 
     /**
+     * Confirms if a variable is a discriminator variable. These need to be handled differently when serializing and parsing.
+     *
+     * @param variableLiteral The variable to search for.
+     * @return boolean returns true if the variable's name is an discriminator field
+     */
+    protected boolean isVariableLiteralDiscriminatorField(VariableLiteral variableLiteral) {
+        return isVariableLiteralDiscriminatorField(variableLiteral, thisType);
+    }
+
+    /**
      * Confirms if a variable is an discriminator variable. These need to be handled differently when serializing and parsing.
      *
-     * @param vl The variable to search for.
+     * @param variableLiteral The variable to search for.
+     * @param typeDefinition  Type definition to check
      * @return boolean returns true if the variable's name is an discriminator field
      */
-    protected boolean isVariableLiteralDiscriminatorField(VariableLiteral vl) {
+    protected boolean isVariableLiteralDiscriminatorField(VariableLiteral variableLiteral, TypeDefinition typeDefinition) {
         List<Field> fields = null;
-        if (thisType instanceof ComplexTypeDefinition) {
-            ComplexTypeDefinition complexType = (ComplexTypeDefinition) getThisTypeDefinition();
+        if (typeDefinition instanceof ComplexTypeDefinition) {
+            ComplexTypeDefinition complexType = (ComplexTypeDefinition) typeDefinition;
             fields = complexType.getFields();
         }
         if (fields == null) {
@@ -1077,7 +1097,7 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         for (Field field : fields) {
             if (field.getTypeName().equals(DISCRIMINATOR)) {
                 DiscriminatorField discriminatorField = (DiscriminatorField) field;
-                if (vl.getName().equals(discriminatorField.getName())) {
+                if (variableLiteral.getName().equals(discriminatorField.getName())) {
                     return true;
                 }
             }
@@ -1088,13 +1108,24 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
     /**
      * Returns the implicit field that has the same name as the variable. These need to be handled differently when serializing and parsing.
      *
-     * @param vl The variable to search for.
+     * @param variableLiteral The variable to search for.
      * @return ImplicitField returns the implicit field that corresponds to the variable's name.
      */
-    protected ImplicitField getReferencedImplicitField(VariableLiteral vl) {
+    protected ImplicitField getReferencedImplicitField(VariableLiteral variableLiteral) {
+        return getReferencedImplicitField(variableLiteral, thisType);
+    }
+
+    /**
+     * Returns the implicit field that has the same name as the variable. These need to be handled differently when serializing and parsing.
+     *
+     * @param vl             The variable to search for.
+     * @param typeDefinition Type definition to check
+     * @return ImplicitField returns the implicit field that corresponds to the variable's name.
+     */
+    protected ImplicitField getReferencedImplicitField(VariableLiteral vl, TypeDefinition typeDefinition) {
         List<Field> fields = null;
-        if (thisType instanceof ComplexTypeDefinition) {
-            ComplexTypeDefinition complexType = (ComplexTypeDefinition) getThisTypeDefinition();
+        if (typeDefinition instanceof ComplexTypeDefinition) {
+            ComplexTypeDefinition complexType = (ComplexTypeDefinition) typeDefinition;
             fields = complexType.getFields();
         }
         if (fields == null) {
diff --git a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java
index 67fa00f..de98895 100644
--- a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java
+++ b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageTemplateHelper.java
@@ -18,5 +18,23 @@
  */
 package org.apache.plc4x.plugins.codegenerator.protocol.freemarker;
 
+import org.apache.plc4x.plugins.codegenerator.types.fields.Field;
+import org.apache.plc4x.plugins.codegenerator.types.fields.TypedField;
+import org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference;
+import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
+
 public interface FreemarkerLanguageTemplateHelper {
+    String getLanguageTypeNameForField(Field field);
+
+    String getLanguageTypeNameForTypeReference(TypeReference typeReference);
+
+    default String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference) {
+        return getReadBufferReadMethodCall(simpleTypeReference, null, null);
+    }
+
+    String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString, TypedField field);
+
+    String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName, TypedField field);
+
+    String getNullValueForTypeReference(TypeReference typeReference);
 }
diff --git a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/Tracer.java b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/Tracer.java
index 7ef0181..320ea03 100644
--- a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/Tracer.java
+++ b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/Tracer.java
@@ -25,7 +25,7 @@ package org.apache.plc4x.plugins.codegenerator.protocol.freemarker;
  */
 public class Tracer {
 
-    protected static boolean ENABLED = System.getenv().containsKey("PLC4X_TRACE_CODE_GEN");
+    protected static boolean ENABLED = "true".equalsIgnoreCase(System.getenv().get("PLC4X_TRACE_CODE_GEN"));
 
     protected final String currentTrace;
 
@@ -53,6 +53,19 @@ public class Tracer {
         return new Tracer(currentTrace + separator() + sub);
     }
 
+    /**
+     * Can be used to remove traces from a traced string.
+     *
+     * @param somethingContainingTraces something containing traces
+     * @return de-traced string
+     */
+    public String removeTraces(String somethingContainingTraces) {
+        if (somethingContainingTraces == null) {
+            return null;
+        }
+        return somethingContainingTraces.replaceAll("/\\*.*\\*/", "");
+    }
+
     protected String separator() {
         return "/";
     }
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 445d906..01488e0 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
@@ -45,7 +45,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
 
     /**
      * Little helper that converts a given type name in camel-case into a c-style snake-case expression.
-     * In addition it appends a prefix for the protocol name and the output flavor.
+     * In addition, it appends a prefix for the protocol name and the output flavor.
      *
      * @param typeName camel-case type name
      * @return c-style type name
@@ -58,7 +58,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
 
     public String getFieldName(ComplexTypeDefinition baseType, NamedField field) {
         StringBuilder sb = new StringBuilder();
-        if (baseType != getThisTypeDefinition()) {
+        if (baseType != thisType) {
             sb.append(camelCaseToSnakeCase(baseType.getName())).append("_");
         }
         sb.append(camelCaseToSnakeCase(field.getName()));
@@ -94,7 +94,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         // If the first letter was a capital letter, the string will start with a "_".
         // In this case we cut that char off.
         if (snakeCase.indexOf("_") == 0) {
-            return snakeCase.toString().substring(1);
+            return snakeCase.substring(1);
         }
         return snakeCase.toString();
     }
@@ -108,16 +108,16 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
      */
     @Override
     public String getLanguageTypeNameForField(Field field) {
-        if(!(field instanceof TypedField)) {
+        if (!(field.isTypedField())) {
             throw new FreemarkerException("Field " + field + " is not a TypedField");
         }
         // If this is an array with variable length, then we have to use our "plc4c_list" to store the data.
-        if ((field instanceof ArrayField) && (!isFixedValueExpression(((ArrayField) field).getLoopExpression()))) {
+        if (field.asArrayField().map(ArrayField::getLoopExpression).map(Term::isFixedValueExpression).orElse(false)) {
             return "plc4c_list";
         }
-        TypedField typedField = (TypedField) field;
+        TypedField typedField = field.asTypedField().orElseThrow(IllegalStateException::new);
         TypeReference typeReference = typedField.getType();
-        if (typeReference instanceof ComplexTypeReference) {
+        if (typeReference.isComplexTypeReference()) {
             final TypeDefinition typeDefinition = getTypeDefinitionForTypeReference(typeReference);
             if (typeDefinition instanceof DataIoTypeDefinition) {
                 return "plc4c_data*";
@@ -128,14 +128,16 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
 
     public Map<ConstField, ComplexTypeDefinition> getAllConstFields() {
         Map<ConstField, ComplexTypeDefinition> constFields = new HashMap<>();
-        ((ComplexTypeDefinition) getThisTypeDefinition()).getConstFields().forEach(
-            constField -> constFields.put(constField, (ComplexTypeDefinition) getThisTypeDefinition()));
-        if(getSwitchField() != null) {
-            for (DiscriminatedComplexTypeDefinition switchCase : getSwitchField().getCases()) {
-                switchCase.getConstFields().forEach(
-                    constField -> constFields.put(constField, switchCase));
-            }
-        }
+        ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) this.thisType;
+        complexTypeDefinition.getConstFields()
+            .forEach(constField -> constFields.put(constField, complexTypeDefinition));
+        complexTypeDefinition.getSwitchField()
+            .map(SwitchField::getCases)
+            .ifPresent(discriminatedComplexTypeDefinitions ->
+                discriminatedComplexTypeDefinitions.forEach(switchCase ->
+                    switchCase.getConstFields().forEach(constField -> constFields.put(constField, switchCase))
+                )
+            );
         return constFields;
     }
 
@@ -144,22 +146,29 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
      * same with optional fields.
      *
      * @param typeDefinition type that contains the property or attribute.
-     * @param propertyName name of the property or attribute
+     * @param propertyName   name of the property or attribute
      * @return true if the access needs to be using pointers
      */
     public boolean requiresPointerAccess(ComplexTypeDefinition typeDefinition, String propertyName) {
-        final Optional<NamedField> namedFieldOptional = typeDefinition.getFields().stream().filter(field -> field instanceof NamedField).map(field -> (NamedField) field).filter(namedField -> namedField.getName().equals(propertyName)).findFirst();
+        final Optional<NamedField> namedFieldOptional = typeDefinition.getFields().stream()
+            .filter(field -> field instanceof NamedField)
+            .map(field -> (NamedField) field)
+            .filter(namedField -> namedField.getName().equals(propertyName))
+            .findFirst();
         // If the property name refers to a field, check if it's an optional field.
         // If it is, pointer access is required, if not, it's not.
-        if(namedFieldOptional.isPresent()) {
+        if (namedFieldOptional.isPresent()) {
             final NamedField namedField = namedFieldOptional.get();
-            if(namedField instanceof TypedField) {
+            if (namedField instanceof TypedField) {
                 TypedField typedField = (TypedField) namedField;
-                return !(namedField instanceof EnumField) && (isComplexTypeReference(typedField.getType()));
+                return !(typedField.isEnumField()) && typedField.getType().isComplexTypeReference();
             }
             return false;
         }
-        final Optional<Argument> parserArgument = Arrays.stream(typeDefinition.getParserArguments()).filter(argument -> argument.getName().equals(propertyName)).findFirst();
+        final Optional<Argument> parserArgument = typeDefinition.getParserArguments()
+            .orElse(Collections.emptyList())
+            .stream()
+            .filter(argument -> argument.getName().equals(propertyName)).findFirst();
         // If the property name refers to a parser argument, as soon as it's a complex type,
         // pointer access is required.
         return parserArgument.filter(argument -> argument.getType() instanceof ComplexTypeReference).isPresent();
@@ -249,7 +258,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
             ArrayField arrayField = (ArrayField) field;
             if (arrayField.getLoopType() == ArrayField.LoopType.COUNT) {
                 Term countTerm = arrayField.getLoopExpression();
-                if (isFixedValueExpression(countTerm)) {
+                if (countTerm != null && countTerm.isFixedValueExpression()) {
                     int evaluatedCount = evaluateFixedValueExpression(countTerm);
                     return "[" + evaluatedCount + "]";
                 }
@@ -275,7 +284,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                     return " : 8";
                 case UINT:
                 case INT:
-                    // If the bit-size is exactly one of the built-in tpye-sizes, omit the suffix.
+                    // If the bit-size is exactly one of the built-in type-sizes, omit the suffix.
                     if ((simpleTypeReference.getSizeInBits() == 8) || (simpleTypeReference.getSizeInBits() == 16) ||
                         (simpleTypeReference.getSizeInBits() == 32) || (simpleTypeReference.getSizeInBits() == 64)) {
                         return "";
@@ -283,7 +292,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                     return " : " + simpleTypeReference.getSizeInBits();
                 case FLOAT:
                 case UFLOAT:
-                    // If the bit-size is exactly one of the built-in tpye-sizes, omit the suffix.
+                    // If the bit-size is exactly one of the built-in type-sizes, omit the suffix.
                     if ((simpleTypeReference.getSizeInBits() == 32) || (simpleTypeReference.getSizeInBits() == 64)) {
                         return "";
                     }
@@ -333,7 +342,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
     }
 
     public String escapeEnumValue(TypeReference typeReference, String valueString) {
-        // Currently the only case in which here complex type references are used are when referencing enum constants.
+        // Currently, the only case in which here complex type references are used are when referencing enum constants.
         if (typeReference instanceof ComplexTypeReference) {
             // C doesn't like NULL values for enums, so we have to return something else (we'll treat -1 as NULL)
             if ("null".equals(valueString)) {
@@ -387,13 +396,13 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                 FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
                 if (floatTypeReference.getSizeInBits() <= 32) {
                     return "plc4c_spi_read_float(readBuffer, " + floatTypeReference.getSizeInBits() + ", (float*) " + valueString + ")";
-                } else if(floatTypeReference.getSizeInBits() <= 64) {
+                } else if (floatTypeReference.getSizeInBits() <= 64) {
                     return "plc4c_spi_read_double(readBuffer, " + floatTypeReference.getSizeInBits() + ", (double*) " + valueString + ")";
                 }
                 throw new FreemarkerException("Unsupported float type with " + floatTypeReference.getSizeInBits() + " bits");
             case STRING:
                 StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                return "plc4c_spi_read_string(readBuffer, " + toParseExpression(getThisTypeDefinition(), field, stringTypeReference.getLengthExpression(), null) + ", \"" +
+                return "plc4c_spi_read_string(readBuffer, " + toParseExpression(thisType, field, stringTypeReference.getLengthExpression(), null) + ", \"" +
                     stringTypeReference.getEncoding() + "\"" + ", (char**) " + valueString + ")";
             default:
                 throw new FreemarkerException("Unsupported type " + simpleTypeReference.getBaseType().name());
@@ -441,13 +450,13 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                 FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
                 if (floatTypeReference.getSizeInBits() <= 32) {
                     return "plc4c_spi_write_float(writeBuffer, " + floatTypeReference.getSizeInBits() + ", " + fieldName + ")";
-                } else if(floatTypeReference.getSizeInBits() <= 64) {
+                } else if (floatTypeReference.getSizeInBits() <= 64) {
                     return "plc4c_spi_write_double(writeBuffer, " + floatTypeReference.getSizeInBits() + ", " + fieldName + ")";
                 }
                 throw new FreemarkerException("Unsupported float type with " + floatTypeReference.getSizeInBits() + " bits");
             case STRING:
                 StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                return "plc4c_spi_write_string(writeBuffer, " + toSerializationExpression(getThisTypeDefinition(), field, stringTypeReference.getLengthExpression(), null) + ", \"" +
+                return "plc4c_spi_write_string(writeBuffer, " + toSerializationExpression(thisType, field, stringTypeReference.getLengthExpression(), null) + ", \"" +
                     stringTypeReference.getEncoding() + "\", " + fieldName + ")";
             default:
                 throw new FreemarkerException("Unsupported type " + simpleTypeReference.getBaseType().name());
@@ -488,18 +497,18 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
 
     public String getReservedValue(ReservedField reservedField) {
         final String languageTypeName = getLanguageTypeNameForTypeReference(reservedField.getType());
-        if("BigInteger".equals(languageTypeName)) {
+        if ("BigInteger".equals(languageTypeName)) {
             return "BigInteger.valueOf(" + reservedField.getReferenceValue() + ")";
         } else {
             return "(" + languageTypeName + ") " + reservedField.getReferenceValue();
         }
     }
 
-    public String toParseExpression(TypeDefinition baseType, Field field, Term term, Argument[] parserArguments) {
+    public String toParseExpression(TypeDefinition baseType, Field field, Term term, List<Argument> parserArguments) {
         return toExpression(baseType, field, term, term1 -> toVariableParseExpression(baseType, field, term1, parserArguments));
     }
 
-    public String toSerializationExpression(TypeDefinition baseType, Field field, Term term, Argument[] parserArguments) {
+    public String toSerializationExpression(TypeDefinition baseType, Field field, Term term, List<Argument> parserArguments) {
         return toExpression(baseType, field, term, term1 -> toVariableSerializationExpression(baseType, field, term1, parserArguments));
     }
 
@@ -518,15 +527,15 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                 return "\"" + ((StringLiteral) term).getValue() + "\"";
             } else if (term instanceof VariableLiteral) {
                 VariableLiteral variableLiteral = (VariableLiteral) term;
-                if(variableLiteral.contains("lengthInBytes")) {
+                if (variableLiteral.contains("lengthInBytes")) {
                     TypeDefinition lengthType;
                     String lengthExpression;
-                    if(variableLiteral.getName().equals("lengthInBytes")) {
+                    if (variableLiteral.getName().equals("lengthInBytes")) {
                         lengthType = (baseType.getParentType() == null) ? baseType : (ComplexTypeDefinition) baseType.getParentType();
                         lengthExpression = "_message";
                     } else {
-                        final Optional<TypeReference> typeReferenceForProperty = getTypeReferenceForProperty( (ComplexTypeDefinition) baseType, variableLiteral.getName());
-                        if(!typeReferenceForProperty.isPresent()) {
+                        final Optional<TypeReference> typeReferenceForProperty = getTypeReferenceForProperty((ComplexTypeDefinition) baseType, variableLiteral.getName());
+                        if (!typeReferenceForProperty.isPresent()) {
                             throw new FreemarkerException("Unknown type for property " + variableLiteral.getName());
                         }
                         lengthType = getTypeDefinitionForTypeReference(typeReferenceForProperty.get());
@@ -535,9 +544,9 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                     return getCTypeName(lengthType.getName()) + "_length_in_bytes(" + lengthExpression + ")";
                 } else if (variableLiteral.getName().equals("lastItem")) {
                     return "lastItem";
-                // If this literal references an Enum type, then we have to output it differently.
+                    // If this literal references an Enum type, then we have to output it differently.
                 } else if (getTypeDefinitions().get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
-                    return getCTypeName(variableLiteral.getName()) + "_" + variableLiteral.getChild().getName();
+                    return getCTypeName(variableLiteral.getName()) + "_" + variableLiteral.getChild().map(VariableLiteral::getName).orElseThrow(() -> new FreemarkerException("child required"));
                 } else {
                     return variableExpressionGenerator.apply(term);
                 }
@@ -581,55 +590,60 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         }
     }
 
-    public String toVariableParseExpression(TypeDefinition baseType, Field field, Term term, Argument[] parserArguments) {
+    public String toVariableParseExpression(TypeDefinition baseType, Field field, Term term, List<Argument> parserArguments) {
         VariableLiteral vl = (VariableLiteral) term;
-        if("CAST".equals(vl.getName())) {
+        if ("CAST".equals(vl.getName())) {
 
-            if((vl.getArgs() == null) || (vl.getArgs().size() != 2)) {
+            if ((!vl.getArgs().isPresent()) || (vl.getArgs().get().size() != 2)) {
                 throw new FreemarkerException("A CAST expression expects exactly two arguments.");
             }
-            final VariableLiteral sourceTerm = (VariableLiteral) vl.getArgs().get(0);
-            final VariableLiteral typeTerm = (VariableLiteral) vl.getArgs().get(1);
+            List<Term> args = vl.getArgs().get();
+            final VariableLiteral sourceTerm = (VariableLiteral) args.get(0);
+            final VariableLiteral typeTerm = (VariableLiteral) vl.getArgs().get().get(1);
             final TypeDefinition castType = getTypeDefinitions().get(typeTerm.getName());
             // If we're casting to a sub-type of a discriminated value, we got to cast to the parent
             // type instead and add the name of the sub-type as prefix to the property we're trying to
             // access next.
             StringBuilder sb = new StringBuilder();
             sb.append("((");
-            if(castType.getParentType() != null) {
+            if (castType.getParentType() != null) {
                 sb.append(getCTypeName(castType.getParentType().getName()));
             } else {
                 sb.append(getCTypeName(castType.getName()));
             }
             sb.append("*) (");
             sb.append(toVariableParseExpression(baseType, field, sourceTerm, parserArguments)).append("))");
-            if(vl.getChild() != null) {
-                if(castType.getParentType() != null) {
+            if (vl.getChild().isPresent()) {
+                if (castType.getParentType() != null) {
                     // Change the name of the property to contain the sub-type-prefix.
                     sb.append("->").append(camelCaseToSnakeCase(castType.getName())).append("_");
-                    appendVariableExpressionRest(sb, baseType, vl.getChild());
+                    appendVariableExpressionRest(sb, baseType, vl.getChild().get());
                 } else {
                     sb.append("->");
-                    appendVariableExpressionRest(sb, castType, vl.getChild());
+                    appendVariableExpressionRest(sb, castType, vl.getChild().get());
                 }
             }
             return sb.toString();
         }
         // STATIC_CALL implies that driver specific static logic should be called
         if ("STATIC_CALL".equals(vl.getName())) {
-            if (!(vl.getArgs().get(0) instanceof StringLiteral)) {
+            if (!vl.getArgs().isPresent()) {
+                throw new FreemarkerException("'STATIC_CALL' needs at least one args");
+            }
+            List<Term> terms = vl.getArgs().get();
+            if (!(terms.get(0) instanceof StringLiteral)) {
                 throw new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
             }
-            String functionName = ((StringLiteral) vl.getArgs().get(0)).getValue();
+            String functionName = ((StringLiteral) terms.get(0)).getValue();
             // We'll cut off the java package structure and just take the segment after the last "."
-            functionName = functionName.substring(functionName.lastIndexOf('.') + 1, functionName.length() -1);
+            functionName = functionName.substring(functionName.lastIndexOf('.') + 1, functionName.length() - 1);
             // But to make the function name unique, well add the driver prefix to it.
             StringBuilder sb = new StringBuilder(getCTypeName(functionName));
-            if (vl.getArgs().size() > 1) {
+            if (terms.size() > 1) {
                 sb.append("(");
                 boolean firstArg = true;
-                for (int i = 1; i < vl.getArgs().size(); i++) {
-                    Term arg = vl.getArgs().get(i);
+                for (int i = 1; i < terms.size(); i++) {
+                    Term arg = terms.get(i);
                     if (!firstArg) {
                         sb.append(", ");
                     }
@@ -645,10 +659,11 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         // All should have a name prefix "plc4c_spi_evaluation_helper_".
         else if (vl.getName().equals(vl.getName().toUpperCase())) {
             StringBuilder sb = new StringBuilder("plc4c_spi_evaluation_helper_" + vl.getName().toLowerCase());
-            if (vl.getArgs() != null) {
+            if (vl.getArgs().isPresent()) {
+                // TODO: replace with map join
                 sb.append("(");
                 boolean firstArg = true;
-                for (Term arg : vl.getArgs()) {
+                for (Term arg : vl.getArgs().get()) {
                     if (!firstArg) {
                         sb.append(", ");
                     }
@@ -660,42 +675,44 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
             if (vl.getIndex() != VariableLiteral.NO_INDEX) {
                 sb.append("[").append(vl.getIndex()).append("]");
             }
-            if(vl.getChild() != null) {
+            if (vl.getChild().isPresent()) {
                 sb.append(".");
-                appendVariableExpressionRest(sb, baseType, vl.getChild());
+                appendVariableExpressionRest(sb, baseType, vl.getChild().get());
             }
             return sb.toString();
-        } else if("readBuffer".equals(vl.getName())) {
+        } else if ("readBuffer".equals(vl.getName())) {
             StringBuilder sb = new StringBuilder("readBuffer");
-            if(vl.getChild() != null) {
+            if (vl.getChild().isPresent()) {
+                // TODO: replace with map join
                 sb.append(".");
-                appendVariableExpressionRest(sb, baseType, vl.getChild());
+                appendVariableExpressionRest(sb, baseType, vl.getChild().get());
             }
             return sb.toString();
-        } else if("writeBuffer".equals(vl.getName())) {
+        } else if ("writeBuffer".equals(vl.getName())) {
             StringBuilder sb = new StringBuilder("writeBuffer");
-            if(vl.getChild() != null) {
+            if (vl.getChild().isPresent()) {
                 sb.append(".");
-                appendVariableExpressionRest(sb, baseType, vl.getChild());
+                appendVariableExpressionRest(sb, baseType, vl.getChild().get());
             }
             return sb.toString();
-        } else if("_type".equals(vl.getName())) {
-            if((vl.getChild() != null) && "encoding".equals(vl.getChild().getName()) && (field instanceof TypedField) && (((TypedField) field).getType() instanceof StringTypeReference)) {
+        } else if ("_type".equals(vl.getName())) {
+            if ((vl.getChild().isPresent()) && "encoding".equals(vl.getChild().get().getName()) && (field instanceof TypedField) && (((TypedField) field).getType() instanceof StringTypeReference)) {
+                // TODO: replace with map join
                 TypedField typedField = (TypedField) field;
                 StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
                 return "\"" + stringTypeReference.getEncoding().substring(1, stringTypeReference.getEncoding().length() - 1) + "\"";
             } else {
-                throw new FreemarkerException("_type is currently pretty much hard-coded for some usecases, please check CLanguageTemplateHelper.toVariableParseExpression");
+                throw new FreemarkerException("_type is currently pretty much hard-coded for some use cases, please check CLanguageTemplateHelper.toVariableParseExpression");
             }
         }
 
         final String name = vl.getName();
 
         // In case of DataIo types, we'll just check the arguments.
-        if(baseType instanceof DataIoTypeDefinition) {
-            if(baseType.getParserArguments() != null) {
-                for (Argument parserArgument : baseType.getParserArguments()) {
-                    if(parserArgument.getName().equals(name)) {
+        if (baseType instanceof DataIoTypeDefinition) {
+            if (baseType.getParserArguments().isPresent()) {
+                for (Argument parserArgument : baseType.getParserArguments().get()) {
+                    if (parserArgument.getName().equals(name)) {
                         return name;
                     }
                 }
@@ -707,15 +724,15 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
             getTypeReferenceForProperty((ComplexTypeDefinition) baseType, name);
 
         // If we couldn't find the type, we didn't find the property.
-        if(!propertyTypeOptional.isPresent()) {
+        if (!propertyTypeOptional.isPresent()) {
             throw new FreemarkerException("Could not find property with name '" + name + "' in type " + baseType.getName());
         }
 
         final TypeReference propertyType = propertyTypeOptional.get();
 
         // If it's a simple field, there is no sub-type to access.
-        if(propertyType instanceof SimpleTypeReference) {
-            if(vl.getChild() != null) {
+        if (propertyType instanceof SimpleTypeReference) {
+            if (vl.getChild().isPresent()) {
                 throw new FreemarkerException("Simple property '" + name + "' doesn't have child properties.");
             }
             return name;
@@ -724,51 +741,55 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         // If it references a complex, type we need to get that type's definition first.
         final TypeDefinition propertyTypeDefinition = getTypeDefinitions().get(((ComplexTypeReference) propertyType).getName());
         // If we're not accessing any child property, no need to handle anything special.
-        if(vl.getChild() == null) {
+        if (!vl.getChild().isPresent()) {
             return name;
         }
         // If there is a child we need to check if this is a discriminator property.
         // As discriminator properties are not real properties, but saved in the static metadata
         // of a type, we need to generate a different access pattern.
-        if(propertyTypeDefinition instanceof ComplexTypeDefinition) {
+        if (propertyTypeDefinition instanceof ComplexTypeDefinition) {
             final Optional<DiscriminatorField> discriminatorFieldOptional = ((ComplexTypeDefinition) propertyTypeDefinition).getFields().stream().filter(
                 curField -> curField instanceof DiscriminatorField).map(curField -> (DiscriminatorField) curField).filter(
-                discriminatorField -> discriminatorField.getName().equals(vl.getChild().getName())).findFirst();
+                discriminatorField -> discriminatorField.getName().equals(vl.getChild().get().getName())).findFirst();
             // If child references a discriminator field of the type we found, we have to escape it.
             if (discriminatorFieldOptional.isPresent()) {
-                return getCTypeName(propertyTypeDefinition.getName()) + "_get_discriminator(" + name + "->_type)." + vl.getChild().getName();
+                return getCTypeName(propertyTypeDefinition.getName()) + "_get_discriminator(" + name + "->_type)." + vl.getChild().get().getName();
             }
         }
         // Handling enum properties in C is a little more tricky as we have to use the enum value
         // and pass this to a function that returns the desired property value.
-        else if(propertyTypeDefinition instanceof EnumTypeDefinition) {
+        else if (propertyTypeDefinition instanceof EnumTypeDefinition) {
             return getCTypeName(propertyTypeDefinition.getName()) +
-                "_get_" + camelCaseToSnakeCase(vl.getChild().getName()) +
+                "_get_" + camelCaseToSnakeCase(vl.getChild().get().getName()) +
                 "(*" + vl.getName() + ")";
         }
         // Else ... generate a simple access path.
         StringBuilder sb = new StringBuilder(vl.getName());
-        if(vl.getChild() != null) {
+        if (vl.getChild().isPresent()) {
             sb.append(".");
-            appendVariableExpressionRest(sb, baseType, vl.getChild());
+            appendVariableExpressionRest(sb, baseType, vl.getChild().get());
         }
         return sb.toString();
     }
 
-    private String toVariableSerializationExpression(TypeDefinition baseType, Field field, Term term, Argument[] serialzerArguments) {
+    private String toVariableSerializationExpression(TypeDefinition baseType, Field field, Term term, List<Argument> serializerArguments) {
         VariableLiteral vl = (VariableLiteral) term;
         if ("STATIC_CALL".equals(vl.getName())) {
-            if (!(vl.getArgs().get(0) instanceof StringLiteral)) {
+            if (!vl.getArgs().isPresent()) {
+                throw new FreemarkerException("'STATIC_CALL' needs at least one attribute");
+            }
+            List<Term> args = vl.getArgs().get();
+            if (!(args.get(0) instanceof StringLiteral)) {
                 throw new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
             }
-            String functionName = ((StringLiteral) vl.getArgs().get(0)).getValue();
+            String functionName = ((StringLiteral) args.get(0)).getValue();
             // We'll cut off the java package structure and just take the segment after the last "."
-            functionName = functionName.substring(functionName.lastIndexOf('.') + 1, functionName.length() -1);
+            functionName = functionName.substring(functionName.lastIndexOf('.') + 1, functionName.length() - 1);
             // But to make the function name unique, well add the driver prefix to it.
             StringBuilder sb = new StringBuilder(getCTypeName(functionName));
             sb.append("(");
-            for (int i = 1; i < vl.getArgs().size(); i++) {
-                Term arg = vl.getArgs().get(i);
+            for (int i = 1; i < args.size(); i++) {
+                Term arg = args.get(i);
                 if (i > 1) {
                     sb.append(", ");
                 }
@@ -777,8 +798,8 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                     // "io" and "_value" are always available in every parser.
                     boolean isSerializerArg = "writeBuffer".equals(va.getName()) || "_value".equals(va.getName()) || "element".equals(va.getName());
                     boolean isTypeArg = "_type".equals(va.getName());
-                    if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
-                        for (Argument serializerArgument : serialzerArguments) {
+                    if (!isSerializerArg && !isTypeArg && serializerArguments != null) {
+                        for (Argument serializerArgument : serializerArguments) {
                             if (serializerArgument.getName().equals(va.getName())) {
                                 isSerializerArg = true;
                                 break;
@@ -786,17 +807,17 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                         }
                     }
                     if (isSerializerArg) {
-                        if("_value".equals(va.getName())) {
+                        if ("_value".equals(va.getName())) {
                             sb.append("_message");
                         } else {
                             sb.append(va.getName());
                         }
-                        if(va.getChild() != null) {
+                        if (va.getChild().isPresent()) {
                             sb.append("->");
-                            appendVariableExpressionRest(sb, baseType, va.getChild());
+                            appendVariableExpressionRest(sb, baseType, va.getChild().get());
                         }
                     } else if (isTypeArg) {
-                        String part = va.getChild().getName();
+                        String part = va.getChild().get().getName();
                         switch (part) {
                             case "name":
                                 sb.append("\"").append(field.getTypeName()).append("\"");
@@ -805,11 +826,11 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                                 sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
                                 break;
                             case "encoding":
-                                if(!(field instanceof TypedField)) {
+                                if (!(field instanceof TypedField)) {
                                     throw new FreemarkerException("'encoding' only supported for typed fields.");
                                 }
                                 TypedField typedField = (TypedField) field;
-                                if(!(typedField.getType() instanceof StringTypeReference)) {
+                                if (!(typedField.getType() instanceof StringTypeReference)) {
                                     throw new FreemarkerException("Can only access 'encoding' for string types.");
                                 }
                                 StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
@@ -832,10 +853,10 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         // All uppercase names are not fields, but utility methods.
         else if (vl.getName().equals(vl.getName().toUpperCase())) {
             StringBuilder sb = new StringBuilder("plc4c_spi_evaluation_helper_" + vl.getName().toLowerCase());
-            if (vl.getArgs() != null) {
+            if (vl.getArgs().isPresent()) {
                 sb.append("(");
                 boolean firstArg = true;
-                for (Term arg : vl.getArgs()) {
+                for (Term arg : vl.getArgs().get()) {
                     if (!firstArg) {
                         sb.append(", ");
                     }
@@ -844,8 +865,8 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                         VariableLiteral va = (VariableLiteral) arg;
                         boolean isSerializerArg = "io".equals(va.getName());
                         boolean isTypeArg = "_type".equals(va.getName());
-                        if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
-                            for (Argument serializerArgument : serialzerArguments) {
+                        if (!isSerializerArg && !isTypeArg && serializerArguments != null) {
+                            for (Argument serializerArgument : serializerArguments) {
                                 if (serializerArgument.getName().equals(va.getName())) {
                                     isSerializerArg = true;
                                     break;
@@ -854,12 +875,12 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                         }
                         if (isSerializerArg) {
                             sb.append(va.getName());
-                            if(va.getChild() != null) {
+                            if (va.getChild().isPresent()) {
                                 sb.append(".");
-                                appendVariableExpressionRest(sb, baseType, va.getChild());
+                                appendVariableExpressionRest(sb, baseType, va.getChild().get());
                             }
                         } else if (isTypeArg) {
-                            String part = va.getChild().getName();
+                            String part = va.getChild().get().getName();
                             switch (part) {
                                 case "name":
                                     sb.append("\"").append(field.getTypeName()).append("\"");
@@ -868,11 +889,11 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                                     sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
                                     break;
                                 case "encoding":
-                                    if(!(field instanceof TypedField)) {
+                                    if (!(field instanceof TypedField)) {
                                         throw new FreemarkerException("'encoding' only supported for typed fields.");
                                     }
                                     TypedField typedField = (TypedField) field;
-                                    if(!(typedField.getType() instanceof StringTypeReference)) {
+                                    if (!(typedField.getType() instanceof StringTypeReference)) {
                                         throw new FreemarkerException("Can only access 'encoding' for string types.");
                                     }
                                     StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
@@ -896,13 +917,13 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         }
         // If we are accessing implicit fields, we need to rely on a local variable instead.
         if (isVariableLiteralImplicitField(vl)) {
-            return toSerializationExpression(getThisTypeDefinition(), getReferencedImplicitField(vl), getReferencedImplicitField(vl).getSerializeExpression(), serialzerArguments);
+            return toSerializationExpression(thisType, getReferencedImplicitField(vl), getReferencedImplicitField(vl).getSerializeExpression(), serializerArguments);
         }
         // The synthetic checksumRawData is a local field and should not be accessed as bean property.
         boolean isSerializerArg = "checksumRawData".equals(vl.getName()) || "_value".equals(vl.getName()) || "element".equals(vl.getName()) || "size".equals(vl.getName());
         boolean isTypeArg = "_type".equals(vl.getName());
-        if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
-            for (Argument serializerArgument : serialzerArguments) {
+        if (!isSerializerArg && !isTypeArg && serializerArguments != null) {
+            for (Argument serializerArgument : serializerArguments) {
                 if (serializerArgument.getName().equals(vl.getName())) {
                     isSerializerArg = true;
                     break;
@@ -911,24 +932,24 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         }
         if (isSerializerArg) {
             StringBuilder sb = new StringBuilder(vl.getName());
-            if(vl.getChild() != null) {
+            if (vl.getChild().isPresent()) {
                 sb.append(".");
-                appendVariableExpressionRest(sb, baseType, vl.getChild());
+                appendVariableExpressionRest(sb, baseType, vl.getChild().get());
             }
             return sb.toString();
         } else if (isTypeArg) {
-            String part = vl.getChild().getName();
+            String part = vl.getChild().get().getName();
             switch (part) {
                 case "name":
                     return "\"" + field.getTypeName() + "\"";
                 case "length":
                     return "\"" + ((SimpleTypeReference) field).getSizeInBits() + "\"";
                 case "encoding":
-                    if(!(field instanceof TypedField)) {
+                    if (!(field instanceof TypedField)) {
                         throw new FreemarkerException("'encoding' only supported for typed fields.");
                     }
                     TypedField typedField = (TypedField) field;
-                    if(!(typedField.getType() instanceof StringTypeReference)) {
+                    if (!(typedField.getType() instanceof StringTypeReference)) {
                         throw new FreemarkerException("Can only access 'encoding' for string types.");
                     }
                     StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
@@ -942,33 +963,29 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
         } else {
             // If it wasn't an enum, treat it as a normal property.
             if (vl.getName().equals("lengthInBits")) {
-                StringBuilder sb = new StringBuilder(getCTypeName(baseType.getName()));
-                sb.append("_length_in_bits(_message)");
-                return sb.toString();
-            } else if (vl.getChild() != null && "length".equals(vl.getChild().getName())) {
-                StringBuilder sb = new StringBuilder("");
-                sb.append("sizeof(_message->" + camelCaseToSnakeCase(vl.getName()) + ")");
-                return sb.toString();
+                return getCTypeName(baseType.getName()) + "_length_in_bits(_message)";
+            } else if (vl.getChild().isPresent() && "length".equals(vl.getChild().get().getName())) {
+                return "sizeof(_message->" + camelCaseToSnakeCase(vl.getName()) + ")";
             } else {
                 StringBuilder sb = new StringBuilder("_message->");
                 // If this is a property of a sub-type, add the sub-type name to the property.
-                if(baseType != getThisTypeDefinition()) {
+                if (baseType != thisType) {
                     sb.append(camelCaseToSnakeCase(baseType.getName())).append("_");
                 }
 
                 // If this expression references enum constants we need to do things differently
                 final Optional<TypeReference> typeReferenceForProperty =
                     getTypeReferenceForProperty((ComplexTypeDefinition) baseType, vl.getName());
-                if(typeReferenceForProperty.isPresent()) {
+                if (typeReferenceForProperty.isPresent()) {
                     final TypeReference typeReference = typeReferenceForProperty.get();
-                    if(typeReference instanceof ComplexTypeReference) {
+                    if (typeReference instanceof ComplexTypeReference) {
                         final TypeDefinition typeDefinitionForTypeReference =
                             getTypeDefinitionForTypeReference(typeReference);
-                        if ((typeDefinitionForTypeReference instanceof EnumTypeDefinition) && (vl.getChild() != null)){
+                        if ((typeDefinitionForTypeReference instanceof EnumTypeDefinition) && (vl.getChild().isPresent())) {
                             sb.append(camelCaseToSnakeCase(vl.getName()));
                             return getCTypeName(typeDefinitionForTypeReference.getName()) +
-                                "_get_" + camelCaseToSnakeCase(vl.getChild().getName()) +
-                                "(" + sb.toString() + ")";
+                                "_get_" + camelCaseToSnakeCase(vl.getChild().get().getName()) +
+                                "(" + sb + ")";
                         }
                     }
                 }
@@ -980,7 +997,7 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
     }
 
     private void appendVariableExpressionRest(StringBuilder sb, TypeDefinition baseType, VariableLiteral vl) {
-        if(vl.isIndexed()) {
+        if (vl.isIndexed()) {
             sb.insert(0, "plc4c_utils_list_get_value(");
             sb.append(camelCaseToSnakeCase(vl.getName()));
             sb.append(", ").append(vl.getIndex()).append(")");
@@ -988,9 +1005,9 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
             sb.append(camelCaseToSnakeCase(vl.getName()));
         }
         // Suppress any "lengthInBytes" properties as these are handled differently in C
-        if((vl.getChild() != null) && !vl.getChild().getName().equals("lengthInBytes")) {
+        if ((vl.getChild().isPresent()) && !vl.getChild().get().getName().equals("lengthInBytes")) {
             sb.append(".");
-            appendVariableExpressionRest(sb, baseType, vl.getChild());
+            appendVariableExpressionRest(sb, baseType, vl.getChild().get());
         }
     }
 
@@ -1019,10 +1036,10 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
     }
 
     public String getLengthInBitsFunctionNameForComplexTypedField(Field field) {
-        if(field instanceof TypedField) {
+        if (field instanceof TypedField) {
             TypedField typedField = (TypedField) field;
             final TypeReference typeReference = typedField.getType();
-            if(typeReference instanceof ComplexTypeReference) {
+            if (typeReference instanceof ComplexTypeReference) {
                 ComplexTypeReference complexTypeReference = (ComplexTypeReference) typeReference;
                 return getCTypeName(complexTypeReference.getName()) + "_length_in_bits";
             } else {
diff --git a/code-generation/language-c/src/main/resources/templates/c/data-io-template.c.ftlh b/code-generation/language-c/src/main/resources/templates/c/data-io-template.c.ftlh
index 1be76ce..82497ea 100644
--- a/code-generation/language-c/src/main/resources/templates/c/data-io-template.c.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/data-io-template.c.ftlh
@@ -23,24 +23,8 @@
 <#-- @ftlvariable name="protocolName" type="java.lang.String" -->
 <#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.c.CLanguageTemplateHelper" -->
-<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.DataIoTypeDefinition" -->
 <#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(type.name)}.c
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -72,64 +56,67 @@
 
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 // Parse function.
-plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if type.parserArguments?has_content><#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>plc4c_data** data_item) {
+plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if parserArguments?has_content><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>plc4c_data** data_item) {
     uint16_t startPos = plc4c_spi_read_get_pos(readBuffer);
     uint16_t curPos;
     plc4c_return_code _res = OK;
 
     <#list type.switchField.cases as case>
-        <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if><#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>strcmp(${helper.toParseExpression(type, null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)}, "${discriminatorValue}") == 0<#else>${helper.toParseExpression(type, null [...]
+        <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if><#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>strcmp(${helper.toParseExpression(type, null, type.switchField.discriminatorExpressions[discriminatorValue?index], parserArguments)}, "${discriminatorValue}") == 0<#else>${helper.toParseExpression(type, null, typ [...]
 <#--        (*_message)->_type = ${helper.getCTypeName(type.name)}_type_${helper.getCTypeName(case.name)};-->
         <#assign skipReturn=false>
         <#list case.fields as field>
             <#switch field.typeName>
                 <#case "array">
+                    <#assign arrayField = field.asArrayField().orElseThrow()>
 
-        // Array field (${field.name})
+        // Array field (${arrayField.name})
                 <#-- Only update curPos if the length expression uses it -->
-                    <#if field.loopExpression.contains("curPos")>
+                    <#if arrayField.loopExpression.contains("curPos")>
         curPos = readBuffer.getPos() - startPos;
                     </#if>
                 <#-- If this is a count array, we can directly initialize an array with the given size -->
-                    <#if helper.isCountArrayField(field)>
+                    <#if helper.isCountArrayField(arrayField)>
         // Count array
-        plc4c_list* ${field.name};
-        plc4c_utils_list_create(&${field.name});
-        int itemCount = (int) ${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)};
+        plc4c_list* ${arrayField.name};
+        plc4c_utils_list_create(&${arrayField.name});
+        int itemCount = (int) ${helper.toParseExpression(type, arrayField, arrayField.loopExpression, parserArguments)};
         for(int curItem = 0; curItem < itemCount; curItem++) {
-            ${helper.getLanguageTypeNameForTypeReference(field.type)}* _val = malloc(sizeof(${helper.getLanguageTypeNameForTypeReference(field.type)}) * 1);
-            _res = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type, "_val", field)}<#else>${field.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(type, field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+            ${helper.getLanguageTypeNameForTypeReference(arrayField.type)}* _val = malloc(sizeof(${helper.getLanguageTypeNameForTypeReference(arrayField.type)}) * 1);
+            _res = <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "_val", arrayField)}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index))}) (${helper.t [...]
             if(_res != OK) {
                 return _res;
             }
-            plc4c_data* _item = plc4c_data_create_${helper.getLanguageTypeNameForTypeReference(field.type)}_data(*_val);
-            plc4c_utils_list_insert_head_value(${field.name}, _item);
+            plc4c_data* _item = plc4c_data_create_${helper.getLanguageTypeNameForTypeReference(arrayField.type)}_data(*_val);
+            plc4c_utils_list_insert_head_value(${arrayField.name}, _item);
         }
                     <#-- In all other cases do we have to work with a list, that is later converted to an array -->
                     <#else>
                     <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-                        <#if helper.isLengthArrayField(field)>
+                        <#if helper.isLengthArrayField(arrayField)>
         // Length array
-        int _${field.name}Length = ${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)};
-        List<${helper.getLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        int ${field.name}EndPos = readBuffer.getPos() + _${field.name}Length;
-        while(readBuffer.getPos() < ${field.name}EndPos) {
-            _${field.name}List.add(<#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type, null, field)}<#else>${field.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(type, field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>);
+        int _${arrayField.name}Length = ${helper.toParseExpression(type, arrayField, arrayField.loopExpression, parserArguments)};
+        List<${helper.getLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
+        int ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
+        while(readBuffer.getPos() < ${arrayField.name}EndPos) {
+            _${arrayField.name}List.add(<#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), null, arrayField)}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if field.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index))}) ($ [...]
                         <#-- After parsing, update the current position, but only if it's needed -->
-                            <#if field.loopExpression.contains("curPos")>
+                            <#if arrayField.loopExpression.contains("curPos")>
             curPos = readBuffer.getPos() - startPos;
                             </#if>
         }
                         <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-                        <#elseif helper.isTerminatedArrayField(field)>
+                        <#elseif helper.isTerminatedArrayField(arrayField)>
         // Terminated array
-        List<${helper.getLanguageTypeNameForField(field)}> _${field.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toParseExpression(type, field, field.loopExpression, type.parserArguments)}))) {
-            _${field.name}List.add(<#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(type, field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>);
+        List<${helper.getLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
+        while(!((boolean) (${helper.toParseExpression(type, arrayField, arrayField.loopExpression, parserArguments)}))) {
+            _${arrayField.name}List.add(<#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow())}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index))}) (${helper. [...]
 
                         <#-- After parsing, update the current position, but only if it's needed -->
-                            <#if field.loopExpression.contains("curPos")>
+                            <#if arrayField.loopExpression.contains("curPos")>
             curPos = readBuffer.getPos() - startPos;
                             </#if>
         }
@@ -139,35 +126,38 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
                         type we have to iterate over it's elements and explicitly cast them.
                         Otherwise a simple toArray call is fine.
                     -->
-                        <#if helper.isSimpleTypeReference(field.type)>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = new ${helper.getLanguageTypeNameForField(field)}[_${field.name}List.size()];
-        for(int i = 0; i < _${field.name}List.size(); i++) {
-            ${field.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${field.name}List.get(i);
+                        <#if helper.isSimpleTypeReference(arrayField.type)>
+        ${helper.getLanguageTypeNameForField(arrayField)}[] ${arrayField.name} = new ${helper.getLanguageTypeNameForField(arrayField)}[_${arrayField.name}List.size()];
+        for(int i = 0; i < _${arrayField.name}List.size(); i++) {
+            ${arrayField.name}[i] = (${helper.getLanguageTypeNameForField(arrayField)}) _${arrayField.name}List.get(i);
         }
                         <#else>
-        ${helper.getLanguageTypeNameForField(field)}[] ${field.name} = _${field.name}List.toArray(new ${helper.getLanguageTypeNameForField(field)}[0]);
+        ${helper.getLanguageTypeNameForField(arrayField)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getLanguageTypeNameForField(arrayField)}[0]);
                         </#if>
                     </#if>
-        *data_item = plc4c_data_create_list_data(*${field.name});
+        *data_item = plc4c_data_create_list_data(*${arrayField.name});
 
                     <#break>
                 <#case "const">
+                    <#assign constField =  field.asConstField().orElseThrow()>
 
-                // Const Field (${field.name})
-                ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type)};
-                if(${field.name} != ${type.name}.${field.name?upper_case}) {
-                    throw new ParseException("Expected constant value " + ${type.name}.${field.name?upper_case} + " but got " + ${field.name});
+                // Const Field (${constField.name})
+                ${helper.getLanguageTypeNameForField(constField)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.type.asSimpleTypeReference().orElseThrow())};
+                if(${constField.name} != ${type.name}.${constField.name?upper_case}) {
+                    throw new ParseException("Expected constant value " + ${type.name}.${constField.name?upper_case} + " but got " + ${constField.name});
                 }
                     <#break>
                 <#case "enum">
+                    <#assign enumField =  field.asEnumField().orElseThrow()>
 
-                // Enum field (${field.name})
-                ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(field.type))});
+                // Enum field (${enumField.name})
+                ${helper.getLanguageTypeNameForField(enumField)} ${enumField.name} = ${helper.getLanguageTypeNameForField(enumField)}.valueOf(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type))});
                     <#break>
                 <#case "manual">
+                    <#assign manualField =  field.asManualField().orElseThrow()>
 
-                // Manual Field (${field.name})
-                ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(type, field, field.parseExpression, type.parserArguments)});
+                // Manual Field (${manualField.name})
+                ${helper.getLanguageTypeNameForField(manualField)} ${manualField.name} = (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(type, manualField, manualField.parseExpression, parserArguments)});
 
                     <#switch case.name>
                         <#--#case "Time">
@@ -183,60 +173,63 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
                 return new PlcStruct(${field.name});
                             <#break-->
                         <#case "STRING">
-                *data_item = plc4c_data_create_string_data(stringLength, ${field.name});
+                *data_item = plc4c_data_create_string_data(stringLength, ${manualField.name});
                             <#break>
                         <#default>
-                *data_item = plc4c_data_create_${case.name?lower_case}_data(${field.name});
+                *data_item = plc4c_data_create_${case.name?lower_case}_data(${manualField.name});
                     </#switch>
                     <#assign skipReturn=true>
 
                     <#break>
                 <#case "reserved">
+                    <#assign reservedField=field.asReservedField().orElseThrow()>
 
                 // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
                 {
-                    ${helper.getLanguageTypeNameForField(field)} _reserved = ${helper.getNullValueForTypeReference(field.type)};
-                    _res = ${helper.getReadBufferReadMethodCall(field.type, "&_reserved", field)};
+                    ${helper.getLanguageTypeNameForField(reservedField)} _reserved = ${helper.getNullValueForTypeReference(reservedField.type)};
+                    _res = ${helper.getReadBufferReadMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), "&_reserved", reservedField)};
                     if(_res != OK) {
                         return _res;
                     }
-                    if(_reserved != ${field.referenceValue}) {
-                      printf("Expected constant value '%d' but got '%d' for reserved field.", ${field.referenceValue}, _reserved);
+                    if(_reserved != ${reservedField.referenceValue}) {
+                      printf("Expected constant value '%d' but got '%d' for reserved field.", ${reservedField.referenceValue}, _reserved);
                     }
                 }
                     <#break>
                 <#case "simple">
+                    <#assign simpleField=field.asSimpleField().orElseThrow()>
 
-                // Simple Field (${field.name})
+                // Simple Field (${simpleField.name})
                 <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) -->
-                <#if helper.isSimpleTypeReference(field.type)>
-                ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForTypeReference(field.type)};
-                _res = ${helper.getReadBufferReadMethodCall(field.type, "&" + field.name, field)};
+                <#if helper.isSimpleTypeReference(simpleField.type)>
+                ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = ${helper.getNullValueForTypeReference(simpleField.type)};
+                _res = ${helper.getReadBufferReadMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "&" + simpleField.name, simpleField)};
                 <#else>
                 <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) -->
-                ${helper.getLanguageTypeNameForField(field)}* ${field.name};
-                _res = ${helper.getCTypeName(field.type.name)}_parse(readBuffer<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${field.name});
+                ${helper.getLanguageTypeNameForField(simpleField)}* ${simpleField.name};
+                _res = ${helper.getCTypeName(simpleField.type.asComplexTypeReference().orElseThrow().name)}_parse(readBuffer<#if simpleField.params.isPresent()>, <#list simpleField.params.orElseThrow() as parserTerm>${helper.toParseExpression(type, simpleField, parserTerm, parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${simpleField.name});
                 </#if>
                 if(_res != OK) {
                     return _res;
                 }
 
                 <#if case.name == "BitString">
-                *data_item = plc4c_data_create_${helper.getLanguageTypeNameForField(field)}_bit_string_data(${field.name});
+                *data_item = plc4c_data_create_${helper.getLanguageTypeNameForField(field)}_bit_string_data(${simpleField.name});
                 <#else>
                     // Hurz
-                *data_item = plc4c_data_create_${helper.getLanguageTypeNameForField(field)}_data(${field.name});
+                *data_item = plc4c_data_create_${helper.getLanguageTypeNameForField(field)}_data(${simpleField.name});
                 </#if>
 
                     <#break>
             </#switch>
         </#list>
     }<#sep> else </#sep></#list>
+    </#if>
 
   return OK;
 }
 
-plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, plc4c_data** data_item<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) {
+plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, plc4c_data** data_item<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) {
   plc4c_return_code _res = OK;
 
   return OK;
@@ -252,5 +245,4 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(plc4c_data* data_item)
   return lengthInBits;
 }
 
-</#if>
 </#outputformat>
\ No newline at end of file
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 8e45f05..53303c2 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
@@ -23,7 +23,8 @@
 <#-- @ftlvariable name="protocolName" type="java.lang.String" -->
 <#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.c.CLanguageTemplateHelper" -->
-<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.DataIoTypeDefinition" -->
 <#-- Declare the name and type of variables declared locally inside the template -->
 <#-- @ftlvariable name="field" type="org.apache.plc4x.plugins.codegenerator.types.fields.NamedField" -->
 <#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(type.name)}.h
@@ -65,6 +66,8 @@
 
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -72,12 +75,12 @@ extern "C" {
 <#--
     Define the parse-method for elements of this tpye
 -->
-plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if type.parserArguments?has_content><#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>plc4c_data** data_item);
+plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if parserArguments?has_content><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>plc4c_data** data_item);
 
 <#--
     Define the serialize-method for elements of this tpye
 -->
-plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, plc4c_data** data_item<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>);
+plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, plc4c_data** data_item<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>);
 
 uint16_t ${helper.getCTypeName(type.name)}_length_in_bytes(plc4c_data* data_item);
 
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 9603e0e..8ef9029 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
@@ -18,6 +18,9 @@
 -->
 ${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(typeName)}.c
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.c.CLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -68,7 +71,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
         return NO_MEMORY;
     }
 
-    _res = ${helper.getReadBufferReadMethodCall(type.type, "*_message", null)?no_esc};
+    _res = ${helper.getReadBufferReadMethodCall(type.type.asSimpleTypeReference().orElseThrow(), "*_message", null)?no_esc};
 
     return _res;
 }
@@ -76,7 +79,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, ${helper.getCTypeName(type.name)}* _message) {
     plc4c_return_code _res = OK;
 
-    _res = ${helper.getWriteBufferWriteMethodCall(type.type, "*_message", null)?no_esc};
+    _res = ${helper.getWriteBufferWriteMethodCall(type.type.asSimpleTypeReference().orElseThrow(), "*_message", null)?no_esc};
 
     return _res;
 }
@@ -118,7 +121,7 @@ ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))
   switch(value) {
         <#list helper.getUniqueEnumValues(type.enumValues) as enumValue>
     case ${helper.getCTypeName(type.name)}_${enumValue.name}: { /* '${enumValue.value}' */
-      return <#if helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName)) == '-1'>-1<#elseif helper.isComplexTypeReference(type.getConstantType(constantName))><#if helper.isEnumTypeReference(type.getConstantType(constantName))>${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))}_${helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName))}<#else>${helper.escapeEnumValue(type.getConstantType( [...]
+      return <#if helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow()) == '-1'>-1<#elseif helper.isComplexTypeReference(type.getConstantType(constantName))><#if helper.isEnumTypeReference(type.getConstantType(constantName))>${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))}_${helper.escapeValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())}<#else>${helper.escapeEnu [...]
     }<#sep>
     </#sep></#list>
 
@@ -131,14 +134,14 @@ ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))
 ${helper.getCTypeName(type.name)} ${helper.getCTypeName(type.name)}_get_first_enum_for_field_${helper.camelCaseToSnakeCase(constantName)}(${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))} value) {
     <#if helper.isStringTypeReference(type.getConstantType(constantName))>
         <#list helper.getEnumValuesForUniqueConstantValues(type.enumValues, constantName) as enumValue>
-    if (strcmp(value, ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName))?no_esc}) == 0) {
+    if (strcmp(value, ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())?no_esc}) == 0) {
         return ${helper.getCTypeName(type.name)}_${enumValue.name};
     }
         </#list>
     <#else>
     switch(value) {
     <#list helper.getEnumValuesForUniqueConstantValues(type.enumValues, constantName) as enumValue>
-        case ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName))?no_esc}: {
+        case ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())?no_esc}: {
             return ${helper.getCTypeName(type.name)}_${enumValue.name};
         }
     </#list>
@@ -156,5 +159,5 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bytes(${helper.getCTypeName
 }
 
 uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(type.name)}* _message) {
-    return ${type.type.sizeInBits};
+    return ${type.type.asSimpleTypeReference().orElseThrow().sizeInBits};
 }
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 63d259c..e95aff3 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
@@ -17,6 +17,9 @@
   under the License.
 -->
 ${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(typeName)}.h
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.c.CLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
diff --git a/code-generation/language-c/src/main/resources/templates/c/pojo-template.c.ftlh b/code-generation/language-c/src/main/resources/templates/c/pojo-template.c.ftlh
index ad00410..6fbecca 100644
--- a/code-generation/language-c/src/main/resources/templates/c/pojo-template.c.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/pojo-template.c.ftlh
@@ -23,24 +23,8 @@
 <#-- @ftlvariable name="protocolName" type="java.lang.String" -->
 <#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.c.CLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
 <#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(type.name)}.c
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -67,6 +51,8 @@
 
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 <#-- Helper function to get the discriminator for a given enum type constant -->
 <#if helper.isDiscriminatedParentTypeDefinition(type)>
 // Array of discriminator values that match the enum type constants.
@@ -82,7 +68,8 @@ const ${helper.getCTypeName(type.name)}_discriminator ${helper.getCTypeName(type
                 .${key} = <#if value??>${value}<#else>-1</#if><#sep>,
                    <#else>
                 .${key} = <#if value??>${helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[key])}_${value}<#else>-1</#if><#sep>,
-                   </#if></#list>}<#sep >,
+                   </#if>
+               </#list>}<#sep >,
             </...@compress>
 
         </#list>
@@ -115,7 +102,7 @@ ${helper.getLanguageTypeNameForField(constField)} ${helper.getCTypeName(parentTy
 </#if>
 
 // Parse function.
-plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if type.parserArguments?has_content><#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>${helper.getCTypeName(type.name)}** _message) {
+plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if parserArguments?has_content><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>${helper.getCTypeName(type.name)}** _message) {
   uint16_t startPos = plc4c_spi_read_get_pos(readBuffer);
   uint16_t curPos;
   plc4c_return_code _res = OK;
@@ -127,9 +114,15 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
   }
 <#macro fieldName baseType field>${helper.getFieldName(baseType, field)}</#macro>
 <#macro fieldParser baseType field indentContent>
+    <#-- @ftlvariable name="baseType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+    <#-- @ftlvariable name="field" type="org.apache.plc4x.plugins.codegenerator.types.fields.Field" -->
+    <#-- @ftlvariable name="indentContent" type="java.lang.Boolean" -->
+    <#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+    <#if baseType.parserArguments.isPresent()><#assign parserArguments=baseType.parserArguments.orElseThrow()></#if>
     <#switch field.typeName>
         <#case "array">
-            <#assign arrayField = field>
+            <#assign arrayField = field.asArrayField().orElseThrow()>
+            <#-- @ftlvariable name="field" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
 
 <#if indentContent>  </#if>  // Array field (${arrayField.name})
             <#-- Only update curPos if the length expression uses it -->
@@ -145,7 +138,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  {
             <#if helper.isCountArrayField(field)>
 <#if indentContent>  </#if>    // Count array
-<#if indentContent>  </#if>    uint16_t itemCount = (uint16_t) ${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, baseType.parserArguments)};
+<#if indentContent>  </#if>    uint16_t itemCount = (uint16_t) ${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, parserArguments)};
 <#if indentContent>  </#if>    for(int curItem = 0; curItem < itemCount; curItem++) {
 <#if indentContent>  </#if>      <#if !helper.isSimpleTypeReference(arrayField.type)>bool lastItem = curItem == (itemCount - 1);</#if>
       <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) -->
@@ -159,7 +152,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#else>
       <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) -->
 <#if indentContent>  </#if>      ${helper.getCTypeName(arrayField.type.name)}* _value = NULL;
-<#if indentContent>  </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_parse(readBuffer<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &_value);
+<#if indentContent>  </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_parse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &_value);
 <#if indentContent>  </#if>      if(_res != OK) {
 <#if indentContent>  </#if>        return _res;
 <#if indentContent>  </#if>      }
@@ -167,15 +160,15 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 </#if>
 <#if indentContent>  </#if>    }
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-            <#elseif helper.isLengthArrayField(field)>
+            <#elseif helper.isLengthArrayField(arrayField)>
 <#if indentContent>  </#if>    // Length array
-<#if indentContent>  </#if>    uint8_t _${arrayField.name}Length = ${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, baseType.parserArguments)};
+<#if indentContent>  </#if>    uint8_t _${arrayField.name}Length = ${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, parserArguments)};
 <#if indentContent>  </#if>    uint8_t ${arrayField.name}EndPos = plc4c_spi_read_get_pos(readBuffer) + _${arrayField.name}Length;
 <#if indentContent>  </#if>    while(plc4c_spi_read_get_pos(readBuffer) < ${arrayField.name}EndPos) {
                 <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) -->
 <#if helper.isSimpleTypeReference(arrayField.type)>
 <#if indentContent>  </#if>      ${helper.getLanguageTypeNameForTypeReference(arrayField.type)} _value = ${helper.getNullValueForTypeReference(arrayField.type)};
-<#if indentContent>  </#if>      _res = ${helper.getReadBufferReadMethodCall(arrayField.type, "&_value", field)};
+<#if indentContent>  </#if>      _res = ${helper.getReadBufferReadMethodCall(arrayField.type, "&_value", arrayField)};
 <#if indentContent>  </#if>      if(_res != OK) {
 <#if indentContent>  </#if>        return _res;
 <#if indentContent>  </#if>      }
@@ -183,7 +176,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#else>
                 <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) -->
 <#if indentContent>  </#if>      ${helper.getCTypeName(arrayField.type.name)}* _value = NULL;
-<#if indentContent>  </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_parse(readBuffer<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &_value);
+<#if indentContent>  </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_parse(readBuffer<#if field.params.isPresent()>, <#list field.params.orElseThrow() as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &_value);
 <#if indentContent>  </#if>      if(_res != OK) {
 <#if indentContent>  </#if>        return _res;
 <#if indentContent>  </#if>      }
@@ -195,9 +188,9 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
                 </#if>
 <#if indentContent>  </#if>    }
             <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-            <#elseif helper.isTerminatedArrayField(field)>
+            <#elseif helper.isTerminatedArrayField(arrayField)>
 <#if indentContent>  </#if>    // Terminated array
-<#if indentContent>  </#if>    while(!((boolean) (${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, baseType.parserArguments)}))) {
+<#if indentContent>  </#if>    while(!((boolean) (${helper.toParseExpression(baseType, arrayField, arrayField.loopExpression, parserArguments)}))) {
             <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) -->
 <#if helper.isSimpleTypeReference(arrayField.type)>
 <#if indentContent>  </#if>      ${helper.getLanguageTypeNameForTypeReference(arrayField.type)} _value = ${helper.getNullValueForTypeReference(arrayField.type)};
@@ -209,7 +202,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#else>
                 <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) -->
 <#if indentContent>  </#if>      ${helper.getCTypeName(arrayField.type.name)}* _value = NULL;
-<#if indentContent>  </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_parse(readBuffer<#if field.params?has_content>, <#list field.params as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &_value);
+<#if indentContent>  </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_parse(readBuffer<#if field.params.isPresent()>, <#list field.params.orElseThrow() as parserTerm>${helper.toParseExpression(baseType, field, parserTerm, parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &_value);
 <#if indentContent>  </#if>      if(_res != OK) {
 <#if indentContent>  </#if>        return _res;
 <#if indentContent>  </#if>      }
@@ -225,8 +218,8 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  (*_message)-><@fieldName baseType=baseType field=arrayField/> = ${arrayField.name};
             <#break>
         <#case "checksum">
-            <#assign checksumField = field>
-            <#assign simpleTypeReference = checksumField.type>
+            <#assign checksumField = field.asChecksumField().orElseThrow()>
+            <#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
 
 <#if indentContent>  </#if>  // Checksum Field (${checksumField.name})
 <#if indentContent>  </#if>  {
@@ -237,7 +230,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>    if(_res != OK) {
 <#if indentContent>  </#if>      return _res;
 <#if indentContent>  </#if>    }
-<#if indentContent>  </#if>    ${helper.getLanguageTypeNameForField(field)} _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, checksumField, checksumField.checksumExpression, baseType.parserArguments)});
+<#if indentContent>  </#if>    ${helper.getLanguageTypeNameForField(field)} _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, checksumField, checksumField.checksumExpression, parserArguments)});
 <#if indentContent>  </#if>    if(_checksum != _checksumRef) {
 <#if indentContent>  </#if>      return PARSE_ERROR;
 <#if indentContent>  </#if>      // throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_checksumRef & 0xFFFF, _checksum & 0xFFFF));
@@ -245,8 +238,8 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  }
             <#break>
         <#case "const">
-            <#assign constField = field>
-            <#assign simpleTypeReference = constField.type>
+            <#assign constField = field.asConstField().orElseThrow()>
+            <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
 
 <#if indentContent>  </#if>  // Const Field (${constField.name})
 <#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getNullValueForTypeReference(constField.type)};
@@ -260,7 +253,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  }
             <#break>
         <#case "discriminator">
-            <#assign discriminatorField = field>
+            <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
         // Discriminator Field (${discriminatorField.name})
         <#if helper.isSimpleTypeReference(discriminatorField.type)>
             <#assign simpleTypeReference = discriminatorField.type>
@@ -278,18 +271,18 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  }
             <#break>
         <#case "enum">
-            <#assign enumField = field>
+            <#assign enumField = field.asEnumField().orElseThrow()>
 
 <#if indentContent>  </#if>  // Enum field (${enumField.name})
 <#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getNullValueForTypeReference(enumField.type)};
-            <#if enumField.fieldName?has_content>
+            <#if enumField.fieldName.isPresent()>
 <#if indentContent>  </#if>  {
-<#if indentContent>  </#if>    ${helper.getLanguageTypeNameForTypeReference(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName))} _constantValue = ${helper.getNullValueForTypeReference(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName))};
-<#if indentContent>  </#if>    _res = ${helper.getReadBufferReadMethodCall(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName), "&_constantValue", field)};
+<#if indentContent>  </#if>    ${helper.getLanguageTypeNameForTypeReference(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()))} _constantValue = ${helper.getNullValueForTypeReference(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()))};
+<#if indentContent>  </#if>    _res = ${helper.getReadBufferReadMethodCall(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()), "&_constantValue", field)};
 <#if indentContent>  </#if>    if(_res != OK) {
 <#if indentContent>  </#if>      return _res;
 <#if indentContent>  </#if>    }
-<#if indentContent>  </#if>    ${enumField.name} = ${helper.getLanguageTypeNameForTypeReference(enumField.type)}_get_first_enum_for_field_${helper.camelCaseToSnakeCase(enumField.fieldName)}(_constantValue);
+<#if indentContent>  </#if>    ${enumField.name} = ${helper.getLanguageTypeNameForTypeReference(enumField.type)}_get_first_enum_for_field_${helper.camelCaseToSnakeCase(enumField.fieldName.orElseThrow())}(_constantValue);
 <#if indentContent>  </#if>  }
             <#else>
 <#if indentContent>  </#if>  _res = ${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type), "&" + enumField.name, field)};
@@ -300,7 +293,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  (*_message)-><@fieldName baseType=baseType field=enumField/> = ${enumField.name};
             <#break>
         <#case "implicit">
-            <#assign implicitField = field>
+            <#assign implicitField = field.asImplicitField().orElseThrow()>
             <#assign simpleTypeReference = implicitField.type>
 
 <#if indentContent>  </#if>  // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
@@ -311,26 +304,26 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  }
             <#break>
         <#case "manualArray">
-            <#assign manualArrayField = field>
+            <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 
   <#-- TODO: Implement -->
             <#break>
         <#case "manual">
-            <#assign manualField = field>
+            <#assign manualField = field.asManualField().orElseThrow()>
 
 <#if indentContent>  </#if>  // Manual Field (${manualField.name})<#-- check if complex -->
-<#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, manualField, manualField.parseExpression, baseType.parserArguments)});
+<#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, manualField, manualField.parseExpression, parserArguments)});
 <#if indentContent>  </#if>  (*_message)-><@fieldName baseType=baseType field=manualField/> = ${manualField.name};
         <#break>
         <#case "optional">
-            <#assign optionalField = field>
+            <#assign optionalField = field.asOptionalField().orElseThrow()>
 
 <#if indentContent>  </#if>  // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false)
             <#if optionalField.conditionExpression.contains("curPos")>
 <#if indentContent>  </#if>  curPos = plc4c_spi_read_get_pos(readBuffer) - startPos;
             </#if>
 <#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)}* ${optionalField.name} = NULL;
-<#if indentContent>  </#if>  if(${helper.toParseExpression(baseType, field, optionalField.conditionExpression, baseType.parserArguments)}) {
+<#if indentContent>  </#if>  if(${helper.toParseExpression(baseType, field, optionalField.conditionExpression, parserArguments)}) {
         <#if helper.isSimpleTypeReference(optionalField.type)>
 <#if indentContent>  </#if>    ${optionalField.name} = malloc(sizeof(${helper.getLanguageTypeNameForField(field)}));
 <#if indentContent>  </#if>    if(${optionalField.name} == NULL) {
@@ -339,7 +332,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>    *${optionalField.name} = ${helper.getNullValueForTypeReference(optionalField.type)};
 <#if indentContent>  </#if>    _res = ${helper.getReadBufferReadMethodCall(optionalField.type, optionalField.name, field)};
         <#else>
-<#if indentContent>  </#if>    _res = ${helper.getCTypeName(optionalField.type.name)}_parse(readBuffer<#if optionalField.params?has_content>, <#list optionalField.params as parserTerm>${helper.toParseExpression(baseType, optionalField, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, &${optionalField.name});
+<#if indentContent>  </#if>    _res = ${helper.getCTypeName(optionalField.type.name)}_parse(readBuffer<#if optionalField.params.isPresent()>, <#list optionalField.params.orElseThrow() as parserTerm>${helper.toParseExpression(baseType, optionalField, parserTerm, parserArguments)}<#sep>, </#sep></#list></#if>, &${optionalField.name});
         </#if>
 <#if indentContent>  </#if>    if(_res != OK) {
 <#if indentContent>  </#if>      return _res;
@@ -350,12 +343,12 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  }
             <#break>
         <#case "padding">
-            <#assign paddingField = field>
+            <#assign paddingField = field.asPaddingField().orElseThrow()>
             <#assign simpleTypeReference = paddingField.type>
 
 <#if indentContent>  </#if>  // Padding Field (padding)
 <#if indentContent>  </#if>  {
-<#if indentContent>  </#if>    int _timesPadding = (int) ((plc4c_spi_read_has_more(readBuffer, ${helper.getNumBits(paddingField.type)})) && (${helper.toParseExpression(baseType, paddingField, paddingField.paddingCondition, baseType.parserArguments)}));
+<#if indentContent>  </#if>    int _timesPadding = (int) ((plc4c_spi_read_has_more(readBuffer, ${helper.getNumBits(paddingField.type)})) && (${helper.toParseExpression(baseType, paddingField, paddingField.paddingCondition, parserArguments)}));
 <#if indentContent>  </#if>    while (_timesPadding-- > 0) {
 <#if indentContent>  </#if>      // Just read the padding data and ignore it
 <#if indentContent>  </#if>      ${helper.getLanguageTypeNameForField(field)} _paddingValue = ${helper.getNullValueForTypeReference(paddingField.type)};
@@ -367,7 +360,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  }
             <#break>
         <#case "reserved">
-            <#assign reservedField = field>
+            <#assign reservedField = field.asReservedField().orElseThrow()>
             <#assign simpleTypeReference = reservedField.type>
 
 <#if indentContent>  </#if>  // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
@@ -383,7 +376,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  }
             <#break>
         <#case "simple">
-            <#assign simpleField = field>
+            <#assign simpleField = field.asSimpleField().orElseThrow()>
 
 <#if indentContent>  </#if>  // Simple Field (${simpleField.name})
             <#-- Inizialize a local variable with the simple type (Intentionally keeping the java-style names so they can be used in expressions) -->
@@ -393,7 +386,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
             <#else>
             <#-- Inizialize a local variable with the complex type (Intentionally keeping the java-style names so they can be used in expressions) -->
 <#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)}* ${simpleField.name};
-<#if indentContent>  </#if>  _res = ${helper.getCTypeName(simpleField.type.name)}_parse(readBuffer<#if simpleField.params?has_content>, <#list simpleField.params as parserTerm>${helper.toParseExpression(baseType, simpleField, parserTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${simpleField.name});
+<#if indentContent>  </#if>  _res = ${helper.getCTypeName(simpleField.type.name)}_parse(readBuffer<#if simpleField.params.isPresent()>, <#list simpleField.params.orElseThrow() as parserTerm>${helper.toParseExpression(baseType, simpleField, parserTerm, parserArguments)}<#sep>, </#sep></#list></#if>, (void*) &${simpleField.name});
             </#if>
 <#if indentContent>  </#if>  if(_res != OK) {
 <#if indentContent>  </#if>    return _res;
@@ -401,14 +394,14 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
 <#if indentContent>  </#if>  (*_message)-><@fieldName baseType=baseType field=simpleField/> = <#if helper.isEnumTypeReference(simpleField.type)>*</#if>${simpleField.name};
             <#break>
         <#case "switch">
-            <#assign switchField = field>
+            <#assign switchField = field.asSwitchField().orElseThrow()>
 
 <#if indentContent>  </#if>  // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
         <#list switchField.cases as case>
             <#if !helper.isComplexTypeReference(helper.getDiscriminatorTypes()[field.discriminatorExpressions[0].name])>
-<#if indentContent>  </#if>  <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if>${helper.toVariableParseExpression(baseType, switchField, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == ${discriminatorValue}<#if case.discriminatorValues?size &gt; 1>)</#if><#sep> && </#sep></#list>) </#if>{ /* ${case.name} */
+<#if indentContent>  </#if>  <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if>${helper.toVariableParseExpression(baseType, switchField, switchField.discriminatorExpressions[discriminatorValue?index], parserArguments)} == ${discriminatorValue}<#if case.discriminatorValues?size &gt; 1>)</#if><#sep> && </#sep></#list>) </#if>{ /* ${case.name} */
             <#else>
-<#if indentContent>  </#if>  <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if>${helper.toVariableParseExpression(baseType, switchField, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == ${helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[field.discriminatorExpressions[discriminatorValue?index].name])}_${discriminatorValue}<#if  [...]
+<#if indentContent>  </#if>  <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue><#if case.discriminatorValues?size &gt; 1>(</#if>${helper.toVariableParseExpression(baseType, switchField, switchField.discriminatorExpressions[discriminatorValue?index], parserArguments)} == ${helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[field.discriminatorExpressions[discriminatorValue?index].name])}_${discriminatorValue}<#if case. [...]
            </#if>
 <#if helper.isDiscriminatedChildTypeDefinition()>
     <#assign discriminatedChildType = type>
@@ -427,10 +420,10 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
             </#list>
             <#break>
         <#case "virtual">
-            <#assign virtualField = field>
+            <#assign virtualField = field.asVirtualField().orElseThrow()>
 
 <#if indentContent>  </#if>  // Virtual field (Just declare a local variable so we can access it in the parser)
-<#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, virtualField, virtualField.valueExpression, baseType.parserArguments)});
+<#if indentContent>  </#if>  ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, virtualField, virtualField.valueExpression, parserArguments)});
             <#break>
     </#switch>
 </#macro>
@@ -441,9 +434,14 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer*
   return OK;
 }
 
-plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, ${helper.getCTypeName(type.name)}* _message<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) {
+plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, ${helper.getCTypeName(type.name)}* _message<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) {
   plc4c_return_code _res = OK;
 <#macro fieldSerializer baseType field indentContent>
+    <#-- @ftlvariable name="baseType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+    <#-- @ftlvariable name="field" type="org.apache.plc4x.plugins.codegenerator.types.fields.Field" -->
+    <#-- @ftlvariable name="indentContent" type="boolean" -->
+    <#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+    <#if baseType.parserArguments.isPresent()><#assign parserArguments=baseType.parserArguments.orElseThrow()></#if>
     <#switch field.typeName>
         <#case "array">
             <#assign arrayField = field>
@@ -458,7 +456,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
             <#if helper.isSimpleTypeReference(arrayField.type)>
 <#if indentContent>    </#if>      ${helper.getWriteBufferWriteMethodCall(arrayField.type, "*_value", field)};
             <#else>
-<#if indentContent>    </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_serialize(writeBuffer, (void*) _value<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as serializerTerm>${helper.toSerializationExpression(baseType, field, serializerTerm, baseType.parserArguments)}<#sep>, </#sep></#list></#if>);
+<#if indentContent>    </#if>      _res = ${helper.getCTypeName(arrayField.type.name)}_serialize(writeBuffer, (void*) _value<#if helper.getSerializerTerms(field.params.orElse(null))?has_content>, <#list helper.getSerializerTerms(field.params.orElse(null)) as serializerTerm>${helper.toSerializationExpression(baseType, field, serializerTerm, parserArguments)}<#sep>, </#sep></#list></#if>);
 <#if indentContent>    </#if>      if(_res != OK) {
 <#if indentContent>    </#if>        return _res;
 <#if indentContent>    </#if>      }
@@ -475,7 +473,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
 <#if indentContent>    </#if>    // Create an array of all the bytes read in this message element so far.
 <#if indentContent>    </#if>    unsigned char checksumRawData[] = plc4c_spi_read_get_bytes(writeBuffer, startPos, plc4c_spi_read_get_pos(writeBuffer));
 <#if indentContent>    </#if>    ${helper.getLanguageTypeNameForField(field)} _checksumRef = ${helper.getReadBufferReadMethodCall(checksumField.type, field)};
-<#if indentContent>    </#if>    ${helper.getLanguageTypeNameForField(field)} _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, checksumField, checksumField.checksumExpression, baseType.parserArguments)});
+<#if indentContent>    </#if>    ${helper.getLanguageTypeNameForField(field)} _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(baseType, checksumField, checksumField.checksumExpression, parserArguments)});
 <#if indentContent>    </#if>    if(_checksum != _checksumRef) {
 <#if indentContent>    </#if>      return PARSE_ERROR;
 <#if indentContent>    </#if>      // throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X",_checksumRef & 0xFFFF, _checksum & 0xFFFF));
@@ -503,11 +501,11 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
         </#if>
             <#break>
         <#case "enum">
-            <#assign enumField = field>
+            <#assign enumField = field.asEnumField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Enum field (${enumField.name})
-                <#if enumField.fieldName?has_content>
-<#if indentContent>    </#if>  _res = ${helper.getWriteBufferWriteMethodCall(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName), helper.getLanguageTypeNameForTypeReference(enumField.type) + "_get_" + helper.camelCaseToSnakeCase(enumField.fieldName) + "(_message->" + helper.getFieldName(baseType, enumField) + ")", field)};
+                <#if enumField.fieldName.isPresent()>
+<#if indentContent>    </#if>  _res = ${helper.getWriteBufferWriteMethodCall(helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()), helper.getLanguageTypeNameForTypeReference(enumField.type) + "_get_" + helper.camelCaseToSnakeCase(enumField.fieldName.orElseThrow()) + "(_message->" + helper.getFieldName(baseType, enumField) + ")", field)};
 <#if indentContent>    </#if>  if(_res != OK) {
 <#if indentContent>    </#if>    return _res;
 <#if indentContent>    </#if>  }
@@ -519,11 +517,11 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
                 </#if>
             <#break>
         <#case "implicit">
-            <#assign implicitField = field>
-            <#assign simpleTypeReference = implicitField.type>
+            <#assign implicitField = field.asImplicitField().orElseThrow()>
+            <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
 <#if indentContent>    </#if>  // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-<#if indentContent>    </#if>  _res = ${helper.getWriteBufferWriteMethodCall(implicitField.type, helper.toSerializationExpression(baseType, implicitField, implicitField.serializeExpression, baseType.parserArguments), field)};
+<#if indentContent>    </#if>  _res = ${helper.getWriteBufferWriteMethodCall(simpleTypeReference, helper.toSerializationExpression(baseType, implicitField, implicitField.serializeExpression, parserArguments), field)};
 <#if indentContent>    </#if>  if(_res != OK) {
 <#if indentContent>    </#if>    return _res;
 <#if indentContent>    </#if>  }
@@ -534,23 +532,23 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
             <#-- TODO: Implement -->
             <#break>
         <#case "manual">
-            <#assign manualField = field>
+            <#assign manualField = field.asManualField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Manual Field (${manualField.name})<#if indentContent>    </#if>  {
-<#if indentContent>    </#if>  _res = ${helper.toSerializationExpression(baseType, manualField, manualField.serializeExpression, baseType.parserArguments)};
+<#if indentContent>    </#if>  _res = ${helper.toSerializationExpression(baseType, manualField, manualField.serializeExpression, parserArguments)};
 <#if indentContent>    </#if>  if(_res != OK) {
 <#if indentContent>    </#if>    return _res;
 <#if indentContent>    </#if>  }
             <#break>
         <#case "optional">
-            <#assign optionalField = field>
+            <#assign optionalField = field.asOptionalField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Optional Field (${optionalField.name})
 <#if indentContent>    </#if>  if(_message-><@fieldName baseType=baseType field=optionalField/> != NULL) {
             <#if helper.isSimpleTypeReference(optionalField.type)>
-<#if indentContent>    </#if>    _res = ${helper.getWriteBufferWriteMethodCall(optionalField.type, "*_message->" + helper.getFieldName(baseType, optionalField), field)};
+<#if indentContent>    </#if>    _res = ${helper.getWriteBufferWriteMethodCall(optionalField.type.asSimpleTypeReference().orElseThrow(), "*_message->" + helper.getFieldName(baseType, optionalField), field)};
             <#else>
-<#if indentContent>    </#if>    _res = ${helper.getCTypeName(optionalField.type.name)}_serialize(writeBuffer, _message-><@fieldName baseType=baseType field=optionalField/>);
+<#if indentContent>    </#if>    _res = ${helper.getCTypeName(optionalField.type.asComplexTypeReference().orElseThrow().name)}_serialize(writeBuffer, _message-><@fieldName baseType=baseType field=optionalField/>);
             </#if>
 <#if indentContent>    </#if>    if(_res != OK) {
 <#if indentContent>    </#if>      return _res;
@@ -558,16 +556,16 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
 <#if indentContent>    </#if>  }
             <#break>
         <#case "padding">
-            <#assign paddingField = field>
-            <#assign simpleTypeReference = paddingField.type>
+            <#assign paddingField = field.asPaddingField().orElseThrow()>
+            <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
 <#if indentContent>    </#if>  // Padding Field (padding)
 <#if indentContent>    </#if>  {
     <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last -->
-<#if indentContent>    </#if>    int _timesPadding = (int) (${helper.toSerializationExpression(baseType, paddingField, paddingField.paddingCondition, baseType.parserArguments)});
+<#if indentContent>    </#if>    int _timesPadding = (int) (${helper.toSerializationExpression(baseType, paddingField, paddingField.paddingCondition, parserArguments)});
 <#if indentContent>    </#if>    while (_timesPadding-- > 0) {
 <#if indentContent>    </#if>      // Just output the default padding data
-<#if indentContent>    </#if>      _res = ${helper.getWriteBufferWriteMethodCall(paddingField.type, helper.toParseExpression(baseType, paddingField, paddingField.paddingValue, baseType.parserArguments), field)};
+<#if indentContent>    </#if>      _res = ${helper.getWriteBufferWriteMethodCall(simpleTypeReference, helper.toParseExpression(baseType, paddingField, paddingField.paddingValue, parserArguments), field)};
 <#if indentContent>    </#if>      if(_res != OK) {
 <#if indentContent>    </#if>        return _res;
 <#if indentContent>    </#if>      }
@@ -575,17 +573,17 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
 <#if indentContent>    </#if>  }
             <#break>
         <#case "reserved">
-            <#assign reservedField = field>
-            <#assign simpleTypeReference = reservedField.type>
+            <#assign reservedField = field.asReservedField().orElseThrow()>
+            <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
 <#if indentContent>    </#if>  // Reserved Field
-<#if indentContent>    </#if>  _res = ${helper.getWriteBufferWriteMethodCall(reservedField.type, reservedField.referenceValue, field)};
+<#if indentContent>    </#if>  _res = ${helper.getWriteBufferWriteMethodCall(simpleTypeReference, reservedField.referenceValue, field)};
 <#if indentContent>    </#if>  if(_res != OK) {
 <#if indentContent>    </#if>    return _res;
 <#if indentContent>    </#if>  }
             <#break>
         <#case "simple">
-            <#assign simpleField = field>
+            <#assign simpleField = field.asSimpleField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Simple Field (${simpleField.name})
             <#if helper.isSimpleTypeReference(simpleField.type)>
@@ -598,7 +596,7 @@ plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_bu
 <#if indentContent>    </#if>  }
             <#break>
         <#case "switch">
-            <#assign switchField = field>
+            <#assign switchField = field.asSwitchField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Switch Field (Depending of the current type, serialize the sub-type elements)
 <#if indentContent>    </#if>  switch(_message->_type) {
@@ -628,9 +626,12 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bytes(${helper.getCTypeName
 
 uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(type.name)}* _message) {
     <#macro fieldSize baseType field indentContent>
+        <#-- @ftlvariable name="baseType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+        <#-- @ftlvariable name="field" type="org.apache.plc4x.plugins.codegenerator.types.fields.Field" -->
+        <#-- @ftlvariable name="indentContent" type="boolean" -->
         <#switch field.typeName>
             <#case "array">
-                <#assign arrayField = field>
+                <#assign arrayField = field.asArrayField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Array field
                 <#if helper.isSimpleTypeReference(arrayField.type)>
@@ -647,27 +648,27 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(
                 </#if>
                 <#break>
             <#case "checksum">
-                <#assign checksumField = field>
+                <#assign checksumField = field.asChecksumField().orElseThrow()>
                 <#assign simpleTypeReference = checksumField.type>
 
 <#if indentContent>    </#if>  // Checksum Field (checksum)
 <#if indentContent>    </#if>  lengthInBits += ${simpleTypeReference.sizeInBits};
                 <#break>
             <#case "const">
-                <#assign constField = field>
+                <#assign constField = field.asConstField().orElseThrow()>
                 <#assign simpleTypeReference = constField.type>
 
 <#if indentContent>    </#if>  // Const Field (${constField.name})
 <#if indentContent>    </#if>  lengthInBits += ${simpleTypeReference.sizeInBits};
                 <#break>
             <#case "discriminator">
-                <#assign discriminatorField = field>
+                <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Discriminator Field (${discriminatorField.name})
         <#if helper.isSimpleTypeReference(discriminatorField.type)>
-            <#assign simpleTypeReference = discriminatorField.type>
+            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
             <#if helper.getLanguageTypeNameForTypeReference(discriminatorField.type) = "String">
-<#if indentContent>    </#if>  lengthInBits +=  ${helper.toParseExpression(type, discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)};
+<#if indentContent>    </#if>  lengthInBits +=  ${helper.toParseExpression(type, discriminatorField, simpleTypeReference.getLengthExpression(), parserArguments)};
             <#else>
 <#if indentContent>    </#if>  lengthInBits += ${simpleTypeReference.sizeInBits};
             </#if>
@@ -678,14 +679,14 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(
         </#if>
                 <#break>
             <#case "enum">
-                <#assign enumField = field>
+                <#assign enumField = field.asEnumField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Enum Field (${enumField.name})
 <#if indentContent>    </#if>  lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
                 <#break>
             <#case "implicit">
-                <#assign implicitField = field>
-                <#assign simpleTypeReference = implicitField.type>
+                <#assign implicitField = field.asImplicitField().orElseThrow()>
+                <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
 <#if indentContent>    </#if>  // Implicit Field (${implicitField.name})
 <#if indentContent>    </#if>  lengthInBits += ${simpleTypeReference.sizeInBits};
@@ -694,16 +695,16 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(
                 <#assign manualArrayField = field>
 
 <#if indentContent>    </#if>  // Manual Array Field (${manualArrayField.name})
-<#if indentContent>    </#if>  lengthInBits += ${helper.toParseExpression(type, manualArrayField, manualArrayField.lengthExpression, type.parserArguments)} * 8;
+<#if indentContent>    </#if>  lengthInBits += ${helper.toParseExpression(type, manualArrayField, manualArrayField.lengthExpression, parserArguments)} * 8;
                 <#break>
             <#case "manual">
-                <#assign manualField = field>
+                <#assign manualField = field.asManualField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Manual Field (${manualField.name})
-<#if indentContent>    </#if>  lengthInBits += ${helper.toParseExpression(type, manualField, manualField.lengthExpression, type.parserArguments)} * 8;
+<#if indentContent>    </#if>  lengthInBits += ${helper.toParseExpression(type, manualField, manualField.lengthExpression, parserArguments)} * 8;
                 <#break>
             <#case "optional">
-                <#assign optionalField = field>
+                <#assign optionalField = field.asOptionalField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Optional Field (${optionalField.name})
 <#if indentContent>    </#if>  if(_message-><@fieldName baseType=baseType field=optionalField/> != NULL) {
@@ -716,25 +717,25 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(
 <#if indentContent>    </#if>  }
                 <#break>
             <#case "padding">
-                <#assign paddingField = field>
+                <#assign paddingField = field.asPaddingField().orElseThrow()>
                 <#assign simpleTypeReference = paddingField.type>
 
 <#if indentContent>    </#if>  // Padding Field (padding)
             <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last -->
-<#if indentContent>    </#if> int _needsPadding = (int) (${helper.toSerializationExpression(type, paddingField, paddingField.paddingCondition, type.parserArguments)?replace("lastItem", "false")});
+<#if indentContent>    </#if> int _needsPadding = (int) (${helper.toSerializationExpression(type, paddingField, paddingField.paddingCondition, parserArguments)?replace("lastItem", "false")});
 <#if indentContent>    </#if> while(_needsPadding-- > 0) {
 <#if indentContent>    </#if>    lengthInBits += ${simpleTypeReference.sizeInBits};
 <#if indentContent>    </#if>  }
                 <#break>
             <#case "reserved">
-                <#assign reservedField = field>
+                <#assign reservedField = field.asReservedField().orElseThrow()>
                 <#assign simpleTypeReference = reservedField.type>
 
 <#if indentContent>    </#if>  // Reserved Field (reserved)
 <#if indentContent>    </#if>  lengthInBits += ${simpleTypeReference.sizeInBits};
                 <#break>
             <#case "simple">
-                <#assign simpleField = field>
+                <#assign simpleField = field.asSimpleField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Simple field (${simpleField.name})
                 <#if helper.isSimpleTypeReference(simpleField.type)>
@@ -745,7 +746,7 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(
                 </#if>
                 <#break>
             <#case "switch">
-                <#assign switchField = field>
+                <#assign switchField = field.asSwitchField().orElseThrow()>
 
 <#if indentContent>    </#if>  // Depending of the current type, add the length of sub-type elements ...
 <#if indentContent>    </#if>  switch(_message->_type) {
@@ -763,7 +764,7 @@ uint16_t ${helper.getCTypeName(type.name)}_length_in_bits(${helper.getCTypeName(
 <#if indentContent>    </#if>  }
                 <#break>
             <#case "virtual">
-                <#assign virtualField = field>
+                <#assign virtualField = field.asVirtualField().orElseThrow()>
 
 <#if indentContent>    </#if>  // A virtual field doesn't have any in- or output.
                 <#break>
diff --git a/code-generation/language-c/src/main/resources/templates/c/pojo-template.h.ftlh b/code-generation/language-c/src/main/resources/templates/c/pojo-template.h.ftlh
index 47249d3..e15d9d4 100644
--- a/code-generation/language-c/src/main/resources/templates/c/pojo-template.h.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/pojo-template.h.ftlh
@@ -23,9 +23,10 @@
 <#-- @ftlvariable name="protocolName" type="java.lang.String" -->
 <#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.c.CLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
 <#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="field" type="org.apache.plc4x.plugins.codegenerator.types.fields.NamedField" -->
+<#-- @ftlvariable name="field" type="org.apache.plc4x.plugins.codegenerator.types.fields.Field" -->
 <#if !helper.isDiscriminatedChildTypeDefinition(type)>${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(type.name)}.h
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -73,6 +74,8 @@
 
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -133,8 +136,9 @@ struct ${helper.getCTypeName(type.name)} {
   /* Properties */
 <#list helper.getPropertyAndSwitchFields() as field>
     <#if helper.isSwitchField(field)>
+        <#assign switchField=field.asSwitchField().orElseThrow()>
   union {
-        <#list field.cases as case>
+        <#list switchField.cases as case>
             <#if case.propertyFields?has_content>
     struct { /* ${case.name} */
                 <#list case.propertyFields as caseField>
@@ -151,11 +155,14 @@ struct ${helper.getCTypeName(type.name)} {
         </#list>
   };
     <#elseif (helper.isSimpleTypeReference(field.type) || helper.isEnumField(field)) && !helper.isOptionalField(field) && !helper.isArrayField(field) && !helper.isManualArrayField(field)>
-  ${helper.getLanguageTypeNameForField(field)} ${helper.camelCaseToSnakeCase(field.name)}${helper.getTypeSizeForField(field)}<#if field.loopType??>${helper.getLoopExpressionSuffix(field)}</#if>;
+        <#assign namedField = field.asNamedField().orElseThrow()>
+  ${helper.getLanguageTypeNameForField(field)} ${helper.camelCaseToSnakeCase(namedField.name)}${helper.getTypeSizeForField(field.asTypedField().orElseThrow())}<#if field.loopType??>${helper.getLoopExpressionSuffix(field.asTypedField().orElseThrow())}</#if>;
     <#elseif helper.isArrayField(field) || helper.isManualArrayField(field)>
-  plc4c_list* ${helper.camelCaseToSnakeCase(field.name)};
+        <#assign namedField = field.asNamedField().orElseThrow()>
+  plc4c_list* ${helper.camelCaseToSnakeCase(namedField.name)};
     <#else>
-  ${helper.getLanguageTypeNameForField(field)}* ${helper.camelCaseToSnakeCase(field.name)};
+        <#assign namedField = field.asNamedField().orElseThrow()>
+  ${helper.getLanguageTypeNameForField(field)}* ${helper.camelCaseToSnakeCase(namedField.name)};
     </#if>
 </#list>
 };
@@ -167,12 +174,12 @@ ${helper.getCTypeName(type.name)} ${helper.getCTypeName(type.name)}_null();
 <#--
     Define the parse-method for elements of this tpye
 -->
-plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if type.parserArguments?has_content><#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>${helper.getCTypeName(type.name)}** message);
+plc4c_return_code ${helper.getCTypeName(type.name)}_parse(plc4c_spi_read_buffer* readBuffer, <#if parserArguments?has_content><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#if !helper.isSimpleTypeReference(parserArgument.type)>*</#if> ${parserArgument.name}<#sep>, </#list>, </#if>${helper.getCTypeName(type.name)}** message);
 
 <#--
     Define the serialize-method for elements of this tpye
 -->
-plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, ${helper.getCTypeName(type.name)}* message<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>);
+plc4c_return_code ${helper.getCTypeName(type.name)}_serialize(plc4c_spi_write_buffer* writeBuffer, ${helper.getCTypeName(type.name)}* message<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>);
 
 uint16_t ${helper.getCTypeName(type.name)}_length_in_bytes(${helper.getCTypeName(type.name)}* message);
 
diff --git a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
index 64be124..43234e9 100644
--- a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
+++ b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
@@ -239,22 +239,16 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         if (typeReference instanceof SimpleTypeReference) {
             SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
             switch (simpleTypeReference.getBaseType()) {
-                case BIT: {
+                case BIT:
                     return "false";
-                }
-                case BYTE: {
-                    return "0";
-                }
+                case BYTE:
                 case UINT:
-                case INT: {
+                case INT:
                     return "0";
-                }
-                case FLOAT: {
+                case FLOAT:
                     return "0.0";
-                }
-                case STRING: {
+                case STRING:
                     return "\"\"";
-                }
             }
         } else if (typeReference instanceof ComplexTypeReference) {
             return "0";
@@ -290,7 +284,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
     }
 
     public boolean needsPointerAccess(PropertyField field) {
-        return "optional".equals(field.getTypeName()) || (isComplexTypeReference(field.getType()) && !isEnumField(field));
+        return "optional".equals(field.getTypeName()) || (field.getType().isComplexTypeReference() && !isEnumField(field));
     }
 
     public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReference simpleTypeReference) {
@@ -426,7 +420,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
                 String encoding = ((stringTypeReference.getEncoding() != null) && (stringTypeReference.getEncoding().length() > 2)) ?
                     stringTypeReference.getEncoding().substring(1, stringTypeReference.getEncoding().length() - 1) : "UTF-8";
-                return "writeBuffer.WriteString(\"" + logicalName + "\", uint8(" + toSerializationExpression(field, stringTypeReference.getLengthExpression(), getThisTypeDefinition().getParserArguments()) + "), \"" +
+                return "writeBuffer.WriteString(\"" + logicalName + "\", uint8(" + toSerializationExpression(field, stringTypeReference.getLengthExpression(), thisType.getParserArguments().orElse(Collections.emptyList())) + "), \"" +
                     encoding + "\", " + fieldName + writerArgsString + ")";
             }
         }
@@ -459,35 +453,35 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         }
     }
 
-    public String toParseExpression(TypedField field, Term term, Argument[] parserArguments) {
+    public String toParseExpression(TypedField field, Term term, List<Argument> parserArguments) {
         return toTypedParseExpression((field != null) ? field.getType() : null, term, parserArguments);
     }
 
-    public String toSerializationExpression(TypedField field, Term term, Argument[] serializerArguments) {
+    public String toSerializationExpression(TypedField field, Term term, List<Argument> serializerArguments) {
         return toTypedSerializationExpression((field != null) ? field.getType() : null, term, serializerArguments);
     }
 
-    public String toBooleanParseExpression(Term term, Argument[] parserArguments) {
+    public String toBooleanParseExpression(Term term, List<Argument> parserArguments) {
         return toTypedParseExpression(new DefaultBooleanTypeReference(), term, parserArguments);
     }
 
-    public String toBooleanSerializationExpression(Term term, Argument[] serializerArguments) {
+    public String toBooleanSerializationExpression(Term term, List<Argument> serializerArguments) {
         return toTypedSerializationExpression(new DefaultBooleanTypeReference(), term, serializerArguments);
     }
 
-    public String toIntegerParseExpression(int sizeInBits, Term term, Argument[] parserArguments) {
+    public String toIntegerParseExpression(int sizeInBits, Term term, List<Argument> parserArguments) {
         return toTypedParseExpression(new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.UINT, sizeInBits), term, parserArguments);
     }
 
-    public String toIntegerSerializationExpression(int sizeInBits, Term term, Argument[] serializerArguments) {
+    public String toIntegerSerializationExpression(int sizeInBits, Term term, List<Argument> serializerArguments) {
         return toTypedSerializationExpression(new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.UINT, sizeInBits), term, serializerArguments);
     }
 
-    public String toTypedParseExpression(TypeReference fieldType, Term term, Argument[] parserArguments) {
-        return toExpression(fieldType, term, parserArguments, null, false, isComplexTypeReference(fieldType));
+    public String toTypedParseExpression(TypeReference fieldType, Term term, List<Argument> parserArguments) {
+        return toExpression(fieldType, term, parserArguments, null, false, fieldType != null && fieldType.isComplexTypeReference());
     }
 
-    public String toTypedSerializationExpression(TypeReference fieldType, Term term, Argument[] serializerArguments) {
+    public String toTypedSerializationExpression(TypeReference fieldType, Term term, List<Argument> serializerArguments) {
         return toExpression(fieldType, term, null, serializerArguments, true, false);
     }
 
@@ -501,7 +495,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         }
     }
 
-    private String toExpression(TypeReference fieldType, Term term, Argument[] parserArguments, Argument[] serializerArguments, boolean serialize, boolean suppressPointerAccess) {
+    private String toExpression(TypeReference fieldType, Term term, List<Argument> parserArguments, List<Argument> serializerArguments, boolean serialize, boolean suppressPointerAccess) {
         Tracer tracer = Tracer.start("toExpression");
         if (term == null) {
             return "";
@@ -606,47 +600,43 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         }
     }
 
-    private String toVariableExpression(TypeReference typeReference, VariableLiteral vl, Argument[] parserArguments, Argument[] serializerArguments, boolean serialize, boolean suppressPointerAccess) {
+    private String toVariableExpression(TypeReference typeReference, VariableLiteral variableLiteral, List<Argument> parserArguments, List<Argument> serializerArguments, boolean serialize, boolean suppressPointerAccess) {
         Tracer tracer = Tracer.start("toVariableExpression");
-        if ("lengthInBytes".equals(vl.getName())) {
+        if ("lengthInBytes".equals(variableLiteral.getName())) {
             tracer = tracer.dive("lengthInBytes");
             return tracer + (serialize ? getCastExpressionForTypeReference(typeReference) + "(m." : "") + "LengthInBytes()" + (serialize ? ")" : "");
-        } else if ("lengthInBits".equals(vl.getName())) {
+        } else if ("lengthInBits".equals(variableLiteral.getName())) {
             tracer = tracer.dive("lengthInBits");
             return tracer + (serialize ? getCastExpressionForTypeReference(typeReference) + "(m." : "") + "LengthInBits()" + (serialize ? ")" : "");
-        } else if ("_value".equals(vl.getName())) {
-            tracer = tracer.dive("_value");
-            if (vl.getChild() != null) {
-                tracer = tracer.dive("withChild");
-                return tracer + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, serialize, suppressPointerAccess);
-            } else {
-                return tracer + "m";
-            }
+        } else if ("_value".equals(variableLiteral.getName())) {
+            final Tracer tracer2 = tracer.dive("_value");
+            return variableLiteral.getChild()
+                .map(child -> tracer2.dive("withChild") + toVariableExpression(typeReference, child, parserArguments, serializerArguments, serialize, suppressPointerAccess))
+                .orElse(tracer2 + "m");
         }
-        if (vl.getChild() != null && "length".equals(vl.getChild().getName())) {
+        if ("length".equals(variableLiteral.getChild().map(VariableLiteral::getName).orElse(""))) {
             tracer = tracer.dive("length");
-            return tracer + (serialize ? ("len(m." + StringUtils.capitalize(vl.getName()) + ")") : ("(" + vl.getName() + ")"));
+            return tracer + (serialize ? ("len(m." + StringUtils.capitalize(variableLiteral.getName()) + ")") : ("(" + variableLiteral.getName() + ")"));
         }
         // If this literal references an Enum type, then we have to output it differently.
-        else if (getTypeDefinitions().get(vl.getName()) instanceof EnumTypeDefinition) {
+        else if (getTypeDefinitions().get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
             tracer = tracer.dive("enum");
-            return tracer + vl.getName() + "_" + vl.getChild().getName() +
-                ((vl.getChild().getChild() != null) ?
-                    "." + toVariableExpression(typeReference, vl.getChild().getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+            VariableLiteral child = variableLiteral.getChild().orElseThrow(() -> new RuntimeException("Enum should have a child"));
+            return tracer + variableLiteral.getName() + "_" + child.getName() +
+                child.getChild().map(childChild -> "." + toVariableExpression(typeReference, childChild, parserArguments, serializerArguments, false, suppressPointerAccess)).orElse("");
         }
         // If we are accessing enum constants, these also need to be output differently.
-        else if ((getFieldForNameFromCurrent(vl.getName()) instanceof EnumField) && (vl.getChild() != null)) {
+        else if ((getFieldForNameFromCurrent(variableLiteral.getName()) instanceof EnumField) && (variableLiteral.getChild().isPresent())) {
             tracer = tracer.dive("enum constant");
-            return tracer + vl.getName() + "." + StringUtils.capitalize(vl.getChild().getName()) + "()" +
-                ((vl.getChild().getChild() != null) ?
-                    "." + toVariableExpression(typeReference, vl.getChild().getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+            VariableLiteral child = variableLiteral.getChild().get();
+            return tracer + variableLiteral.getName() + "." + StringUtils.capitalize(child.getName()) + "()" +
+                child.getChild().map(childChild -> "." + toVariableExpression(typeReference, childChild, parserArguments, serializerArguments, false, suppressPointerAccess)).orElse("");
         }
         // If we are accessing optional fields, (we might need to use pointer-access).
-        else if (!serialize && (getFieldForNameFromCurrent(vl.getName()) instanceof OptionalField)) {
+        else if (!serialize && (getFieldForNameFromCurrent(variableLiteral.getName()) instanceof OptionalField)) {
             tracer = tracer.dive("optional fields");
-            return tracer + "(" + (suppressPointerAccess ? "" : "*") + vl.getName() + ")" +
-                ((vl.getChild() != null) ?
-                    "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, serialize, suppressPointerAccess) : "");
+            return tracer + "(" + (suppressPointerAccess ? "" : "*") + variableLiteral.getName() + ")" +
+                variableLiteral.getChild().map(child -> "." + toVariableExpression(typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess)).orElse("");
         }
         // If we are accessing implicit fields, we need to rely on local variable instead.
         //else if (isVariableLiteralImplicitField(vl)) {
@@ -657,12 +647,20 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         // If we are accessing implicit fields, we need to rely on a local variable instead.
 
         // CAST expressions are special as we need to add a ".class" to the second parameter in Java.
-        else if ("CAST".equals(vl.getName())) {
+        else if ("CAST".equals(variableLiteral.getName())) {
             tracer = tracer.dive("CAST");
-            if ((vl.getArgs() == null) || (vl.getArgs().size() != 2)) {
+            List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A Cast expression needs arguments"));
+            if (arguments.size() != 2) {
                 throw new RuntimeException("A CAST expression expects exactly two arguments.");
             }
-            VariableLiteral typeLiteral = (VariableLiteral) vl.getArgs().get(1);
+            VariableLiteral firstArgument = arguments.get(0).asLiteral()
+                .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+                .asVariableLiteral()
+                .orElseThrow(() -> new RuntimeException("First argument should be a Variable literal"));
+            VariableLiteral typeLiteral = arguments.get(1).asLiteral()
+                .orElseThrow(() -> new RuntimeException("Second argument should be a literal"))
+                .asVariableLiteral()
+                .orElseThrow(() -> new RuntimeException("Second argument should be a Variable literal"));
             final TypeDefinition typeDefinition = getTypeDefinitions().get(typeLiteral.getName());
             TypeReference type = typeDefinition.getTypeReference();
             StringBuilder sb = new StringBuilder();
@@ -670,16 +668,21 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 sb.append("Cast");
             }
             sb.append(typeLiteral.getName());
-            sb.append("(").append(toVariableExpression(typeReference, (VariableLiteral) vl.getArgs().get(0), parserArguments, serializerArguments, serialize, suppressPointerAccess)).append(")");
-            return tracer + sb.toString() + ((vl.getChild() != null) ? "." + StringUtils.capitalize(toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess)) : "");
-        } else if ("STATIC_CALL".equals(vl.getName())) {
+            sb.append("(").append(toVariableExpression(typeReference, firstArgument, parserArguments, serializerArguments, serialize, suppressPointerAccess)).append(")");
+            return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + StringUtils.capitalize(toVariableExpression(typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess))).orElse("");
+        } else if ("STATIC_CALL".equals(variableLiteral.getName())) {
             tracer = tracer.dive("STATIC_CALL");
             StringBuilder sb = new StringBuilder();
-            if (!(vl.getArgs().get(0) instanceof StringLiteral)) {
-                throw new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
+            List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
+            if (arguments.size() < 1) {
+                throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
             }
             // Get the class and method name
-            String staticCall = ((StringLiteral) vl.getArgs().get(0)).getValue();
+            String staticCall = arguments.get(0).asLiteral()
+                .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+                .asStringLiteral()
+                .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
+                getValue();
             // Cut off the double-quotes
             staticCall = staticCall.substring(1, staticCall.length() - 1);
             // Remove all the previous parts prior to the Class name (Which starts with an uppercase letter)
@@ -689,15 +692,15 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             String className = staticCall.substring(0, staticCall.indexOf("."));
             String methodName = staticCall.substring(staticCall.indexOf(".") + 1);
             sb.append(className).append(StringUtils.capitalize(methodName)).append("(");
-            for (int i = 1; i < vl.getArgs().size(); i++) {
-                Term arg = vl.getArgs().get(i);
+            for (int i = 1; i < arguments.size(); i++) {
+                Term arg = arguments.get(i);
                 if (i > 1) {
                     sb.append(", ");
                 }
                 if (arg instanceof VariableLiteral) {
                     VariableLiteral va = (VariableLiteral) arg;
                     // "io" is the default name of the reader argument which is always available.
-                    boolean isParserArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName()) || ((getThisTypeDefinition() instanceof DataIoTypeDefinition) && "_value".equals(va.getName()));
+                    boolean isParserArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName()) || ((thisType instanceof DataIoTypeDefinition) && "_value".equals(va.getName()));
                     boolean isTypeArg = "_type".equals(va.getName());
                     if (!isParserArg && !isTypeArg && parserArguments != null) {
                         for (Argument parserArgument : parserArguments) {
@@ -709,16 +712,15 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                     }
                     if (isParserArg) {
                         if (va.getName().equals("_value")) {
-                            sb.append(va.getName().substring(1)).append((va.getChild() != null) ?
-                                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+                            sb.append(va.getName().substring(1)).append(va.getChild().map(child -> "." + toVariableExpression(typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess)).orElse(""));
                         } else {
-                            sb.append(va.getName()).append((va.getChild() != null) ?
-                                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+                            sb.append(va.getName()).append((va.getChild().isPresent()) ?
+                                "." + toVariableExpression(typeReference, variableLiteral.getChild().get(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
                         }
                     }
                     // We have to manually evaluate the type information at code-generation time.
                     else if (isTypeArg) {
-                        String part = va.getChild().getName();
+                        String part = va.getChild().map(VariableLiteral::getName).orElse("");
                         switch (part) {
                             case "name":
 //                                sb.append("\"").append(field.getTypeName()).append("\"");
@@ -742,14 +744,27 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             }
             sb.append(")");
             return tracer + sb.toString();
-        } else if ("COUNT".equals(vl.getName())) {
+        } else if ("COUNT".equals(variableLiteral.getName())) {
             tracer = tracer.dive("count");
+            VariableLiteral countLiteral = variableLiteral.getArgs()
+                .orElseThrow(() -> new RuntimeException("Count needs at least one arg"))
+                .get(0)
+                .asLiteral()
+                .orElseThrow(() -> new RuntimeException("Count needs a literal"))
+                .asVariableLiteral()
+                .orElseThrow(() -> new RuntimeException("Count needs a variable literal"));
             return tracer + (typeReference instanceof SimpleTypeReference ? getCastExpressionForTypeReference(typeReference) : "") + "(len(" +
-                toVariableExpression(typeReference, (VariableLiteral) vl.getArgs().get(0), parserArguments, serializerArguments, serialize, suppressPointerAccess) +
+                toVariableExpression(typeReference, countLiteral, parserArguments, serializerArguments, serialize, suppressPointerAccess) +
                 "))";
-        } else if ("ARRAY_SIZE_IN_BYTES".equals(vl.getName())) {
+        } else if ("ARRAY_SIZE_IN_BYTES".equals(variableLiteral.getName())) {
             tracer = tracer.dive("array size in bytes");
-            VariableLiteral va = (VariableLiteral) vl.getArgs().get(0);
+            VariableLiteral va = variableLiteral.getArgs()
+                .orElseThrow(() -> new RuntimeException("ARRAY_SIZE_IN_BYTES needs at least one arg"))
+                .get(0)
+                .asLiteral()
+                .orElseThrow(() -> new RuntimeException("ARRAY_SIZE_IN_BYTES needs a literal"))
+                .asVariableLiteral()
+                .orElseThrow(() -> new RuntimeException("ARRAY_SIZE_IN_BYTES needs a variable literal"));
             // "io" and "m" are always available in every parser.
             boolean isSerializerArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName()) || "m".equals(va.getName()) || "element".equals(va.getName());
             if (!isSerializerArg && serializerArguments != null) {
@@ -762,27 +777,27 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             }
             StringBuilder sb = new StringBuilder();
             if (isSerializerArg) {
-                sb.append(va.getName()).append(((va.getChild() != null) ? "." + toVariableExpression(typeReference, va.getChild(), parserArguments, serializerArguments, true, suppressPointerAccess) : ""));
+                sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpression(typeReference, child, parserArguments, serializerArguments, true, suppressPointerAccess)).orElse(""));
             } else {
                 sb.append(toVariableExpression(typeReference, va, parserArguments, serializerArguments, true, suppressPointerAccess));
             }
-            return tracer + getCastExpressionForTypeReference(typeReference) + "(" + ((VariableLiteral) vl.getArgs().get(0)).getName() + "ArraySizeInBytes(" + sb.toString() + "))";
-        } else if ("CEIL".equals(vl.getName())) {
+            return tracer + getCastExpressionForTypeReference(typeReference) + "(" + va.getName() + "ArraySizeInBytes(" + sb.toString() + "))";
+        } else if ("CEIL".equals(variableLiteral.getName())) {
             tracer = tracer.dive("ceil");
-            Term va = vl.getArgs().get(0);
+            Term va = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("CEIL needs at least one arg")).get(0);
             // The Ceil function expects 64 bit floating point values.
             TypeReference tr = new DefaultFloatTypeReference(SimpleTypeReference.SimpleBaseType.FLOAT, 11, 52);
             emitRequiredImport("math");
             return tracer + "math.Ceil(" + toExpression(tr, va, parserArguments, serializerArguments, serialize, suppressPointerAccess) + ")";
         }
         // All uppercase names are not fields, but utility methods.
-        else if (vl.getName().equals(vl.getName().toUpperCase())) {
+        else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) {
             tracer = tracer.dive("utility medhods");
-            StringBuilder sb = new StringBuilder(vl.getName());
-            if (vl.getArgs() != null) {
+            StringBuilder sb = new StringBuilder(variableLiteral.getName());
+            if (variableLiteral.getArgs().isPresent()) {
                 sb.append("(");
                 boolean firstArg = true;
-                for (Term arg : vl.getArgs()) {
+                for (Term arg : variableLiteral.getArgs().get()) {
                     if (!firstArg) {
                         sb.append(", ");
                     }
@@ -791,23 +806,24 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 }
                 sb.append(")");
             }
-            if (vl.getIndex() != VariableLiteral.NO_INDEX) {
-                sb.append("[").append(vl.getIndex()).append("]");
+            if (variableLiteral.getIndex() != VariableLiteral.NO_INDEX) {
+                sb.append("[").append(variableLiteral.getIndex()).append("]");
             }
-            return tracer + sb.toString() + ((vl.getChild() != null) ?
-                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+            return tracer + sb.toString() + variableLiteral.getChild()
+                .map(child -> "." + toVariableExpression(typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess))
+                .orElse("");
         }
 
         // If the current property references a discriminator value, we have to serialize it differently.
-        else if ((getFieldForNameFromCurrentOrParent(vl.getName()) != null) && (getFieldForNameFromCurrentOrParent(vl.getName()) instanceof DiscriminatorField)) {
+        else if ((getFieldForNameFromCurrentOrParent(variableLiteral.getName()) != null) && (getFieldForNameFromCurrentOrParent(variableLiteral.getName()) instanceof DiscriminatorField)) {
             tracer = tracer.dive("discriminator value");
-            final DiscriminatorField discriminatorField = (DiscriminatorField) getFieldForNameFromCurrentOrParent(vl.getName());
+            final DiscriminatorField discriminatorField = (DiscriminatorField) getFieldForNameFromCurrentOrParent(variableLiteral.getName());
             // TODO: Should this return something?
         }
         // If the variable has a child element and we're able to find a type for this ... get the type.
-        else if ((vl.getChild() != null) && (getTypeReferenceForProperty(((ComplexTypeDefinition) getThisTypeDefinition()), vl.getName()).isPresent())) {
+        else if ((variableLiteral.getChild().isPresent()) && (getTypeReferenceForProperty(((ComplexTypeDefinition) thisType), variableLiteral.getName()).isPresent())) {
             tracer = tracer.dive("child element");
-            final Optional<TypeReference> typeReferenceForProperty = getTypeReferenceForProperty(((ComplexTypeDefinition) getThisTypeDefinition()), vl.getName());
+            final Optional<TypeReference> typeReferenceForProperty = getTypeReferenceForProperty(((ComplexTypeDefinition) thisType), variableLiteral.getName());
             if (typeReferenceForProperty.isPresent() && typeReferenceForProperty.get() instanceof ComplexTypeReference) {
                 tracer = tracer.dive("complex");
                 final TypeReference complexTypeReference = typeReferenceForProperty.get();
@@ -815,44 +831,49 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 if (typeDefinition instanceof ComplexTypeDefinition) {
                     tracer = tracer.dive("complex");
                     ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) typeDefinition;
-                    String childProperty = vl.getChild().getName();
+                    String childProperty = variableLiteral.getChild().orElseThrow(() -> new RuntimeException("complex needs a child")).getName();
                     final Optional<Field> matchingDiscriminatorField = complexTypeDefinition.getFields().stream().filter(field -> (field instanceof DiscriminatorField) && ((DiscriminatorField) field).getName().equals(childProperty)).findFirst();
                     if (matchingDiscriminatorField.isPresent()) {
-                        return tracer + "Cast" + getLanguageTypeNameForTypeReference(complexTypeReference) + "(" + vl.getName() + ").Child." + StringUtils.capitalize(childProperty) + "()";
+                        return tracer + "Cast" + getLanguageTypeNameForTypeReference(complexTypeReference) + "(" + variableLiteral.getName() + ").Child." + StringUtils.capitalize(childProperty) + "()";
                     }
                 } else if (typeDefinition instanceof EnumTypeDefinition) {
                     tracer = tracer.dive("enum");
-                    return tracer + (serialize ? "m." + StringUtils.capitalize(vl.getName()) : vl.getName()) +
-                        "." + StringUtils.capitalize(vl.getChild().getName()) + "()";
+                    return tracer + (serialize ? "m." + StringUtils.capitalize(variableLiteral.getName()) : variableLiteral.getName()) +
+                        "." + StringUtils.capitalize(variableLiteral.getChild().orElseThrow(() -> new RuntimeException("enum needs a child")).getName()) + "()";
                 }
             }
-        } else if (isVariableLiteralImplicitField(vl)) {
+        } else if (isVariableLiteralImplicitField(variableLiteral)) {
             tracer = tracer.dive("implicit");
             if (serialize) {
                 tracer = tracer.dive("serialize");
-                return tracer + toSerializationExpression(getReferencedImplicitField(vl), getReferencedImplicitField(vl).getSerializeExpression(), serializerArguments);
+                return tracer + toSerializationExpression(getReferencedImplicitField(variableLiteral), getReferencedImplicitField(variableLiteral).getSerializeExpression(), serializerArguments);
             } else {
-                return tracer + vl.getName();
+                return tracer + variableLiteral.getName();
                 //return toParseExpression(getReferencedImplicitField(vl), getReferencedImplicitField(vl).getSerializeExpression(), serializerArguments);
             }
         }
         // If the current term references a serialization argument, handle it differently (don't prefix it with "m.")
-        else if ((serializerArguments != null) && Arrays.stream(serializerArguments).anyMatch(argument -> argument.getName().equals(vl.getName()))) {
+        else if ((serializerArguments != null) && serializerArguments.stream()
+            .anyMatch(argument -> argument.getName().equals(variableLiteral.getName()))) {
             tracer = tracer.dive("serialization argument");
-            return tracer + vl.getName() + ((vl.getChild() != null) ?
-                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+            return tracer + variableLiteral.getName() +
+                variableLiteral.getChild()
+                    .map(child -> "." + toVariableExpression(typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess))
+                    .orElse("");
         }
         String indexCall = "";
-        if (vl.getIndex() >= 0) {
+        if (variableLiteral.getIndex() >= 0) {
             tracer = tracer.dive("indexCall");
             // We have a index call
-            indexCall = "[" + vl.getIndex() + "]";
+            indexCall = "[" + variableLiteral.getIndex() + "]";
         }
-        return tracer + (serialize ? "m." + StringUtils.capitalize(vl.getName()) : vl.getName()) + indexCall + ((vl.getChild() != null) ?
-            "." + StringUtils.capitalize(toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess)) : "");
+        return tracer + (serialize ? "m." + StringUtils.capitalize(variableLiteral.getName()) : variableLiteral.getName()) + indexCall +
+            variableLiteral.getChild()
+                .map(child -> "." + StringUtils.capitalize(toVariableExpression(typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess)))
+                .orElse("");
     }
 
-    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, Argument[] parserArguments) {
+    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, List<Argument> parserArguments) {
         int sizeInBits = 0;
         StringBuilder sb = new StringBuilder();
         for (Field field : complexTypeDefinition.getFields()) {
@@ -926,7 +947,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         }
     }
 
-    public Collection<EnumValue> getUniqueEnumValues(EnumValue[] enumValues) {
+    public Collection<EnumValue> getUniqueEnumValues(List<EnumValue> enumValues) {
         Map<String, EnumValue> filteredEnumValues = new TreeMap<>();
         for (EnumValue enumValue : enumValues) {
             if (!filteredEnumValues.containsKey(enumValue.getValue())) {
@@ -981,7 +1002,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         NamedField namedField = (NamedField) field;
 
         String name = null;
-        for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
+        for (Field curField : ((ComplexTypeDefinition) thisType).getFields()) {
             if (curField == field) {
                 name = namedField.getName();
             } else if (name != null) {
@@ -1038,7 +1059,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                         }
                     }
                     for (DiscriminatedComplexTypeDefinition curCase : switchField.getCases()) {
-                        for (Argument parserArgument : curCase.getParserArguments()) {
+                        for (Argument parserArgument : curCase.getParserArguments().orElse(Collections.emptyList())) {
                             if (parserArgument.getName().equals(name)) {
                                 return name;
                             }
@@ -1050,11 +1071,9 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                         return name;
                     }
                 }
-                if (curField.getParams() != null) {
-                    for (Term param : curField.getParams()) {
-                        if (param.contains(name)) {
-                            return name;
-                        }
+                for (Term param : curField.getParams().orElse(Collections.emptyList())) {
+                    if (param.contains(name)) {
+                        return name;
                     }
                 }
             }
@@ -1069,11 +1088,10 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 return true;
             }
         }
-        if ((field.getParams() != null) && (field.getParams().length > 0)) {
-            for (Term param : field.getParams()) {
-                if (param.contains(variableName)) {
-                    return true;
-                }
+        List<Term> fieldParams = field.getParams().orElse(Collections.emptyList());
+        for (Term param : fieldParams) {
+            if (param.contains(variableName)) {
+                return true;
             }
         }
         return false;
@@ -1086,13 +1104,13 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
      * so we'll simplify things here for now.
      *
      * @param functionName name of the
-     * @return
+     * @return something
      */
     public Map<String, String> requiresHelperFunctions(String functionName) {
         Map<String, String> result = new HashMap<>();
         boolean usesFunction = false;
         // As the ARRAY_SIZE_IN_BYTES only applies to ArrayFields, search for these
-        for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
+        for (Field curField : ((ComplexTypeDefinition) thisType).getFields()) {
             if (curField instanceof ArrayField) {
                 ArrayField arrayField = (ArrayField) curField;
                 if (arrayField.getLoopExpression().contains(functionName)) {
@@ -1113,8 +1131,9 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
     }
 
     public boolean requiresStartPosAndCurPos() {
-        if (getThisTypeDefinition() instanceof ComplexTypeDefinition) {
-            for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
+        if (thisType instanceof ComplexTypeDefinition) {
+            ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) this.thisType;
+            for (Field curField : complexTypeDefinition.getFields()) {
                 if (requiresVariable(curField, "curPos")) {
                     return true;
                 }
@@ -1135,11 +1154,9 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 return true;
             }
         }
-        if (curField.getParams() != null) {
-            for (Term paramTerm : curField.getParams()) {
-                if (paramTerm.contains(variable)) {
-                    return true;
-                }
+        for (Term paramTerm : curField.getParams().orElse(Collections.emptyList())) {
+            if (paramTerm.contains(variable)) {
+                return true;
             }
         }
         return false;
@@ -1151,13 +1168,13 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             if (variableLiteral.getName().equals(name)) {
                 return variableLiteral;
             }
-            if (variableLiteral.getChild() != null) {
-                Term found = findTerm(variableLiteral.getChild(), name);
+            if (variableLiteral.getChild().isPresent()) {
+                Term found = findTerm(variableLiteral.getChild().get(), name);
                 if (found != null) {
                     return found;
                 }
             }
-            for (Term arg : variableLiteral.getArgs()) {
+            for (Term arg : variableLiteral.getArgs().orElse(Collections.emptyList())) {
                 Term found = findTerm(arg, name);
                 if (found != null) {
                     return found;
@@ -1165,10 +1182,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             }
         } else if (baseTerm instanceof UnaryTerm) {
             UnaryTerm unaryTerm = (UnaryTerm) baseTerm;
-            Term found = findTerm(unaryTerm.getA(), name);
-            if (found != null) {
-                return found;
-            }
+            return findTerm(unaryTerm.getA(), name);
         } else if (baseTerm instanceof BinaryTerm) {
             BinaryTerm binaryTerm = (BinaryTerm) baseTerm;
             Term found = findTerm(binaryTerm.getA(), name);
@@ -1176,9 +1190,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 return found;
             }
             found = findTerm(binaryTerm.getB(), name);
-            if (found != null) {
-                return found;
-            }
+            return found;
         } else if (baseTerm instanceof TernaryTerm) {
             TernaryTerm ternaryTerm = (TernaryTerm) baseTerm;
             Term found = findTerm(ternaryTerm.getA(), name);
@@ -1190,9 +1202,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                 return found;
             }
             found = findTerm(ternaryTerm.getC(), name);
-            if (found != null) {
-                return found;
-            }
+            return found;
         }
         return null;
     }
@@ -1204,14 +1214,17 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
     }
 
     public boolean needsReferenceForParserArgument(String propertyName, TypeReference argumentType) {
-        // Check if this is a local field.
-        if (argumentType instanceof ComplexTypeReference) {
-            Field field = getFieldForNameFromCurrent(propertyName);
-            if (field instanceof TypedField) {
-                TypedField typedField = (TypedField) field;
-                return typedField.getType() instanceof ComplexTypeReference && !(getTypeDefinitionForTypeReference(typedField.getType()) instanceof EnumTypeDefinition);
-            }
-        }
-        return false;
+        return argumentType.asComplexTypeReference()
+            .map(complexTypeReference -> {
+                // Check if this is a local field.
+                // FIXME: shouldn't this look onto the argumentType? this is nowhere used...
+                Field field = getFieldForNameFromCurrent(propertyName);
+                if (field instanceof TypedField) {
+                    TypedField typedField = (TypedField) field;
+                    return typedField.getType() instanceof ComplexTypeReference && !(getTypeDefinitionForTypeReference(typedField.getType()) instanceof EnumTypeDefinition);
+                }
+                return false;
+            })
+            .orElse(false);
     }
 }
diff --git a/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh
index fef9ef0..a5a801a 100644
--- a/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/data-io-template.go.ftlh
@@ -24,24 +24,7 @@
 <#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.go.GoLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
-<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.DataIoTypeDefinition" -->
 ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.go
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -82,12 +65,14 @@ import (
 
 <@importSectionWithContentBelow><@emitImport import="github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils" /><@emitImport import="github.com/apache/plc4x/plc4go/internal/plc4go/spi/values" /><@emitImportWithAlias alias="api" import="github.com/apache/plc4x/plc4go/pkg/plc4go/values" />
 // Code generated by code-generation. DO NOT EDIT.
-
-func ${type.name}Parse(readBuffer utils.ReadBuffer<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>I</#if>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) (api.PlcValue, error) {
+	
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
+func ${type.name}Parse(readBuffer utils.ReadBuffer<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>I</#if>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) (api.PlcValue, error) {
 	readBuffer.PullContext("${type.name}")
 	switch {
 	<#list type.switchField.cases as case>
-        <#if case.discriminatorValues?has_content>case <#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(type.parserArguments[discriminatorValue?index].type)><#if helper.isEn [...]
+        <#if case.discriminatorValues?has_content>case <#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(parserArguments[discriminatorValue?index].type)><#if helper.isEnumTypeRefe [...]
 		<#assign valueDefined=false>
 		<#if case.name == "Struct">
 			_map := map[string]api.PlcValue{}
@@ -96,51 +81,51 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if type.parserArguments?has_
 		<#list case.fields as field>
 			<#switch field.typeName>
 				<#case "array">
-					<#assign arrayField = field>
+					<#assign arrayField = field.asArrayField().orElseThrow()>
 
-			// Array Field (${field.name})
-			var ${field.name} []api.PlcValue
-			for i := 0; i < int(${helper.toParseExpression(null, field.loopExpression, type.parserArguments)}); i++ {
-				_item, _itemErr := <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.name, field.type)}<#else>Complex type array in data-io parsing currently not implemented</#if>
+			// Array Field (${arrayField.name})
+			var ${arrayField.name} []api.PlcValue
+			for i := 0; i < int(${helper.toParseExpression(null, arrayField.loopExpression, parserArguments)}); i++ {
+				_item, _itemErr := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.name, arrayField.type.asSimpleTypeReference().orElseThrow())}<#else>Complex type array in data-io parsing currently not implemented</#if>
 				if _itemErr != nil {
 					return nil, errors.Wrap(_itemErr, "Error parsing 'value' field")<@emitImport import="github.com/pkg/errors" />
 				}
-				${field.name} = append(${field.name}, ${helper.getPlcValueTypeForTypeReference(field.type)}(_item))
+				${arrayField.name} = append(${arrayField.name}, ${helper.getPlcValueTypeForTypeReference(arrayField.type)}(_item))
 			}
-					<#if field.name == "value">
+					<#if arrayField.name == "value">
 						<#assign valueDefined=true>
 					</#if>
 					<#break>
 				<#case "manual">
-					<#assign arrayField = field>
+					<#assign arrayField = field.asManualField().orElseThrow()>
 
-			// Manual Field (${field.name})
-			${field.name}, _${field.name}Err := ${helper.toParseExpression(field, field.parseExpression, type.parserArguments)}
-			if _${field.name}Err != nil {
-				return nil, errors.Wrap(_${field.name}Err, "Error parsing '${field.name}' field")<@emitImport import="github.com/pkg/errors" />
+			// Manual Field (${arrayField.name})
+			${arrayField.name}, _${arrayField.name}Err := ${helper.toParseExpression(arrayField, arrayField.parseExpression, parserArguments)}
+			if _${arrayField.name}Err != nil {
+				return nil, errors.Wrap(_${arrayField.name}Err, "Error parsing '${arrayField.name}' field")<@emitImport import="github.com/pkg/errors" />
 			}
-					<#if field.name == "value">
+					<#if arrayField.name == "value">
 						<#assign valueDefined=true>
 					</#if>
 					<#break>
 				<#case "reserved">
-					<#assign reservedField = field>
+					<#assign reservedField = field.asReservedField().orElseThrow()>
 
 			// Reserved Field (Just skip the bytes)
-			if _, _err := ${helper.getReadBufferReadMethodCall("reserved", field.type)}; _err != nil {
+			if _, _err := ${helper.getReadBufferReadMethodCall("reserved", reservedField.type.asSimpleTypeReference().orElseThrow())}; _err != nil {
 				return nil, errors.Wrap(_err, "Error parsing reserved field")<@emitImport import="github.com/pkg/errors" />
 			}
 					<#break>
 				<#case "simple">
-					<#assign simpleField = field>
+					<#assign simpleField = field.asSimpleField().orElseThrow()>
 
-			// Simple Field (${field.name})
-			<#if case.name == "Struct" || ((case.name == "DATE_AND_TIME") && ((field.name == "year") || (field.name == "month") || (field.name == "day") || (field.name == "hour") || (field.name == "minutes") || (field.name == "seconds") || (field.name == "secondsSinceEpoch"))) || ((case.name == "DATE") && ((field.name == "year") || (field.name == "month") || (field.name == "day"))) || ((case.name == "TIME_OF_DAY") && ((field.name == "hour") || (field.name == "minutes") || (field.name == "seconds" [...]
-			if _${field.name}Err != nil {
-				return nil, errors.Wrap(_${field.name}Err, "Error parsing '${field.name}' field")<@emitImport import="github.com/pkg/errors" />
+			// Simple Field (${simpleField.name})
+			<#if case.name == "Struct" || ((case.name == "DATE_AND_TIME") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day") || (simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds") || (simpleField.name == "secondsSinceEpoch"))) || ((case.name == "DATE") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day"))) || ((case.name == "TIME_OF_DAY") && ((simpleField.name = [...]
+			if _${simpleField.name}Err != nil {
+				return nil, errors.Wrap(_${simpleField.name}Err, "Error parsing '${simpleField.name}' field")<@emitImport import="github.com/pkg/errors" />
 			}
 					<#if case.name == "Struct">
-			_map["${case.name}"] = ${helper.getPlcValueTypeForTypeReference(field.type)}(${field.name})
+			_map["${case.name}"] = ${helper.getPlcValueTypeForTypeReference(simpleField.type)}(${simpleField.name})
 					</#if>
 					<#assign valueDefined=true>
 					<#break>
@@ -191,51 +176,51 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if type.parserArguments?has_
 	return nil, errors.New("unsupported type")<@emitImport import="github.com/pkg/errors" />
 }
 
-func ${type.name}Serialize(writeBuffer utils.WriteBuffer, value api.PlcValue<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>I</#if>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
+func ${type.name}Serialize(writeBuffer utils.WriteBuffer, value api.PlcValue<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>I</#if>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
 	writeBuffer.PushContext("${type.name}")
 	switch {
 	<#assign defaultSet=false>
 	<#list type.switchField.cases as case>
-        <#if case.discriminatorValues?has_content>case <#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(type.parserArguments[discriminatorValue?index].type)><#if helper.isEn [...]
+        <#if case.discriminatorValues?has_content>case <#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(parserArguments[discriminatorValue?index].type)><#if helper.isEnumTypeRefe [...]
 		<#list case.fields as field>
 			<#switch field.typeName>
 				<#case "array">
-					<#assign arrayField = field>
+					<#assign arrayField = field.asArrayField().orElseThrow()>
 
-			// Array Field (${field.name})
-			for i := uint32(0); i < uint32(${helper.toSerializationExpression(null, field.loopExpression, type.parserArguments)}); i++ {
+			// Array Field (${arrayField.name})
+			for i := uint32(0); i < uint32(${helper.toSerializationExpression(null, field.loopExpression, parserArguments)}); i++ {
 					<#if case.name = "Struct">
 				${arrayField.name} := value.GetValue("${arrayField.name}")
 					</#if>
-				_itemErr := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getWriteBufferWriteMethodCall("", arrayField.type, arrayField.name + ".GetIndex(i).Get" + helper.getLanguageTypeNameForTypeReference(arrayField.type)?cap_first + "()", field)}<#else>Complex type array in data-io serialization currently not implemented</#if>
+				_itemErr := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getWriteBufferWriteMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), arrayField.name + ".GetIndex(i).Get" + helper.getLanguageTypeNameForTypeReference(arrayField.type)?cap_first + "()", arrayField)}<#else>Complex type array in data-io serialization currently not implemented</#if>
 				if _itemErr != nil {
 					return errors.Wrap(_itemErr, "Error serializing 'value' field")<@emitImport import="github.com/pkg/errors" />
 				}
 			}
 					<#break>
 				<#case "manual">
-					<#assign manualField = field>
+					<#assign manualField = field.asManualField().orElseThrow()>
 
-			// Manual Field (${field.name})
-			_${field.name}Err := ${helper.toSerializationExpression(field, manualField.serializeExpression, type.parserArguments)}
-			if _${field.name}Err != nil {
-				return errors.Wrap(_${field.name}Err, "Error serializing '${field.name}' field")<@emitImport import="github.com/pkg/errors" />
+			// Manual Field (${manualField.name})
+			_${manualField.name}Err := ${helper.toSerializationExpression(field, manualField.serializeExpression, parserArguments)}
+			if _${manualField.name}Err != nil {
+				return errors.Wrap(_${manualField.name}Err, "Error serializing '${manualField.name}' field")<@emitImport import="github.com/pkg/errors" />
 			}
 					<#break>
 				<#case "reserved">
-					<#assign reservedField = field>
+					<#assign reservedField = field.asReservedField().orElseThrow()>
 
 			// Reserved Field (Just skip the bytes)
-			if _err := ${helper.getWriteBufferWriteMethodCall("reserved", field.type, helper.getReservedValue(field), field)}; _err != nil {
+			if _err := ${helper.getWriteBufferWriteMethodCall("reserved", reservedField.type.asSimpleTypeReference().orElseThrow(), helper.getReservedValue(reservedField), reservedField)}; _err != nil {
 				return errors.Wrap(_err, "Error serializing reserved field")<@emitImport import="github.com/pkg/errors" />
 			}
 					<#break>
 				<#case "simple">
-					<#assign simpleField = field>
+					<#assign simpleField = field.asSimpleField().orElseThrow()>
 
-			// Simple Field (${field.name})
-			if _err := <#if helper.isSimpleTypeReference(field.type)>${helper.getWriteBufferWriteMethodCall(field.name, field.type, "value.Get" + helper.getLanguageTypeNameForTypeReference(field.type)?cap_first + "()", field)}<#else>${field.type.name}Serialize(io, <#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, typ [...]
-				return errors.Wrap(_err, "Error serializing '${field.name}' field")<@emitImport import="github.com/pkg/errors" />
+			// Simple Field (${simpleField.name})
+			if _err := <#if helper.isSimpleTypeReference(simpleField.type)>${helper.getWriteBufferWriteMethodCall(simpleField.name, simpleField.type.asSimpleTypeReference().orElseThrow(), "value.Get" + helper.getLanguageTypeNameForTypeReference(simpleField.type)?cap_first + "()", simpleField)}<#else>${simpleField.type.asComplexTypeReference().orElseThrow().name}Serialize(io, <#if simpleField.params.isPresent()>, <#list simpleField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNa [...]
+				return errors.Wrap(_err, "Error serializing '${simpleField.name}' field")<@emitImport import="github.com/pkg/errors" />
 			}
 					<#break>
 			</#switch>
diff --git a/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh
index 98d883f..93ae262 100644
--- a/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/enum-template.go.ftlh
@@ -26,7 +26,6 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.go.GoLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
 ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.go
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -99,12 +98,12 @@ func (e ${type.name}) ${constantName?cap_first}() ${helper.getLanguageTypeNameFo
 		case ${helper.escapeValue(type.type, enumValue.value)}: { /* '${enumValue.value}' */
 		    <#if helper.isComplexTypeReference(type.getConstantType(constantName))>
 		        <#if helper.isEnumTypeReference(type.getConstantType(constantName))>
-			return <#if helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName)) = "0">${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName))}<#else>${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))}_${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName))}</#if>
+			return <#if helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow()) = "0">${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())}<#else>${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName))}_${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())}</#if>
 			    <#else>
-            return ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName))}
+            return ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())}
                 </#if>
             <#else>
-            return ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName))}
+            return ${helper.escapeEnumValue(type.getConstantType(constantName), enumValue.getConstant(constantName).orElseThrow())}
             </#if>
 		}
 		</#list>
@@ -155,7 +154,7 @@ func Cast${type.name}(structType interface{}) ${type.name} {
 }
 
 func (m ${type.name}) LengthInBits() uint16 {
-	<#assign simpleTypeReference = type.type>
+	<#assign simpleTypeReference = type.type.asSimpleTypeReference().orElseThrow()>
 	return <#if helper.isStringTypeReference(type.type)>0<#else>${simpleTypeReference.sizeInBits}</#if>
 }
 
@@ -164,7 +163,7 @@ func (m ${type.name}) LengthInBytes() uint16 {
 }
 
 <#if type.type?has_content && helper.isSimpleTypeReference(type.type)>
-	<#assign simpleTypeReference = type.type>
+	<#assign simpleTypeReference = type.type.asSimpleTypeReference().orElseThrow()>
 	<#if simpleTypeReference.getSizeInBits() != -1>
 func ${type.name}Parse(readBuffer utils.ReadBuffer) (${type.name}, error) {
 	val, err := ${helper.getReadBufferReadMethodCall(type.name, helper.getEnumBaseTypeReference(type.typeReference))}
diff --git a/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
index cd5264e..0f2f8e6 100644
--- a/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/model-template.go.ftlh
@@ -25,24 +25,6 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.go.GoLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="unknownField" type="org.apache.plc4x.plugins.codegenerator.types.fields.UnknownField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
 ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.go
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -84,6 +66,8 @@ import (
 <@importSectionWithContentBelow><@emitImport import="github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils" />
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 <#if type.constFields?has_content>
 
 // Constant values.
@@ -152,12 +136,12 @@ func (m *${type.name}) ${discriminatorName?cap_first}() ${helper.getLanguageType
 <#if helper.isDiscriminatedParentTypeDefinition()>
 
 type I${type.name}Parent interface {
-	SerializeParent(writeBuffer utils.WriteBuffer, child I${type.name}, serializeChildFunction func() error<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error
+	SerializeParent(writeBuffer utils.WriteBuffer, child I${type.name}, serializeChildFunction func() error<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error
 	GetTypeName() string
 }
 
 type I${type.name}Child interface {
-	Serialize(writeBuffer utils.WriteBuffer<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error
+	Serialize(writeBuffer utils.WriteBuffer<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error
 	InitializeParent(parent *${type.name}<#if type.getPropertyFields()?has_content>, <#list type.getPropertyFields() as field>${field.name} <#if field.loopType??>[]</#if><#if helper.needsPointerAccess(field)>*</#if>${helper.getLanguageTypeNameForField(field)}<#sep>, </#sep></#list></#if><#if type.getPropertyFields()?has_content && type.virtualFields?has_content>, </#if><#list type.virtualFields as field>${field.name} <#if field.loopType??>[]</#if><#if helper.needsPointerAccess(field)>*</#if [...]
 	GetTypeName() string
 	I${type.name}
@@ -172,8 +156,8 @@ func ${type.name}${discriminatorName?cap_first}(m I${type.name}) ${helper.getLan
 	</#list-->
 <#elseif type.parentType??>
 
-func (m *${type.name}) InitializeParent(parent *${type.parentType.name}<#if type.parentType.getAllPropertyFields()?has_content>, <#list type.parentPropertyFields as parentField>${parentField.name} <#if parentField.loopType??>[]</#if><#if helper.needsPointerAccess(parentField)>*</#if>${helper.getLanguageTypeNameForField(parentField)}<#sep>, </#sep></#list></#if><#if type.parentType.getAllPropertyFields()?has_content && type.parentType.virtualFields?has_content>, </#if><#list type.parentTy [...]
-	<#list type.parentType.getAllPropertyFields() as field>
+func (m *${type.name}) InitializeParent(parent *${type.parentType.name}<#if type.parentType.asComplexTypeDefinition().orElseThrow().allPropertyFields?has_content>, <#list type.parentPropertyFields as parentField>${parentField.name} <#if parentField.loopType??>[]</#if><#if helper.needsPointerAccess(parentField)>*</#if>${helper.getLanguageTypeNameForField(parentField)}<#sep>, </#sep></#list></#if><#if type.parentType.asComplexTypeDefinition().orElseThrow().allPropertyFields?has_content &&  [...]
+	<#list type.parentType.asComplexTypeDefinition().orElseThrow().allPropertyFields as field>
 	m.Parent.${field.name?cap_first} = ${field.name}
 	</#list>
 }
@@ -236,14 +220,15 @@ func (m *${type.name}) LengthInBitsConditional(lastItem bool) uint16 {
 		<#list type.fields as field>
 			<#switch field.typeName>
 				<#case "array">
-					<#assign arrayField = field>
+					<#assign arrayField = field.asArrayField().orElseThrow()>
 
 	// Array field
 	if len(m.${arrayField.name?cap_first}) > 0 {
-				<#assign simpleTypeReference = arrayField.type>
 				<#if helper.getLanguageTypeNameForTypeReference(arrayField.type) = "string">
-		lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)}) * uint16(len(m.${arrayField.name?cap_first}))
+                    <#assign stringTypeReference = arrayField.type.asStringTypeReference().orElseThrow()>
+		lengthInBits += uint16(${helper.toSerializationExpression(arrayField, stringTypeReference.lengthExpression, parserArguments)}) * uint16(len(m.${arrayField.name?cap_first}))
 				<#elseif helper.isSimpleTypeReference(arrayField.type)>
+                    <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
 		lengthInBits += ${simpleTypeReference.sizeInBits} * uint16(len(m.${arrayField.name?cap_first}))
 				<#else>
 				<#if helper.isCountArrayField(arrayField)>
@@ -259,30 +244,32 @@ func (m *${type.name}) LengthInBitsConditional(lastItem bool) uint16 {
 	}
 					<#break>
 				<#case "checksum">
-					<#assign checksumField = field>
-					<#assign simpleTypeReference = checksumField.type>
+					<#assign checksumField = field.asChecksumField().orElseThrow()>
+					<#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Checksum Field (checksum)
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 					<#break>
 				<#case "const">
-					<#assign constField = field>
-					<#assign simpleTypeReference = constField.type>
+					<#assign constField = field.asConstField().orElseThrow()>
 
 	// Const Field (${constField.name})
 				<#if helper.getLanguageTypeNameForTypeReference(constField.type) = "string">
-	lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)})
+					<#assign stringTypeReference = constField.type.asStringTypeReference().orElseThrow()>
+	lengthInBits += uint16(${helper.toSerializationExpression(constField, stringTypeReference.lengthExpression, parserArguments)})
 				<#else>
+                    <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 				</#if>
 					<#break>
 				<#case "discriminator">
-					<#assign discriminatorField = field>
-					<#assign simpleTypeReference = discriminatorField.type>
+					<#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 	// Discriminator Field (${discriminatorField.name})
-		<#if helper.isSimpleTypeReference(simpleTypeReference)>
+		<#if helper.isSimpleTypeReference(discriminatorField.type)>
+            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
 			<#if helper.getLanguageTypeNameForTypeReference(discriminatorField.type) = "String">
-			lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)})
+                <#assign stringTypeReference = discriminatorField.type.asStringTypeReference().orElseThrow()>
+			lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, stringTypeReference.getLengthExpression(), parserArguments)})
 			<#else>
 			lengthInBits += ${simpleTypeReference.sizeInBits};
 			</#if>
@@ -293,38 +280,38 @@ func (m *${type.name}) LengthInBitsConditional(lastItem bool) uint16 {
 		</#if>
 					<#break>
 				<#case "enum">
-					<#assign enumField = field>
+					<#assign enumField = field.asEnumField().orElseThrow()>
 
 	// Enum Field (${enumField.name})
 	lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits}
 					<#break>
 				<#case "implicit">
-					<#assign implicitField = field>
-					<#assign simpleTypeReference = implicitField.type>
+					<#assign implicitField = field.asImplicitField().orElseThrow()>
+					<#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Implicit Field (${implicitField.name})
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 					<#break>
 				<#case "manualArray">
-					<#assign manualArrayField = field>
+					<#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 
 	// Manual Array Field (${manualArrayField.name})
 	${manualArrayField.name} := m.${manualArrayField.name?cap_first}<#-- TODO: ugly workaround for missing static evaluation-->
-	lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, type.parserArguments)} * 8
+	lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, parserArguments)} * 8
 					<#break>
 				<#case "manual">
-					<#assign manualField = field>
+					<#assign manualField = field.asManualField().orElseThrow()>
 
 	// Manual Field (${manualField.name})
-	lengthInBits += uint16(${helper.toParseExpression(manualField, manualField.lengthExpression, type.parserArguments)} * 8)
+	lengthInBits += uint16(${helper.toParseExpression(manualField, manualField.lengthExpression, parserArguments)} * 8)
 					<#break>
 				<#case "optional">
-					<#assign optionalField = field>
+					<#assign optionalField = field.asOptionalField().orElseThrow()>
 
 	// Optional Field (${optionalField.name})
 	if m.${optionalField.name?cap_first} != nil {
 					<#if helper.isSimpleTypeReference(optionalField.type)>
-						<#assign simpleTypeReference = optionalField.type>
+						<#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
 		lengthInBits += ${simpleTypeReference.sizeInBits}
 					<#elseif helper.isEnumField(field)>
 		lengthInBits += ${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits}
@@ -334,32 +321,32 @@ func (m *${type.name}) LengthInBitsConditional(lastItem bool) uint16 {
 	}
 					<#break>
 				<#case "padding">
-					<#assign paddingField = field>
-					<#assign simpleTypeReference = paddingField.type>
+					<#assign paddingField = field.asPaddingField().orElseThrow()>
+					<#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Padding Field (padding)
-	_timesPadding := uint8(${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, type.parserArguments)})
+	_timesPadding := uint8(${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, parserArguments)})
 	for ;_timesPadding > 0; _timesPadding-- {
 		lengthInBits += ${simpleTypeReference.sizeInBits}
 	}
 					<#break>
 				<#case "reserved">
-					<#assign reservedField = field>
-					<#assign simpleTypeReference = reservedField.type>
+					<#assign reservedField = field.asReservedField().orElseThrow()>
+					<#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Reserved Field (reserved)
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 					<#break>
 				<#case "simple">
-					<#assign simpleField = field>
+					<#assign simpleField = field.asSimpleField().orElseThrow()>
 
 	// Simple field (${simpleField.name})
 					<#if helper.isSimpleTypeReference(simpleField.type)>
 						<#if helper.getLanguageTypeNameForTypeReference(simpleField.type) = "string">
-							<#assign simpleTypeReference = simpleField.type>
-	lengthInBits += uint16(${helper.toSerializationExpression(simpleField, simpleTypeReference.getLengthExpression(), type.parserArguments)})
+							<#assign stringTypeReference = simpleField.type.asStringTypeReference().orElseThrow()>
+	lengthInBits += uint16(${helper.toSerializationExpression(simpleField, stringTypeReference.lengthExpression, parserArguments)})
 						<#else>
-							<#assign simpleTypeReference = simpleField.type>
+							<#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
 	lengthInBits += ${simpleTypeReference.sizeInBits};
 						</#if>
 					<#elseif helper.isEnumField(field)>
@@ -369,21 +356,21 @@ func (m *${type.name}) LengthInBitsConditional(lastItem bool) uint16 {
 					</#if>
 					<#break>
 				<#case "switch">
-					<#assign switchField = field>
+					<#assign switchField = field.asSwitchField().orElseThrow()>
 
 	// Length of sub-type elements will be added by sub-type...
 	lengthInBits += m.Child.LengthInBits()
 					<#break>
 				<#case "unknown">
-					<#assign unknownField = field>
-					<#assign simpleTypeReference = unknownField.type>
+					<#assign unknownField = field.asUnknownField().orElseThrow()>
+					<#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Unknown field
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 
 					<#break>
 				<#case "virtual">
-					<#assign virtualField = field>
+					<#assign virtualField = field.asVirtualField().orElseThrow()>
 
 	// A virtual field doesn't have any in- or output.
 					<#break>
@@ -400,14 +387,15 @@ func (m *${type.name}) ParentLengthInBits() uint16 {
 	<#list type.fields as field>
 		<#switch field.typeName>
 			<#case "array">
-				<#assign arrayField = field>
+				<#assign arrayField = field.asArrayField().orElseThrow()>
 
 	// Array field
 	if len(m.${arrayField.name?cap_first}) > 0 {
-				<#assign simpleTypeReference = arrayField.type>
 				<#if helper.getLanguageTypeNameForTypeReference(arrayField.type) = "string">
-		lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)}) * uint16(len(m.${arrayField.name?cap_first}))
+					<#assign stringTypeReference=arrayField.type.asSimpleTypeReference().orElseThrow()>
+		lengthInBits += uint16(${helper.toSerializationExpression(arrayField, stringTypeReference.asStringTypeReference().orElseThrow().getLengthExpression(), parserArguments)}) * uint16(len(m.${arrayField.name?cap_first}))
 				<#elseif helper.isSimpleTypeReference(arrayField.type)>
+                    <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
 		lengthInBits += ${simpleTypeReference.sizeInBits} * uint16(len(m.${arrayField.name?cap_first}))
 				<#else>
 					<#if helper.isCountArrayField(arrayField)>
@@ -423,34 +411,34 @@ func (m *${type.name}) ParentLengthInBits() uint16 {
 				}
 				<#break>
 			<#case "checksum">
-				<#assign checksumField = field>
-				<#assign simpleTypeReference = checksumField.type>
+				<#assign checksumField = field.asChecksumField().orElseThrow()>
+				<#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Checksum Field (checksum)
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 				<#break>
 			<#case "const">
-				<#assign constField = field>
+				<#assign constField = field.asConstField().orElseThrow()>
 				<#assign simpleTypeReference = constField.type>
 
 	// Const Field (${constField.name})
 				<#if helper.getLanguageTypeNameForTypeReference(constField.type) = "string">
-	lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)})
+	lengthInBits += uint16(${helper.toSerializationExpression(constField, simpleTypeReference.asStringTypeReference().orElseThrow().getLengthExpression(), parserArguments)})
 				<#elseif helper.isEnumTypeReference(constField.type)>
 	lengthInBits += ${helper.getEnumBaseTypeReference(constField.type).sizeInBits};
 				<#else>
-	lengthInBits += ${simpleTypeReference.sizeInBits}
+	lengthInBits += ${simpleTypeReference.asSimpleTypeReference().orElseThrow().sizeInBits}
 				</#if>
 				<#break>
 			<#case "discriminator">
-				<#assign discriminatorField = field>
+				<#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 				<#assign simpleTypeReference = discriminatorField.type>
 	// Discriminator Field (${discriminatorField.name})
 				<#if helper.isSimpleTypeReference(simpleTypeReference)>
 					<#if helper.getLanguageTypeNameForTypeReference(discriminatorField.type) = "String">
-	lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)})
+	lengthInBits += uint16(${helper.toSerializationExpression(discriminatorField, discriminatorField.type.asStringTypeReference().orElseThrow().getLengthExpression(), parserArguments)})
 					<#else>
-	lengthInBits += ${simpleTypeReference.sizeInBits};
+	lengthInBits += ${simpleTypeReference.asSimpleTypeReference().orElseThrow().sizeInBits};
 					</#if>
 				<#elseif helper.isEnumField(discriminatorField)>
 	lengthInBits += ${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits};
@@ -459,37 +447,37 @@ func (m *${type.name}) ParentLengthInBits() uint16 {
 				</#if>
 				<#break>
 			<#case "enum">
-				<#assign enumField = field>
+				<#assign enumField = field.asEnumField().orElseThrow()>
 
 	// Enum Field (${enumField.name})
 	lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits}
 				<#break>
 			<#case "implicit">
-				<#assign implicitField = field>
+				<#assign implicitField = field.asImplicitField().orElseThrow()>
 				<#assign simpleTypeReference = implicitField.type>
 
 	// Implicit Field (${implicitField.name})
-	lengthInBits += ${simpleTypeReference.sizeInBits}
+	lengthInBits += ${simpleTypeReference.asSimpleTypeReference().orElseThrow().sizeInBits}
 				<#break>
 			<#case "manualArray">
-				<#assign manualArrayField = field>
+				<#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 
 	// Manual Array Field (${manualArrayField.name})
-	lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, type.parserArguments)} * 8
+	lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, parserArguments)} * 8
 				<#break>
 			<#case "manual">
-				<#assign manualField = field>
+				<#assign manualField = field.asManualField().orElseThrow()>
 
 	// Manual Field (${manualField.name})
-	lengthInBits += ${helper.toParseExpression(manualField, manualField.lengthExpression, type.parserArguments)} * 8
+	lengthInBits += ${helper.toParseExpression(manualField, manualField.lengthExpression, parserArguments)} * 8
 				<#break>
 			<#case "optional">
-				<#assign optionalField = field>
+				<#assign optionalField = field.asOptionalField().orElseThrow()>
 
 	// Optional Field (${optionalField.name})
 	if m.${optionalField.name?cap_first} != nil {
 				<#if helper.isSimpleTypeReference(optionalField.type)>
-					<#assign simpleTypeReference = optionalField.type>
+					<#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
 		lengthInBits += ${simpleTypeReference.sizeInBits}
 				<#elseif helper.isEnumField(field)>
 		lengthInBits += ${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits}
@@ -499,32 +487,32 @@ func (m *${type.name}) ParentLengthInBits() uint16 {
 	}
 				<#break>
 			<#case "padding">
-				<#assign paddingField = field>
-				<#assign simpleTypeReference = paddingField.type>
+				<#assign paddingField = field.asPaddingField().orElseThrow()>
+				<#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Padding Field (padding)
-	_timesPadding := uint8(${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, type.parserArguments)})
+	_timesPadding := uint8(${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, parserArguments)})
 	for ;_timesPadding > 0; _timesPadding-- {
 		lengthInBits += ${simpleTypeReference.sizeInBits}
 	}
 				<#break>
 			<#case "reserved">
-				<#assign reservedField = field>
-				<#assign simpleTypeReference = reservedField.type>
+				<#assign reservedField = field.asReservedField().orElseThrow()>
+				<#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Reserved Field (reserved)
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 				<#break>
 			<#case "simple">
-				<#assign simpleField = field>
+				<#assign simpleField = field.asSimpleField().orElseThrow()>
 
 	// Simple field (${simpleField.name})
 				<#if helper.isSimpleTypeReference(simpleField.type)>
 					<#if helper.getLanguageTypeNameForTypeReference(simpleField.type) = "string">
-						<#assign simpleTypeReference = simpleField.type>
-	lengthInBits += uint16(${helper.toSerializationExpression(simpleField, simpleTypeReference.getLengthExpression(), type.parserArguments)})
+						<#assign stringTypeReference = simpleField.type.asStringTypeReference().orElseThrow()>
+	lengthInBits += uint16(${helper.toSerializationExpression(simpleField, stringTypeReference.lengthExpression, parserArguments)})
 					<#else>
-						<#assign simpleTypeReference = simpleField.type>
+						<#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
 	lengthInBits += ${simpleTypeReference.sizeInBits};
 					</#if>
 				<#elseif helper.isEnumField(field)>
@@ -534,15 +522,15 @@ func (m *${type.name}) ParentLengthInBits() uint16 {
 				</#if>
 				<#break>
 			<#case "unknown">
-				<#assign unknownField = field>
-			<#assign simpleTypeReference = unknownField.type>
+				<#assign unknownField = field.asUnknownField().orElseThrow()>
+			<#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Unknown field
 	lengthInBits += ${simpleTypeReference.sizeInBits}
 
 				<#break>
 			<#case "virtual">
-				<#assign virtualField = field>
+				<#assign virtualField = field.asVirtualField().orElseThrow()>
 
 	// A virtual field doesn't have any in- or output.
 				<#break>
@@ -557,10 +545,10 @@ func (m *${type.name}) LengthInBytes() uint16 {
 	return m.LengthInBits() / 8
 }
 
-<#assign hasParserArguments=type.parserArguments?has_content/>
-<#assign parserArgumentList><#if hasParserArguments><#list type.parserArguments as parserArgument>${parserArgument.name}${tracer.dive("parserArgument")} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if></#assign>
-<#assign hasParentParserArguments=(type.parentType?? && type.parentType.parserArguments?has_content && type.parentType.parserArguments?filter(arg -> hasParserArguments && !type.parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments)?has_content)>
-<#assign parentParserArgumentList><#if hasParentParserArguments><#list type.parentType.parserArguments?filter(arg -> (hasParserArguments && !type.parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments) && helper.isNonDiscriminatorField(arg.name)) as parserArgument>${tracer.dive("parentParserArgument")}${parserArgument.name} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if>${helper.getLan [...]
+<#assign hasParserArguments=parserArguments?has_content/>
+<#assign parserArgumentList><#if hasParserArguments><#list parserArguments as parserArgument>${parserArgument.name}${tracer.dive("parserArgument")} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if></#assign>
+<#assign hasParentParserArguments=(type.parentType?? && type.parentType.parserArguments.isPresent() && type.parentType.parserArguments.orElseThrow()?filter(arg -> hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments)?has_content)>
+<#assign parentParserArgumentList><#if hasParentParserArguments><#list type.parentType.parserArguments.orElseThrow()?filter(arg -> (hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments) && helper.isNonDiscriminatorField(arg.name)) as parserArgument>${tracer.dive("parentParserArgument")}${parserArgument.name} <#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>*</#if>${help [...]
 func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${parserArgumentList}</#if><#if hasParentParserArguments>, ${parentParserArgumentList}</#if>) (*<#if type.parentType?has_content>${type.parentType.name}<#else>${type.name}</#if>, error) {
 	if pullErr := readBuffer.PullContext("${type.name}"); pullErr != nil {
 		return nil, pullErr
@@ -572,18 +560,18 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	<#list type.fields as field>
 		<#switch field.typeName>
 			<#case "array">
-				<#assign arrayField = field>
+				<#assign arrayField = field.asArrayField().orElseThrow()>
 				<#if helper.isByteBased(arrayField.type)>
 	// Byte Array field (${arrayField.name})
 	<#assign numberOfBytesExpression>
 		<#compress>
 		<#if helper.isCountArrayField(field)>
-			numberOfBytes := int(${helper.toIntegerParseExpression(16, arrayField.loopExpression, type.parserArguments)})
+			numberOfBytes := int(${helper.toIntegerParseExpression(16, arrayField.loopExpression, parserArguments)})
 		<#elseif helper.isLengthArrayField(field)>
-			numberOfBytes := int(${helper.toIntegerParseExpression(16, arrayField.loopExpression, type.parserArguments)})
+			numberOfBytes := int(${helper.toIntegerParseExpression(16, arrayField.loopExpression, parserArguments)})
 		<#elseif helper.isTerminatedArrayField(field)>
 			<#-- TODO: we need to find out to implement this-->
-			numberOfBytes := int(${helper.toIntegerParseExpression(16, arrayField.loopExpression, type.parserArguments)})
+			numberOfBytes := int(${helper.toIntegerParseExpression(16, arrayField.loopExpression, parserArguments)})
 		<#else>
 			<#-- TODO: we should throw a exception here-->
 			numberOfBytes := int(-1)
@@ -608,12 +596,12 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 			<#-- If this is a count array, we can directly initialize an array with the given size -->
 					<#if helper.isCountArrayField(field)>
 	// Count array
-	${arrayField.name} := make([]<#if helper.isComplexTypeReference(arrayField.type)>*</#if>${helper.getLanguageTypeNameForField(field)}, ${helper.toIntegerParseExpression(16, arrayField.loopExpression, type.parserArguments)})
-	for curItem := uint16(0); curItem < uint16(${helper.toIntegerParseExpression(16, arrayField.loopExpression, type.parserArguments)}); curItem++ {
+	${arrayField.name} := make([]<#if helper.isComplexTypeReference(arrayField.type)>*</#if>${helper.getLanguageTypeNameForField(field)}, ${helper.toIntegerParseExpression(16, arrayField.loopExpression, parserArguments)})
+	for curItem := uint16(0); curItem < uint16(${helper.toIntegerParseExpression(16, arrayField.loopExpression, parserArguments)}); curItem++ {
 					<#if (!helper.isSimpleTypeReference(arrayField.type)) && helper.requiresVariable(arrayField, "lastItem")>
-		lastItem := curItem == uint16(${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)} - 1)
+		lastItem := curItem == uint16(${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)} - 1)
 					</#if>
-		_item, _err := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall("", arrayField.type)}<#else>${arrayField.type.name}Parse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${helper.toTypedParseExpression(helper.getArgumentType(arrayField.type, parserArgument?index), parserArgument, type.parserArguments)}<#sep>, </#sep></# [...]
+		_item, _err := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow())}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}Parse(readBuffer<#if field.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${helper.toTypedParseExpression(helper.getArgumentType(array [...]
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing '${arrayField.name}' field")<@emitImport import="github.com/pkg/errors" />
 		}
@@ -624,10 +612,10 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 				<#-- For a length array, we read data till the read position of the buffer reaches a given position -->
 	// Length array
 	${arrayField.name} := make([]<#if helper.isComplexTypeReference(arrayField.type)>*</#if>${helper.getLanguageTypeNameForField(field)}, 0)
-	_${arrayField.name}Length := ${helper.toIntegerParseExpression(16, arrayField.loopExpression, type.parserArguments)}
+	_${arrayField.name}Length := ${helper.toIntegerParseExpression(16, arrayField.loopExpression, parserArguments)}
 	_${arrayField.name}EndPos := readBuffer.GetPos() + uint16(_${arrayField.name}Length)
 	for ;readBuffer.GetPos() < _${arrayField.name}EndPos; {
-		_item, _err := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall("", arrayField.type)}<#else>${arrayField.type.name}Parse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${helper.toTypedParseExpression(helper.getArgumentType(arrayField.type, parserArgument?index), parserArgument, type.parserArguments)}<#sep>, </#sep></# [...]
+		_item, _err := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow())}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}Parse(readBuffer<#if field.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${helper.toTypedParseExpression(helper.getArgumentType(array [...]
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing '${arrayField.name}' field")<@emitImport import="github.com/pkg/errors" />
 		}
@@ -641,8 +629,8 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 					<#elseif helper.isTerminatedArrayField(field)>
 	// Terminated array
 	${arrayField.name} := make([]<#if helper.isComplexTypeReference(arrayField.type)>*</#if>${helper.getLanguageTypeNameForField(field)}, 0)
-	for ;!bool(${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}); {
-		_item, _err := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall("", arrayField.type)}<#else>${arrayField.type.name}Parse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${helper.toTypedParseExpression(helper.getArgumentType(arrayField.type, parserArgument?index), parserArgument, type.parserArguments)}<#sep>, </#sep></# [...]
+	for ;!bool(${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}); {
+		_item, _err := <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow())}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}Parse(readBuffer<#if field.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${helper.toTypedParseExpression(helper.getArgumentType(array [...]
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing '${arrayField.name}' field")<@emitImport import="github.com/pkg/errors" />
 		}
@@ -660,8 +648,8 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 				</#if>
 				<#break>
 			<#case "checksum">
-				<#assign checksumField = field>
-				<#assign simpleTypeReference = checksumField.type>
+				<#assign checksumField = field.asChecksumField().orElseThrow()>
+				<#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Checksum Field (checksum)
 	{
@@ -669,7 +657,7 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 		if _checksumRefErr != nil {
 			return nil, errors.Wrap(_checksumRefErr, "Error parsing 'checksum' field")<@emitImport import="github.com/pkg/errors" />
 		}
-		checksum, _checksumErr := ${helper.toParseExpression(checksumField, checksumField.checksumExpression, type.parserArguments)}
+		checksum, _checksumErr := ${helper.toParseExpression(checksumField, checksumField.checksumExpression, parserArguments)}
 		if _checksumErr != nil {
 			return nil, errors.Wrap(_checksumErr, "Error parsing 'checksum' field")<@emitImport import="github.com/pkg/errors" />
 		}
@@ -679,17 +667,18 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "const">
-				<#assign constField = field>
-				<#assign simpleTypeReference = constField.type>
+				<#assign constField = field.asConstField().orElseThrow()>
 
 	// Const Field (${constField.name})
 				<#if helper.isEnumTypeReference(constField.type)>
-                    <#if constField.fieldName?has_content>
-	${constField.name}${constField.fieldName?cap_first}, _${constField.name}${constField.fieldName?cap_first}Err := ${helper.getReadBufferReadMethodCall(constField.type.name, helper.getConstFieldSimpleTypeReference(constField.type, constField.fieldName))}
-	if _${constField.name}${constField.fieldName?cap_first}Err != nil {
-		return nil, errors.Wrap(_${constField.name}${constField.fieldName?cap_first}Err, "Error serializing '${constField.name}' field")<@emitImport import="github.com/pkg/errors" />
-	}
-	${constField.name}, _${constField.name}Err := ${helper.getLanguageTypeNameForField(field)}FirstEnumForField${constField.fieldName?cap_first}(${constField.name}${constField.fieldName?cap_first})
+                    <#--<#assign constField=constField.asEnumField().orElseThrow()>-->
+					<#-- TODO: finish me-->
+                    <#if false && constField.fieldName.isPresent()>
+	${constField.name}${constField.fieldName.orElseThrow()?cap_first}, _${constField.name}${constField.fieldName.orElseThrow()?cap_first}Err := ${helper.getReadBufferReadMethodCall(constField.name, helper.getEnumFieldSimpleTypeReference(constField.type, constField.fieldName.orElseThrow()))}
+	if _${constField.name}${constField.fieldName.orElseThrow()?cap_first}Err != nil {
+		return nil, errors.Wrap(_${constField.name}${constField.fieldName.orElseThrow()?cap_first}Err, "Error serializing '${constField.name}' field")<@emitImport import="github.com/pkg/errors" />
+	}
+	${constField.name}, _${constField.name}Err := ${helper.getLanguageTypeNameForField(field)}FirstEnumForField${constField.fieldName.orElseThrow()?cap_first}(${constField.name}${constField.fieldName.orElseThrow()?cap_first})
 	if _${constField.name}Err != nil {
 		return nil, errors.Wrap(_${constField.name}Err, "Error serializing '${constField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
@@ -700,7 +689,7 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
                     </#if> 
 				<#else>
-	${constField.name}, _${constField.name}Err := ${helper.getReadBufferReadMethodCall(constField.name, simpleTypeReference)}
+	${constField.name}, _${constField.name}Err := ${helper.getReadBufferReadMethodCall(constField.name, constField.type.asSimpleTypeReference().orElseThrow())}
 				</#if>
 	if _${constField.name}Err != nil {
 		return nil, errors.Wrap(_${constField.name}Err, "Error parsing '${constField.name}' field")<@emitImport import="github.com/pkg/errors" />
@@ -710,14 +699,14 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "discriminator">
-				<#assign discriminatorField = field>
-				<#assign simpleTypeReference = discriminatorField.type>
+				<#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 
 	// Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
 	<#if helper.isEnumField(field)>
 	${helper.getVariableName(field)}_temp, _${discriminatorField.name}Err := ${helper.getLanguageTypeNameForField(discriminatorField)}Parse(readBuffer)
 	var ${helper.getVariableName(field)} ${helper.getLanguageTypeNameForField(discriminatorField)} = ${helper.getVariableName(field)}_temp
 	<#else>
+        <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
 	${helper.getVariableName(field)}, _${discriminatorField.name}Err := ${helper.getReadBufferReadMethodCall(discriminatorField.name, simpleTypeReference)}
 	</#if>
 	if _${discriminatorField.name}Err != nil {
@@ -725,18 +714,18 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "enum">
-				<#assign enumField = field>
+				<#assign enumField = field.asEnumField().orElseThrow()>
 
 	if pullErr := readBuffer.PullContext("${enumField.name}"); pullErr != nil {
 		return nil, pullErr
 	}
-				<#if enumField.fieldName?has_content>
+				<#if enumField.fieldName.isPresent()>
 	// Enum field (${enumField.name})
-	${enumField.name}${enumField.fieldName?cap_first}, _${enumField.name}${enumField.fieldName?cap_first}Err := ${helper.getReadBufferReadMethodCall(enumField.type.name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName))}
-	if _${enumField.name}${enumField.fieldName?cap_first}Err != nil {
-		return nil, errors.Wrap(_${enumField.name}${enumField.fieldName?cap_first}Err, "Error serializing '${enumField.name}' field")<@emitImport import="github.com/pkg/errors" />
+	${enumField.name}${enumField.fieldName.orElseThrow()?cap_first}, _${enumField.name}${enumField.fieldName.orElseThrow()?cap_first}Err := ${helper.getReadBufferReadMethodCall(enumField.type.name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()))}
+	if _${enumField.name}${enumField.fieldName.orElseThrow()?cap_first}Err != nil {
+		return nil, errors.Wrap(_${enumField.name}${enumField.fieldName.orElseThrow()?cap_first}Err, "Error serializing '${enumField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
-	${enumField.name}, _${enumField.name}Err := ${helper.getLanguageTypeNameForField(field)}FirstEnumForField${enumField.fieldName?cap_first}(${enumField.name}${enumField.fieldName?cap_first})
+	${enumField.name}, _${enumField.name}Err := ${helper.getLanguageTypeNameForField(field)}FirstEnumForField${enumField.fieldName.orElseThrow()?cap_first}(${enumField.name}${enumField.fieldName.orElseThrow()?cap_first})
 	if _${enumField.name}Err != nil {
 		return nil, errors.Wrap(_${enumField.name}Err, "Error serializing '${enumField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
@@ -752,8 +741,8 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "implicit">
-				<#assign implicitField = field>
-				<#assign simpleTypeReference = implicitField.type>
+				<#assign implicitField = field.asImplicitField().orElseThrow()>
+				<#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
 	${implicitField.name}, _${implicitField.name}Err := ${helper.getReadBufferReadMethodCall(implicitField.name, simpleTypeReference)}
@@ -763,7 +752,7 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "manualArray">
-				<#assign manualArrayField = field>
+				<#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 	if pullErr := readBuffer.PullContext("${manualArrayField.name}", utils.WithRenderAsList(true)); pullErr != nil {
 		return nil, pullErr
 	}
@@ -775,21 +764,21 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 			<#-- If this is a count array, we can directly initialize an array with the given size -->
 				<#if helper.isCountArrayField(field)>
 	// Count array
-	_${manualArrayField.name}Count := ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)}
+	_${manualArrayField.name}Count := ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)}
 	${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}Count]
 	for i := 0; i < _${manualArrayField.name}Count; i++ {
-		${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)})
+		${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)})
 	}
 				<#-- In all other cases do we have to work with a list, that is later converted to an array -->
 				<#else>
 				<#-- For a length array, we read data till the read position of the buffer reaches a given position -->
 					<#if helper.isLengthArrayField(field)>
 	// Length array
-	_${manualArrayField.name}Length := ${helper.toIntegerParseExpression(16, manualArrayField.loopExpression, type.parserArguments)}
+	_${manualArrayField.name}Length := ${helper.toIntegerParseExpression(16, manualArrayField.loopExpression, parserArguments)}
 	_${manualArrayField.name}List := make([]${helper.getLanguageTypeNameForField(manualArrayField)}, 0)
 	${manualArrayField.name}EndPos := readBuffer.GetPos() + _${manualArrayField.name}Length
 	for ;readBuffer.GetPos() < ${manualArrayField.name}EndPos; {
-		_${manualArrayField.name}List = append(_${manualArrayField.name}List, ((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)})))
+		_${manualArrayField.name}List = append(_${manualArrayField.name}List, ((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)})))
 					<#-- After parsing, update the current position, but only if it's needed -->
 						<#if manualArrayField.loopExpression.contains("curPos")>
 		curPos = readBuffer.GetPos() - startPos
@@ -799,8 +788,8 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 					<#elseif helper.isTerminatedArrayField(field)>
 	// Terminated array
 	_${manualArrayField.name}List := make([]${helper.getLanguageTypeNameForField(manualArrayField)}, 0)
-	for ;!((bool) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)})); {
-		_${manualArrayField.name}List = append(_${manualArrayField.name}List, ((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)})))
+	for ;!((bool) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)})); {
+		_${manualArrayField.name}List = append(_${manualArrayField.name}List, ((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)})))
 
 					<#-- After parsing, update the current position, but only if it's needed -->
 						<#if manualArrayField.loopExpression.contains("curPos")>
@@ -827,13 +816,13 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "manual">
-				<#assign manualField = field>
+				<#assign manualField = field.asManualField().orElseThrow()>
 
 	// Manual Field (${manualField.name})
 	if pullErr := readBuffer.PullContext("${manualField.name}"); pullErr != nil {
 		return nil, pullErr
 	}
-	${manualField.name}, _${manualField.name}Err := ${helper.toParseExpression(manualField, manualField.parseExpression, type.parserArguments)}
+	${manualField.name}, _${manualField.name}Err := ${helper.toParseExpression(manualField, manualField.parseExpression, parserArguments)}
 	if _${manualField.name}Err != nil {
 		return nil, errors.Wrap(_${manualField.name}Err, "Error parsing '${manualField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
@@ -842,16 +831,16 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 			<#break>
 			<#case "optional">
-				<#assign optionalField = field>
+				<#assign optionalField = field.asOptionalField().orElseThrow()>
 
 	// Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false)
 				<#if optionalField.conditionExpression.contains("curPos")>
 	curPos = readBuffer.GetPos() - startPos
 				</#if>
 	var ${optionalField.name} *${helper.getLanguageTypeNameForField(field)} = nil
-	if ${helper.toBooleanParseExpression(optionalField.conditionExpression, type.parserArguments)} {
+	if ${helper.toBooleanParseExpression(optionalField.conditionExpression, parserArguments)} {
 			<#if helper.isSimpleTypeReference(optionalField.type)>
-		_val, _err := ${helper.getReadBufferReadMethodCall(optionalField.name, optionalField.type)}
+		_val, _err := ${helper.getReadBufferReadMethodCall(optionalField.name, optionalField.type.asSimpleTypeReference().orElseThrow())}
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing '${optionalField.name}' field")<@emitImport import="github.com/pkg/errors" />
 		}
@@ -864,7 +853,7 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 		${optionalField.name} = &_val
 			<#else>
 				<@compress single_line=true>
-                <#assign complexTypeReference=optionalField.type>
+                <#assign complexTypeReference=optionalField.type.asComplexTypeReference().orElseThrow()>
                 <#assign typeName=complexTypeReference.name>
                 <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
                 <#if helper.isDiscriminatedChildTypeDefinition(typeDefinition)>
@@ -872,21 +861,21 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
                     <#assign typeName=typeDefinition.parentType.name>
                     <#assign typeDefinition=typeDefinition.parentType>
                 </#if>
-				<#assign hasFieldParams=field.params?has_content>
+				<#assign hasFieldParams=field.params.isPresent()>
 				<#assign fieldParams>
 					<#if hasFieldParams>
 						,
-						<#list field.params as parserArgument>
-							${helper.toTypedParseExpression(helper.getArgumentType(optionalField.type, parserArgument?index), parserArgument, type.parserArguments)}
+						<#list field.params.orElseThrow() as parserArgument>
+							${helper.toTypedParseExpression(helper.getArgumentType(optionalField.type, parserArgument?index), parserArgument, parserArguments)}
 							<#sep>, </#sep>
 						</#list>
 					</#if>
 				</#assign>
-				<#assign hasRefParams=complexTypeReference.params?has_content && typeDefinition.parserArguments?has_content>
+				<#assign hasRefParams=complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
 				<#assign refParams>
                     <#if hasRefParams>
 						,
-						<#list complexTypeReference.params as typeParam>
+						<#list complexTypeReference.params.orElseThrow() as typeParam>
 							${helper.toTypedParseExpression(null, typeParam, null)}
 							<#sep>, </#sep>
 						</#list>
@@ -903,14 +892,14 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 			<#break>
 			<#case "assert">
-				<#assign assertField = field>
+				<#assign assertField = field.asAssertField().orElseThrow()>
 
 	// Assert Field (${assertField.name}) (Can be skipped, if a given expression evaluates to false)
 				<#if assertField.conditionExpression.contains("curPos")>
 	curPos = readBuffer.GetPos() - startPos
 				</#if>
 			<#if helper.isSimpleTypeReference(assertField.type)>
-	${assertField.name}, _err := ${helper.getReadBufferReadMethodCall(assertField.name, assertField.type)}
+	${assertField.name}, _err := ${helper.getReadBufferReadMethodCall(assertField.name, assertField.type.asSimpleTypeReference().orElseThrow())}
 	if _err != nil {
 		return nil, errors.Wrap(_err, "Error parsing '${assertField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
@@ -921,7 +910,7 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 			<#else>
 				<@compress single_line=true>
-                <#assign complexTypeReference=assertField.type>
+                <#assign complexTypeReference=assertField.type.asComplexTypeReference().orElseThrow()>
                 <#assign typeName=complexTypeReference.name>
                 <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
                 <#if helper.isDiscriminatedChildTypeDefinition(typeDefinition)>
@@ -929,10 +918,10 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
                     <#assign typeName=typeDefinition.parentType.name>
                     <#assign typeDefinition=typeDefinition.parentType>
                 </#if>
-				<#assign hasFieldParams=field.params?has_content>
-				<#assign fieldParams><#if hasFieldParams>, <#list field.params as parserArgument>${helper.toTypedParseExpression(helper.getArgumentType(assertField.type, parserArgument?index), parserArgument, type.parserArguments)}<#sep>, </#sep></#list></#if></#assign>
-				<#assign hasRefParams=complexTypeReference.params?has_content && typeDefinition.parserArguments?has_content>
-				<#assign refParams> <#if hasRefParams> <#assign filteredCompleTypeReferences=helper.removeDiscriminatorsFromReferenceParams(assertField, complexTypeReference)> , <#list filteredCompleTypeReferences as typeParam>${helper.toTypedParseExpression(null, typeParam, null)}<#sep>, </#sep></#list> </#if> </#assign>
+				<#assign hasFieldParams=field.params.isPresent()>
+				<#assign fieldParams><#if hasFieldParams>, <#list field.params.orElseThrow() as parserArgument>${helper.toTypedParseExpression(helper.getArgumentType(assertField.type, parserArgument?index), parserArgument, parserArguments)}<#sep>, </#sep></#list></#if></#assign>
+				<#assign hasRefParams=complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
+				<#assign refParams> <#if hasRefParams>, <#list complexTypeReference.params.orElseThrow() as typeParam>${helper.toTypedParseExpression(null, typeParam, null)}<#sep>, </#sep></#list> </#if> </#assign>
                 </...@compress>
 	_val, _err := ${helper.getLanguageTypeNameForField(field)}Parse(readBuffer${fieldParams}${refParams})
 	if _err != nil {
@@ -942,15 +931,15 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 			</#if>
 				<#break>
 			<#case "padding">
-				<#assign paddingField = field>
-				<#assign simpleTypeReference = paddingField.type>
+				<#assign paddingField = field.asPaddingField().orElseThrow()>
+				<#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Padding Field (padding)
 	{
 		if pullErr := readBuffer.PullContext("padding", utils.WithRenderAsList(true)); pullErr != nil {
 			return nil, pullErr
 		}
-		_timesPadding := (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)})
+		_timesPadding := (${helper.toParseExpression(paddingField, paddingField.paddingCondition, parserArguments)})
 		for ;(readBuffer.HasMore(${helper.getNumBits(simpleTypeReference)})) && (_timesPadding > 0);_timesPadding-- {
 			// Just read the padding data and ignore it
 			_, _err := ${helper.getReadBufferReadMethodCall("", simpleTypeReference)}
@@ -964,8 +953,8 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "reserved">
-				<#assign reservedField = field>
-				<#assign simpleTypeReference = reservedField.type>
+				<#assign reservedField = field.asReservedField().orElseThrow()>
+				<#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Reserved Field (Compartmentalized so the "reserved" variable can't leak)
 	{
@@ -982,7 +971,7 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	}
 				<#break>
 			<#case "simple">
-				<#assign simpleField = field>
+				<#assign simpleField = field.asSimpleField().orElseThrow()>
 
 	// Simple Field (${simpleField.name})
 				<#if !helper.isSimpleTypeReference(simpleField.type)>
@@ -994,9 +983,9 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 	<@compress single_line=true>
 	${simpleField.name}, _${simpleField.name}Err :=
 	<#if helper.isSimpleTypeReference(simpleField.type)>
-		${helper.getReadBufferReadMethodCall(simpleFieldLogicalName, simpleField.type, null, field)}
+		${helper.getReadBufferReadMethodCall(simpleFieldLogicalName, simpleField.type.asSimpleTypeReference().orElseThrow(), null, simpleField)}
 	<#else>
-        <#assign complexTypeReference=simpleField.type>
+        <#assign complexTypeReference=simpleField.type.asComplexTypeReference().orElseThrow()>
         <#assign typeName=complexTypeReference.name>
         <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
         <#if helper.isDiscriminatedChildTypeDefinition(typeDefinition)>
@@ -1004,21 +993,21 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
             <#assign typeName=typeDefinition.parentType.name>
             <#assign typeDefinition=typeDefinition.parentType>
         </#if>
-        <#assign hasFieldParams=field.params?has_content>
+        <#assign hasFieldParams=field.params.isPresent()>
         <#assign fieldParams>
             <#if hasFieldParams>
 				,
-                <#list field.params as parserArgument>
-                    ${helper.toTypedParseExpression(helper.getArgumentType(simpleField.type, parserArgument?index), parserArgument, type.parserArguments)}
+                <#list field.params.orElseThrow() as parserArgument>
+                    ${helper.toTypedParseExpression(helper.getArgumentType(simpleField.type, parserArgument?index), parserArgument, parserArguments)}
                     <#sep>, </#sep>
                 </#list>
             </#if>
         </#assign>
-        <#assign hasRefParams=complexTypeReference.params?has_content && typeDefinition.parserArguments?has_content>
+        <#assign hasRefParams=complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
         <#assign refParams>
             <#if hasRefParams>
 				,
-                <#list complexTypeReference.params as typeParam>
+                <#list complexTypeReference.params.orElseThrow() as typeParam>
                     ${helper.toTypedParseExpression(null, typeParam, null)}
                     <#sep>, </#sep>
                 </#list>
@@ -1043,16 +1032,44 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 				<#break>
 
 			<#case "switch">
-				<#assign switchField = field>
+				<#assign switchField = field.asSwitchField().orElseThrow()>
 
 	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
 	var _parent *${type.name}
 	var typeSwitchError error
 	switch {
 				<#list switchField.cases as case>
-					<#--TODO: refactor the line below into multiple assigns -->
-	<#if case.discriminatorValues?has_content>case <#list case.discriminatorValues as discriminatorValue><#if helper.isComplexTypeReference(helper.getDiscriminatorTypes()[helper.toParseExpression(null, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)])></#if>${helper.toParseExpression(null, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(switchField.discrimin [...]
-		_parent, typeSwitchError = ${case.name}Parse(readBuffer<#if case.parserArguments?has_content>, <#list case.parserArguments as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${parserArgument.name}<#sep>, </#sep></#list></#if>)
+					<@compress single_line=true>
+						<#if case.discriminatorValues?has_content>
+							case
+							<#list case.discriminatorValues as discriminatorValue>
+								<#assign discriminatorExpression=switchField.discriminatorExpressions[discriminatorValue?index]>
+								<#assign parsedDiscriminatorExpression=helper.toParseExpression(null, discriminatorExpression, parserArguments)>
+								<#-- We remove debug informations as we need them for lookup-->
+								<#assign parsedDiscriminatorExpression=tracer.removeTraces(parsedDiscriminatorExpression)>
+								<#if helper.getDiscriminatorTypes()[parsedDiscriminatorExpression]??><#assign discriminatorType=helper.getDiscriminatorTypes()[parsedDiscriminatorExpression]></#if>
+								<#if helper.isComplexTypeReference(discriminatorType)>
+									<#--TODO: What is meant to be here????-->
+								</#if>
+								${helper.toParseExpression(null, discriminatorExpression, parserArguments)} ==
+								<#if helper.discriminatorValueNeedsStringEqualityCheck(discriminatorExpression)>"${discriminatorValue}"
+								<#elseif helper.isComplexTypeReference(discriminatorType)>
+									<#if helper.isEnumTypeReference(discriminatorType)>
+										${helper.getLanguageTypeNameForTypeReference(discriminatorType)}_${discriminatorValue}
+									<#else>
+										${discriminatorValue}
+									</#if>
+								<#else>
+									${discriminatorValue}
+								</#if>
+								<#sep> && </#sep>
+							</#list>
+						<#else>
+							<#assign defaultCaseOutput=true>
+						</#if>: // ${case.name}
+                    </...@compress>
+
+		_parent, typeSwitchError = ${case.name}Parse(readBuffer<#if case.parserArguments.isPresent()>, <#list case.parserArguments.orElseThrow() as parserArgument><#if helper.isOptionalField(helper.getFieldForNameFromCurrentOrParent(parserArgument.name))>*</#if>${parserArgument.name}<#sep>, </#sep></#list></#if>)
 				</#list>
 	default:
 		// TODO: return actual type
@@ -1064,20 +1081,20 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 				<#break>
 
 			<#case "unknown">
-				<#assign unknownField = field>
+				<#assign unknownField = field.asUnknownField().orElseThrow()>
 
 	// Unknown field
-	_, _UnknownErr := ${helper.getReadBufferReadMethodCall("unknown", unknownField.type, null, field)}
+	_, _UnknownErr := ${helper.getReadBufferReadMethodCall("unknown", unknownField.type.asSimpleTypeReference().orElseThrow(), null, unknownField)}
 	if _UnknownErr != nil {
 		return nil, errors.Wrap(_UnknownErr, "Error parsing unknown field")<@emitImport import="github.com/pkg/errors" />
 	}
 				<#break>
 
 			<#case "virtual">
-				<#assign virtualField = field>
+				<#assign virtualField = field.asVirtualField().orElseThrow()>
 
 	// Virtual field
-	${virtualField.name} := ${helper.toParseExpression(virtualField, virtualField.valueExpression, type.parserArguments)}
+	${virtualField.name} := ${helper.toParseExpression(virtualField, virtualField.valueExpression, parserArguments)}
 				<#break>
 		</#switch>
 	</#list>
@@ -1107,13 +1124,13 @@ func ${type.name}Parse(readBuffer utils.ReadBuffer<#if hasParserArguments>, ${pa
 }
 
 <#if helper.isDiscriminatedParentTypeDefinition()>
-func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
-	return m.Child.Serialize(writeBuffer<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>)
+func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
+	return m.Child.Serialize(writeBuffer<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>)
 }
 
-func (m *${type.name}) SerializeParent(writeBuffer utils.WriteBuffer, child I${type.name}, serializeChildFunction func() error<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
+func (m *${type.name}) SerializeParent(writeBuffer utils.WriteBuffer, child I${type.name}, serializeChildFunction func() error<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
 <#else>
-func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
+func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name} ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}<#sep>, </#sep></#list></#if>) error {
 </#if>
 	<#if helper.hasFieldOfType("unknown")>
 	return errors.New("Unknown field not serializable")
@@ -1145,7 +1162,7 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 		<#list type.fields as field>
 			<#switch field.typeName>
 				<#case "array">
-					<#assign arrayField = field>
+					<#assign arrayField = field.asArrayField().orElseThrow()>
 					<#assign simpleTypeReference = arrayField.type>
 
 	// Array Field (${arrayField.name})
@@ -1166,14 +1183,14 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 					</#if>
 		for _, _element := range m.${arrayField.name?cap_first} {
 						<#if helper.isSimpleTypeReference(arrayField.type)>
-							<#assign simpleTypeReference = arrayField.type>
-			_elementErr := ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "_element", field)}
+							<#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
+			_elementErr := ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "_element", arrayField)}
 						<#else>
 						<#assign complexTypeReference = arrayField.type>
 						<#if helper.needsVariable(arrayField, "lastItem", true)>
 			var lastItem bool = curItem == (itemCount - 1)
 						</#if>
-			_elementErr := _element.Serialize(writeBuffer<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>)
+			_elementErr := _element.Serialize(writeBuffer<#if helper.getSerializerTerms(arrayField.params.orElse(null))?has_content>, <#list helper.getSerializerTerms(arrayField.params.orElse(null)) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>)
 					</#if>
 			if _elementErr != nil {
 				return errors.Wrap(_elementErr, "Error serializing '${arrayField.name}' field")<@emitImport import="github.com/pkg/errors" />
@@ -1189,30 +1206,30 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "checksum">
-					<#assign checksumField = field>
-					<#assign simpleTypeReference = checksumField.type>
+					<#assign checksumField = field.asChecksumField().orElseThrow()>
+					<#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Checksum Field (checksum) (Calculated)
 	{
-		_checksum, _checksumErr := ${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, type.parserArguments)}
+		_checksum, _checksumErr := ${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, parserArguments)}
 		if _checksumErr != nil {
 			return errors.Wrap(_checksumErr, "Error serializing 'checksum' field")<@emitImport import="github.com/pkg/errors" />
 		}
-		_checksumErr = ${helper.getWriteBufferWriteMethodCall("checksum", simpleTypeReference, "(_checksum)", field)}
+		_checksumErr = ${helper.getWriteBufferWriteMethodCall("checksum", simpleTypeReference, "(_checksum)", checksumField)}
 		if _checksumErr != nil {
 			return errors.Wrap(_checksumErr, "Error serializing 'checksum' field")<@emitImport import="github.com/pkg/errors" />
 		}
 	}
 					<#break>
 				<#case "const">
-					<#assign constField = field>
-					<#assign simpleTypeReference = constField.type>
+					<#assign constField = field.asConstField().orElseThrow()>
 
 					<#if helper.isEnumTypeReference(constField.type)>
+						<#-- TODO: finish me-->
                         <#if constField.fieldName?has_content>
                             <#assign enumValueFieldAccessor=type.name+"_"+constField.name?upper_case>
 	// Const field (${constField.name})
-	_${constField.name}Err := ${helper.getWriteBufferWriteMethodCall(constField.type.name, helper.getConstFieldSimpleTypeReference(constField.type, constField.fieldName), enumValueFieldAccessor, constField, "utils.WithAdditionalStringRepresentation(${type.name}_${constField.name?upper_case}.name())")}
+	_${constField.name}Err := ${helper.getWriteBufferWriteMethodCall(constField.type.name, helper.getEnumFieldSimpleTypeReference(constField.type, constField.fieldName), enumValueFieldAccessor, constField, "utils.WithAdditionalStringRepresentation(${type.name}_${constField.name?upper_case}.name())")}
 	if _${constField.name}Err != nil {
 		return errors.Wrap(_${constField.name}Err, "Error serializing '${constField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
@@ -1226,22 +1243,22 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
                         </#if>
 					<#else>
 	// Const Field (${constField.name})
-	_${constField.name}Err := ${helper.getWriteBufferWriteMethodCall(constField.name, simpleTypeReference, constField.referenceValue, field)}
+	_${constField.name}Err := ${helper.getWriteBufferWriteMethodCall(constField.name, constField.type.asSimpleTypeReference().orElseThrow(), constField.referenceValue, constField)}
 	if _${constField.name}Err != nil {
 		return errors.Wrap(_${constField.name}Err, "Error serializing '${constField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
 					</#if>
 					<#break>
 				<#case "discriminator">
-					<#assign discriminatorField = field>
-					<#assign simpleTypeReference = discriminatorField.type>
+					<#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 
 	// Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
 	${discriminatorField.name} := ${helper.getLanguageTypeNameForField(field)}(child.${discriminatorField.name?cap_first}())
 					<#if helper.isEnumField(field)>
 	_${discriminatorField.name}Err := ${discriminatorField.name}.Serialize(writeBuffer)
 					<#else>
-	_${discriminatorField.name}Err := ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, simpleTypeReference, "(" + discriminatorField.name + ")", field)}
+                        <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
+	_${discriminatorField.name}Err := ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, simpleTypeReference, "(" + discriminatorField.name + ")", discriminatorField)}
 					</#if>
 
 	if _${discriminatorField.name}Err != nil {
@@ -1249,15 +1266,15 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "enum">
-					<#assign enumField = field>
+					<#assign enumField = field.asEnumField().orElseThrow()>
 
 	if pushErr := writeBuffer.PushContext("${enumField.name}"); pushErr != nil {
 		return pushErr
 	}
-						<#if enumField.fieldName?has_content>
-							<#assign enumValueFieldAccessor="m."+enumField.name?cap_first+"."+enumField.fieldName?cap_first+"()">
+						<#if enumField.fieldName.isPresent()>
+							<#assign enumValueFieldAccessor="m."+enumField.name?cap_first+"."+enumField.fieldName.orElseThrow()?cap_first+"()">
 	// Enum field (${enumField.name})
-	_${enumField.name}Err := ${helper.getWriteBufferWriteMethodCall(enumField.type.name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName), enumValueFieldAccessor, enumField, "utils.WithAdditionalStringRepresentation(m.${enumField.name?cap_first}.name())")}
+	_${enumField.name}Err := ${helper.getWriteBufferWriteMethodCall(enumField.type.asComplexTypeReference().orElseThrow().name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()), enumValueFieldAccessor, enumField, "utils.WithAdditionalStringRepresentation(m.${enumField.name?cap_first}.name())")}
 	if _${enumField.name}Err != nil {
 		return errors.Wrap(_${enumField.name}Err, "Error serializing '${enumField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
@@ -1274,18 +1291,18 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "implicit">
-					<#assign implicitField = field>
-					<#assign simpleTypeReference = implicitField.type>
+					<#assign implicitField = field.asImplicitField().orElseThrow()>
+					<#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-	${implicitField.name} := ${helper.getLanguageTypeNameForField(field)}(${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, type.parserArguments)})
-	_${implicitField.name}Err := ${helper.getWriteBufferWriteMethodCall(implicitField.name, simpleTypeReference, "(" + implicitField.name + ")", field)}
+	${implicitField.name} := ${helper.getLanguageTypeNameForField(field)}(${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, parserArguments)})
+	_${implicitField.name}Err := ${helper.getWriteBufferWriteMethodCall(implicitField.name, simpleTypeReference, "(" + implicitField.name + ")", implicitField)}
 	if _${implicitField.name}Err != nil {
 		return errors.Wrap(_${implicitField.name}Err, "Error serializing '${implicitField.name}' field")<@emitImport import="github.com/pkg/errors" />
 	}
 					<#break>
 				<#case "manualArray">
-					<#assign manualArrayField = field>
+					<#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 
 	// Manual Array Field (${manualArrayField.name})
 	if m.${manualArrayField.name?cap_first} != nil {
@@ -1294,7 +1311,7 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 		}
 		for _, Element := range m.${manualArrayField.name?cap_first} {
 			<#-- TODO at the moment the implementation below is broken as element get prefixed wrong therefore we substract it with substring-->
-			${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, type.parserArguments)?replace("m.","")}
+			${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, parserArguments)?replace("m.","")}
 		}
 		if popErr := writeBuffer.PopContext("${manualArrayField.name}", utils.WithRenderAsList(true)); popErr != nil {
 			return popErr
@@ -1302,13 +1319,13 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "manual">
-					<#assign manualField = field>
+					<#assign manualField = field.asManualField().orElseThrow()>
 
 	// Manual Field (${manualField.name})
 	if pushErr := writeBuffer.PushContext("${simpleField.name}"); pushErr != nil {
 		return pushErr
 	}
-	_${manualField.name}Err := ${helper.toSerializationExpression(manualField, manualField.serializeExpression, type.parserArguments)}
+	_${manualField.name}Err := ${helper.toSerializationExpression(manualField, manualField.serializeExpression, parserArguments)}
 	if popErr := writeBuffer.PopContext("${manualField.name}"); popErr != nil {
 		return popErr
 	}
@@ -1317,15 +1334,15 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "optional">
-					<#assign optionalField = field>
+					<#assign optionalField = field.asOptionalField().orElseThrow()>
 
 	// Optional Field (${optionalField.name}) (Can be skipped, if the value is null)
 	var ${optionalField.name} *${helper.getLanguageTypeNameForField(field)} = nil
 	if m.${optionalField.name?cap_first} != nil {
 					<#if helper.isSimpleTypeReference(optionalField.type)>
-						<#assign simpleTypeReference = optionalField.type>
+						<#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
 		${optionalField.name} = m.${optionalField.name?cap_first}
-		_${optionalField.name}Err := ${helper.getWriteBufferWriteMethodCall(optionalField.name, simpleTypeReference, "*(" + optionalField.name + ")", field)}
+		_${optionalField.name}Err := ${helper.getWriteBufferWriteMethodCall(optionalField.name, simpleTypeReference, "*(" + optionalField.name + ")", optionalField)}
 					<#else>
 						<#assign complexTypeReference = optionalField.type>
 		${optionalField.name} = m.${optionalField.name?cap_first}
@@ -1337,18 +1354,18 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "padding">
-					<#assign paddingField = field>
-					<#assign simpleTypeReference = paddingField.type>
+					<#assign paddingField = field.asPaddingField().orElseThrow()>
+					<#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Padding Field (padding)
 	{
 		if pushErr := writeBuffer.PushContext("padding", utils.WithRenderAsList(true)); pushErr != nil {
 			return pushErr
 		}
-		_timesPadding := uint8(${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, type.parserArguments)})
+		_timesPadding := uint8(${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, parserArguments)})
 		for ;_timesPadding > 0; _timesPadding-- {
-			_paddingValue := ${helper.getLanguageTypeNameForField(field)}(${helper.toSerializationExpression(paddingField, paddingField.paddingValue, type.parserArguments)})
-			_paddingErr := ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", field)}
+			_paddingValue := ${helper.getLanguageTypeNameForField(field)}(${helper.toSerializationExpression(paddingField, paddingField.paddingValue, parserArguments)})
+			_paddingErr := ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", paddingField)}
 			if _paddingErr != nil {
 				return errors.Wrap(_paddingErr, "Error serializing 'padding' field")<@emitImport import="github.com/pkg/errors" />
 			}
@@ -1359,23 +1376,23 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "reserved">
-					<#assign reservedField = field>
-					<#assign simpleTypeReference = reservedField.type>
+					<#assign reservedField = field.asReservedField().orElseThrow()>
+					<#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
 	// Reserved Field (reserved)
 	{
-		_err := ${helper.getWriteBufferWriteMethodCall("reserved", simpleTypeReference, helper.getReservedValue(field), field)}
+		_err := ${helper.getWriteBufferWriteMethodCall("reserved", simpleTypeReference, helper.getReservedValue(field), reservedField)}
 		if _err != nil {
 			return errors.Wrap(_err, "Error serializing 'reserved' field")<@emitImport import="github.com/pkg/errors" />
 		}
 	}
 					<#break>
 				<#case "simple">
-					<#assign simpleField = field>
+					<#assign simpleField = field.asSimpleField().orElseThrow()>
 
 	// Simple Field (${simpleField.name})
 					<#if helper.isSimpleTypeReference(simpleField.type)>
-						<#assign simpleTypeReference = simpleField.type>
+						<#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
 						<#assign simpleFieldLogicalName><#if helper.isSimpleTypeReference(simpleField.type) && !helper.isEnumField(field)>${simpleField.name}<#else>${simpleField.typeName}</#if></#assign>
 	${simpleField.name} := ${helper.getLanguageTypeNameForField(field)}(m.${simpleField.name?cap_first})
 						<#if helper.isEnumField(field)>
@@ -1398,7 +1415,7 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	}
 					<#break>
 				<#case "switch">
-					<#assign switchField = field>
+					<#assign switchField = field.asSwitchField().orElseThrow()>
 
 	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
 	_typeSwitchErr := serializeChildFunction()
@@ -1427,7 +1444,7 @@ func (m *${type.name}) Serialize(writeBuffer utils.WriteBuffer<#if helper.getSer
 	</#if>
 }
 
-<#if !helper.getSerializerArguments(type.parserArguments)?has_content><#-- We only generate String() methods for serializer witout arguments -->
+<#if !helper.getSerializerArguments(parserArguments)?has_content><#-- We only generate String() methods for serializer witout arguments -->
 func (m *${type.name}) String() string {
 	if m == nil {
 		return "<nil>"
diff --git a/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh
index d6c9f8e..3364d6a 100644
--- a/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/parser-factory-template.go.ftlh
@@ -25,23 +25,6 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.go.GoLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
 ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/ParserHelper.go
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -79,8 +62,8 @@ func (m ${helper.getSanitizedProtocolName()?cap_first}ParserHelper) Parse(typeNa
 	switch typeName {
 <#list helper.getComplexTypeRootDefinitions() as typeDefinition>
 	case "${typeDefinition.name}":
-	<#if typeDefinition.parserArguments?has_content>
-		<#list typeDefinition.parserArguments as parserArgument>
+	<#if typeDefinition.parserArguments.isPresent()>
+		<#list typeDefinition.parserArguments.orElseThrow() as parserArgument>
 			<#if helper.isSimpleTypeReference(parserArgument.type)>
 		${parserArgument.name}, err := utils.StrTo${helper.getLanguageTypeNameForTypeReference(parserArgument.type)?cap_first}(arguments[${parserArgument?index}])
 		if err != nil {
@@ -91,7 +74,7 @@ func (m ${helper.getSanitizedProtocolName()?cap_first}ParserHelper) Parse(typeNa
 			</#if>
 		</#list>
 	</#if>
-		return model.${typeDefinition.name}Parse(io<#if typeDefinition.parserArguments?has_content>, <#list typeDefinition.parserArguments as parserArgument><#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>&</#if>${parserArgument.name}<#sep>, </#list></#if>)
+		return model.${typeDefinition.name}Parse(io<#if typeDefinition.parserArguments.isPresent()>, <#list typeDefinition.parserArguments.orElseThrow() as parserArgument><#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>&</#if>${parserArgument.name}<#sep>, </#list></#if>)
 </#list>
 	}
 	return nil, errors.Errorf("Unsupported type %s", typeName)
diff --git a/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh b/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh
index 2139408..9ba859d 100644
--- a/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh
+++ b/code-generation/language-go/src/main/resources/templates/go/xml-parser-factory-template.go.ftlh
@@ -25,23 +25,6 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.go.GoLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
 ${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/XmlParserHelper.go
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -89,9 +72,9 @@ func (m ${helper.getSanitizedProtocolName()?cap_first}XmlParserHelper) Parse(typ
     switch typeName {
     <#list helper.getComplexTypeRootDefinitions() as typeDefinition>
         case "${typeDefinition.name}":
-        <#if typeDefinition.parserArguments??>
-            <#list 0..typeDefinition.parserArguments?size-1 as i>
-                <#assign parserArgument=typeDefinition.parserArguments[i]>
+        <#if typeDefinition.parserArguments.isPresent()>
+            <#list 0..typeDefinition.parserArguments.orElseThrow()?size-1 as i>
+                <#assign parserArgument=typeDefinition.parserArguments.orElseThrow()[i]>
                 <#if helper.isEnumTypeReference(parserArgument.type)>
             ${parserArgument.name} := model.${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}ByName(parserArguments[${i}])
                 <#else>
@@ -133,7 +116,7 @@ func (m ${helper.getSanitizedProtocolName()?cap_first}XmlParserHelper) Parse(typ
                     </#switch>
                 </#if>
             </#list>
-            <#assign parserArgumentList><#list typeDefinition.parserArguments as parserArgument><#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>&</#if>${parserArgument.name}<#sep>, </#sep> </#list> </#assign>
+            <#assign parserArgumentList><#list typeDefinition.parserArguments.orElseThrow() as parserArgument><#if helper.isComplexTypeReference(parserArgument.type) && !helper.isEnumTypeReference(parserArgument.type)>&</#if>${parserArgument.name}<#sep>, </#sep> </#list> </#assign>
             return model.${typeDefinition.name}Parse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)), ${parserArgumentList})
         <#else>
 			return model.${typeDefinition.name}Parse(utils.NewXmlReadBuffer(strings.NewReader(xmlString)))
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index 43a5ea7..754f2dc 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -23,6 +23,8 @@ import java.math.BigInteger;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.util.Collections;
+import java.util.List;
 import java.util.Optional;
 
 import org.apache.commons.lang3.StringUtils;
@@ -30,6 +32,7 @@ import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.commons.text.WordUtils;
 import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
 import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
 import org.apache.plc4x.plugins.codegenerator.types.fields.*;
@@ -38,6 +41,7 @@ import org.apache.plc4x.plugins.codegenerator.types.terms.*;
 
 import java.util.Map;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
 @SuppressWarnings({"unused", "WeakerAccess"})
 public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
@@ -467,7 +471,7 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
             }
             case STRING: {
                 StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
-                return "writeBuffer.writeString(\"" + logicalName + "\", " + toSerializationExpression(field, stringTypeReference.getLengthExpression(), getThisTypeDefinition().getParserArguments()) + ", \"" +
+                return "writeBuffer.writeString(\"" + logicalName + "\", " + toSerializationExpression(field, stringTypeReference.getLengthExpression(), thisType.getParserArguments().orElse(Collections.emptyList())) + ", \"" +
                     stringTypeReference.getEncoding() + "\", (String) " + fieldName + "" + writerArgsString + ")";
             }
         }
@@ -540,7 +544,7 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         return types.values();
     }*/
 
-    public String toAccessExpression(TypedField field, Term term, Argument[] parserArguments) {
+    public String toAccessExpression(TypedField field, Term term, List<Argument> parserArguments) {
         return toExpression(field, term, variableLiteral -> {
             if (isVariableLiteralVirtualField(variableLiteral) || isVariableLiteralDiscriminatorField(variableLiteral)) { // If we are accessing virtual|discriminator fields, we need to call the getter.
                 return "get" + StringUtils.capitalize(variableLiteral.getName()) + "()";
@@ -549,12 +553,12 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         });
     }
 
-    public String toParseExpression(TypedField field, Term term, Argument[] parserArguments) {
+    public String toParseExpression(TypedField field, Term term, List<Argument> parserArguments) {
         Tracer tracer = Tracer.start("toParseExpression");
         return tracer + toExpression(field, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableParseExpression(field, variableLiteral, parserArguments));
     }
 
-    public String toSerializationExpression(TypedField field, Term term, Argument[] serializerArguments) {
+    public String toSerializationExpression(TypedField field, Term term, List<Argument> serializerArguments) {
         Tracer tracer = Tracer.start("toSerializationExpression");
         return tracer + toExpression(field, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableSerializationExpression(field, variableLiteral, serializerArguments));
     }
@@ -585,9 +589,10 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
                 // If this literal references an Enum type, then we have to output it differently.
                 if (getTypeDefinitions().get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
                     tracer = tracer.dive("enum definition instanceOf");
-                    return tracer + variableLiteral.getName() + "." + variableLiteral.getChild().getName() +
-                        ((variableLiteral.getChild().getChild() != null) ?
-                            "." + toVariableExpressionRest(variableLiteral.getChild().getChild()) : "");
+                    VariableLiteral enumDefinitionChild = variableLiteral.getChild()
+                        .orElseThrow(() -> new RuntimeException("enum definitions should have childs"));
+                    return tracer + variableLiteral.getName() + "." + enumDefinitionChild.getName() +
+                        enumDefinitionChild.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
                 } else {
                     return tracer + variableExpressionGenerator.apply(variableLiteral);
                 }
@@ -644,33 +649,46 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         return variableLiteral.getName();
     }
 
-    private String toVariableParseExpression(TypedField field, VariableLiteral variableLiteral, Argument[] parserArguments) {
+    private String toVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments) {
         Tracer tracer = Tracer.start("toVariableParseExpression");
         // CAST expressions are special as we need to add a ".class" to the second parameter in Java.
         if ("CAST".equals(variableLiteral.getName())) {
             tracer = tracer.dive("CAST");
             StringBuilder sb = new StringBuilder(variableLiteral.getName());
-            if ((variableLiteral.getArgs() == null) || (variableLiteral.getArgs().size() != 2)) {
+            List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A Cast expression needs arguments"));
+            if (arguments.size() != 2) {
                 throw new RuntimeException("A CAST expression expects exactly two arguments.");
             }
+            VariableLiteral firstArgument = arguments.get(0).asLiteral()
+                .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+                .asVariableLiteral()
+                .orElseThrow(() -> new RuntimeException("First argument should be a Variable literal"));
+            VariableLiteral secondArgument = arguments.get(1).asLiteral().orElseThrow(() -> new RuntimeException("Second argument should be a literal"))
+                .asVariableLiteral()
+                .orElseThrow(() -> new RuntimeException("Second argument should be a Variable literal"));
             sb.append("(")
-                .append(toVariableParseExpression(field, (VariableLiteral) variableLiteral.getArgs().get(0), parserArguments))
+                .append(toVariableParseExpression(field, firstArgument, parserArguments))
                 .append(", ")
-                .append(((VariableLiteral) variableLiteral.getArgs().get(1)).getName()).append(".class)");
-            return tracer + sb.toString() + ((variableLiteral.getChild() != null) ? "." + toVariableExpressionRest(variableLiteral.getChild()) : "");
+                .append(secondArgument.getName()).append(".class)");
+            return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
         } else if ("STATIC_CALL".equals(variableLiteral.getName())) {
             tracer = tracer.dive("STATIC_CALL");
             StringBuilder sb = new StringBuilder();
-            if (!(variableLiteral.getArgs().get(0) instanceof StringLiteral)) {
-                throw new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
+            List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
+            if (arguments.size() < 1) {
+                throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
             }
             // Get the class and method name
-            String methodName = ((StringLiteral) variableLiteral.getArgs().get(0)).getValue();
+            String methodName = arguments.get(0).asLiteral()
+                .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+                .asStringLiteral()
+                .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
+                getValue();
             // Cut off the double-quotes
             methodName = methodName.substring(1, methodName.length() - 1);
             sb.append(methodName).append("(");
-            for (int i = 1; i < variableLiteral.getArgs().size(); i++) {
-                Term arg = variableLiteral.getArgs().get(i);
+            for (int i = 1; i < arguments.size(); i++) {
+                Term arg = arguments.get(i);
                 if (i > 1) {
                     sb.append(", ");
                 }
@@ -688,9 +706,9 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
                         }
                     }
                     if (isParserArg) {
-                        sb.append(variableLiteralArg.getName()).append((variableLiteralArg.getChild() != null) ? "." + toVariableExpressionRest(variableLiteralArg.getChild()) : "");
+                        sb.append(variableLiteralArg.getName()).append(variableLiteralArg.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
                     } else if (isTypeArg) {// We have to manually evaluate the type information at code-generation time.
-                        String part = variableLiteralArg.getChild().getName();
+                        String part = variableLiteralArg.getChild().map(VariableLiteral::getName).orElse("");
                         switch (part) {
                             case "name":
                                 sb.append("\"").append(field.getTypeName()).append("\"");
@@ -720,10 +738,10 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         } else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) { // All uppercase names are not fields, but utility methods.
             tracer = tracer.dive("UPPERCASE");
             StringBuilder sb = new StringBuilder(variableLiteral.getName());
-            if (variableLiteral.getArgs() != null) {
+            if (variableLiteral.getArgs().isPresent()) {
                 sb.append("(");
                 boolean firstArg = true;
-                for (Term arg : variableLiteral.getArgs()) {
+                for (Term arg : variableLiteral.getArgs().get()) {
                     if (!firstArg) {
                         sb.append(", ");
                     }
@@ -735,24 +753,30 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
             if (variableLiteral.getIndex() != VariableLiteral.NO_INDEX) {
                 sb.append("[").append(variableLiteral.getIndex()).append("]");
             }
-            return tracer + sb.toString() + ((variableLiteral.getChild() != null) ? "." + toVariableExpressionRest(variableLiteral.getChild()) : "");
+            return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
         }
-        return tracer + variableLiteral.getName() + ((variableLiteral.getChild() != null) ? "." + toVariableExpressionRest(variableLiteral.getChild()) : "");
+        return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
     }
 
-    private String toVariableSerializationExpression(TypedField field, VariableLiteral variableLiteral, Argument[] serialzerArguments) {
+    private String toVariableSerializationExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> serialzerArguments) {
         Tracer tracer = Tracer.start("variable serialization expression");
         if ("STATIC_CALL".equals(variableLiteral.getName())) {
             tracer = tracer.dive("STATIC_CALL");
             StringBuilder sb = new StringBuilder();
-            if (!(variableLiteral.getArgs().get(0) instanceof StringLiteral)) {
-                throw new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
+            List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
+            if (arguments.size() < 1) {
+                throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
             }
-            String methodName = ((StringLiteral) variableLiteral.getArgs().get(0)).getValue();
+            // Get the class and method name
+            String methodName = arguments.get(0).asLiteral()
+                .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+                .asStringLiteral()
+                .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
+                getValue();
             methodName = methodName.substring(1, methodName.length() - 1);
             sb.append(methodName).append("(");
-            for (int i = 1; i < variableLiteral.getArgs().size(); i++) {
-                Term arg = variableLiteral.getArgs().get(i);
+            for (int i = 1; i < arguments.size(); i++) {
+                Term arg = arguments.get(i);
                 if (i > 1) {
                     sb.append(", ");
                 }
@@ -770,9 +794,9 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
                         }
                     }
                     if (isSerializerArg) {
-                        sb.append(va.getName()).append((va.getChild() != null) ? "." + toVariableExpressionRest(va.getChild()) : "");
+                        sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
                     } else if (isTypeArg) {
-                        String part = va.getChild().getName();
+                        String part = va.getChild().map(VariableLiteral::getName).orElse("");
                         switch (part) {
                             case "name":
                                 sb.append("\"").append(field.getTypeName()).append("\"");
@@ -801,10 +825,10 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) {
             tracer = tracer.dive("UPPER_CASE");
             StringBuilder sb = new StringBuilder(variableLiteral.getName());
-            if (variableLiteral.getArgs() != null) {
+            if (variableLiteral.getArgs().isPresent()) {
                 sb.append("(");
                 boolean firstArg = true;
-                for (Term arg : variableLiteral.getArgs()) {
+                for (Term arg : variableLiteral.getArgs().get()) {
                     if (!firstArg) {
                         sb.append(", ");
                     }
@@ -822,9 +846,9 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
                             }
                         }
                         if (isSerializerArg) {
-                            sb.append(va.getName()).append((va.getChild() != null) ? "." + toVariableExpressionRest(va.getChild()) : "");
+                            sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
                         } else if (isTypeArg) {
-                            String part = va.getChild().getName();
+                            String part = va.getChild().map(VariableLiteral::getName).orElse("");
                             switch (part) {
                                 case "name":
                                     sb.append("\"").append(field.getTypeName()).append("\"");
@@ -870,10 +894,10 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         }
         if (isSerializerArg) {
             tracer = tracer.dive("serializer arg");
-            return tracer + variableLiteral.getName() + ((variableLiteral.getChild() != null) ? "." + toVariableExpressionRest(variableLiteral.getChild()) : "");
+            return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
         } else if (isTypeArg) {
             tracer = tracer.dive("type arg");
-            String part = variableLiteral.getChild().getName();
+            String part = variableLiteral.getChild().map(VariableLiteral::getName).orElse("");
             switch (part) {
                 case "name":
                     return tracer + "\"" + field.getTypeName() + "\"";
@@ -900,13 +924,13 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         if (variableLiteralName.equals("length")) {
             tracer = tracer.dive("length");
             return tracer + variableLiteralName + "()" + ((variableLiteral.isIndexed() ? "[" + variableLiteral.getIndex() + "]" : "") +
-                ((variableLiteral.getChild() != null) ? "." + toVariableExpressionRest(variableLiteral.getChild()) : ""));
+                variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
         }
         return tracer + "get" + WordUtils.capitalize(variableLiteralName) + "()" + ((variableLiteral.isIndexed() ? "[" + variableLiteral.getIndex() + "]" : "") +
-            ((variableLiteral.getChild() != null) ? "." + toVariableExpressionRest(variableLiteral.getChild()) : ""));
+            variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
     }
 
-    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, Argument[] parserArguments) {
+    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, List<Argument> parserArguments) {
         int sizeInBits = 0;
         StringBuilder sb = new StringBuilder();
         for (Field field : complexTypeDefinition.getFields()) {
diff --git a/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh
index ca8926a..9e5ea5b 100644
--- a/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/data-io-template.java.ftlh
@@ -25,23 +25,6 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
 ${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${type.name}IO.java
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -86,53 +69,84 @@ import java.util.function.Supplier;
 
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 public class ${type.name}IO {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
-    public static PlcValue staticParse(ReadBuffer readBuffer<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+    public static PlcValue staticParse(ReadBuffer readBuffer<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         <#assign defaultCaseOutput=false>
-        <#list type.switchField.cases as case>
-<#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)}, <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(type.parserArguments[discriminatorValue?index].type)><#if [...]
+        <#assign dataIoTypeDefinition=type.asDataIoTypeDefinition().orElseThrow()>
+        <#list dataIoTypeDefinition.switchField.cases as case>
+            <#if case.discriminatorValues?has_content>
+            <@compress single_line=true>
+            if(
+                <#list case.discriminatorValues as discriminatorValue>
+                    <#assign discriminatorExpression=dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValue?index]>
+                EvaluationHelper.equals(
+                    ${helper.toParseExpression(null, discriminatorExpression, parserArguments)}
+                    ,
+                    <#if helper.discriminatorValueNeedsStringEqualityCheck(discriminatorExpression)>
+                        "${discriminatorValue}"
+                    <#elseif helper.isComplexTypeReference(parserArguments[discriminatorValue?index].type)>
+                        <#if helper.isEnumTypeReference(parserArguments[discriminatorValue?index].type)>
+                            ${helper.getLanguageTypeNameForTypeReference(parserArguments[discriminatorValue?index].type, false)}
+                            .
+                            ${discriminatorValue}
+                        <#else>
+                        ${discriminatorValue}
+                        </#if>
+                    <#else>
+            ${discriminatorValue}
+                    </#if>
+                )
+                <#sep> && </#sep>
+                </#list>
+            )
+            </...@compress>
+            <#else>
+                <#assign defaultCaseOutput=true>
+            </#if>{ // ${case.name}
             <#assign valueDefined=false>
             <#list case.fields as field>
                 <#switch field.typeName>
                     <#case "array">
-
-            // Array field (${field.name})
+                        <#assign arrayField=field.asArrayField().orElseThrow()>
+            // Array field (${arrayField.name})
             <#-- Only update curPos if the length expression uses it -->
-                        <#if field.loopExpression.contains("curPos")>
+                        <#if arrayField.loopExpression.contains("curPos")>
             curPos = readBuffer.getPos() - startPos;
                         </#if>
             <#-- If this is a count array, we can directly initialize an array with the given size -->
                         <#if helper.isCountArrayField(field)>
             // Count array
-            if(${helper.toParseExpression(field, field.loopExpression, type.parserArguments)} > Integer.MAX_VALUE) {
-                throw new ParseException("Array count of " + (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
+            if(${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)} > Integer.MAX_VALUE) {
+                throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
             }
-            List<PlcValue> ${field.name};
+            List<PlcValue> ${arrayField.name};
             {
-                int itemCount = (int) ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)};
-                ${field.name} = new LinkedList<>();
+                int itemCount = (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)};
+                ${arrayField.name} = new LinkedList<>();
                 for(int curItem = 0; curItem < itemCount; curItem++) {
-                    ${field.name}.add(new ${helper.getPlcValueTypeForTypeReference(field.type)}((${helper.getNonPrimitiveLanguageTypeNameForField(field)}) <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type, "", field)})<#else>${field.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)} [...]
+                    ${arrayField.name}.add(new ${helper.getPlcValueTypeForTypeReference(arrayField.type)}((${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}) <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)})<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if field.params.isPresent()>, <#list arrayField.params.orElseThrow [...]
                 }
             }
             <#-- In all other cases do we have to work with a list, that is later converted to an array -->
                         <#else>
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
-                            <#if helper.isLengthArrayField(field)>
+                            <#if helper.isLengthArrayField(arrayField)>
             // Length array
-            long _${field.name}Length = ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)};
-            long ${field.name}EndPos = readBuffer.getPos() + _${field.name}Length;
+            long _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)};
+            long ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
             List<PlcValue> value = new LinkedList<>();
-            while(readBuffer.getPos() < ${field.name}EndPos) {
+            while(readBuffer.getPos() < ${arrayField.name}EndPos) {
                 value.add(
-                <#if helper.isSimpleTypeReference(field.type)>
-                    new ${helper.getPlcValueTypeForTypeReference(field.type)}(${helper.getReadBufferReadMethodCall(field.type, "", field)})
-                <#else>${field.type.name}IO.staticParse(readBuffer
-                    <#if field.params?has_content>,
-                        <#list field.params as parserArgument>
-                            (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})
+                <#if helper.isSimpleTypeReference(arrayField.type)>
+                    new ${helper.getPlcValueTypeForTypeReference(arrayField.type)}(${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)})
+                <#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+                    <#if arrayField.params.isPresent()>,
+                        <#list arrayField.params.orElseThrow() as parserArgument>
+                            (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument,parserArguments)})
                             <#sep>, </#sep>
                         </#list>
                     </#if>
@@ -141,75 +155,80 @@ public class ${type.name}IO {
                 );
             }
             <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
-                            <#elseif helper.isTerminatedArrayField(field)>
+                            <#elseif helper.isTerminatedArrayField(arrayField)>
             // Terminated array
-            List<${helper.getNonPrimitiveLanguageTypeNameForField(field)}> ${field.name} = new LinkedList<>();
-            while(!((boolean) (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)}))) {
-                ${field.name}.add(<#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type, "", field)}<#else>${field.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>);
+            List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = new LinkedList<>();
+            while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)}))) {
+                ${arrayField.name}.add(<#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index [...]
 
                 <#-- After parsing, update the current position, but only if it's needed -->
-                                <#if field.loopExpression.contains("curPos")>
+                                <#if arrayField.loopExpression.contains("curPos")>
                 curPos = readBuffer.getPos() - startPos;
                                 </#if>
             }
                             </#if>
                         </#if>
-                        <#if field.name == "value">
+                        <#if arrayField.name == "value">
                             <#assign valueDefined=true>
                         </#if>
                     <#break>
                     <#case "const">
+                        <#assign constField=field.asConstField().orElseThrow()>
 
-            // Const Field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = ${helper.getReadBufferReadMethodCall(field.type, "", field)};
-            if(${field.name} != ${type.name}.${field.name?upper_case}) {
-                throw new ParseException("Expected constant value " + ${type.name}.${field.name?upper_case} + " but got " + ${field.name});
+            // Const Field (${constField.name})
+            ${helper.getNonPrimitiveLanguageTypeNameForField(constField)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), "", constField)};
+            if(${constField.name} != ${dataIoTypeDefinition.name}.${constField.name?upper_case}) {
+                throw new ParseException("Expected constant value " + ${dataIoTypeDefinition.name}.${constField.name?upper_case} + " but got " + ${constField.name});
             }
-                        <#if field.name == "value">
+                        <#if constField.name == "value">
                             <#assign valueDefined=true>
                         </#if>
                     <#break>
                     <#case "enum">
+                        <#assign enumField=field.asEnumField().orElseThrow()>
 
-            // Enum field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(field.type), "", field)});
-                        <#if field.name == "value">
+            // Enum field (${enumField.name})
+            ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)} ${enumField.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type.asSimpleTypeReference().orElseThrow()), "", enumField)});
+                        <#if enumField.name == "value">
                             <#assign valueDefined=true>
                         </#if>
                     <#break>
                     <#case "manual">
+                        <#assign manualField=field.asManualField().orElseThrow()>
 
-            // Manual Field (${field.name})
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)});
-                        <#if field.name == "value">
+            // Manual Field (${manualField.name})
+            ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(manualField, manualField.parseExpression,parserArguments)});
+                        <#if manualField.name == "value">
                             <#assign valueDefined=true>
                         </#if>
                     <#break>
                     <#case "reserved">
+                        <#assign reservedField=field.asReservedField().orElseThrow()>
 
             // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
             {
-                ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(field.type, "", field)};
-                if(reserved != ${helper.getReservedValue(field)}) {
-                    LOGGER.info("Expected constant value " + ${field.referenceValue} + " but got " + reserved + " for reserved field.");
+                ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), "", reservedField)};
+                if(reserved != ${helper.getReservedValue(reservedField)}) {
+                    LOGGER.info("Expected constant value " + ${reservedField.referenceValue} + " but got " + reserved + " for reserved field.");
                 }
             }
                     <#break>
                     <#case "simple">
+                        <#assign simpleField=field.asSimpleField().orElseThrow()>
 
-                        <#if helper.isEnumField(field)>
-            // Enum field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(field.type), "", field)});
+                        <#if helper.isEnumField(simpleField)>
+            // Enum field (${simpleField.name})
+            ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} ${simpleField.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)});
                         <#else>
-            // Simple Field (${field.name})
-            ${helper.getNonPrimitiveLanguageTypeNameForField(field)} ${field.name} = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type, "", field)}<#else>${field.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArgumen [...]
+            // Simple Field (${simpleField.name})
+            ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} ${simpleField.name} = <#if helper.isSimpleTypeReference(simpleField.type)>${helper.getReadBufferReadMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}<#else>${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if simpleField.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(he [...]
                         </#if>
                         <#if case.name == "Struct" ||
-                            ((case.name == "DATE_AND_TIME") && ((field.name == "year") || (field.name == "month") || (field.name == "day") || (field.name == "hour") || (field.name == "minutes") || (field.name == "seconds"))) ||
-                            ((case.name == "DATE_AND_TIME") && (field.name == "secondsSinceEpoch")) ||
-                            ((case.name == "DATE") && ((field.name == "year") || (field.name == "month") || (field.name == "day"))) ||
-                            ((case.name == "TIME_OF_DAY") && ((field.name == "hour") || (field.name == "minutes") || (field.name == "seconds"))) ||
-                            field.name == "value">
+                            ((case.name == "DATE_AND_TIME") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day") || (simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds"))) ||
+                            ((case.name == "DATE_AND_TIME") && (simpleField.name == "secondsSinceEpoch")) ||
+                            ((case.name == "DATE") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day"))) ||
+                            ((case.name == "TIME_OF_DAY") && ((simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds"))) ||
+                        simpleField.name == "value">
                             <#assign valueDefined=true>
                         </#if>
                     <#break>
@@ -221,8 +240,10 @@ public class ${type.name}IO {
             Map<String, PlcValue> _map = new HashMap<>();
                 <#list case.fields as field>
                     <#if helper.isArrayField(field)>
+                        <#assign field=field.asArrayField().orElseThrow()>
             _map.put("${field.name}", new PlcList(${field.name}));
                     <#elseif helper.isPropertyField(field)>
+                        <#assign field=field.asPropertyField().orElseThrow()>
                         <#switch helper.getLanguageTypeNameForTypeReference(field.type)>
                             <#case "Boolean">
             _map.put("${field.name}", new PlcBOOL(${field.name}));
@@ -315,29 +336,31 @@ public class ${type.name}IO {
     }
 
 <#if outputFlavor != "passive">
-    public static WriteBufferByteBased staticSerialize(PlcValue _value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
-        return staticSerialize(_value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>, false);
+    public static WriteBufferByteBased staticSerialize(PlcValue _value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+        return staticSerialize(_value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>, false);
     }
 
-    public static WriteBufferByteBased staticSerialize(PlcValue _value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>, boolean littleEndian) throws ParseException {
+    public static WriteBufferByteBased staticSerialize(PlcValue _value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>, boolean littleEndian) throws ParseException {
         <#assign defaultCaseOutput=false>
-        <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)},<#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(type.parserA [...]
-        WriteBufferByteBased writeBuffer = new WriteBufferByteBased((int) Math.ceil(((float) ${helper.getSizeInBits(case, type.parserArguments)}) / 8.0f), littleEndian);
+        <#assign dataIoTypeDefinition=type.asDataIoTypeDefinition().orElseThrow()>
+        <#list dataIoTypeDefinition.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments.orElseThrow())},<#if helper.discriminatorValueNeedsStringEqualityCheck(dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValue?index])>"${discrimin [...]
+        WriteBufferByteBased writeBuffer = new WriteBufferByteBased((int) Math.ceil(((float) ${helper.getSizeInBits(case,parserArguments)}) / 8.0f), littleEndian);
 
             <#list case.fields as field>
                 <#switch field.typeName>
                     <#case "array">
+                        <#assign arrayField=field.asArrayField().orElseThrow()>
             PlcList values = (PlcList) _value;
 
                         <#if case.name == "Struct">
-            for (PlcValue val : ((List<PlcValue>) values.getStruct().get("${field.name}").getList())) {
-                ${helper.getLanguageTypeNameForField(field)} value = (${helper.getLanguageTypeNameForField(field)}) val.get${helper.getLanguageTypeNameForField(field)?cap_first}();
-                ${helper.getWriteBufferWriteMethodCall(field.type, "value", field)};
+            for (PlcValue val : ((List<PlcValue>) values.getStruct().get("${arrayField.name}").getList())) {
+                ${helper.getLanguageTypeNameForField(arrayField)} value = (${helper.getLanguageTypeNameForField(arrayField)}) val.get${helper.getLanguageTypeNameForField(arrayField)?cap_first}();
+                ${helper.getWriteBufferWriteMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "value", arrayField)};
             }
                         <#else>
             for (PlcValue val : ((List<PlcValue>) values.getList())) {
-                ${helper.getLanguageTypeNameForField(field)} value = (${helper.getLanguageTypeNameForField(field)}) val.get${helper.getLanguageTypeNameForField(field)?cap_first}();
-                ${helper.getWriteBufferWriteMethodCall(field.type, "(" + field.name + ")", field)};
+                ${helper.getLanguageTypeNameForField(arrayField)} value = (${helper.getLanguageTypeNameForField(arrayField)}) val.get${helper.getLanguageTypeNameForField(arrayField)?cap_first}();
+                ${helper.getWriteBufferWriteMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "(" + arrayField.name + ")", arrayField)};
             }
                         </#if>
 
@@ -348,38 +371,43 @@ public class ${type.name}IO {
                     </#if>
                     <#break>
                     <#case "const">
-            // Const Field (${field.name})
-            ${helper.getWriteBufferWriteMethodCall(field.type, field.referenceValue, field)};
+                        <#assign constField=field.asConstField().orElseThrow()>
+            // Const Field (${constField.name})
+            ${helper.getWriteBufferWriteMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), constField.referenceValue, constField)};
                     <#break>
                     <#case "enum">
-            // Enum field (${field.name})
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${field.name?cap_first}();
-            ${helper.getWriteBufferWriteMethodCall(helper.getEnumBaseTypeReference(field.type), "(" + field.name + ".getValue())", field)};
+                        <#assign enumField=field.asEnumField().orElseThrow()>
+            // Enum field (${enumField.name})
+            ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${enumField.name?cap_first}();
+            ${helper.getWriteBufferWriteMethodCall(helper.getEnumBaseTypeReference(field.asTypedField().orElseThrow().type), "(" + enumField.name + ".getValue())", enumField)};
                     <#break>
                     <#case "manual">
-            // Manual Field (${field.name})
-            ${helper.toSerializationExpression(field, field.serializeExpression, type.parserArguments)};
+                        <#assign manualField=field.asManualField().orElseThrow()>
+            // Manual Field (${manualField.name})
+            ${helper.toSerializationExpression(manualField, manualField.serializeExpression, type.parserArguments.orElse(null))};
                     <#break>
                     <#case "reserved">
+                        <#assign reservedField=field.asReservedField().orElseThrow()>
             // Reserved Field
-            ${helper.getWriteBufferWriteMethodCall(field.type, helper.getReservedValue(field), field)};
+            ${helper.getWriteBufferWriteMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), helper.getReservedValue(reservedField), reservedField)};
                     <#break>
                     <#case "simple">
-            // Simple Field (${field.name})
+                        <#assign simpleField=field.asSimpleField().orElseThrow()>
+            // Simple Field (${simpleField.name})
                         <#if case.name == "Struct">
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.getStruct().get("${field.name}").get${helper.getLanguageTypeNameForField(field)?cap_first}();
+            ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.getStruct().get("${simpleField.name}").get${helper.getLanguageTypeNameForField(simpleField)?cap_first}();
                         <#else>
-                            <#if field.name == "value">
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${helper.getLanguageTypeNameForField(field)?cap_first}();
+                            <#if simpleField.name == "value">
+            ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${helper.getLanguageTypeNameForField(simpleField)?cap_first}();
                             <#else>
                                 <#-- Just for now -->
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForTypeReference(field.type)};
+            ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = ${helper.getNullValueForTypeReference(simpleField.type)};
                             </#if>
                         </#if>
-                        <#if helper.isSimpleTypeReference(field.type)>
-            ${helper.getWriteBufferWriteMethodCall(field.type, "(" + field.name + ")", field)};
+                        <#if helper.isSimpleTypeReference(simpleField.type)>
+            ${helper.getWriteBufferWriteMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "(" + simpleField.name + ")", simpleField)};
                         <#else>
-            ${field.type.name}IO.staticSerialize(writeBuffer, ${field.name});
+            ${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.staticSerialize(writeBuffer, ${simpleField.name});
                         </#if>
                     <#break>
                 </#switch>
diff --git a/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh
index a5ad8a1..49bd6c6 100644
--- a/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/enum-template.java.ftlh
@@ -61,7 +61,7 @@ import java.util.Map;
 public enum ${type.name} {
 
 <#list type.enumValues as enumValue>
-    ${enumValue.name}(<#if type.type?has_content>(${helper.getLanguageTypeNameForTypeReference(type.type, true)}) <#if helper.isStringTypeReference(type.type)>"${enumValue.value}"<#elseif helper.isComplexTypeReference(type.type)><#if helper.isEnumTypeReference(type.type)>${helper.getLanguageTypeNameForTypeReference(type.type, true)}.${enumValue.value}<#else>${enumValue.value}</#if><#else>${enumValue.value}</#if></#if><#if type.constantNames?has_content><#if type.type?has_content>, </#if> [...]
+    ${enumValue.name}(<#if type.type?has_content>(${helper.getLanguageTypeNameForTypeReference(type.type, true)}) <#if helper.isStringTypeReference(type.type)>"${enumValue.value}"<#elseif helper.isComplexTypeReference(type.type)><#if helper.isEnumTypeReference(type.type)>${helper.getLanguageTypeNameForTypeReference(type.type, true)}.${enumValue.value}<#else>${enumValue.value}</#if><#else>${enumValue.value}</#if></#if><#if type.constantNames?has_content><#if type.type?has_content>, </#if> [...]
 </#sep></#list>;
 
 <#if type.type?has_content>
diff --git a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
index c50b1ba..ebb9a9e 100644
--- a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
@@ -25,26 +25,6 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-<#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="typedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.TypedField" -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="assertField" type="org.apache.plc4x.plugins.codegenerator.types.fields.AssertField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="unknownField" type="org.apache.plc4x.plugins.codegenerator.types.fields.UnknownField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
 ${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${type.name}IO.java
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -86,6 +66,8 @@ import java.util.function.Supplier;
 
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<${type.name}, ${type.name}><#else>MessageInput<${type.name}></#if> {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
@@ -94,11 +76,11 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 <#if !helper.isDiscriminatedChildTypeDefinition()>
     @Override
     public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException {
-        <#if type.parserArguments?has_content>
-        if((args == null) || (args.length != ${type.parserArguments?size})) {
-            throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length);
+        <#if parserArguments?has_content>
+        if((args == null) || (args.length != ${parserArguments?size})) {
+            throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
         }
-        <#list type.parserArguments as parserArgument>
+            <#list parserArguments as parserArgument>
         ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name};
         if(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) {
             ${parserArgument.name} = (${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) args[${parserArgument?index}];
@@ -109,26 +91,26 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         } else {
             throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} or a string which is parseable but was " + args[${parserArgument?index}].getClass().getName());
         }
-        </#list>
+            </#list>
         </#if>
-        return ${type.name}IO.staticParse(readBuffer<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+        return ${type.name}IO.staticParse(readBuffer<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
     }
 
     <#if outputFlavor != "passive">
     @Override
     public void serialize(WriteBuffer writeBuffer, ${type.name} value, Object... args) throws ParseException {
-        <#if helper.getSerializerArguments(type.parserArguments)?has_content>
-        if((args == null) || (args.length != ${type.parserArguments?size})) {
-            throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length);
+        <#if helper.getSerializerArguments(parserArguments)?has_content>
+        if((args == null) || (args.length != ${parserArguments?size})) {
+            throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
         }
-        <#list helper.getSerializerArguments(type.parserArguments) as serializerArgument>
+        <#list helper.getSerializerArguments(parserArguments) as serializerArgument>
         if(!(args[${serializerArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)})) {
             throw new PlcRuntimeException("Argument ${serializerArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} but was " + args[${serializerArgument?index}].getClass().getName());
         }
         ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} ${serializerArgument.name} = (${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)}) args[${serializerArgument?index}];
         </#list>
         </#if>
-        ${type.name}IO.staticSerialize(writeBuffer, value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+        ${type.name}IO.staticSerialize(writeBuffer, value<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
     }
 
     </#if>
@@ -147,10 +129,10 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 </#if>
 </#if>
 <#-- Here come the actual parse and serialize methods that actually do the parsing and serlaizing -->
-    <#assign hasParserArguments=type.parserArguments?has_content/>
-    <#assign parserArgumentList><#if hasParserArguments><#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-    <#assign hasParentParserArguments=(type.parentType?? && type.parentType.parserArguments?has_content && type.parentType.parserArguments?filter(arg -> hasParserArguments && !type.parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments)?has_content)>
-    <#assign parentParserArgumentList><#if hasParentParserArguments><#list type.parentType.parserArguments?filter(arg -> hasParserArguments && !type.parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+    <#assign hasParserArguments=parserArguments?has_content/>
+    <#assign parserArgumentList><#if hasParserArguments><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+    <#assign hasParentParserArguments=(type.parentType?? && type.parentType.parserArguments.isPresent() && type.parentType.parserArguments.orElseThrow()?filter(arg -> hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments)?has_content)>
+    <#assign parentParserArgumentList><#if hasParentParserArguments><#list type.parentType.parserArguments.orElseThrow()?filter(arg -> hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
     public static ${type.name}<#if helper.isDiscriminatedChildTypeDefinition()>Builder</#if> staticParse(ReadBuffer readBuffer<#if hasParserArguments>, ${parserArgumentList}</#if><#if hasParentParserArguments>, ${parentParserArgumentList}</#if>) throws ParseException {
         readBuffer.pullContext("${type.name}");
         int startPos = readBuffer.getPos();
@@ -158,18 +140,18 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
-        <#assign arrayField = field>
+        <#assign arrayField = field.asArrayField().orElseThrow()>
         <#if helper.isByteBased(arrayField.type)>
         // Byte Array field (${arrayField.name})
             <#assign numberOfBytesExpression>
                 <#compress>
                     <#if helper.isCountArrayField(field)>
-                        int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
+                        int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
                     <#elseif helper.isLengthArrayField(field)>
-                        int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
+                        int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
                     <#elseif helper.isTerminatedArrayField(field)>
                     <#-- TODO: we need to find out to implement this-->
-                        int numberOfBytes := ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
+                        int numberOfBytes := ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
                     <#else>
                     <#-- TODO: we should throw a exception here-->
                         int numberOfBytes := -1
@@ -188,12 +170,12 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#-- If this is a count array, we can directly initialize an array with the given size -->
             <#if helper.isCountArrayField(field)>
         // Count array
-        if(${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)} > Integer.MAX_VALUE) {
-            throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
+        if(${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)} > Integer.MAX_VALUE) {
+            throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
         }
         ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name};
         {
-            int itemCount = Math.max(0, (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)});
+            int itemCount = Math.max(0, (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
             ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount];
             for(int curItem = 0; curItem < itemCount; curItem++) {
                 <#-- When parsing simple types, there is nothing that could require the "lastItem" -->
@@ -201,24 +183,23 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             <@compress single_line=true>
                 ${arrayField.name}[curItem] =
                 <#if helper.isSimpleTypeReference(arrayField.type)>
-                    <#assign simpleTypeReference = arrayField.type>
-                    ${helper.getReadBufferReadMethodCall("", simpleTypeReference, "", arrayField)}
+                    ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
                 <#else>
-                    ${arrayField.type.name}IO.staticParse(readBuffer
-                    <#if field.params?has_content>
+                    ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+                    <#if field.params.isPresent()>
                         ,
-                        <#list field.params as parserArgument>
+                        <#list field.params.orElseThrow() as parserArgument>
                             <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true) = 'String'>
-                                ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}.valueOf(${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                                ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}.valueOf(${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
                             <#else>
-                                (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                                (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
                             </#if>
                         </#list>
                     </#if>
                     <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
                     <#-- We expose the parentParserArguments to the child here too-->
-                    <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments?has_content>
-                    <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+                    <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
+                    <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
                     <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
                     )
                     <#if helper.isDiscriminatedChildTypeDefinition(helper.getTypeDefinitionForTypeReference(arrayField.type))>
@@ -233,28 +214,27 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
                 <#if helper.isLengthArrayField(field)>
         // Length array
-        long _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)};
+        long _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
         List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
         long ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
         while(readBuffer.getPos() < ${arrayField.name}EndPos) {
                     <@compress single_line=true>
             _${arrayField.name}List.add(
                         <#if helper.isSimpleTypeReference(arrayField.type)>
-                            <#assign simpleTypeReference = arrayField.type>
-                            ${helper.getReadBufferReadMethodCall("", simpleTypeReference, "", arrayField)}
+                            ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
                         <#else>
-                            ${arrayField.type.name}IO.staticParse(readBuffer
-                            <#if field.params?has_content>
+                            ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+                            <#if field.params.isPresent()>
                                 ,
-                                <#list field.params as parserArgument>
+                                <#list field.params.orElseThrow() as parserArgument>
                                     (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
-                                    (${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                                    (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
                                 </#list>
                             </#if>
                             <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
                         <#-- We expose the parentParserArguments to the child here too-->
-                            <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments?has_content>
-                            <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+                            <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
+                            <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
                             <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
                             )
                         </#if>
@@ -269,25 +249,24 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
                 <#elseif helper.isTerminatedArrayField(field)>
         // Terminated array
         List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}))) {
+        while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}))) {
                     <@compress single_line=true>
             _${arrayField.name}List.add(
                         <#if helper.isSimpleTypeReference(arrayField.type)>
-                            <#assign simpleTypeReference = arrayField.type>
-                            ${helper.getReadBufferReadMethodCall("", simpleTypeReference, "", arrayField)}
+                            ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
                         <#else>
-                            ${arrayField.type.name}IO.staticParse(readBuffer
-                            <#if field.params?has_content>
+                            ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+                            <#if field.params.isPresent()>
                                 ,
-                                <#list field.params as parserArgument>
+                                <#list field.params.orElseThrow() as parserArgument>
                                     (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
-                                    (${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                                    (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
                                 </#list>
                             </#if>
                             <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
                         <#-- We expose the parentParserArguments to the child here too-->
-                            <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments?has_content>
-                            <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+                            <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
+                            <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
                             <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
                             )
                         </#if>
@@ -318,25 +297,25 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         </#if>
         <#break>
     <#case "checksum">
-        <#assign checksumField = field>
-        <#assign simpleTypeReference = checksumField.type>
+        <#assign checksumField = field.asChecksumField().orElseThrow()>
+        <#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
 
         // Checksum Field (checksum)
         {
             ${helper.getLanguageTypeNameForField(field)} checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
             ${helper.getLanguageTypeNameForField(field)} checksumRef = ${helper.getReadBufferReadMethodCall("checksum", simpleTypeReference, "", checksumField)};
-            checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.checksumExpression, type.parserArguments)});
+            checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.checksumExpression, parserArguments)});
             if(checksum != checksumRef) {
                 throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X", checksumRef & 0xFFFF, checksum & 0xFFFF));
             }
         }
         <#break>
     <#case "const">
-        <#assign constField = field>
+        <#assign constField = field.asConstField().orElseThrow()>
 
         // Const Field (${constField.name})
         <#if helper.isSimpleTypeReference(constField.type)>
-        <#assign simpleTypeReference = constField.type>
+            <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
         ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.name, simpleTypeReference, "", constField)};
         <#else>
         ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(constField.name, helper.getEnumBaseTypeReference(constField.type), "", constField)});
@@ -346,23 +325,24 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         }
         <#break>
     <#case "discriminator">
-        <#assign discriminatorField = field>
+        <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 
         // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
         <#if helper.isEnumField(field)>
-        ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = ${helper.getLanguageTypeNameForField(discriminatorField)}.enumForValue(${helper.getReadBufferReadMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "", discriminatorField)});
+        ${helper.getLanguageTypeNameForField(discriminatorField)} ${discriminatorField.name} = ${helper.getLanguageTypeNameForField(discriminatorField)}.enumForValue(${helper.getReadBufferReadMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "", discriminatorField)});
         <#else>
+            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
             <@compress single_line=true>
-        ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} =
+        ${helper.getLanguageTypeNameForField(discriminatorField)} ${discriminatorField.name} =
                 <#if helper.isSimpleTypeReference(discriminatorField.type)>
-                    ${helper.getReadBufferReadMethodCall(discriminatorField.name, discriminatorField.type, "", discriminatorField)}
+                    ${helper.getReadBufferReadMethodCall(discriminatorField.name, simpleTypeReference, "", discriminatorField)}
                 <#else>
-                    ${discriminatorField.type.name}IO.staticParse(readBuffer
-                    <#if field.params?has_content>
+                    ${discriminatorField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+                    <#if discriminatorField.params.isPresent()>
                         ,
-                        <#list field.params as parserArgument>
-                            (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(discriminatorField.type, parserArgument?index), true)})
-                            (${helper.toParseExpression(discriminatorField, parserArgument, type)})<#sep>, </#sep>
+                        <#list discriminatorField.params.orElseThrow() as parserArgument>
+                            (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleTypeReference, parserArgument?index), true)})
+                            (${helper.toParseExpression(discriminatorField, parserArgument, null)})<#sep>, </#sep>
                         </#list>
                     </#if>
                     )
@@ -372,26 +352,26 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 
         <#break>
     <#case "enum">
-        <#assign enumField = field>
+        <#assign enumField = field.asEnumField().orElseThrow()>
 
         readBuffer.pullContext("${enumField.name}");
         // Enum field (${enumField.name})
-        <#if enumField.fieldName?has_content>
-        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.firstEnumForField${enumField.fieldName?cap_first}(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)});
+        <#if enumField.fieldName.isPresent()>
+        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.firstEnumForField${enumField.fieldName.orElseThrow()?cap_first}(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)});
         <#else>
         ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)});
         </#if>
         readBuffer.closeContext("${enumField.name}");
         <#break>
     <#case "implicit">
-        <#assign implicitField = field>
-        <#assign simpleTypeReference = implicitField.type>
+        <#assign implicitField = field.asImplicitField().orElseThrow()>
+        <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
         // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
         ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = ${helper.getReadBufferReadMethodCall(implicitField.name, simpleTypeReference, "", implicitField)};
         <#break>
     <#case "manualArray">
-        <#assign manualArrayField = field>
+        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 
         readBuffer.pullContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         // Manual Array Field (${manualArrayField.name})
@@ -402,21 +382,21 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#-- If this is a count array, we can directly initialize an array with the given size -->
         <#if helper.isCountArrayField(field)>
         // Count array
-        int _${manualArrayField.name}Count = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)};
+        int _${manualArrayField.name}Count = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)};
         ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}Count];
         for(int i = 0; i < _${manualArrayField.name}Count; i++) {
-            ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)});
+            ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)});
         }
         <#-- In all other cases do we have to work with a list, that is later converted to an array -->
         <#else>
             <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
             <#if helper.isLengthArrayField(field)>
         // Length array
-        long _${manualArrayField.name}Length = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)};
+        long _${manualArrayField.name}Length = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)};
         List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
         long ${manualArrayField.name}EndPos = readBuffer.getPos() + _${manualArrayField.name}Length;
         while(readBuffer.getPos() < ${manualArrayField.name}EndPos) {
-            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)}));
+            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)}));
             <#-- After parsing, update the current position, but only if it's needed -->
             <#if manualArrayField.loopExpression.contains("curPos")>
             curPos = readBuffer.getPos() - startPos;
@@ -426,8 +406,8 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             <#elseif helper.isTerminatedArrayField(field)>
         // Terminated array
         List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
-        while(!((boolean) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)}))) {
-            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)}));
+        while(!((boolean) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)}))) {
+            _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)}));
 
             <#-- After parsing, update the current position, but only if it's needed -->
             <#if manualArrayField.loopExpression.contains("curPos")>
@@ -452,20 +432,20 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         readBuffer.closeContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         <#break>
     <#case "manual">
-        <#assign manualField = field>
+        <#assign manualField = field.asManualField().orElseThrow()>
 
         // Manual Field (${manualField.name})
-        ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, type.parserArguments)});
+        ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, parserArguments)});
         <#break>
     <#case "optional">
-        <#assign optionalField = field>
+        <#assign optionalField = field.asOptionalField().orElseThrow()>
 
         // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false)
         <#if optionalField.conditionExpression.contains("curPos")>
         curPos = readBuffer.getPos() - startPos;
         </#if>
         ${helper.getLanguageTypeNameForField(field)} ${optionalField.name} = null;
-        if(${helper.toParseExpression(optionalField, optionalField.conditionExpression, type.parserArguments)}) {
+        if(${helper.toParseExpression(optionalField, optionalField.conditionExpression, parserArguments)}) {
         <@compress single_line=true>
             ${optionalField.name} =
             <#if helper.isEnumField(optionalField)>
@@ -473,7 +453,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
                 ${helper.getReadBufferReadMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "", optionalField)}
             )
             <#elseif helper.isComplexTypeReference(optionalField.type)>
-                <#assign complexTypeReference=optionalField.type>
+                <#assign complexTypeReference=optionalField.type.asComplexTypeReference().orElseThrow()>
                 <#assign typeName=complexTypeReference.name>
                 <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
                 <#if helper.isDiscriminatedChildTypeDefinition(typeDefinition)>
@@ -482,27 +462,27 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
                     <#assign typeDefinition=typeDefinition.parentType>
                 </#if>
                 <#-- We downcast to the referenced type-->
-            (${optionalField.type.name}) ${typeName}IO.staticParse(
+            (${complexTypeReference.name}) ${typeName}IO.staticParse(
                 readBuffer
-                <#if field.params?has_content>,
-                    <#list field.params as parserArgument>
+                <#if field.params.isPresent()>,
+                    <#list field.params.orElseThrow() as parserArgument>
                         (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(optionalField.type, parserArgument?index), true)})
-                        (${helper.toParseExpression(optionalField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                        (${helper.toParseExpression(optionalField, parserArgument, parserArguments)})<#sep>, </#sep>
                     </#list>
                 </#if>
-                <#if complexTypeReference.params?has_content && typeDefinition.parserArguments?has_content>
+                <#if complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
                     <#assign argumentOffset=0>
-                    <#if field.params?has_content><#assign argumentOffset=field.params?size></#if>
+                    <#if field.params.isPresent()><#assign argumentOffset=field.params.orElseThrow()?size></#if>
                     ,
-                    <#list complexTypeReference.params as typeParam>
+                    <#list complexTypeReference.params.orElseThrow() as typeParam>
                     <#-- We cast here explicitly as java sometimes can't infer the type. e.g. 0 is a int and not a byte#-->
-                        (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments[typeParam?index + argumentOffset].type, true)})
+                        (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments.orElseThrow()[typeParam?index + argumentOffset].type, true)})
                         ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
                     </#list>
                 </#if>
                 )
             <#else>
-             ${helper.getReadBufferReadMethodCall(optionalField.name, optionalField.type, "", optionalField)}
+             ${helper.getReadBufferReadMethodCall(optionalField.name, optionalField.type.asSimpleTypeReference().orElseThrow(), "", optionalField)}
             </#if>
             ;
         </...@compress>
@@ -510,49 +490,50 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         }
         <#break>
     <#case "assert">
-        <#assign assertField = field>
+        <#assign assertField = field.asAssertField().orElseThrow()>
 
         // Assert Field
         <#if helper.isEnumField(assertField)>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getLanguageTypeNameForField(assertField)}.enumForValue(${helper.getReadBufferReadMethodCall(assertField.name, helper.getEnumBaseTypeReference(assertField.type), "", assertField)});
+        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getLanguageTypeNameForField(assertField)}.enumForValue(${helper.getReadBufferReadMethodCall(assertField.name, helper.getEnumBaseTypeReference(simpleTypeReference), "", assertField)});
         <#elseif helper.isComplexTypeReference(assertField.type)>
-            <#assign complexTypeReference=assertField.type>
+            <#assign complexTypeReference=assertField.type.asComplexTypeReference().orElseThrow()>
             <#assign typeName=complexTypeReference.name>
             <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
             <#if helper.isDiscriminatedChildTypeDefinition(typeDefinition)>
                 <#assign typeName=typeDefinition.getParentType().name>
             </#if>
             <@compress single_line=true>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = (${assertField.type.name}) ${typeName}IO.staticParse(readBuffer
-                <#if field.params?has_content>
+        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = (${complexTypeReference.name}) ${typeName}IO.staticParse(readBuffer
+                <#if field.params.isPresent()>
                     ,
-                    <#list field.params as parserArgument>
-                        (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(assertField.type, parserArgument?index), true)})
-                        (${helper.toParseExpression(assertField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                    <#list field.params.orElseThrow() as parserArgument>
+                        (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleTypeReference, parserArgument?index), true)})
+                        (${helper.toParseExpression(assertField, parserArgument, parserArguments)})<#sep>, </#sep>
                     </#list>
                 </#if>
-                <#if assertField.type.params?has_content>
+                <#if complexTypeReference.params.isPresent()>
                     ,
-                    <#list assertField.type.params as typeParam>
+                    <#list complexTypeReference.params.orElseThrow() as typeParam>
                         ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
                     </#list>
                 </#if>);
             </...@compress>
         <#else>
-        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getReadBufferReadMethodCall(assertField.name, assertField.type, "", assertField)};
+            <#assign simpleTypeReference = assertField.type.asSimpleTypeReference().orElseThrow()>
+        ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getReadBufferReadMethodCall(assertField.name, simpleTypeReference.asSimpleTypeReference().orElseThrow(), "", assertField)};
         </#if>
-        if(${assertField.name} != ${helper.toParseExpression(assertField, assertField.conditionExpression, type.parserArguments)}) {
-            throw new ParseAssertException("assertField ${assertField.name} with value " + ${assertField.name} + " didn't match the expected value " + ${helper.toParseExpression(assertField, assertField.conditionExpression, type.parserArguments)});
+        if(${assertField.name} != ${helper.toParseExpression(assertField.asTypedField().orElseThrow(), assertField.conditionExpression, parserArguments)}) {
+            throw new ParseAssertException("assertField ${assertField.name} with value " + ${assertField.name} + " didn't match the expected value " + ${helper.toParseExpression(assertField, assertField.conditionExpression, parserArguments)});
         }
         <#break>
     <#case "padding">
-        <#assign paddingField = field>
-        <#assign simpleTypeReference = paddingField.type>
+        <#assign paddingField = field.asPaddingField().orElseThrow()>
+        <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
         // Padding Field (padding)
         {
             readBuffer.pullContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
-            int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)});
+            int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, parserArguments)});
             while ((readBuffer.hasMore(${helper.getNumBits(simpleTypeReference)})) && (_timesPadding-- > 0)) {
                 // Just read the padding data and ignore it
                 ${helper.getReadBufferReadMethodCall(simpleTypeReference, "", paddingField)};
@@ -561,8 +542,8 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         }
         <#break>
     <#case "reserved">
-        <#assign reservedField = field>
-        <#assign simpleTypeReference = reservedField.type>
+        <#assign reservedField = field.asReservedField().orElseThrow()>
+        <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
         // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
         {
@@ -573,7 +554,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         }
         <#break>
     <#case "simple">
-        <#assign simpleField = field>
+        <#assign simpleField = field.asSimpleField().orElseThrow()>
 
         <#if simpleField.isTry()>
             <#-- TODO: we need to initalize base types-->
@@ -596,7 +577,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             ${helper.getReadBufferReadMethodCall(simpleField.type.name, helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)}
         );
         <#elseif helper.isComplexTypeReference(simpleField.type)>
-            <#assign complexTypeReference = simpleField.type>
+            <#assign complexTypeReference = simpleField.type.asComplexTypeReference().orElseThrow()>
             <#assign typeName=complexTypeReference.name>
             <#assign typeDefinition = helper.getTypeDefinitionForTypeReference(complexTypeReference)>
             <#if helper.isDiscriminatedChildTypeDefinition(typeDefinition)>
@@ -606,30 +587,30 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             </#if>
                 <#-- We downcast to the referenced type -->
         (${simpleField.type.name}) ${typeName}IO.staticParse(readBuffer
-            <#if field.params?has_content>,
-                <#list field.params as parserArgument>
+            <#if field.params.isPresent()>,
+                <#list field.params.orElseThrow() as parserArgument>
                     <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true) = 'String'>
             ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true)}
-                .valueOf(${helper.toParseExpression(simpleField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                .valueOf(${helper.toParseExpression(simpleField, parserArgument, parserArguments)})<#sep>, </#sep>
                     <#else>
                 (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true)})
-                (${helper.toParseExpression(simpleField, parserArgument, type.parserArguments)})<#sep>, </#sep>
+                (${helper.toParseExpression(simpleField, parserArgument, parserArguments)})<#sep>, </#sep>
                     </#if>
                 </#list>
             </#if>
-            <#if complexTypeReference.params?has_content && typeDefinition.parserArguments?has_content>
+            <#if complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
                 <#assign argumentOffset=0>
-                <#if field.params?has_content><#assign argumentOffset=field.params?size></#if>
+                <#if field.params.isPresent()><#assign argumentOffset=field.params.orElseThrow()?size></#if>
             ,
-                    <#list complexTypeReference.params as typeParam>
+                    <#list complexTypeReference.params.orElseThrow() as typeParam>
                             <#-- We cast here explicitly as java sometimes can't infer the type. e.g. 0 is a int and not a byte#-->
-            (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments[typeParam?index + argumentOffset].type, true)})
+            (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments.orElseThrow()[typeParam?index + argumentOffset].type, true)})
             ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
                     </#list>
             </#if>
                 )
         <#else>
-        ${helper.getReadBufferReadMethodCall(simpleFieldLogicalName, simpleField.type, "", simpleField)}
+        ${helper.getReadBufferReadMethodCall(simpleFieldLogicalName, simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}
         </#if>
             ;
         </...@compress>
@@ -646,18 +627,41 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         </#if>
         <#break>
     <#case "switch">
-        <#assign switchField = field>
+        <#assign switchField = field.asSwitchField().orElseThrow()>
 
         // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
         ${type.name}Builder builder = null;
         <#list switchField.cases as case>
-            <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)}, <#if helper.discriminatorValueNeedsStringEqualityCheck(switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(helper.getDiscriminatorTypes()[field.discriminatorExpre [...]
             <@compress single_line=true>
-            <#assign hasCaseParseArguments=case.parserArguments?has_content>
-            <#assign caseParseArguments><#if hasCaseParseArguments><#list case.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+            <#if case.discriminatorValues?has_content>
+                if(
+                <#list case.discriminatorValues as discriminatorValue>
+                    <#assign discriminatorExpression=switchField.discriminatorExpressions[discriminatorValue?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>
+                    EvaluationHelper.equals(
+                    ${helper.toParseExpression(null, discriminatorExpression, parserArguments)},
+                    <#if helper.discriminatorValueNeedsStringEqualityCheck(discriminatorExpression)>
+                        ${tracer.dive("discriminatorValueNeedsStringEqualityCheck")}"${discriminatorValue}"
+                    <#elseif helper.isComplexTypeReference(helper.getDiscriminatorTypes()[discriminatorExpression.name])>
+                        <#if helper.isEnumTypeReference(helper.getDiscriminatorTypes()[discriminatorExpression.name])>
+                            ${tracer.dive("isEnumTypeReference")}${helper.getDiscriminatorTypes()[discriminatorExpression.name].asComplexTypeReference().orElseThrow().name}.${discriminatorValue}
+                        <#else>
+                            ${tracer.dive("!isEnumTypeReference")}${discriminatorValue}
+                        </#if>
+                    <#else>
+                        ${tracer.dive("else")}${discriminatorValue}
+                    </#if>
+                    )
+                    <#sep> && </#sep>
+                    </#list>
+                )
+            </#if>{
+            </...@compress>
+            <@compress single_line=true>
+            <#assign hasCaseParseArguments=case.parserArguments.isPresent() && case.parserArguments.orElseThrow()?has_content>
+            <#assign caseParseArguments><#if hasCaseParseArguments><#list case.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
             <#-- We expose the parentParserArguments to the child here too-->
-            <#assign hasParentCaseParseArguments=case.parentType?? && case.parentType.parserArguments?has_content && case.parentType.parserArguments?filter(arg -> hasCaseParseArguments && !case.parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments)?has_content>
-            <#assign parentCaseParseArguments><#if hasParentCaseParseArguments><#list case.parentType.parserArguments?filter(arg -> hasCaseParseArguments && !case.parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+            <#assign hasParentCaseParseArguments=case.parentType?? && case.parentType.parserArguments.isPresent() && case.parentType.parserArguments.orElseThrow()?filter(arg -> hasCaseParseArguments && !case.parserArguments.orElseThrow()?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments)?has_content>
+            <#assign parentCaseParseArguments><#if hasParentCaseParseArguments><#list case.parentType.parserArguments.orElseThrow()?filter(arg -> hasCaseParseArguments && !case.parserArguments.orElseThrow()?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
             builder = ${case.name}IO.staticParse(readBuffer<#if hasCaseParseArguments>, ${tracer.dive("case parse arguments")} ${caseParseArguments}</#if><#if hasParentCaseParseArguments>, ${tracer.dive("case parent parse arguments")} ${parentCaseParseArguments}</#if>);
             </...@compress>
         }<#sep> else </#sep>
@@ -668,21 +672,21 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#break>
 
     <#case "unknown">
-        <#assign unknownField = field>
-        <#assign simpleTypeReference = unknownField.type>
+        <#assign unknownField = field.asUnknownField().orElseThrow()>
+        <#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
 
         // Unknown Field
         ${helper.getReadBufferReadMethodCall("unknown" , simpleTypeReference, "", unknownField)};
         <#break>
 
     <#case "virtual">
-        <#assign virtualField = field>
+        <#assign virtualField = field.asVirtualField().orElseThrow()>
 
         // Virtual field (Just declare a local variable so we can access it in the parser)
         <#if helper.getLanguageTypeNameForField(field) = 'String'>
-        ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toParseExpression(virtualField, virtualField.valueExpression, type.parserArguments)});
+        ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toParseExpression(virtualField, virtualField.valueExpression, parserArguments)});
         <#else>
-        ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(virtualField, virtualField.valueExpression, type.parserArguments)});
+        ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(virtualField, virtualField.valueExpression, parserArguments)});
         </#if>
         <#break>
 </#switch>
@@ -700,7 +704,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
     }
 
 <#if outputFlavor != "passive">
-    public static void staticSerialize(WriteBuffer writeBuffer, ${type.name} _value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+    public static void staticSerialize(WriteBuffer writeBuffer, ${type.name} _value<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
     <#if helper.hasFieldOfType("unknown")>
         throw new ParseException("Unknown field not serializable");
     <#else>
@@ -709,8 +713,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
-        <#assign arrayField = field>
-        <#assign simpleTypeReference = arrayField.type>
+        <#assign arrayField = field.asArrayField().orElseThrow()>
 
         // Array Field (${arrayField.name})
         if(_value.get${arrayField.name?cap_first}() != null) {
@@ -721,14 +724,14 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             writeBuffer.pushContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
             int itemCount = (int) _value.get${arrayField.name?cap_first}().length;
             int curItem = 0;
-            for(${helper.getLanguageTypeNameForField(field)} element : _value.get${arrayField.name?cap_first}()) {
+            for(${helper.getLanguageTypeNameForField(arrayField)} element : _value.get${arrayField.name?cap_first}()) {
                     <#if helper.isSimpleTypeReference(arrayField.type)>
-                        <#assign simpleTypeReference = arrayField.type>
-                ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "element", field)};
+                        <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
+                ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "element", arrayField)};
                     <#else>
-                        <#assign complexTypeReference = arrayField.type>
+                        <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
                 boolean lastItem = curItem == (itemCount - 1);
-                ${complexTypeReference.name}IO.staticSerialize(writeBuffer, element<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+                ${complexTypeReference.name}IO.staticSerialize(writeBuffer, element<#if helper.getSerializerTerms(field.params.orElse(null))?has_content>, <#list helper.getSerializerTerms(field.params.orElseThrow()) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
                     </#if>
                 curItem++;
             }
@@ -737,102 +740,102 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         }
         <#break>
     <#case "checksum">
-        <#assign checksumField = field>
-        <#assign simpleTypeReference = checksumField.type>
+        <#assign checksumField = field.asChecksumField().orElseThrow()>
+        <#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
 
         // Checksum Field (checksum) (Calculated)
         {
             ${helper.getLanguageTypeNameForField(field)} _checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
-            _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, type.parserArguments)});
-            ${helper.getWriteBufferWriteMethodCall("checksum", simpleTypeReference, "(_checksum)", field)};
+            _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, parserArguments)});
+            ${helper.getWriteBufferWriteMethodCall("checksum", simpleTypeReference, "(_checksum)", checksumField)};
         }
         <#break>
     <#case "const">
-        <#assign constField = field>
+        <#assign constField = field.asConstField().orElseThrow()>
 
         // Const Field (${constField.name})
         <#if helper.isSimpleTypeReference(constField.type)>
-            <#assign simpleTypeReference = constField.type>
+            <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
             <#if helper.getLanguageTypeNameForField(field) = 'float'>
-        ${helper.getWriteBufferWriteMethodCall(simpleTypeReference, constField.referenceValue + "f", field)};
+        ${helper.getWriteBufferWriteMethodCall(simpleTypeReference, constField.referenceValue + "f", constField)};
             <#else>
-        ${helper.getWriteBufferWriteMethodCall(constField.name, simpleTypeReference, constField.referenceValue, field)};
+        ${helper.getWriteBufferWriteMethodCall(constField.name, simpleTypeReference, constField.referenceValue, constField)};
             </#if>
         <#else>
             <#assign enumTypeReference = constField.type>
-            ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumTypeReference).name, helper.getEnumBaseTypeReference(enumTypeReference), "(" + type.name + "." + constField.name?upper_case + ".getValue())", field, "WithReaderWriterArgs.WithAdditionalStringRepresentation("+ type.name + "." + constField.name?upper_case + ".name())")};
+            ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumTypeReference).name, helper.getEnumBaseTypeReference(enumTypeReference), "(" + type.name + "." + constField.name?upper_case + ".getValue())", constField, "WithReaderWriterArgs.WithAdditionalStringRepresentation("+ type.name + "." + constField.name?upper_case + ".name())")};
         </#if>
         <#break>
     <#case "discriminator">
-        <#assign discriminatorField = field>
+        <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 
         // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
         ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${discriminatorField.name?cap_first}();
         <#if helper.isSimpleTypeReference(discriminatorField.type)>
-            <#assign simpleTypeReference = discriminatorField.type>
-            ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, simpleTypeReference, "(" + discriminatorField.name + ")", field)};
+            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
+            ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, simpleTypeReference, "(" + discriminatorField.name + ")", discriminatorField)};
         <#else>
             <#assign complexTypeReference = discriminatorField.type>
             <#if helper.isEnumField(field)>
-                ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "(" + discriminatorField.name + ".getValue())", field)};
+                ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "(" + discriminatorField.name + ".getValue())", discriminatorField)};
             <#else>
                 ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${discriminatorField.name});
             </#if>
         </#if>
         <#break>
     <#case "enum">
-        <#assign enumField = field>
+        <#assign enumField = field.asEnumField().orElseThrow()>
 
         writeBuffer.pushContext("${enumField.name}");
         // Enum field (${enumField.name})
-        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${enumField.name?cap_first}();
-        <#if enumField.fieldName?has_content>
-        ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName), "(" + enumField.name + ".get" + enumField.fieldName?cap_first + "())", field, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
+        ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(enumField)}) _value.get${enumField.name?cap_first}();
+        <#if enumField.fieldName.isPresent()>
+        ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()), "(" + enumField.name + ".get" + enumField.fieldName.orElseThrow()?cap_first + "())", enumField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
         <#else>
-        ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "(" + enumField.name + ".getValue())", field, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
+        ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "(" + enumField.name + ".getValue())", enumField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
         </#if>
         writeBuffer.popContext("${enumField.name}");
         <#break>
     <#case "implicit">
-        <#assign implicitField = field>
-        <#assign simpleTypeReference = implicitField.type>
+        <#assign implicitField = field.asImplicitField().orElseThrow()>
+        <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
         // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
-        ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, type.parserArguments)});
-        ${helper.getWriteBufferWriteMethodCall(implicitField.name, simpleTypeReference, "(" + implicitField.name + ")", field)};
+        ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, parserArguments)});
+        ${helper.getWriteBufferWriteMethodCall(implicitField.name, simpleTypeReference, "(" + implicitField.name + ")", implicitField)};
         <#break>
     <#case "manualArray">
-        <#assign manualArrayField = field>
+        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 
         // Manual Array Field (${manualArrayField.name})
         if(_value.get${manualArrayField.name?cap_first}() != null) {
             writeBuffer.pushContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
             for(${helper.getLanguageTypeNameForField(field)} element : _value.get${manualArrayField.name?cap_first}()) {
-                ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, type.parserArguments)};
+                ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, parserArguments)};
             }
             writeBuffer.popContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
         }
         <#break>
     <#case "manual">
-        <#assign manualField = field>
+        <#assign manualField = field.asTypedField().orElseThrow()>
 
         // Manual Field (${manualField.name})
-        ${helper.toSerializationExpression(manualField, manualField.serializeExpression, type.parserArguments)};
+        ${helper.toSerializationExpression(manualField, manualField.serializeExpression, parserArguments)};
        <#break>
     <#case "optional">
-        <#assign optionalField = field>
+        <#assign optionalField = field.asOptionalField().orElseThrow()>
 
         // Optional Field (${optionalField.name}) (Can be skipped, if the value is null)
         ${helper.getLanguageTypeNameForField(field)} ${optionalField.name} = null;
         if(_value.get${optionalField.name?cap_first}() != null) {
             ${optionalField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${optionalField.name?cap_first}();
             <#if helper.isSimpleTypeReference(optionalField.type)>
-                <#assign simpleTypeReference = optionalField.type>
-            ${helper.getWriteBufferWriteMethodCall(optionalField.name, simpleTypeReference, "(" + optionalField.name + ")", field)};
+                <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
+            ${helper.getWriteBufferWriteMethodCall(optionalField.name, simpleTypeReference, "(" + optionalField.name + ")", optionalField)};
             <#else>
                 <#assign complexTypeReference = optionalField.type>
                 <#if helper.isEnumField(field)>
-            ${helper.getWriteBufferWriteMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "(" + optionalField.name + ".getValue())", field)};
+            ${helper.getWriteBufferWriteMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "(" + optionalField.name + ".getValue())", optionalField)};
                 <#else>
             ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${optionalField.name});
                 </#if>
@@ -840,37 +843,37 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         }
         <#break>
     <#case "padding">
-        <#assign paddingField = field>
-        <#assign simpleTypeReference = paddingField.type>
+        <#assign paddingField = field.asPaddingField().orElseThrow()>
+        <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
         // Padding Field (padding)
         {
             writeBuffer.pushContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
-            int _timesPadding = (int) (${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, type.parserArguments)});
+            int _timesPadding = (int) (${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, parserArguments)});
             while (_timesPadding-- > 0) {
-                ${helper.getLanguageTypeNameForField(field)} _paddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(paddingField, paddingField.paddingValue, type.parserArguments)});
-                ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", field)};
+                ${helper.getLanguageTypeNameForField(field)} _paddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(paddingField, paddingField.paddingValue, parserArguments)});
+                ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", paddingField)};
             }
             writeBuffer.popContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
         }
         <#break>
     <#case "reserved">
-        <#assign reservedField = field>
-        <#assign simpleTypeReference = reservedField.type>
+        <#assign reservedField = field.asReservedField().orElseThrow()>
+        <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
         // Reserved Field (reserved)
-        ${helper.getWriteBufferWriteMethodCall("reserved", simpleTypeReference, helper.getReservedValue(field), field)};
+        ${helper.getWriteBufferWriteMethodCall("reserved", simpleTypeReference, helper.getReservedValue(reservedField), reservedField)};
         <#break>
     <#case "simple">
-        <#assign simpleField = field>
+        <#assign simpleField = field.asSimpleField().orElseThrow()>
 
         // Simple Field (${simpleField.name})
         ${helper.getLanguageTypeNameForField(field)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${simpleField.name?cap_first}();
         <#if helper.isSimpleTypeReference(simpleField.type)>
-            <#assign simpleTypeReference = simpleField.type>
+            <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
             <#if helper.isEnumField(field)>
-        // enum based simple field with type ${simpleField.type.name}
-        ${helper.getWriteBufferWriteMethodCall(simpleField.type.name, simpleTypeReference, "(" + simpleField.name + ")", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
+        // enum based simple field with type ${simpleField.type.asComplexTypeReference().orElseThrow().name}
+        ${helper.getWriteBufferWriteMethodCall(simpleField.type.asComplexTypeReference().orElseThrow().name, simpleTypeReference, "(" + simpleField.name + ")", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
             <#else>
         ${helper.getWriteBufferWriteMethodCall(simpleField.name, simpleTypeReference, "(" + simpleField.name + ")", simpleField)};
             </#if>
@@ -878,8 +881,8 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         writeBuffer.pushContext("${simpleField.name}");
             <#assign complexTypeReference = simpleField.type>
             <#if helper.isEnumField(field)>
-        // enum field with type ${simpleField.type.name}
-        ${helper.getWriteBufferWriteMethodCall(simpleField.type.name, helper.getEnumBaseTypeReference(simpleField.type), "(" + simpleField.name + ".getValue())", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
+        // enum field with type ${complexTypeReference.name}
+        ${helper.getWriteBufferWriteMethodCall(complexTypeReference.name, helper.getEnumBaseTypeReference(simpleField.type), "(" + simpleField.name + ".getValue())", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
             <#else>
         ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${simpleField.name});
             </#if>
@@ -887,7 +890,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         </#if>
         <#break>
     <#case "switch">
-        <#assign switchField = field>
+        <#assign switchField = field.asSwitchField().orElseThrow()>
 
         // Switch field (Depending on the discriminator values, passes the instantiation to a sub-type)
         <#list switchField.cases as case>
@@ -925,7 +928,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
             </#list>
         }
 
-        public ${type.name} build(<#list type.parentType.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
+        public ${type.name} build(<#list type.parentType.asComplexTypeDefinition().orElseThrow().propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
             return new ${type.name}(<#list type.allPropertyFields as field>${field.name}<#sep>, </#sep></#list>);
         }
     }
diff --git a/code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh
index ab85f9a..05693d6 100644
--- a/code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/pojo-template.java.ftlh
@@ -26,23 +26,6 @@
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
 <#-- Declare the name and type of variables declared locally inside the template -->
-<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
-<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
-<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
-<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
-<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
-<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
-<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
-<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
-<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
-<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
-<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
-<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
-<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
-<#-- @ftlvariable name="unknownField" type="org.apache.plc4x.plugins.codegenerator.types.fields.UnknownField" -->
-<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
-<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
-<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
 ${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.java
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -81,6 +64,8 @@ import java.math.BigInteger;
 
 // Code generated by code-generation. DO NOT EDIT.
 
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
 public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${type.name}<#if type.parentType??> extends ${type.parentType.name}</#if> implements Message {
 
 <#--
@@ -146,8 +131,8 @@ public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${
 </#list>
     }
 
-<#list type.getAbstractFields() as field>
-    public abstract ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> get${field.name?cap_first}();
+<#list type.abstractFields as field>
+    public abstract ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> get${field.asNamedField().orElseThrow().name?cap_first}();
 
 </#list>
 <#list type.propertyFields as field>
@@ -160,9 +145,9 @@ public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${
     <#if !helper.isDiscriminatorField(field.name)>
     public ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> get${field.name?cap_first}() {
         <#if helper.getLanguageTypeNameForField(field) = 'String'>
-        return ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toAccessExpression(field, field.valueExpression, type.parserArguments)});
+        return ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toAccessExpression(field, field.valueExpression, parserArguments)});
         <#else>
-        return (${helper.getLanguageTypeNameForField(field)}) (${helper.toAccessExpression(field, field.valueExpression, type.parserArguments)});
+        return (${helper.getLanguageTypeNameForField(field)}) (${helper.toAccessExpression(field, field.valueExpression, parserArguments)});
         </#if>
     }
     </#if>
@@ -185,17 +170,17 @@ public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
-        <#assign arrayField = field>
+        <#assign arrayField = field.asArrayField().orElseThrow()>
 
         // Array field
         if(${arrayField.name} != null) {
         <#if helper.isSimpleTypeReference(arrayField.type)>
-            <#assign simpleTypeReference = arrayField.type>
+            <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
             lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.length;
         <#elseif helper.isCountArrayField(arrayField)>
             int i=0;
-            <#assign simpleTypeReference = arrayField.type>
-            for(${arrayField.type.name} element : ${arrayField.name}) {
+            <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
+            for(${complexTypeReference.name} element : ${arrayField.name}) {
                 boolean last = ++i >= ${arrayField.name}.length;
                 lengthInBits += element.getLengthInBitsConditional(last);
             }
@@ -226,13 +211,13 @@ public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${
         </#if>
         <#break>
     <#case "discriminator">
-        <#assign discriminatorField = field>
+        <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 
         // Discriminator Field (${discriminatorField.name})
         <#if helper.isSimpleTypeReference(discriminatorField.type)>
-            <#assign simpleTypeReference = discriminatorField.type>
+            <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
             <#if helper.getLanguageTypeNameForTypeReference(discriminatorField.type) = "String">
-        lengthInBits += ${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)};
+        lengthInBits += ${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), parserArguments)};
             <#else>
         lengthInBits += ${simpleTypeReference.sizeInBits};
             </#if>
@@ -249,34 +234,34 @@ public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${
         lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
         <#break>
     <#case "implicit">
-        <#assign implicitField = field>
+        <#assign implicitField = field.asImplicitField().orElseThrow()>
         <#assign simpleTypeReference = implicitField.type>
 
         // Implicit Field (${implicitField.name})
         lengthInBits += ${simpleTypeReference.sizeInBits};
-        //${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, type.parserArguments)});
+        //${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, parserArguments)});
         <#break>
     <#case "manualArray">
-        <#assign manualArrayField = field>
+        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
 
         // Manual Array Field (${manualArrayField.name})
-        lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, type.parserArguments)} * 8;
+        lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, parserArguments)} * 8;
         <#break>
     <#case "manual">
-        <#assign manualField = field>
+        <#assign manualField = field.asManualField().orElseThrow()>
 
         // Manual Field (${manualField.name})
-        lengthInBits += ${helper.toParseExpression(manualField, manualField.lengthExpression, type.parserArguments)} * 8;
+        lengthInBits += ${helper.toParseExpression(manualField, manualField.lengthExpression, parserArguments)} * 8;
         <#break>
     <#case "optional">
-        <#assign optionalField = field>
+        <#assign optionalField = field.asOptionalField().orElseThrow()>
 
         // Optional Field (${optionalField.name})
         if(${optionalField.name} != null) {
         <#if helper.isSimpleTypeReference(optionalField.type)>
-            <#assign simpleTypeReference = optionalField.type>
+            <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
             <#if helper.getLanguageTypeNameForTypeReference(optionalField.type) = "String">
-            lengthInBits += ${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), type.parserArguments)};
+            lengthInBits += ${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), parserArguments)};
             <#else>
             lengthInBits += ${simpleTypeReference.sizeInBits};
             </#if>
@@ -288,12 +273,12 @@ public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${
         }
         <#break>
     <#case "padding">
-        <#assign paddingField = field>
+        <#assign paddingField = field.asPaddingField().orElseThrow()>
         <#assign simpleTypeReference = paddingField.type>
 
         // Padding Field (padding)
         <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last -->
-        int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)});
+        int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, parserArguments)});
         while (_timesPadding-- > 0) {
             lengthInBits += ${simpleTypeReference.sizeInBits};
         }
@@ -306,15 +291,15 @@ public<#if helper.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${
         lengthInBits += ${simpleTypeReference.sizeInBits};
         <#break>
     <#case "simple">
-        <#assign simpleField = field>
+        <#assign simpleField = field.asSimpleField().orElseThrow()>
 
         // Simple field (${simpleField.name})
         <#if helper.isSimpleTypeReference(simpleField.type)>
                 <#if helper.getLanguageTypeNameForTypeReference(simpleField.type) = "String">
-                    <#assign simpleTypeReference = simpleField.type>
-        lengthInBits += ${helper.toSerializationExpression(simpleField, simpleTypeReference.getLengthExpression(), type.parserArguments)};
+                    <#assign stringTypeReference = simpleField.type.asStringTypeReference().orElseThrow()>
+        lengthInBits += ${helper.toSerializationExpression(simpleField, stringTypeReference.getLengthExpression(), parserArguments)};
                 <#else>
-                    <#assign simpleTypeReference = simpleField.type>
+                    <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
         lengthInBits += ${simpleTypeReference.sizeInBits};
                 </#if>
         <#elseif helper.isEnumField(field)>
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringListener.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringListener.java
index 31bf29a..22ea74c 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringListener.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringListener.java
@@ -20,10 +20,8 @@ package org.apache.plc4x.plugins.codegenerator.language.mspec.expression;
 
 import org.apache.plc4x.plugins.codegenerator.types.terms.*;
 
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Stack;
+import java.util.*;
+import java.util.stream.Collectors;
 
 public class ExpressionStringListener extends ExpressionBaseListener {
 
@@ -59,27 +57,27 @@ public class ExpressionStringListener extends ExpressionBaseListener {
 
     @Override
     public void exitNullExpression(ExpressionParser.NullExpressionContext ctx) {
-        parserContexts.peek().add(new NullLiteral());
+        parserContexts.peek().add(new DefaultNullLiteral());
     }
 
     @Override
     public void exitBoolExpression(ExpressionParser.BoolExpressionContext ctx) {
-        parserContexts.peek().add(new BooleanLiteral(Boolean.parseBoolean(ctx.getText())));
+        parserContexts.peek().add(new DefaultBooleanLiteral(Boolean.parseBoolean(ctx.getText())));
     }
 
     @Override
     public void exitNumberExpression(ExpressionParser.NumberExpressionContext ctx) {
         String strValue = ctx.Number().getText();
         if (strValue.contains(".")) {
-            parserContexts.peek().add(new NumericLiteral(Double.valueOf(strValue)));
+            parserContexts.peek().add(new DefaultNumericLiteral(Double.valueOf(strValue)));
         } else {
-            parserContexts.peek().add(new NumericLiteral(Long.valueOf(strValue)));
+            parserContexts.peek().add(new DefaultNumericLiteral(Long.valueOf(strValue)));
         }
     }
 
     @Override
     public void exitStringExpression(ExpressionParser.StringExpressionContext ctx) {
-        parserContexts.peek().add(new StringLiteral(ctx.getText()));
+        parserContexts.peek().add(new DefaultStringLiteral(ctx.getText()));
     }
 
     @Override
@@ -113,7 +111,7 @@ public class ExpressionStringListener extends ExpressionBaseListener {
         if (restContext != null) {
             rest = restContext.getFirst();
         }
-        parserContexts.peek().add(new VariableLiteral(name, argsContext, index, rest));
+        parserContexts.peek().add(new DefaultVariableLiteral(name, argsContext, index, rest));
     }
 
     @Override
@@ -135,7 +133,8 @@ public class ExpressionStringListener extends ExpressionBaseListener {
     @Override
     public void exitIdentifierSegmentIndexes(ExpressionParser.IdentifierSegmentIndexesContext ctx) {
         List<Term> args = parserContexts.pop();
-        parserContexts.peek().add(new IndexContext(args));
+        List<NumericLiteral> numericLiterals = args.stream().map(NumericLiteral.class::cast).collect(Collectors.toList());
+        parserContexts.peek().add(new IndexContext(numericLiterals));
     }
 
     @Override
@@ -146,7 +145,8 @@ public class ExpressionStringListener extends ExpressionBaseListener {
     @Override
     public void exitIdentifierSegmentRest(ExpressionParser.IdentifierSegmentRestContext ctx) {
         List<Term> args = parserContexts.pop();
-        parserContexts.peek().add(new RestContext(args));
+        List<VariableLiteral> variableLiterals = args.stream().map(VariableLiteral.class::cast).collect(Collectors.toList());
+        parserContexts.peek().add(new RestContext(variableLiterals));
     }
 
     /////////////////////////////////////////////////////////////////////////////////////////
@@ -324,7 +324,7 @@ public class ExpressionStringListener extends ExpressionBaseListener {
             throw new RuntimeException(op + " should be a unary operation");
         }
         Term a = terms.get(0);
-        return new UnaryTerm(a, op);
+        return new DefaultUnaryTerm(a, op);
     }
 
     private BinaryTerm getBinaryTerm(String op, List<Term> terms) {
@@ -333,7 +333,7 @@ public class ExpressionStringListener extends ExpressionBaseListener {
         }
         Term a = terms.get(0);
         Term b = terms.get(1);
-        return new BinaryTerm(a, b, op);
+        return new DefaultBinaryTerm(a, b, op);
     }
 
     private TernaryTerm getTernaryTerm(String op, List<Term> terms) {
@@ -343,11 +343,11 @@ public class ExpressionStringListener extends ExpressionBaseListener {
         Term a = terms.get(0);
         Term b = terms.get(1);
         Term c = terms.get(2);
-        return new TernaryTerm(a, b, c, op);
+        return new DefaultTernaryTerm(a, b, c, op);
     }
 
     static class ArgsContext extends LinkedList<Term> implements Term {
-        ArgsContext(Collection c) {
+        ArgsContext(Collection<Term> c) {
             super(c);
         }
 
@@ -355,10 +355,15 @@ public class ExpressionStringListener extends ExpressionBaseListener {
         public boolean contains(String str) {
             return false;
         }
+
+        @Override
+        public String stringRepresentation() {
+            return "";
+        }
     }
 
     static class IndexContext extends LinkedList<NumericLiteral> implements Term {
-        IndexContext(Collection c) {
+        IndexContext(Collection<NumericLiteral> c) {
             super(c);
         }
 
@@ -366,10 +371,15 @@ public class ExpressionStringListener extends ExpressionBaseListener {
         public boolean contains(String str) {
             return false;
         }
+
+        @Override
+        public String stringRepresentation() {
+            return "";
+        }
     }
 
     static class RestContext extends LinkedList<VariableLiteral> implements Term {
-        RestContext(Collection c) {
+        RestContext(Collection<VariableLiteral> c) {
             super(c);
         }
 
@@ -377,6 +387,11 @@ public class ExpressionStringListener extends ExpressionBaseListener {
         public boolean contains(String str) {
             return false;
         }
+
+        @Override
+        public String stringRepresentation() {
+            return "";
+        }
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java
index 3bc873e..9fdae0b 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultComplexTypeDefinition.java
@@ -25,6 +25,7 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.*;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 public class DefaultComplexTypeDefinition extends DefaultTypeDefinition implements ComplexTypeDefinition {
@@ -32,10 +33,10 @@ public class DefaultComplexTypeDefinition extends DefaultTypeDefinition implemen
     private final boolean isAbstract;
     private final List<Field> fields;
 
-    public DefaultComplexTypeDefinition(String name, Argument[] parserArguments, String[] tags, boolean isAbstract, List<Field> fields) {
+    public DefaultComplexTypeDefinition(String name, List<Argument> parserArguments, List<String> tags, boolean isAbstract, List<Field> fields) {
         super(name, parserArguments, tags);
         this.isAbstract = isAbstract;
-        this.fields = fields;
+        this.fields = Objects.requireNonNull(fields);
     }
 
     public boolean isAbstract() {
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDataIoTypeDefinition.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDataIoTypeDefinition.java
index 204aad8..396063c 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDataIoTypeDefinition.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDataIoTypeDefinition.java
@@ -25,21 +25,29 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField;
 import org.apache.plc4x.plugins.codegenerator.types.references.DefaultComplexTypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 
+import java.util.List;
+import java.util.Objects;
+
 public class DefaultDataIoTypeDefinition extends DefaultTypeDefinition implements DataIoTypeDefinition {
 
     private final SwitchField switchField;
     private final TypeReference type;
 
-    public DefaultDataIoTypeDefinition(String name, Argument[] parserArguments, String[] tags, SwitchField switchField) {
+    public DefaultDataIoTypeDefinition(String name, List<Argument> parserArguments, List<String> tags, SwitchField switchField) {
         super(name, parserArguments, tags);
-        this.switchField = switchField;
-        this.type = parserArguments[0].getType();
+        this.switchField = Objects.requireNonNull(switchField);
+        if (parserArguments.size() < 1) {
+            throw new IllegalStateException();
+        }
+        this.type = Objects.requireNonNull(parserArguments.get(0).getType());
     }
 
     public SwitchField getSwitchField() {
         return switchField;
     }
 
-    public TypeReference getType() { return this.type; }
+    public TypeReference getType() {
+        return this.type;
+    }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDiscriminatedComplexTypeDefinition.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDiscriminatedComplexTypeDefinition.java
index c7d39b9..9bbec47 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDiscriminatedComplexTypeDefinition.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultDiscriminatedComplexTypeDefinition.java
@@ -24,14 +24,15 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField;
 import org.apache.plc4x.plugins.codegenerator.types.fields.Field;
 
 import java.util.List;
+import java.util.Objects;
 
 public class DefaultDiscriminatedComplexTypeDefinition extends DefaultComplexTypeDefinition implements DiscriminatedComplexTypeDefinition {
 
-    private final String[] discriminatorValues;
+    private final List<String> discriminatorValues;
 
-    public DefaultDiscriminatedComplexTypeDefinition(String name, Argument[] parserArguments, String[] tags, String[] discriminatorValues, List<Field> fields) {
+    public DefaultDiscriminatedComplexTypeDefinition(String name, List<Argument> parserArguments, List<String> tags, List<String> discriminatorValues, List<Field> fields) {
         super(name, parserArguments, tags, false, fields);
-        this.discriminatorValues = discriminatorValues;
+        this.discriminatorValues = Objects.requireNonNull(discriminatorValues);
     }
 
     public DiscriminatorField getDiscriminatorField() {
@@ -44,7 +45,7 @@ public class DefaultDiscriminatedComplexTypeDefinition extends DefaultComplexTyp
             .orElse(null);
     }
 
-    public String[] getDiscriminatorValues() {
+    public List<String> getDiscriminatorValues() {
         return discriminatorValues;
     }
 
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumTypeDefinition.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumTypeDefinition.java
index a8ba2f6..730213f 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumTypeDefinition.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumTypeDefinition.java
@@ -23,20 +23,19 @@ import org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefiniti
 import org.apache.plc4x.plugins.codegenerator.types.enums.EnumValue;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 
 public class DefaultEnumTypeDefinition extends DefaultTypeDefinition implements EnumTypeDefinition {
 
     private final TypeReference type;
-    private final EnumValue[] enumValues;
+    private final List<EnumValue> enumValues;
     private final Map<String, TypeReference> constants;
 
-    public DefaultEnumTypeDefinition(String name, TypeReference type, EnumValue[] enumValues,
-                                     Argument[] constants, String[] tags) {
+    public DefaultEnumTypeDefinition(String name, TypeReference type, List<EnumValue> enumValues,
+                                     List<Argument> constants, List<String> tags) {
         super(name, constants, tags);
-        this.type = type;
-        this.enumValues = enumValues;
+        this.type = Objects.requireNonNull(type);
+        this.enumValues = Objects.requireNonNull(enumValues);
         this.constants = new HashMap<>();
         if (constants != null) {
             for (Argument constant : constants) {
@@ -51,13 +50,13 @@ public class DefaultEnumTypeDefinition extends DefaultTypeDefinition implements
     }
 
     @Override
-    public EnumValue[] getEnumValues() {
+    public List<EnumValue> getEnumValues() {
         return enumValues;
     }
 
     @Override
-    public String[] getConstantNames() {
-        return constants.keySet().toArray(new String[0]);
+    public List<String> getConstantNames() {
+        return new ArrayList<>(constants.keySet());
     }
 
     @Override
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumValue.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumValue.java
index 84f0033..12dd6d8 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumValue.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultEnumValue.java
@@ -21,6 +21,8 @@ package org.apache.plc4x.plugins.codegenerator.language.mspec.model.definitions;
 import org.apache.plc4x.plugins.codegenerator.types.enums.EnumValue;
 
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 
 public class DefaultEnumValue implements EnumValue {
 
@@ -29,8 +31,8 @@ public class DefaultEnumValue implements EnumValue {
     private final Map<String, String> constants;
 
     public DefaultEnumValue(String value, String name, Map<String, String> constants) {
-        this.value = value;
-        this.name = name;
+        this.value = Objects.requireNonNull(value);
+        this.name = Objects.requireNonNull(name);
         this.constants = constants;
     }
 
@@ -45,8 +47,11 @@ public class DefaultEnumValue implements EnumValue {
     }
 
     @Override
-    public String getConstant(String name) {
-        return constants.get(name);
+    public Optional<String> getConstant(String name) {
+        if (constants == null) {
+            return Optional.empty();
+        }
+        return Optional.ofNullable(constants.get(name));
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultTypeDefinition.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultTypeDefinition.java
index e72df8a..a105dfd 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultTypeDefinition.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultTypeDefinition.java
@@ -24,15 +24,19 @@ import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
 import org.apache.plc4x.plugins.codegenerator.types.references.DefaultComplexTypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public abstract class DefaultTypeDefinition {
 
-    private final String name;
-    private final Argument[] parserArguments;
-    private final String[] tags;
-    private TypeDefinition parentType;
+    protected final String name;
+    protected final List<Argument> parserArguments;
+    protected final List<String> tags;
+    protected TypeDefinition parentType;
 
-    public DefaultTypeDefinition(String name, Argument[] parserArguments, String[] tags) {
-        this.name = name;
+    public DefaultTypeDefinition(String name, List<Argument> parserArguments, List<String> tags) {
+        this.name = Objects.requireNonNull(name);
         this.parserArguments = parserArguments;
         this.tags = tags;
         this.parentType = null;
@@ -42,12 +46,12 @@ public abstract class DefaultTypeDefinition {
         return name;
     }
 
-    public Argument[] getParserArguments() {
-        return parserArguments;
+    public Optional<List<Argument>> getParserArguments() {
+        return Optional.ofNullable(parserArguments);
     }
 
-    public String[] getTags() {
-        return tags;
+    public Optional<List<String>> getTags() {
+        return Optional.ofNullable(tags);
     }
 
     public TypeDefinition getParentType() {
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAbstractField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAbstractField.java
index 2bcd33b..6bcbb4d 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAbstractField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAbstractField.java
@@ -23,16 +23,20 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultAbstractField extends DefaultField implements AbstractField {
 
     private final TypeReference type;
     private final String name;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultAbstractField(String[] tags, boolean isTry, TypeReference type, String name, Term[] params) {
+    public DefaultAbstractField(List<String> tags, boolean isTry, TypeReference type, String name, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
         this.params = params;
     }
 
@@ -44,8 +48,8 @@ public class DefaultAbstractField extends DefaultField implements AbstractField
         return name;
     }
 
-    public Term[] getParams() {
-        return params;
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java
index 2405869..55a5fef 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultArrayField.java
@@ -22,20 +22,24 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultArrayField extends DefaultField implements ArrayField {
 
     private final TypeReference type;
     private final String name;
     private final LoopType loopType;
     private final Term loopExpression;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultArrayField(String[] tags, boolean isTry, TypeReference type, String name, LoopType loopType, Term loopExpression, Term[] params) {
+    public DefaultArrayField(List<String> tags, boolean isTry, TypeReference type, String name, LoopType loopType, Term loopExpression, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.loopType = loopType;
-        this.loopExpression = loopExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.loopType = Objects.requireNonNull(loopType);
+        this.loopExpression = Objects.requireNonNull(loopExpression);
         this.params = params;
     }
 
@@ -56,8 +60,8 @@ public class DefaultArrayField extends DefaultField implements ArrayField {
     }
 
     @Override
-    public Term[] getParams() {
-        return params;
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAssertField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAssertField.java
index 5299099..514a1ab 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAssertField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultAssertField.java
@@ -22,18 +22,22 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.AssertField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultAssertField extends DefaultField implements AssertField {
 
     private final TypeReference type;
     private final String name;
     private final Term conditionExpression;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultAssertField(String[] tags, boolean isTry, TypeReference type, String name, Term conditionExpression, Term[] params) {
+    public DefaultAssertField(List<String> tags, boolean isTry, TypeReference type, String name, Term conditionExpression, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.conditionExpression = conditionExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.conditionExpression = Objects.requireNonNull(conditionExpression);
         this.params = params;
     }
 
@@ -49,8 +53,9 @@ public class DefaultAssertField extends DefaultField implements AssertField {
         return conditionExpression;
     }
 
-    public Term[] getParams() {
-        return params;
+    @Override
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultChecksumField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultChecksumField.java
index f305320..f51a7d3 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultChecksumField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultChecksumField.java
@@ -22,17 +22,22 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultChecksumField extends DefaultField implements ChecksumField {
 
     private final TypeReference type;
     private final String name;
     private final Term checksumExpression;
 
-    public DefaultChecksumField(String[] tags, boolean isTry, TypeReference type, String name, Term checksumExpression) {
+    public DefaultChecksumField(List<String> tags, boolean isTry, TypeReference type, String name, Term checksumExpression) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.checksumExpression = checksumExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.checksumExpression = Objects.requireNonNull(checksumExpression);
     }
 
     public TypeReference getType() {
@@ -47,8 +52,8 @@ public class DefaultChecksumField extends DefaultField implements ChecksumField
         return checksumExpression;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultConstField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultConstField.java
index ebadc92..a5373ed 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultConstField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultConstField.java
@@ -22,17 +22,22 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.ConstField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultConstField extends DefaultField implements ConstField {
 
     private final TypeReference type;
     private final String name;
     private final Object referenceValue;
 
-    public DefaultConstField(String[] tags, boolean isTry, TypeReference type, String name, Object referenceValue) {
+    public DefaultConstField(List<String> tags, boolean isTry, TypeReference type, String name, Object referenceValue) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.referenceValue = referenceValue;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.referenceValue = Objects.requireNonNull(referenceValue);
     }
 
     public TypeReference getType() {
@@ -47,8 +52,8 @@ public class DefaultConstField extends DefaultField implements ConstField {
         return referenceValue;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultDiscriminatorField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultDiscriminatorField.java
index aa94673..69c8d51 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultDiscriminatorField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultDiscriminatorField.java
@@ -22,15 +22,20 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultDiscriminatorField extends DefaultField implements DiscriminatorField {
 
     private final TypeReference type;
     private final String name;
 
-    public DefaultDiscriminatorField(String[] tags, boolean isTry, TypeReference type, String name) {
+    public DefaultDiscriminatorField(List<String> tags, boolean isTry, TypeReference type, String name) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
     }
 
     public TypeReference getType() {
@@ -41,8 +46,8 @@ public class DefaultDiscriminatorField extends DefaultField implements Discrimin
         return name;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultEnumField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultEnumField.java
index c59d159..ba7ba5e 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultEnumField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultEnumField.java
@@ -22,17 +22,21 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.EnumField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultEnumField extends DefaultField implements EnumField {
 
     private final TypeReference type;
     private final String name;
     private final String fieldName;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultEnumField(String[] tags, boolean isTry, TypeReference type, String name, String fieldName, Term[] params) {
+    public DefaultEnumField(List<String> tags, boolean isTry, TypeReference type, String name, String fieldName, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
         this.fieldName = fieldName;
         this.params = params;
     }
@@ -45,12 +49,13 @@ public class DefaultEnumField extends DefaultField implements EnumField {
         return name;
     }
 
-    public String getFieldName() {
-        return fieldName;
+    public Optional<String> getFieldName() {
+        return Optional.ofNullable(fieldName);
     }
 
-    public Term[] getParams() {
-        return params;
+    @Override
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultField.java
index 62fa841..4aee4c3 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultField.java
@@ -18,11 +18,15 @@
  */
 package org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields;
 
+import org.apache.plc4x.plugins.codegenerator.types.fields.TryField;
+
+import java.util.List;
+
 public abstract class DefaultField extends DefaultTaggedField implements TryField {
 
     private final boolean isTry;
 
-    protected DefaultField(String[] tags, boolean isTry) {
+    protected DefaultField(List<String> tags, boolean isTry) {
         super(tags);
         this.isTry = isTry;
     }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultImplicitField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultImplicitField.java
index ebae488..dc78b8a 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultImplicitField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultImplicitField.java
@@ -22,17 +22,22 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultImplicitField extends DefaultField implements ImplicitField {
 
     private final TypeReference type;
     private final String name;
     private final Term serializeExpression;
 
-    public DefaultImplicitField(String[] tags, boolean isTry, TypeReference type, String name, Term serializeExpression) {
+    public DefaultImplicitField(List<String> tags, boolean isTry, TypeReference type, String name, Term serializeExpression) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.serializeExpression = serializeExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.serializeExpression = Objects.requireNonNull(serializeExpression);
     }
 
     public TypeReference getType() {
@@ -47,8 +52,8 @@ public class DefaultImplicitField extends DefaultField implements ImplicitField
         return serializeExpression;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java
index b39a4b6..e438118 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualArrayField.java
@@ -22,6 +22,10 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultManualArrayField extends DefaultField implements ManualArrayField {
 
     private final TypeReference type;
@@ -31,17 +35,17 @@ public class DefaultManualArrayField extends DefaultField implements ManualArray
     private final Term parseExpression;
     private final Term serializeExpression;
     private final Term lengthExpression;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultManualArrayField(String[] tags, boolean isTry, TypeReference type, String name, LoopType loopType, Term loopExpression, Term parseExpression, Term serializeExpression, Term lengthExpression, Term[] params) {
+    public DefaultManualArrayField(List<String> tags, boolean isTry, TypeReference type, String name, LoopType loopType, Term loopExpression, Term parseExpression, Term serializeExpression, Term lengthExpression, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.loopType = loopType;
-        this.loopExpression = loopExpression;
-        this.parseExpression = parseExpression;
-        this.serializeExpression = serializeExpression;
-        this.lengthExpression = lengthExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.loopType = Objects.requireNonNull(loopType);
+        this.loopExpression = Objects.requireNonNull(loopExpression);
+        this.parseExpression = Objects.requireNonNull(parseExpression);
+        this.serializeExpression = Objects.requireNonNull(serializeExpression);
+        this.lengthExpression = Objects.requireNonNull(lengthExpression);
         this.params = params;
     }
 
@@ -74,8 +78,7 @@ public class DefaultManualArrayField extends DefaultField implements ManualArray
     }
 
     @Override
-    public Term[] getParams() {
-        return params;
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
-
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualField.java
index 9328418..b8e7d68 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultManualField.java
@@ -22,6 +22,10 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.ManualField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultManualField extends DefaultField implements ManualField {
 
     private final TypeReference type;
@@ -29,15 +33,15 @@ public class DefaultManualField extends DefaultField implements ManualField {
     private final Term parseExpression;
     private final Term serializeExpression;
     private final Term lengthExpression;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultManualField(String[] tags, boolean isTry, TypeReference type, String name, Term parseExpression, Term serializeExpression, Term lengthExpression, Term[] params) {
+    public DefaultManualField(List<String> tags, boolean isTry, TypeReference type, String name, Term parseExpression, Term serializeExpression, Term lengthExpression, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.parseExpression = parseExpression;
-        this.serializeExpression = serializeExpression;
-        this.lengthExpression = lengthExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.parseExpression = Objects.requireNonNull(parseExpression);
+        this.serializeExpression = Objects.requireNonNull(serializeExpression);
+        this.lengthExpression = Objects.requireNonNull(lengthExpression);
         this.params = params;
     }
 
@@ -61,8 +65,8 @@ public class DefaultManualField extends DefaultField implements ManualField {
         return lengthExpression;
     }
 
-    public Term[] getParams() {
-        return params;
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultOptionalField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultOptionalField.java
index 3697e59..4ef70f5 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultOptionalField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultOptionalField.java
@@ -22,18 +22,22 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultOptionalField extends DefaultField implements OptionalField {
 
     private final TypeReference type;
     private final String name;
     private final Term conditionExpression;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultOptionalField(String[] tags, boolean isTry, TypeReference type, String name, Term conditionExpression, Term[] params) {
+    public DefaultOptionalField(List<String> tags, boolean isTry, TypeReference type, String name, Term conditionExpression, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.conditionExpression = conditionExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.conditionExpression = Objects.requireNonNull(conditionExpression);
         this.params = params;
     }
 
@@ -49,8 +53,8 @@ public class DefaultOptionalField extends DefaultField implements OptionalField
         return conditionExpression;
     }
 
-    public Term[] getParams() {
-        return params;
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultPaddingField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultPaddingField.java
index 59f83da..a476ee1 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultPaddingField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultPaddingField.java
@@ -22,20 +22,24 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultPaddingField extends DefaultField implements PaddingField {
 
     private final TypeReference type;
     private final String name;
     private final Term paddingValue;
     private final Term paddingCondition;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultPaddingField(String[] tags, boolean isTry, TypeReference type, String name, Term paddingValue, Term paddingCondition, Term[] params) {
+    public DefaultPaddingField(List<String> tags, boolean isTry, TypeReference type, String name, Term paddingValue, Term paddingCondition, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.paddingValue = paddingValue;
-        this.paddingCondition = paddingCondition;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.paddingValue = Objects.requireNonNull(paddingValue);
+        this.paddingCondition = Objects.requireNonNull(paddingCondition);
         this.params = params;
     }
 
@@ -55,8 +59,8 @@ public class DefaultPaddingField extends DefaultField implements PaddingField {
         return paddingCondition;
     }
 
-    public Term[] getParams() {
-        return params;
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultReservedField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultReservedField.java
index f535cdf..8ec0089 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultReservedField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultReservedField.java
@@ -22,15 +22,20 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultReservedField extends DefaultField implements ReservedField {
 
     private final TypeReference type;
     private final Object referenceValue;
 
-    public DefaultReservedField(String[] tags, boolean isTry, TypeReference type, Object referenceValue) {
+    public DefaultReservedField(List<String> tags, boolean isTry, TypeReference type, Object referenceValue) {
         super(tags, isTry);
-        this.type = type;
-        this.referenceValue = referenceValue;
+        this.type = Objects.requireNonNull(type);
+        this.referenceValue = Objects.requireNonNull(referenceValue);
     }
 
     public TypeReference getType() {
@@ -41,8 +46,8 @@ public class DefaultReservedField extends DefaultField implements ReservedField
         return referenceValue;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSimpleField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSimpleField.java
index 4c5abe3..780d02d 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSimpleField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSimpleField.java
@@ -22,16 +22,20 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultSimpleField extends DefaultField implements SimpleField {
 
     private final TypeReference type;
     private final String name;
-    private final Term[] params;
+    private final List<Term> params;
 
-    public DefaultSimpleField(String[] tags, boolean isTry, TypeReference type, String name, Term[] params) {
+    public DefaultSimpleField(List<String> tags, boolean isTry, TypeReference type, String name, List<Term> params) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
         this.params = params;
     }
 
@@ -43,8 +47,8 @@ public class DefaultSimpleField extends DefaultField implements SimpleField {
         return name;
     }
 
-    public Term[] getParams() {
-        return params;
+    public Optional<List<Term>> getParams() {
+        return Optional.ofNullable(params);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSwitchField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSwitchField.java
index 3fd3f7f..c67cba0 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSwitchField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultSwitchField.java
@@ -21,27 +21,28 @@ package org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields;
 
 import org.apache.plc4x.plugins.codegenerator.types.definitions.DiscriminatedComplexTypeDefinition;
 import org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField;
+import org.apache.plc4x.plugins.codegenerator.types.fields.TryField;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
 
 public class DefaultSwitchField implements SwitchField, TryField {
 
     private final boolean isTry;
-    private final Term[] discriminatorExpressions;
+    private final List<Term> discriminatorExpressions;
     private final List<DiscriminatedComplexTypeDefinition> cases;
 
-    public DefaultSwitchField(boolean isTry, Term[] discriminatorExpressions) {
+    public DefaultSwitchField(boolean isTry, List<Term> discriminatorExpressions) {
         this.isTry = isTry;
-        this.discriminatorExpressions = discriminatorExpressions;
+        this.discriminatorExpressions = Objects.requireNonNull(discriminatorExpressions);
         this.cases = new LinkedList<>();
     }
 
-    public Term[] getDiscriminatorExpressions() {
+    public List<Term> getDiscriminatorExpressions() {
         return discriminatorExpressions;
     }
 
+    // TODO: replace with immutable
     public void addCase(DiscriminatedComplexTypeDefinition caseType) {
         cases.add(caseType);
     }
@@ -50,8 +51,8 @@ public class DefaultSwitchField implements SwitchField, TryField {
         return cases;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
     public boolean isTry() {
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultTaggedField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultTaggedField.java
index c5d8a16..ce44570 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultTaggedField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultTaggedField.java
@@ -20,17 +20,21 @@ package org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields;
 
 import org.apache.plc4x.plugins.codegenerator.types.fields.TaggedField;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public abstract class DefaultTaggedField implements TaggedField {
 
-    private final String[] tags;
+    private final List<String> tags;
 
-    public DefaultTaggedField(String[] tags) {
+    public DefaultTaggedField(List<String> tags) {
         this.tags = tags;
     }
 
     @Override
-    public String[] getTags() {
-        return tags;
+    public Optional<List<String>> getTags() {
+        return Optional.ofNullable(tags);
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultUnknownField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultUnknownField.java
index ce15538..e0db6de 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultUnknownField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultUnknownField.java
@@ -22,21 +22,26 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.UnknownField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultUnknownField extends DefaultField implements UnknownField {
 
     private final TypeReference type;
 
-    public DefaultUnknownField(String[] tags, boolean isTry, TypeReference type) {
+    public DefaultUnknownField(List<String> tags, boolean isTry, TypeReference type) {
         super(tags, isTry);
-        this.type = type;
+        this.type = Objects.requireNonNull(type);
     }
 
     public TypeReference getType() {
         return type;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultVirtualField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultVirtualField.java
index c4fee4e..f273a45 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultVirtualField.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/DefaultVirtualField.java
@@ -22,17 +22,22 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField;
 import org.apache.plc4x.plugins.codegenerator.types.references.TypeReference;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
 public class DefaultVirtualField extends DefaultField implements VirtualField {
 
     private final TypeReference type;
     private final String name;
     private final Term valueExpression;
 
-    public DefaultVirtualField(String[] tags, boolean isTry, TypeReference type, String name, Term valueExpression) {
+    public DefaultVirtualField(List<String> tags, boolean isTry, TypeReference type, String name, Term valueExpression) {
         super(tags, isTry);
-        this.type = type;
-        this.name = name;
-        this.valueExpression = valueExpression;
+        this.type = Objects.requireNonNull(type);
+        this.name = Objects.requireNonNull(name);
+        this.valueExpression = Objects.requireNonNull(valueExpression);
     }
 
     public TypeReference getType() {
@@ -47,8 +52,8 @@ public class DefaultVirtualField extends DefaultField implements VirtualField {
         return valueExpression;
     }
 
-    public Term[] getParams() {
-        return new Term[0];
+    public Optional<List<Term>> getParams() {
+        return Optional.of(Collections.emptyList());
     }
 
 }
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/TryField.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/TryField.java
deleted file mode 100644
index 6b51a70..0000000
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/fields/TryField.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.apache.plc4x.plugins.codegenerator.language.mspec.model.fields;
-
-public interface TryField {
-    /**
-     * Returns true if this field should be tryed to be parsed
-     *
-     * @return true if failure is an option
-     */
-    boolean isTry();
-}
diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
index 3b72bf0..34e01ad 100644
--- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
+++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatListener.java
@@ -25,6 +25,7 @@ import org.apache.plc4x.plugins.codegenerator.language.mspec.expression.Expressi
 import org.apache.plc4x.plugins.codegenerator.language.mspec.model.definitions.*;
 import org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields.*;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.Argument;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.DefaultArgument;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.DiscriminatedComplexTypeDefinition;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
 import org.apache.plc4x.plugins.codegenerator.types.enums.EnumValue;
@@ -35,9 +36,11 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField;
 import org.apache.plc4x.plugins.codegenerator.types.references.*;
 import org.apache.plc4x.plugins.codegenerator.types.terms.Term;
 
+import javax.xml.crypto.OctetStreamData;
 import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.util.*;
+import java.util.stream.Collectors;
 
 public class MessageFormatListener extends MSpecBaseListener {
 
@@ -80,7 +83,7 @@ public class MessageFormatListener extends MSpecBaseListener {
     @Override
     public void exitComplexType(MSpecParser.ComplexTypeContext ctx) {
         String typeName = getIdString(ctx.name);
-        Argument[] parserArguments = null;
+        List<Argument> parserArguments = null;
         if (ctx.params != null) {
             parserArguments = getParserArguments(ctx.params.argument());
         }
@@ -88,7 +91,11 @@ public class MessageFormatListener extends MSpecBaseListener {
         // Handle enum types.
         if (ctx.enumValues != null) {
             TypeReference type = (ctx.type != null) ? getTypeReference(ctx.type) : null;
-            EnumValue[] enumValues = getEnumValues();
+            List<EnumValue> enumValues = getEnumValues();
+            if (type == null) {
+                // in case there is no type we default to uint32
+                type = new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.UINT, 32);
+            }
             DefaultEnumTypeDefinition enumType = new DefaultEnumTypeDefinition(typeName, type, enumValues,
                 parserArguments, null);
             types.put(typeName, enumType);
@@ -112,8 +119,7 @@ public class MessageFormatListener extends MSpecBaseListener {
             // If the type has sub-types it's an abstract type.
             SwitchField switchField = getSwitchField();
             boolean abstractType = switchField != null;
-            DefaultComplexTypeDefinition type = new DefaultComplexTypeDefinition(typeName, parserArguments, null,
-                abstractType, parserContexts.peek());
+            DefaultComplexTypeDefinition type = new DefaultComplexTypeDefinition(typeName, parserArguments, null, abstractType, parserContexts.peek());
             types.put(typeName, type);
 
             // Set the parent type for all sub-types.
@@ -133,7 +139,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         TypeReference type = getTypeReference(ctx.type);
         String name = getIdString(ctx.name);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultAbstractField(null, fieldDefinitionContext.tryParse() != null, type, name, params);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -148,7 +154,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         String loopExpressionString = getExprString(ctx.loopExpression);
         Term loopExpression = getExpressionTerm(loopExpressionString);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultArrayField(null, fieldDefinitionContext.tryParse() != null, type, name, loopType, loopExpression, params);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -200,7 +206,7 @@ public class MessageFormatListener extends MSpecBaseListener {
             fieldName = getIdString(ctx.fieldName);
         }
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultEnumField(null, fieldDefinitionContext.tryParse() != null, type, name, fieldName, params);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -227,7 +233,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         String conditionExpressionString = getExprString(ctx.condition);
         Term conditionExpression = getExpressionTerm(conditionExpressionString);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultAssertField(null, fieldDefinitionContext.tryParse() != null, type, name, conditionExpression, params);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -249,7 +255,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         String lengthExpressionString = getExprString(ctx.lengthExpression);
         Term lengthExpression = getExpressionTerm(lengthExpressionString);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultManualArrayField(null, fieldDefinitionContext.tryParse() != null, type, name, loopType, loopExpression,
             parseExpression, serializeExpression, lengthExpression, params);
         if (parserContexts.peek() != null) {
@@ -268,7 +274,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         String lengthExpressionString = getExprString(ctx.lengthExpression);
         Term lengthExpression = getExpressionTerm(lengthExpressionString);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultManualField(null, fieldDefinitionContext.tryParse() != null, type, name, parseExpression, serializeExpression,
             lengthExpression, params);
         if (parserContexts.peek() != null) {
@@ -283,7 +289,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         String conditionExpressionString = getExprString(ctx.condition);
         Term conditionExpression = getExpressionTerm(conditionExpressionString);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultOptionalField(null, fieldDefinitionContext.tryParse() != null, type, name, conditionExpression, params);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -299,7 +305,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         String paddingConditionString = getExprString(ctx.paddingCondition);
         Term paddingCondition = getExpressionTerm(paddingConditionString);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultPaddingField(null, fieldDefinitionContext.tryParse() != null, type, name, paddingValue, paddingCondition, params);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -321,7 +327,7 @@ public class MessageFormatListener extends MSpecBaseListener {
         TypeReference type = getTypeReference(ctx.type);
         String name = getIdString(ctx.name);
         MSpecParser.FieldDefinitionContext fieldDefinitionContext = (MSpecParser.FieldDefinitionContext) ctx.parent.parent;
-        Term[] params = getFieldParams(fieldDefinitionContext);
+        List<Term> params = getFieldParams(fieldDefinitionContext);
         Field field = new DefaultSimpleField(null, fieldDefinitionContext.tryParse() != null, type, name, params);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -330,11 +336,10 @@ public class MessageFormatListener extends MSpecBaseListener {
 
     @Override
     public void enterTypeSwitchField(MSpecParser.TypeSwitchFieldContext ctx) {
-        int numDiscriminators = ctx.discriminators.expression().size();
-        Term[] discriminatorExpressions = new Term[numDiscriminators];
-        for (int i = 0; i < numDiscriminators; i++) {
-            discriminatorExpressions[i] = getExpressionTerm(getExprString(ctx.discriminators.expression().get(i)));
-        }
+        List<Term> discriminatorExpressions = ctx.discriminators.expression().stream()
+            .map(this::getExprString)
+            .map(this::getExpressionTerm)
+            .collect(Collectors.toList());
         DefaultSwitchField field = new DefaultSwitchField(false, discriminatorExpressions);
         if (parserContexts.peek() != null) {
             parserContexts.peek().add(field);
@@ -375,26 +380,24 @@ public class MessageFormatListener extends MSpecBaseListener {
         // For DataIO types, add all the arguments from the parent type.
         if (!(ctx.parent.parent.parent.parent instanceof MSpecParser.ComplexTypeContext)
             && ((MSpecParser.ComplexTypeContext) ctx.parent.parent.parent).params != null) {
-            parserArguments.addAll(Arrays.asList(getParserArguments(
-                ((MSpecParser.ComplexTypeContext) ctx.parent.parent.parent).params.argument())));
+            parserArguments.addAll(getParserArguments(
+                ((MSpecParser.ComplexTypeContext) ctx.parent.parent.parent).params.argument()));
         }
         // Add all eventually existing local arguments.
         if (ctx.argumentList() != null) {
-            parserArguments.addAll(Arrays.asList(getParserArguments(ctx.argumentList().argument())));
+            parserArguments.addAll(getParserArguments(ctx.argumentList().argument()));
         }
 
-        String[] discriminatorValues;
+        List<String> discriminatorValues;
         if (ctx.discriminatorValues != null) {
-            List<MSpecParser.ExpressionContext> expressions = ctx.discriminatorValues.expression();
-            discriminatorValues = new String[expressions.size()];
-            for (int i = 0; i < expressions.size(); i++) {
-                discriminatorValues[i] = getExprString(expressions.get(i));
-            }
+            discriminatorValues = ctx.discriminatorValues.expression().stream()
+                .map(this::getExprString)
+                .collect(Collectors.toList());
         } else {
-            discriminatorValues = new String[0];
+            discriminatorValues = Collections.emptyList();
         }
         DefaultDiscriminatedComplexTypeDefinition type =
-            new DefaultDiscriminatedComplexTypeDefinition(typeName, parserArguments.toArray(new Argument[0]), null,
+            new DefaultDiscriminatedComplexTypeDefinition(typeName, parserArguments, null,
                 discriminatorValues, parserContexts.pop());
 
         // Add the type to the switch field definition.
@@ -438,8 +441,19 @@ public class MessageFormatListener extends MSpecBaseListener {
                 constants.put(constantName, constant);
             }
         }
+        List<EnumValue> enumValues = Objects.requireNonNull(this.enumContexts.peek());
+        if (value == null) {
+            // If no values are specified we count
+            String counted = "0";
+            if (enumValues.size() > 0) {
+                String previousValue = enumValues.get(enumValues.size() - 1).getValue();
+                int parsedPreviousValue = Integer.parseInt(previousValue);
+                counted = "" + (parsedPreviousValue + 1);
+            }
+            value = counted;
+        }
         final DefaultEnumValue enumValue = new DefaultEnumValue(value, name, constants);
-        this.enumContexts.peek().add(enumValue);
+        enumValues.add(enumValue);
     }
 
     private Term getExpressionTerm(String expressionString) {
@@ -503,33 +517,28 @@ public class MessageFormatListener extends MSpecBaseListener {
         return null;
     }
 
-    private EnumValue[] getEnumValues() {
-        return Objects.requireNonNull(enumContexts.peek()).toArray(new EnumValue[0]);
+    private List<EnumValue> getEnumValues() {
+        return Objects.requireNonNull(enumContexts.peek());
     }
 
-    private Argument[] getParserArguments(List<MSpecParser.ArgumentContext> params) {
-        Argument[] parserArguments = new Argument[params.size()];
-        for (int i = 0; i < params.size(); i++) {
-            TypeReference type = getTypeReference(params.get(i).type);
-            String name = getIdString(params.get(i).name);
-            parserArguments[i] = new Argument(type, name);
-        }
-        return parserArguments;
+    private List<Argument> getParserArguments(List<MSpecParser.ArgumentContext> params) {
+        return params.stream()
+            .map(argumentContext -> new DefaultArgument(getTypeReference(argumentContext.type), getIdString(argumentContext.name)))
+            .collect(Collectors.toList());
     }
 
-    private Term[] getFieldParams(MSpecParser.FieldDefinitionContext parentCtx) {
+    private List<Term> getFieldParams(MSpecParser.FieldDefinitionContext parentCtx) {
         return getParams(parentCtx.params);
     }
 
-    private Term[] getParams(MSpecParser.MultipleExpressionsContext params) {
+    private List<Term> getParams(MSpecParser.MultipleExpressionsContext params) {
         if (params == null) {
             return null;
         }
-        Term[] terms = new Term[params.expression().size()];
-        for (int i = 0; i < params.expression().size(); i++) {
-            terms[i] = parseExpression(getExprString(params.expression().get(i)));
-        }
-        return terms;
+        return params.expression().stream()
+            .map(this::getExprString)
+            .map(this::parseExpression)
+            .collect(Collectors.toList());
     }
 
     private Term parseExpression(String expressionString) {
diff --git a/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringParserTest.java b/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringParserTest.java
index 986edb0..4034b45 100644
--- a/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringParserTest.java
+++ b/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/ExpressionStringParserTest.java
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
 
 import java.nio.charset.Charset;
 import java.util.List;
+import java.util.Optional;
 import java.util.function.Consumer;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -161,14 +162,14 @@ class ExpressionStringParserTest {
         assertThat(variableLiteral.getName(), is(name));
         assertThat(variableLiteral.getIndex(), is(index));
         if (argsAsserter != null) {
-            argsAsserter.accept(variableLiteral.getArgs());
+            argsAsserter.accept(variableLiteral.getArgs().orElseThrow(RuntimeException::new));
         } else {
-            assertThat(variableLiteral.getArgs(), nullValue());
+            assertThat(variableLiteral.getArgs().orElse(null), nullValue());
         }
         if (childAsserter != null) {
-            childAsserter.accept(variableLiteral.getChild());
+            childAsserter.accept(variableLiteral.getChild().orElseThrow(RuntimeException::new));
         } else {
-            assertThat(variableLiteral.getChild(), nullValue());
+            assertThat(variableLiteral.getChild().orElse(null), nullValue());
         }
     }
 
diff --git a/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatParserTest.java b/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatParserTest.java
index d5c827f..c914d68 100644
--- a/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatParserTest.java
+++ b/code-generation/protocol-base-mspec/src/test/java/org/apache/plc4x/plugins/codegenerator/language/mspec/parser/MessageFormatParserTest.java
@@ -40,6 +40,11 @@ class MessageFormatParserTest {
     void parseSomething() {
         Map<String, TypeDefinition> parse = SUT.parse(getClass().getResourceAsStream("/mspec.example"));
         System.out.println(parse);
+    }
 
+    @Test
+    void parseSomethingElse() {
+        Map<String, TypeDefinition> parse = SUT.parse(getClass().getResourceAsStream("/mspec.example2"));
+        System.out.println(parse);
     }
 }
\ No newline at end of file
diff --git a/code-generation/protocol-base-mspec/src/test/resources/mspec.example2 b/code-generation/protocol-base-mspec/src/test/resources/mspec.example2
new file mode 100644
index 0000000..04d89ff
--- /dev/null
+++ b/code-generation/protocol-base-mspec/src/test/resources/mspec.example2
@@ -0,0 +1,449 @@
+/*
+ * 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.
+ */
+
+////////////////////////////////////////////////////////////////
+// Simple Type
+////////////////////////////////////////////////////////////////
+
+//Showing below an example comment including which languages it is supported in and ascii doc reference.
+// Bit Field Test Single
+// Java +, C +, Go +
+// tag::SimpleBitTypeTest[]
+[type 'SimpleBitTypeTest'
+    [simple bit 'bitField']
+]
+// end::SimpleBitTypeTest[]
+
+[type 'FieldTypeTest'
+    [simple         uint 8 'simpleField']
+    //Abstract fields can only be used within discriminated base types.
+    //[abstract       unit 8  'abstractField']
+    [array          uint 8  'arrayField'        count      '5']
+    //TODO: Checksums fields are not supported in C
+    //[checksum       uint 8  'checksumField'     '100']
+    [const          uint 8  'constField'        '5']
+    // Discriminated Field can't be used in simple type
+    //[discriminator  uint 8  'discriminatorField']
+    [enum           EnumType  'enumField']
+    [implicit       uint 8  'implicitField' 'simpleField']
+    [optional       uint 8  'optionalField' 'simpleField == 5']
+    [padding        uint 8  'paddingField'  '0x00'  'simpleField']
+    [reserved       uint 8  '0x00']
+    // TypeSwitch field can't be used in non discriminatedTypes
+    //[typeSwitch 'simpleField' ]
+]
+
+// If a type has an unknown field, the entire serializer is reduced to firing an exception
+[type 'FieldTypeTestWithUnknownField'
+    [simple         uint 8 'simpleField']
+    //Abstract fields can only be used within discriminated base types.
+    //[abstract       unit 8  'abstractField']
+    [array          uint 8  'arrayField'        count      '5']
+    //TODO: Checksums fields are not supported in C
+    //[checksum       uint 8  'checksumField'     '100']
+    [const          uint 8  'constField'        '5']
+    // Discriminated Field can't be used in simple type
+    //[discriminator  uint 8  'discriminatorField']
+    [enum           EnumType  'enumField']
+    [implicit       uint 8  'implicitField' 'simpleField']
+    [optional       uint 8  'optionalField' 'simpleField == 5']
+    [padding        uint 8  'paddingField'  '0x00'  'simpleField']
+    [reserved       uint 8  '0x00']
+    [unknown        uint 16]
+    // TypeSwitch field can't be used in non discriminatedTypes
+    //[typeSwitch 'simpleField' ]
+]
+
+/*
+ * TODO: doesn't compile in java
+[type 'UFloatTypeTest'
+    [simple ufloat 8.23 'ufloatField']
+    [simple ufloat 11.52 'udoubleField']
+]
+*/
+
+/*
+ * TODO: doesn't compile in java
+[type 'TimeTypeTest'
+    [simple time 8 'timeField']
+    [simple date 8 'dateField']
+    [simple dateTime 8 'dateTimeField']
+]
+*/
+
+[type 'SimpleTypeTest'
+    [simple bit 'bitField']
+    [simple byte 'byteField']
+    [simple int 8 'intField']
+    [simple uint 8 'uintField']
+    [simple float 8.23 'floatField']
+    [simple float 11.52 'doubleField']
+    [simple string '8' 'UTF-8' 'stringField']
+]
+
+[type 'AbstractTypeTest'
+    //Abstract fields can only be used within discriminated base types.
+    [simple         uint 8 'simpleField']
+    [abstract bit 'abstractBitField']
+    [abstract int 8 'abstractIntField']
+    [abstract uint 8 'abstractUintField']
+    [abstract float 8.23 'abstractFloatField']
+    [abstract float 11.52 'abstractDoubleField']
+    [abstract string '8' 'UTF-8' 'abstractStringField']
+    [typeSwitch 'simpleField'
+        ['0' AbstractedType
+            [simple bit 'abstractBitField']
+            [simple int 8 'abstractIntField']
+            [simple uint 8 'abstractUintField']
+            [simple float 8.23 'abstractFloatField']
+            [simple float 11.52 'abstractDoubleField']
+            [simple string '8' 'UTF-8' 'abstractStringField']
+        ]
+    ]
+]
+
+[type 'AbstractTypeTest'
+    //Abstract fields can only be used within discriminated base types.
+    [simple   uint 8 'simpleField']
+    [abstract bit 'abstractBitField']
+    [abstract int 8 'abstractIntField']
+    [abstract uint 8 'abstractUintField']
+    [abstract float 8.23 'abstractFloatField']
+    [abstract float 11.52 'abstractDoubleField']
+    [abstract string '8' 'UTF-8' 'abstractStringField']
+    [typeSwitch 'simpleField'
+        ['0' AbstractedType
+            //Abstract fields need to be overriden in child
+            [simple bit 'abstractBitField']
+            [simple int 8 'abstractIntField']
+            [simple uint 8 'abstractUintField']
+            [simple float 8.23 'abstractFloatField']
+            [simple float 11.52 'abstractDoubleField']
+            [simple string '8' 'UTF-8' 'abstractStringField']
+        ]
+    ]
+]
+
+[type 'ArrayTypeTest'
+    [array bit 'bitField' count      '5']
+    [array int 8 'intField' count      '5']
+    [array uint 8 'uintField' count      '5']
+    [array float 8.23 'floatField' count      '5']
+    [array float 11.52 'doubleField' count      '5']
+    [array string '8' 'UTF-8' 'stringField' count      '5']
+]
+
+//TODO: Checksums fields are not supported in C
+//[type 'CheckSumTypeTest'
+    //Bit field cannot be used for a checksum
+    //[checksum bit 'bitField' true]
+    //[checksum int 8 'intField' '100']
+    //[checksum uint 8 'uintField' '100']
+    //Float fields cannot be used as checksums
+    //[checksum float 8.23 'floatField' '100.0f']
+    //[checksum float 11.52 'doubleField' '100.0']
+    //String field cannot be used as a checksum
+    //[checksum string '11 * 8' 'UTF-8' 'stringField' '"HELLO TODDY"']
+//]
+
+[type 'ConstTypeTest'
+    [const bit 'bitField' 'true']
+    [const int 8 'intField' '100']
+    [const uint 8 'uintField' '100']
+    [const float 8.23 'floatField' '100.0']
+    [const float 11.52 'doubleField' '100.0']
+    [const string '8' 'UTF-8' 'stringField' '"HELLO TODDY"']
+]
+
+[type 'EnumTypeTest'
+    [enum           EnumType  'enumField']
+]
+
+[type 'PascalStringTypeTest'
+    [simple int 8 'stringLength']
+    [simple string 'stringLength' 'UTF-8' 'stringField']
+]
+
+[type 'ImplicitPascalStringTypeTest'
+    [implicit int 8 'stringLength' 'stringField.length']
+    [simple string 'stringLength' 'UTF-8' 'stringField']
+]
+
+[type 'ImplicitTypeTest'
+    //Implicit types have the requirement that the expression is of a similar type to the field
+    //TODO: i.e Integers can't be cast to Booleans
+    [simple   uint 8 'simpleField']
+
+    [implicit bit 'bitField' 'simpleField > 0']
+    [implicit int 8 'intField' 'simpleField']
+    [implicit uint 8 'uintField' 'simpleField']
+    [implicit float 8.23 'floatField' 'simpleField']
+    [implicit float 11.52 'doubleField' 'simpleField']
+    //TODO: String literals can't be used in the expression
+    //[implicit string '8' 'UTF-8' 'stringField' 'simpleField > 0 ? "HELLO TODDY" : "BYE TODDY"']
+]
+
+[type 'OptionalTypeTest'
+    [simple         uint 8 'simpleField']
+    [optional       uint 8  'optionalField' 'simpleField == 5']
+]
+
+[type 'PaddingTypeTest'
+    [simple         uint 8 'simpleField']
+    [padding        uint 8  'paddingField'  '0x00'  'simpleField']
+]
+
+[type 'ReservedTypeTest'
+    [reserved       uint 8  '0x00']
+]
+
+//TODO: Virtual fields fail for GO, haven't checked C assuming fails.
+//[type 'VirtualFieldTest'
+//    [simple  uint 8 'simpleField']
+//    [virtual bit 'virtualBitField' 'simpleField == 0']
+//    [virtual int 8 'virtualIntField' 'simpleField']
+//    [virtual uint 8 'virtualUintField' 'simpleField']
+//    [virtual float 8.23 'virtualFloatField' 'simpleField']
+//    [virtual float 11.52 'virtualDoubleField' 'simpleField']
+//    [virtual string '24' 'virtualStringField' 'simpleField']
+//]
+
+//TODO: Virtual fields fail for GO, haven't checked C assuming fails.
+//[discriminatedType 'DiscriminatedVirtualTypeTest'
+//    [simple  uint 8 'simpleField']
+//    [virtual bit 'virtualBitField' 'simpleField == 0']
+//    [virtual int 8 'virtualIntField' 'simpleField']
+//    [virtual uint 8 'virtualUintField' 'simpleField']
+//    [virtual float 8.23 'virtualFloatField' 'simpleField']
+//    [virtual float 11.52 'virtualDoubleField' 'simpleField']
+//    [virtual string '24' 'UTF-8' 'virtualStringField' 'simpleField']
+//    [typeSwitch 'simpleField'
+//        ['0' DiscriminatedVirtualType
+//            [simple int 8 'intField']
+//        ]
+//    ]
+//]
+
+[type 'IntTypeTest'
+    [simple int 3 'ThreeField']
+    [simple int 8 'ByteField']
+    [simple int 16 'WordField']
+    [simple int 24 'WordPlusByteField']
+    [simple int 32 'DoubleIntField']
+    [simple int 64 'QuadIntField']
+]
+
+[type 'UIntTypeTest'
+    [simple uint 3 'ThreeField']
+    [simple uint 8 'ByteField']
+    [simple uint 16 'WordField']
+    [simple uint 24 'WordPlusByteField']
+    [simple uint 32 'DoubleIntField']
+    [simple uint 64 'QuadIntField']
+]
+
+//Specific test confirming a continous loop isn't formed when working out the length.
+[type 'LentghLoopTest'
+    [simple        uint 16 'commandType']
+    [implicit      uint 16 'len' 'lengthInBytes - 8']
+]
+
+////////////////////////////////////////////////////////////////
+// Discriminated Type Tests
+////////////////////////////////////////////////////////////////
+
+[discriminatedType 'EnumDiscriminatedType'
+    [discriminator EnumType 'discr']
+    [typeSwitch 'discr'
+        ['BOOL' EnumDiscriminatedTypeA
+            [simple        uint 8 'simpA']
+        ]
+        ['UINT' EnumDiscriminatedTypeB
+            [simple        uint 8 'simpB']
+        ]
+        ['INT' EnumDiscriminatedTypeC
+            [simple        uint 8 'simpC']
+        ]
+    ]
+]
+
+// Multiple Enumerated discriminators
+[discriminatedType 'EnumDiscriminatedTypeMultiple'
+    [discriminator EnumType 'discr1']
+    [discriminator EnumTypeInt 'discr2']
+    [typeSwitch 'discr1','discr2'
+        ['BOOL','BOOLINT' EnumDiscriminatedTypeMultipleA
+            [simple        uint 8 'simpA']
+        ]
+        ['UINT','UINTINT' EnumDiscriminatedTypeMultipleB
+            [simple        uint 8 'simpB']
+        ]
+        ['INT','INTINT' EnumDiscriminatedTypeMultipleC
+            [simple        uint 8 'simpC']
+        ]
+    ]
+]
+
+// Enumerated Parameter
+[discriminatedType 'EnumDiscriminatedTypeParameter' [EnumType 'discr']
+    [typeSwitch 'discr'
+        ['BOOL' EnumDiscriminatedTypeAParameter
+            [simple        uint 8 'simpA']
+        ]
+        ['UINT' EnumDiscriminatedTypeBParameter
+            [simple        uint 8 'simpB']
+        ]
+        ['INT' EnumDiscriminatedTypeCParameter
+            [simple        uint 8 'simpC']
+        ]
+    ]
+]
+
+// Multiple Enumerated Parameters
+[discriminatedType 'EnumDiscriminatedTypeParameterMultiple' [EnumType 'discr1', EnumTypeInt 'discr2']
+    [typeSwitch 'discr1','discr2'
+        ['BOOL','BOOLINT' EnumDiscriminatedTypeAParameterMultiple
+            [simple        uint 8 'simpA']
+        ]
+        ['UINT','UINTINT' EnumDiscriminatedTypeBParameterMultiple
+            [simple        uint 8 'simpB']
+        ]
+        ['INT','INTINT' EnumDiscriminatedTypeCParameterMultiple
+            [simple        uint 8 'simpC']
+        ]
+    ]
+]
+
+[discriminatedType 'SimpleDiscriminatedType'
+    [discriminator uint 8 'discr']
+    [typeSwitch 'discr'
+        ['0x00' SimpleDiscriminatedTypeA
+            [simple        uint 8 'simpA']
+        ]
+        ['0x01' SimpleDiscriminatedTypeB
+            [simple        uint 8 'simpB']
+        ]
+        ['0x02' SimpleDiscriminatedTypeC
+            [simple        uint 8 'simpC']
+        ]
+    ]
+]
+
+
+//Test to check if we can include concrete types as fields. Doesn't work in any language at the moment.
+//[discriminatedType 'SimpleDiscriminatedType'
+//    [discriminator uint 8 'discr']
+//    [typeSwitch 'discr'
+//        ['0x00' SimpleDiscriminatedTypeA
+//            [simple        AnotherSimpleDiscriminatedTypeA 'simpA']
+//        ]
+//    ]
+//]
+
+//[discriminatedType 'AnotherSimpleDiscriminatedType'
+//    [discriminator uint 8 'discr']
+//    [typeSwitch 'discr'
+//        ['0x00' AnotherSimpleDiscriminatedTypeA
+//            [simple        uint 8 'simpA']
+//        ]
+//    ]
+//]
+
+////////////////////////////////////////////////////////////////
+// Enumerated Type Tests
+////////////////////////////////////////////////////////////////
+
+[enum bit 'EnumTypeBit'
+    ['true' TRUE]
+    ['false' FALSE]
+]
+
+[enum int 8 'EnumTypeInt'
+    ['0x01' BOOLINT]
+    ['0x02' UINTINT]
+    ['0x03' INTINT]
+]
+
+[enum uint 8 'EnumType'
+    ['0x01' BOOL]
+    ['0x02' UINT]
+    ['0x03' INT]
+]
+
+//TODO:  C doesn't support non integer switch fields
+//[enum float 8.23 'EnumTypeFloat'
+//    ['100.0' LOW]
+//    ['101.0' MID]
+//    ['102.0' BIG]
+//]
+
+//TODO:  C doesn't support non integer switch fields
+//[enum float 11.52 'EnumTypeDouble'
+//    ['100.0' LOW]
+//    ['101.0' MID]
+//    ['102.0' BIG]
+//]
+
+//TODO:  C doesn't support non integer switch fields
+//[enum string '-1' 'EnumTypeString'
+//    ['Toddy1' TODDY]
+//]
+
+//TODO:  Fails to import the base Enum in C, need to find it in getComplexTypeReferences
+//[enum EnumType 'EnumTypeEnum'
+//    ['BOOL' BOOL]
+//    ['UINT' UINT]
+//    ['INT' INT]
+//]
+
+//TODO:  Float parameters aren't implemented for constants in enums in C
+//[enum int 8 'EnumTypeAllTest'  [bit 'bitType', int 8 'intType', uint 8 'uintType', float 8.23 'floatType', float 11.52 'doubleType', string '-1' 'stringType', EnumType 'enumType']
+//    ['0x01' BOOL             ['false'      , '1'               , '1'                 , '100.0'                  , '100.0'              , 'BOOL'         , 'BOOL']]
+//    ['0x02' BYTE             ['true'       , '2'               , '2'                 , '101.1'                  , '101.1'              , 'BYTE'         , 'UINT']]
+//]
+
+//TODO:  Keyword named parameters aren't allowed
+//[enum int 8 'EnumTypeIntTest'  [int 8 'int']
+//    ['0x01' BOOL             ['1']]
+//    ['0x02' BYTE             ['2']]
+//]
+
+//Showing allowed parameter types for enums
+[enum int 8 'EnumTypeParameters'  [bit 'bitType', int 8 'intType', uint 8 'uintType', string '-1' 'stringType', EnumType 'enumType']
+    ['0x01' BOOL             ['false'      , '1'               , '1'                 , 'BOOL'         , 'BOOL']]
+    ['0x02' BYTE             ['true'       , '2'               , '2'                 , 'BYTE'         , 'UINT']]
+]
+
+////////////////////////////////////////////////////////////////
+// Data IO Tests
+////////////////////////////////////////////////////////////////
+
+[dataIo 'DataIOType' [EnumType 'dataType']
+    [typeSwitch 'dataType'
+        ['BOOL' BOOL
+            [simple bit 'value']
+        ]
+        ['UINT' USINT
+            [simple uint 8 'value']
+        ]
+        ['INT' UINT
+            [simple uint 16 'value']
+        ]
+    ]
+]
diff --git a/plc4c/generated-sources/modbus/include/modbus_pdu.h b/plc4c/generated-sources/modbus/include/modbus_pdu.h
index 9394b93..d963501 100644
--- a/plc4c/generated-sources/modbus/include/modbus_pdu.h
+++ b/plc4c/generated-sources/modbus/include/modbus_pdu.h
@@ -30,7 +30,6 @@
 #include "modbus_pdu_read_file_record_request_item.h"
 #include "modbus_pdu_read_file_record_response_item.h"
 #include "modbus_pdu_write_file_record_response_item.h"
-#include "modbus_pdu.h"
 #include "modbus_error_code.h"
 
 // Code generated by code-generation. DO NOT EDIT.
diff --git a/plc4c/generated-sources/modbus/src/modbus_pdu.c b/plc4c/generated-sources/modbus/src/modbus_pdu.c
index 4f80c12..344a7d8 100644
--- a/plc4c/generated-sources/modbus/src/modbus_pdu.c
+++ b/plc4c/generated-sources/modbus/src/modbus_pdu.c
@@ -27,84 +27,84 @@
 // (The order is identical to the enum constants so we can use the
 // enum constant to directly access a given types discriminator values)
 const plc4c_modbus_read_write_modbus_pdu_discriminator plc4c_modbus_read_write_modbus_pdu_discriminators[] = {
-  {/* plc4c_modbus_read_write_modbus_pdu_error */
-   .errorFlag = true, .functionFlag = -1, .response = -1},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_discrete_inputs_request */
-   .errorFlag = false, .functionFlag = 0x02, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_discrete_inputs_response */
-   .errorFlag = false, .functionFlag = 0x02, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_coils_request */
-   .errorFlag = false, .functionFlag = 0x01, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_coils_response */
-   .errorFlag = false, .functionFlag = 0x01, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_single_coil_request */
-   .errorFlag = false, .functionFlag = 0x05, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_single_coil_response */
-   .errorFlag = false, .functionFlag = 0x05, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_multiple_coils_request */
-   .errorFlag = false, .functionFlag = 0x0F, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_multiple_coils_response */
-   .errorFlag = false, .functionFlag = 0x0F, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_input_registers_request */
-   .errorFlag = false, .functionFlag = 0x04, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_input_registers_response */
-   .errorFlag = false, .functionFlag = 0x04, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_holding_registers_request */
-   .errorFlag = false, .functionFlag = 0x03, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_holding_registers_response */
-   .errorFlag = false, .functionFlag = 0x03, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_single_register_request */
-   .errorFlag = false, .functionFlag = 0x06, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_single_register_response */
-   .errorFlag = false, .functionFlag = 0x06, .response = true},
   {/* plc4c_modbus_read_write_modbus_pdu_write_multiple_holding_registers_request */
-   .errorFlag = false, .functionFlag = 0x10, .response = false},
+   .errorFlag = false, .functionFlag = 0x10, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_get_com_event_counter_response */
+   .errorFlag = false, .functionFlag = 0x0B, .response = true },
   {/* plc4c_modbus_read_write_modbus_pdu_write_multiple_holding_registers_response */
-   .errorFlag = false, .functionFlag = 0x10, .response = true},
+   .errorFlag = false, .functionFlag = 0x10, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_multiple_coils_response */
+   .errorFlag = false, .functionFlag = 0x0F, .response = true },
   {/* plc4c_modbus_read_write_modbus_pdu_read_write_multiple_holding_registers_request */
-   .errorFlag = false, .functionFlag = 0x17, .response = false},
+   .errorFlag = false, .functionFlag = 0x17, .response = false },
   {/* plc4c_modbus_read_write_modbus_pdu_read_write_multiple_holding_registers_response */
-   .errorFlag = false, .functionFlag = 0x17, .response = true},
+   .errorFlag = false, .functionFlag = 0x17, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_exception_status_response */
+   .errorFlag = false, .functionFlag = 0x07, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_coils_response */
+   .errorFlag = false, .functionFlag = 0x01, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_file_record_request */
+   .errorFlag = false, .functionFlag = 0x14, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_fifo_queue_response */
+   .errorFlag = false, .functionFlag = 0x18, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_report_server_id_request */
+   .errorFlag = false, .functionFlag = 0x11, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_single_coil_request */
+   .errorFlag = false, .functionFlag = 0x05, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_holding_registers_request */
+   .errorFlag = false, .functionFlag = 0x03, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_report_server_id_response */
+   .errorFlag = false, .functionFlag = 0x11, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_coils_request */
+   .errorFlag = false, .functionFlag = 0x01, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_input_registers_request */
+   .errorFlag = false, .functionFlag = 0x04, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_device_identification_response */
+   .errorFlag = false, .functionFlag = 0x2B, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_single_register_request */
+   .errorFlag = false, .functionFlag = 0x06, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_get_com_event_counter_request */
+   .errorFlag = false, .functionFlag = 0x0B, .response = false },
   {/* plc4c_modbus_read_write_modbus_pdu_mask_write_holding_register_request */
-   .errorFlag = false, .functionFlag = 0x16, .response = false},
+   .errorFlag = false, .functionFlag = 0x16, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_error */
+   .errorFlag = true, .functionFlag = -1, .response = -1 },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_holding_registers_response */
+   .errorFlag = false, .functionFlag = 0x03, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_single_coil_response */
+   .errorFlag = false, .functionFlag = 0x05, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_device_identification_request */
+   .errorFlag = false, .functionFlag = 0x2B, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_input_registers_response */
+   .errorFlag = false, .functionFlag = 0x04, .response = true },
   {/* plc4c_modbus_read_write_modbus_pdu_mask_write_holding_register_response */
-   .errorFlag = false, .functionFlag = 0x16, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_fifo_queue_request */
-   .errorFlag = false, .functionFlag = 0x18, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_fifo_queue_response */
-   .errorFlag = false, .functionFlag = 0x18, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_file_record_request */
-   .errorFlag = false, .functionFlag = 0x14, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_file_record_response */
-   .errorFlag = false, .functionFlag = 0x14, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_file_record_request */
-   .errorFlag = false, .functionFlag = 0x15, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_write_file_record_response */
-   .errorFlag = false, .functionFlag = 0x15, .response = true},
+   .errorFlag = false, .functionFlag = 0x16, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_discrete_inputs_request */
+   .errorFlag = false, .functionFlag = 0x02, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_multiple_coils_request */
+   .errorFlag = false, .functionFlag = 0x0F, .response = false },
   {/* plc4c_modbus_read_write_modbus_pdu_read_exception_status_request */
-   .errorFlag = false, .functionFlag = 0x07, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_exception_status_response */
-   .errorFlag = false, .functionFlag = 0x07, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_diagnostic_request */
-   .errorFlag = false, .functionFlag = 0x08, .response = false},
+   .errorFlag = false, .functionFlag = 0x07, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_file_record_response */
+   .errorFlag = false, .functionFlag = 0x15, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_discrete_inputs_response */
+   .errorFlag = false, .functionFlag = 0x02, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_file_record_response */
+   .errorFlag = false, .functionFlag = 0x14, .response = true },
   {/* plc4c_modbus_read_write_modbus_pdu_diagnostic_response */
-   .errorFlag = false, .functionFlag = 0x08, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_get_com_event_counter_request */
-   .errorFlag = false, .functionFlag = 0x0B, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_get_com_event_counter_response */
-   .errorFlag = false, .functionFlag = 0x0B, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_get_com_event_log_request */
-   .errorFlag = false, .functionFlag = 0x0C, .response = false},
+   .errorFlag = false, .functionFlag = 0x08, .response = true },
   {/* plc4c_modbus_read_write_modbus_pdu_get_com_event_log_response */
-   .errorFlag = false, .functionFlag = 0x0C, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_report_server_id_request */
-   .errorFlag = false, .functionFlag = 0x11, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_report_server_id_response */
-   .errorFlag = false, .functionFlag = 0x11, .response = true},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_device_identification_request */
-   .errorFlag = false, .functionFlag = 0x2B, .response = false},
-  {/* plc4c_modbus_read_write_modbus_pdu_read_device_identification_response */
-   .errorFlag = false, .functionFlag = 0x2B, .response = true}
+   .errorFlag = false, .functionFlag = 0x0C, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_get_com_event_log_request */
+   .errorFlag = false, .functionFlag = 0x0C, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_read_fifo_queue_request */
+   .errorFlag = false, .functionFlag = 0x18, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_single_register_response */
+   .errorFlag = false, .functionFlag = 0x06, .response = true },
+  {/* plc4c_modbus_read_write_modbus_pdu_write_file_record_request */
+   .errorFlag = false, .functionFlag = 0x15, .response = false },
+  {/* plc4c_modbus_read_write_modbus_pdu_diagnostic_request */
+   .errorFlag = false, .functionFlag = 0x08, .response = false }
 
 };
 
diff --git a/plc4c/generated-sources/s7/include/cotp_packet.h b/plc4c/generated-sources/s7/include/cotp_packet.h
index a9ae97d..06935f8 100644
--- a/plc4c/generated-sources/s7/include/cotp_packet.h
+++ b/plc4c/generated-sources/s7/include/cotp_packet.h
@@ -26,7 +26,6 @@
 #include <plc4c/spi/read_buffer.h>
 #include <plc4c/spi/write_buffer.h>
 #include <plc4c/utils/list.h>
-#include "cotp_packet.h"
 #include "s7_message.h"
 #include "cotp_parameter.h"
 #include "cotp_protocol_class.h"
diff --git a/plc4c/generated-sources/s7/include/cotp_parameter.h b/plc4c/generated-sources/s7/include/cotp_parameter.h
index bf1f9af..87b7af7 100644
--- a/plc4c/generated-sources/s7/include/cotp_parameter.h
+++ b/plc4c/generated-sources/s7/include/cotp_parameter.h
@@ -27,7 +27,6 @@
 #include <plc4c/spi/write_buffer.h>
 #include <plc4c/utils/list.h>
 #include "cotp_tpdu_size.h"
-#include "cotp_parameter.h"
 
 // Code generated by code-generation. DO NOT EDIT.
 
diff --git a/plc4c/generated-sources/s7/include/s7_address.h b/plc4c/generated-sources/s7/include/s7_address.h
index f0f16b1..44eb358 100644
--- a/plc4c/generated-sources/s7/include/s7_address.h
+++ b/plc4c/generated-sources/s7/include/s7_address.h
@@ -26,7 +26,6 @@
 #include <plc4c/spi/read_buffer.h>
 #include <plc4c/spi/write_buffer.h>
 #include <plc4c/utils/list.h>
-#include "s7_address.h"
 #include "memory_area.h"
 #include "transport_size.h"
 
diff --git a/plc4c/generated-sources/s7/include/s7_data_alarm_message.h b/plc4c/generated-sources/s7/include/s7_data_alarm_message.h
index cccfcbb..7298d8e 100644
--- a/plc4c/generated-sources/s7/include/s7_data_alarm_message.h
+++ b/plc4c/generated-sources/s7/include/s7_data_alarm_message.h
@@ -30,7 +30,6 @@
 #include "data_transport_size.h"
 #include "syntax_id_type.h"
 #include "alarm_type.h"
-#include "s7_data_alarm_message.h"
 #include "query_type.h"
 
 // Code generated by code-generation. DO NOT EDIT.
@@ -57,9 +56,9 @@ plc4c_s7_read_write_s7_data_alarm_message_discriminator plc4c_s7_read_write_s7_d
 
 // Constant values.
 uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_NUMBER_MESSAGE_OBJ();
+uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID();
 uint8_t PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_LENGTH();
 uint8_t PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_VARIABLE_SPEC();
-uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID();
 
 struct plc4c_s7_read_write_s7_data_alarm_message {
   /* This is an abstract type so this property saves the type of this typed union */
diff --git a/plc4c/generated-sources/s7/include/s7_message.h b/plc4c/generated-sources/s7/include/s7_message.h
index 784933d..5fe2ef5 100644
--- a/plc4c/generated-sources/s7/include/s7_message.h
+++ b/plc4c/generated-sources/s7/include/s7_message.h
@@ -26,7 +26,6 @@
 #include <plc4c/spi/read_buffer.h>
 #include <plc4c/spi/write_buffer.h>
 #include <plc4c/utils/list.h>
-#include "s7_message.h"
 #include "s7_parameter.h"
 #include "s7_payload.h"
 
diff --git a/plc4c/generated-sources/s7/include/s7_parameter.h b/plc4c/generated-sources/s7/include/s7_parameter.h
index d34dccc..4989b4a 100644
--- a/plc4c/generated-sources/s7/include/s7_parameter.h
+++ b/plc4c/generated-sources/s7/include/s7_parameter.h
@@ -28,7 +28,6 @@
 #include <plc4c/utils/list.h>
 #include "s7_var_request_parameter_item.h"
 #include "s7_parameter_user_data_item.h"
-#include "s7_parameter.h"
 
 // Code generated by code-generation. DO NOT EDIT.
 
diff --git a/plc4c/generated-sources/s7/include/s7_parameter_user_data_item.h b/plc4c/generated-sources/s7/include/s7_parameter_user_data_item.h
index e68fb26..d8de1d4 100644
--- a/plc4c/generated-sources/s7/include/s7_parameter_user_data_item.h
+++ b/plc4c/generated-sources/s7/include/s7_parameter_user_data_item.h
@@ -26,7 +26,6 @@
 #include <plc4c/spi/read_buffer.h>
 #include <plc4c/spi/write_buffer.h>
 #include <plc4c/utils/list.h>
-#include "s7_parameter_user_data_item.h"
 
 // Code generated by code-generation. DO NOT EDIT.
 
diff --git a/plc4c/generated-sources/s7/include/s7_payload.h b/plc4c/generated-sources/s7/include/s7_payload.h
index da61619..3a4f6f5 100644
--- a/plc4c/generated-sources/s7/include/s7_payload.h
+++ b/plc4c/generated-sources/s7/include/s7_payload.h
@@ -30,7 +30,6 @@
 #include "s7_var_payload_status_item.h"
 #include "s7_var_payload_data_item.h"
 #include "s7_parameter.h"
-#include "s7_payload.h"
 
 // Code generated by code-generation. DO NOT EDIT.
 
diff --git a/plc4c/generated-sources/s7/include/s7_payload_user_data_item.h b/plc4c/generated-sources/s7/include/s7_payload_user_data_item.h
index bd10a28..3deaf56 100644
--- a/plc4c/generated-sources/s7/include/s7_payload_user_data_item.h
+++ b/plc4c/generated-sources/s7/include/s7_payload_user_data_item.h
@@ -28,7 +28,6 @@
 #include <plc4c/utils/list.h>
 #include "data_transport_error_code.h"
 #include "syntax_id_type.h"
-#include "s7_payload_user_data_item.h"
 #include "alarm_type.h"
 #include "date_and_time.h"
 #include "szl_id.h"
@@ -81,13 +80,13 @@ typedef enum plc4c_s7_read_write_s7_payload_user_data_item_type plc4c_s7_read_wr
 plc4c_s7_read_write_s7_payload_user_data_item_discriminator plc4c_s7_read_write_s7_payload_user_data_item_get_discriminator(plc4c_s7_read_write_s7_payload_user_data_item_type type);
 
 // Constant values.
-uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ();
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_NUMBER_MESSAGE_OBJ();
-uint16_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH();
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_VARIABLE_SPEC();
-uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID();
+uint16_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH();
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_FUNCTION_ID();
+uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ();
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_LENGTH();
+uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID();
 
 struct plc4c_s7_read_write_s7_payload_user_data_item {
   /* This is an abstract type so this property saves the type of this typed union */
diff --git a/plc4c/generated-sources/s7/include/s7_var_request_parameter_item.h b/plc4c/generated-sources/s7/include/s7_var_request_parameter_item.h
index 2bdeaba..e826511 100644
--- a/plc4c/generated-sources/s7/include/s7_var_request_parameter_item.h
+++ b/plc4c/generated-sources/s7/include/s7_var_request_parameter_item.h
@@ -27,7 +27,6 @@
 #include <plc4c/spi/write_buffer.h>
 #include <plc4c/utils/list.h>
 #include "s7_address.h"
-#include "s7_var_request_parameter_item.h"
 
 // Code generated by code-generation. DO NOT EDIT.
 
diff --git a/plc4c/generated-sources/s7/include/transport_size.h b/plc4c/generated-sources/s7/include/transport_size.h
index d827640..758849a 100644
--- a/plc4c/generated-sources/s7/include/transport_size.h
+++ b/plc4c/generated-sources/s7/include/transport_size.h
@@ -29,7 +29,6 @@
 // Code generated by code-generation. DO NOT EDIT.
 
 #include "data_transport_size.h"
-#include "transport_size.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/plc4c/generated-sources/s7/src/cotp_packet.c b/plc4c/generated-sources/s7/src/cotp_packet.c
index 9e72cad..a57924f 100644
--- a/plc4c/generated-sources/s7/src/cotp_packet.c
+++ b/plc4c/generated-sources/s7/src/cotp_packet.c
@@ -27,18 +27,18 @@
 // (The order is identical to the enum constants so we can use the
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_cotp_packet_discriminator plc4c_s7_read_write_cotp_packet_discriminators[] = {
-  {/* plc4c_s7_read_write_cotp_packet_data */
-   .tpduCode = 0xF0},
-  {/* plc4c_s7_read_write_cotp_packet_connection_request */
-   .tpduCode = 0xE0},
   {/* plc4c_s7_read_write_cotp_packet_connection_response */
-   .tpduCode = 0xD0},
-  {/* plc4c_s7_read_write_cotp_packet_disconnect_request */
-   .tpduCode = 0x80},
+   .tpduCode = 0xD0 },
+  {/* plc4c_s7_read_write_cotp_packet_data */
+   .tpduCode = 0xF0 },
   {/* plc4c_s7_read_write_cotp_packet_disconnect_response */
-   .tpduCode = 0xC0},
+   .tpduCode = 0xC0 },
+  {/* plc4c_s7_read_write_cotp_packet_disconnect_request */
+   .tpduCode = 0x80 },
+  {/* plc4c_s7_read_write_cotp_packet_connection_request */
+   .tpduCode = 0xE0 },
   {/* plc4c_s7_read_write_cotp_packet_tpdu_error */
-   .tpduCode = 0x70}
+   .tpduCode = 0x70 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/cotp_parameter.c b/plc4c/generated-sources/s7/src/cotp_parameter.c
index 3497d86..6975c52 100644
--- a/plc4c/generated-sources/s7/src/cotp_parameter.c
+++ b/plc4c/generated-sources/s7/src/cotp_parameter.c
@@ -28,15 +28,15 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_cotp_parameter_discriminator plc4c_s7_read_write_cotp_parameter_discriminators[] = {
   {/* plc4c_s7_read_write_cotp_parameter_tpdu_size */
-   .parameterType = 0xC0},
+   .parameterType = 0xC0 },
+  {/* plc4c_s7_read_write_cotp_parameter_disconnect_additional_information */
+   .parameterType = 0xE0 },
   {/* plc4c_s7_read_write_cotp_parameter_calling_tsap */
-   .parameterType = 0xC1},
+   .parameterType = 0xC1 },
   {/* plc4c_s7_read_write_cotp_parameter_called_tsap */
-   .parameterType = 0xC2},
+   .parameterType = 0xC2 },
   {/* plc4c_s7_read_write_cotp_parameter_checksum */
-   .parameterType = 0xC3},
-  {/* plc4c_s7_read_write_cotp_parameter_disconnect_additional_information */
-   .parameterType = 0xE0}
+   .parameterType = 0xC3 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/s7_address.c b/plc4c/generated-sources/s7/src/s7_address.c
index 63c7cf8..539bf7e 100644
--- a/plc4c/generated-sources/s7/src/s7_address.c
+++ b/plc4c/generated-sources/s7/src/s7_address.c
@@ -28,7 +28,7 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_address_discriminator plc4c_s7_read_write_s7_address_discriminators[] = {
   {/* plc4c_s7_read_write_s7_address_any */
-   .addressType = 0x10}
+   .addressType = 0x10 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/s7_data_alarm_message.c b/plc4c/generated-sources/s7/src/s7_data_alarm_message.c
index 30cf17f..842b225 100644
--- a/plc4c/generated-sources/s7/src/s7_data_alarm_message.c
+++ b/plc4c/generated-sources/s7/src/s7_data_alarm_message.c
@@ -28,9 +28,9 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_data_alarm_message_discriminator plc4c_s7_read_write_s7_data_alarm_message_discriminators[] = {
   {/* plc4c_s7_read_write_s7_message_object_request */
-   .cpuFunctionType = 0x04},
+   .cpuFunctionType = 0x04 },
   {/* plc4c_s7_read_write_s7_message_object_response */
-   .cpuFunctionType = 0x08}
+   .cpuFunctionType = 0x08 }
 
 };
 
@@ -52,6 +52,10 @@ static const uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_NUMBER_MESSAGE_OB
 uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_NUMBER_MESSAGE_OBJ() {
   return PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_NUMBER_MESSAGE_OBJ_const;
 }
+static const uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID_const = 0x00;
+uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID() {
+  return PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID_const;
+}
 static const uint8_t PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_LENGTH_const = 0x08;
 uint8_t PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_LENGTH() {
   return PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_LENGTH_const;
@@ -60,10 +64,6 @@ static const uint8_t PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_VARIABLE_SPEC
 uint8_t PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_VARIABLE_SPEC() {
   return PLC4C_S7_READ_WRITE_S7_MESSAGE_OBJECT_REQUEST_VARIABLE_SPEC_const;
 }
-static const uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID_const = 0x00;
-uint8_t PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID() {
-  return PLC4C_S7_READ_WRITE_S7_DATA_ALARM_MESSAGE_FUNCTION_ID_const;
-}
 
 // Parse function.
 plc4c_return_code plc4c_s7_read_write_s7_data_alarm_message_parse(plc4c_spi_read_buffer* readBuffer, uint8_t cpuFunctionType, plc4c_s7_read_write_s7_data_alarm_message** _message) {
diff --git a/plc4c/generated-sources/s7/src/s7_message.c b/plc4c/generated-sources/s7/src/s7_message.c
index d25d54a..c33711a 100644
--- a/plc4c/generated-sources/s7/src/s7_message.c
+++ b/plc4c/generated-sources/s7/src/s7_message.c
@@ -27,14 +27,14 @@
 // (The order is identical to the enum constants so we can use the
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_message_discriminator plc4c_s7_read_write_s7_message_discriminators[] = {
-  {/* plc4c_s7_read_write_s7_message_request */
-   .messageType = 0x01},
   {/* plc4c_s7_read_write_s7_message_response */
-   .messageType = 0x02},
+   .messageType = 0x02 },
   {/* plc4c_s7_read_write_s7_message_response_data */
-   .messageType = 0x03},
+   .messageType = 0x03 },
+  {/* plc4c_s7_read_write_s7_message_request */
+   .messageType = 0x01 },
   {/* plc4c_s7_read_write_s7_message_user_data */
-   .messageType = 0x07}
+   .messageType = 0x07 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/s7_parameter.c b/plc4c/generated-sources/s7/src/s7_parameter.c
index 3ea52fd..9e642ca 100644
--- a/plc4c/generated-sources/s7/src/s7_parameter.c
+++ b/plc4c/generated-sources/s7/src/s7_parameter.c
@@ -27,20 +27,20 @@
 // (The order is identical to the enum constants so we can use the
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_parameter_discriminator plc4c_s7_read_write_s7_parameter_discriminators[] = {
-  {/* plc4c_s7_read_write_s7_parameter_setup_communication */
-   .parameterType = 0xF0, .messageType = -1},
+  {/* plc4c_s7_read_write_s7_parameter_mode_transition */
+   .parameterType = 0x01, .messageType = 0x07 },
   {/* plc4c_s7_read_write_s7_parameter_read_var_request */
-   .parameterType = 0x04, .messageType = 0x01},
+   .parameterType = 0x04, .messageType = 0x01 },
   {/* plc4c_s7_read_write_s7_parameter_read_var_response */
-   .parameterType = 0x04, .messageType = 0x03},
+   .parameterType = 0x04, .messageType = 0x03 },
+  {/* plc4c_s7_read_write_s7_parameter_user_data */
+   .parameterType = 0x00, .messageType = 0x07 },
   {/* plc4c_s7_read_write_s7_parameter_write_var_request */
-   .parameterType = 0x05, .messageType = 0x01},
+   .parameterType = 0x05, .messageType = 0x01 },
+  {/* plc4c_s7_read_write_s7_parameter_setup_communication */
+   .parameterType = 0xF0, .messageType = -1 },
   {/* plc4c_s7_read_write_s7_parameter_write_var_response */
-   .parameterType = 0x05, .messageType = 0x03},
-  {/* plc4c_s7_read_write_s7_parameter_user_data */
-   .parameterType = 0x00, .messageType = 0x07},
-  {/* plc4c_s7_read_write_s7_parameter_mode_transition */
-   .parameterType = 0x01, .messageType = 0x07}
+   .parameterType = 0x05, .messageType = 0x03 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c b/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c
index 0345cab..f913c5a 100644
--- a/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c
+++ b/plc4c/generated-sources/s7/src/s7_parameter_user_data_item.c
@@ -28,7 +28,7 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_parameter_user_data_item_discriminator plc4c_s7_read_write_s7_parameter_user_data_item_discriminators[] = {
   {/* plc4c_s7_read_write_s7_parameter_user_data_item_cpu_functions */
-   .itemType = 0x12}
+   .itemType = 0x12 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/s7_payload.c b/plc4c/generated-sources/s7/src/s7_payload.c
index 681d056..02e3a49 100644
--- a/plc4c/generated-sources/s7/src/s7_payload.c
+++ b/plc4c/generated-sources/s7/src/s7_payload.c
@@ -27,14 +27,14 @@
 // (The order is identical to the enum constants so we can use the
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_payload_discriminator plc4c_s7_read_write_s7_payload_discriminators[] = {
-  {/* plc4c_s7_read_write_s7_payload_read_var_response */
-   .parameterParameterType = 0x04, .messageType = 0x03},
-  {/* plc4c_s7_read_write_s7_payload_write_var_request */
-   .parameterParameterType = 0x05, .messageType = 0x01},
-  {/* plc4c_s7_read_write_s7_payload_write_var_response */
-   .parameterParameterType = 0x05, .messageType = 0x03},
   {/* plc4c_s7_read_write_s7_payload_user_data */
-   .parameterParameterType = 0x00, .messageType = 0x07}
+   .parameterParameterType = 0x00, .messageType = 0x07 },
+  {/* plc4c_s7_read_write_s7_payload_write_var_response */
+   .parameterParameterType = 0x05, .messageType = 0x03 },
+  {/* plc4c_s7_read_write_s7_payload_write_var_request */
+   .parameterParameterType = 0x05, .messageType = 0x01 },
+  {/* plc4c_s7_read_write_s7_payload_read_var_response */
+   .parameterParameterType = 0x04, .messageType = 0x03 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c b/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
index 8b25429..d9f9b0d 100644
--- a/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
+++ b/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
@@ -27,42 +27,42 @@
 // (The order is identical to the enum constants so we can use the
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_payload_user_data_item_discriminator plc4c_s7_read_write_s7_payload_user_data_item_discriminators[] = {
-  {/* plc4c_s7_read_write_s7_payload_diagnostic_message */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x03, .dataLength = -1},
+  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_msg_subscription_response */
+   .cpuFunctionType = 0x08, .cpuSubfunction = 0x02, .dataLength = 0x00 },
   {/* plc4c_s7_read_write_s7_payload_alarm8 */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x05, .dataLength = -1},
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x05, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_alarm_sc */
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x13, .dataLength = -1 },
   {/* plc4c_s7_read_write_s7_payload_notify */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x06, .dataLength = -1},
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x06, .dataLength = -1 },
   {/* plc4c_s7_read_write_s7_payload_alarm_ack_ind */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x0c, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_alarm_sq */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x11, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_alarm_s */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x12, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_alarm_sc */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x13, .dataLength = -1},
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x0c, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_msg_subscription_sys_response */
+   .cpuFunctionType = 0x08, .cpuSubfunction = 0x02, .dataLength = 0x02 },
   {/* plc4c_s7_read_write_s7_payload_notify8 */
-   .cpuFunctionType = 0x00, .cpuSubfunction = 0x16, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_read_szl_request */
-   .cpuFunctionType = 0x04, .cpuSubfunction = 0x01, .dataLength = -1},
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x16, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_alarm_ack_response */
+   .cpuFunctionType = 0x08, .cpuSubfunction = 0x0b, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_diagnostic_message */
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x03, .dataLength = -1 },
   {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_read_szl_response */
-   .cpuFunctionType = 0x08, .cpuSubfunction = 0x01, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_msg_subscription */
-   .cpuFunctionType = 0x04, .cpuSubfunction = 0x02, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_msg_subscription_response */
-   .cpuFunctionType = 0x08, .cpuSubfunction = 0x02, .dataLength = 0x00},
-  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_msg_subscription_sys_response */
-   .cpuFunctionType = 0x08, .cpuSubfunction = 0x02, .dataLength = 0x02},
+   .cpuFunctionType = 0x08, .cpuSubfunction = 0x01, .dataLength = -1 },
   {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_msg_subscription_alarm_response */
-   .cpuFunctionType = 0x08, .cpuSubfunction = 0x02, .dataLength = 0x05},
-  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_alarm_ack */
-   .cpuFunctionType = 0x04, .cpuSubfunction = 0x0b, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_alarm_ack_response */
-   .cpuFunctionType = 0x08, .cpuSubfunction = 0x0b, .dataLength = -1},
-  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_alarm_query */
-   .cpuFunctionType = 0x04, .cpuSubfunction = 0x13, .dataLength = -1},
+   .cpuFunctionType = 0x08, .cpuSubfunction = 0x02, .dataLength = 0x05 },
+  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_msg_subscription */
+   .cpuFunctionType = 0x04, .cpuSubfunction = 0x02, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_alarm_sq */
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x11, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_alarm_s */
+   .cpuFunctionType = 0x00, .cpuSubfunction = 0x12, .dataLength = -1 },
   {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_alarm_query_response */
-   .cpuFunctionType = 0x08, .cpuSubfunction = 0x13, .dataLength = -1}
+   .cpuFunctionType = 0x08, .cpuSubfunction = 0x13, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_alarm_query */
+   .cpuFunctionType = 0x04, .cpuSubfunction = 0x13, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_read_szl_request */
+   .cpuFunctionType = 0x04, .cpuSubfunction = 0x01, .dataLength = -1 },
+  {/* plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_alarm_ack */
+   .cpuFunctionType = 0x04, .cpuSubfunction = 0x0b, .dataLength = -1 }
 
 };
 
@@ -80,34 +80,34 @@ plc4c_s7_read_write_s7_payload_user_data_item plc4c_s7_read_write_s7_payload_use
 
 
 // Constant values.
-static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ_const = 0x01;
-uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ() {
-  return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ_const;
-}
 static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_NUMBER_MESSAGE_OBJ_const = 0x01;
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_NUMBER_MESSAGE_OBJ() {
   return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_NUMBER_MESSAGE_OBJ_const;
 }
-static const uint16_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH_const = 28;
-uint16_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH() {
-  return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH_const;
-}
 static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_VARIABLE_SPEC_const = 0x12;
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_VARIABLE_SPEC() {
   return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_VARIABLE_SPEC_const;
 }
-static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID_const = 0x00;
-uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID() {
-  return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID_const;
+static const uint16_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH_const = 28;
+uint16_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH() {
+  return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_READ_SZL_RESPONSE_SZL_ITEM_LENGTH_const;
 }
 static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_FUNCTION_ID_const = 0x00;
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_FUNCTION_ID() {
   return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_FUNCTION_ID_const;
 }
+static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ_const = 0x01;
+uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ() {
+  return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_RESPONSE_NUMBER_MESSAGE_OBJ_const;
+}
 static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_LENGTH_const = 0x08;
 uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_LENGTH() {
   return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_LENGTH_const;
 }
+static const uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID_const = 0x00;
+uint8_t PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID() {
+  return PLC4C_S7_READ_WRITE_S7_PAYLOAD_USER_DATA_ITEM_CPU_FUNCTION_ALARM_QUERY_FUNCTION_ID_const;
+}
 
 // Parse function.
 plc4c_return_code plc4c_s7_read_write_s7_payload_user_data_item_parse(plc4c_spi_read_buffer* readBuffer, uint8_t cpuFunctionType, uint8_t cpuSubfunction, plc4c_s7_read_write_s7_payload_user_data_item** _message) {
diff --git a/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c b/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c
index 58388ba..26ce5d4 100644
--- a/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c
+++ b/plc4c/generated-sources/s7/src/s7_var_request_parameter_item.c
@@ -28,7 +28,7 @@
 // enum constant to directly access a given types discriminator values)
 const plc4c_s7_read_write_s7_var_request_parameter_item_discriminator plc4c_s7_read_write_s7_var_request_parameter_item_discriminators[] = {
   {/* plc4c_s7_read_write_s7_var_request_parameter_item_address */
-   .itemType = 0x12}
+   .itemType = 0x12 }
 
 };
 
diff --git a/plc4c/generated-sources/s7/src/transport_size.c b/plc4c/generated-sources/s7/src/transport_size.c
index b7758d1..831240b 100644
--- a/plc4c/generated-sources/s7/src/transport_size.c
+++ b/plc4c/generated-sources/s7/src/transport_size.c
@@ -23,7 +23,6 @@
 // Code generated by code-generation. DO NOT EDIT.
 
 #include "data_transport_size.h"
-#include "transport_size.h"
 
 // Create an empty NULL-struct
 static const plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_null_const;
diff --git a/plc4c/spi/src/system.c b/plc4c/spi/src/system.c
index abc1c15..a822bd1 100644
--- a/plc4c/spi/src/system.c
+++ b/plc4c/spi/src/system.c
@@ -26,7 +26,7 @@
 #include "plc4c/spi/types_private.h"
 
 // Uncomment to add printf spam at end of plc4c_system_create_connection()
-#define DEBUG_PLC4C_SYSTEM
+//#define DEBUG_PLC4C_SYSTEM
 
 #ifdef _WIN32
 #define strtok_r strtok_s