macro WIP

This commit is contained in:
folex 2018-09-08 19:53:02 +02:00
parent 8bc3f6c194
commit db09f03940
6 changed files with 157 additions and 2 deletions

View File

@ -30,11 +30,17 @@ lazy val core = project.settings(
"org.typelevel" %% "cats-core" % "1.2.0", "org.typelevel" %% "cats-core" % "1.2.0",
"org.typelevel" %% "cats-free" % "1.2.0", "org.typelevel" %% "cats-free" % "1.2.0",
"com.chuusai" %% "shapeless" % "2.3.3", "com.chuusai" %% "shapeless" % "2.3.3",
"org.scalatest" %% "scalatest" % "3.0.5" % Test "org.scalatest" %% "scalatest" % "3.0.5" % Test,
) scalaVersion("org.scala-lang" % "scala-reflect" % _).value
),
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)
) )
lazy val root = project lazy val root = project
.in(file(".")) .in(file("."))
.dependsOn(core) .dependsOn(core)
.aggregate(core) .aggregate(core)
.settings(
libraryDependencies ++= Seq("com.chuusai" %% "shapeless" % "2.3.3"),
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)
)

View File

@ -0,0 +1,132 @@
package fluence.hackethberlin
import fluence.hackethberlin.types.{PrimitiveType, _}
import shapeless.labelled.FieldType
import shapeless.syntax
import shapeless.syntax.SingletonOps
import syntax.singleton._
import scala.annotation.{compileTimeOnly, StaticAnnotation}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import scala.reflect.runtime.universe.{Tree, ValDef}
@compileTimeOnly("ToVyper is compileTimeOnly")
class ToVyper extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro ToVyper.impl
}
object ToVyper {
def mapParam(p: ValDef): (String, PrimitiveType) = {
p.name.toString -> mapType(p.tpt)
}
def mapType(t: Tree) = {
t.toString match {
case "String" => fluence.hackethberlin.types.address
case "Int" => fluence.hackethberlin.types.int128
}
}
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe.{Quasiquote, Tree => CTree}
annottees.headOption.map(_.tree) match {
case Some(q"$mods class $tpname $ctorMods(..$paramss) { ..$stats }") =>
println(s"QUASI MATCHED \nmods $mods \ntpname $tpname \nctorMods $ctorMods \nparamss $paramss \nstats$stats")
implicit val liftPrimitive: c.universe.Liftable[PrimitiveType] = c.universe.Liftable[PrimitiveType] {
case `address` => q"_root_.fluence.hackethberlin.types.address"
case `bool` => q"_root_.fluence.hackethberlin.types.bool"
case `int128` => q"_root_.fluence.hackethberlin.types.int128"
case `uint256` => q"_root_.fluence.hackethberlin.types.uint256"
case `decimal` => q"_root_.fluence.hackethberlin.types.decimal"
case `string` => q"_root_.fluence.hackethberlin.types.string"
}
// fluence.hackethberlin.types.PrimitiveType with shapeless.labelled.KeyTag[l.type,fluence.hackethberlin.types.PrimitiveType]
implicit val lift: c.universe.Liftable[(Symbol, PrimitiveType)] = c.universe.Liftable[(Symbol, PrimitiveType)] {
case (l, r) =>
type wtf = fluence.hackethberlin.types.PrimitiveType with shapeless.labelled.KeyTag[
l.type,
fluence.hackethberlin.types.PrimitiveType
]
implicit val liftWtf: c.universe.Liftable[wtf] = c.universe.Liftable[wtf] {
case _ => q"shapeless.labelled.field.apply(_root_.fluence.hackethberlin.types.address)"
}
// q"$l -> $r"
// q"('abc ->> $r)"
q"(${shapeless.syntax.singleton.mkSingletonOps(l).->>(r)})"
}
val params = paramss
.map(p => mapParam(p.asInstanceOf[ValDef]))
.foldRight[CTree](q"shapeless.HNil")(
(elem, acc) => q"$elem :: $acc"
)
c.Expr[Any](q"""
class $tpname(..$paramss) {
def toAST = {
fluence.hackethberlin.FuncDef.apply(
"__init__", $params
)(fluence.hackethberlin.types.EmptyBody.get($params))
}
}
""")
case _ => c.abort(c.enclosingPosition, "Invalid annottee")
}
}
}
// .${params.map(mapParam)} ::
// @inline def apply(defn: Any): Any = meta {
// defn match {
// case cls @ Defn.Class(_, name, _, ctor, template) =>
// val params = ctor.paramss.head
// val tree: Tree =
// q"""
// FuncDef("__init__", HNil, uint256)
// """
// tree
//
// case _ => throw new Exception()
// }
// }
//
//
// def mapParam(p: Term.Param) = {
// s"${p.name}" -> s"${mapType(p.decltpe.get)}"
// }
/*
// Scala
class MyContract(owner: String) {
val _owner: String = owner
def isOwner(addr: String): Boolean = {
_owner == owner
}
}
// Vyper
_owner: public(string)
@public
__init__(owner: string):
self._owner = owner
@public
def isOwner(addr: string):
return self._owner == addr
*/

View File

@ -16,5 +16,6 @@ object PrimitiveType {
case object int128 extends PrimitiveType("int128") case object int128 extends PrimitiveType("int128")
case object uint256 extends PrimitiveType("uint256") case object uint256 extends PrimitiveType("uint256")
case object decimal extends PrimitiveType("decimal") case object decimal extends PrimitiveType("decimal")
case object string extends PrimitiveType("string")
} }
} }

View File

@ -1,4 +1,7 @@
package fluence.hackethberlin.types package fluence.hackethberlin.types
import cats.free.Free
import fluence.hackethberlin.Expr
import shapeless.HList
sealed trait Void extends Type sealed trait Void extends Type
@ -6,3 +9,10 @@ sealed trait Void extends Type
case object Void extends Void { case object Void extends Void {
override def toVyper: String = "" override def toVyper: String = ""
} }
case object EmptyBody {
def get[Args <: HList: DataVyper](args: Args): ProductType[Args] Free[Expr, Unit] = { _ =>
Free.pure(Void)
}
}

View File

@ -65,4 +65,5 @@ object MakeVyperApp extends App {
func(recordStruct.ref('record_address) :: HNil).toVyper func(recordStruct.ref('record_address) :: HNil).toVyper
) )
println(s"MMMMMACRO\n\n ${new MyContract("abc", 123).toAST.toVyper}")
} }

View File

@ -0,0 +1,5 @@
package fluence
import fluence.hackethberlin.ToVyper
@ToVyper
class MyContract(owner: String, friend: Int) {}