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

izumi.idealingua.translator.toscala.tools.ScalaTranslationTools.scala Maven / Gradle / Ivy

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

import izumi.idealingua.model.common.TypeId.DTOId
import izumi.idealingua.model.common.{Builtin, SigParam, StructureId, TypeId}
import izumi.idealingua.model.typespace.structures.ConverterDef
import izumi.idealingua.translator.toscala.STContext
import izumi.idealingua.translator.toscala.types.CompositeStructure

import scala.meta._

case class Params(params: List[Term.Param], types: List[TypeId], assertions: List[Term.ApplyInfix]) {
  def assertion: List[Term] = {
    if (assertions.isEmpty) {
      List.empty
    } else {
      val expr = assertions.tail.foldLeft(assertions.head) {
        case (a, acc) =>
          q"$acc && $a"
      }
      List(q"assert($expr)")
    }
  }
}

class ScalaTranslationTools(ctx: STContext) {

  import izumi.idealingua.translator.toscala.types.ScalaField._
  import ctx.conv._

  def mkStructure(id: StructureId): CompositeStructure = {
    val fields = ctx.typespace.structure.structure(id).toScala
    new CompositeStructure(ctx, fields)
  }

  def idToParaName(id: TypeId): Term.Name = Term.Name(ctx.typespace.tools.idToParaName(id))

  def makeParams(t: ConverterDef): Params = {
    val out = t.outerParams.map {
      f =>
        /*
          ANYVAL:ERASURE
           this is a workaround for anyval/scala erasure issue.
           We prohibit to use DTOs directly in parameters and using mirrors instead
         */
        val source = f.sourceType match {
          case s: DTOId =>
            ctx.typespace.tools.defnId(s)

          case o =>
            o
        }

        val scalaType = ctx.conv.toScala(source)
        val name      = Term.Name(f.sourceName)

        (f, source, (name, scalaType.typeFull))
    }

    // this allows us to get rid of "unused" warnings and do a good thing
    val assertions = out.map {
      case (field, _, (name, _)) =>
        if (!ctx.typespace.dealias(field.sourceType).isInstanceOf[Builtin]) {
          List(q"$name.asInstanceOf[_root_.scala.AnyRef] ne null")
        } else {
          List.empty
        }
    }

    Params(out.map(_._3).toParams, out.map(_._2), assertions.flatten)
  }

  def makeConstructor(t: ConverterDef): List[Term.Assign] = {
    t.allFields.map(toAssignment)
  }

  private def toAssignment(f: SigParam): Term.Assign = {
    f.sourceFieldName match {
      case Some(sourceFieldName) =>
        q""" ${Term.Name(f.targetFieldName)} = ${Term.Name(f.source.sourceName)}.${Term.Name(sourceFieldName)}  """

      case None =>
        val sourceType = f.source.sourceType

        val defnid = sourceType match {
          case d: DTOId =>
            ctx.typespace.tools.defnId(d)
          case o =>
            o
        }

        if (defnid == sourceType) {
          q""" ${Term.Name(f.targetFieldName)} = ${Term.Name(f.source.sourceName)}  """
        } else {
          q""" ${Term.Name(f.targetFieldName)} = ${ctx.conv.toScala(sourceType).termFull}(${Term.Name(f.source.sourceName)})"""
        }
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy