mbeckerle commented on code in PR #901:
URL: https://github.com/apache/daffodil/pull/901#discussion_r1073783098


##########
daffodil-core/src/main/scala/org/apache/daffodil/grammar/AlignedMixin.scala:
##########
@@ -138,7 +138,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
   // The separator is text in some encoding, might not be the same as this 
term's encoding, and
   // the alignment will be left where that text leaves it.
   //
-  private lazy val priorAlignmentApprox: AlignmentMultipleOf = 
LV('priorAlignmentApprox) {
+  lazy val priorAlignmentApprox: AlignmentMultipleOf = 
LV('priorAlignmentApprox) {

Review Comment:
   I don't think you want to expose these. I think you want to define a simpler 
concept. 
   
   I think you just want to call isKnownToBeAligned (already public). If false, 
you must generate a call to an operation that advances to achieve the required 
alignment (which is always 4 as I understand it.) 



##########
daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala:
##########
@@ -404,76 +542,117 @@ class CodeGeneratorState(private val root: ElementBase) {
     finalStructs += struct
   }
 
-  def addSimpleTypeStatements(initERDStatement: String, initSelfStatement: 
String, parseStatement: String, unparseStatement: String): Unit = {
-    if (initERDStatement.nonEmpty) structs.top.initERDStatements += 
initERDStatement
-    if (initSelfStatement.nonEmpty) structs.top.initSelfStatements += 
initSelfStatement
+  // Add C code to initialize, parse, and unparse a primitive value element
+  def addSimpleTypeStatements(initERDStatement: String, parseStatement: 
String, unparseStatement: String): Unit = {
+    if (initERDStatement.nonEmpty) {
+      if (hasChoice)
+        structs.top.initChoiceStatements += initERDStatement
+      else
+        structs.top.initERDStatements += initERDStatement
+    }
     if (parseStatement.nonEmpty) structs.top.parserStatements += parseStatement
     if (unparseStatement.nonEmpty) structs.top.unparserStatements += 
unparseStatement
   }
 
-  def addComplexTypeStatements(child: ElementBase): Unit = {
+  // Generate C code to initialize, parse, and unparse a child element
+  def addPerChildStatements(child: ElementBase): Unit = {
     val C = cStructName(child)
-    val e = child.name
-    val hasChoice = structs.top.initChoiceStatements.nonEmpty
-    val arraySize = if (child.occursCountKind == OccursCountKind.Fixed) 
child.maxOccurs else 0
+    val e = child.namedQName.local
 
+    // Generate a choice statement case if the child is in a choice element
+    val hasChoice = structs.top.initChoiceStatements.nonEmpty
     if (hasChoice) {
+      val position = child.position
       structs.top.initChoiceStatements ++= 
ChoiceBranchKeyCooker.convertConstant(
         child.choiceBranchKey, child, forUnparse = false).map { key => s"    
case $key:"}
-
-      val offset = child.position - 1
-      val initChoiceStatement = s"        instance->_choice = $offset;"
-      val parseStatement = s"    case $offset:"
-      val unparseStatement = s"    case $offset:"
-
-      structs.top.initChoiceStatements += initChoiceStatement
-      structs.top.parserStatements += parseStatement
-      structs.top.unparserStatements += unparseStatement
+      structs.top.initChoiceStatements += s"        instance->_choice = 
$position;"
+      structs.top.parserStatements += s"    case $position:"
+      structs.top.unparserStatements += s"    case $position:"
     }
+    val indent1 = if (hasChoice) "    " else ""
 
-    def addStatements(deref: String): Unit = {
-      val initChoiceStatement = s"        ${C}_initERD(&instance->$e$deref);"
-      val initERDStatement = s"    ${C}_initERD(&instance->$e$deref);"
-      val initSelfStatement = s"    ${C}_initSelf(&instance->$e$deref);"
-      val moreIndent = if (hasChoice) "    " else ""
-      val parseStatement =
-        s"""$moreIndent    ${C}_parseSelf(&instance->$e$deref, pstate);
-           |$moreIndent    if (pstate->error) return;""".stripMargin
-      val unparseStatement =
-        s"""$moreIndent    ${C}_unparseSelf(&instance->$e$deref, ustate);
-           |$moreIndent    if (ustate->error) return;""".stripMargin
+    // Add an array if the child occurs multiple times
+    val hasArray = arrayMaxOccurs(child) > 0
+    val deref = if (hasArray) "[i]" else ""
+    val indent2 = if (hasArray) "    " else ""
+    if (hasArray) pushArray(child)
 
+    // Generate statements to initialize, parse, and unparse the child
+    Runtime2CodeGenerator.generateCode(child.enclosedElement, this)
+    if (!child.isSimpleType) {
       if (hasChoice)
-        structs.top.initChoiceStatements += initChoiceStatement
+        structs.top.initChoiceStatements += s"$indent2        
${C}_initERD(&instance->$e$deref, (InfosetBase *)instance);"
       else
-        structs.top.initERDStatements += initERDStatement
-      structs.top.initSelfStatements += initSelfStatement
-      structs.top.parserStatements += parseStatement
-      structs.top.unparserStatements += unparseStatement
+        structs.top.initERDStatements += s"$indent2    
${C}_initERD(&instance->$e$deref, (InfosetBase *)instance);"
+      structs.top.parserStatements +=
+        s"""$indent1$indent2    ${C}_parseSelf(&instance->$e$deref, pstate);
+           |$indent1$indent2    if (pstate->error) return;""".stripMargin
+      structs.top.unparserStatements +=
+        s"""$indent1$indent2    ${C}_unparseSelf(&instance->$e$deref, ustate);
+           |$indent1$indent2    if (ustate->error) return;""".stripMargin
     }
-    if (arraySize > 0)
-      for (i <- 0 until arraySize)
-        addStatements(s"[$i]")
-    else
-      addStatements("")
 
-    if (hasChoice) {
-      val initChoiceStatement = s"        break;"
-      val parseStatement = s"        break;"
-      val unparseStatement = s"        break;"
+    // Generate statements to align the next element
+    val mustAlign = child.endingAlignmentApprox.nBits > 
child.priorAlignmentApprox.nBits

Review Comment:
   I'd like to suggest that Daffodil's schema compiler should provide an 
available option which is to require all alignment to be static except for 
alignment after something that is truly variable length. Runtime 2 would then 
always require this to be enabled. But I think this would be popular for any 
schema author. 
   
   For example: 
   
   this would not be allowed:
   ```
   <sequence dfdl:alignment="4">
      <element dfdl:alignment="4" .fixed length element of length 4.../>
      <element dfdl:alignment="8" .fixed length element of length 8 ../>
   </sequence>
   ```
   because the 2nd element may or may not require 4 bytes of alignment fill 
depending on the actual alignment of the starting sequence. This is a complete 
pain in the neck because you can't even tell the length of this structure 
without knowing where it starts despite the fact that it is all fixed length 
stuff.  (This is called the "interior aligment problem" lots of things that 
appear fixed length become variable length.)
   
   I think we should have an option where we just say no to this. We have a 
property dfdlx:alignmentKind. Current values are 'manual' (no alignment regions 
ever inserted) or 'automatic' (everything including interior alignment 
allowed). 
   
   I'm suggesting we add another enum value for this of 'onlyForVariableLength' 
which says alignment must be achieved manually by the schema author (using 
things like leading/trailing skip properties) except after variable-length 
elements.
   
   Daffodil's core isKnownToBeAligned is false for the 2nd element in the 
example above even if it is true for the surrounding sequence. 
   
   So when dfdl:alignmentKind is 'onlyForVariableLength' we would make it an 
SDE if any element is not knownToBeAligned unless it is preceded by something 
variable length. The SDE could require the author to increase the alignment of 
the surrounding sequence to 8, and then they could fix an SDE on the 2nd 
element by adding a leading skip  (or trailing to the prior).



##########
daffodil-runtime2/src/test/resources/org/apache/daffodil/runtime2/variablelen.dfdl.xsd:
##########
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+
+<xs:schema
+ elementFormDefault="qualified"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/";
+ xmlns:xs="http://www.w3.org/2001/XMLSchema";>
+
+  <!-- Binary data format bindings -->
+
+  <xs:include 
schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+  <xs:annotation>
+    <xs:appinfo source="http://www.ogf.org/dfdl/";>
+      <dfdl:format
+        ref="GeneralFormat"
+        binaryBooleanFalseRep="0"
+        binaryBooleanTrueRep="1"
+        fillByte="%NUL;"
+        prefixIncludesPrefixLength="no"
+        representation="binary"/>
+    </xs:appinfo>
+  </xs:annotation>
+
+  <!-- Types for testing -->
+
+  <!-- Unsuitable since variable length array must allow 0 to 16 numbers -->

Review Comment:
   What do you mean  by unsuitable?  For what is it unsuitable?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to