blob: eac262f3f856a211cecae6cc8517a7a12cc395e4 [file] [log] [blame]
/* Copyright (c) 2012-2015 Tresys Technology, LLC. All rights reserved.
*
* Developed by: Tresys Technology, LLC
* http://www.tresys.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal with
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimers.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimers in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the names of Tresys Technology, nor the names of its contributors
* may be used to endorse or promote products derived from this Software
* without specific prior written permission.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
* SOFTWARE.
*/
package edu.illinois.ncsa.daffodil.dsom
import edu.illinois.ncsa.daffodil.schema.annotation.props.gen._
import edu.illinois.ncsa.daffodil.exceptions.Assert
import scala.collection.mutable.ListBuffer
import edu.illinois.ncsa.daffodil.dpath.NodeInfo
import edu.illinois.ncsa.daffodil.equality._
import edu.illinois.ncsa.daffodil.dpath.NodeInfo.PrimType
/**
* These are the DFDL properties which can have their values come
* from the data stream itself by way of expressions.
*
* TODO: EscapeScheme's have a few more of these runtime properties
* escapeCharacter, and escapeEscapeCharacter.
*/
trait CommonRuntimeValuedPropertiesMixin
extends DFDLBaseTypeMixin
with RawCommonRuntimeValuedPropertiesMixin { decl: SchemaComponent =>
final lazy val byteOrder = LV('byteOrder) { ExpressionCompiler.compile(NodeInfo.NonEmptyString, byteOrderRaw) }.value
final lazy val encoding = LV('encoding) {
this match {
case eb: ElementBase if (eb.isSimpleType && eb.primType =:= PrimType.HexBinary) => {
//
// We treat hex binary as a string in iso-8859-1 encoding.
// That lets us reuse the various string parsing bases to grab the content.
//
ConstantExpression(PrimType.HexBinary, "iso-8859-1")
}
case _ => ExpressionCompiler.compile(NodeInfo.NonEmptyString, encodingRaw)
}
}.value
final lazy val outputNewLine = LV('outputNewLine) {
// First compile is just to take advantage of the expression compiler's ability
// to detect expressions vs. string literals, so we know whether or not to substitute
// for entities.
val ce = ExpressionCompiler.compile(NodeInfo.NonEmptyString, outputNewLineRaw)
val exprOrLiteral = if (ce.isConstant) EntityReplacer { _.replaceAll(ce.constantAsString, Some(decl)) } else outputNewLineRaw.value
val c =
if (ce.isConstant) {
// compile again, since we've now substituted for entities
ExpressionCompiler.compile(NodeInfo.NonEmptyString, Found(exprOrLiteral, outputNewLineRaw.location))
} else ce // use what we already compiled.
if (c.isConstant) {
val s = c.constantAsString
this.schemaDefinitionUnless(!s.contains("%NL;"), "outputNewLine cannot contain NL")
this.schemaDefinitionUnless(!s.contains("%WSP;"), "outputNewLine cannot contain WSP")
this.schemaDefinitionUnless(!s.contains("%WSP+;"), "outputNewLine cannot contain WSP+")
this.schemaDefinitionUnless(!s.contains("%WSP*;"), "outputNewLine cannot contain WSP*")
this.schemaDefinitionUnless(!s.contains("%ES;"), "outputNewLine cannot contain ES")
val validNLs: List[Char] = List('\u000A', '\u000D', '\u0085', '\u2028')
s.foreach(x => {
this.schemaDefinitionUnless(validNLs.contains(x), "'" + x + "' is not a valid new line character for outputNewLine!")
})
}
c
}.value
}
trait DelimitedRuntimeValuedPropertiesMixin
extends CommonRuntimeValuedPropertiesMixin
with RawDelimitedRuntimeValuedPropertiesMixin { decl: SchemaComponent =>
// Can be whitespace separated lists, as a result the entity replacement needs to take place elsewhere
// as it's possible to replace an entity with a whitespace character.
// final lazy val initiator = ExpressionCompiler.compile('String, EntityReplacer.replaceAll(initiatorRaw))
// final lazy val terminator = ExpressionCompiler.compile('String, EntityReplacer.replaceAll(terminatorRaw))
final lazy val initiator = LV('initiator) {
val c = {
val typeIfStaticallyKnown = NodeInfo.String
val typeIfRuntimeKnown = NodeInfo.NonEmptyString
ExpressionCompiler.compile(typeIfStaticallyKnown, typeIfRuntimeKnown, initiatorRaw)
}
if (c.isConstant) {
val s = c.constantAsString
this.schemaDefinitionUnless(!s.contains("%ES;"), "Initiator cannot contain ES")
}
c
}.value
final def initiatorLoc = (this.prettyName, this.path)
final lazy val terminator = LV('terminator) {
val c = {
val typeIfStaticallyKnown = NodeInfo.String
val typeIfRuntimeKnown = NodeInfo.NonEmptyString
ExpressionCompiler.compile(typeIfStaticallyKnown, typeIfRuntimeKnown, terminatorRaw)
}
if (c.isConstant) {
val s = c.constantAsString
this.schemaDefinitionUnless(!s.contains("%ES;"), "Terminator cannot contain ES")
}
c
}.value
final def terminatorLoc = (this.prettyName, this.path)
}
trait ElementRuntimeValuedPropertiesMixin
extends DelimitedRuntimeValuedPropertiesMixin
with OccursAGMixin
with LengthAGMixin
with SimpleTypeRuntimeValuedPropertiesMixin
with RawElementRuntimeValuedPropertiesMixin { decl: ElementBase =>
final lazy val length = LV('length) {
ExpressionCompiler.compile(NodeInfo.UnsignedLong, lengthRaw)
}.value
//
// The occursCount expression is written on the array element, but that expression
// is actually evaluated before any instances of the element exist. Hence, an
// expression like { ../c } that appears to be reaching back to a prior peer to get
// the count... well that expression gets evaluated while we are in the parent context
// hence if we literally execute the ".." we'll be one element too high in the
// infoset.
//
// So we adjust the expression so that the context is as if on the parent.
//
// Not at all sure why this worked with Saxon, but in our new Infoset and DPath
// implementation, the ".." does get literally evaluated.
//
final lazy val occursCount = LV('occursCount) {
val isEvaluatedAbove = true
ExpressionCompiler.compile(NodeInfo.UnsignedLong, occursCountRaw, isEvaluatedAbove) //NodeInfo.UnsignedInt
}.value
}
trait SequenceRuntimeValuedPropertiesMixin
extends DelimitedRuntimeValuedPropertiesMixin
with Sequence_AnnotationMixin
with RawSequenceRuntimeValuedPropertiesMixin { decl: GroupBase =>
final lazy val separator = LV('separator) {
val c = {
val typeIfStaticallyKnown = NodeInfo.String
val typeIfRuntimeKnown = NodeInfo.NonEmptyString
ExpressionCompiler.compile(typeIfStaticallyKnown, typeIfRuntimeKnown, separatorRaw)
}
if (c.isConstant) {
val s = c.constantAsString
this.schemaDefinitionUnless(!s.contains("%ES;"), "Separator cannot contain ES")
}
c
}.value
final def separatorLoc = (this.prettyName, this.path)
}
trait SimpleTypeRuntimeValuedPropertiesMixin
extends CommonRuntimeValuedPropertiesMixin
with DFDLSimpleTypeMixin
with RawSimpleTypeRuntimeValuedPropertiesMixin { decl: SchemaComponent =>
final lazy val textStandardDecimalSeparator = LV('textStandardDecimalSeparator) {
val c = ExpressionCompiler.compile(NodeInfo.String, textStandardDecimalSeparatorRaw)
c
}.value
final lazy val textStandardGroupingSeparator = LV('textStandardGroupingSeparator) {
val c = ExpressionCompiler.compile(NodeInfo.String, textStandardGroupingSeparatorRaw)
c
}.value
final lazy val textStandardExponentRep = LV('textStandardExponentRep) {
val c = ExpressionCompiler.compile(NodeInfo.String, textStandardExponentRepRaw)
c
}.value
final lazy val binaryFloatRep = LV('binaryFloatRep) {
ExpressionCompiler.compile(NodeInfo.NonEmptyString, binaryFloatRepRaw)
}.value
// TODO: Will need to 'evaluate' and perform entity replacement on textBooleanTrueRep in Parser where it is used.
final lazy val textBooleanTrueRep = LV('textBooleanTrueRep) {
val c = ExpressionCompiler.compile(NodeInfo.NonEmptyString, textBooleanTrueRepRaw)
if (c.isConstant) {
val s = c.constantAsString
this.schemaDefinitionUnless(!s.contains("%NL;"), "textBooleanTrueRep cannot contain NL")
this.schemaDefinitionUnless(!s.contains("%WSP;"), "textBooleanTrueRep cannot contain WSP")
this.schemaDefinitionUnless(!s.contains("%WSP*;"), "textBooleanTrueRep cannot contain WSP*")
this.schemaDefinitionUnless(!s.contains("%WSP+;"), "textBooleanTrueRep cannot contain WSP+")
this.schemaDefinitionUnless(!s.contains("%ES;"), "textBooleanTrueRep cannot contain ES")
}
c
}.value
// TODO: Will need to 'evaluate' and perform entity replacement on textBooleanFalseRep in Parser where it is used.
final lazy val textBooleanFalseRep = LV('textBooleanFalseRep) {
val c = ExpressionCompiler.compile(NodeInfo.NonEmptyString, textBooleanFalseRepRaw)
if (c.isConstant) {
val s = c.constantAsString
this.schemaDefinitionUnless(!s.contains("%NL;"), "textBooleanFalseRep cannot contain NL")
this.schemaDefinitionUnless(!s.contains("%WSP;"), "textBooleanFalseRep cannot contain WSP")
this.schemaDefinitionUnless(!s.contains("%WSP*;"), "textBooleanFalseRep cannot contain WSP*")
this.schemaDefinitionUnless(!s.contains("%WSP+;"), "textBooleanFalseRep cannot contain WSP+")
this.schemaDefinitionUnless(!s.contains("%ES;"), "textBooleanFalseRep cannot contain ES")
}
c
}.value
}