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

olon.json.ScalaSig.scala Maven / Gradle / Ivy

package olon
package json

import scala.tools.scalap.scalax.rules.scalasig._

private[json] object ScalaSigReader {
  // Originally, we used `method.children` and expected all children of a
  // MethodSymbol to be parameters. In Scala 2.13, a change was made that never
  // returns parameters in `children`. To get around this, we look up parameter
  // symbols separately here.
  //
  // This works across Scala versions, so we don't scope it to 2.13
  // specifically. See Scala bug 11747, currently at
  // https://github.com/scala/bug/issues/11747 , for more.
  private def paramSymbolsFor(method: MethodSymbol): Seq[Symbol] = { // TODO gets type params of the method
    method
      .applyScalaSigRule(ScalaSigParsers.symbols)
      .filter(symbol => symbol.parent == Some(method) && symbol.isParam)
  }

  // SCALA3 using `?` instead of `_`
  // TODO gets the constructor of clazz, gets its typeArgIndex type argument primitive type
  def readConstructor(
      argName: String,
      clazz: Class[?],
      typeArgIndex: Int,
      argNames: List[String]
  ): Class[?] = { // returns a class with the type of an typeArgIndex argument
    val cl = findClass(clazz)
    val cstr = findConstructor(cl, argNames)
      .getOrElse( // finds constructor with argNames arguments
        Meta.fail("Can't find constructor for " + clazz)
      )
    findArgType(
      cstr,
      argNames.indexOf(argName),
      typeArgIndex
    ) // finds argIndex tastyp
  }

  // SCALA3 using `?` instead of `_`
  // TODO returns the primitive that is the typeArgIndex argument of the method `name` in clazz
  def readField(name: String, clazz: Class[?], typeArgIndex: Int): Class[?] = {
    def read(current: Class[?]): MethodSymbol = { // TODO
      if (current == null)
        Meta.fail("Can't find field " + name + " from " + clazz)
      else
        findField(findClass(current), name).getOrElse(
          read(current.getSuperclass)
        )
    }
    findArgTypeForField(read(clazz), typeArgIndex)
  }

  // SCALA3 using `?` instead of `_`
  private def findClass(clazz: Class[?]): ClassSymbol = {
    val sig = findScalaSig(clazz).getOrElse(
      Meta.fail("Can't find ScalaSig for " + clazz)
    )
    findClass(sig, clazz).getOrElse(
      Meta.fail("Can't find " + clazz + " from parsed ScalaSig")
    )
  }

  // SCALA3 using `?` instead of `_`
  private def findClass(sig: ScalaSig, clazz: Class[?]): Option[ClassSymbol] = { // ScalaSig => (class)Symbol
    sig.symbols // TODO fieldMembers and method members of a class
      .collect {
        case c: ClassSymbol if !c.isModule => c
      } // TODO collect internal classes
      .find(_.name == clazz.getSimpleName) // TODO equals clazz
      .orElse {
        sig.topLevelClasses // TODO get inner classes of ScalaSig
          .find(_.symbolInfo.name == clazz.getSimpleName) // TODO equals clazz
          .orElse {
            sig.topLevelObjects.map { obj =>
              val t =
                obj.infoType.asInstanceOf[
                  TypeRefType
                ] // TODO gets objects and their children
              t.symbol.children collect { case c: ClassSymbol =>
                c
              } find (_.symbolInfo.name == clazz.getSimpleName) // TODO equals clazz
            }.head
          }
      }
  }

  private def findConstructor(
      c: ClassSymbol,
      argNames: List[String]
  ): Option[MethodSymbol] = {
    val ms = c.children collect {
      case m: MethodSymbol if m.name == "" => m
    }
    ms.find(m => paramSymbolsFor(m).map(_.name) == argNames)
  }

  private def findField(
      c: ClassSymbol,
      name: String
  ): Option[MethodSymbol] = // TODO returns method with `name`
    (c.children collect {
      case m: MethodSymbol if m.name == name => m
    }).headOption

  // SCALA3 using `?` instead of `_`
  private def findArgType( // `converts` argIdx's type parameter into a primitive
      s: MethodSymbol,
      argIdx: Int,
      typeArgIndex: Int
  ): Class[?] = {
    def findPrimitive(t: Type): Symbol =
      t match { // TODO looks for first primitive in type parameters
        case TypeRefType(ThisType(_), symbol, _) if isPrimitive(symbol) =>
          symbol
        case TypeRefType(_, _, TypeRefType(ThisType(_), symbol, _) :: _) =>
          symbol
        case TypeRefType(_, symbol, Nil) => symbol
        case TypeRefType(_, _, args) if typeArgIndex >= args.length =>
          findPrimitive(args(0))
        case TypeRefType(_, _, args) =>
          args(typeArgIndex) match {
            case ref @ TypeRefType(_, _, _) => findPrimitive(ref)
            case x => Meta.fail("Unexpected type info " + x)
          }
        case x => Meta.fail("Unexpected type info " + x)
      }
    toClass(
      findPrimitive(
        paramSymbolsFor(s)(argIdx).asInstanceOf[SymbolInfoSymbol].infoType
      )
    )
  }

  // SCALA3 using `?` instead of `_`
  private def findArgTypeForField(
      s: MethodSymbol,
      typeArgIdx: Int
  ): Class[?] = {
    val t = s.infoType match {
      case NullaryMethodType(TypeRefType(_, _, args)) => args(typeArgIdx)
    }

    @scala.annotation.tailrec
    def findPrimitive(t: Type): Symbol = t match {
      case TypeRefType(ThisType(_), symbol, _) => symbol
      case ref @ TypeRefType(_, _, _)          => findPrimitive(ref)
      case x => Meta.fail("Unexpected type info " + x)
    }
    toClass(findPrimitive(t))
  }

  private def toClass(s: Symbol) = s.path match {
    case "scala.Short"   => classOf[Short]
    case "scala.Int"     => classOf[Int]
    case "scala.Long"    => classOf[Long]
    case "scala.Boolean" => classOf[Boolean]
    case "scala.Float"   => classOf[Float]
    case "scala.Double"  => classOf[Double]
    case _               => classOf[AnyRef]
  }

  private def isPrimitive(s: Symbol) = toClass(s) != classOf[AnyRef]

  // SCALA3 using `?` instead of `_`
  private def findScalaSig(clazz: Class[?]): Option[ScalaSig] = {
    ScalaSigParser
      .parse(clazz)
      .orElse(findScalaSig(clazz.getDeclaringClass)) // TODO guess: class Symbol
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy