stevedlawrence commented on a change in pull request #369:
URL: https://github.com/apache/incubator-daffodil/pull/369#discussion_r413217592
##########
File path:
daffodil-core/src/main/scala/org/apache/daffodil/dsom/DFDLStatementMixin.scala
##########
@@ -202,6 +208,13 @@ trait ProvidesDFDLStatementMixin extends ThrowsSDE with
HasTermCheck { self: Ann
svs
}
+ private def checkDistinctNewVariableInstances(nvis:
Seq[DFDLNewVariableInstance]) = {
+ val names = nvis.map { _.defv.globalQName }
+ val areAllDistinct = names.distinct.size == names.size
+ schemaDefinitionUnless(areAllDistinct, "Variables referenced by
newVariableInstances must all be distinct within the same scope: %s", names)
Review comment:
Might be helpful to print the variables that are duplicated rather than
all of the names.
##########
File path:
daffodil-core/src/main/scala/org/apache/daffodil/grammar/HasStatementsGrammarMixin.scala
##########
@@ -18,10 +18,11 @@
package org.apache.daffodil.grammar
import org.apache.daffodil.dsom.Term
+import org.apache.daffodil.dsom.DFDLNewVariableInstance
trait HasStatementsGrammarMixin extends GrammarMixin { self: Term =>
- private lazy val statementGrams = statements.map { _.gram(self) }
+ private lazy val statementGrams = statements.filter{ st =>
!st.isInstanceOf[DFDLNewVariableInstance] }.map { _.gram(self) }
Review comment:
Why filter out NVE? I guess because NVE isn't a dfdlStatementEvaluation
and is handled differently? Maybe this variable (or trait) needs a different
name or maybe we just move this into the dfdlStatementEvaluations variable?
Nothing else outside of this trait uses statementGrams. What are the other
DFDLStatements? Does it make sense to collect those that we explictly want
rather than filtering out NVE?
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -53,28 +54,54 @@ case object VariableRead extends VariableState
case object VariableInProcess extends VariableState
/**
- * Core tuple of a pure functional "state" for variables.
+ * Core tuple of a "state" for variables.
*/
-case class Variable(state: VariableState, value: DataValuePrimitiveNullable,
rd: VariableRuntimeData, defaultValueExpr: Maybe[CompiledExpression[AnyRef]])
extends Serializable
+case class Variable(
+ var state: VariableState,
+ var value: DataValuePrimitiveNullable,
+ rd: VariableRuntimeData,
+ defaultValueExpr: Maybe[CompiledExpression[AnyRef]],
+ var priorState: VariableState = VariableUndefined,
+ var priorValue: DataValuePrimitiveNullable = DataValue.NoValue)
+ extends Serializable {
+
+ def copy(
+ state: VariableState = state,
+ value: DataValuePrimitiveNullable = value,
+ rd: VariableRuntimeData = rd,
+ defaultValueExpr: Maybe[CompiledExpression[AnyRef]] = defaultValueExpr,
+ priorState: VariableState = priorState,
+ priorValue: DataValuePrimitiveNullable = priorValue) =
+ new Variable(state, value, rd, defaultValueExpr, priorState, priorValue)
Review comment:
Does this add any extra value over what a case class provides? Cases
class I think should generate the same thing, right?
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -129,54 +156,66 @@ final class VariableBox(initialVMap: VariableMap) {
* The DPath implementation must be made to implement the
* no-set-after-default-value-has-been-read behavior. This requires that
reading the variables causes a state transition.
*/
-class VariableMap private(vTable: Map[GlobalQName, List[List[Variable]]])
+class VariableMap private(vTable: Map[GlobalQName, MStackOf[Variable]])
extends Serializable {
def this(topLevelVRDs: Seq[VariableRuntimeData] = Nil) =
- this(topLevelVRDs.map {
+ this(Map(topLevelVRDs.map {
vrd =>
val variab = vrd.newVariableInstance
- (vrd.globalQName, List(List(variab)))
- }.toMap)
+ val stack = new MStackOf[Variable]
+ stack.push(variab)
+ (vrd.globalQName, stack)
+ }: _*))
override def toString(): String = {
"VariableMap(" + vTable.mkString(" | ") + ")"
}
+ def copy(): VariableMap = {
+ val table = Map[GlobalQName, MStackOf[Variable]]()
+ vTable.foreach { case (k: GlobalQName, s: MStackOf[Variable]) => {
+ val newStack= new MStackOf[Variable]()
+ newStack.push(s.top.copy())
+ table(k) = newStack
+ }}
+
+ new VariableMap(table)
+ }
+
def find(qName: GlobalQName): Option[Variable] = {
val optVrd = getVariableRuntimeData(qName)
- val optLists = optVrd.flatMap { vrd => vTable.get(vrd.globalQName) }
- val variab = optLists.flatMap { lists => lists.flatMap {
- _.toStream
- }.headOption
+ val optStack = optVrd.flatMap { vrd => vTable.get(vrd.globalQName) }
+ val variab = {
+ if (optStack.isDefined)
+ Some(optStack.get.top)
+ else
+ None
}
variab
}
def getVariableRuntimeData(qName: GlobalQName): Option[VariableRuntimeData]
= {
- val optLists = vTable.get(qName)
- optLists match {
+ val optStack = vTable.get(qName)
+ optStack match {
case None => None // no such variable.
- case Some(lists) => {
- val flatLists = lists.flatten
- Assert.invariant(flatLists.length > 0)
- val varObj = flatLists.head
+ case Some(stack) => {
+ val varObj = stack.top
Some(varObj.rd)
}
}
}
- lazy val context = Assert.invariantFailed("unused.")
-
- private def mkVMapForNewVariable(newVar: Variable, firstTier:
List[Variable], enclosingScopes: List[List[Variable]]) = {
- val newMap = vTable + ((newVar.rd.globalQName, (newVar :: firstTier) ::
enclosingScopes))
- new VariableMap(newMap)
+ def getVaraibleStack(qName: GlobalQName): Option[MStackOf[Variable]] = {
Review comment:
Or find() and getVariableRUntimeData() could use this.
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -129,54 +156,66 @@ final class VariableBox(initialVMap: VariableMap) {
* The DPath implementation must be made to implement the
* no-set-after-default-value-has-been-read behavior. This requires that
reading the variables causes a state transition.
*/
-class VariableMap private(vTable: Map[GlobalQName, List[List[Variable]]])
+class VariableMap private(vTable: Map[GlobalQName, MStackOf[Variable]])
extends Serializable {
def this(topLevelVRDs: Seq[VariableRuntimeData] = Nil) =
- this(topLevelVRDs.map {
+ this(Map(topLevelVRDs.map {
vrd =>
val variab = vrd.newVariableInstance
- (vrd.globalQName, List(List(variab)))
- }.toMap)
+ val stack = new MStackOf[Variable]
+ stack.push(variab)
+ (vrd.globalQName, stack)
+ }: _*))
override def toString(): String = {
"VariableMap(" + vTable.mkString(" | ") + ")"
}
+ def copy(): VariableMap = {
Review comment:
I think this needs a comment that this isn't really a copy. It looks
like it's creating a new variable map where each stack just contains the top of
the existing stack. Is this intentional?
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -185,96 +224,84 @@ class VariableMap private(vTable: Map[GlobalQName,
List[List[Variable]]])
* shows that the variable has been read (state VariableRead), when the
variable hadn't
* previously been read yet.
*/
- def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
(DataValuePrimitive, VariableMap) = {
+ def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
DataValuePrimitive = {
val referringContext: VariableRuntimeData = vrd
val varQName = vrd.globalQName
- val lists = vTable.get(varQName)
- lists match {
-
- case Some(firstTier :: enclosingScopes) =>
- firstTier match {
-
- case Variable(VariableRead, v, ctxt, _) :: rest if (v.isDefined) =>
(v.getNonNullable, this)
-
- case Variable(st, v, ctxt, defExpr) :: rest if ((v.isDefined) && (st
== VariableDefined || st == VariableSet)) => {
- val newVar = Variable(VariableRead, v, ctxt, defExpr)
- val vmap = mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- val converted = v.getNonNullable // already converted
- (converted, vmap)
- }
-
- case _ => {
- // Fix DFDL-766
- throw new VariableHasNoValue(varQName, referringContext)
- // Runtime error:
- // referringContext.SDE(msg, varQName)
- }
+ val stack = vTable.get(varQName)
Review comment:
Should we use the new getVariableStack()? Or should that function be
removed? Not sure if anything uses it.
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -129,54 +156,66 @@ final class VariableBox(initialVMap: VariableMap) {
* The DPath implementation must be made to implement the
* no-set-after-default-value-has-been-read behavior. This requires that
reading the variables causes a state transition.
*/
-class VariableMap private(vTable: Map[GlobalQName, List[List[Variable]]])
+class VariableMap private(vTable: Map[GlobalQName, MStackOf[Variable]])
extends Serializable {
def this(topLevelVRDs: Seq[VariableRuntimeData] = Nil) =
- this(topLevelVRDs.map {
+ this(Map(topLevelVRDs.map {
vrd =>
val variab = vrd.newVariableInstance
- (vrd.globalQName, List(List(variab)))
- }.toMap)
+ val stack = new MStackOf[Variable]
+ stack.push(variab)
+ (vrd.globalQName, stack)
+ }: _*))
override def toString(): String = {
"VariableMap(" + vTable.mkString(" | ") + ")"
}
+ def copy(): VariableMap = {
+ val table = Map[GlobalQName, MStackOf[Variable]]()
+ vTable.foreach { case (k: GlobalQName, s: MStackOf[Variable]) => {
+ val newStack= new MStackOf[Variable]()
+ newStack.push(s.top.copy())
+ table(k) = newStack
+ }}
+
+ new VariableMap(table)
+ }
+
def find(qName: GlobalQName): Option[Variable] = {
val optVrd = getVariableRuntimeData(qName)
- val optLists = optVrd.flatMap { vrd => vTable.get(vrd.globalQName) }
- val variab = optLists.flatMap { lists => lists.flatMap {
- _.toStream
- }.headOption
+ val optStack = optVrd.flatMap { vrd => vTable.get(vrd.globalQName) }
+ val variab = {
+ if (optStack.isDefined)
+ Some(optStack.get.top)
+ else
+ None
Review comment:
Can this just instead just do something like:
```scala
val optStack = vTable.get(qName)
val variab = ...
```
If this uses getVariableRuntimeData it's going to do two looks up. Once in
getVariableRuntimeData to find the right stack and get the rd of the the thing
on the top, then another to find that stack that getVariableRuntimeData already
found.
And then getVariableRuntimeData can just be
```
val optVariable = find(qName)
if (optVariable.isDefined) Some(optVariable.get.rd) else None
```
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -185,96 +224,84 @@ class VariableMap private(vTable: Map[GlobalQName,
List[List[Variable]]])
* shows that the variable has been read (state VariableRead), when the
variable hadn't
* previously been read yet.
*/
- def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
(DataValuePrimitive, VariableMap) = {
+ def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
DataValuePrimitive = {
val referringContext: VariableRuntimeData = vrd
val varQName = vrd.globalQName
- val lists = vTable.get(varQName)
- lists match {
-
- case Some(firstTier :: enclosingScopes) =>
- firstTier match {
-
- case Variable(VariableRead, v, ctxt, _) :: rest if (v.isDefined) =>
(v.getNonNullable, this)
-
- case Variable(st, v, ctxt, defExpr) :: rest if ((v.isDefined) && (st
== VariableDefined || st == VariableSet)) => {
- val newVar = Variable(VariableRead, v, ctxt, defExpr)
- val vmap = mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- val converted = v.getNonNullable // already converted
- (converted, vmap)
- }
-
- case _ => {
- // Fix DFDL-766
- throw new VariableHasNoValue(varQName, referringContext)
- // Runtime error:
- // referringContext.SDE(msg, varQName)
- }
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ val variable = stack.get.top
+ variable.state match {
+ case VariableRead if (variable.value.isDefined) =>
variable.value.getNonNullable
+ case VariableDefined | VariableSet if (variable.value.isDefined) => {
+ variable.setState(VariableRead)
+ variable.value.getNonNullable
}
-
- case Some(Nil) => Assert.invariantFailed()
-
- case None => {
- // Compile time error:
- referringContext.SDE("Variable map (compilation): unknown variable
%s", varQName)
+ case _ => throw new VariableHasNoValue(varQName, referringContext)
}
- }
+ } else
+ referringContext.SDE("Variable map (compilation): unknown variable %s",
varQName) // Fix DFDL-766
Review comment:
Not sure this comment adds anything. I'd just remove it.
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -340,6 +393,6 @@ class VariableMap private(vTable: Map[GlobalQName,
List[List[Variable]]])
}
case x => Assert.invariantFailed("variables data structure not as
expected. Should not be " + x)
}
- }
+ }*/
Review comment:
Remove comment.
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -185,96 +224,84 @@ class VariableMap private(vTable: Map[GlobalQName,
List[List[Variable]]])
* shows that the variable has been read (state VariableRead), when the
variable hadn't
* previously been read yet.
*/
- def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
(DataValuePrimitive, VariableMap) = {
+ def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
DataValuePrimitive = {
val referringContext: VariableRuntimeData = vrd
val varQName = vrd.globalQName
- val lists = vTable.get(varQName)
- lists match {
-
- case Some(firstTier :: enclosingScopes) =>
- firstTier match {
-
- case Variable(VariableRead, v, ctxt, _) :: rest if (v.isDefined) =>
(v.getNonNullable, this)
-
- case Variable(st, v, ctxt, defExpr) :: rest if ((v.isDefined) && (st
== VariableDefined || st == VariableSet)) => {
- val newVar = Variable(VariableRead, v, ctxt, defExpr)
- val vmap = mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- val converted = v.getNonNullable // already converted
- (converted, vmap)
- }
-
- case _ => {
- // Fix DFDL-766
- throw new VariableHasNoValue(varQName, referringContext)
- // Runtime error:
- // referringContext.SDE(msg, varQName)
- }
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ val variable = stack.get.top
+ variable.state match {
+ case VariableRead if (variable.value.isDefined) =>
variable.value.getNonNullable
+ case VariableDefined | VariableSet if (variable.value.isDefined) => {
+ variable.setState(VariableRead)
+ variable.value.getNonNullable
}
-
- case Some(Nil) => Assert.invariantFailed()
-
- case None => {
- // Compile time error:
- referringContext.SDE("Variable map (compilation): unknown variable
%s", varQName)
+ case _ => throw new VariableHasNoValue(varQName, referringContext)
}
- }
+ } else
+ referringContext.SDE("Variable map (compilation): unknown variable %s",
varQName) // Fix DFDL-766
}
/**
* Assigns a variable, returning a new VariableMap which shows the state of
the variable.
*/
- def setVariable(vrd: VariableRuntimeData, newValue: DataValuePrimitive,
referringContext: ThrowsSDE, pstate: ParseOrUnparseState): VariableMap = {
+ def setVariable(vrd: VariableRuntimeData, newValue: DataValuePrimitive,
referringContext: ThrowsSDE, pstate: ParseOrUnparseState) = {
val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ val variable = stack.get.top
+ variable.state match {
+ case VariableSet => {
+ referringContext.SDE("Cannot set variable %s twice. State was: %s.
Existing value: %s",
+ variable.rd.globalQName, VariableSet, variable.value)
+ }
- vTable.get(varQName) match {
-
- case None => referringContext.schemaDefinitionError("unknown variable
%s", varQName)
-
- // There should always be a list with at least one tier in it (the
global tier).
- case x @ Some(firstTier :: enclosingScopes) => {
- firstTier match {
-
- case Variable(VariableDefined, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
-
- case Variable(VariableUndefined, DataValue.NoValue, ctxt,
defaultExpr) :: rest => {
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
-
- case Variable(VariableSet, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- referringContext.SDE("Cannot set variable %s twice. State was: %s.
Existing value: %s", ctxt.globalQName, VariableSet, v)
- }
-
- case Variable(VariableRead, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- // referringContext.SDE
- pstate.SDW("Cannot set variable %s after reading the default
value. State was: %s. Existing value: %s", ctxt.globalQName, VariableSet, v)
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
+ case VariableRead => {
+ referringContext.SDE("Cannot set variable %s after reading the
default value. State was: %s. Existing value: %s",
+ variable.rd.globalQName, VariableSet, variable.value)
+ }
- case _ => Assert.invariantFailed("variable map internal list
structure not as expected: " + x)
+ case _ => {
+ variable.setValue(VariableUtils.convert(newValue.getAnyRef.toString,
variable.rd))
+ variable.setState(VariableSet)
}
}
- case x => Assert.invariantFailed("variables data structure not as
expected. Should not be " + x)
}
}
+ /**
+ * Creates a new instance of a variable
+ */
+ def newVariableInstance(vrd: VariableRuntimeData) = {
+ val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ stack.get.push(vrd.newVariableInstance)
+ }
Review comment:
In what case is stack not defined? Should this be an Assertion that
stack.isDefined instead
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ExpressionEvaluatingParsers.scala
##########
@@ -158,25 +158,24 @@ class SetVariableParser(expr: CompiledExpression[AnyRef],
decl: VariableRuntimeD
}
}
-class NewVariableInstanceStartParser(
- override val context: RuntimeData)
+class NewVariableInstanceStartParser(override val context: VariableRuntimeData)
extends PrimParser {
- context.notYetImplemented("newVariableInstance")
override lazy val runtimeDependencies = Vector()
- def parse(pstate: PState) = {
- context.notYetImplemented("newVariableInstance")
+ def parse(start: PState): Unit = {
+ log(LogLevel.Debug, "This is %s", toString) // important. Don't toString
unless we have to log.
+ if (start.processorStatus.isInstanceOf[Failure]) return
+ // val vmap = start.variableMap
+ start.newVariableInstance(context)
Review comment:
In what case does the previous processor fail but we continue to call
this one? If we do need thi heck, can you remove the return, so it's something
like
```
if (start.processorStatus == Success) {
start.newVariableInstance(contxt)
}
```
Can you remove the comment.
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/PState.scala
##########
@@ -166,6 +168,9 @@ final class PState private (
private val discriminatorStack = MStackOfBoolean()
discriminatorStack.push(false)
+ private val changedVariablesStack = new
MStackOf[mutable.MutableList[GlobalQName]]()
Review comment:
Can you add a comment describing what this is? It's not clear what a
stack of lists of qnames is used for.
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ExpressionEvaluatingParsers.scala
##########
@@ -158,25 +158,24 @@ class SetVariableParser(expr: CompiledExpression[AnyRef],
decl: VariableRuntimeD
}
}
-class NewVariableInstanceStartParser(
- override val context: RuntimeData)
+class NewVariableInstanceStartParser(override val context: VariableRuntimeData)
extends PrimParser {
- context.notYetImplemented("newVariableInstance")
override lazy val runtimeDependencies = Vector()
- def parse(pstate: PState) = {
- context.notYetImplemented("newVariableInstance")
+ def parse(start: PState): Unit = {
+ log(LogLevel.Debug, "This is %s", toString) // important. Don't toString
unless we have to log.
Review comment:
Remove ebug message. I don't think this provides anything extra.
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/PState.scala
##########
@@ -265,17 +276,29 @@ final class PState private (
}
def setVariable(vrd: VariableRuntimeData, newValue: DataValuePrimitive,
referringContext: VariableRuntimeData, pstate: PState) {
- this.setVariableMap(variableMap.setVariable(vrd, newValue,
referringContext, pstate))
+ variableMap.setVariable(vrd, newValue, referringContext, pstate)
+ changedVariablesStack.top += vrd.globalQName
+ }
Review comment:
Do we also need to modify changedVariableStack if a variable is read,
since that does change the state of the variable? Or is resetting that handled
somehow else?
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -185,96 +224,84 @@ class VariableMap private(vTable: Map[GlobalQName,
List[List[Variable]]])
* shows that the variable has been read (state VariableRead), when the
variable hadn't
* previously been read yet.
*/
- def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
(DataValuePrimitive, VariableMap) = {
+ def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
DataValuePrimitive = {
val referringContext: VariableRuntimeData = vrd
val varQName = vrd.globalQName
- val lists = vTable.get(varQName)
- lists match {
-
- case Some(firstTier :: enclosingScopes) =>
- firstTier match {
-
- case Variable(VariableRead, v, ctxt, _) :: rest if (v.isDefined) =>
(v.getNonNullable, this)
-
- case Variable(st, v, ctxt, defExpr) :: rest if ((v.isDefined) && (st
== VariableDefined || st == VariableSet)) => {
- val newVar = Variable(VariableRead, v, ctxt, defExpr)
- val vmap = mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- val converted = v.getNonNullable // already converted
- (converted, vmap)
- }
-
- case _ => {
- // Fix DFDL-766
- throw new VariableHasNoValue(varQName, referringContext)
- // Runtime error:
- // referringContext.SDE(msg, varQName)
- }
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ val variable = stack.get.top
+ variable.state match {
+ case VariableRead if (variable.value.isDefined) =>
variable.value.getNonNullable
+ case VariableDefined | VariableSet if (variable.value.isDefined) => {
+ variable.setState(VariableRead)
+ variable.value.getNonNullable
}
-
- case Some(Nil) => Assert.invariantFailed()
-
- case None => {
- // Compile time error:
- referringContext.SDE("Variable map (compilation): unknown variable
%s", varQName)
+ case _ => throw new VariableHasNoValue(varQName, referringContext)
}
- }
+ } else
+ referringContext.SDE("Variable map (compilation): unknown variable %s",
varQName) // Fix DFDL-766
}
/**
* Assigns a variable, returning a new VariableMap which shows the state of
the variable.
*/
- def setVariable(vrd: VariableRuntimeData, newValue: DataValuePrimitive,
referringContext: ThrowsSDE, pstate: ParseOrUnparseState): VariableMap = {
+ def setVariable(vrd: VariableRuntimeData, newValue: DataValuePrimitive,
referringContext: ThrowsSDE, pstate: ParseOrUnparseState) = {
val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ val variable = stack.get.top
+ variable.state match {
+ case VariableSet => {
+ referringContext.SDE("Cannot set variable %s twice. State was: %s.
Existing value: %s",
+ variable.rd.globalQName, VariableSet, variable.value)
+ }
- vTable.get(varQName) match {
-
- case None => referringContext.schemaDefinitionError("unknown variable
%s", varQName)
-
- // There should always be a list with at least one tier in it (the
global tier).
- case x @ Some(firstTier :: enclosingScopes) => {
- firstTier match {
-
- case Variable(VariableDefined, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
-
- case Variable(VariableUndefined, DataValue.NoValue, ctxt,
defaultExpr) :: rest => {
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
-
- case Variable(VariableSet, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- referringContext.SDE("Cannot set variable %s twice. State was: %s.
Existing value: %s", ctxt.globalQName, VariableSet, v)
- }
-
- case Variable(VariableRead, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- // referringContext.SDE
- pstate.SDW("Cannot set variable %s after reading the default
value. State was: %s. Existing value: %s", ctxt.globalQName, VariableSet, v)
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
+ case VariableRead => {
+ referringContext.SDE("Cannot set variable %s after reading the
default value. State was: %s. Existing value: %s",
+ variable.rd.globalQName, VariableSet, variable.value)
+ }
- case _ => Assert.invariantFailed("variable map internal list
structure not as expected: " + x)
+ case _ => {
+ variable.setValue(VariableUtils.convert(newValue.getAnyRef.toString,
variable.rd))
+ variable.setState(VariableSet)
}
}
- case x => Assert.invariantFailed("variables data structure not as
expected. Should not be " + x)
}
}
+ /**
+ * Creates a new instance of a variable
+ */
+ def newVariableInstance(vrd: VariableRuntimeData) = {
+ val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ stack.get.push(vrd.newVariableInstance)
+ }
+ }
+
+ def removeVariableInstance(vrd: VariableRuntimeData) {
+ val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ stack.get.pop
+ }
Review comment:
Same here, should there be an assertion that stack is defined?
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/VariableMap1.scala
##########
@@ -185,96 +224,84 @@ class VariableMap private(vTable: Map[GlobalQName,
List[List[Variable]]])
* shows that the variable has been read (state VariableRead), when the
variable hadn't
* previously been read yet.
*/
- def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
(DataValuePrimitive, VariableMap) = {
+ def readVariable(vrd: VariableRuntimeData, referringContext: ThrowsSDE):
DataValuePrimitive = {
val referringContext: VariableRuntimeData = vrd
val varQName = vrd.globalQName
- val lists = vTable.get(varQName)
- lists match {
-
- case Some(firstTier :: enclosingScopes) =>
- firstTier match {
-
- case Variable(VariableRead, v, ctxt, _) :: rest if (v.isDefined) =>
(v.getNonNullable, this)
-
- case Variable(st, v, ctxt, defExpr) :: rest if ((v.isDefined) && (st
== VariableDefined || st == VariableSet)) => {
- val newVar = Variable(VariableRead, v, ctxt, defExpr)
- val vmap = mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- val converted = v.getNonNullable // already converted
- (converted, vmap)
- }
-
- case _ => {
- // Fix DFDL-766
- throw new VariableHasNoValue(varQName, referringContext)
- // Runtime error:
- // referringContext.SDE(msg, varQName)
- }
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ val variable = stack.get.top
+ variable.state match {
+ case VariableRead if (variable.value.isDefined) =>
variable.value.getNonNullable
+ case VariableDefined | VariableSet if (variable.value.isDefined) => {
+ variable.setState(VariableRead)
+ variable.value.getNonNullable
}
-
- case Some(Nil) => Assert.invariantFailed()
-
- case None => {
- // Compile time error:
- referringContext.SDE("Variable map (compilation): unknown variable
%s", varQName)
+ case _ => throw new VariableHasNoValue(varQName, referringContext)
}
- }
+ } else
+ referringContext.SDE("Variable map (compilation): unknown variable %s",
varQName) // Fix DFDL-766
}
/**
* Assigns a variable, returning a new VariableMap which shows the state of
the variable.
*/
- def setVariable(vrd: VariableRuntimeData, newValue: DataValuePrimitive,
referringContext: ThrowsSDE, pstate: ParseOrUnparseState): VariableMap = {
+ def setVariable(vrd: VariableRuntimeData, newValue: DataValuePrimitive,
referringContext: ThrowsSDE, pstate: ParseOrUnparseState) = {
val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ val variable = stack.get.top
+ variable.state match {
+ case VariableSet => {
+ referringContext.SDE("Cannot set variable %s twice. State was: %s.
Existing value: %s",
+ variable.rd.globalQName, VariableSet, variable.value)
+ }
- vTable.get(varQName) match {
-
- case None => referringContext.schemaDefinitionError("unknown variable
%s", varQName)
-
- // There should always be a list with at least one tier in it (the
global tier).
- case x @ Some(firstTier :: enclosingScopes) => {
- firstTier match {
-
- case Variable(VariableDefined, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
-
- case Variable(VariableUndefined, DataValue.NoValue, ctxt,
defaultExpr) :: rest => {
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
-
- case Variable(VariableSet, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- referringContext.SDE("Cannot set variable %s twice. State was: %s.
Existing value: %s", ctxt.globalQName, VariableSet, v)
- }
-
- case Variable(VariableRead, v, ctxt, defaultExpr) :: rest if
(v.isDefined) => {
- // referringContext.SDE
- pstate.SDW("Cannot set variable %s after reading the default
value. State was: %s. Existing value: %s", ctxt.globalQName, VariableSet, v)
- val newVar = Variable(VariableSet,
VariableUtils.convert(newValue.getAnyRef.toString, ctxt), ctxt, defaultExpr)
- mkVMapForNewVariable(newVar, firstTier, enclosingScopes)
- }
+ case VariableRead => {
+ referringContext.SDE("Cannot set variable %s after reading the
default value. State was: %s. Existing value: %s",
+ variable.rd.globalQName, VariableSet, variable.value)
+ }
- case _ => Assert.invariantFailed("variable map internal list
structure not as expected: " + x)
+ case _ => {
+ variable.setValue(VariableUtils.convert(newValue.getAnyRef.toString,
variable.rd))
+ variable.setState(VariableSet)
}
}
- case x => Assert.invariantFailed("variables data structure not as
expected. Should not be " + x)
}
}
+ /**
+ * Creates a new instance of a variable
+ */
+ def newVariableInstance(vrd: VariableRuntimeData) = {
+ val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ stack.get.push(vrd.newVariableInstance)
+ }
+ }
+
+ def removeVariableInstance(vrd: VariableRuntimeData) {
+ val varQName = vrd.globalQName
+ val stack = vTable.get(varQName)
+ if (stack.isDefined) {
+ stack.get.pop
+ }
+ }
+
+
private lazy val externalVarGlobalQNames: Seq[GlobalQName] =
vTable.map { pair => pair match {
- case (gqn, firstTier :: _) => firstTier match {
- case (variable@Variable(_, v, ctxt, _)) :: _ if (ctxt.external) =>
variable.rd.globalQName
+ case (gqn, stack) if (stack.top.rd.external) => {
+ stack.top.rd.globalQName
}
- case (_, Nil) => Assert.invariantFailed("empty tier")
+ case (_, stack) if (stack.isEmpty) => Assert.invariantFailed("empty
tier")
Review comment:
Does stack.top throw an exception if the stack is empty? Seems like it's
never possible to hit this case.
----------------------------------------------------------------
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.
For queries about this service, please contact Infrastructure at:
[email protected]