Merge remote-tracking branch 'origin/master'

This commit is contained in:
alari 2018-09-08 22:35:50 +02:00
commit 863f3491cb
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-free" % "1.2.0",
"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
.in(file("."))
.dependsOn(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 uint256 extends PrimitiveType("uint256")
case object decimal extends PrimitiveType("decimal")
case object string extends PrimitiveType("string")
}
}

View File

@ -1,4 +1,7 @@
package fluence.hackethberlin.types
import cats.free.Free
import fluence.hackethberlin.Expr
import shapeless.HList
sealed trait Void extends Type
@ -6,3 +9,10 @@ sealed trait Void extends Type
case object Void extends Void {
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
)
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) {}