Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.prophecy.abinitio.dml.Parser.scala Maven / Gradle / Ivy
package io.prophecy.abinitio.dml
import io.prophecy.abinitio.dml.pSchemaParser.condition
import io.prophecy.libs.{
FFAST,
FFCompoundSchemaRow,
FFConditionalSchemaRow,
FFDataFormat,
FFDateFormat,
FFDateTimeFormat,
FFDefaultVal,
FFDoubleDefaultVal,
FFIncludeFileRow,
FFIntDefaultVal,
FFNoDefaultVal,
FFNullDefaultVal,
FFNumberArrayFormat,
FFNumberFormat,
FFRecordType,
FFSchemaRecord,
FFSchemaRow,
FFSimpleSchemaList,
FFSimpleSchemaRow,
FFStringArrayFormat,
FFStringDefaultVal,
FFStringFormat,
FFStructArrayType,
FFStructType,
FFTypeName,
FFTypeNameWithProperties,
FFUnionType,
FFUnknownFormat,
FFVoidFormat
}
import org.apache.commons.lang.StringEscapeUtils
import org.slf4j.LoggerFactory
import scala.collection.immutable.Map
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.io.Source
import scala.util.{Left, Right}
import scala.util.parsing.combinator.{PackratParsers, Parsers}
import scala.util.parsing.input.{NoPosition, Position, Reader}
object pSchemaCompiler {
private val LOGGER = LoggerFactory.getLogger(this.getClass)
var debug = false
def apply(
code: String,
merge: Boolean = true,
keepConditions: Boolean = false
): Either[pSchemaCompilationError, FFAST] = {
if (debug) LOGGER.info(s"Parsing Schema: ${code}")
val x = for {
tokens ← pSchemaLexer(code).right
ast ← pSchemaParser(tokens, merge, keepConditions).right
} yield ast
if (pSchemaCompiler.debug) LOGGER.debug(s"Parsed Schema: ${x}")
x
}
def parseDML(field: String, addHeader: Boolean = true, merge: Boolean = true): FFAST = {
val dml = if (addHeader) s"record\n$field;\nend;" else field
val newDML = StringEscapeUtils.unescapeXml(dml.replace(" ", " "))
val compiledAST = apply(newDML, merge)
compiledAST match {
case Right(schemaRecord) ⇒
schemaRecord
case Left(errorDetails) ⇒
// logger.error(s"Error parsing \nERR::SCHEMA: $coreSchema\nERR::ERROR: $errorDetails")
throw new Exception(s"Error parsing \nERR::SCHEMA: $dml\nERR::ERROR: $errorDetails")
}
}
}
object pSchemaParser extends Parsers with PackratParsers {
import org.slf4j.LoggerFactory
import pSchemaCompiler.parseDML
private val LOGGER = LoggerFactory.getLogger(classOf[SchemaTokenReader])
var debug = false
var debugTokens = false
val DEFAULT_PREC = 38
override type Elem = SchemaToken
class SchemaTokenReader(tokens: Seq[SchemaToken]) extends Reader[SchemaToken] {
if (debugTokens) LOGGER.info("TOKENS: " + tokens.take(10).toString())
override def first: SchemaToken = tokens.head
override def atEnd: Boolean = tokens.isEmpty
override def pos: Position = tokens.headOption.map(_.pos).getOrElse(NoPosition)
override def rest: Reader[SchemaToken] = new SchemaTokenReader(tokens.tail)
}
/**
* Method to replace unknown record types with struct type mapping provided in passed map.
*
* @param row
* @param recordNameToRecordMap
* @return
*/
private def replaceUnknownTypesIfPossible(
oldRow: FFSchemaRow,
recordNameToRecordMap: Map[String, FFSchemaRecord],
keepConditions: Boolean
): FFSchemaRow = {
if (recordNameToRecordMap.isEmpty) oldRow
else {
val row =
if (oldRow.isInstanceOf[FFConditionalSchemaRow]) oldRow.asInstanceOf[FFConditionalSchemaRow].schemaRow
else oldRow
val resultRow = row match {
case x @ FFSimpleSchemaRow(name, FFUnknownFormat(FFTypeName(unknownType, None), arraySizeInfo), value) ⇒
if (recordNameToRecordMap.contains(unknownType)) {
val replacedByRows = recordNameToRecordMap.get(unknownType).get.rows
if (
replacedByRows.size == 1 && replacedByRows.head
.isInstanceOf[FFSimpleSchemaRow] && replacedByRows.head.asInstanceOf[FFSimpleSchemaRow].name.isEmpty
) {
FFSimpleSchemaRow(name, replacedByRows.head.asInstanceOf[FFSimpleSchemaRow].format, value)
} else {
FFCompoundSchemaRow(
if (arraySizeInfo.isDefined) FFStructArrayType(name, arraySizeInfo) else FFStructType(name),
replacedByRows
)
}
} else x
case x @ FFSimpleSchemaRow(name, format, value) ⇒ x
case FFCompoundSchemaRow(compound, rows) ⇒
FFCompoundSchemaRow(compound,
rows.map(replaceUnknownTypesIfPossible(_, recordNameToRecordMap, keepConditions))
)
case x @ FFSimpleSchemaList(rows) ⇒ x
}
if (keepConditions && oldRow.isInstanceOf[FFConditionalSchemaRow])
oldRow.asInstanceOf[FFConditionalSchemaRow].copy(schemaRow = resultRow)
else resultRow
}
}
def read_file(filename: String): String = {
if (filename == null) null
else {
try {
val bufferedSource = Source.fromFile(filename)
val content = bufferedSource.getLines().mkString("\n")
bufferedSource.close
content
} catch {
case _: Throwable ⇒ ""
}
}
}
private def replaceFFConditionalRowsIfNeeded(row: FFSchemaRow, keepConditions: Boolean): FFSchemaRow = {
row match {
case x @ FFConditionalSchemaRow(condition, schemaRow) ⇒
if (keepConditions) x else x.schemaRow
case x @ FFCompoundSchemaRow(compound, rows) ⇒
x.copy(rows = rows.map(row ⇒ replaceFFConditionalRowsIfNeeded(row, keepConditions)))
case x ⇒ x
}
}
private def replaceFFConditionalRowsIfNeeded(input: FFSchemaRecord, keepConditions: Boolean): FFAST = {
val newRows = input.rows.map(replaceFFConditionalRowsIfNeeded(_, keepConditions))
input.copy(rows = generateElseConditions(newRows))
}
private def generateElseCondition(conditions: Seq[String]): String = {
conditions match {
case Nil ⇒ throw new Exception("Cant generate else condition when no if condition provided")
case head :: Nil ⇒ s"!($head)"
case head :: tail ⇒ s"!($head) && " + generateElseCondition(tail)
}
}
private def generateElseConditions(rows: Seq[FFSchemaRow]): Seq[FFSchemaRow] = {
val conditionQueue = ListBuffer[FFConditionalSchemaRow]()
rows.map {
case row @ FFConditionalSchemaRow("else", schemaRow) ⇒
val elseCondition = generateElseCondition(conditionQueue.map(_.condition).toList)
val newRow = row.copy(condition = elseCondition)
conditionQueue += newRow
newRow
case row @ FFConditionalSchemaRow(condition, schemaRow) ⇒
conditionQueue += row
row
case row @ FFCompoundSchemaRow(compound, rows) ⇒
conditionQueue.clear()
row.copy(rows = generateElseConditions(rows))
case row ⇒
conditionQueue.clear()
row
}
}
/**
* Method to take care of merging of multiple named schema record definition like in below
* type tmp_record_type = record
* string("") dimension ;
* integer(8) dxf_sk = 0;
* end;
*
* metadata type = tmp_record_type;
*
* tmp_record_type in last record definition is replaced with tmp_record_type definition in first record definition to
* return final schema Record as below
* record
* string("") dimension ;
* integer(8) dxf_sk = 0;
* end;
*
* Also This method replaces unknown struct types with their definitions like in below example
* type hash_key_combine_type =
* record
* unsigned integer(8) dxf_hk_part1 = 0 ;
* end ;
*
* record
* decimal("") fsk_hk;
* hash_key_combine_type fsk_hk2;
* end;
*
* hash_key_combine_type in second record definition is replaced with its definition in first record definition to
* give final record definition as
* record
* decimal("") fsk_hk;
* record
* unsigned integer(8) dxf_hk_part1 = 0 ;
* end fsk_hk2;
* end;
*
* @param records
* @return
*/
private def mergeRecordDefinitions(
records: FFSchemaRecords,
merge: Boolean = true,
keepConditions: Boolean
): FFAST = {
val recordNameToRecordMap = mutable.Map[String, FFSchemaRecord]()
val includedDefinitions = records.recordDefinitions.flatMap {
case FFSchemaRecordDefinition(FFSchemaRecord("include", List(FFIncludeFileRow(filePath))), None) ⇒
val content = read_file(filePath)
if (content.isEmpty) Nil
else
parseDML(content, false, false).asInstanceOf[FFSchemaRecords].recordDefinitions
case x @ _ ⇒ x :: Nil
}
val mergedRecords = includedDefinitions.map { recordDefinition ⇒
val rows = recordDefinition.schemaRecord.rows.filter {
case FFSimpleSchemaRow(name, format, value) if name.endsWith("()") ⇒ false
case _ ⇒ true
}
val modifiedDefinition = if (rows.nonEmpty) {
val modifiedRows =
rows.map(replaceUnknownTypesIfPossible(_, recordNameToRecordMap.toMap, keepConditions))
val newSchemaRecord =
if (
rows.length == 1 && rows.head.isInstanceOf[FFSimpleSchemaRow] && rows.head
.asInstanceOf[FFSimpleSchemaRow]
.format
.isInstanceOf[FFUnknownFormat] && rows.head.asInstanceOf[FFSimpleSchemaRow].name.isEmpty
)
recordDefinition.schemaRecord.copy(
rows = modifiedRows,
recordType = recordNameToRecordMap
.getOrElse(rows.head
.asInstanceOf[FFSimpleSchemaRow]
.format
.asInstanceOf[FFUnknownFormat]
.name
.name,
recordDefinition.schemaRecord
)
.recordType
)
else recordDefinition.schemaRecord.copy(rows = modifiedRows)
recordDefinition.copy(schemaRecord = newSchemaRecord)
} else {
recordDefinition
}
modifiedDefinition.name match {
case None ⇒
modifiedDefinition.schemaRecord
case Some(name) ⇒
val newSchemaRecord =
if (modifiedDefinition.schemaRecord.rows.isEmpty && recordNameToRecordMap.contains(name)) {
recordNameToRecordMap.getOrElse(name, modifiedDefinition.schemaRecord)
} else modifiedDefinition.schemaRecord
recordNameToRecordMap.put(name, newSchemaRecord)
newSchemaRecord
}
}
val result = replaceFFConditionalRowsIfNeeded(mergedRecords.last, keepConditions)
result
}
def apply(
tokens: Seq[SchemaToken],
merge: Boolean = true,
keepConditions: Boolean = false
): Either[pSchemaParserError, FFAST] = {
val reader = new PackratReader(new SchemaTokenReader(tokens))
schemaRecords(reader) match {
case NoSuccess(msg, next) ⇒ Left(pSchemaParserError(pLocation(next.pos.line, next.pos.column), msg))
case Success(result, _) ⇒
val curResult = if (merge) mergeRecordDefinitions(result, merge, keepConditions) else result
val finalResult = curResult match {
case FFSchemaRecord(recordType, rows)
if rows.length == 1 && rows.head.isInstanceOf[FFCompoundSchemaRow] && rows.head
.asInstanceOf[FFCompoundSchemaRow]
.compound
.name
.get
.isEmpty ⇒
FFSchemaRecord(recordType, rows.head.asInstanceOf[FFCompoundSchemaRow].rows)
case _ ⇒ curResult
}
Right(finalResult)
}
}
def dbg[T](p: ⇒ Parser[T])(name: String): Parser[T] = {
if (!debug) p
// uncomment a parser to see all it's application attempts (success + failure)
name match {
// Row types
case "multiRow" ⇒ p
case "simpleRow" ⇒ p // log(p)(name)
// case "simpleRow1" ⇒ p // log(p)(name)
case "noAssignmentSimpleRow" ⇒ p // log(p)(name)
case "structRecord" ⇒ p // log(p)(name)
case "structRecordWithoutEnd" ⇒ p
case "unionRecord1" ⇒ p // log(p)(name)
case "unionRecord2" ⇒ p // log(p)(name)
case "structArrayRecord" ⇒ p // log(p)(name)
case "structArrayRecord2" ⇒ p
case "structArrayRecord2" ⇒ p
case "functionCallRow" ⇒ p
case "discardedFunctionCallRow" ⇒ p
case "ifConditionRow" ⇒ p
case "ifExprRow2" ⇒ p
case "ifExprRow3" ⇒ p
case "ifElseExprRow3" ⇒ p
case "ifElseExprRow4" ⇒ p
case "ifElseExprRow2" ⇒ p
// Declarations
case "oneLiteral" ⇒ p // log(p)(name)
case "oneLiteralWithDateTimeFormat" ⇒ p // log(p)(name)
case "oneLiteralWithInnerArrayType" ⇒ p
case "oneLiteralWithArrayType2" ⇒ p
case "oneLiteralWithArrayType" ⇒ p
case "twoLiteral" ⇒ p // log(p)(name)
case "twoLiteralWithZeroFilling" ⇒ p // log(p)(name)
case "twoLiteralWithZoned" ⇒ p
case "oneLiteralMaxLength" ⇒ p // log(p)(name)
case "oneLiteralPrecisionAndMaxLength" ⇒ p // log(p)(name)
case "oneLiteralWithCentury" ⇒ p // log(p)(name)
case "twoLiteralMaxLength1" ⇒ p // log(p)(name)
case "oneLiteralWithConstantArrayType" ⇒ p
case "decimalWithSingleLiteralAndSignReserved" ⇒ p
case "decimalWithDoubleLiteralAndSignReserved" ⇒ p
case "decimalWithNumbersAndSignReserved" ⇒ p // log(p)(name)
case "decimalWithNumbersAndZeroFill" ⇒ p
case "twoLiteralMaxLengthWithSignReserved" ⇒ p // log(p)(name)
case "singleLiteralMaxLengthWithSignReserved" ⇒ p
case "twoLiteralMaxLength2" ⇒ p // log(p)(name)
case "twoLiteralMaxLengthAndSignReserved" ⇒ p
case "decimalWithDot" ⇒ p // log(p)(name)
case "decimalWithGenericProperty" ⇒ p
case "decimalWithDotWithSignReserved" ⇒ p // log(p)(name)
case "noLiteral" ⇒ p // log(p)(name)
case "structArrayUnBoundedRecord" ⇒ p
}
}
case class FFSchemaRecords(recordDefinitions: Seq[FFSchemaRecordDefinition]) extends FFAST
case class FFSchemaRows(rows: Seq[FFSchemaRow]) extends FFAST
case class FFSchemaRecordDefinition(schemaRecord: FFSchemaRecord, name: Option[String] = None) extends FFAST
lazy val schemaRecords: Parser[FFSchemaRecords] = positioned {
rep1(schemaRecord) ^^ {
case records ⇒
FFSchemaRecords(records)
}
}
lazy val schemaRecord: Parser[FFSchemaRecordDefinition] = positioned {
val includeRow = identifier ~ literal ~ SEMICOLON() ^^ {
case IDENTIFIER("include") ~ STRING_LITERAL(content) ~ _ ⇒
FFSchemaRecordDefinition(FFSchemaRecord("include", FFIncludeFileRow(content) :: Nil))
}
val x0 = VOID() ~ OPAREN() ~ literal ~ CPAREN() ^^ {
case _ ~ _ ~ literal ~ _ ⇒
literal match {
case INT_LITERAL(value) ⇒
FFSchemaRecordDefinition(
FFSchemaRecord("void",
FFSimpleSchemaRow("",
FFVoidFormat(FFTypeName("ByteType", delimiter = None), Some(value)),
FFNoDefaultVal()
) :: Nil
)
)
case x ⇒ throw new Exception(s"Bad literal $x")
}
}
val x01 = STRING() ~ OPAREN() ~ literal ~ CPAREN() ~ SEMICOLON() ^^ {
case _ ~ _ ~ literal ~ _ ~ _ ⇒
literal match {
case STRING_LITERAL(value) ⇒
FFSchemaRecordDefinition(
FFSchemaRecord(
"record",
FFSimpleSchemaRow("",
FFStringFormat(FFTypeName("StringType", delimiter = Some(value)), None, None),
FFNoDefaultVal()
) :: Nil
)
)
case x ⇒ throw new Exception(s"Bad literal $x")
}
}
val x001 = RECORD() ~ END() ~ SEMICOLON() ^^ {
case _ ~ _ ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord("UnknownType", Nil)
)
}
val x1 = recordType ~ rep(record) ~ END() ^^ {
case FFRecordType(rType) ~ statements ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
statements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
)
)
}
val x2 = recordType ~ rep(record) ~ END() ~ SEMICOLON() ^^ {
case FFRecordType(rType) ~ statements ~ _ ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
statements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
)
)
}
val x8 = recordType ~ rep(record) ~ SEMICOLON() ^^ {
case FFRecordType(rType) ~ statements ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
statements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
)
)
}
val x6 = recordType ~ rep1(
record
) ~ IF() ~ OPAREN() ~ identifier ~ EQUALS() ~ EQUALS() ~ literal ~ CPAREN() ~ BEGIN() ~ rep1(
record
) ~ END() ~ opt(
ELSE() ~ IF() ~ OPAREN() ~ identifier ~ EQUALS() ~ EQUALS() ~ literal ~ CPAREN() ~ BEGIN() ~ rep1(
record
) ~ END()
) ~ opt(ELSE() ~ BEGIN() ~ rep1(record) ~ END()) ~ rep(record) ~ END() ~ SEMICOLON() ^^ {
case FFRecordType(
rType
) ~ statements1 ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ statements2 ~ _ ~ elseIfOpt ~ elseOpt ~ remainingStmts ~ _ ~ _ ⇒
val statements3 = if (elseIfOpt.isDefined) elseIfOpt.get._1._2 else Nil
val statements4 = if (elseOpt.isDefined) elseOpt.get._1._2 else Nil
val finalStatements = statements1 ++ statements2 ++ statements3 ++ statements4 ++ remainingStmts
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
finalStatements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
)
)
}
val x7 = recordType ~ rep1(
record
) ~ IF() ~ OPAREN() ~ identifier ~ EQUALS() ~ EQUALS() ~ literal ~ CPAREN() ~ BEGIN() ~ rep1(
record
) ~ END() ~ IF() ~ OPAREN() ~ identifier ~ EQUALS() ~ EQUALS() ~ literal ~ CPAREN() ~ BEGIN() ~ rep1(
record
) ~ END() ~ BEGIN() ~ rep1(record) ~ END() ~ SEMICOLON() ^^ {
case FFRecordType(
rType
) ~ statements1 ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ statements2 ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ _ ~ statements3 ~ _ ~ _ ~ statements4 ~ _ ~ _ ⇒
val finalStatements = statements1 ++ statements2 ++ statements3 ++ statements4
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
finalStatements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
)
)
}
val x3 = TYPE() ~ identifier ~ EQUALS() ~ recordType ~ rep(record) ~ END() ~ SEMICOLON() ^^ {
case _ ~ IDENTIFIER(name) ~ _ ~ FFRecordType(rType) ~ statements ~ _ ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
statements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
),
Some(name)
)
}
val x5 = TYPE() ~ identifier ~ EQUALS() ~ recordType ~ rep(
record
) ~ END() ~ OBRACK() ~ theFormat ~ CBRACK() ~ SEMICOLON() ^^ {
case _ ~ IDENTIFIER(name) ~ _ ~ FFRecordType(rType) ~ statements ~ _ ~ _ ~ dataType ~ _ ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
statements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
),
Some(name)
)
}
val x4 = METADATA() ~ TYPE() ~ EQUALS() ~ identifier ~ SEMICOLON() ^^ {
case _ ~ _ ~ _ ~ IDENTIFIER(name) ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord("record",
FFSimpleSchemaRow("", FFUnknownFormat(FFTypeName(name, None), None), FFNoDefaultVal()) :: Nil
),
Some(name)
)
}
val x41 =
TYPE() ~ identifier ~ EQUALS() ~ identifier ~ OBRACK() ~ datatypeWithTypeInfo ~ OPAREN() ~ literal ~ CPAREN() ~ CBRACK() ~ SEMICOLON() ^^ {
case _ ~ IDENTIFIER(name1) ~ _ ~ IDENTIFIER(name) ~ _ ~ arrayType ~ _ ~ literal ~ _ ~ _ ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord("record",
FFSimpleSchemaRow("",
FFUnknownFormat(FFTypeName(name, None), Some(arrayType.name)),
FFNoDefaultVal()
) :: Nil
),
Some(name1)
)
}
val x10 = TYPE() ~ identifier ~ EQUALS() ~ theFormat ~ SEMICOLON() ^^ {
case _ ~ IDENTIFIER(typeName) ~ _ ~ dataType ~ _ ⇒
FFSchemaRecordDefinition(FFSchemaRecord("", FFSimpleSchemaRow("", dataType, FFNoDefaultVal()) :: Nil),
Some(typeName)
)
}
val x9 = METADATA() ~ TYPE() ~ EQUALS() ~ recordType ~ rep(record) ~ END() ~ SEMICOLON() ^^ {
case _ ~ _ ~ _ ~ FFRecordType(rType) ~ statements ~ _ ~ _ ⇒
FFSchemaRecordDefinition(
FFSchemaRecord(rType,
statements.flatMap(_.rows).flatMap { x ⇒
x match {
case list: FFSimpleSchemaList ⇒
list.rows.map { y ⇒
y.asInstanceOf[FFSchemaRow]
}
case _ ⇒ List(x)
}
}
)
)
}
includeRow | x6 | x7 | x2 | x8 | x1 | x3 | x9 | x4 | x41 | x5 | x0 | x01 | x10 | x001
}
lazy val record: Parser[FFSchemaRows] = positioned {
val simpleRow = theFormat ~ identifier ~ assignment ^^ {
case dataType ~ IDENTIFIER(name) ~ assignment1 ⇒
FFSchemaRows(FFSimpleSchemaRow(name, dataType, assignment1) :: Nil)
}
val ifExprRow2 =
IF() ~ repN(2, OPAREN()) ~ (nestedTernaryCondition | ternaryCondition | condition) ~ repN(2,
CPAREN()
) ~ record ^^ {
case _ ~ _ ~ condition ~ _ ~ row ⇒
row.copy(rows = row.rows.map(row ⇒ FFConditionalSchemaRow(condition.startType, row)))
}
val ifExprRow3 = IF() ~ OPAREN() ~ (nestedTernaryCondition | ternaryCondition | condition) ~ CPAREN() ~ record ^^ {
case _ ~ _ ~ condition ~ _ ~ row ⇒
row.copy(rows = row.rows.map(row ⇒ FFConditionalSchemaRow(condition.startType, row)))
}
val ifElseExprRow2 =
ELSE() ~ IF() ~ repN(2, OPAREN()) ~ (nestedTernaryCondition | ternaryCondition | condition) ~ repN(2,
CPAREN()
) ~ record ^^ {
case _ ~ _ ~ _ ~ condition ~ _ ~ row ⇒
row.copy(rows = row.rows.map(row ⇒ FFConditionalSchemaRow(condition.startType, row)))
}
val ifElseExprRow3 =
ELSE() ~ IF() ~ OPAREN() ~ (nestedTernaryCondition | ternaryCondition | condition) ~ CPAREN() ~ record ^^ {
case _ ~ _ ~ _ ~ condition ~ _ ~ row ⇒
row.copy(rows = row.rows.map(row ⇒ FFConditionalSchemaRow(condition.startType, row)))
}
val ifElseExprRow4 =
ELSE() ~ record ^^ {
case _ ~ row ⇒
row.copy(rows = row.rows.map(row ⇒ FFConditionalSchemaRow("else", row)))
}
val discardedFunctionCallRow =
theFormat ~ identifier ~ OPAREN() ~ theFormat ~ identifier ~ CPAREN() ~ assignment ^^ {
case colDataType ~ IDENTIFIER(colName) ~ _ ~ datatype ~ IDENTIFIER(argName) ~ _ ~ assignment ⇒
FFSchemaRows(FFSimpleSchemaRow(colName + "()", colDataType, assignment) :: Nil)
}
val functionCallRow = theFormat ~ identifier ~ OPAREN() ~ CPAREN() ~ assignment ^^ {
case datatype ~ IDENTIFIER(name) ~ _ ~ _ ~ assignment ⇒
FFSchemaRows(FFSimpleSchemaRow(name + "()", datatype, assignment) :: Nil)
}
val multiRow = theFormat ~ rep(identifier ~ assignment ~ COMMA()) ~ identifier ~ assignment ^^ {
case dataType ~ inputs1 ~ IDENTIFIER(lastName) ~ lastAssignment ⇒
val rows =
inputs1.map(x ⇒ FFSimpleSchemaRow(x._1._1.str, dataType, x._1._2)) :+ FFSimpleSchemaRow(lastName,
dataType,
lastAssignment
)
FFSchemaRows(rows)
}
val noAssignmentSimpleRow = theFormat ~ rep(identifier ~ COMMA()) ~ rep(identifier) ~ SEMICOLON() ^^ {
case dataType ~ inputs1 ~ lastInput ~ _ ⇒
FFSchemaRows(FFSimpleSchemaList((inputs1.map(_._1) ++ lastInput).map {
case IDENTIFIER(name) ⇒ FFSimpleSchemaRow(name, dataType, FFNoDefaultVal())
}) :: Nil)
}
val structRecord = recordType ~ rep(record) ~ END() ~ identifier ~ SEMICOLON() ^^ {
case _ ~ (records: Seq[FFSchemaRows]) ~ _ ~ IDENTIFIER(name) ~ _ ⇒
FFSchemaRows(FFCompoundSchemaRow(FFStructType(name), records.flatMap(_.rows)) :: Nil)
}
val structRecordWithoutEnd = recordType ~ rep(record) ~ SEMICOLON() ^^ {
case _ ~ (records: Seq[FFSchemaRows]) ~ _ ⇒
FFSchemaRows(FFCompoundSchemaRow(FFStructType(""), records.flatMap(_.rows)) :: Nil)
}
val structArrayRecord =
recordType ~ rep(record) ~ END() ~ OBRACK() ~ opt(literal) ~ CBRACK() ~ identifier ~ SEMICOLON() ^^ {
case _ ~ (records: Seq[FFSchemaRows]) ~ _ ~ _ ~ optLiteral ~ _ ~ IDENTIFIER(name) ~ _ ⇒
FFSchemaRows(
FFCompoundSchemaRow(FFStructArrayType(name, getArraySizeInfo(optLiteral)), records.flatMap(_.rows)) :: Nil
)
}
val structArrayRecord2 =
recordType ~ rep(record) ~ END() ~ identifier ~ OBRACK() ~ identifier ~ CBRACK() ~ SEMICOLON() ^^ {
case _ ~ (records: Seq[FFSchemaRows]) ~ _ ~ IDENTIFIER(name) ~ _ ~ IDENTIFIER(arraySize) ~ _ ~ _ ⇒
FFSchemaRows(
FFCompoundSchemaRow(FFStructArrayType(name, Some(arraySize)), records.flatMap(_.rows)) :: Nil
)
}
val structArrayUnBoundedRecord =
recordType ~ rep(record) ~ END() ~ OBRACK() ~ theFormat ~ CBRACK() ~ identifier ~ assignment ^^ {
case _ ~ (records: Seq[FFSchemaRows]) ~ _ ~ _ ~ literal1 ~ _ ~ IDENTIFIER(name) ~ _ ⇒
FFSchemaRows(
FFCompoundSchemaRow(FFStructArrayType(name, Some(literal1.toString)), records.flatMap(_.rows)) :: Nil
)
}
val unionRecord1 = unionRecordType ~ rep(record) ~ END() ~ identifier ~ SEMICOLON() ^^ {
case _ ~ (records: Seq[FFSchemaRows]) ~ _ ~ IDENTIFIER(name) ~ _ ⇒
FFSchemaRows(FFCompoundSchemaRow(FFUnionType(Some(name)), records.flatMap(_.rows)) :: Nil)
}
val unionRecord2 = unionRecordType ~ rep(record) ~ END() ~ SEMICOLON() ^^ {
case _ ~ (records: Seq[FFSchemaRows]) ~ _ ~ _ ⇒
FFSchemaRows(FFCompoundSchemaRow(FFUnionType(None), records.flatMap(_.rows)) :: Nil)
}
// dbg(simpleRow)(name = "simpleRow") |
dbg(functionCallRow)(name = "functionCallRow") |
dbg(discardedFunctionCallRow)(name = "discardedFunctionCallRow") |
dbg(multiRow)(name = "multiRow") |
dbg(noAssignmentSimpleRow)(name = "noAssignmentSimpleRow") |
dbg(structRecord)(name = "structRecord") |
dbg(structRecordWithoutEnd)(name = "structRecordWithoutEnd") |
dbg(unionRecord1)(name = "unionRecord1") |
dbg(unionRecord2)(name = "unionRecord2") |
dbg(structArrayRecord2)(name = "structArrayRecord2") |
dbg(structArrayRecord)(name = "structArrayRecord") |
dbg(structArrayUnBoundedRecord)(name = "structArrayUnBoundedRecord") |
dbg(ifExprRow2)(name = "ifExprRow2") |
dbg(ifExprRow3)(name = "ifExprRow3") |
dbg(ifElseExprRow2)(name = "ifElseExprRow2") |
dbg(ifElseExprRow3)(name = "ifElseExprRow3") |
dbg(ifElseExprRow4)(name = "ifElseExprRow4")
}
lazy val condition: Parser[FFRecordType] = positioned {
identifier ~ rep(DOT() ~ identifier) ~ EQUALS() ~ EQUALS() ~ literal ^^ {
case IDENTIFIER(var1) ~ restIdentifiers ~ _ ~ _ ~ STRING_LITERAL(str) ⇒
FFRecordType(s"""$var1${if (restIdentifiers.nonEmpty) ("." + restIdentifiers.map(_._2.str).mkString("."))
else ""} == "$str"""")
}
}
lazy val ternaryCondition: Parser[FFRecordType] = positioned {
OPAREN() ~ condition ~ CPAREN() ~ QUESTION_MARK() ~ literal ~ COLON() ~ OPAREN() ~ condition ~ CPAREN() ^^ {
case _ ~ condition ~ _ ~ _ ~ STRING_LITERAL(str) ~ _ ~ _ ~ condition2 ~ _ ⇒
FFRecordType(s"""(${condition.startType}) ? "$str" : (${condition2.startType})""")
case _ ~ condition ~ _ ~ _ ~ INT_LITERAL(num) ~ _ ~ _ ~ condition2 ~ _ ⇒
FFRecordType(s"""(${condition.startType}) ? $num : (${condition2.startType})""")
}
}
lazy val nestedTernaryCondition: Parser[FFRecordType] = positioned {
OPAREN() ~ condition ~ CPAREN() ~ QUESTION_MARK() ~ literal ~ COLON() ~ OPAREN() ~ ternaryCondition ~ CPAREN() ^^ {
case _ ~ condition ~ _ ~ _ ~ STRING_LITERAL(str) ~ _ ~ _ ~ condition2 ~ _ ⇒
FFRecordType(s"""(${condition.startType}) ? "$str" : (${condition2.startType})""")
case _ ~ condition ~ _ ~ _ ~ INT_LITERAL(num) ~ _ ~ _ ~ condition2 ~ _ ⇒
FFRecordType(s"""(${condition.startType}) ? "$num" : (${condition2.startType})""")
}
}
lazy val recordType: Parser[FFRecordType] = positioned {
val x1 = RECORD() ^^ { _ ⇒
FFRecordType("record")
}
val ifExpr =
IF() ~ OPAREN() ~ OPAREN() ~ identifier ~ EQUALS() ~ EQUALS() ~ literal ~ CPAREN() ~ CPAREN() ~ RECORD() ^^ {
case _ ~ _ ~ _ ~ IDENTIFIER(name) ~ _ ~ _ ~ literal ~ _ ~ _ ~ _ ⇒ FFRecordType("record")
}
val ifWithSingleParentExpr =
IF() ~ OPAREN() ~ identifier ~ EQUALS() ~ EQUALS() ~ literal ~ CPAREN() ~ RECORD() ^^ {
case _ ~ _ ~ IDENTIFIER(name) ~ _ ~ _ ~ literal ~ _ ~ _ ⇒ FFRecordType("record")
}
val elseIfExpr =
ELSE() ~ IF() ~ OPAREN() ~ identifier ~ EQUALS() ~ EQUALS() ~ literal ~ CPAREN() ~ RECORD() ^^ {
case _ ~ _ ~ _ ~ IDENTIFIER(name) ~ _ ~ _ ~ literal ~ _ ~ _ ⇒ FFRecordType("record")
}
val x2 = ASCII() ~ RECORD() ^^ { case _ ~ _ ⇒ FFRecordType("ascii") }
val x3 = UTF8() ~ RECORD() ^^ { case _ ~ _ ⇒ FFRecordType("utf8") }
val x4 = EBCDIC() ~ RECORD() ^^ { case _ ~ _ ⇒ FFRecordType("ebcdic") }
val x5 = ISO_LATIN() ~ RECORD() ^^ { case _ ~ _ ⇒ FFRecordType("iso_latin") }
x1 | x2 | x3 | x4 | x5 | ifWithSingleParentExpr | elseIfExpr | ifExpr
}
lazy val unionRecordType: Parser[FFRecordType] = positioned {
val x1 = UNION() ^^ { case _ ⇒ FFRecordType("union") }
val x2 = ASCII() ~ UNION() ^^ { case _ ~ _ ⇒ FFRecordType("ascii") }
val x3 = UTF8() ~ UNION() ^^ { case _ ~ _ ⇒ FFRecordType("utf8") }
val x4 = EBCDIC() ~ UNION() ^^ { case _ ~ _ ⇒ FFRecordType("ebcdic") }
val x5 = ISO_LATIN() ~ UNION() ^^ { case _ ~ _ ⇒ FFRecordType("iso_latin") }
x1 | x2 | x3 | x4
}
/**
* Changes the numerical type name to an integer if the scale is not present.
*
* @param inTyp number format type to check
* @return The same number format, but with an integer type if the scale is not present, otherwise return unchanged
*/
def zpd(inTyp: FFNumberFormat): FFNumberFormat = {
inTyp match {
// case FFNumberFormat(FFTypeName(typeName, delimiter), precision, scale, miscProperties) ⇒
// if (typeName == "DecimalType" && scale.isDefined && scale.get == 0 && precision.isDefined && precision.get < 10)
// FFNumberFormat(FFTypeName("IntegerType", delimiter), precision, scale, miscProperties)
// else inTyp
case _ ⇒ inTyp
}
}
def processStringProperties(_props: Map[String, Any]): Option[Map[String, String]] = {
val props = _props.filterNot(p ⇒ p._1 == "packed" || p._1 == "signReserved")
if (props.isEmpty) None
else {
Some(props.map(entry ⇒ (entry._1, entry._2.toString)))
}
}
def processDateProperties(props: Map[String, Any]): Map[String, Any] =
props.filterNot(p ⇒ p._1 == "packed" || p._1 == "signReserved")
private def getArraySizeInfo(literal1: Option[LITERAL]): Option[String] = {
literal1 match {
case Some(STRING_LITERAL(str)) ⇒ Some(str)
case Some(INT_LITERAL(num)) ⇒ Some(num.toString)
case Some(DOUBLE_LITERAL(dub)) ⇒ Some(dub.asInstanceOf[Int].toString)
case _ ⇒ None
}
}
lazy val theFormat: Parser[FFDataFormat] = positioned {
// string("|")
// string(1)
// decimal(",")
// decimal("record (")
// decimal(5)
// date( "YYYYMMDD" )
val oneLiteral =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ opt(COMMA() ~ CHARSET() ~ EQUALS() ~ literal) ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ optCharSet ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "StringType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFStringFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
props = processStringProperties(ptypeName.miscProperties)
)
case INT_LITERAL(value) ⇒
FFStringFormat(FFTypeName(typeName, delimiter = None),
precision = Some(value),
props = processStringProperties(ptypeName.miscProperties)
)
case INT() ⇒
FFStringFormat(FFTypeName(typeName, delimiter = None),
precision = None,
props = processStringProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DecimalType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
scale = None,
miscProperties = properties
)
)
case INT_LITERAL(value) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(DEFAULT_PREC, value)),
scale = None,
miscProperties = properties
)
)
case DOUBLE_LITERAL(value) ⇒
val fractionString = String.valueOf(value)
val fraction = fractionString.substring(fractionString.indexOf('.') + 1).toInt
val precision = Some(Math.min(DEFAULT_PREC, Math.floor(value).toInt - 1))
val scale = Some(fraction)
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = precision,
scale = scale,
miscProperties = properties ++ Map("decimal_point" → "Period")
)
)
case x ⇒ FFUnknownFormat(FFTypeName(typeName, delimiter = None), None)
}
case "DateType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFDateFormat(
FFTypeName(typeName, delimiter = None),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value)),
processDateProperties(ptypeName.miscProperties)
)
case INT_LITERAL(value) ⇒
FFDateFormat(FFTypeName(typeName, delimiter = None),
format = None,
processDateProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DateTimeType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFDateTimeFormat(
FFTypeName(typeName, delimiter = None),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value)),
processDateProperties(ptypeName.miscProperties)
)
case INT_LITERAL(value) ⇒
FFDateTimeFormat(FFTypeName(typeName, delimiter = None),
format = None,
processDateProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "TimestampType" ⇒
// @TODO this requires adding the timestamp format later on
literal1 match {
case STRING_LITERAL(value) ⇒
FFStringFormat(FFTypeName(typeName, delimiter = None),
precision = None,
props = processStringProperties(ptypeName.miscProperties)
)
case INT_LITERAL(value) ⇒
FFStringFormat(FFTypeName(typeName, delimiter = None),
precision = None,
props = processStringProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "TimestampType" ⇒
// @TODO this requires adding the timestamp format later on
literal1 match {
case STRING_LITERAL(value) ⇒
FFStringFormat(FFTypeName(typeName, delimiter = None),
precision = None,
props = processStringProperties(ptypeName.miscProperties)
)
case INT_LITERAL(value) ⇒
FFStringFormat(FFTypeName(typeName, delimiter = None),
precision = None,
props = processStringProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "BinaryType" ⇒
literal1 match {
case INT_LITERAL(value) ⇒ FFVoidFormat(FFTypeName("ByteType", delimiter = None), Some(value))
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "IntegerType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
scale = None,
miscProperties = properties
)
case INT_LITERAL(value) ⇒
if (value > 4)
FFNumberFormat(FFTypeName("LongType", delimiter = None),
precision = Some(Math.min(value, DEFAULT_PREC)),
scale = None,
miscProperties = properties
)
else
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value, DEFAULT_PREC)),
scale = None,
miscProperties = properties
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DoubleType" ⇒
literal1 match {
case INT_LITERAL(value) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value, DEFAULT_PREC)),
scale = None,
miscProperties = properties
)
)
case x @ _ ⇒ throw new Exception(s"$x not supported")
}
case x ⇒
throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// integer(4)[integer(4)]
val oneLiteralWithArrayType =
datatypeWithTypeInfo ~ opt(
OPAREN() ~ literal ~ CPAREN()
) ~ OBRACK() ~ datatypeWithTypeInfo ~ OPAREN() ~ literal ~ CPAREN() ~ CBRACK() ^^ {
case ptypeName ~ literal1Opt ~ _ ~ FFTypeNameWithProperties(typeName2, delim2, _) ~ _ ~ literal2 ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val literal1 = literal1Opt.map(_._1._2)
val typeName = ptypeName.name
(typeName2, literal2) match {
case ("IntegerType", INT_LITERAL(value)) ⇒
typeName match {
case "StringType" ⇒
literal1 match {
case Some(STRING_LITERAL(value)) ⇒
FFStringArrayFormat(FFTypeName(typeName, delimiter = Some(value)), precision = None, Some(value))
case Some(INT_LITERAL(value)) ⇒
FFStringArrayFormat(FFTypeName(typeName, delimiter = None),
precision = Some(value),
Some(value.toString)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DecimalType" ⇒
val (format, arraySizeInfo) = literal1 match {
case Some(STRING_LITERAL(value)) ⇒
(zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
scale = None,
miscProperties = properties
)
),
Some(value)
)
case Some(INT_LITERAL(value)) ⇒
(zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value, DEFAULT_PREC)),
scale = None,
miscProperties = properties
)
),
Some(value.toString)
)
case Some(DOUBLE_LITERAL(value)) ⇒
val fractionString = String.valueOf(value)
val fraction = fractionString.substring(fractionString.indexOf('.') + 1).toInt
val precision = Some(Math.min(DEFAULT_PREC, Math.floor(value).toInt - 1))
val scale = Some(fraction)
(zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = precision,
scale = scale,
miscProperties = properties ++ Map("decimal_point" → "Period")
)
),
Some(precision.get.toString)
)
case x ⇒
(FFUnknownFormat(FFTypeName(typeName, delimiter = None), getArraySizeInfo(Some(literal2))),
getArraySizeInfo(Some(literal2))
)
}
if (format.isInstanceOf[FFNumberFormat]) {
val numberFormat = format.asInstanceOf[FFNumberFormat]
FFNumberArrayFormat(numberFormat.name,
numberFormat.precision,
numberFormat.scale,
arraySizeInfo,
numberFormat.miscProperties
)
} else {
format
}
case "DateType" ⇒
literal1 match {
case Some(STRING_LITERAL(value)) ⇒
FFDateFormat(
FFTypeName(typeName, delimiter = None),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value)),
miscProperties = processDateProperties(ptypeName.miscProperties)
)
case Some(INT_LITERAL(value)) ⇒
FFDateFormat(FFTypeName(typeName, delimiter = None),
format = None,
miscProperties = processDateProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DateTimeType" ⇒
literal1 match {
case Some(STRING_LITERAL(value)) ⇒
FFDateTimeFormat(
FFTypeName(typeName, delimiter = None),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value)),
processDateProperties(ptypeName.miscProperties)
)
case Some(INT_LITERAL(value)) ⇒
FFDateTimeFormat(FFTypeName(typeName, delimiter = None),
format = None,
processDateProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "IntegerType" ⇒
literal1 match {
case Some(STRING_LITERAL(value)) ⇒
FFNumberArrayFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
scale = None,
arraySizeInfo = Some(value),
properties
)
case Some(INT_LITERAL(value)) ⇒
FFNumberArrayFormat(FFTypeName(typeName, delimiter = None),
precision = Some(value),
scale = None,
arraySizeInfo = Some(value.toString),
miscProperties = properties
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case x ⇒ FFUnknownFormat(FFTypeName(typeName, None), getArraySizeInfo(literal1))
// throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
case (_: String, _) ⇒
FFUnknownFormat(FFTypeName(ptypeName.name, ptypeName.delimiter), getArraySizeInfo(literal1))
case x ⇒ throw new Exception(s"Bad literal $x for $typeName2")
}
}
// utf8 string(big endian integer(4)) value;
val oneLiteralWithInnerArrayType =
datatypeWithTypeInfo ~
OPAREN() ~ datatypeWithTypeInfo ~ opt(OPAREN() ~ literal ~ CPAREN()) ~ opt(
COMMA() ~ CHARSET() ~ EQUALS() ~ literal
) ~ CPAREN() ~ opt(
OBRACK() ~ datatypeWithTypeInfo ~ opt(OPAREN() ~ literal ~ CPAREN()) ~ CBRACK()
) ^^ {
case ptypeName ~ _ ~ ptype2 ~ _ ~ charSetOpt ~ _ ~ optArrayPart ⇒
val optArrayLiteral = optArrayPart.flatMap(_._1._2)
var arraySizeInfo = optArrayLiteral.map(entry ⇒
entry._1._2 match {
case STRING_LITERAL(str) ⇒ str
case INT_LITERAL(num) ⇒ num.toString
case DOUBLE_LITERAL(dub) ⇒ dub.asInstanceOf[Int].toString
case _ ⇒ ""
}
)
arraySizeInfo = if (arraySizeInfo.getOrElse("") != "") Some(arraySizeInfo.get) else None
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties ++ (if (charSetOpt.isDefined)
Map(
"charset" → charSetOpt.get._2
.asInstanceOf[STRING_LITERAL]
.str
)
else Map())
val typeName = ptypeName.name
typeName match {
case "StringType" ⇒
if (optArrayPart.isDefined)
FFStringArrayFormat(FFTypeName(typeName, delimiter = None),
precision = None,
arraySizeInfo = arraySizeInfo
)
else
FFStringFormat(
FFTypeName(typeName, delimiter = None),
None,
props = processStringProperties(properties)
)
case "BinaryType" ⇒
FFVoidFormat(FFTypeName(typeName, None), None)
case "DecimalType" ⇒
val numberFormat = zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = None,
scale = None,
miscProperties = properties
)
)
if (optArrayPart.isDefined)
FFNumberArrayFormat(numberFormat.name,
numberFormat.precision,
numberFormat.scale,
arraySizeInfo,
numberFormat.miscProperties
)
else numberFormat
case "DateType" ⇒
FFDateFormat(FFTypeName(typeName, delimiter = None),
format = None,
miscProperties = processDateProperties(properties)
)
case "DateTimeType" ⇒
FFDateTimeFormat(FFTypeName(typeName, delimiter = None),
format = None,
processDateProperties(properties)
)
case "IntegerType" | "LongType" ⇒
if (optArrayPart.isDefined)
FFNumberArrayFormat(FFTypeName(typeName, delimiter = None),
precision = None,
scale = None,
arraySizeInfo = arraySizeInfo
)
else
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = None,
scale = None,
miscProperties = properties
)
case x: String if x.length > 0 ⇒
FFUnknownFormat(FFTypeName(x, None), arraySizeInfo)
}
}
// utf8 string(big endian integer(4)) value;
val oneLiteralWithArrayType2 =
datatypeWithTypeInfo ~ OBRACK() ~ datatypeWithTypeInfo ~ CBRACK() ^^ {
case ptypeName ~ _ ~ arrayType ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
val arrayTypeInfo = Some(arrayType.name)
typeName match {
case "StringType" ⇒
FFStringArrayFormat(FFTypeName(typeName, delimiter = None),
precision = None,
arraySizeInfo = arrayTypeInfo
)
case "BinaryType" ⇒
FFVoidFormat(FFTypeName(typeName, None), None)
case "DecimalType" ⇒
val numberFormat = zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = None,
scale = None,
miscProperties = properties
)
)
FFNumberArrayFormat(numberFormat.name,
numberFormat.precision,
numberFormat.scale,
arrayTypeInfo,
numberFormat.miscProperties
)
case "DateType" ⇒
FFDateFormat(FFTypeName(typeName, delimiter = None),
format = None,
miscProperties = processDateProperties(properties)
)
case "DateTimeType" ⇒
FFDateTimeFormat(FFTypeName(typeName, delimiter = None), format = None, processDateProperties(properties))
case "IntegerType" | "LongType" ⇒
FFNumberArrayFormat(FFTypeName(typeName, delimiter = None),
precision = None,
scale = None,
arrayTypeInfo,
miscProperties = properties
)
case x: String if x.length > 0 ⇒
FFUnknownFormat(FFTypeName(x, None), arrayTypeInfo)
}
}
// string(2)[256] hex2
val oneLiteralWithConstantArrayType =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ CPAREN() ~ OBRACK() ~ literal ~ CBRACK() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ _ ~ literal2 ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val arrayTypeInfo = getArraySizeInfo(Some(literal2))
val typeName = ptypeName.name
typeName match {
case "StringType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFStringArrayFormat(FFTypeName(typeName, delimiter = Some(value)), precision = None, arrayTypeInfo)
case INT_LITERAL(value) ⇒
FFStringArrayFormat(FFTypeName(typeName, delimiter = None), precision = Some(value), arrayTypeInfo)
case INT() ⇒
FFStringArrayFormat(FFTypeName(typeName, delimiter = None), precision = None, arrayTypeInfo)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DecimalType" ⇒
val format = literal1 match {
case STRING_LITERAL(value) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
scale = None,
miscProperties = properties
)
)
case INT_LITERAL(value) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value, DEFAULT_PREC)),
scale = None,
miscProperties = properties
)
)
case DOUBLE_LITERAL(value) ⇒
val fractionString = String.valueOf(value)
val fraction = fractionString.substring(fractionString.indexOf('.') + 1).toInt
val precision = Some(Math.min(DEFAULT_PREC, Math.floor(value).toInt - 1))
val scale = Some(fraction)
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = precision,
scale = scale,
miscProperties = properties ++ Map("decimal_point" → "Period")
)
)
case x ⇒
FFUnknownFormat(FFTypeName(typeName, delimiter = None), arrayTypeInfo)
}
if (format.isInstanceOf[FFNumberFormat]) {
val numberFormat = format.asInstanceOf[FFNumberFormat]
FFNumberArrayFormat(numberFormat.name,
numberFormat.precision,
numberFormat.scale,
arrayTypeInfo,
numberFormat.miscProperties
)
} else {
format
}
case "DateType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFDateFormat(
FFTypeName(typeName, delimiter = None),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value)),
miscProperties = processDateProperties(ptypeName.miscProperties)
)
case INT_LITERAL(value) ⇒
FFDateFormat(FFTypeName(typeName, delimiter = None),
format = None,
miscProperties = processDateProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DateTimeType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFDateTimeFormat(
FFTypeName(typeName, delimiter = None),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value)),
processDateProperties(ptypeName.miscProperties)
)
case INT_LITERAL(value) ⇒
FFDateTimeFormat(FFTypeName(typeName, delimiter = None),
format = None,
processDateProperties(ptypeName.miscProperties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "IntegerType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
FFNumberArrayFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
scale = None,
arrayTypeInfo,
miscProperties = properties
)
case INT_LITERAL(value) ⇒
FFNumberArrayFormat(FFTypeName(typeName, delimiter = None),
precision = Some(value),
scale = None,
arrayTypeInfo,
miscProperties = properties
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
val noLiteral = datatypeWithTypeInfo ^^ {
case FFTypeNameWithProperties(typeName, delim, properties) ⇒
typeName match {
case "StringType" ⇒
FFStringFormat(FFTypeName(typeName, delimiter = None),
precision = None,
props = processStringProperties(properties)
)
case "DoubleType" ⇒ FFNumberFormat(FFTypeName(typeName, None), None, None, properties)
case "IntegerType" ⇒ FFNumberFormat(FFTypeName(typeName, None), Some(4), None, properties)
case "LongType" ⇒ FFNumberFormat(FFTypeName(typeName, None), Some(8), None, properties)
case x ⇒
FFUnknownFormat(FFTypeName(typeName, None), None)
}
}
// date ( "YYYYMMDD" ) ('|')
// datetime ( "yyyyMMDD" ) ('|')
val oneLiteralWithDateTimeFormat =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ CPAREN() ~ OPAREN() ~ literal ~ CPAREN() ^^ {
case FFTypeNameWithProperties(typeName, delim, properties) ~ _ ~ literal1 ~ _ ~ _ ~ literal2 ~ _ ⇒
typeName match {
case "StringType" | "DecimalType" ⇒
throw new Exception(
s"String or Decimal Type can't have two string literals $literal1 and $literal2 for $typeName"
)
case "DateType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), STRING_LITERAL(value2)) ⇒
FFDateFormat(
FFTypeName(typeName, delimiter = Some(value2)),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value1)),
processDateProperties(properties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case "DateTimeType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), STRING_LITERAL(value2)) ⇒
FFDateTimeFormat(
FFTypeName(typeName, delimiter = Some(value2)),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value1)),
processDateProperties(properties)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal("\x01", 0)
// decimal(",", 0)
// string(",", 5)
val twoLiteral =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ literal ~ rep(
COMMA() ~ identifier ~ opt(EQUALS() ~ literal)
) ~ CPAREN() ~ opt(
OBRACK() ~ literal ~ CBRACK()
) ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2 ~ miscProperties ~ _ ~ optArraySize ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties ++ miscProperties.map(entry ⇒
if (entry._2.isDefined && entry._2.get._2.isInstanceOf[STRING_LITERAL])
(entry._1._2.str, entry._2.get._2.asInstanceOf[STRING_LITERAL].str)
else (entry._1._2.str, true)
)
val typeName = ptypeName.name
val arraySizeInfo = if (optArraySize.isDefined) getArraySizeInfo(Some(optArraySize.get._1._2)) else None
typeName match {
case "StringType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), INT_LITERAL(value2)) ⇒
if (arraySizeInfo.isEmpty)
FFStringFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(value2),
props = processStringProperties(properties)
)
else
FFStringArrayFormat(FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(value2),
arraySizeInfo
)
case (x, y) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y")
}
case "DecimalType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), INT_LITERAL(value2)) ⇒
if (arraySizeInfo.isEmpty)
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(DEFAULT_PREC),
scale = Some(value2),
miscProperties = properties ++ Map("decimal_point" → "Comma")
)
)
else
FFNumberArrayFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(DEFAULT_PREC),
scale = Some(value2),
arraySizeInfo = arraySizeInfo,
miscProperties = properties ++ Map("decimal_point" → "Comma")
)
case (INT_LITERAL(value1), INT_LITERAL(value2)) ⇒
if (arraySizeInfo.isEmpty)
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value1, DEFAULT_PREC)),
scale = Some(value2),
miscProperties = properties ++ Map("decimal_point" → "Comma")
)
)
else
FFNumberArrayFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(value1),
scale = Some(value2),
arraySizeInfo = arraySizeInfo,
miscProperties = properties ++ Map("decimal_point" → "Comma")
)
case (x, y) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
val twoLiteralWithZeroFilling = datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ ZEROFILL() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties ++ Map("zerofill" → true)
val typeName = ptypeName.name
typeName match {
case "StringType" ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $literal1")
case "DecimalType" ⇒
literal1 match {
case STRING_LITERAL(value1) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(0),
scale = None,
miscProperties = properties
)
)
case INT_LITERAL(value1) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value1, DEFAULT_PREC)),
scale = None,
miscProperties = properties
)
)
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
val twoLiteralWithZoned =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ opt(literal ~ COMMA()) ~ ZONED() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2Opt ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
val value2: Option[Int] =
if (literal2Opt.isDefined && literal2Opt.get._1.isInstanceOf[INT_LITERAL])
Some(literal2Opt.get._1.asInstanceOf[INT_LITERAL].num)
else None
typeName match {
case "StringType" ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $literal1")
case "DecimalType" ⇒
literal1 match {
case INT_LITERAL(value1) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value1, DEFAULT_PREC)),
scale = value2,
miscProperties = properties ++ Map("decimal_point" → "Comma")
)
)
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// string("\x01", maximum_length=1)
// string(",", maximum_length=1)
val oneLiteralMaxLength =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ opt(
CHARSET() ~ EQUALS() ~ literal ~ COMMA()
) ~ MAX_LEN() ~ EQUALS() ~ literal ~ CPAREN() ~ opt(OBRACK() ~ literal ~ CBRACK()) ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ charSetOpt ~ _ ~ _ ~ literal2 ~ _ ~ arrayTypeOpt ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
val arraySizeInfo = if (arrayTypeOpt.isDefined) getArraySizeInfo(Some(arrayTypeOpt.get._1._2)) else None
typeName match {
case "StringType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), INT_LITERAL(value2)) ⇒
if (arraySizeInfo.isDefined)
FFStringArrayFormat(FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(value2),
arraySizeInfo = arraySizeInfo
)
else
FFStringFormat(FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(value2),
props = processStringProperties(ptypeName.miscProperties)
)
case (x, y) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y")
}
case "DecimalType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), INT_LITERAL(value2)) ⇒
if (arrayTypeOpt.isDefined)
FFNumberArrayFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value2)),
scale = None,
arraySizeInfo = arraySizeInfo,
miscProperties = properties
)
else
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value2)),
scale = None,
miscProperties = properties
)
)
case (x, y) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// string("\x01", maximum_length=1)
// string(",", maximum_length=1)
// only accept if this is string type, as fixed width and maxlength
// can only really occur together in string
val oneLiteralPrecisionAndMaxLength =
datatypeWithTypeInfo ~ OPAREN() ~ datatypeWithTypeInfo ~ opt(OPAREN() ~ literal ~ CPAREN()) ~ COMMA() ~ opt(
CHARSET() ~ EQUALS() ~ literal <~ COMMA()
) ~ MAX_LEN() ~ EQUALS() ~ literal ~ CPAREN() ^^ {
case colType ~ _ ~ precisionType ~ packType ~ _ ~ _ ~ _ ~ _ ~ literal2 ~ _
if colType.name == "StringType" && precisionType.name == "IntegerType" ⇒
// get the pack type data
val packLen = packType match {
case Some(value) ⇒ Some(value._1._2.asInstanceOf[INT_LITERAL].num)
case _ ⇒ None
}
var properties: Map[String, Any] = colType.miscProperties ++ precisionType.miscProperties
literal2 match {
case INT_LITERAL(num) ⇒
if (packLen.isDefined) {
properties = properties ++ Map("pckLen" → packLen.get.toString)
if (precisionType.miscProperties.contains("endian")) {
properties = properties ++ Map("endian" → precisionType.miscProperties("endian").toString)
}
FFStringFormat(
FFTypeName(colType.name, delimiter = None),
precision = Some(num),
props = processStringProperties(properties)
)
} else
FFStringFormat(
FFTypeName(colType.name, delimiter = None),
precision = Some(num),
props = processStringProperties(properties)
)
case _ ⇒ throw new Exception(s"Max length should be integer")
}
}
// date("YYMMDD", century="2000")
val oneLiteralWithCentury =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ CENTURY() ~ EQUALS() ~ literal ~ CPAREN() ^^ {
case FFTypeNameWithProperties(typeName, delim, properties) ~ _ ~ literal1 ~ _ ~ _ ~ _ ~ literal2 ~ _ ⇒
typeName match {
case "DateType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), STRING_LITERAL(value2)) ⇒
FFDateFormat(FFTypeName(typeName, None),
format = Some(AbInitioToSparkFunctionMapping.getSparkDateTimeFormat(value1)),
properties ++ Map("century" → value2)
)
case x ⇒ throw new Exception(s"Bad literal $x for $typeName")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal(",", 2, maximum_length=9 )
val twoLiteralMaxLength1 =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ literal ~ COMMA() ~ MAX_LEN() ~ EQUALS() ~ literal ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2 ~ _ ~ _ ~ _ ~ literal3 ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2, literal3) match {
case (STRING_LITERAL(value1), INT_LITERAL(value2), INT_LITERAL(value3)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value3)),
scale = Some(value2),
miscProperties = properties ++ Map("decimal_point" → "Comma")
)
)
case (x, y, z) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y, $z")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal(",", 2, maximum_length=9 , sign_reserved)
val twoLiteralMaxLengthWithSignReserved =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ literal ~ COMMA() ~ MAX_LEN() ~ EQUALS() ~ literal ~ COMMA() ~ SIGN_RESERVED() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2 ~ _ ~ _ ~ _ ~ literal3 ~ _ ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2, literal3) match {
case (STRING_LITERAL(value1), INT_LITERAL(value2), INT_LITERAL(value3)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value3)),
scale = Some(value2),
properties ++ Map[String, Any]("signReserved" → true, "decimal_point" → "Comma")
)
)
case (x, y, z) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y, $z")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
val singleLiteralMaxLengthWithSignReserved =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ MAX_LEN() ~ EQUALS() ~ literal ~ COMMA() ~ SIGN_RESERVED() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ _ ~ _ ~ literal3 ~ _ ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal3) match {
case (STRING_LITERAL(value1), INT_LITERAL(value3)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value3)),
scale = None,
properties ++ Map[String, Any]("signReserved" → true, "decimal_point" → "Comma")
)
)
case (x, z) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $z")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal("\x01".2, maximum_length=9 )
val twoLiteralMaxLength2 =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ literal ~ COMMA() ~ MAX_LEN() ~ EQUALS() ~ literal ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ literal2 ~ _ ~ _ ~ _ ~ literal3 ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2, literal3) match {
case (STRING_LITERAL(value1), DOUBLE_LITERAL(value2), INT_LITERAL(value3)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value3 - 1)),
scale = Some((value2 * 10).toInt),
miscProperties = properties ++ Map("decimal_point" → "Period")
)
)
case (x, y, z) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y, $z")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal("\x01", 4, maximum_length=7, signReserved)
val twoLiteralMaxLengthAndSignReserved =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ literal ~ COMMA() ~ MAX_LEN() ~ EQUALS() ~ literal ~ COMMA() ~ SIGN_RESERVED() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2 ~ _ ~ _ ~ _ ~ literal3 ~ _ ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2, literal3) match {
case (STRING_LITERAL(value1), INT_LITERAL(value2), INT_LITERAL(value3)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value3)),
scale = Some(value2),
miscProperties = properties ++ Map[String, Any]("signReserved" → true, "decimal_point" → "Comma")
)
)
case (x, y, z) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y, $z")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal(",", 2, maximum_length=9 )
val decimalWithNumbersAndSignReserved =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ literal ~ COMMA() ~ SIGN_RESERVED() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2 ~ _ ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2) match {
case (INT_LITERAL(value1), INT_LITERAL(value2)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value1, DEFAULT_PREC)),
scale = Some(value2),
properties ++ Map[String, Any]("signReserved" → true, "decimal_point" → "Comma")
)
)
case (STRING_LITERAL(value1), INT_LITERAL(value2)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(value2, DEFAULT_PREC)),
scale = None,
miscProperties = properties ++ Map[String, Any]("signReserved" → true)
)
)
case (x, y) ⇒
throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
val decimalWithNumbersAndZeroFill =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ literal ~ COMMA() ~ ZEROFILL() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2 ~ _ ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties ++ Map("zerofill" → true)
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2) match {
case (INT_LITERAL(value1), INT_LITERAL(value2)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value1, DEFAULT_PREC)),
scale = Some(value2),
properties ++ Map[String, Any]("zerofill" → true, "decimal_point" → "Comma")
)
)
case (x, y) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
val decimalWithGenericProperty =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ opt(literal ~ COMMA()) ~ opt(
ZEROFILL() ~ COMMA()
) ~ rep(identifier ~ COMMA()) ~ identifier ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literalOpt ~ zeroFillOpt ~ multiProperties ~ IDENTIFIER(propName) ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties ++ multiProperties.map(x ⇒ (x._1.str, true)).toMap
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
val value2: Option[Int] =
if (literalOpt.isDefined && literalOpt.get._1.isInstanceOf[INT_LITERAL])
Some(literalOpt.get._1.asInstanceOf[INT_LITERAL].num)
else None
literal1 match {
case INT_LITERAL(value1) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value1, DEFAULT_PREC)),
scale = value2,
properties ++ Map[String, Any](propName → true, "decimal_point" → "Comma") ++ (if (
zeroFillOpt.isDefined
)
Map(
"zerofill" → true
)
else Map())
)
)
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal(10, 2, unsigned)
val decimalWithDoubleLiteralAndSignReserved =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ literal ~ COMMA() ~ (SIGN_RESERVED() | UNSIGNED()) ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ literal2 ~ _ ~ property ~ _ ⇒
val newProperty = if (property == SIGN_RESERVED()) "signReserved" else "unsigned"
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value), INT_LITERAL(num)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value)),
precision = Some(DEFAULT_PREC),
scale = Some(num),
miscProperties = properties ++ Map[String, Any](newProperty → true, "decimal_point" → "Comma")
)
)
case (INT_LITERAL(value1), INT_LITERAL(value2)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(value1),
scale = Some(value2),
miscProperties = properties ++ Map[String, Any](newProperty → true, "decimal_point" → "Comma")
)
)
case (DOUBLE_LITERAL(value), _) ⇒
val fractionString = String.valueOf(value)
val fraction = fractionString.substring(fractionString.indexOf('.') + 1).toInt
val scale = Some(fraction)
val precision = Some(Math.min(Math.floor(value).toInt - 1, DEFAULT_PREC))
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = precision,
scale = scale,
miscProperties = properties ++ Map[String, Any](newProperty → true, "decimal_point" → "Period")
)
)
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal(",", 2, maximum_length=9 )
val decimalWithSingleLiteralAndSignReserved =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ COMMA() ~ (SIGN_RESERVED() | UNSIGNED()) ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ _ ~ property ~ _ ⇒
val newProperty = if (property == SIGN_RESERVED()) "signReserved" else "unsigned"
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
literal1 match {
case STRING_LITERAL(value) ⇒
zpd(
FFNumberFormat(FFTypeName(typeName, delimiter = Some(value)),
precision = None,
scale = None,
miscProperties = properties ++ Map[String, Any](newProperty → true)
)
)
case INT_LITERAL(value) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = Some(Math.min(value, DEFAULT_PREC)),
scale = None,
miscProperties = properties ++ Map[String, Any](newProperty → true)
)
)
case DOUBLE_LITERAL(value) ⇒
val fractionString = String.valueOf(value)
val fraction = fractionString.substring(fractionString.indexOf('.') + 1).toInt
val scale = Some(fraction)
val precision = Some(Math.min(Math.floor(value).toInt - 1, DEFAULT_PREC))
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = None),
precision = precision,
scale = scale,
miscProperties = properties ++ Map[String, Any](newProperty → true, "decimal_point" → "Period")
)
)
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal("\x01".2, maximum_length=9, sign_reserved )
val decimalWithDotWithSignReserved =
datatypeWithTypeInfo ~ OPAREN() ~ literal ~ literal ~ COMMA() ~ MAX_LEN() ~ EQUALS() ~ literal ~ COMMA() ~ SIGN_RESERVED() ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ literal2 ~ _ ~ _ ~ _ ~ literal3 ~ _ ~ _ ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2, literal3) match {
case (STRING_LITERAL(value1), DOUBLE_LITERAL(value2), INT_LITERAL(value3)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(Math.min(DEFAULT_PREC, value3 - 1)),
scale = Some((value2 * 10).toInt),
properties ++ Map[String, Any]("signReserved" → true, "decimal_point" → "Period")
)
)
case (x, y, z) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y, $z")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
// decimal("\x01".2)
val decimalWithDot = datatypeWithTypeInfo ~ OPAREN() ~ literal ~ literal ~ CPAREN() ^^ {
case ptypeName ~ _ ~ literal1 ~ literal2 ~ _ ⇒
val properties = FFNumberFormat(FFTypeName(ptypeName.name, ptypeName.delimiter),
None,
None
).miscProperties ++ ptypeName.miscProperties
val typeName = ptypeName.name
typeName match {
case "DecimalType" ⇒
(literal1, literal2) match {
case (STRING_LITERAL(value1), DOUBLE_LITERAL(value2)) ⇒
zpd(
FFNumberFormat(
FFTypeName(typeName, delimiter = Some(value1)),
precision = Some(DEFAULT_PREC - 1),
scale = Some((value2 * 10).toInt),
miscProperties = properties ++ Map("decimal_point" → "Period")
)
)
case (x, y) ⇒ throw new Exception(s"Don't know how to parse type $typeName with literals $x, $y")
}
case x ⇒ throw new Exception(s"Don't know how to parse type $typeName with literal $x")
}
}
dbg(oneLiteralWithDateTimeFormat)(name = "oneLiteralWithDateTimeFormat") |
dbg(oneLiteralWithArrayType)(name = "oneLiteralWithArrayType") |
dbg(oneLiteralWithConstantArrayType)(name = "oneLiteralWithConstantArrayType") |
dbg(twoLiteralWithZeroFilling)(name = "twoLiteralWithZeroFilling") |
dbg(twoLiteralWithZoned)(name = "twoLiteralWithZoned") |
dbg(oneLiteral)(name = "oneLiteral") |
dbg(twoLiteral)(name = "twoLiteral") |
dbg(oneLiteralWithArrayType2)(name = "oneLiteralWithArrayType2") |
dbg(oneLiteralWithInnerArrayType)(name = "oneLiteralWithInnerArrayType") |
dbg(oneLiteralMaxLength)(name = "oneLiteralMaxLength") |
dbg(oneLiteralPrecisionAndMaxLength)(name = "oneLiteralPrecisionAndMaxLength") |
dbg(oneLiteralWithCentury)(name = "oneLiteralWithCentury") |
dbg(decimalWithDoubleLiteralAndSignReserved)(name = "decimalWithDoubleLiteralAndSignReserved") |
dbg(decimalWithSingleLiteralAndSignReserved)(name = "decimalWithSingleLiteralAndSignReserved") |
dbg(decimalWithNumbersAndSignReserved)(name = "decimalWithNumbersAndSignReserved") |
dbg(twoLiteralMaxLengthWithSignReserved)(name = "twoLiteralMaxLengthWithSignReserved") |
dbg(singleLiteralMaxLengthWithSignReserved)(name = "singleLiteralMaxLengthWithSignReserved") |
dbg(twoLiteralMaxLength1)(name = "twoLiteralMaxLength1") |
dbg(decimalWithDotWithSignReserved)(name = "decimalWithDotWithSignReserved") |
dbg(twoLiteralMaxLengthAndSignReserved)(name = "twoLiteralMaxLengthAndSignReserved") |
dbg(twoLiteralMaxLength2)(name = "twoLiteralMaxLength2") |
dbg(decimalWithDot)(name = "decimalWithDot") |
dbg(decimalWithNumbersAndZeroFill)(name = "decimalWithNumbersAndZeroFill") |
dbg(decimalWithGenericProperty)(name = "decimalWithGenericProperty") |
dbg(noLiteral)(name = "noLiteral")
}
lazy val assignment: PackratParser[FFDefaultVal] = positioned {
val x1 = SEMICOLON() ^^ { _ ⇒
FFNoDefaultVal()
}
val x2 = EQUALS() ~ NULL() ~ SEMICOLON() ^^ { _ ⇒
FFNullDefaultVal()
}
val x3 = EQUALS() ~ literal ~ opt(SEMICOLON()) ^^ {
case _ ~ STRING_LITERAL(value) ~ _ ⇒ FFStringDefaultVal(value)
case _ ~ INT_LITERAL(value) ~ _ ⇒ FFIntDefaultVal(value)
case _ ~ DOUBLE_LITERAL(value) ~ _ ⇒ FFDoubleDefaultVal(value)
}
val x31 = EQUALS() ~ OPAREN() ~ literal ~ CPAREN() ~ opt(SEMICOLON()) ^^ {
case _ ~ _ ~ STRING_LITERAL(value) ~ _ ~ _ ⇒ FFStringDefaultVal(value)
case _ ~ _ ~ INT_LITERAL(value) ~ _ ~ _ ⇒ FFIntDefaultVal(value)
case _ ~ _ ~ DOUBLE_LITERAL(value) ~ _ ~ _ ⇒ FFDoubleDefaultVal(value)
}
val x4 = EQUALS() ~ NULL() ~ OPAREN() ~ literal ~ CPAREN() ~ opt(SEMICOLON()) ^^ { _ ⇒
FFNullDefaultVal()
}
val x41 = EQUALS() ~ (OBRACK() | OBRACE()) ~ identifier ~ (CBRACK() | CBRACE()) ~ SEMICOLON() ^^ { _ ⇒
FFNoDefaultVal()
}
val x5 = EQUALS() ~ OPAREN() ~ literal ~ CPAREN() ~ opt(SEMICOLON()) ^^ {
case _ ~ STRING_LITERAL(value) ~ _ ⇒ FFStringDefaultVal(value)
case _ ~ INT_LITERAL(value) ~ _ ⇒ FFIntDefaultVal(value)
case _ ~ DOUBLE_LITERAL(value) ~ _ ⇒ FFDoubleDefaultVal(value)
}
val x6 = EQUALS() ~ identifier ~ OPAREN() ~ opt(identifier ~ COMMA() ~ literal) ~ CPAREN() ~ SEMICOLON() ^^ { _ ⇒
FFNullDefaultVal()
}
val x61 = EQUALS() ~ NOT_OP1() ~ identifier ~ OPAREN() ~ identifier ~ CPAREN() ~ SEMICOLON() ^^ { _ ⇒
FFNullDefaultVal()
}
val x7 =
EQUALS() ~ OPAREN() ~ identifier ~ OPAREN() ~ identifier ~ CPAREN() ~ GREATER_THAN() ~ literal ~ CPAREN() ~ SEMICOLON() ^^ {
_ ⇒
FFNullDefaultVal()
}
val x8 =
EQUALS() ~ NULL() ~ OPAREN() ~ identifier ~ OPAREN() ~ theFormat ~ COMMA() ~ literal ~ CPAREN() ~ CPAREN() ~ SEMICOLON() ^^ {
_ ⇒
FFNullDefaultVal()
}
val x9 = EQUALS() ~ NULL() ~ OPAREN() ~ OBRACK() ~ VECTOR() ~ CBRACK() ~ CPAREN() ~ opt(SEMICOLON()) ^^ { _ ⇒
FFNullDefaultVal()
}
x2 | x31 | x3 | x4 | x5 | x61 | x6 | x7 | x1 | x8 | x41 | x9
}
//(reinterpret_as(packed decimal(8)," "))
lazy val datatypeWithTypeInfo: PackratParser[FFTypeNameWithProperties] = positioned {
val x1 = datatype ^^ { case ptypeName ⇒ ptypeName }
val x2 = ASCII() ~ datatype ^^ { case _ ~ ptypeName ⇒ ptypeName }
val x3 = UTF8() ~ datatype ^^ { case _ ~ ptypeName ⇒ ptypeName }
x1 | x2 | x3
}
lazy val datatype: PackratParser[FFTypeNameWithProperties] = positioned {
val x111 = EBCDIC() ~ STRING() ^^ {
case _ ~ _ ⇒ FFTypeNameWithProperties("StringType", None, Map("ebcdic" → true))
}
val x112 = UNICODE() ~ STRING() ^^ { case _ ~ _ ⇒ FFTypeNameWithProperties("StringType", None) }
val x1 = STRING() ^^ { _ ⇒
FFTypeNameWithProperties("StringType", None)
}
val x12 = VARCHAR() ^^ { _ ⇒
FFTypeNameWithProperties("StringType", None)
}
val x21 = EBCDIC() ~ INTEGER() ^^ {
case _ ~ _ ⇒
FFTypeNameWithProperties("IntegerType", None, Map("ebcdic" → true))
}
val x22 = BIGENDIAN() ~ (INTEGER() | REAL() | DECIMAL()) ^^ {
case _ ~ INTEGER() ⇒
FFTypeNameWithProperties("IntegerType", None, miscProperties = Map("packed" → false, "endian" → "big"))
case _ ~ REAL() ⇒
FFTypeNameWithProperties("DoubleType", None, miscProperties = Map("packed" → false, "endian" → "big"))
case _ ~ DECIMAL() ⇒
FFTypeNameWithProperties("DecimalType", None, miscProperties = Map("packed" → false, "endian" → "big"))
}
val x23 = (UNSIGNED() | SIGNED()) ~ (LITTLE_ENDIAN() | BIGENDIAN()) ~ INTEGER() ^^ {
case SIGNED() ~ LITTLE_ENDIAN() ~ _ ⇒
FFTypeNameWithProperties("IntegerType", None, miscProperties = Map("packed" → false, "endian" → "little"))
case UNSIGNED() ~ LITTLE_ENDIAN() ~ _ ⇒
FFTypeNameWithProperties("IntegerType",
None,
miscProperties = Map("packed" → false, "endian" → "little", "unsigned" → true)
)
case SIGNED() ~ BIGENDIAN() ~ _ ⇒
FFTypeNameWithProperties("IntegerType", None, miscProperties = Map("packed" → false, "endian" → "big"))
case UNSIGNED() ~ BIGENDIAN() ~ _ ⇒
FFTypeNameWithProperties("IntegerType",
None,
miscProperties = Map("packed" → false, "endian" → "big", "unsigned" → true)
)
}
val x26 = LITTLE_ENDIAN() ~ INTEGER() ^^ {
case _ ~ _ ⇒
FFTypeNameWithProperties("IntegerType", None, miscProperties = Map("packed" → false, "endian" → "little"))
}
val x2 = (INTEGER() | INT() | LONG()) ^^ {
case INTEGER() | INT() ⇒ FFTypeNameWithProperties("IntegerType", None)
case LONG() ⇒
FFTypeNameWithProperties("LongType", None, miscProperties = Map("packed" → false))
}
val x25 = UNSIGNED() ~ (INTEGER() | INT()) ^^ { _ ⇒
FFTypeNameWithProperties(name = "IntegerType", None, miscProperties = Map("unsigned" → true))
}
val x24 = BIGINT() ^^ { _ ⇒
FFTypeNameWithProperties("IntegerType", None)
}
val x31 = PACKED() ~ DECIMAL() ^^ {
case _ ~ _ ⇒ FFTypeNameWithProperties("DecimalType", None, Map("packed" → true))
}
val x32 = EBCDIC() ~ DECIMAL() ^^ {
case _ ~ _ ⇒ FFTypeNameWithProperties("DecimalType", None, Map("ebcdic" → true))
}
val x3 = DECIMAL() ^^ { _ ⇒
FFTypeNameWithProperties("DecimalType", None)
}
val x33 = DOUBLE() ^^ { _ ⇒
FFTypeNameWithProperties("DoubleType", None)
}
val x41 = EBCDIC() ~ DATE() ^^ { case _ ~ _ ⇒ FFTypeNameWithProperties("DateType", None) }
val x4 = DATE() ^^ { _ ⇒
FFTypeNameWithProperties("DateType", None)
}
val x51 = EBCDIC() ~ DATETIME() ^^ { case _ ~ _ ⇒ FFTypeNameWithProperties("DateTimeType", None) }
val x5 = DATETIME() ^^ { _ ⇒
FFTypeNameWithProperties("DateTimeType", None)
}
val x61 = EBCDIC() ~ TIMESTAMP() ^^ { case _ ~ _ ⇒ FFTypeNameWithProperties("TimestampType", None) }
val x6 = TIMESTAMP() ^^ { _ ⇒
FFTypeNameWithProperties("TimestampType", None)
}
val x7 = VOID() ^^ { _ ⇒
FFTypeNameWithProperties("BinaryType", None)
}
val x10 = identifier ^^ {
case IDENTIFIER(typeName) ⇒ FFTypeNameWithProperties(typeName, None)
}
x111 | x112 | x31 | x1 | x12 | x32 | x21 | x22 | x23 | x25 | x26 | x2 | x24 | x3 | x33 | x41 | x4 | x51 | x5 | x61 | x6 | x7 | x10
}
private def identifier: Parser[IDENTIFIER] = positioned {
accept("identifier", { case id @ IDENTIFIER(name) ⇒ id })
}
private def literal: Parser[LITERAL] = positioned {
accept("string literal",
{
case lit @ INT_LITERAL(name) ⇒ lit
case lit @ DOUBLE_LITERAL(name) ⇒ lit
case lit @ STRING_LITERAL(name) ⇒ lit
case lit @ INT() ⇒ lit
}
)
}
}