mirror of
https://github.com/fluencelabs/hackethberlin
synced 2025-04-24 17:02:18 +00:00
macro WIP
This commit is contained in:
parent
8bc3f6c194
commit
db09f03940
10
build.sbt
10
build.sbt
@ -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)
|
||||||
|
)
|
||||||
|
132
core/src/main/scala/fluence/hackethberlin/ToVyper.scala
Normal file
132
core/src/main/scala/fluence/hackethberlin/ToVyper.scala
Normal 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
|
||||||
|
|
||||||
|
*/
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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}")
|
||||||
}
|
}
|
||||||
|
5
src/main/scala/fluence/MyContract.scala
Normal file
5
src/main/scala/fluence/MyContract.scala
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package fluence
|
||||||
|
import fluence.hackethberlin.ToVyper
|
||||||
|
|
||||||
|
@ToVyper
|
||||||
|
class MyContract(owner: String, friend: Int) {}
|
Loading…
x
Reference in New Issue
Block a user