All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.kaitai.struct.translators.ExpressionValidator.scala Maven / Gradle / Ivy

package io.kaitai.struct.translators

import io.kaitai.struct.datatype.DataType
import io.kaitai.struct.exprlang.Ast
import io.kaitai.struct.format.Identifier
import io.kaitai.struct.precompile.EnumMemberNotFoundError

/**
  * Validates expressions usage of types (in typecasting operator,
  * enums, sizeof operator, etc) to match actual layout of class specs
  * loaded in type provider.
  *
  * Implemented essentially as a no-op translator, which does all the
  * recursive traversing that regular translator performs, but outputs
  * not result.
  *
  * @param provider TypeProvider that will answer queries on user types
  */
class ExpressionValidator(val provider: TypeProvider)
  extends TypeDetector(provider)
  with CommonMethods[Unit]
  with ByteArraysAsTrueArrays[Unit] {
  /**
    * Validates one expression. Throws exceptions when encounters an error.
    * @param v expression to validate
    */
  def validate(v: Ast.expr): Unit = {
    v match {
      case _: Ast.expr.IntNum |
           _: Ast.expr.FloatNum |
           _: Ast.expr.Str |
           _: Ast.expr.Bool => // all simple literals are good and valid
      case Ast.expr.EnumById(enumType, id, inType) =>
        provider.resolveEnum(inType, enumType.name)
        validate(id)
      case Ast.expr.EnumByLabel(enumType, label, inType) =>
        val enumSpec = provider.resolveEnum(inType, enumType.name)
        if (!enumSpec.map.values.exists(_.name == label.name)) {
          throw new EnumMemberNotFoundError(label.name, enumType.name, enumSpec.path.mkString("/"))
        }
      case Ast.expr.Name(name: Ast.identifier) =>
        if (name.name == Identifier.SIZEOF) {
          CommonSizeOf.getByteSizeOfClassSpec(provider.nowClass)
        } else {
          // local name already checked by type detection
        }
      case Ast.expr.UnaryOp(op: Ast.unaryop, inner: Ast.expr) =>
        validate(inner)
      case Ast.expr.Compare(left: Ast.expr, op: Ast.cmpop, right: Ast.expr) =>
        validate(left)
        validate(right)
      case Ast.expr.BinOp(left: Ast.expr, op: Ast.operator, right: Ast.expr) =>
        validate(left)
        validate(right)
      case Ast.expr.BoolOp(op: Ast.boolop, values: Seq[Ast.expr]) =>
        values.foreach(validate)
      case Ast.expr.IfExp(condition, ifTrue, ifFalse) =>
        validate(condition)
        validate(ifTrue)
        validate(ifFalse)
      case Ast.expr.Subscript(container: Ast.expr, idx: Ast.expr) =>
        validate(container)
        validate(idx)
      case call: Ast.expr.Attribute =>
        translateAttribute(call)
      case call: Ast.expr.Call =>
        translateCall(call)
      case Ast.expr.List(values: Seq[Ast.expr]) =>
        values.foreach(validate)
      case ctt: Ast.expr.CastToType =>
        validate(ctt.value)
        detectCastType(ctt.typeName)
      case Ast.expr.ByteSizeOfType(typeName) =>
        CommonSizeOf.getBitsSizeOfType(typeName.nameAsStr, detectCastType(typeName))
      case Ast.expr.BitSizeOfType(typeName) =>
        CommonSizeOf.getBitsSizeOfType(typeName.nameAsStr, detectCastType(typeName))
    }
  }

  override def userTypeField(ut: DataType.UserType, value: Ast.expr, name: String): Unit = {
    validate(value)
    // TODO: check that field exists
  }
  override def kaitaiStructField(value: Ast.expr, name: String): Unit = {
    validate(value)
    // TODO: check that field exists
  }

  override def strLength(s: Ast.expr): Unit = validate(s)
  override def strReverse(s: Ast.expr): Unit = validate(s)
  override def strToInt(s: Ast.expr, base: Ast.expr): Unit = {
    validate(s)
    validate(base)
  }
  override def strSubstring(s: Ast.expr, from: Ast.expr, to: Ast.expr): Unit = {
    validate(s)
    validate(from)
    validate(to)
  }

  override def bytesToStr(value: Ast.expr, expr: Ast.expr): Unit = {
    validate(value)
    validate(expr)
  }

  override def intToStr(value: Ast.expr, num: Ast.expr): Unit = {
    validate(value)
    validate(num)
  }

  override def floatToInt(value: Ast.expr): Unit = validate(value)

  override def kaitaiStreamSize(value: Ast.expr): Unit = validate(value)
  override def kaitaiStreamEof(value: Ast.expr): Unit = validate(value)
  override def kaitaiStreamPos(value: Ast.expr): Unit = validate(value)

  override def arraySubscript(container: Ast.expr, idx: Ast.expr): Unit = {
    validate(container)
    validate(idx)
  }
  override def arrayFirst(a: Ast.expr): Unit = validate(a)
  override def arrayLast(a: Ast.expr): Unit = validate(a)
  override def arraySize(a: Ast.expr): Unit = validate(a)
  override def arrayMin(a: Ast.expr): Unit = validate(a)
  override def arrayMax(a: Ast.expr): Unit = validate(a)

  override def enumToInt(value: Ast.expr, et: DataType.EnumType): Unit = validate(value)

  override def boolToInt(value: Ast.expr): Unit = validate(value)

  override def byteSizeOfValue(attrName: String, valType: DataType): Unit =
    CommonSizeOf.getBitsSizeOfType(attrName, valType)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy