mbeckerle commented on a change in pull request #488:
URL: https://github.com/apache/incubator-daffodil/pull/488#discussion_r573787898



##########
File path: daffodil-runtime2/src/main/resources/c/libcli/daffodil_argp.c
##########
@@ -62,6 +63,9 @@ static const struct argp parse_argp = {
     parse_handler,  // function to get these CLI options
     parse_args_doc, // short usage documentation
     parse_doc,      // long help documentation
+    0,              // children

Review comment:
       What are children, help filter, and domain? Expand comments to explain 
what these are actually for. 

##########
File path: daffodil-runtime2/src/main/resources/examples/ex_nums.c
##########
@@ -80,182 +71,133 @@ static const ptrdiff_t array_offsets[6] = {
 };
 
 static const ERD *array_childrenERDs[6] = {
-    &be_int16_array_ex_nums__ERD,
-    &be_int16_array_ex_nums__ERD,
-    &be_int16_array_ex_nums__ERD,
-    &be_float_array_ex_nums__ERD,
-    &be_float_array_ex_nums__ERD,
-    &be_float_array_ex_nums__ERD
+    &be_int16_array_ex_nums_ERD,

Review comment:
       
   For these arrays of 3 int16 or 3 float, why are you storing the ERD 
redundantly?
   
   An array should have a single ERD pointer for all the elements. This of 
course requires special case treatment of arrays vs. the way scalars are 
handled. 

##########
File path: daffodil-runtime2/src/main/resources/examples/ex_nums.c
##########
@@ -568,6 +467,7 @@ array_unparseSelf(const array *instance, UState *ustate)
 static void
 bigEndian_initSelf(bigEndian *instance)

Review comment:
       Why does the byte order matter here?

##########
File path: daffodil-runtime2/src/main/resources/examples/NestedUnion.c
##########
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ */
+
+#include "NestedUnion.h"
+#include "parsers.h"    // for parse_be_double, parse_be_float, 
parse_be_int16, parse_be_int32, parse_be_int64, parse_be_int8, parse_be_uint16, 
parse_be_uint32, parse_be_uint64, parse_be_uint8, parse_le_double, 
parse_le_float, parse_le_int16, parse_le_int32, parse_le_int64, parse_le_int8, 
parse_le_uint16, parse_le_uint32, parse_le_uint64, parse_le_uint8
+#include "unparsers.h"  // for unparse_be_double, unparse_be_float, 
unparse_be_int16, unparse_be_int32, unparse_be_int64, unparse_be_int8, 
unparse_be_uint16, unparse_be_uint32, unparse_be_uint64, unparse_be_uint8, 
unparse_le_double, unparse_le_float, unparse_le_int16, unparse_le_int32, 
unparse_le_int64, unparse_le_int8, unparse_le_uint16, unparse_le_uint32, 
unparse_le_uint64, unparse_le_uint8
+#include <math.h>       // for NAN
+#include <stdbool.h>    // for bool, false, true
+#include <stddef.h>     // for NULL, size_t
+
+// Prototypes needed for compilation
+
+static void foo_initSelf(foo *instance);
+static void foo_parseSelf(foo *instance, PState *pstate);
+static void foo_unparseSelf(const foo *instance, UState *ustate);
+static void bar_initSelf(bar *instance);
+static void bar_parseSelf(bar *instance, PState *pstate);
+static void bar_unparseSelf(const bar *instance, UState *ustate);
+static void data_initSelf(data *instance);
+static bool data_initChoice(data *instance, const NestedUnion *rootElement);
+static void data_parseSelf(data *instance, PState *pstate);
+static void data_unparseSelf(const data *instance, UState *ustate);
+static void NestedUnion_initSelf(NestedUnion *instance);
+static void NestedUnion_parseSelf(NestedUnion *instance, PState *pstate);
+static void NestedUnion_unparseSelf(const NestedUnion *instance, UState 
*ustate);
+
+// Metadata singletons
+
+static const ERD tag_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "tag", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD _choice_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "_choice", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    CHOICE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD a_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "a", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD b_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "b", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD c_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "c", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const foo foo_compute_offsets;
+
+static const size_t foo_offsets[3] = {
+    (const char *)&foo_compute_offsets.a - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.b - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.c - (const char *)&foo_compute_offsets
+};
+
+static const ERD *foo_childrenERDs[3] = {
+    &a_FooType_ERD,
+    &b_FooType_ERD,
+    &c_FooType_ERD
+};
+
+static const ERD foo_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "foo", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    foo_offsets, // offsets
+    foo_childrenERDs, // childrenERDs
+    (ERDInitSelf)&foo_initSelf, // initSelf
+    (ERDParseSelf)&foo_parseSelf, // parseSelf
+    (ERDUnparseSelf)&foo_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const ERD x_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "x", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD y_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "y", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD z_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "z", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const bar bar_compute_offsets;
+
+static const size_t bar_offsets[3] = {
+    (const char *)&bar_compute_offsets.x - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.y - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.z - (const char *)&bar_compute_offsets
+};
+
+static const ERD *bar_childrenERDs[3] = {
+    &x_BarType_ERD,
+    &y_BarType_ERD,
+    &z_BarType_ERD
+};
+
+static const ERD bar_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "bar", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    bar_offsets, // offsets
+    bar_childrenERDs, // childrenERDs
+    (ERDInitSelf)&bar_initSelf, // initSelf
+    (ERDParseSelf)&bar_parseSelf, // parseSelf
+    (ERDUnparseSelf)&bar_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const data data_compute_offsets;
+
+static const size_t data_offsets[3] = {
+    (const char *)&data_compute_offsets._choice - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.foo - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.bar - (const char 
*)&data_compute_offsets
+};
+
+static const ERD *data_childrenERDs[3] = {
+    &_choice_data_NestedUnionType_ERD,
+    &foo_data_NestedUnionType_ERD,
+    &bar_data_NestedUnionType_ERD
+};
+
+static const ERD data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "data", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    2, // numChildren
+    data_offsets, // offsets
+    data_childrenERDs, // childrenERDs
+    (ERDInitSelf)&data_initSelf, // initSelf
+    (ERDParseSelf)&data_parseSelf, // parseSelf
+    (ERDUnparseSelf)&data_unparseSelf, // unparseSelf
+    (ERDInitChoice)&data_initChoice // initChoice
+};
+
+static const NestedUnion NestedUnion_compute_offsets;
+
+static const size_t NestedUnion_offsets[2] = {
+    (const char *)&NestedUnion_compute_offsets.tag - (const char 
*)&NestedUnion_compute_offsets,
+    (const char *)&NestedUnion_compute_offsets.data - (const char 
*)&NestedUnion_compute_offsets
+};
+
+static const ERD *NestedUnion_childrenERDs[2] = {
+    &tag_NestedUnionType_ERD,
+    &data_NestedUnionType_ERD
+};
+
+static const ERD NestedUnion_ERD = {
+    {
+        "idl", // namedQName.prefix
+        "NestedUnion", // namedQName.local
+        "urn:idl:1.0", // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    2, // numChildren
+    NestedUnion_offsets, // offsets
+    NestedUnion_childrenERDs, // childrenERDs
+    (ERDInitSelf)&NestedUnion_initSelf, // initSelf
+    (ERDParseSelf)&NestedUnion_parseSelf, // parseSelf
+    (ERDUnparseSelf)&NestedUnion_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+// Return a root element to be used for parsing or unparsing
+
+InfosetBase *
+rootElement(void)
+{
+    static bool initialized;
+    static NestedUnion root;
+    if (!initialized)
+    {
+        NestedUnion_initSelf(&root);
+        initialized = true;
+    }
+    return &root._base;
+}
+
+// Methods to initialize, parse, and unparse infoset nodes
+
+static void
+foo_initSelf(foo *instance)
+{
+    instance->_base.erd = &foo_data_NestedUnionType_ERD;
+    instance->a = 0xCCCCCCCC;
+    instance->b = 0xCCCCCCCC;
+    instance->c = 0xCCCCCCCC;
+}
+
+static void
+foo_parseSelf(foo *instance, PState *pstate)
+{
+    parse_be_int32(&instance->a, pstate);
+    parse_be_int32(&instance->b, pstate);
+    parse_be_int32(&instance->c, pstate);
+}
+
+static void
+foo_unparseSelf(const foo *instance, UState *ustate)
+{
+    unparse_be_int32(instance->a, ustate);
+    unparse_be_int32(instance->b, ustate);
+    unparse_be_int32(instance->c, ustate);
+}
+
+static void
+bar_initSelf(bar *instance)
+{
+    instance->_base.erd = &bar_data_NestedUnionType_ERD;
+    instance->x = NAN;
+    instance->y = NAN;
+    instance->z = NAN;
+}
+
+static void
+bar_parseSelf(bar *instance, PState *pstate)
+{
+    parse_be_double(&instance->x, pstate);
+    parse_be_double(&instance->y, pstate);
+    parse_be_double(&instance->z, pstate);
+}
+
+static void
+bar_unparseSelf(const bar *instance, UState *ustate)
+{
+    unparse_be_double(instance->x, ustate);
+    unparse_be_double(instance->y, ustate);
+    unparse_be_double(instance->z, ustate);
+}
+
+static void
+data_initSelf(data *instance)
+{
+    instance->_base.erd = &data_NestedUnionType_ERD;
+    instance->_choice = NO_CHOICE;
+    foo_initSelf(&instance->foo);
+    bar_initSelf(&instance->bar);
+}
+
+static bool
+data_initChoice(data *instance, const NestedUnion *rootElement)
+{
+    int64_t key = rootElement->tag;
+    switch (key)
+    {
+    case 1:
+    case 2:
+        instance->_choice = 0;
+        break;
+    case 3:
+    case 4:
+        instance->_choice = 1;
+        break;
+    default:
+        instance->_choice = NO_CHOICE;
+        break;
+    }
+
+    if (instance->_choice != NO_CHOICE)
+    {
+        const size_t choice = instance->_choice + 1; // skip the _choice field
+        const size_t offset = instance->_base.erd->offsets[choice];
+        const ERD *  childERD = instance->_base.erd->childrenERDs[choice];
+        InfosetBase *childNode = (InfosetBase *)((const char *)instance + 
offset);
+        childNode->erd = childERD;
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+static void
+data_parseSelf(data *instance, PState *pstate)
+{
+    instance->_base.erd->initChoice(&instance->_base, rootElement());
+    switch (instance->_choice)
+    {
+    case 0:
+        foo_parseSelf(&instance->foo, pstate);
+        break;
+    case 1:
+        bar_parseSelf(&instance->bar, pstate);
+        break;
+    default:
+        pstate->error_msg = "node's _choice field was not initialized during 
parsing";

Review comment:
       We should distinguish this kind of error. This isn't an error a DFDL 
schema author should be able to cause. If this error occurs it's a bug in the 
C-code-generator causing it, as an internal invariant - that _choice gets set 
when parsing, has been violated. 

##########
File path: daffodil-runtime2/src/main/resources/examples/ex_nums.c
##########
@@ -660,10 +559,10 @@ littleEndian_unparseSelf(const littleEndian *instance, 
UState *ustate)
 static void
 ex_nums_initSelf(ex_nums *instance)
 {
+    instance->_base.erd = &ex_nums_ERD;
     array_initSelf(&instance->array);
     bigEndian_initSelf(&instance->bigEndian);
     littleEndian_initSelf(&instance->littleEndian);
-    instance->_base.erd = &ex_nums__ERD;
 }
 

Review comment:
       They are hand-crafted examples of what the generated C code should be. 
They are almost documentation, except we want them compiled so we know if our 
generation goals lead to something similar. 
   
   I think src/test/c/handCrafted or something makes sense, because we do want 
examples of this that can be tested against the generated code to be sure they 
are work-alike. 
   
   
   
   

##########
File path: daffodil-runtime2/src/main/resources/examples/ex_nums.c
##########
@@ -80,182 +71,133 @@ static const ptrdiff_t array_offsets[6] = {
 };
 
 static const ERD *array_childrenERDs[6] = {
-    &be_int16_array_ex_nums__ERD,
-    &be_int16_array_ex_nums__ERD,
-    &be_int16_array_ex_nums__ERD,
-    &be_float_array_ex_nums__ERD,
-    &be_float_array_ex_nums__ERD,
-    &be_float_array_ex_nums__ERD
+    &be_int16_array_ex_nums_ERD,
+    &be_int16_array_ex_nums_ERD,
+    &be_int16_array_ex_nums_ERD,
+    &be_float_array_ex_nums_ERD,
+    &be_float_array_ex_nums_ERD,
+    &be_float_array_ex_nums_ERD
 };
 
-static const ERD array_ex_nums__ERD = {
+static const ERD array_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "array", // namedQName.local
         NULL, // namedQName.ns
     },
-    COMPLEX,                         // typeCode
-    6,                               // numChildren
-    array_offsets,                      // offsets
-    array_childrenERDs,                 // childrenERDs
-    (ERDInitSelf)&array_initSelf,       // initSelf
-    (ERDParseSelf)&array_parseSelf,     // parseSelf
+    COMPLEX, // typeCode
+    6, // numChildren

Review comment:
       ERD of an array element is metadata, and so needs a minOccurs and 
maxOccurs, where minOccurs is unsigned and maxOccurs is signed with -1 meaning 
"unbounded". The actual number of children in an array instance has to be 
stored in the array instance object.  An array node has to be a different kind 
of infoset node with a place for this number of actual children to be stored. 
Probably all ERDs should just get minOccurs and maxOccurs and a scalar is just 
one with 1, 1 as those values, an optional element is 0,1, and an array is all 
other legal combinations. N, -1 and N, M with N<=M.  A restriction that 
minOccurs is 0, 1, or equal to maxOccurs (which is not -1) is acceptable.  A 
restriction that maxOccurs is 1, -1, or equal to minOccurs is also fine (means 
variable-length arrays always have unbounded number of elements.) 

##########
File path: daffodil-runtime2/src/main/resources/examples/NestedUnion.c
##########
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ */
+
+#include "NestedUnion.h"
+#include "parsers.h"    // for parse_be_double, parse_be_float, 
parse_be_int16, parse_be_int32, parse_be_int64, parse_be_int8, parse_be_uint16, 
parse_be_uint32, parse_be_uint64, parse_be_uint8, parse_le_double, 
parse_le_float, parse_le_int16, parse_le_int32, parse_le_int64, parse_le_int8, 
parse_le_uint16, parse_le_uint32, parse_le_uint64, parse_le_uint8
+#include "unparsers.h"  // for unparse_be_double, unparse_be_float, 
unparse_be_int16, unparse_be_int32, unparse_be_int64, unparse_be_int8, 
unparse_be_uint16, unparse_be_uint32, unparse_be_uint64, unparse_be_uint8, 
unparse_le_double, unparse_le_float, unparse_le_int16, unparse_le_int32, 
unparse_le_int64, unparse_le_int8, unparse_le_uint16, unparse_le_uint32, 
unparse_le_uint64, unparse_le_uint8
+#include <math.h>       // for NAN
+#include <stdbool.h>    // for bool, false, true
+#include <stddef.h>     // for NULL, size_t
+
+// Prototypes needed for compilation
+
+static void foo_initSelf(foo *instance);
+static void foo_parseSelf(foo *instance, PState *pstate);
+static void foo_unparseSelf(const foo *instance, UState *ustate);
+static void bar_initSelf(bar *instance);
+static void bar_parseSelf(bar *instance, PState *pstate);
+static void bar_unparseSelf(const bar *instance, UState *ustate);
+static void data_initSelf(data *instance);
+static bool data_initChoice(data *instance, const NestedUnion *rootElement);
+static void data_parseSelf(data *instance, PState *pstate);
+static void data_unparseSelf(const data *instance, UState *ustate);
+static void NestedUnion_initSelf(NestedUnion *instance);
+static void NestedUnion_parseSelf(NestedUnion *instance, PState *pstate);
+static void NestedUnion_unparseSelf(const NestedUnion *instance, UState 
*ustate);
+
+// Metadata singletons
+
+static const ERD tag_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "tag", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD _choice_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "_choice", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    CHOICE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD a_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "a", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD b_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "b", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD c_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "c", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const foo foo_compute_offsets;
+
+static const size_t foo_offsets[3] = {
+    (const char *)&foo_compute_offsets.a - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.b - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.c - (const char *)&foo_compute_offsets
+};
+
+static const ERD *foo_childrenERDs[3] = {
+    &a_FooType_ERD,
+    &b_FooType_ERD,
+    &c_FooType_ERD
+};
+
+static const ERD foo_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "foo", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    foo_offsets, // offsets
+    foo_childrenERDs, // childrenERDs
+    (ERDInitSelf)&foo_initSelf, // initSelf
+    (ERDParseSelf)&foo_parseSelf, // parseSelf
+    (ERDUnparseSelf)&foo_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const ERD x_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "x", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD y_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "y", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD z_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "z", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const bar bar_compute_offsets;
+
+static const size_t bar_offsets[3] = {
+    (const char *)&bar_compute_offsets.x - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.y - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.z - (const char *)&bar_compute_offsets
+};
+
+static const ERD *bar_childrenERDs[3] = {
+    &x_BarType_ERD,
+    &y_BarType_ERD,
+    &z_BarType_ERD
+};
+
+static const ERD bar_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "bar", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    bar_offsets, // offsets
+    bar_childrenERDs, // childrenERDs
+    (ERDInitSelf)&bar_initSelf, // initSelf
+    (ERDParseSelf)&bar_parseSelf, // parseSelf
+    (ERDUnparseSelf)&bar_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const data data_compute_offsets;
+
+static const size_t data_offsets[3] = {
+    (const char *)&data_compute_offsets._choice - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.foo - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.bar - (const char 
*)&data_compute_offsets
+};
+
+static const ERD *data_childrenERDs[3] = {
+    &_choice_data_NestedUnionType_ERD,
+    &foo_data_NestedUnionType_ERD,
+    &bar_data_NestedUnionType_ERD
+};
+
+static const ERD data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "data", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    2, // numChildren
+    data_offsets, // offsets
+    data_childrenERDs, // childrenERDs
+    (ERDInitSelf)&data_initSelf, // initSelf
+    (ERDParseSelf)&data_parseSelf, // parseSelf
+    (ERDUnparseSelf)&data_unparseSelf, // unparseSelf
+    (ERDInitChoice)&data_initChoice // initChoice
+};
+
+static const NestedUnion NestedUnion_compute_offsets;
+
+static const size_t NestedUnion_offsets[2] = {
+    (const char *)&NestedUnion_compute_offsets.tag - (const char 
*)&NestedUnion_compute_offsets,
+    (const char *)&NestedUnion_compute_offsets.data - (const char 
*)&NestedUnion_compute_offsets
+};
+
+static const ERD *NestedUnion_childrenERDs[2] = {
+    &tag_NestedUnionType_ERD,
+    &data_NestedUnionType_ERD
+};
+
+static const ERD NestedUnion_ERD = {
+    {
+        "idl", // namedQName.prefix
+        "NestedUnion", // namedQName.local
+        "urn:idl:1.0", // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    2, // numChildren
+    NestedUnion_offsets, // offsets
+    NestedUnion_childrenERDs, // childrenERDs
+    (ERDInitSelf)&NestedUnion_initSelf, // initSelf
+    (ERDParseSelf)&NestedUnion_parseSelf, // parseSelf
+    (ERDUnparseSelf)&NestedUnion_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+// Return a root element to be used for parsing or unparsing
+
+InfosetBase *
+rootElement(void)
+{
+    static bool initialized;
+    static NestedUnion root;
+    if (!initialized)
+    {
+        NestedUnion_initSelf(&root);
+        initialized = true;
+    }
+    return &root._base;
+}
+
+// Methods to initialize, parse, and unparse infoset nodes
+
+static void
+foo_initSelf(foo *instance)
+{
+    instance->_base.erd = &foo_data_NestedUnionType_ERD;
+    instance->a = 0xCCCCCCCC;
+    instance->b = 0xCCCCCCCC;
+    instance->c = 0xCCCCCCCC;
+}
+
+static void
+foo_parseSelf(foo *instance, PState *pstate)
+{
+    parse_be_int32(&instance->a, pstate);
+    parse_be_int32(&instance->b, pstate);
+    parse_be_int32(&instance->c, pstate);
+}
+
+static void
+foo_unparseSelf(const foo *instance, UState *ustate)
+{
+    unparse_be_int32(instance->a, ustate);
+    unparse_be_int32(instance->b, ustate);
+    unparse_be_int32(instance->c, ustate);
+}
+
+static void
+bar_initSelf(bar *instance)
+{
+    instance->_base.erd = &bar_data_NestedUnionType_ERD;
+    instance->x = NAN;
+    instance->y = NAN;
+    instance->z = NAN;
+}
+
+static void
+bar_parseSelf(bar *instance, PState *pstate)
+{
+    parse_be_double(&instance->x, pstate);
+    parse_be_double(&instance->y, pstate);
+    parse_be_double(&instance->z, pstate);
+}
+
+static void
+bar_unparseSelf(const bar *instance, UState *ustate)
+{
+    unparse_be_double(instance->x, ustate);
+    unparse_be_double(instance->y, ustate);
+    unparse_be_double(instance->z, ustate);
+}
+
+static void
+data_initSelf(data *instance)
+{
+    instance->_base.erd = &data_NestedUnionType_ERD;
+    instance->_choice = NO_CHOICE;
+    foo_initSelf(&instance->foo);
+    bar_initSelf(&instance->bar);
+}
+
+static bool
+data_initChoice(data *instance, const NestedUnion *rootElement)
+{
+    int64_t key = rootElement->tag;
+    switch (key)
+    {
+    case 1:
+    case 2:
+        instance->_choice = 0;
+        break;
+    case 3:
+    case 4:
+        instance->_choice = 1;
+        break;
+    default:
+        instance->_choice = NO_CHOICE;
+        break;
+    }
+
+    if (instance->_choice != NO_CHOICE)
+    {
+        const size_t choice = instance->_choice + 1; // skip the _choice field
+        const size_t offset = instance->_base.erd->offsets[choice];

Review comment:
       Where does this index value named choice come from that allows you to 
index into the offsets & ERDs of children? I was assuming this would have to be 
passed into this routine. 

##########
File path: daffodil-runtime2/src/main/resources/c/libruntime/infoset.h
##########
@@ -38,6 +33,8 @@ typedef struct VisitEventHandler  VisitEventHandler;
 typedef void (*ERDInitSelf)(InfosetBase *infoNode);
 typedef void (*ERDParseSelf)(InfosetBase *infoNode, PState *pstate);
 typedef void (*ERDUnparseSelf)(const InfosetBase *infoNode, UState *ustate);
+typedef bool (*ERDInitChoice)(const InfosetBase *infoNode,

Review comment:
       I think you should rename this to InitChoiceRD. A choice needs a runtime 
data structure, but it's not an "E"RD, it's a "C"RD. 

##########
File path: 
daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala
##########
@@ -105,41 +129,178 @@ class CodeGeneratorState {
     qnameInit
   }
 
+  /**
+   * We want to convert a choiceDispatchKey expression into C struct dot
+   * notation (rootElement->[subElement.field]) which will access the C
+   * struct field containing the choiceDispatchKey's runtime value.
+   *
+   * We make some assumptions to make generating the dot notation easier:
+   * - the expression starts with '{xs:string( and ends with )}'
+   * - the expression returns the value of a previous element without
+   *   changing the value in any way (except converting it to xs:string)
+   * - both the expression and the C code use only local names (for now...)
+   * - we can map the context node's path to a Unix-like slash path
+   * - all dpath operations look like Unix-like relative paths (../tag)
+   * - we can normalize the new path and convert it to C struct dot notation
+   * - we can store the accessed value in an int64_t local variable safely
+   */
+  private def choiceDispatchField(context: ElementBase): String = {
+    // We want to use SchemaComponent.scPath but it's private so duplicate it 
here (for now...)
+    def scPath(sc: SchemaComponent): Seq[SchemaComponent] = 
sc.optLexicalParent.map { scPath }.getOrElse(Nil) :+ sc
+    val localNames = scPath(context).map {
+      case er: AbstractElementRef => er.refQName.local
+      case e: ElementBase => e.namedQName.local
+      case ed: GlobalElementDecl => ed.namedQName.local
+      case _ => ""
+    }
+    val absoluteSlashPath = localNames.mkString("/")
+    val dispatchSlashPath = context.complexType.modelGroup match {
+      case choice: Choice if choice.isDirectDispatch =>
+        val expr = choice.choiceDispatchKeyEv.expr.toBriefXML()
+        val before = "'{xs:string("
+        val after = ")}'"
+        val relativePath = if (expr.startsWith(before) && expr.endsWith(after))
+          expr.substring(before.length, expr.length - after.length) else expr
+        val normalizedURI = new URI(absoluteSlashPath + "/" + 
relativePath).normalize
+        normalizedURI.getPath.substring(1)
+      case _ => ""
+    }
+    // Strip namespace prefixes since C code uses only local names (for now...)
+    val localDispatchSlashPath = dispatchSlashPath.replaceAll("/[^:]+:", "/")
+    val res = localDispatchSlashPath.replace('/', '.')
+    res
+  }

Review comment:
       Yes, the right way to do this eventually is have DPath generate C-code 
from expressions. 

##########
File path: 
daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala
##########
@@ -105,41 +129,178 @@ class CodeGeneratorState {
     qnameInit
   }
 
+  /**
+   * We want to convert a choiceDispatchKey expression into C struct dot
+   * notation (rootElement->[subElement.field]) which will access the C
+   * struct field containing the choiceDispatchKey's runtime value.
+   *
+   * We make some assumptions to make generating the dot notation easier:
+   * - the expression starts with '{xs:string( and ends with )}'
+   * - the expression returns the value of a previous element without
+   *   changing the value in any way (except converting it to xs:string)
+   * - both the expression and the C code use only local names (for now...)
+   * - we can map the context node's path to a Unix-like slash path
+   * - all dpath operations look like Unix-like relative paths (../tag)
+   * - we can normalize the new path and convert it to C struct dot notation
+   * - we can store the accessed value in an int64_t local variable safely
+   */
+  private def choiceDispatchField(context: ElementBase): String = {
+    // We want to use SchemaComponent.scPath but it's private so duplicate it 
here (for now...)
+    def scPath(sc: SchemaComponent): Seq[SchemaComponent] = 
sc.optLexicalParent.map { scPath }.getOrElse(Nil) :+ sc
+    val localNames = scPath(context).map {
+      case er: AbstractElementRef => er.refQName.local
+      case e: ElementBase => e.namedQName.local
+      case ed: GlobalElementDecl => ed.namedQName.local
+      case _ => ""
+    }
+    val absoluteSlashPath = localNames.mkString("/")
+    val dispatchSlashPath = context.complexType.modelGroup match {
+      case choice: Choice if choice.isDirectDispatch =>
+        val expr = choice.choiceDispatchKeyEv.expr.toBriefXML()
+        val before = "'{xs:string("
+        val after = ")}'"
+        val relativePath = if (expr.startsWith(before) && expr.endsWith(after))
+          expr.substring(before.length, expr.length - after.length) else expr
+        val normalizedURI = new URI(absoluteSlashPath + "/" + 
relativePath).normalize
+        normalizedURI.getPath.substring(1)
+      case _ => ""
+    }
+    // Strip namespace prefixes since C code uses only local names (for now...)
+    val localDispatchSlashPath = dispatchSlashPath.replaceAll("/[^:]+:", "/")
+    val res = localDispatchSlashPath.replace('/', '.')
+    res
+  }
+
+  def addBeforeSwitchStatements(context: ElementBase): Unit = {
+    val erd = erdName(context)
+    val initStatement = s"    instance->_base.erd = &$erd;"
+
+    structs.top.initStatements += initStatement
+
+    val dispatchField = choiceDispatchField(context)
+    if (dispatchField.nonEmpty) {
+      val C = localName(context)
+      val declaration =
+        s"""    size_t      _choice; // choice of which union field to use
+           |    union
+           |    {""".stripMargin
+      val erdDef =
+        s"""static const ERD _choice_$erd = {
+           |    {
+           |        NULL, // namedQName.prefix
+           |        "_choice", // namedQName.local
+           |        NULL, // namedQName.ns
+           |    },
+           |    CHOICE, // typeCode
+           |    0, NULL, NULL, NULL, NULL, NULL, NULL
+           |};
+           |""".stripMargin
+      val offsetComputation = s"    (const char 
*)&${C}_compute_offsets._choice - (const char *)&${C}_compute_offsets"
+      val erdComputation = s"    &_choice_$erd"
+      val initStatement = s"    instance->_choice = NO_CHOICE;"
+      val initChoiceStatement =
+        s"""    int64_t key = rootElement->$dispatchField;
+           |    switch (key)
+           |    {""".stripMargin
+      val parseStatement =
+        s"""    instance->_base.erd->initChoice(&instance->_base, 
rootElement());
+           |    switch (instance->_choice)
+           |    {""".stripMargin
+      val unparseStatement =
+        s"""    instance->_base.erd->initChoice(&instance->_base, 
rootElement());
+           |    switch (instance->_choice)
+           |    {""".stripMargin
+
+      erds += erdDef
+      structs.top.declarations += declaration
+      structs.top.offsetComputations += offsetComputation
+      structs.top.erdComputations += erdComputation
+      structs.top.initStatements += initStatement
+      structs.top.initChoiceStatements += initChoiceStatement
+      structs.top.parserStatements += parseStatement
+      structs.top.unparserStatements += unparseStatement
+    }
+  }
+
+  def addAfterSwitchStatements(): Unit = {
+    if (structs.top.initChoiceStatements.nonEmpty) {
+      val declaration = s"    };"
+      val initChoiceStatement =
+        s"""    default:
+           |        instance->_choice = NO_CHOICE;
+           |        break;
+           |    }
+           |
+           |    if (instance->_choice != NO_CHOICE)
+           |    {
+           |        const size_t choice = instance->_choice + 1; // skip the 
_choice field
+           |        const size_t offset = instance->_base.erd->offsets[choice];
+           |        const ERD *  childERD = 
instance->_base.erd->childrenERDs[choice];
+           |        InfosetBase *childNode = (InfosetBase *)((const char 
*)instance + offset);
+           |        childNode->erd = childERD;
+           |        return true;
+           |    }
+           |    else
+           |    {
+           |        return false;
+           |    }""".stripMargin
+      val parseStatement =
+        s"""    default:
+           |        pstate->error_msg = "node's _choice field was not 
initialized during parsing";

Review comment:
       I already made this comment in the example code. But this should be a 
different kind of error. We need to distinghish errors that come from users 
making mistakes writing schemas, and failures of the implementation to 
correctly compile or run the schema.
   The latter are fatal errors and the right thing is probably to fail and stop 
processing. (Fail in simplest way possible.)

##########
File path: daffodil-runtime2/src/main/resources/examples/ex_nums.c
##########
@@ -269,186 +211,137 @@ static const ptrdiff_t bigEndian_offsets[10] = {
 };
 
 static const ERD *bigEndian_childrenERDs[10] = {
-    &be_double_bigEndian_ex_nums__ERD,
-    &be_float_bigEndian_ex_nums__ERD,
-    &be_uint64_bigEndian_ex_nums__ERD,
-    &be_uint32_bigEndian_ex_nums__ERD,
-    &be_uint16_bigEndian_ex_nums__ERD,
-    &be_uint8_bigEndian_ex_nums__ERD,
-    &be_int64_bigEndian_ex_nums__ERD,
-    &be_int32_bigEndian_ex_nums__ERD,
-    &be_int16_bigEndian_ex_nums__ERD,
-    &be_int8_bigEndian_ex_nums__ERD
-};
-
-static const ERD bigEndian_ex_nums__ERD = {
+    &be_double_bigEndian_ex_nums_ERD,
+    &be_float_bigEndian_ex_nums_ERD,
+    &be_uint64_bigEndian_ex_nums_ERD,
+    &be_uint32_bigEndian_ex_nums_ERD,
+    &be_uint16_bigEndian_ex_nums_ERD,
+    &be_uint8_bigEndian_ex_nums_ERD,
+    &be_int64_bigEndian_ex_nums_ERD,
+    &be_int32_bigEndian_ex_nums_ERD,
+    &be_int16_bigEndian_ex_nums_ERD,
+    &be_int8_bigEndian_ex_nums_ERD
+};
+
+static const ERD bigEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "bigEndian", // namedQName.local
         NULL, // namedQName.ns
     },
-    COMPLEX,                         // typeCode
-    10,                               // numChildren
-    bigEndian_offsets,                      // offsets
-    bigEndian_childrenERDs,                 // childrenERDs
-    (ERDInitSelf)&bigEndian_initSelf,       // initSelf
-    (ERDParseSelf)&bigEndian_parseSelf,     // parseSelf
+    COMPLEX, // typeCode
+    10, // numChildren
+    bigEndian_offsets, // offsets
+    bigEndian_childrenERDs, // childrenERDs
+    (ERDInitSelf)&bigEndian_initSelf, // initSelf
+    (ERDParseSelf)&bigEndian_parseSelf, // parseSelf
     (ERDUnparseSelf)&bigEndian_unparseSelf, // unparseSelf
+    NULL // initChoice
 };
 
-static const ERD le_uint64_littleEndian_ex_nums__ERD = {
+static const ERD le_uint64_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_uint64", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_UINT64, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_uint32_littleEndian_ex_nums__ERD = {
+static const ERD le_uint32_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_uint32", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_UINT32, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_uint16_littleEndian_ex_nums__ERD = {
+static const ERD le_uint16_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_uint16", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_UINT16, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_uint8_littleEndian_ex_nums__ERD = {
+static const ERD le_uint8_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_uint8", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_UINT8, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_int64_littleEndian_ex_nums__ERD = {
+static const ERD le_int64_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_int64", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_INT64, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_int32_littleEndian_ex_nums__ERD = {
+static const ERD le_int32_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_int32", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_INT32, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_int16_littleEndian_ex_nums__ERD = {
+static const ERD le_int16_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_int16", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_INT16, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_int8_littleEndian_ex_nums__ERD = {
+static const ERD le_int8_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_int8", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_INT8, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_float_littleEndian_ex_nums__ERD = {
+static const ERD le_float_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_float", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_FLOAT, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-static const ERD le_double_littleEndian_ex_nums__ERD = {
+static const ERD le_double_littleEndian_ex_nums_ERD = {
     {
         NULL, // namedQName.prefix
         "le_double", // namedQName.local
         NULL, // namedQName.ns
     },
     PRIMITIVE_DOUBLE, // typeCode
-    0,               // numChildren
-    NULL,            // offsets
-    NULL,            // childrenERDs
-    NULL,            // initSelf
-    NULL,            // parseSelf
-    NULL,            // unparseSelf
+    0, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
 static const littleEndian littleEndian_compute_offsets;
 
-static const ptrdiff_t littleEndian_offsets[10] = {
+static const size_t littleEndian_offsets[10] = {

Review comment:
       I don't understand this. littleEndian and bigEndian don't affect the 
size of things, so why do we need different offset computations given the byte 
order?

##########
File path: daffodil-runtime2/src/main/resources/examples/NestedUnion.c
##########
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ */
+
+#include "NestedUnion.h"
+#include "parsers.h"    // for parse_be_double, parse_be_float, 
parse_be_int16, parse_be_int32, parse_be_int64, parse_be_int8, parse_be_uint16, 
parse_be_uint32, parse_be_uint64, parse_be_uint8, parse_le_double, 
parse_le_float, parse_le_int16, parse_le_int32, parse_le_int64, parse_le_int8, 
parse_le_uint16, parse_le_uint32, parse_le_uint64, parse_le_uint8
+#include "unparsers.h"  // for unparse_be_double, unparse_be_float, 
unparse_be_int16, unparse_be_int32, unparse_be_int64, unparse_be_int8, 
unparse_be_uint16, unparse_be_uint32, unparse_be_uint64, unparse_be_uint8, 
unparse_le_double, unparse_le_float, unparse_le_int16, unparse_le_int32, 
unparse_le_int64, unparse_le_int8, unparse_le_uint16, unparse_le_uint32, 
unparse_le_uint64, unparse_le_uint8
+#include <math.h>       // for NAN
+#include <stdbool.h>    // for bool, false, true
+#include <stddef.h>     // for NULL, size_t
+
+// Prototypes needed for compilation
+
+static void foo_initSelf(foo *instance);
+static void foo_parseSelf(foo *instance, PState *pstate);
+static void foo_unparseSelf(const foo *instance, UState *ustate);
+static void bar_initSelf(bar *instance);
+static void bar_parseSelf(bar *instance, PState *pstate);
+static void bar_unparseSelf(const bar *instance, UState *ustate);
+static void data_initSelf(data *instance);
+static bool data_initChoice(data *instance, const NestedUnion *rootElement);
+static void data_parseSelf(data *instance, PState *pstate);
+static void data_unparseSelf(const data *instance, UState *ustate);
+static void NestedUnion_initSelf(NestedUnion *instance);
+static void NestedUnion_parseSelf(NestedUnion *instance, PState *pstate);
+static void NestedUnion_unparseSelf(const NestedUnion *instance, UState 
*ustate);
+
+// Metadata singletons
+
+static const ERD tag_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "tag", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD _choice_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "_choice", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    CHOICE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD a_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "a", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD b_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "b", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD c_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "c", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const foo foo_compute_offsets;
+
+static const size_t foo_offsets[3] = {
+    (const char *)&foo_compute_offsets.a - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.b - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.c - (const char *)&foo_compute_offsets
+};
+
+static const ERD *foo_childrenERDs[3] = {
+    &a_FooType_ERD,
+    &b_FooType_ERD,
+    &c_FooType_ERD
+};
+
+static const ERD foo_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "foo", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    foo_offsets, // offsets
+    foo_childrenERDs, // childrenERDs
+    (ERDInitSelf)&foo_initSelf, // initSelf
+    (ERDParseSelf)&foo_parseSelf, // parseSelf
+    (ERDUnparseSelf)&foo_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const ERD x_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "x", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD y_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "y", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD z_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "z", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const bar bar_compute_offsets;
+
+static const size_t bar_offsets[3] = {
+    (const char *)&bar_compute_offsets.x - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.y - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.z - (const char *)&bar_compute_offsets
+};
+
+static const ERD *bar_childrenERDs[3] = {
+    &x_BarType_ERD,
+    &y_BarType_ERD,
+    &z_BarType_ERD
+};
+
+static const ERD bar_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "bar", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    bar_offsets, // offsets
+    bar_childrenERDs, // childrenERDs
+    (ERDInitSelf)&bar_initSelf, // initSelf
+    (ERDParseSelf)&bar_parseSelf, // parseSelf
+    (ERDUnparseSelf)&bar_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const data data_compute_offsets;
+
+static const size_t data_offsets[3] = {
+    (const char *)&data_compute_offsets._choice - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.foo - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.bar - (const char 
*)&data_compute_offsets
+};
+
+static const ERD *data_childrenERDs[3] = {
+    &_choice_data_NestedUnionType_ERD,
+    &foo_data_NestedUnionType_ERD,
+    &bar_data_NestedUnionType_ERD
+};
+
+static const ERD data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "data", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    2, // numChildren
+    data_offsets, // offsets
+    data_childrenERDs, // childrenERDs
+    (ERDInitSelf)&data_initSelf, // initSelf
+    (ERDParseSelf)&data_parseSelf, // parseSelf
+    (ERDUnparseSelf)&data_unparseSelf, // unparseSelf
+    (ERDInitChoice)&data_initChoice // initChoice

Review comment:
       I think this initChoice is null for a complex element that has choice 
children. But in the ChoiceRDs of those choices this is populated. Do I have 
that correct? 
   
   If so why isn't this initChoice just the initSelf of a ChoiceRD ? It would 
need an offset passed to it, as it would be initializing a choice child within 
the parent's structure. 

##########
File path: daffodil-runtime2/src/main/resources/c/libruntime/infoset.h
##########
@@ -81,34 +79,35 @@ typedef struct ElementRuntimeData
     const NamedQName    namedQName;
     const enum TypeCode typeCode;
     const size_t        numChildren;
-    const ptrdiff_t *   offsets;
+    const size_t *      offsets;

Review comment:
       why change to size_t? I thought ptrdiff_t was a good selection of type 
for this. An offset is the delta of two pointers.

##########
File path: daffodil-runtime2/src/main/resources/c/libruntime/infoset.h
##########
@@ -81,34 +79,35 @@ typedef struct ElementRuntimeData
     const NamedQName    namedQName;
     const enum TypeCode typeCode;
     const size_t        numChildren;
-    const ptrdiff_t *   offsets;
+    const size_t *      offsets;
     const ERD **        childrenERDs;
 
     const ERDInitSelf    initSelf;
     const ERDParseSelf   parseSelf;
     const ERDUnparseSelf unparseSelf;
+    const ERDInitChoice  initChoice;
 } ERD;
 
-// InfosetBase - representation of an infoset element
+// InfosetBase - metadata of an infoset element
 
 typedef struct InfosetBase
 {
     const ERD *erd;
 } InfosetBase;
 
-// PState - parser state while parsing input
+// PState - mutable state while parsing data
 
 typedef struct PState
 {
-    FILE *      stream;    // input to read from
+    FILE *      stream;    // input to read data from
     const char *error_msg; // to stop if an error happens
 } PState;
 
-// UState - unparser state while unparsing infoset
+// UState - mutable state while unparsing infoset
 
 typedef struct UState
 {
-    FILE *      stream;    // output to write to
+    FILE *      stream;    // output to write infoset to

Review comment:
       For unparser, we're not writing out the infoset, we're writing out the 
native data representation. 

##########
File path: daffodil-runtime2/src/main/resources/c/libruntime/infoset.c
##########
@@ -159,6 +159,13 @@ walkInfosetNode(const VisitEventHandler *handler, const 
InfosetBase *infoNode)
             error_msg =
                 handler->visitNumberElem(handler, childERD, numLocation);
             break;
+        case CHOICE:
+            if (!infoNode->erd->initChoice(infoNode, rootElement()))

Review comment:
       What does initChoice do? I searched and did not find an example of one 
in this change set. 
   
   This seems to assume the entire infonode is just a single choice.  It seems 
like it needs an offset passed to it, or a child number anyway in order for an 
element to be able to have multiple choice groups inside it. 

##########
File path: 
daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala
##########
@@ -105,41 +129,178 @@ class CodeGeneratorState {
     qnameInit
   }
 
+  /**
+   * We want to convert a choiceDispatchKey expression into C struct dot
+   * notation (rootElement->[subElement.field]) which will access the C
+   * struct field containing the choiceDispatchKey's runtime value.
+   *

Review comment:
       This is ok  temporarily. Eventually we want to modify the DPath 
expression compiler to generate C code from expressions. That shouldn't be too 
hard, but will require refactoring code a bit. 

##########
File path: daffodil-runtime2/src/main/resources/examples/NestedUnion.c
##########
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ */
+
+#include "NestedUnion.h"
+#include "parsers.h"    // for parse_be_double, parse_be_float, 
parse_be_int16, parse_be_int32, parse_be_int64, parse_be_int8, parse_be_uint16, 
parse_be_uint32, parse_be_uint64, parse_be_uint8, parse_le_double, 
parse_le_float, parse_le_int16, parse_le_int32, parse_le_int64, parse_le_int8, 
parse_le_uint16, parse_le_uint32, parse_le_uint64, parse_le_uint8
+#include "unparsers.h"  // for unparse_be_double, unparse_be_float, 
unparse_be_int16, unparse_be_int32, unparse_be_int64, unparse_be_int8, 
unparse_be_uint16, unparse_be_uint32, unparse_be_uint64, unparse_be_uint8, 
unparse_le_double, unparse_le_float, unparse_le_int16, unparse_le_int32, 
unparse_le_int64, unparse_le_int8, unparse_le_uint16, unparse_le_uint32, 
unparse_le_uint64, unparse_le_uint8
+#include <math.h>       // for NAN
+#include <stdbool.h>    // for bool, false, true
+#include <stddef.h>     // for NULL, size_t
+
+// Prototypes needed for compilation
+
+static void foo_initSelf(foo *instance);
+static void foo_parseSelf(foo *instance, PState *pstate);
+static void foo_unparseSelf(const foo *instance, UState *ustate);
+static void bar_initSelf(bar *instance);
+static void bar_parseSelf(bar *instance, PState *pstate);
+static void bar_unparseSelf(const bar *instance, UState *ustate);
+static void data_initSelf(data *instance);
+static bool data_initChoice(data *instance, const NestedUnion *rootElement);
+static void data_parseSelf(data *instance, PState *pstate);
+static void data_unparseSelf(const data *instance, UState *ustate);
+static void NestedUnion_initSelf(NestedUnion *instance);
+static void NestedUnion_parseSelf(NestedUnion *instance, PState *pstate);
+static void NestedUnion_unparseSelf(const NestedUnion *instance, UState 
*ustate);
+
+// Metadata singletons
+
+static const ERD tag_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "tag", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD _choice_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "_choice", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    CHOICE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD a_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "a", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD b_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "b", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD c_FooType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "c", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_INT32, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const foo foo_compute_offsets;
+
+static const size_t foo_offsets[3] = {
+    (const char *)&foo_compute_offsets.a - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.b - (const char *)&foo_compute_offsets,
+    (const char *)&foo_compute_offsets.c - (const char *)&foo_compute_offsets
+};
+
+static const ERD *foo_childrenERDs[3] = {
+    &a_FooType_ERD,
+    &b_FooType_ERD,
+    &c_FooType_ERD
+};
+
+static const ERD foo_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "foo", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    foo_offsets, // offsets
+    foo_childrenERDs, // childrenERDs
+    (ERDInitSelf)&foo_initSelf, // initSelf
+    (ERDParseSelf)&foo_parseSelf, // parseSelf
+    (ERDUnparseSelf)&foo_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const ERD x_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "x", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD y_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "y", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ERD z_BarType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "z", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    PRIMITIVE_DOUBLE, // typeCode
+    0, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const bar bar_compute_offsets;
+
+static const size_t bar_offsets[3] = {
+    (const char *)&bar_compute_offsets.x - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.y - (const char *)&bar_compute_offsets,
+    (const char *)&bar_compute_offsets.z - (const char *)&bar_compute_offsets
+};
+
+static const ERD *bar_childrenERDs[3] = {
+    &x_BarType_ERD,
+    &y_BarType_ERD,
+    &z_BarType_ERD
+};
+
+static const ERD bar_data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "bar", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    3, // numChildren
+    bar_offsets, // offsets
+    bar_childrenERDs, // childrenERDs
+    (ERDInitSelf)&bar_initSelf, // initSelf
+    (ERDParseSelf)&bar_parseSelf, // parseSelf
+    (ERDUnparseSelf)&bar_unparseSelf, // unparseSelf
+    NULL // initChoice
+};
+
+static const data data_compute_offsets;
+
+static const size_t data_offsets[3] = {
+    (const char *)&data_compute_offsets._choice - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.foo - (const char 
*)&data_compute_offsets,
+    (const char *)&data_compute_offsets.bar - (const char 
*)&data_compute_offsets
+};
+
+static const ERD *data_childrenERDs[3] = {
+    &_choice_data_NestedUnionType_ERD,
+    &foo_data_NestedUnionType_ERD,
+    &bar_data_NestedUnionType_ERD
+};
+
+static const ERD data_NestedUnionType_ERD = {
+    {
+        NULL, // namedQName.prefix
+        "data", // namedQName.local
+        NULL, // namedQName.ns
+    },
+    COMPLEX, // typeCode
+    2, // numChildren
+    data_offsets, // offsets
+    data_childrenERDs, // childrenERDs

Review comment:
       Can one of these childrenERDs be for a choice? 




----------------------------------------------------------------
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.

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


Reply via email to