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

izumi.idealingua.translator.toscala.IdRenderer.scala Maven / Gradle / Ivy

The newest version!
package izumi.idealingua.translator.toscala

import izumi.idealingua.model.common.PrimitiveId
import izumi.idealingua.model.common.TypeId.{EnumId, IdentifierId}
import izumi.idealingua.model.problems.IDLException
import izumi.idealingua.model.il.ast.typed.TypeDef.Identifier
import izumi.idealingua.translator.toscala.products.{CogenProduct, RenderableCogenProduct}

import scala.meta._

class IdRenderer(ctx: STContext) {
  import ctx._
  import conv._

  def renderIdentifier(i: Identifier): RenderableCogenProduct = {
    val fields   = typespace.structure.structure(i).toScala
    val decls    = fields.all.toParams
    val typeName = i.id.name

    val interp = Term.Interpolate(Term.Name("s"), List(Lit.String(typeName + "#"), Lit.String("")), List(Term.Name("suffix")))

    val t     = conv.toScala(i.id)
    val tools = t.within(s"${i.id.name}Extensions")

    val qqTools = q"""implicit class ${tools.typeName}(_value: ${t.typeFull}) { }"""

    val sortedFields = fields.all.sortBy(_.field.field.name)

    val parsers = sortedFields.zipWithIndex.map { case (field, idx) => (field, idx, field.field.field.typeId) }.map {
      case (field, idx, t: EnumId) =>
        q"${field.name} = ${conv.toScala(t).termFull}.parse(parts(${Lit.Int(idx)}))"
      case (field, idx, t: IdentifierId) =>
        q"${field.name} = ${conv.toScala(t).termFull}.parse(parts(${Lit.Int(idx)}))"
      case (field, idx, _: PrimitiveId) =>
        q"${field.name} = parsePart[${field.fieldType}](parts(${Lit.Int(idx)}), classOf[${field.fieldType}])"
      case o =>
        throw new IDLException(s"Impossible case/id field: $o")
    }

    val parts = sortedFields.map(fi => q"this.${fi.name}")

    val superClasses = List(rt.generated.init(), rt.tIDLIdentifier.init())

    val errorInterp = Term.Interpolate(Term.Name("s"), List(Lit.String("Serialized form of "), Lit.String(s" should start with $typeName#")), List(Term.Name("name")))

    val qqCompanion =
      q"""object ${t.termName} {
            def parse(s: String): ${t.typeName} = {
              import ${rt.tIDLIdentifier.termBase}._
              if (!s.startsWith(${Lit.String(typeName.toString + "#")})) {
                val name = ${Lit.String(i.id.toString)}
                throw new IllegalArgumentException($errorInterp)
              }
              val withoutPrefix = s.substring(s.indexOf("#") + 1)
              val parts = withoutPrefix.split(':').map(part => unescape(part))
              ${t.termName}(..$parsers)
            }
      }"""

    val qqIdentifier =
      q"""final case class ${t.typeName} (..$decls) extends ..$superClasses {
            override def toString: String = {
              import ${rt.tIDLIdentifier.termBase}._
              val suffix = Seq(..$parts).map(part => escape(part.toString)).mkString(":")
              $interp
            }
         }"""

    ext.extend(i, CogenProduct(qqIdentifier, qqCompanion, qqTools, List.empty), _.handleIdentifier)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy