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

slawrence pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-daffodil.git


The following commit(s) were added to refs/heads/master by this push:
     new cbdf30f  Support empty choice branches with direct dispatch
cbdf30f is described below

commit cbdf30fbc9c447581218fb0df51cf0912d0dc757
Author: Steve Lawrence <[email protected]>
AuthorDate: Thu Mar 26 08:17:40 2020 -0400

    Support empty choice branches with direct dispatch
    
    When parsing a direct dispatch choice, it's possible one of the choice
    branches is an empty sequences. This optimizes to a NadaParser which
    cannot be used at runtime. So when this happens, instead use a custom
    parser that does nothing, but allows for the ChoiceCombinatorParser to
    have a parser to run for that branch.
    
    The logic already exists for non-direct dispatch choices--this just uses
    that same parser, though moved to a choice specific file and rename to
    be consistent with the equivalent unparser and make the "choice" aspect
    of it more apparent.
    
    DAFFODIL-2306
---
 .../grammar/primitives/ChoiceCombinator.scala      | 10 +++++++--
 .../unparsers/ChoiceAndOtherVariousUnparsers.scala | 14 ++++++------
 .../processors/parsers/ElementKindParsers.scala    | 15 +++++++++++++
 .../daffodil/processors/parsers/Parser.scala       | 22 -------------------
 .../daffodil/section15/choice_groups/choice.tdml   | 25 ++++++++++++++++++++++
 .../section15/choice_groups/TestChoice.scala       |  1 +
 6 files changed, 56 insertions(+), 31 deletions(-)

diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
index abab995..14016ec 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
@@ -61,7 +61,7 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: 
Seq[Gram])
       val p = alt.parser
       val res =
         if (p.isEmpty)
-          new EmptyChoiceBranchParser(alt.context.runtimeData)
+          new ChoiceBranchEmptyParser(alt.context.runtimeData)
         else p
       res
     }
@@ -225,7 +225,13 @@ case class ChoiceCombinator(ch: ChoiceTermBase, 
alternatives: Seq[Gram])
 
       val dispatchBranchKeyMap = 
dispatchBranchKeyValueTuples.toMap.mapValues(gram => {
         val isRepresented = true // FIXME: Verify is ok? Was: 
gram.context.enclosingTerm.get.isRepresented
-        val parser = gram.parser
+        val gramParser = gram.parser
+        val parser =
+          if (gramParser.isEmpty) {
+            new ChoiceBranchEmptyParser(gram.context.runtimeData)
+          } else {
+            gramParser
+          }
         (parser, isRepresented)
       })
       val serializableMap: Map[String, (Parser, Boolean)] = 
dispatchBranchKeyMap.map(identity)
diff --git 
a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ChoiceAndOtherVariousUnparsers.scala
 
b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ChoiceAndOtherVariousUnparsers.scala
index 47cd220..6d18562 100644
--- 
a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ChoiceAndOtherVariousUnparsers.scala
+++ 
b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ChoiceAndOtherVariousUnparsers.scala
@@ -67,15 +67,15 @@ case class ChoiceBranchMap(
 }
 
 /*
- * Sometimes choices will have an empty branch (e.g. a sequence that just has
- * an assert in it) that optimize to a NadaUnparser. NadaUnparsers should all
- * be optimized out, but the ChoiceCombinatorUnparser still expects to have
- * something in this cases. So we have a special empty branch unparser that
- * does nothing, but gives the ChoiceCombinatorUnparsering an unparse that it
- * can use.
+ * Sometimes choices have an empty branch (e.g. a sequence that just has an
+ * assert in it) that optimizes to a NadaUnparser. NadaUnparsers should all
+ * optimize out, but the ChoiceCombinatorUnparser still expects to have
+ * something in these cases. So we have a special empty branch unparser that
+ * does nothing, but gives the ChoiceCombinatorUnparser something that it can
+ * use.
  */
 class ChoiceBranchEmptyUnparser(val context: RuntimeData)
