tuxji commented on code in PR #1098:
URL: https://github.com/apache/daffodil/pull/1098#discussion_r1367603917
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libruntime/parsers.c:
##########
@@ -563,36 +535,36 @@ void
parse_hexBinary(HexBinary *hexBinary, PState *pstate)
{
read_bits(hexBinary->array, hexBinary->lengthInBytes * BYTE_WIDTH, pstate);
- if (pstate->error) return;
- pstate->bitPos0b += hexBinary->lengthInBytes * BYTE_WIDTH;
+ if (pstate->pu.error) return;
+ pstate->pu.bitPos0b += hexBinary->lengthInBytes * BYTE_WIDTH;
}
-// Validate element's value matches its fixed attribute
+// Parse fill bits up to alignmentInBits or end_bitPos0b
void
-parse_validate_fixed(bool same, const char *element, PState *pstate)
+parse_align(size_t alignmentInBits, PState *pstate)
{
- if (!same)
- {
- Diagnostics *diagnostics = get_diagnostics();
- const Error error = {ERR_FIXED_VALUE, {.s = element}};
-
- add_diagnostic(diagnostics, &error);
- pstate->diagnostics = diagnostics;
- }
+ size_t end_bitPos0b = ((pstate->pu.bitPos0b + alignmentInBits - 1) /
alignmentInBits) * alignmentInBits;
+ parse_fill_bits(end_bitPos0b, pstate);
}
-// Check array count is within bounds
-
void
-parse_check_bounds(const char *name, size_t count, size_t minOccurs, size_t
maxOccurs, PState *pstate)
+parse_fill_bits(size_t end_bitPos0b, PState *pstate)
Review Comment:
Sure, I've changed the name.
##########
daffodil-codegen-c/src/test/resources/org/apache/daffodil/codegen/c/ex_nums.dfdl.xsd:
##########
@@ -17,184 +17,197 @@
-->
<xs:schema
- elementFormDefault="qualified"
- targetNamespace="http://example.com"
- xmlns="http://example.com"
- xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
- xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ elementFormDefault="qualified"
+ targetNamespace="http://example.com"
+ version="1.2.3"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
+ xmlns:net="urn:network/format"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://example.com">
- <!-- Representation property bindings -->
+ <!-- Network order binary format (net:format) -->
Review Comment:
OK, saying `Network order big endian format (net:format)`.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libruntime/infoset.h:
##########
@@ -102,52 +102,56 @@ typedef struct ERD
typedef struct HexBinary
{
- uint8_t *array; // pointer to data in byte array
- size_t lengthInBytes; // length of data in bytes
- bool dynamic; // true if byte array was malloc'ed
+ uint8_t *array; // pointer to data in byte array
+ size_t lengthInBytes; // length of data in bytes
+ bool dynamic; // true if byte array was malloc'ed
} HexBinary;
// InfosetBase - metadata of an infoset element
typedef struct InfosetBase
{
- const ERD * erd;
+ const ERD *erd;
const struct InfosetBase *parent;
} InfosetBase;
+// ParserOrUnparserState - common mutable state while parsing or unparsing
Review Comment:
OK, done.
##########
daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryValueCodeGenerator.scala:
##########
@@ -50,6 +51,53 @@ trait BinaryValueCodeGenerator {
if (e.hasFixedValue && e.fixedValueAsString.nonEmpty) {
validateFixed(deref)
}
+
+ // Check if the element's value is restricted to a set of enumerations
+ if (e.typeDef.optRestriction.exists(_.hasEnumeration)) {
+ // Split the enumeration values into an array of strings ready to be
inserted into the C code
+ val enumerationValues =
e.typeDef.optRestriction.flatMap(_.enumerationValues).get
+ val enums = enumerationValues.split('|').map(_.replaceAll("\\\\(\\W)",
"$1"))
+ // Call another function which can be redefined differently if necessary
Review Comment:
This is a place where I was not keeping things as simple as possible. I
wrote the comment while imagining some possible future need for polymorphic
behavior, but it turned out I didn't need such behavior. I've removed the
comment.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libcli/daffodil_main.c:
##########
@@ -21,8 +21,8 @@
#include <string.h> // for strcmp
#include "cli_errors.h" // for CLI_DIAGNOSTICS, CLI_FILE_CLOSE,
CLI_FILE_OPEN
#include "daffodil_getopt.h" // for daffodil_cli, daffodil_parse,
daffodil_parse_cli, parse_daffodil_cli, daffodil_unparse, daffodil_unparse_cli,
DAFFODIL_PARSE, DAFFODIL_UNPARSE
-#include "errors.h" // for continue_or_exit, print_diagnostics,
Error, Diagnostics, Error::(anonymous)
-#include "infoset.h" // for get_infoset, walk_infoset, PState,
UState, parse_data, unparse_infoset, InfosetBase, VisitEventHandler
+#include "errors.h" // for continue_or_exit, Diagnostics,
print_diagnostics, Error
+#include "infoset.h" // for ParserOrUnparserState, PState, UState,
get_infoset, walk_infoset, parse_data, unparse_infoset, InfosetBase,
VisitEventHandler
Review Comment:
Good idea, I've added a `// auto-maintained by iwyu` comment to each
iwyu-maintained part.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libruntime/validators.c:
##########
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+// clang-format off
+#include "validators.h"
+#include <stdbool.h> // for bool, false, true
+#include <string.h> // for memcmp
+#include "errors.h" // for add_diagnostic, get_diagnostics, Error,
Diagnostics, ERR_ENUM_MATCH, ERR_ARRAY_BOUNDS, ERR_FIXED_VALUE,
ERR_OUTSIDE_RANGE, Error::(anonymous)
+// clang-format on
+
+// Validate element's array count is within its array bounds
+
+void
+validate_array_bounds(const char *name, size_t count, size_t minOccurs, size_t
maxOccurs,
+ ParserOrUnparserState *pustate)
+{
+ if (count < minOccurs || count > maxOccurs)
+ {
+ // Array count is not within bounds, so report error
+ static Error error = {ERR_ARRAY_BOUNDS, {0}};
+ error.arg.s = name;
+ pustate->error = &error;
+ }
+}
+
+// Validate element's value is same as its fixed attribute
+
+void
+validate_fixed_attribute(bool same, const char *element, ParserOrUnparserState
*pustate)
+{
+ if (!same)
+ {
+ // Element is not same as its fixed attribute, so diagnose problem
+ Diagnostics *diagnostics = get_diagnostics();
+ const Error error = {ERR_FIXED_VALUE, {.s = element}};
+
+ add_diagnostic(diagnostics, &error);
+ pustate->diagnostics = diagnostics;
+ }
+}
+
+// Validate element's value matches an enumeration (either floating point or
integer)
Review Comment:
> A specialized validator for the integer case I can see. But floating
point? What's the point (heh)?
Just keeping daffodil and daffodilC as compatible as possible in the places
where they both overlap.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libruntime/parsers.c:
##########
@@ -21,7 +21,7 @@
#include <stdbool.h> // for bool, false, true
#include <stdio.h> // for fread, fgetc, EOF
#include <stdlib.h> // for free, malloc
-#include "errors.h" // for Error, eof_or_error, Error::(anonymous),
ERR_LEFTOVER_DATA, add_diagnostic, get_diagnostics, ERR_ARRAY_BOUNDS,
ERR_FIXED_VALUE, ERR_HEXBINARY_ALLOC, ERR_PARSE_BOOL, Diagnostics
+#include "errors.h" // for Error, eof_or_error, ERR_LEFTOVER_DATA,
Error::(anonymous), ERR_HEXBINARY_ALLOC, ERR_PARSE_BOOL
Review Comment:
What you're noticing is that iwyu never puts a comment on a C source file's
own header file. That is, parsers.c "uses" a few symbols from errors.h, but
errors.c "implements" nearly all of errors.h's symbols. Even iwyu put a
comment anyway, the comment would be too long trying to list all the header
symbols implemented by the source file.
##########
BUILD.md:
##########
@@ -50,9 +50,9 @@ following its website's instructions. This is necessary to
install the
[libmxml-devel][Mini-XML] package.
You can use the `dnf` package manager to install most of the tools
-needed to build Daffodil:
+used to develop Daffodil:
- sudo dnf install clang gcc git java-11-openjdk-devel llvm make mxml-devel
pkgconf
+ sudo dnf install clang gcc git iwyu java-11-openjdk-devel llvm make
mxml-devel pkgconf
If you want to use clang instead of gcc, you'll have to set your
Review Comment:
If you're talking about the paragraph `If you want to use clang instead of
gcc, ...`, I originally added that paragraph because you told me you didn't
want to require GNU-licensed tools to develop or use any part of Daffodil. I
even made sure that the GitHub Action workflow (main.yml) would set these
environment variables to build Daffodil with clang and lvvm-ar instead of gcc
and ar. I can reword the paragraph to say you can set these environment
variables to use clang and llvm-ar instead of gcc and ar if you have a policy
forbidding GNU-licensed tools.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libruntime/unparsers.c:
##########
@@ -401,69 +401,41 @@ unparse_le_uint8(uint8_t number, size_t num_bits, UState
*ustate)
unparse_endian_uint64(LITTLE_ENDIAN_DATA, number, num_bits, ustate);
}
+// Unparse opaque bytes from hexBinary field
+
+void
+unparse_hexBinary(HexBinary hexBinary, UState *ustate)
+{
+ write_bits(hexBinary.array, hexBinary.lengthInBytes * BYTE_WIDTH, ustate);
+ if (ustate->pu.error) return;
+ ustate->pu.bitPos0b += hexBinary.lengthInBytes * BYTE_WIDTH;
+}
+
// Unparse fill bits up to alignmentInBits or end_bitPos0b
void
unparse_align(size_t alignmentInBits, const uint8_t fill_byte, UState *ustate)
{
- size_t end_bitPos0b = ((ustate->bitPos0b + alignmentInBits - 1) /
alignmentInBits) * alignmentInBits;
+ size_t end_bitPos0b = ((ustate->pu.bitPos0b + alignmentInBits - 1) /
alignmentInBits) * alignmentInBits;
unparse_fill_bits(end_bitPos0b, fill_byte, ustate);
}
void
unparse_fill_bits(size_t end_bitPos0b, const uint8_t fill_byte, UState *ustate)
Review Comment:
I've changed the name too.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/tests/bits.c:
##########
Review Comment:
Both C tooling limitations and keeping things as simple as possible (it's
more work to exclude the tests than to simply include them in generated c
directory).
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libruntime/validators.c:
##########
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+// clang-format off
+#include "validators.h"
+#include <stdbool.h> // for bool, false, true
+#include <string.h> // for memcmp
+#include "errors.h" // for add_diagnostic, get_diagnostics, Error,
Diagnostics, ERR_ENUM_MATCH, ERR_ARRAY_BOUNDS, ERR_FIXED_VALUE,
ERR_OUTSIDE_RANGE, Error::(anonymous)
+// clang-format on
+
+// Validate element's array count is within its array bounds
+
+void
+validate_array_bounds(const char *name, size_t count, size_t minOccurs, size_t
maxOccurs,
+ ParserOrUnparserState *pustate)
+{
+ if (count < minOccurs || count > maxOccurs)
+ {
+ // Array count is not within bounds, so report error
+ static Error error = {ERR_ARRAY_BOUNDS, {0}};
+ error.arg.s = name;
+ pustate->error = &error;
+ }
+}
+
+// Validate element's value is same as its fixed attribute
+
+void
+validate_fixed_attribute(bool same, const char *element, ParserOrUnparserState
*pustate)
+{
+ if (!same)
+ {
+ // Element is not same as its fixed attribute, so diagnose problem
+ Diagnostics *diagnostics = get_diagnostics();
+ const Error error = {ERR_FIXED_VALUE, {.s = element}};
+
+ add_diagnostic(diagnostics, &error);
+ pustate->diagnostics = diagnostics;
+ }
+}
+
+// Validate element's value matches an enumeration (either floating point or
integer)
+
+void
+validate_floatpt_enumeration(double number, size_t num_enums, double enums[],
const char *element,
+ ParserOrUnparserState *pustate)
+{
+ bool match_found = false;
+ for (size_t i = 0; !match_found && i < num_enums; i++)
+ {
+ if (number == enums[i])
+ {
+ match_found = true;
+ }
+ }
+ if (!match_found)
+ {
+ // Number does not match any enumeration, so diagnose problem
+ Diagnostics *diagnostics = get_diagnostics();
+ const Error error = {ERR_ENUM_MATCH, {.s = element}};
+
+ add_diagnostic(diagnostics, &error);
+ pustate->diagnostics = diagnostics;
+ }
+}
+
+void
+validate_hexbinary_enumeration(const HexBinary *hexBinary, size_t num_enums,
HexBinary enums[],
Review Comment:
Added comment.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/libruntime/validators.c:
##########
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+// clang-format off
+#include "validators.h"
+#include <stdbool.h> // for bool, false, true
+#include <string.h> // for memcmp
+#include "errors.h" // for add_diagnostic, get_diagnostics, Error,
Diagnostics, ERR_ENUM_MATCH, ERR_ARRAY_BOUNDS, ERR_FIXED_VALUE,
ERR_OUTSIDE_RANGE, Error::(anonymous)
+// clang-format on
+
+// Validate element's array count is within its array bounds
+
+void
+validate_array_bounds(const char *name, size_t count, size_t minOccurs, size_t
maxOccurs,
+ ParserOrUnparserState *pustate)
Review Comment:
> These validation functions are the only thing that I find here that
actually uses states polymorphically via ParserOrUnparserState as a type. Is
that correct?
Yes, that's correct.
##########
daffodil-codegen-c/src/main/resources/org/apache/daffodil/codegen/c/files/tests/bits.c:
##########
@@ -20,29 +20,29 @@
#include <criterion/new/assert.h> // for CRI_ASSERT_OP_VAR_TAGGED,
CRI_ASSERT_OP_TYPE_TAGGED, CRI_ASSERT_OP_VAL_TAGGED, CRI_ASSERT_TEST_TAG_u8,
cr_user_u8_tostr, CRI_ASSERT_OP_MKNODE_TAGGED, CRI_ASSERT_OP_NAME_TAGGED,
CRI_ASSERT_TEST_TAG_sz, cr_user_sz_tostr, CRI_ASSERT_TYPE_TAG_ID_u8,
cr_user_u8_eq, CRI_ASSERT_TEST_TAG_ptr, cr_user_ptr_tostr, CRI_ASSERT_MKLIST_2,
CRI_ASSERT_SPECIFIER_OP1, CRI_ASSERT_SPECIFIER_eq, CRI_ASSERT_SPEC_OPLEN_2,
CRI_ASSERT_TEST_SPECIFIER_eq, cr_expect, CRI_ASSERT_TYPE_TAG_u8,
CRI_ASSERT_TYPE_TAG_ID_sz, cr_user_sz_eq, CRI_ASSERT_TYPE_TAG_sz,
CRI_ASSERT_TYPE_TAG_ID_ptr, cr_user_ptr_eq, CRI_ASSERT_TEST_TAGC_u8,
CRI_ASSERT_TEST_TAG_int, cr_user_int_tostr, CRI_ASSERT_TYPE_TAG_ptr,
CRI_ASSERT_TEST_TAGC_sz, CRI_ASSERT_TYPE_TAG_ID_int, cr_user_int_eq,
CRI_ASSERT_TEST_TAGC_ptr, CRI_ASSERT_TYPE_TAG_int, CRI_ASSERT_TEST_TAG_i16,
CRI_ASSERT_TEST_TAG_i32, CRI_ASSERT_TEST_TAG_i64, CRI_ASSERT_TEST_TAG_i8,
CRI_ASSERT_TEST_TAG_u16, CRI_ASSERT_TEST_TAG_u32, CRI_ASSERT_TE..
.
Review Comment:
Changed Makefile to tell iwyu to put 110 characters max (same as
.clang-format's column limit).
##########
daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/AlignmentFillCodeGenerator.scala:
##########
@@ -31,11 +31,11 @@ trait AlignmentFillCodeGenerator {
val parseStatement =
s"""$indent1$indent2 // Fill to closest alignment
|$indent1$indent2 parse_align($alignmentInBits, pstate);
- |$indent1$indent2 if (pstate->error) return;""".stripMargin
+ |$indent1$indent2 if (pstate->pu.error) return;""".stripMargin
val unparseStatement =
s"""$indent1$indent2 // Fill to closest alignment
Review Comment:
I've considered implementing an indentStripMargin(indent) function which
would let me remove the $indent1$indent2 and let the function generate the
required indentation instead.
##########
daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryValueCodeGenerator.scala:
##########
@@ -50,6 +51,53 @@ trait BinaryValueCodeGenerator {
if (e.hasFixedValue && e.fixedValueAsString.nonEmpty) {
validateFixed(deref)
}
+
+ // Check if the element's value is restricted to a set of enumerations
+ if (e.typeDef.optRestriction.exists(_.hasEnumeration)) {
+ // Split the enumeration values into an array of strings ready to be
inserted into the C code
+ val enumerationValues =
e.typeDef.optRestriction.flatMap(_.enumerationValues).get
+ val enums = enumerationValues.split('|').map(_.replaceAll("\\\\(\\W)",
"$1"))
+ // Call another function which can be redefined differently if necessary
+ valueValidateEnumeration(e, deref, enums, cgState)
+ }
+
+ // Check if the element's value is restricted to a range (we will need to
handle any
+ // combination of inclusive and exclusive endpoints when generating our C
expression)
+ val hasMinExclusive = e.typeDef.optRestriction.exists(_.hasMinExclusive)
+ val hasMinInclusive = e.typeDef.optRestriction.exists(_.hasMinInclusive)
+ val hasMaxExclusive = e.typeDef.optRestriction.exists(_.hasMaxExclusive)
+ val hasMaxInclusive = e.typeDef.optRestriction.exists(_.hasMaxInclusive)
+ if (hasMinExclusive || hasMinInclusive || hasMaxExclusive ||
hasMaxInclusive) {
+ // Generate the minimum endpoint comparison
+ val minEndpoint = if (hasMinExclusive) {
+ val endpoint = e.typeDef.optRestriction.map(_.minExclusiveValue).get
+ s"""> $endpoint"""
+ } else if (hasMinInclusive) {
+ val endpoint = e.typeDef.optRestriction.map(_.minInclusiveValue).get
+ // Avoid unsigned >= 0 comparisons (causes gcc warnings)
+ e.optPrimType.get match {
+ case PrimType.UnsignedByte | PrimType.UnsignedShort |
PrimType.UnsignedInt |
+ PrimType.UnsignedLong | PrimType.NonNegativeInteger if
endpoint.toString == "0" =>
+ ""
Review Comment:
I've moved a comment (`// Avoid unsigned >= 0 comparisons (causes gcc
warnings)`) down two lines so the reason for the "" will be more visible. I
won't bother using Option at this time.
##########
daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryValueCodeGenerator.scala:
##########
@@ -93,11 +141,94 @@ trait BinaryValueCodeGenerator {
val initERDStatement = ""
val parseStatement =
- s"""$indent1$indent2 parse_validate_fixed($field == $fixed,
"$localName", pstate);
- |$indent1$indent2 if (pstate->error) return;""".stripMargin
+ s"""$indent1$indent2 validate_fixed_attribute($field == $fixed,
"$localName", &pstate->pu);
+ |$indent1$indent2 if (pstate->pu.error) return;""".stripMargin
+ val unparseStatement =
+ s"""$indent1$indent2 validate_fixed_attribute($field == $fixed,
"$localName", &ustate->pu);
+ |$indent1$indent2 if (ustate->pu.error) return;""".stripMargin
+ cgState.addSimpleTypeStatements(initERDStatement, parseStatement,
unparseStatement)
+ }
+
+ // Generate C code to validate a primitive element matches one of its
enumeration values.
+ // May be replaced by a more specialized function in another trait for some
types.
Review Comment:
I deleted this `"May be replaced by` comment as well since I ended up doing
all the necessary implementation for all types in the same function anyway (no
mixin trait needed).
##########
daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryValueCodeGenerator.scala:
##########
@@ -50,6 +51,53 @@ trait BinaryValueCodeGenerator {
if (e.hasFixedValue && e.fixedValueAsString.nonEmpty) {
validateFixed(deref)
}
+
+ // Check if the element's value is restricted to a set of enumerations
+ if (e.typeDef.optRestriction.exists(_.hasEnumeration)) {
+ // Split the enumeration values into an array of strings ready to be
inserted into the C code
+ val enumerationValues =
e.typeDef.optRestriction.flatMap(_.enumerationValues).get
+ val enums = enumerationValues.split('|').map(_.replaceAll("\\\\(\\W)",
"$1"))
+ // Call another function which can be redefined differently if necessary
+ valueValidateEnumeration(e, deref, enums, cgState)
+ }
+
+ // Check if the element's value is restricted to a range (we will need to
handle any
+ // combination of inclusive and exclusive endpoints when generating our C
expression)
+ val hasMinExclusive = e.typeDef.optRestriction.exists(_.hasMinExclusive)
+ val hasMinInclusive = e.typeDef.optRestriction.exists(_.hasMinInclusive)
+ val hasMaxExclusive = e.typeDef.optRestriction.exists(_.hasMaxExclusive)
+ val hasMaxInclusive = e.typeDef.optRestriction.exists(_.hasMaxInclusive)
+ if (hasMinExclusive || hasMinInclusive || hasMaxExclusive ||
hasMaxInclusive) {
+ // Generate the minimum endpoint comparison
+ val minEndpoint = if (hasMinExclusive) {
+ val endpoint = e.typeDef.optRestriction.map(_.minExclusiveValue).get
+ s"""> $endpoint"""
+ } else if (hasMinInclusive) {
+ val endpoint = e.typeDef.optRestriction.map(_.minInclusiveValue).get
+ // Avoid unsigned >= 0 comparisons (causes gcc warnings)
+ e.optPrimType.get match {
+ case PrimType.UnsignedByte | PrimType.UnsignedShort |
PrimType.UnsignedInt |
+ PrimType.UnsignedLong | PrimType.NonNegativeInteger if
endpoint.toString == "0" =>
+ ""
+ case _ =>
+ s""">= $endpoint"""
+ }
+ } else {
+ ""
+ }
+ // Generate the maximum endpoint comparison
+ val maxEndpoint = if (hasMaxExclusive) {
+ val endpoint = e.typeDef.optRestriction.map(_.maxExclusiveValue).get
+ s"""< $endpoint"""
+ } else if (hasMaxInclusive) {
+ val endpoint = e.typeDef.optRestriction.map(_.maxInclusiveValue).get
+ s"""<= $endpoint"""
+ } else {
+ ""
+ }
+ // Call another function which can be redefined differently if necessary
Review Comment:
Agreed, I just deleted the comment to keep things as simple as possible.
##########
daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryValueCodeGenerator.scala:
##########
@@ -93,11 +141,94 @@ trait BinaryValueCodeGenerator {
val initERDStatement = ""
val parseStatement =
- s"""$indent1$indent2 parse_validate_fixed($field == $fixed,
"$localName", pstate);
- |$indent1$indent2 if (pstate->error) return;""".stripMargin
+ s"""$indent1$indent2 validate_fixed_attribute($field == $fixed,
"$localName", &pstate->pu);
+ |$indent1$indent2 if (pstate->pu.error) return;""".stripMargin
+ val unparseStatement =
+ s"""$indent1$indent2 validate_fixed_attribute($field == $fixed,
"$localName", &ustate->pu);
+ |$indent1$indent2 if (ustate->pu.error) return;""".stripMargin
+ cgState.addSimpleTypeStatements(initERDStatement, parseStatement,
unparseStatement)
+ }
+
+ // Generate C code to validate a primitive element matches one of its
enumeration values.
+ // May be replaced by a more specialized function in another trait for some
types.
+ private def valueValidateEnumeration(
+ e: ElementBase,
+ deref: String,
+ enums: Array[String],
+ cgState: CodeGeneratorState,
+ ): Unit = {
+ val indent1 = if (cgState.hasChoice) INDENT else NO_INDENT
+ val indent2 = if (deref.nonEmpty) INDENT else NO_INDENT
+ val localName = cgState.cName(e)
+ val field = s"instance->$localName$deref"
+
+ // Extra initialization only for hexBinary enumerations
+ val arraysName = s"arrays_$localName"
+ val hexEnums = enums.zipWithIndex.map { case (s, index) =>
+ s"{$arraysName[$index], ${s.length / 2}, false}"
+ }
+ val hexEnumsInit = enums.map(_.grouped(2).map("0x" + _).mkString("{", ",
", "}"))
+ val enumsLenMax = enums.map(_.length / 2).max
+ val arraysInit =
+ s"""$indent1$indent2 uint8_t $arraysName[][$enumsLenMax] =
${hexEnumsInit.mkString(
+ "{",
+ ", ",
+ "}",
+ )};\n"""
+
+ val (enumsInit, extraInit, primType, valType, fieldArg) =
e.optPrimType.get match {
+ case PrimType.Double | PrimType.Float => (enums, "", "double",
"floatpt", field)
+ case PrimType.HexBinary => (hexEnums, arraysInit, "HexBinary",
"hexbinary", s"&$field")
+ case _ => (enums, "", "int64_t", "integer", field)
+ }
+
+ // Initialization for all enumerations
+ val enumsArray = s"enums_$localName"
+ val varsInit = extraInit +
+ s"""$indent1$indent2 $primType $enumsArray[] = ${enumsInit.mkString(
Review Comment:
C compilers are pretty robust programs, so I doubt giant enums would blow
them up. But we very well might need to refactor the C implementation to be
more readable when let loose on 4096 enums.
--
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]