public String toVariableParseExpression(TypeDefinition baseType, Field field, VariableLiteral variableLiteral, List<Argument> parserArguments) {
        Tracer tracer = Tracer.start("toVariableParseExpression");
        if ("CAST".equals(variableLiteral.getName())) {
            return toCastVariableParseExpression(baseType, field, variableLiteral, parserArguments, tracer);
        }
        if ("STATIC_CALL".equals(variableLiteral.getName())) {
            return toStaticCallVariableParseExpression(baseType, field, variableLiteral, parserArguments, tracer);
        }
        if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) {
            return toUpperCaseVariableParseExpression(baseType, field, variableLiteral, parserArguments, tracer);
        } else if ("readBuffer".equals(variableLiteral.getName())) {
            return toReadBufferVariableParseExpression(baseType, variableLiteral, tracer);
        } else if ("writeBuffer".equals(variableLiteral.getName())) {
            return toWriteBufferVariableParseExpression(baseType, variableLiteral, tracer);
        } else if ("_type".equals(variableLiteral.getName())) {
            return toTypeVariableParseExpression(field, variableLiteral, tracer);
        }

        final String name = variableLiteral.getName();

        // In case of DataIo types, we'll just check the arguments.
        if (baseType instanceof DataIoTypeDefinition) {
            if (baseType.getParserArguments().isPresent()) {
                for (Argument parserArgument : baseType.getParserArguments().get()) {
                    if (parserArgument.getName().equals(name)) {
                        return name;
                    }
                }
            }
        }

        // If the literal is referencing a constant field, we need to reference the constant variable instead.
        final Optional<NamedField> namedField = ((ComplexTypeDefinition) baseType).getNamedFieldByName(name);
        if(namedField.isPresent() && namedField.get() instanceof ConstField) {
            return getCTypeName(baseType.getName()).toUpperCase() + "_" + camelCaseToSnakeCase(name).toUpperCase() + "()";
        }

        // Try to find the type of the addressed property.
        Optional<TypeReference> propertyTypeOptional =
            ((ComplexTypeDefinition) baseType).getTypeReferenceForProperty(name);

        // If we couldn't find the type in the parent, try checking in the sub-type, that contains the current field.
        if (propertyTypeOptional.isEmpty() && baseType.isComplexTypeDefinition()) {
            if(baseType.asComplexTypeDefinition().orElseThrow().getSwitchField().isPresent()) {
                final SwitchField switchField = baseType.asComplexTypeDefinition().orElseThrow().getSwitchField().get();
                // Search for a case containing the current field
                for (DiscriminatedComplexTypeDefinition aCase : switchField.getCases()) {
                    if(aCase.getFields().stream().anyMatch(field1 -> field1 == field)) {
                        // Search this case for the referenced field.
                        final Optional<Field> referencedField = aCase.getFields().stream().filter(field1 -> field1.isNamedField() && field1.asNamedField().orElseThrow().getName().equals(name)).findFirst();
                        if(referencedField.isPresent()) {
                            propertyTypeOptional = Optional.of(referencedField.get().asTypedField().orElseThrow().getType());
                            break;
                        }
                    }
                }
            }
        }

        // If we couldn't find the type, we didn't find the property.
        if (propertyTypeOptional.isEmpty()) {
            final List<Argument> arguments = baseType.getAllParserArguments().orElse(Collections.emptyList());
            for (Argument argument : arguments) {
                if (argument.getName().equals(name)) {
                    propertyTypeOptional = Optional.of(argument.getType());
                }
            }
            if (propertyTypeOptional.isEmpty()) {
                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 subtype to access.
        if (propertyType instanceof SimpleTypeReference) {
            if (variableLiteral.getChild().isPresent()) {
                throw new FreemarkerException("Simple property '" + name + "' doesn't have child properties.");
            }
            return name;
        }

        if (propertyType instanceof ArrayTypeReference) {
            if (variableLiteral.getChild().isPresent()) {
                throw new FreemarkerException("array property '" + name + "' doesn't have child properties.");
            }
            return name;
        }

        // If it references a complex, type we need to get that type's definition first.
        final TypeDefinition propertyTypeDefinition = getTypeDefinitions().get(((NonSimpleTypeReference) propertyType).getName());
        // If we're not accessing any child property, no need to handle anything special.
        if (variableLiteral.getChild().isEmpty()) {
            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) {
            final Optional<DiscriminatorField> discriminatorFieldOptional = ((ComplexTypeDefinition) propertyTypeDefinition).getFields().stream().filter(
                curField -> curField instanceof DiscriminatorField).map(curField -> (DiscriminatorField) curField).filter(
                discriminatorField -> discriminatorField.getName().equals(variableLiteral.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)." + variableLiteral.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) {
            return getCTypeName(propertyTypeDefinition.getName()) +
                "_get_" + camelCaseToSnakeCase(variableLiteral.getChild().get().getName()) +
                "(" + variableLiteral.getName() + ")";
        }
        // Else ... generate a simple access path.
        StringBuilder sb = new StringBuilder(variableLiteral.getName());
        if (variableLiteral.getChild().isPresent()) {
            sb.append(".");
            appendVariableExpressionRest(sb, baseType, variableLiteral.getChild().get());
        }
        return sb.toString();
    }
Ge the type-size suffix in case of simple types.

@param field the field we want to get the type-size for
@return a type-size string for the given field or an empty string if this does not apply
code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java