Skip to content

Commit

Permalink
Use expression parser to parse user type refs
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingun committed Aug 13, 2020
1 parent f725faf commit 28add0d
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
43 changes: 43 additions & 0 deletions jvm/src/test/scala/io/kaitai/struct/exprlang/ExpressionsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,47 @@ class ExpressionsSpec extends FunSpec {
Expressions.parse("foo.bar") should be (Attribute(Name(identifier("foo")),identifier("bar")))
}
}

describe("Expressions.parseTypeRef") {
describe("parses local type refs") {
it("some_type") {
Expressions.parseTypeRef("some_type") should be (List("some_type"), List())
}
it("with spaces: ' some_type '") {
Expressions.parseTypeRef(" some_type ") should be (List("some_type"), List())
}
it("some_type(1+2,data)") {
Expressions.parseTypeRef("some_type(1+2,data)") should be (List("some_type"), List(
BinOp(IntNum(1), Add, IntNum(2)),
Name(identifier("data"))
))
}
it("with spaces: ' some_type ( 1 + 2 , data ) '") {
Expressions.parseTypeRef(" some_type ( 1 + 2 , data ) ") should be (List("some_type"), List(
BinOp(IntNum(1), Add, IntNum(2)),
Name(identifier("data"))
))
}
}
describe("parses path type refs") {
it("some::type") {
Expressions.parseTypeRef("some::type") should be (List("some", "type"), List())
}
it("with spaces: ' some :: type '") {
Expressions.parseTypeRef(" some :: type ") should be (List("some", "type"), List())
}
it("some::type(1+2,data)") {
Expressions.parseTypeRef("some::type(1+2,data)") should be (List("some", "type"), List(
BinOp(IntNum(1), Add, IntNum(2)),
Name(identifier("data"))
))
}
it("with spaces: ' some :: type ( 1 + 2 , data ) '") {
Expressions.parseTypeRef(" some :: type ( 1 + 2 , data ) ") should be (List("some", "type"), List(
BinOp(IntNum(1), Add, IntNum(2)),
Name(identifier("data"))
))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,6 @@ object DataType {
private val ReIntType = """([us])(2|4|8)(le|be)?""".r
private val ReFloatType = """f(4|8)(le|be)?""".r
private val ReBitType = """b(\d+)(le|be)?""".r
private val ReUserTypeWithArgs = """^((?:[a-z][a-z0-9_]*::)*[a-z][a-z0-9_]*)\((.*)\)$""".r

def fromYaml(
dto: Option[String],
Expand Down Expand Up @@ -376,11 +375,7 @@ object DataType {
val bat = arg2.getByteArrayType(path)
StrFromBytesType(bat, enc)
case _ =>
val (arglessType, args) = dt match {
case ReUserTypeWithArgs(typeStr, argsStr) => (typeStr, Expressions.parseList(argsStr))
case _ => (dt, List())
}
val dtl = classNameToList(arglessType)
val (dtl, args) = Expressions.parseTypeRef(dt)
if (arg.size.isEmpty && !arg.sizeEos && arg.terminator.isEmpty) {
if (arg.process.isDefined)
throw new YAMLParseException(s"user type '$dt': need 'size' / 'size-eos' / 'terminator' if 'process' is used", path)
Expand Down
14 changes: 14 additions & 0 deletions shared/src/main/scala/io/kaitai/struct/exprlang/Expressions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,25 @@ object Expressions {

val topExprList: P[Seq[Ast.expr]] = P(testlist1 ~ End)

val typeRef: P[(List[String], Seq[Ast.expr])] = P(Start ~ NAME.rep(1, "::") ~ ("(" ~ testlist1 ~ ")").? ~ End).map {
case (path, None) => (path.map(n => n.toString).toList, List())
case (path, Some(args)) => (path.map(n => n.toString).toList, args)
}

class ParseException(val src: String, val failure: Parsed.Failure)
extends RuntimeException(failure.msg)

def parse(src: String): Ast.expr = realParse(src, topExpr)
def parseList(src: String): Seq[Ast.expr] = realParse(src, topExprList)
/**
* Parse string with reference tu user-type definition, optionally in full path format
* and optional arguments.
*
* @param src Type reference as string
* @return Tuple with path to type and type arguments. If arguments are not provided,
* corresponding list is empty. List with path always contains at least one element
*/
def parseTypeRef(src: String): (List[String], Seq[Ast.expr]) = realParse(src, typeRef)

private def realParse[T](src: String, parser: P[T]): T = {
val r = parser.parse(src.trim)
Expand Down

0 comments on commit 28add0d

Please sign in to comment.