diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala
index a6d52b8a5c..50722e1360 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala
@@ -21,12 +21,14 @@ import org.apache.daffodil.core.dsom.ElementBase
import org.apache.daffodil.core.dsom.ModelGroup
import org.apache.daffodil.core.dsom.QuasiElementDeclBase
import org.apache.daffodil.core.dsom.Root
+import org.apache.daffodil.core.dsom.SequenceTermBase
import org.apache.daffodil.core.dsom.Term
import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.lib.schema.annotation.props.gen.AlignmentKind
import org.apache.daffodil.lib.schema.annotation.props.gen.AlignmentUnits
import org.apache.daffodil.lib.schema.annotation.props.gen.LengthKind
import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits
+import org.apache.daffodil.lib.schema.annotation.props.gen.SeparatorPosition
import org.apache.daffodil.lib.util.Math
case class AlignmentMultipleOf(nBits: Long) {
@@ -65,7 +67,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
final lazy val isKnownToBeAligned: Boolean = LV(Symbol("isKnownToBeAligned")) {
if (!isRepresented || (alignmentKindDefaulted == AlignmentKind.Manual)) true
else {
- val pa = priorAlignmentWithLeadingSkipApprox
+ val pa = priorAlignmentWithLeftFramingApprox
val aa = alignmentApprox
val res = (pa % aa) == 0
res
@@ -85,7 +87,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
else if (isKnownEncoding) {
if (knownEncodingAlignmentInBits == 1)
true
- else if (priorAlignmentWithLeadingSkipApprox.nBits % knownEncodingAlignmentInBits == 0)
+ else if (priorAlignmentWithLeftFramingApprox.nBits % knownEncodingAlignmentInBits == 0)
true
else
false
@@ -134,11 +136,14 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
LengthExact(trailingSkipInBits)
}
- // FIXME: DAFFODIL-2295
- // Does not take into account that in a sequence, what may be prior may be a separator.
- // The separator is text in some encoding, might not be the same as this term's encoding, and
- // the alignment will be left where that text leaves it.
- //
+ /**
+ * The priorAlignmentApprox doesn't need to take into account the separator
+ * alignment/length as that comes after the priorAlignmentApprox, but before
+ * the leadingSkip.
+ *
+ * TODO: DAFFODIL-3056 We need to consider the initiator MTA/length,
+ * as well as the prefix length
+ */
private lazy val priorAlignmentApprox: AlignmentMultipleOf =
LV(Symbol("priorAlignmentApprox")) {
if (this.isInstanceOf[Root] || this.isInstanceOf[QuasiElementDeclBase]) {
@@ -201,7 +206,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
// Return 0 here, unordered alignment will be handled by unorderedSequenceSelfAlignment
AlignmentMultipleOf(0)
} else {
- ps.endingAlignmentApprox
+ ps.endingAlignmentWithRightFramingApprox
}
eaa
}
@@ -228,14 +233,59 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
}
}.value
- private lazy val priorAlignmentWithLeadingSkipApprox: AlignmentMultipleOf = {
- priorAlignmentApprox + leadingSkipApprox
+ private lazy val separatorPrefixMTAApprox =
+ this.optLexicalParent match {
+ case Some(s: SequenceTermBase) if s.hasSeparator =>
+ import SeparatorPosition.*
+ s.separatorPosition match {
+ case Prefix | Infix => AlignmentMultipleOf(s.knownEncodingAlignmentInBits)
+ case Postfix => AlignmentMultipleOf(0)
+ }
+ case _ => AlignmentMultipleOf(0)
+ }
+
+ private lazy val separatorPostfixMTAApprox =
+ this.optLexicalParent match {
+ case Some(s: SequenceTermBase) if s.hasSeparator =>
+ import SeparatorPosition.*
+ s.separatorPosition match {
+ case Prefix | Infix => AlignmentMultipleOf(0)
+ case Postfix => AlignmentMultipleOf(s.knownEncodingAlignmentInBits)
+ }
+ case _ => AlignmentMultipleOf(0)
+ }
+
+ private lazy val separatorLengthApprox = this.optLexicalParent match {
+ case Some(s: SequenceTermBase) if s.hasSeparator =>
+ getEncodingLengthApprox(s)
+ case _ => LengthMultipleOf(0)
+ }
+
+ private def getEncodingLengthApprox(t: Term) = {
+ if (t.isKnownEncoding) {
+ val dfdlCharset = t.charsetEv.optConstant.get
+ val fixedWidth =
+ if (dfdlCharset.maybeFixedWidth.isDefined) dfdlCharset.maybeFixedWidth.get else 8
+ LengthMultipleOf(fixedWidth)
+ } else {
+ // runtime encoding, which must be a byte-length encoding
+ LengthMultipleOf(8)
+ }
+ }
+
+ private lazy val priorAlignmentWithLeftFramingApprox: AlignmentMultipleOf = {
+ val pawls =
+ (priorAlignmentApprox
+ * separatorPrefixMTAApprox)
+ + separatorLengthApprox
+ + leadingSkipApprox
+ pawls
}
protected lazy val contentStartAlignment: AlignmentMultipleOf = {
- if (priorAlignmentWithLeadingSkipApprox % alignmentApprox == 0) {
+ if (priorAlignmentWithLeftFramingApprox % alignmentApprox == 0) {
// alignment won't be needed, continue using prior alignment as start alignment
- priorAlignmentWithLeadingSkipApprox
+ priorAlignmentWithLeftFramingApprox
} else {
// alignment will be needed, it will be forced to be aligned to alignmentApprox
alignmentApprox
@@ -291,6 +341,18 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
}
}
+ /**
+ * The postfix separator MTA/length needs to be added after the trailing skip
+ *
+ * TODO: DAFFODIL-3057 needs to consider terminator MTA/length before trailingSkip
+ */
+ protected lazy val endingAlignmentWithRightFramingApprox: AlignmentMultipleOf = {
+ val res = (endingAlignmentApprox
+ * separatorPostfixMTAApprox)
+ + separatorLengthApprox
+ res
+ }
+
protected lazy val elementSpecifiedLengthApprox: LengthApprox = {
this match {
case eb: ElementBase => {
@@ -329,15 +391,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
}
private lazy val encodingLengthApprox: LengthApprox = {
- if (isKnownEncoding) {
- val dfdlCharset = charsetEv.optConstant.get
- val fixedWidth =
- if (dfdlCharset.maybeFixedWidth.isDefined) dfdlCharset.maybeFixedWidth.get else 8
- LengthMultipleOf(fixedWidth)
- } else {
- // runtime encoding, which must be a byte-length encoding
- LengthMultipleOf(8)
- }
+ getEncodingLengthApprox(this)
}
protected lazy val isKnownToBeByteAlignedAndByteLength: Boolean = {
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml
index 0ab4ea916e..61d08de6b9 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml
@@ -143,14 +143,6 @@
separatorPosition="infix"
emptyElementParsePolicy="treatAsEmpty"/>
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ aa/Bbb
+
+
+
+
+ aa
+ bb
+
+
+
+
+
+
+
+ /Aaa/Bbb
+
+
+
+
+ aa
+ bb
+
+
+
+
+
+
+
+ aa/Bbb/
+
+
+
+
+
+ aa
+ bb
+
+
+
+
+
+
+
+ cc-Aaa/Bbb/-dd-
+
+
+
+
+
+ cc
+ aa
+ bb
+ dd
+
+
+
+
+
+
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/usertests/TestSepTests.scala b/daffodil-test/src/test/scala/org/apache/daffodil/usertests/TestSepTests.scala
index 3ffd036121..9c27ba7261 100644
--- a/daffodil-test/src/test/scala/org/apache/daffodil/usertests/TestSepTests.scala
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/usertests/TestSepTests.scala
@@ -55,4 +55,11 @@ class TestSepTests extends TdmlTests {
// DAFFODIL-2791
@Test def test_treatAsAbsent_occursIndex = test
+
+ // DAFFODIL-2295
+ @Test def test_sep_alignment_1 = test
+ @Test def test_sep_alignment_2 = test
+ @Test def test_sep_alignment_3 = test
+
+ @Test def test_sep_alignment_4 = test
}