<commit_before>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wvlet.airframe.surface

import scala.language.experimental.macros
import scala.reflect.macros.{blackbox => sm}

/**
  *
  */
private[surface] object SurfaceMacros {

  def surfaceOf[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    import c.universe._
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    q"wvlet.airframe.surface.SurfaceFactory.of[${targetType}]"
  }

  def methodSurfaceOf[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    import c.universe._
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    q"wvlet.airframe.surface.SurfaceFactory.methodsOf[${targetType}]"
  }

  def of[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    new SurfaceGenerator[c.type](c).createSurfaceOf(targetType)
  }

  def methodsOf[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    new SurfaceGenerator[c.type](c).createMethodSurfaceOf(targetType)
  }

  private[surface] class SurfaceGenerator[C <: sm.Context](val c: C) {

    import c.universe._

    private val seen       = scala.collection.mutable.Set[Type]()
    private val memo       = scala.collection.mutable.Map[Type, c.Tree]()
    private val methodSeen = scala.collection.mutable.Set[Type]()
    private val methodMemo = scala.collection.mutable.Map[Type, c.Tree]()

    type SurfaceFactory = PartialFunction[c.Type, c.Tree]

    def createSurfaceOf(targetType: c.Type): c.Tree = {
      surfaceOf(targetType)
    }

    def localMethodsOf(t: c.Type): Iterable[MethodSymbol] = {
      t.members
        .filter(x => x.isMethod && !x.isConstructor && !x.isImplementationArtifact).map(_.asMethod).filter(
          isTargetMethod(_, t))
    }

    private def createMethodCaller(t: c.Type, name: String, methodArgs: Seq[MethodArg]): c.Tree = {
      val methodName = TermName(name)
      try {
        if (methodArgs.size == 0) {
          q"""
         Some({ (x: Any, args: Seq[Any]) =>  x.asInstanceOf[${t}].${methodName} })
            """
        } else {
          val argList = methodArgs.zipWithIndex.map {
            case (x, i) =>
              q"args(${i}).asInstanceOf[${x.tpe}]"
          }
          q"""
         Some({ (x: Any, args: Seq[Any]) =>  x.asInstanceOf[${t}].${methodName}(..${argList}) })
            """
        }
      } catch {
        case e: Throwable =>
          // Fallback for an unknown error
          q"None"
      }
    }

    def createMethodSurfaceOf(targetType: c.Type): c.Tree = {
      if (methodMemo.contains(targetType)) {
        methodMemo(targetType)
      } else {
        if (methodSeen.contains(targetType)) {
          c.abort(c.enclosingPosition, s"recursive type in method: ${targetType.typeSymbol.fullName}")
        }
        methodSeen += targetType
        val result = targetType match {
          case t @ TypeRef(prefix, typeSymbol, typeArgs) =>
            val list = for (m <- localMethodsOf(t.dealias)) yield {
              val mod        = modifierBitMaskOf(m)
              val owner      = surfaceOf(t)
              val name       = m.name.decodedName.toString
              val ret        = surfaceOf(m.returnType)
              val methodArgs = methodArgsOf(t, m).flatten
              val args       = methodParametersOf(m.owner.typeSignature, m, methodArgs)
              // Generate code for supporting ClassMethodSurface.call(instance, args)
              val methodCaller = createMethodCaller(t, name, methodArgs)
              q"wvlet.airframe.surface.ClassMethodSurface(${mod}, ${owner}, ${name}, ${ret}, ${args}.toIndexedSeq, ${methodCaller})"
            }
            q"IndexedSeq(..$list)"
          case _ =>
            q"Seq.empty"
        }

        val fullName = fullTypeNameOf(targetType.dealias)
        val expr     = q"wvlet.airframe.surface.methodSurfaceCache.getOrElseUpdate(${fullName}, ${result})"
        methodMemo += targetType -> expr
        expr
      }
    }

    private def isEnum(t: c.Type): Boolean = {
      t.baseClasses.exists(x => x.isJava && x.isType && x.asType.name.decodedName.toString.startsWith("java.lang.Enum"))
    }

    private def typeArgsOf(t: c.Type): List[c.Type] = t match {<commit_msg>Generate method caller only for public methods<commit_after>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wvlet.airframe.surface

import scala.language.experimental.macros
import scala.reflect.macros.{blackbox => sm}

/**
  *
  */
private[surface] object SurfaceMacros {

  def surfaceOf[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    import c.universe._
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    q"wvlet.airframe.surface.SurfaceFactory.of[${targetType}]"
  }

  def methodSurfaceOf[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    import c.universe._
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    q"wvlet.airframe.surface.SurfaceFactory.methodsOf[${targetType}]"
  }

  def of[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    new SurfaceGenerator[c.type](c).createSurfaceOf(targetType)
  }

  def methodsOf[A: c.WeakTypeTag](c: sm.Context): c.Tree = {
    val targetType = implicitly[c.WeakTypeTag[A]].tpe
    new SurfaceGenerator[c.type](c).createMethodSurfaceOf(targetType)
  }

  private[surface] class SurfaceGenerator[C <: sm.Context](val c: C) {

    import c.universe._

    private val seen       = scala.collection.mutable.Set[Type]()
    private val memo       = scala.collection.mutable.Map[Type, c.Tree]()
    private val methodSeen = scala.collection.mutable.Set[Type]()
    private val methodMemo = scala.collection.mutable.Map[Type, c.Tree]()

    type SurfaceFactory = PartialFunction[c.Type, c.Tree]

    def createSurfaceOf(targetType: c.Type): c.Tree = {
      surfaceOf(targetType)
    }

    def localMethodsOf(t: c.Type): Iterable[MethodSymbol] = {
      t.members
        .filter(x => x.isMethod && !x.isConstructor && !x.isImplementationArtifact).map(_.asMethod).filter(
          isTargetMethod(_, t))
    }

    private def createMethodCaller(t: c.Type, m: MethodSymbol, name: String, methodArgs: Seq[MethodArg]): c.Tree = {
      val methodName = TermName(name)
      if (m.isPublic) {
        if (methodArgs.size == 0) {
          q"""
         Some({ (x: Any, args: Seq[Any]) =>  x.asInstanceOf[${t}].${methodName} })
            """
        } else {
          val argList = methodArgs.zipWithIndex.map {
            case (x, i) =>
              q"args(${i}).asInstanceOf[${x.tpe}]"
          }
          q"""
         Some({ (x: Any, args: Seq[Any]) =>  x.asInstanceOf[${t}].${methodName}(..${argList}) })
            """
        }
      } else {
        // Fallback for an unknown error
        q"None"
      }
    }

    def createMethodSurfaceOf(targetType: c.Type): c.Tree = {
      if (methodMemo.contains(targetType)) {
        methodMemo(targetType)
      } else {
        if (methodSeen.contains(targetType)) {
          c.abort(c.enclosingPosition, s"recursive type in method: ${targetType.typeSymbol.fullName}")
        }
        methodSeen += targetType
        val result = targetType match {
          case t @ TypeRef(prefix, typeSymbol, typeArgs) =>
            val list = for (m <- localMethodsOf(t.dealias)) yield {
              val mod        = modifierBitMaskOf(m)
              val owner      = surfaceOf(t)
              val name       = m.name.decodedName.toString
              val ret        = surfaceOf(m.returnType)
              val methodArgs = methodArgsOf(t, m).flatten
              val args       = methodParametersOf(m.owner.typeSignature, m, methodArgs)
              // Generate code for supporting ClassMethodSurface.call(instance, args)
              val methodCaller = createMethodCaller(t, m, name, methodArgs)
              q"wvlet.airframe.surface.ClassMethodSurface(${mod}, ${owner}, ${name}, ${ret}, ${args}.toIndexedSeq, ${methodCaller})"
            }
            q"IndexedSeq(..$list)"
          case _ =>
            q"Seq.empty"
        }

        val fullName = fullTypeNameOf(targetType.dealias)
        val expr     = q"wvlet.airframe.surface.methodSurfaceCache.getOrElseUpdate(${fullName}, ${result})"
        methodMemo += targetType -> expr
        expr
      }
    }

    private def isEnum(t: c.Type): Boolean = {
      t.baseClasses.exists(x => x.isJava && x.isType && x.asType.name.decodedName.toString.startsWith("java.lang.Enum"))
    }

    private def typeArgsOf(t: c.Type): List[c.Type] = t match {
{'fraction_non_alphanumeric': 0.12989863099592433, 'fraction_numerical': 0.0010450412791305256, 'mean_word_length': 2.616780045351474, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3636994', 'n_tokens_mistral': 3022, 'n_tokens_neox': 2953, 'n_words': 659}