blob: 884ad9811b9f8416743146d2d363555156611add [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 scala.xml.Node
import scala.xml.Utility
import edu.illinois.ncsa.daffodil.ExecutionMode
import edu.illinois.ncsa.daffodil.schema.annotation.props.gen.EscapeScheme_AnnotationMixin
import edu.illinois.ncsa.daffodil.dpath._
import edu.illinois.ncsa.daffodil.schema.annotation.props.gen.EscapeKind
import edu.illinois.ncsa.daffodil.processors.EscapeSchemeParseEv
import edu.illinois.ncsa.daffodil.processors.EscapeSchemeBlockParseEv
import edu.illinois.ncsa.daffodil.processors.EscapeSchemeCharParseEv
import edu.illinois.ncsa.daffodil.processors.EscapeSchemeUnparseEv
import edu.illinois.ncsa.daffodil.processors.EscapeSchemeBlockUnparseEv
import edu.illinois.ncsa.daffodil.processors.EscapeSchemeCharUnparseEv
import edu.illinois.ncsa.daffodil.processors.EscapeCharEv
import edu.illinois.ncsa.daffodil.processors.EscapeEscapeCharEv
import edu.illinois.ncsa.daffodil.util.Maybe._
final class DFDLEscapeScheme(node: Node, decl: AnnotatedSchemaComponent, defES: DFDLDefineEscapeScheme)
extends DFDLFormatAnnotation(node, decl)
with EscapeScheme_AnnotationMixin
with RawEscapeSchemeRuntimeValuedPropertiesMixin {
final protected override def enclosingComponentDef = Some(defES)
final lazy val referringComponent: Option[SchemaComponent] = Some(defES)
final override def findPropertyOption(pname: String): PropertyLookupResult = {
ExecutionMode.requireCompilerMode // never get properties at runtime, only compile time.
val propNodeSeq = xml.attribute(pname)
propNodeSeq match {
case None => NotFound(Seq(this), Nil, pname) // attribute was not found
case Some(nodeseq) => {
//
// Interesting that attributeName="" produces a Nil nodeseq, not an empty string.
//
// This whole attributes as NodeSeq thing in Scala seems strange, but attributes
// can contain unresolved entities, e.g., quote=""2B || ! 2B""
// so really they do have to return them as node sequences. It requires DTD processing
// to resolve everything, and most code isn't going to process the DTDs. I.e., the scala
// XML library lets your code be the one doing the DTD resolving, so they can't do it for you.
//
nodeseq match {
case Nil => Found("", this, pname) // we want to hand back the empty string as a value.
case _ => Found(nodeseq.toString, this, pname)
}
}
}
}
final def escapeCharacterEv = LV('escapeCharacterEv) {
val qn = this.qNameForProperty("escapeCharacter")
val expr = ExpressionCompilers.String.compile(qn, NodeInfo.NonEmptyString, escapeCharacterRaw)
val ev = new EscapeCharEv(expr, runtimeData)
ev.compile()
ev
}.value
final def optionEscapeEscapeCharacterEv = LV('optionEscapeEscapeCharacterEv) {
val qn = this.qNameForProperty("escapeEscapeCharacter")
escapeEscapeCharacterRaw match {
case Found("", loc, _) => Nope
case found @ Found(v, loc, _) => {
val typeIfStaticallyKnown = NodeInfo.String
val typeIfRuntimeKnown = NodeInfo.NonEmptyString
val expr = ExpressionCompilers.String.compile(qn, typeIfStaticallyKnown, typeIfRuntimeKnown, found)
val ev = new EscapeEscapeCharEv(expr, runtimeData)
ev.compile()
One(ev)
}
}
}.value
final def optionExtraEscapedCharacters = LV('optionExtraEscapedCharacters) {
extraEscapedCharactersRaw match {
case Found("", _, _) => Nope
case Found(v, _, _) => One(v)
}
}.value
final lazy val escapeSchemeParseEv: EscapeSchemeParseEv = {
val espev = escapeKind match {
case EscapeKind.EscapeBlock => new EscapeSchemeBlockParseEv(escapeBlockStart, escapeBlockEnd, optionEscapeEscapeCharacterEv, runtimeData)
case EscapeKind.EscapeCharacter => new EscapeSchemeCharParseEv(escapeCharacterEv, optionEscapeEscapeCharacterEv, runtimeData)
}
espev.compile()
espev
}
final lazy val escapeSchemeUnparseEv: EscapeSchemeUnparseEv = {
val esuev = escapeKind match {
case EscapeKind.EscapeBlock => new EscapeSchemeBlockUnparseEv(escapeBlockStart, escapeBlockEnd, optionEscapeEscapeCharacterEv, optionExtraEscapedCharacters, generateEscapeBlock, runtimeData)
case EscapeKind.EscapeCharacter => new EscapeSchemeCharUnparseEv(escapeCharacterEv, optionEscapeEscapeCharacterEv, optionExtraEscapedCharacters, runtimeData)
}
esuev.compile()
esuev
}
}
final class DFDLDefineEscapeSchemeFactory(node: Node, decl: SchemaDocument)
extends DFDLDefiningAnnotation(node, decl) {
def forComponent(pointOfUse: SchemaComponent) = new DFDLDefineEscapeScheme(node, decl, pointOfUse)
}
final class DFDLDefineEscapeScheme(node: Node, decl: SchemaDocument, pointOfUse: SchemaComponent)
extends DFDLDefiningAnnotation(node, decl) // Note: defineEscapeScheme isn't a format annotation itself.
// with DefineEscapeScheme_AnnotationMixin
{
final override protected def enclosingComponentDef = Some(pointOfUse)
/*
* For diagnostic messages, we need the decl - because that's where the
* escapescheme definition is written.
*
* But for purposes of compilation of expressions, we need the
* nearest enclosing element. That will be made to happen by way of
* the ExpressionCompiler - every schema component potentially has one.
*/
requiredEvaluations(escapeScheme)
lazy val referringComponent: Option[SchemaComponent] = Some(pointOfUse)
lazy val escapeScheme = {
val des = Utility.trim(node)
val res = des match {
case <dfdl:defineEscapeScheme>{ e @ <dfdl:escapeScheme>{ contents @ _* }</dfdl:escapeScheme> }</dfdl:defineEscapeScheme> =>
new DFDLEscapeScheme(e, decl, this)
case _ => SDE("The content of %s is not complete.", des.label)
}
res
}
override def toString(): String = {
"DFDLDefineEscapeScheme." + name
}
}