Implements Static vs Dynamic LiteralNils.

Adds DelimParserBase primitive that all of
the 'delimited' and 'Static/DynamicText' inherit
from.  This is where the DFDLDelimParser gets
instantiated.

Adds a 'Dynamic' trait that contains the dynamic
specific versions of methods to be overriden in
the base classes.

Updates StringDelimited primitive to factor out
the processResult protion of the parse method. Which
allows for LiteralNil type primitives to directly
inherit from StringDelimited.

DFDL-572
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/GrammarMixins.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/GrammarMixins.scala
index f09a794..5311fdd 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/GrammarMixins.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/GrammarMixins.scala
@@ -668,7 +668,9 @@
       nilElementInitiator ~ {
         // if (representation != Representation.Text) this.SDE("LiteralValue Nils require representation='text'.")
         lengthKind match {
-          case LengthKind.Delimited => LiteralNilDelimitedOrEndOfData(this)
+//          case LengthKind.Delimited => LiteralNilDelimitedOrEndOfData(this)
+          case LengthKind.Delimited if this.hasExpressionsInTerminatingMarkup => LiteralNilDelimitedEndOfDataDynamic(this)
+          case LengthKind.Delimited  => LiteralNilDelimitedEndOfDataStatic(this)
           case LengthKind.Pattern => LiteralNilPattern(this)
           case LengthKind.Explicit => {
             lengthUnits match {
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/Primitives.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/Primitives.scala
index 9dd5b04..69eb81b 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/Primitives.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/Primitives.scala
@@ -1069,6 +1069,11 @@
 
 }
 
+abstract class DelimParserBase(e: Term, guard: Boolean) extends Terminal(e, guard){
+  override def toString = "DelimParserBase[" + name + "]"
+  val dp = new DFDLDelimParserStatic(e.knownEncodingStringBitLengthFunction)
+}
+
 abstract class ZonedTextNumberPrim(e: ElementBase, guard: Boolean) extends Terminal(e, guard) {
   def parser: DaffodilParser = new PrimParser(this, e) {
     def parse(start: PState): PState = {
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesDelimiters.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesDelimiters.scala
index 21119bd..fc698eb 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesDelimiters.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesDelimiters.scala
@@ -66,7 +66,7 @@
   extends StaticText(delim, e, kindString, guard)

 

 abstract class StaticText(delim: String, e: Term, kindString: String, guard: Boolean = true)

-  extends Terminal(e, guard)

+  extends DelimParserBase(e, guard)

   with WithParseErrorThrowing with TextReader {

 

   val charset = e.knownEncodingCharset

@@ -203,8 +203,8 @@
   lazy val (staticDelimsParsers, staticDelimsRegex) = delimParser.generateDelimiter(staticDelimsCooked.toSet)

 

   def parseMethod(pInputDelimiterParser: delimParser.Parser[String],

-                  pIsLocalDelimParser: delimParser.Parser[String],

-                  input: Reader[Char]): DelimParseResult = {

+    pIsLocalDelimParser: delimParser.Parser[String],

+    input: Reader[Char]): DelimParseResult = {

     val result: DelimParseResult = delimParser.parseInputDelimiter(pInputDelimiterParser, pIsLocalDelimParser, input)

     result

   }

@@ -768,116 +768,53 @@
   }

 }

 

-case class LiteralNilDelimitedOrEndOfData(e: ElementBase)

-  extends StaticText(e.nilValue, e, "LiteralNilDelimitedOrEndOfData", e.isNillable)

-  with Padded {

-  lazy val unparserDelim = Assert.notYetImplemented()

+abstract class LiteralNilDelimitedEndOfData(eb: ElementBase)

+  extends StringDelimited(eb) {

+  val nilValuesCooked = new ListOfStringValueAsLiteral(eb.nilValue, eb).cooked

+  val isEmptyAllowed = eb.nilValue.contains("%ES;") // TODO: move outside parser

 

-  val stParser = super.parser

+  override def processResult(result: DelimParseResult, state: PState): PState = {

+    result match {

+      case f: DelimParseFailure =>

+        return parser.PE(state, "%s - %s - Parse failed.", this.toString(), eName)

+      case s: DelimParseSuccess => {

+        // We have a field, is it empty?

+        //val field = dp.removePadding(s.field, justificationTrim, padChar)

+        val field = s.field

+        val isFieldEmpty = field.length() == 0 // Note: field has been stripped of padChars

 

-  override def parser = new PrimParser(this, e) {

-    override def toString = "LiteralNilDelimitedOrEndOfData(" + e.nilValue + ")"

-    val eName = e.toString()

+        if (isFieldEmpty && !isEmptyAllowed) {

+          // Fail!

+          return parser.PE(state, "%s - Empty field found but not allowed!", eName)

+        } else if ((isFieldEmpty && isEmptyAllowed) || // Empty, but must advance past padChars if there were any. 

+          dp.isFieldDfdlLiteral(field, nilValuesCooked.toSet)) { // Not empty, but matches.

+          // Contains a nilValue, Success!

+          state.parentElement.makeNil()

 

-    def parse(start: PState): PState = {

-      // withLoggingLevel(LogLevel.Debug) 

-      {

-        // TODO: Why are we even doing this here?  LiteralNils don't care about delimiters

-        // and LiteralNils don't have expressions! I think we can get rid of this variable

-        // mapping stuff.

-        //

-        // We must feed variable context out of one evaluation and into the next.

-        // So that the resulting variable map has the updated status of all evaluated variables.

-        var vars = start.variableMap

-        val delimsRaw = e.allTerminatingMarkup.map {

-          x =>

-            {

-              val R(res, newVMap) = x.evaluate(start.parentElement, vars, start)

-              vars = newVMap

-              res

-            }

-        }

-        val delimsCooked1 = delimsRaw.map(raw => { new ListOfStringValueAsLiteral(raw.toString, e).cooked })

-        val delimsCooked = delimsCooked1.flatten

-        //val nilValuesCooked1 = delimsRaw.map(raw => { new ListOfStringValueAsLiteral(e.nilValue, e).cooked })

-        val nilValuesCooked = new ListOfStringValueAsLiteral(e.nilValue, e).cooked //nilValuesCooked1.flatten

-        val postEvalState = start.withVariables(vars)

+          val numBits = s.numBits

+          //val endCharPos = start.charPos + result.field.length()

+          val endCharPos = if (state.charPos == -1) s.numCharsRead else state.charPos + s.numCharsRead

+          val endBitPos = numBits + state.bitPos

 

-        log(LogLevel.Debug, "%s - Looking for: %s Count: %s", eName, delimsCooked, delimsCooked.length)

+          log(LogLevel.Debug, "%s - Found %s", eName, s.field)

+          log(LogLevel.Debug, "%s - Ended at byte position %s", eName, (endBitPos >> 3))

+          log(LogLevel.Debug, "%s - Ended at bit position ", eName, endBitPos)

 

-        val bytePos = (postEvalState.bitPos >> 3).toInt

-        log(LogLevel.Debug, "%s - Starting at bit pos: %s", eName, postEvalState.bitPos)

-        log(LogLevel.Debug, "%s - Starting at byte pos: %s", eName, bytePos)

-

-        // Don't check alignment this way. This is encoding specific. (Some encodings not byte aligned)

-        // if (postEvalState.bitPos % 8 != 0) { return PE(start, "LiteralNilDelimitedOrEndOfData - not byte aligned.") }

-

-        log(LogLevel.Debug, "Retrieving reader state.")

-        val reader1 = getReader(charset, start.bitPos, start)

-        //        val byteReader = in.byteReader.atPos(bytePos)

-        //        val reader = byteReader.charReader(decoder.charset().name())

-

-        // 1. Parse up until terminating Markup

-        // 2. Compare resultant field to nilValue(s)

-        //		Same, success

-        //		Diff, fail

-        val d = new DelimParser(e.knownEncodingStringBitLengthFunction)

-        val result =

-          if (esObj.escapeSchemeKind == EscapeSchemeKind.Block) {

-            //          result = d.parseInputEscapeBlock(Set.empty[String], delimsCooked.toSet, reader,

-            //            esObj.escapeBlockStart, esObj.escapeBlockEnd, esObj.escapeEscapeCharacter)

-            d.parseInputEscapeBlock(Set.empty[String], delimsCooked.toSet, reader1,

-              esObj.escapeBlockStart, esObj.escapeBlockEnd, esObj.escapeEscapeCharacter, justificationTrim, padChar)

-          } else if (esObj.escapeSchemeKind == EscapeSchemeKind.Character) {

-            d.parseInputEscapeCharacter(Set.empty[String], delimsCooked.toSet, reader1,

-              esObj.escapeCharacter, esObj.escapeEscapeCharacter, justificationTrim, padChar)

-          } else {

-            d.parseInput(Set.empty[String], delimsCooked.toSet, reader1, justificationTrim, padChar)

-          }

-

-        result match {

-          case f: DelimParseFailure =>

-            return PE(postEvalState, "%s - %s - Parse failed.", this.toString(), eName)

-          case s: DelimParseSuccess => {

-            // We have a field, is it empty?

-            val field = d.removePadding(s.field, justificationTrim, padChar)

-            val isFieldEmpty = field.length() == 0 // Note: field has been stripped of padChars

-            val isEmptyAllowed = e.nilValue.contains("%ES;") // TODO: move outside parser

-            if (isFieldEmpty && !isEmptyAllowed) {

-              // Fail!

-              return PE(postEvalState, "%s - Empty field found but not allowed!", eName)

-            } else if ((isFieldEmpty && isEmptyAllowed) || // Empty, but must advance past padChars if there were any. 

-              d.isFieldDfdlLiteral(field, nilValuesCooked.toSet)) { // Not empty, but matches.

-              // Contains a nilValue, Success!

-              start.parentElement.makeNil()

-

-              val numBits = s.numBits

-              //val endCharPos = start.charPos + result.field.length()

-              val endCharPos = if (postEvalState.charPos == -1) s.numCharsRead else postEvalState.charPos + s.numCharsRead

-              val endBitPos = numBits + start.bitPos

-

-              log(LogLevel.Debug, "%s - Found %s", eName, s.field)

-              log(LogLevel.Debug, "%s - Ended at byte position %s", eName, (endBitPos >> 3))

-              log(LogLevel.Debug, "%s - Ended at bit position ", eName, endBitPos)

-

-              //return postEvalState.withPos(endBitPos, endCharPos) // Need to advance past found nilValue

-              return postEvalState.withPos(endBitPos, endCharPos, Some(s.next)) // Need to advance past found nilValue

-            } else {

-              // Fail!

-              return PE(postEvalState, "%s - Does not contain a nil literal!", eName)

-            }

-          }

+          //return postEvalState.withPos(endBitPos, endCharPos) // Need to advance past found nilValue

+          return state.withPos(endBitPos, endCharPos, Some(s.next)) // Need to advance past found nilValue

+        } else {

+          // Fail!

+          return parser.PE(state, "%s - Does not contain a nil literal!", eName)

         }

       }

     }

   }

-

-  override def unparser: Unparser = new Unparser(e) {

-    def unparse(start: UState): UState = {

-      Assert.notYetImplemented()

-    }

-  }

 }

 

+case class LiteralNilDelimitedEndOfDataStatic(eb: ElementBase)

+  extends LiteralNilDelimitedEndOfData(eb)

+case class LiteralNilDelimitedEndOfDataDynamic(eb: ElementBase)

+  extends LiteralNilDelimitedEndOfData(eb) with Dynamic

+

 case class LogicalNilValue(e: ElementBase) extends Primitive(e, e.isNillable)

 

diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesLengthKind.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesLengthKind.scala
index 50bc4bc..23a1e07 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesLengthKind.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/processors/PrimitivesLengthKind.scala
@@ -62,7 +62,7 @@
 import edu.illinois.ncsa.daffodil.processors.{ Parser => DaffodilParser }

 

 abstract class StringLength(e: ElementBase)

-  extends Terminal(e, true)

+  extends DelimParserBase(e, true)

   with TextReader

   with Padded

   with WithParseErrorThrowing {

@@ -71,7 +71,7 @@
   val stringLengthInBitsFnc = e.knownEncodingStringBitLengthFunction

   val codepointWidth = e.knownEncodingWidthInBits

 

-  lazy val dp = new DFDLDelimParserStatic(e.knownEncodingStringBitLengthFunction)

+  //lazy val dp = new DFDLDelimParserStatic(e.knownEncodingStringBitLengthFunction)

   lazy val removePaddingParser: Option[dp.Parser[String]] = dp.generateRemovePaddingParser(justificationTrim, padChar)

 

   def lengthText: String

@@ -383,7 +383,7 @@
 }

 

 abstract class StringDelimited(e: ElementBase)

-  extends Terminal(e, true)

+  extends DelimParserBase(e, true)

   with TextReader

   with Padded

   with WithParseErrorThrowing {

@@ -392,9 +392,11 @@
   lazy val tm = e.allTerminatingMarkup

   lazy val cname = toString

 

+  val eName = e.toString()

   val charset = e.knownEncodingCharset

+  val elemBase = e

 

-  val dp = new DFDLDelimParserStatic(e.knownEncodingStringBitLengthFunction)

+  //val dp = new DFDLDelimParserStatic(e.knownEncodingStringBitLengthFunction)

 

   // If there are any static delimiters, pre-process them here

   val staticDelimsRaw = e.allTerminatingMarkup.filter(x => x.isConstant).map { _.constantAsString }

@@ -407,7 +409,7 @@
   //    reader: Reader[Char]): DelimParseResult

 

   def parseMethod(hasDelim: Boolean, delimsParser: dp.Parser[String], delimsRegex: Array[String],

-                  reader: Reader[Char]): DelimParseResult = {

+    reader: Reader[Char]): DelimParseResult = {

     // TODO: Change DFDLDelimParser calls to get rid of Array.empty[String] since we're only passing a single list the majority of the time.

     if (esObj.escapeSchemeKind == EscapeSchemeKind.Block) {

       val (escapeBlockParser, escapeBlockEndRegex, escapeEscapeRegex) = dp.generateEscapeBlockParsers2(delimsParser,

@@ -440,13 +442,42 @@
 

   }

 

-  def getDelims(pstate: PState): (List[String], Array[String], dp.Parser[String], Option[VariableMap])

+  def getDelims(pstate: PState): (List[String], Array[String], dp.Parser[String], Option[VariableMap]) = {

+    (staticDelimsCooked, staticDelimsRegex, combinedStaticDelimsParser, None)

+  }

+

+//  def errorIfDelimsHaveWSPStar(delims: List[String]) = {

+//    /* Nothing to do here only applies to Dynamic case */ }

+  

+  def errorIfDelimsHaveWSPStar(delims: List[String]) = {

+    // TODO: refactor. This check isn't needed in static case. Only dynamic case.

+    if (delims.filter(x => x == "%WSP*;").length > 0) {

+      // We cannot detect this error until expressions have been evaluated!

+      log(LogLevel.Debug, "%s - Failed due to WSP* detected as a delimiter for lengthKind=delimited", eName)

+      elemBase.schemaDefinitionError("WSP* cannot be used as a delimiter when lengthKind=delimited!")

+    }

+  }

+

+  def processResult(result: DelimParseResult, state: PState): PState = {

+    result match {

+      case f: DelimParseFailure =>

+        return parser.PE(state, "%s - %s - Parse failed.", this.toString(), eName)

+      case s: DelimParseSuccess => {

+        val field = s.get

+        val numBits = s.numBits

+        log(LogLevel.Debug, "%s - Parsed: %s Parsed Bytes: %s (bits %s)", eName, field, numBits / 8, numBits)

+        val endCharPos = if (state.charPos == -1) s.numCharsRead else state.charPos + s.numCharsRead

+        val endBitPos = state.bitPos + numBits

+        val currentElement = state.parentElement

+        currentElement.setDataValue(field)

+        return state.withPos(endBitPos, endCharPos, Some(s.next))

+      }

+    }

+  }

 

   def parser: DaffodilParser = new PrimParser(this, e) {

     override def toString = cname + "(" + tm.map { _.prettyExpr } + ")"

 

-    val eName = e.toString()

-

     def parse(start: PState): PState = withParseErrorThrowing(start) {

 

       val (delimsCooked, delimsRegex, delimsParser, vars) = getDelims(start)

@@ -458,12 +489,13 @@
         case None => start

       }

 

-      // TODO: refactor. This check isn't needed in static case. Only dynamic case.

-      if (delimsCooked.filter(x => x == "%WSP*;").length > 0) {

-        // We cannot detect this error until expressions have been evaluated!

-        log(LogLevel.Debug, "%s - Failed due to WSP* detected as a delimiter for lengthKind=delimited", eName)

-        e.schemaDefinitionError("WSP* cannot be used as a delimiter when lengthKind=delimited!")

-      }

+      //      // TODO: refactor. This check isn't needed in static case. Only dynamic case.

+      //      if (delimsCooked.filter(x => x == "%WSP*;").length > 0) {

+      //        // We cannot detect this error until expressions have been evaluated!

+      //        log(LogLevel.Debug, "%s - Failed due to WSP* detected as a delimiter for lengthKind=delimited", eName)

+      //        e.schemaDefinitionError("WSP* cannot be used as a delimiter when lengthKind=delimited!")

+      //      }

+      errorIfDelimsHaveWSPStar(delimsCooked)

 

       log(LogLevel.Debug, "%s - Looking for: %s Count: %s", eName, delimsCooked, delimsCooked.length)

 

@@ -481,20 +513,21 @@
           throw new ParseError(e, Some(postEvalState), "Malformed input, length: %s", mie.getInputLength())

       }

 

-      result match {

-        case f: DelimParseFailure =>

-          return PE(postEvalState, "%s - %s - Parse failed.", this.toString(), eName)

-        case s: DelimParseSuccess => {

-          val field = s.get

-          val numBits = s.numBits

-          log(LogLevel.Debug, "%s - Parsed: %s Parsed Bytes: %s (bits %s)", eName, field, numBits / 8, numBits)

-          val endCharPos = if (postEvalState.charPos == -1) s.numCharsRead else postEvalState.charPos + s.numCharsRead

-          val endBitPos = postEvalState.bitPos + numBits

-          val currentElement = postEvalState.parentElement

-          currentElement.setDataValue(field)

-          return postEvalState.withPos(endBitPos, endCharPos, Some(s.next))

-        }

-      }

+      //      result match {

+      //        case f: DelimParseFailure =>

+      //          return PE(postEvalState, "%s - %s - Parse failed.", this.toString(), eName)

+      //        case s: DelimParseSuccess => {

+      //          val field = s.get

+      //          val numBits = s.numBits

+      //          log(LogLevel.Debug, "%s - Parsed: %s Parsed Bytes: %s (bits %s)", eName, field, numBits / 8, numBits)

+      //          val endCharPos = if (postEvalState.charPos == -1) s.numCharsRead else postEvalState.charPos + s.numCharsRead

+      //          val endBitPos = postEvalState.bitPos + numBits

+      //          val currentElement = postEvalState.parentElement

+      //          currentElement.setDataValue(field)

+      //          return postEvalState.withPos(endBitPos, endCharPos, Some(s.next))

+      //        }

+      //      }

+      processResult(result, postEvalState)

     }

   }

 

@@ -518,19 +551,14 @@
 case class StringDelimitedEndOfDataStatic(e: ElementBase)

   extends StringDelimited(e) {

 

-  def getDelims(pstate: PState): (List[String], Array[String], dp.Parser[String], Option[VariableMap]) = {

-    (staticDelimsCooked, staticDelimsRegex, combinedStaticDelimsParser, None)

-  }

 }

 

-case class StringDelimitedEndOfDataDynamic(e: ElementBase)

-  extends StringDelimited(e) {

-

-  def getDelims(pstate: PState): (List[String], Array[String], dp.Parser[String], Option[VariableMap]) = {

+trait Dynamic { self: StringDelimited =>

+  override def getDelims(pstate: PState): (List[String], Array[String], dp.Parser[String], Option[VariableMap]) = {

     // We must feed variable context out of one evaluation and into the next.

     // So that the resulting variable map has the updated status of all evaluated variables.

     var vars = pstate.variableMap

-    val dynamicDelimsRaw = e.allTerminatingMarkup.filter(x => !x.isConstant).map {

+    val dynamicDelimsRaw = elemBase.allTerminatingMarkup.filter(x => !x.isConstant).map {

       x =>

         {

           val R(res, newVMap) = x.evaluate(pstate.parentElement, vars, pstate)

@@ -538,7 +566,7 @@
           res

         }

     }

-    val dynamicDelimsCooked1 = dynamicDelimsRaw.map(raw => { new ListOfStringValueAsLiteral(raw.toString, e).cooked })

+    val dynamicDelimsCooked1 = dynamicDelimsRaw.map(raw => { new ListOfStringValueAsLiteral(raw.toString, elemBase).cooked })

     val dynamicDelimsCooked = dynamicDelimsCooked1.flatten

     val (dynamicDelimsParser, dynamicDelimsRegex) = dp.generateDelimiter(dynamicDelimsCooked.toSet)

 

@@ -548,148 +576,16 @@
     val delimsRegex = dynamicDelimsRegex.union(staticDelimsRegex)

     (delimsCooked, delimsRegex, delimsParser, Some(vars))

   }

+

+//  override def errorIfDelimsHaveWSPStar(delims: List[String]) = {

+//    // TODO: refactor. This check isn't needed in static case. Only dynamic case.

+//    if (delims.filter(x => x == "%WSP*;").length > 0) {

+//      // We cannot detect this error until expressions have been evaluated!

+//      log(LogLevel.Debug, "%s - Failed due to WSP* detected as a delimiter for lengthKind=delimited", eName)

+//      elemBase.schemaDefinitionError("WSP* cannot be used as a delimiter when lengthKind=delimited!")

+//    }

+//  }

 }

 

-//case class StringDelimitedEndOfData(eArg: ElementBase)

-//  extends Terminal(eArg, true)

-//  with WithParseErrorThrowing with TextReader with Padded {

-//  def e = eArg

-//  lazy val es = e.escapeScheme

-//  lazy val esObj = EscapeScheme.getEscapeScheme(es, e)

-//  lazy val tm = e.allTerminatingMarkup

-//  lazy val cname = toString

-//

-//  val charset = e.knownEncodingCharset

-//

-//  lazy val dp = new DFDLDelimParserStatic(e.knownEncodingStringBitLengthFunction)

-//

-//  // If there are any static delimiters, pre-process them here

-//  lazy val staticDelimsRaw = e.allTerminatingMarkup.filter(x => x.isConstant).map { _.constantAsString }

-//  lazy val staticDelimsCooked1 = staticDelimsRaw.map(raw => { new ListOfStringValueAsLiteral(raw.toString, e).cooked })

-//  lazy val staticDelimsCooked = staticDelimsCooked1.flatten

-//  lazy val (staticDelimsParser, staticDelimsRegex) = dp.generateDelimiter(staticDelimsCooked.toSet)

-//

-//  // DFDL Literal Only

-//  // escapeBlockStart/End

-//  //

-//  // DFDL Expression OR DFDL Literal

-//  // escapeCharacter

-//  // escapeEscapeCharacter

-//

-//  def parseMethod(hasDelim: Boolean, delimsParser: dp.Parser[String], delimsRegex: Array[String],

-//    reader: Reader[Char]): DelimParseResult = {

-//    // TODO: Change DFDLDelimParser calls to get rid of Array.empty[String] since we're only passing a single list the majority of the time.

-//    if (esObj.escapeSchemeKind == EscapeSchemeKind.Block) {

-//      val (escapeBlockParser, escapeBlockEndRegex, escapeEscapeRegex) = dp.generateEscapeBlockParsers2(delimsParser,

-//        esObj.escapeBlockStart, esObj.escapeBlockEnd, esObj.escapeEscapeCharacter, justificationTrim, padChar, true)

-//      val removeEscapeBlocksRegex = dp.removeEscapesBlocksRegex(escapeEscapeRegex, escapeBlockEndRegex)

-//      val parseInputParser = dp.generateInputParser2(dp.emptyParser, delimsParser, Array.empty[String], delimsRegex,

-//        hasDelim, justificationTrim, padChar, true)

-//      dp.parseInputEscapeBlock(escapeBlockParser, dp.emptyParser, delimsParser, reader,

-//        justificationTrim, removeEscapeBlocksRegex, parseInputParser)

-//    } else if (esObj.escapeSchemeKind == EscapeSchemeKind.Character) {

-//      val delimsRegexCombined = dp.combineDelimitersRegex(Array.empty[String], delimsRegex)

-//      val escapeCharacterParser = dp.generateInputEscapeCharacterParser2(delimsParser, delimsRegexCombined,

-//        hasDelim, esObj.escapeCharacter, esObj.escapeEscapeCharacter, justificationTrim, padChar, true)

-//      val esRegex = dp.convertDFDLLiteralToRegex(esObj.escapeCharacter)

-//      val esEsRegex = dp.convertDFDLLiteralToRegex(esObj.escapeEscapeCharacter)

-//      val removeEscapeCharacterRegex = dp.generateRemoveEscapeCharactersSameRegex(esRegex)

-//      val removeUnescapedEscapesRegex = dp.removeUnescapedEscapesRegex(esEsRegex, esRegex)

-//      val removeEscapeEscapesThatEscapeRegex = dp.removeEscapeEscapesThatEscapeRegex(esEsRegex, esRegex)

-//      val removeEscapeRegex = dp.removeEscapeRegex(esRegex)

-//      dp.parseInputEscapeCharacter(escapeCharacterParser, dp.emptyParser, delimsParser, reader,

-//        justificationTrim, removeEscapeCharacterRegex, removeUnescapedEscapesRegex,

-//        removeEscapeEscapesThatEscapeRegex, removeEscapeRegex, esObj.escapeCharacter,

-//        esObj.escapeEscapeCharacter)

-//    } else {

-//      //d.parseInput(Set.empty[String], delimsCooked.toSet, reader, justificationTrim, padChar)

-//      val parseInputParser = dp.generateInputParser2(dp.emptyParser, delimsParser, Array.empty[String], delimsRegex,

-//        hasDelim, justificationTrim, padChar, true)

-//      dp.parseInput(parseInputParser, dp.emptyParser, delimsParser, reader, justificationTrim)

-//    }

-//

-//  }

-//

-//  def parser: DaffodilParser = new PrimParser(this, e) {

-//    override def toString = cname + "(" + tm.map { _.prettyExpr } + ")"

-//    val eName = e.toString()

-//

-//    def parse(start: PState): PState = withParseErrorThrowing(start) {

-//

-//      // We must feed variable context out of one evaluation and into the next.

-//      // So that the resulting variable map has the updated status of all evaluated variables.

-//      var vars = start.variableMap

-//      val dynamicDelimsRaw = e.allTerminatingMarkup.filter(x => !x.isConstant).map {

-//        x =>

-//          {

-//            val R(res, newVMap) = x.evaluate(start.parentElement, vars, start)

-//            vars = newVMap

-//            res

-//          }

-//      }

-//      val dynamicDelimsCooked1 = dynamicDelimsRaw.map(raw => { new ListOfStringValueAsLiteral(raw.toString, e).cooked })

-//      val dynamicDelimsCooked = dynamicDelimsCooked1.flatten

-//      val (dynamicDelimsParser, dynamicDelimsRegex) = dp.generateDelimiter(dynamicDelimsCooked.toSet)

-//

-//      val delimsParser = dp.combineLongest(dynamicDelimsParser.union(staticDelimsParser))

-//      val delimsCooked = dynamicDelimsCooked.union(staticDelimsCooked)

-//      val delimsRegex = dynamicDelimsRegex.union(staticDelimsRegex)

-//      //val delimsRegexCombined = dp.combineDelimitersRegex(Array.empty[String], delimsRegex)

-//      //System.err.println("startCharPos: " + start.charPos)

-//      val postEvalState = start.withVariables(vars)

-//

-//      if (delimsCooked.filter(x => x == "%WSP*;").length > 0) {

-//        // We cannot detect this error until expressions have been evaluated!

-//        log(LogLevel.Debug, "%s - Failed due to WSP* detected as a delimiter for lengthKind=delimited", eName))

-//        e.schemaDefinitionError("WSP* cannot be used as a delimiter when lengthKind=delimited!")

-//      }

-//

-//      log(LogLevel.Debug, "%s - Looking for: %s Count: %s", eName, delimsCooked, delimsCooked.length))

-//

-//      val bytePos = (postEvalState.bitPos >> 3).toInt

-//      log(LogLevel.Debug, "%s - Starting at bit pos: %s", eName, postEvalState.bitPos))

-//      log(LogLevel.Debug, "%s - Starting at byte pos: %s", eName, bytePos))

-//

-//      val reader = getReader(charset, postEvalState.bitPos, postEvalState)

-//      val hasDelim = delimsCooked.length > 0

-//

-//      val result = try {

-//        parseMethod(hasDelim, delimsParser, delimsRegex, reader)

-//      } catch {

-//        case mie: MalformedInputException =>

-//          throw new ParseError(e, Some(postEvalState), "Malformed input, length: %s", mie.getInputLength())

-//      }

-//

-//      result match {

-//        case f: DelimParseFailure =>

-//          return PE(postEvalState, "%s - %s - Parse failed.", this.toString(), eName)

-//        case s: DelimParseSuccess => {

-//          val field = s.get

-//          val numBits = s.numBits

-//          log(LogLevel.Debug, "%s - Parsed: %s Parsed Bytes: %s (bits %s)", eName, field, numBits / 8, numBits))

-//          val endCharPos = if (postEvalState.charPos == -1) s.numCharsRead else postEvalState.charPos + s.numCharsRead

-//          val endBitPos = postEvalState.bitPos + numBits

-//          val currentElement = postEvalState.parentElement

-//          currentElement.setDataValue(field)

-//          return postEvalState.withPos(endBitPos, endCharPos, Some(s.next))

-//        }

-//      }

-//    }

-//  }

-//

-//  def unparser: Unparser = new Unparser(e) {

-//    override def toString = cname + "(" + tm.map { _.prettyExpr } + ")"

-//

-//    def unparse(start: UState): UState =

-//      // withLoggingLevel(LogLevel.Info) 

-//      {

-//        val data = start.currentElement.getText

-//

-//        val encoder = charset.newEncoder()

-//        start.outStream.setEncoder(encoder)

-//        start.outStream.fillCharBuffer(data)

-//        log(LogLevel.Debug, "Unparsed: " + start.outStream.getData))

-//        start

-//      }

-//  }

-//}

+case class StringDelimitedEndOfDataDynamic(e: ElementBase)

+  extends StringDelimited(e) with Dynamic