-  extends PrimUnparser {
+  extends PrimUnparserNoData {
 
   override lazy val runtimeDependencies = Vector()
 
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
index 7bf3aab..f54c0af 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
@@ -120,6 +120,21 @@ class DynamicEscapeSchemeParser(
 }
 
 /*
+ * Sometimes choices will have an empty branch (e.g. an empty <xs:sequence />)
+ * that optimizes to a NadaParser. NadaParsers should all optimize out, but the
+ * ChoiceCombinatorParsers still expect to have a parser to use in these cases.
+ * So we have a special empty branch parser that does nothing and always
+ * succeeds, but gives the ChoiceCombinatorParsers something that they can use.
+ */
+class ChoiceBranchEmptyParser(val context: RuntimeData)
+  extends PrimParserNoData {
+
+  override lazy val runtimeDependencies = Vector()
+
+  def parse(state: PState): Unit = {}
+}
+
+/*
  * dispatchBranchKeyMap: choiceBranchKey -> (Parser, hasRepresentation)
  */
 
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/Parser.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/Parser.scala
index 978015b..208de71 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/Parser.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/Parser.scala
@@ -156,28 +156,6 @@ final class NadaParser(override val context: RuntimeData)
   }
 }
 
-/**
- * Explicit parser for the case of
- *    <choice>
- *       ....
- *       ....
- *       <sequence/> <!-- branch explicitly contains nothing at all -->
- *    </choice>
- *
- */
-final class EmptyChoiceBranchParser(override val context: RuntimeData)
-  extends PrimParserNoData {
-  override def runtimeDependencies: Vector[Evaluatable[AnyRef]] = Vector()
-
-  override def isEmpty = false // it's an empty one, but lying here let's us 
avoid having this optimized out.
-
-  override def toString = "Empty Choice Branch"
-
-  override def parse(start: PState): Unit = {
-    // nothing
-  }
-}
-
 abstract class CombinatorParser(override val context: RuntimeData)
   extends Parser with CombinatorProcessor
 
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml
 
b/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml
index 0273105..d549e03 100644
--- 
a/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/section15/choice_groups/choice.tdml
@@ -1754,6 +1754,18 @@ it sure is/
       </xs:sequence>
     </xs:group>
 
+    <xs:element name="dd8">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="branch" type="xs:string" 
dfdl:lengthKind="explicit" dfdl:length="1" />
+          <xs:choice dfdl:choiceDispatchKey="{ ./ex:branch }">
+            <xs:sequence dfdl:choiceBranchKey="0" />
+            <xs:element ref="inty1" dfdl:choiceBranchKey="1" />
+          </xs:choice>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
   </tdml:defineSchema>
 
   <tdml:parserTestCase name="direct_dispatch_01" root="dd1"
@@ -1965,4 +1977,17 @@ it sure is/
     </tdml:infoset>
   </tdml:parserTestCase>
 
+  <tdml:parserTestCase name="direct_dispatch_17" root="dd8"
+    model="direct_dispatch_1"
+    description="direct dispatch to empty branch">
+    <tdml:document><![CDATA[0]]></tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset xmlns:ex="http://example.com";>
+        <ex:dd8>
+          <ex:branch>0</ex:branch>
+        </ex:dd8>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
 </tdml:testSuite>
diff --git 
a/daffodil-test/src/test/scala/org/apache/daffodil/section15/choice_groups/TestChoice.scala
 
b/daffodil-test/src/test/scala/org/apache/daffodil/section15/choice_groups/TestChoice.scala
index 3f8e1ee..51f22a0 100644
--- 
a/daffodil-test/src/test/scala/org/apache/daffodil/section15/choice_groups/TestChoice.scala
+++ 
b/daffodil-test/src/test/scala/org/apache/daffodil/section15/choice_groups/TestChoice.scala
@@ -121,6 +121,7 @@ class TestChoice {
   @Test def test_direct_dispatch_14() { 
runnerCH.runOneTest("direct_dispatch_14") }
   @Test def test_direct_dispatch_15() { 
runnerCH.runOneTest("direct_dispatch_15") }
   @Test def test_direct_dispatch_16() { 
runnerCH.runOneTest("direct_dispatch_16") }
+  @Test def test_direct_dispatch_17() { 
runnerCH.runOneTest("direct_dispatch_17") }
 
   //@Test def test_choice_noBranch() { runnerCH.runOneTest("choice_noBranch") 
} - Test consumes no data, which causes a TDMLError
 

Reply via email to