blob: 045f0f073cda6360bd7a5e6f07c4f052e40b762c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.daffodil.processors.dfa
import scala.collection.mutable.ArrayBuffer
import org.apache.daffodil.processors.CharDelim
import org.apache.daffodil.processors.DelimBase
import org.apache.daffodil.processors.Delimiter
import org.apache.daffodil.processors.ESDelim
import org.apache.daffodil.processors.NLDelim
import org.apache.daffodil.processors.WSPDelim
import org.apache.daffodil.processors.WSPPlusDelim
import org.apache.daffodil.processors.WSPStarDelim
import org.apache.daffodil.processors.parsers.DelimiterTextType
import org.apache.daffodil.dsom.DPathCompileInfo
object CreateDelimiterDFA {
/**
* Constructs an Array of states reflecting the delimiters only.
* StateNum is offset by stateOffset
*/
protected def apply(delimType: DelimiterTextType.Type, ci: DPathCompileInfo, delimiter: Seq[DelimBase], delimiterStr: String, outputNewLine: String): DFADelimiter = {
val allStates: ArrayBuffer[State] = ArrayBuffer.empty
buildTransitions(delimiter, allStates, false)
val unparseValue = delimiter.map { _.unparseValue(outputNewLine) }.mkString
new DFADelimiterImplUnparse(delimType, allStates.reverse.toArray, delimiterStr, unparseValue, ci.schemaFileLocation)
}
/**
* Constructs an Array of states reflecting the delimiters only.
* StateNum is offset by stateOffset
*/
protected def apply(delimType: DelimiterTextType.Type, ci: DPathCompileInfo, delimiter: Seq[DelimBase], delimiterStr: String, ignoreCase: Boolean): DFADelimiter = {
val allStates: ArrayBuffer[State] = ArrayBuffer.empty
buildTransitions(delimiter, allStates, ignoreCase)
new DFADelimiterImpl(delimType, allStates.reverse.toArray, delimiterStr, ci.schemaFileLocation)
}
/**
* Converts a String to a DFA representing
* that string
*/
def apply(delimType: DelimiterTextType.Type, ci: DPathCompileInfo, delimiterStr: String, ignoreCase: Boolean): DFADelimiter = {
val d = new Delimiter()
d.compileDelimiter(delimiterStr, ignoreCase)
val db = d.delimBuf
apply(delimType, ci, db, delimiterStr, ignoreCase)
}
/**
* Converts a String to a DFA representing
* that string
*/
def apply(delimType: DelimiterTextType.Type, ci: DPathCompileInfo, delimiterStr: String, outputNewLine: String): DFADelimiter = {
val d = new Delimiter()
d.compileDelimiter(delimiterStr, false)
val db = d.delimBuf
apply(delimType, ci, db, delimiterStr, outputNewLine)
}
/**
* Converts a Seq of String to a Seq of
* DFA's representing each String with outputNewLine.
*/
def apply(delimType: DelimiterTextType.Type, ci: DPathCompileInfo, delimiters: Seq[String], outputNewLine: String): Array[DFADelimiter] = {
delimiters.map(d => apply(delimType, ci, d, outputNewLine)).toArray
}
/**
* Converts a Seq of String to a Seq of
* DFA's representing each String.
*/
def apply(delimType: DelimiterTextType.Type, ci: DPathCompileInfo, delimiters: Seq[String], ignoreCase: Boolean): Array[DFADelimiter] = {
delimiters.map(d => apply(delimType, ci, d, ignoreCase)).toArray
}
/**
* Returns a state representing the DelimBase object.
*/
protected def getState(d: DelimBase, nextState: Int, stateNum: Int,
allStates: ArrayBuffer[State], ignoreCase: Boolean): DelimStateBase = {
val theState = d match {
case d: CharDelim => {
new CharState(allStates, d.char, nextState, stateNum, ignoreCase)
}
case d: WSPDelim => {
new WSPState(allStates, nextState, stateNum)
}
case d: WSPStarDelim => {
new WSPStarState(allStates, nextState, stateNum)
}
case d: WSPPlusDelim => {
new WSPPlusState(allStates, nextState, stateNum)
}
case d: NLDelim => {
new NLState(allStates, nextState, stateNum)
}
case d: ESDelim => {
new ESState(allStates, nextState, stateNum)
}
}
theState
}
private def buildTransitions(
delim: Seq[DelimBase],
allStates: ArrayBuffer[State], ignoreCase: Boolean): State = {
assert(!delim.isEmpty)
buildTransitions(null, delim.reverse, allStates, ignoreCase)
}
private def buildTransitions(nextState: DelimStateBase, delim: Seq[DelimBase],
allStates: ArrayBuffer[State], ignoreCase: Boolean): State = {
if (delim.isEmpty && nextState != null) {
// We are initial state
nextState.stateName = "StartState" //"PTERM0"
return nextState
}
val currentState = getState(
delim(0),
if (nextState == null) DFA.FinalState else nextState.stateNum,
delim.length - 1, allStates, ignoreCase)
val rest = delim.tail
allStates += currentState
return buildTransitions(currentState, rest, allStates, ignoreCase)
}
}