diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/DFDLStatementMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/DFDLStatementMixin.scala index a00306938b..a7175b3233 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/DFDLStatementMixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/DFDLStatementMixin.scala @@ -217,7 +217,7 @@ trait ProvidesDFDLStatementMixin extends ThrowsSDE with HasTermCheck { final lazy val patternStatements: Seq[DFDLStatement] = patternAsserts ++ patternDiscrims final lazy val lowPriorityStatements: Seq[DFDLStatement] = - setVariableStatements ++ nonPatternAsserts ++ nonPatternDiscrims + nonPatternAsserts ++ nonPatternDiscrims final protected lazy val localStatements = this.annotationObjs.collect { case st: DFDLStatement => st diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/Grammar.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/Grammar.scala index 6a4c5d700b..7a9e84f57a 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/Grammar.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/Grammar.scala @@ -23,6 +23,7 @@ object INoWarn { ImplicitsSuppressUnusedImportWarning() } import org.apache.daffodil.core.compiler.ForParser import org.apache.daffodil.core.compiler.ForUnparser import org.apache.daffodil.core.dsom._ +import org.apache.daffodil.runtime1.processors.parsers.AssertExpressionEvaluationParser import org.apache.daffodil.runtime1.processors.parsers.NadaParser import org.apache.daffodil.runtime1.processors.parsers.SeqCompParser import org.apache.daffodil.runtime1.processors.unparsers.SeqCompUnparser @@ -89,10 +90,19 @@ class SeqComp private (context: SchemaComponent, children: Seq[Gram]) _.isInstanceOf[NadaParser] } + lazy val assertExpressionChildren = parserChildren.filter { + _.isInstanceOf[AssertExpressionEvaluationParser] + } + final override lazy val parser = { if (parserChildren.isEmpty) new NadaParser(context.runtimeData) else if (parserChildren.length == 1) parserChildren.head - else new SeqCompParser(context.runtimeData, parserChildren.toVector) + else + new SeqCompParser( + context.runtimeData, + parserChildren.toVector, + assertExpressionChildren.toVector, + ) } lazy val unparserChildren = { diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ModelGroupGrammarMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ModelGroupGrammarMixin.scala index bb5b9c567b..bd32a449db 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ModelGroupGrammarMixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ModelGroupGrammarMixin.scala @@ -50,8 +50,10 @@ trait ModelGroupGrammarMixin // See 9.5 Evaluation Order for Statement Annotations dfdlPatternStatementEvaluations ~ // Assert and Discriminator statements with testKind="pattern" dfdlScopeBegin ~ // newVariableInstance - dfdlLowPriorityStatementEvaluations ~ // setVariable and the rest of the Assert and Discriminator statements - groupLeftFraming ~ groupContentWithInitiatorTerminator ~ groupRightFraming ~ dfdlScopeEnd + dfdlSetVariableStatements ~ + groupLeftFraming ~ groupContentWithInitiatorTerminator ~ groupRightFraming ~ + dfdlLowPriorityStatementEvaluations ~ // The rest of the Assert and Discriminator statements + dfdlScopeEnd } private lazy val groupContentWithInitiatorTerminator = diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/TermGrammarMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/TermGrammarMixin.scala index f3891d16da..fcb58cc7d9 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/TermGrammarMixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/TermGrammarMixin.scala @@ -48,6 +48,15 @@ trait TermGrammarMixin extends AlignedMixin with BitOrderMixin with TermRuntime1 newVarEnds.fold(mt) { _ ~ _ } } + private lazy val setVars = this.setVariableStatements + + private lazy val setVarGrams = setVars.map { _.gram(self) } + + protected lazy val dfdlSetVariableStatements = + prod("dfdlSetVariableStatments", setVarGrams.length > 0) { + setVarGrams.fold(mt) { _ ~ _ } + } + /** * Mandatory text alignment or mta * diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/SequenceCombinator.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/SequenceCombinator.scala index 8d6600ab51..a7f12c9778 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/SequenceCombinator.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/SequenceCombinator.scala @@ -71,7 +71,9 @@ class OrderedSequence(sq: SequenceTermBase, sequenceChildrenArg: Seq[SequenceChi // the mta parser differently to avoid this private lazy val sepUnparser = sepGram.unparser - lazy val sequenceChildren = sequenceChildrenArg.toVector + lazy val sequenceChildren = { + sequenceChildrenArg.toVector + } override lazy val parser: Parser = sq.hasSeparator match { case true => diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ExpressionEvaluatingParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ExpressionEvaluatingParsers.scala index fa35fa4b1d..03f66c98df 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ExpressionEvaluatingParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/ExpressionEvaluatingParsers.scala @@ -225,7 +225,6 @@ final class AssertExpressionEvaluationParser( with AssertParserMixin { def parse(start: PState): Unit = { - Logger.log.debug(s"This is ${toString}") // // This now informs us of the success/failure of the expression // evaluation via side-effect on the start state passed here. diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PState.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PState.scala index adf085ff1c..5d4ab4fa8d 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PState.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PState.scala @@ -61,6 +61,7 @@ import org.apache.daffodil.runtime1.processors.NonTermRuntimeData import org.apache.daffodil.runtime1.processors.ParseOrUnparseState import org.apache.daffodil.runtime1.processors.ProcessorResult import org.apache.daffodil.runtime1.processors.RuntimeData +import org.apache.daffodil.runtime1.processors.Success import org.apache.daffodil.runtime1.processors.TermRuntimeData import org.apache.daffodil.runtime1.processors.VariableInstance import org.apache.daffodil.runtime1.processors.VariableMap @@ -586,6 +587,23 @@ final class PState private ( } } + /** + * This function is used for cases where a parse must be performed after there + * has already been a failed parse of an enclosing element/sequence. Most + * common example of this would be a choice branch containing a sequence with + * an annotated assert expression. According to 9.5.2 of the DFDL spec this + * assert expression needs to be parsed regardless of whether or not the + * enclosing sequence content parses or not as the assert expression may be + * used as a discriminator for the choice branch. + */ + def withTempSuccess(func: (PState) => Unit): Unit = { + val priorProcessorStatus = processorStatus + setSuccess() + func(this) + if (processorStatus eq Success) + _processorStatus = priorProcessorStatus + } + def suspensions = Seq.empty } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala index d546b0869d..c508fc9e36 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala @@ -178,8 +178,11 @@ abstract class CombinatorParser(override val context: RuntimeData) extends Parser with CombinatorProcessor -final class SeqCompParser(context: RuntimeData, val childParsers: Vector[Parser]) - extends CombinatorParser(context) { +final class SeqCompParser( + context: RuntimeData, + val childParsers: Vector[Parser], + testAssert: Vector[Parser], +) extends CombinatorParser(context) { override lazy val runtimeDependencies = Vector() override def childProcessors = childParsers @@ -192,8 +195,14 @@ final class SeqCompParser(context: RuntimeData, val childParsers: Vector[Parser] while (i < numChildParsers) { val parser = childParsers(i) parser.parse1(pstate) - if (pstate.processorStatus ne Success) + if (pstate.processorStatus ne Success) { + if (testAssert.nonEmpty) { + testAssert.foreach { ap => + pstate.withTempSuccess(ap.parse1) + } + } return + } i += 1 } } diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section07/discriminators/discriminator.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section07/discriminators/discriminator.tdml index 93629b6858..4dfbeed986 100644 --- a/daffodil-test/src/test/resources/org/apache/daffodil/section07/discriminators/discriminator.tdml +++ b/daffodil-test/src/test/resources/org/apache/daffodil/section07/discriminators/discriminator.tdml @@ -655,7 +655,6 @@ - - - - - abc - - - + + Parse Error + Failed to populate ex:ints + Unable to parse xs:int from text: a + diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section07/discriminators/TestDiscriminators.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section07/discriminators/TestDiscriminators.scala index c5051c0b2c..acc183a4de 100644 --- a/daffodil-test/src/test/scala/org/apache/daffodil/section07/discriminators/TestDiscriminators.scala +++ b/daffodil-test/src/test/scala/org/apache/daffodil/section07/discriminators/TestDiscriminators.scala @@ -79,7 +79,7 @@ class TestDiscriminators { @Test def test_discrimExpression_03() = { runner.runOneTest("discrimExpression_03") } // DAFFODIL-1971 - // @Test def test_discrimExpression_04() = { runner.runOneTest("discrimExpression_04") } + @Test def test_discrimExpression_04() = { runner.runOneTest("discrimExpression_04") } @Test def test_discrimFailStopsFollowingAssert1(): Unit = { runner.runOneTest("discrimFailStopsFollowingAssert1")