mirror of
https://github.com/fluencelabs/hackethberlin
synced 2025-04-24 17:02:18 +00:00
Writes simple 3-line program without conditionals
This commit is contained in:
parent
8f2a329f73
commit
9c222f1013
@ -4,6 +4,10 @@ version := "0.1"
|
||||
|
||||
scalaVersion := "2.12.6"
|
||||
|
||||
resolvers += Resolver.sonatypeRepo("releases")
|
||||
|
||||
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
|
||||
|
||||
version := "0.1"
|
||||
fork in Test := true
|
||||
parallelExecution in Test := false
|
||||
|
46
src/main/scala/fluence/hackethberlin/CodeChunk.scala
Normal file
46
src/main/scala/fluence/hackethberlin/CodeChunk.scala
Normal file
@ -0,0 +1,46 @@
|
||||
package fluence.hackethberlin
|
||||
|
||||
import cats.data.Writer
|
||||
import cats.{~>, Monad, Monoid}
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
sealed trait CodeChunk {
|
||||
def toVyper(indent: Int): String
|
||||
}
|
||||
|
||||
case class CodeBlock(lines: Queue[String]) extends CodeChunk {
|
||||
override def toVyper(indent: Int): String =
|
||||
lines.mkString(CodeChunk.spaces(indent), ";\n" + CodeChunk.spaces(indent), ";\n")
|
||||
}
|
||||
|
||||
case class CodeLine(line: String) extends CodeChunk {
|
||||
override def toVyper(indent: Int): String =
|
||||
CodeChunk.spaces(indent) + line
|
||||
}
|
||||
|
||||
object CodeChunk {
|
||||
val Space = " "
|
||||
|
||||
def spaces(indent: Int): String = Space * indent
|
||||
|
||||
implicit object codeChunkMonoid extends Monoid[CodeChunk] {
|
||||
override def empty: CodeChunk = CodeBlock(Queue.empty)
|
||||
|
||||
override def combine(x: CodeChunk, y: CodeChunk): CodeChunk =
|
||||
(x, y) match {
|
||||
case (CodeBlock(lines), CodeLine(line)) ⇒ CodeBlock(lines enqueue line)
|
||||
case (CodeLine(l1), CodeLine(l2)) ⇒ CodeBlock(Queue(l1, l2))
|
||||
case (CodeBlock(ls1), CodeBlock(ls2)) ⇒ CodeBlock(ls1 enqueue ls2)
|
||||
case (CodeLine(line), CodeBlock(lines)) ⇒ CodeBlock(line +: lines)
|
||||
}
|
||||
}
|
||||
|
||||
type W[A] = Writer[CodeChunk, A]
|
||||
|
||||
object fromExpr extends (Expr ~> W) {
|
||||
override def apply[A](fa: Expr[A]): W[A] =
|
||||
Writer(CodeLine(fa.toVyper), fa.boxedValue)
|
||||
|
||||
}
|
||||
}
|
@ -1,27 +1,53 @@
|
||||
package fluence.hackethberlin
|
||||
|
||||
sealed trait Expr[T <: types.Type] {
|
||||
def toVyper(depth: Int): String
|
||||
import types._
|
||||
|
||||
protected def spaces(depth: Int): String = " " * depth
|
||||
sealed trait Expr[T] {
|
||||
def boxedValue: T
|
||||
|
||||
def toVyper: String
|
||||
}
|
||||
|
||||
sealed trait InlineExpr[T <: types.Type] extends Expr[T]{
|
||||
override def toVyper(depth: Int): String = spaces(depth) + toInlineVyper
|
||||
|
||||
def toInlineVyper: String
|
||||
|
||||
sealed trait InlineExpr[T <: types.Type] extends Expr[T] {
|
||||
def toReturn: Expr.Return[T] = Expr.Return[T](this)
|
||||
|
||||
def :=:(name: Symbol): Expr[Expr.Ref[T]] = Expr.Assign[T](Expr.Ref[T](name.name, boxedValue), this)
|
||||
}
|
||||
|
||||
object Expr {
|
||||
case class Ref[T <: types.Type](name: String) extends InlineExpr[T] {
|
||||
override def toInlineVyper: String = name
|
||||
case class Ref[T <: types.Type](name: String, boxedValue: T) extends InlineExpr[T] {
|
||||
override def toVyper: String = name
|
||||
}
|
||||
|
||||
case class Infix[L <: types.Type, R <: types.Type, T <: types.Type](
|
||||
op: String,
|
||||
left: InlineExpr[L],
|
||||
right: InlineExpr[R],
|
||||
boxedValue: T
|
||||
) extends InlineExpr[T] {
|
||||
override def toVyper: String = left.toVyper + s" $op " + right.toVyper
|
||||
}
|
||||
|
||||
case class Assign[T <: Type](ref: Ref[T], value: InlineExpr[T]) extends Expr[Ref[T]] {
|
||||
override def boxedValue: Ref[T] = ref
|
||||
|
||||
override def toVyper: String =
|
||||
s"${ref.toVyper} = ${value.toVyper}"
|
||||
}
|
||||
|
||||
case class Return[T <: types.Type](ret: InlineExpr[T]) extends Expr[T] {
|
||||
override def toVyper(depth: Int): String =
|
||||
spaces(depth) + "return "+ret.toInlineVyper
|
||||
override def boxedValue: T = ret.boxedValue
|
||||
|
||||
override def toVyper: String =
|
||||
"return " + ret.toVyper
|
||||
|
||||
}
|
||||
|
||||
trait Defs {
|
||||
|
||||
def `++`(a: InlineExpr[uint256.type], b: InlineExpr[uint256.type]): InlineExpr[uint256.type] =
|
||||
Infix("+", a, b, uint256)
|
||||
}
|
||||
|
||||
object Defs extends Defs
|
||||
}
|
||||
|
@ -1,18 +1,24 @@
|
||||
package fluence.hackethberlin
|
||||
|
||||
import cats.Monad
|
||||
import fluence.hackethberlin.types.{DataVyper, ProductType}
|
||||
import shapeless._
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
|
||||
class FuncDef[Args <: HList, Ret <: types.Type](
|
||||
name: String,
|
||||
argsDef: ProductType[Args],
|
||||
ret: Option[Ret],
|
||||
body: ProductType[Args] ⇒ Expr[Ret],
|
||||
decorators: Set[Decorator] = Set.empty
|
||||
name: String,
|
||||
argsDef: ProductType[Args],
|
||||
ret: Option[Ret],
|
||||
body: ProductType[Args] ⇒ Free[Expr, Ret],
|
||||
decorators: Set[Decorator] = Set.empty
|
||||
) {
|
||||
|
||||
def bodyVyper: String =
|
||||
body(argsDef).foldMap(CodeChunk.fromExpr).run._1.toVyper(1)
|
||||
|
||||
def toVyper: String =
|
||||
s"${decorators.map(_.toVyper).mkString("\n")}\ndef $name(${argsDef.toArgsVyper})${ret.fold("")(" -> " + _.toVyper)}:\n${body(argsDef).toVyper(1)};\n"
|
||||
s"${decorators.map(_.toVyper).mkString("\n")}\ndef $name(${argsDef.toArgsVyper})${ret.fold("")(" -> " + _.toVyper)}:\n$bodyVyper\n"
|
||||
|
||||
def @:(decorator: Decorator): FuncDef[Args, Ret] =
|
||||
new FuncDef[Args, Ret](name, argsDef, ret, body, decorators + decorator)
|
||||
@ -24,13 +30,13 @@ object FuncDef {
|
||||
name: String,
|
||||
argsDef: Args,
|
||||
ret: Ret
|
||||
)(body: ProductType[Args] ⇒ Expr.Return[Ret]): FuncDef[Args, Ret] =
|
||||
)(body: ProductType[Args] ⇒ Free[Expr, Ret]): FuncDef[Args, Ret] =
|
||||
new FuncDef(name, ProductType(argsDef), Some(ret), body)
|
||||
|
||||
def apply[Args <: HList: DataVyper](
|
||||
name: String,
|
||||
argsDef: Args
|
||||
)(body: ProductType[Args] ⇒ Expr[types.Void]): FuncDef[Args, types.Void] =
|
||||
new FuncDef(name, ProductType(argsDef), None, body)
|
||||
)(body: ProductType[Args] ⇒ Free[Expr, Unit]): FuncDef[Args, types.Void] =
|
||||
new FuncDef(name, ProductType(argsDef), None, args ⇒ body(args).map(_ ⇒ types.Void))
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package fluence.hackethberlin
|
||||
import shapeless._
|
||||
import types._
|
||||
import Decorator._
|
||||
import cats.free.Free
|
||||
import syntax.singleton._
|
||||
|
||||
object MakeVyperApp extends App {
|
||||
@ -27,7 +28,7 @@ object MakeVyperApp extends App {
|
||||
"myFunc",
|
||||
('addr ->> address) :: HNil,
|
||||
address
|
||||
)(args ⇒ args.ref('addr).toReturn)
|
||||
)(args ⇒ Free.liftF(args.ref('addr).toReturn))
|
||||
|
||||
val recordStruct = ProductType(
|
||||
('record_address ->> address) :: ('other_some ->> uint256) :: HNil
|
||||
@ -41,6 +42,21 @@ object MakeVyperApp extends App {
|
||||
|
||||
println(func.toVyper)
|
||||
|
||||
println((`@public` @: func).toVyper)
|
||||
val sumArgs = ProductType(('a ->> uint256) :: ('b ->> uint256) :: HNil)
|
||||
|
||||
import Expr.Defs._
|
||||
|
||||
println(
|
||||
(
|
||||
`@public` @:
|
||||
sumArgs.funcDef("sum", uint256) { args ⇒
|
||||
for {
|
||||
c ← Free.liftF('c :=: `++`(args.ref('a), args.ref('b)))
|
||||
d ← Free.liftF('d :=: `++`(args.ref('b), c))
|
||||
sum ← Free.liftF[Expr, uint256.type](`++`(args.ref('a), d).toReturn)
|
||||
} yield sum
|
||||
}
|
||||
).toVyper
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ sealed trait LowPriorityDataVyperImplicits {
|
||||
}
|
||||
|
||||
implicit def recDataVyper[K <: Symbol, V <: Type](implicit wk: Witness.Aux[K]): DataVyper[FieldType[K, V]] =
|
||||
new DataVyper[FieldType[K, V]]{
|
||||
new DataVyper[FieldType[K, V]] {
|
||||
override def toVyperDefinitions(data: FieldType[K, V]): List[String] =
|
||||
s"${wk.value.name}: ${data.toVyper}" :: Nil
|
||||
}
|
||||
@ -34,13 +34,17 @@ object DataVyper extends LowPriorityDataVyperImplicits {
|
||||
|
||||
def apply[T](implicit dataVyper: DataVyper[T]): DataVyper[T] = dataVyper
|
||||
|
||||
implicit def pairDataIndexedVyper[K <: Symbol, T <: Type](implicit wk: Witness.Aux[K]): DataVyper[FieldType[K, T @@ Indexed]] =
|
||||
implicit def pairDataIndexedVyper[K <: Symbol, T <: Type](
|
||||
implicit wk: Witness.Aux[K]
|
||||
): DataVyper[FieldType[K, T @@ Indexed]] =
|
||||
new DataVyper[FieldType[K, T @@ Indexed]] {
|
||||
override def toVyperDefinitions(data: FieldType[K, T @@ Indexed]): List[String] =
|
||||
s"${wk.value.name}: indexed(${data.toVyper})" :: Nil
|
||||
}
|
||||
|
||||
implicit def pairDataPublicVyper[K <: Symbol, T <: Type](implicit wk: Witness.Aux[K]): DataVyper[FieldType[K, T @@ Public]] =
|
||||
implicit def pairDataPublicVyper[K <: Symbol, T <: Type](
|
||||
implicit wk: Witness.Aux[K]
|
||||
): DataVyper[FieldType[K, T @@ Public]] =
|
||||
new DataVyper[FieldType[K, T @@ Public]] {
|
||||
override def toVyperDefinitions(data: FieldType[K, T @@ Public]): List[String] =
|
||||
s"${wk.value.name}: public(${data.toVyper})" :: Nil
|
||||
|
@ -9,6 +9,7 @@ abstract sealed class PrimitiveType(name: String) extends Type {
|
||||
}
|
||||
|
||||
object PrimitiveType {
|
||||
|
||||
trait Defs {
|
||||
case object address extends PrimitiveType("address")
|
||||
case object bool extends PrimitiveType("bool")
|
||||
@ -16,4 +17,4 @@ object PrimitiveType {
|
||||
case object uint256 extends PrimitiveType("uint256")
|
||||
case object decimal extends PrimitiveType("decimal")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package fluence.hackethberlin.types
|
||||
|
||||
import cats.free.Free
|
||||
import fluence.hackethberlin.{Expr, FuncDef}
|
||||
import shapeless.{HList, Witness}
|
||||
import shapeless.ops.record.Selector
|
||||
|
||||
class ProductType[D <: HList](dataDef: D, dv: DataVyper[D]) extends Type {
|
||||
|
||||
def ref[T <: Symbol, V <: Type](k: Witness.Aux[T])(implicit selector : Selector.Aux[D, T, V]): Expr.Ref[V] =
|
||||
Expr.Ref[V](k.value.name)
|
||||
def ref[T <: Symbol, V <: Type](k: Witness.Aux[T])(implicit selector: Selector.Aux[D, T, V]): Expr.Ref[V] =
|
||||
Expr.Ref[V](k.value.name, selector(dataDef))
|
||||
|
||||
// type in type definition somewhere
|
||||
override def toVyper: String =
|
||||
@ -21,12 +22,13 @@ class ProductType[D <: HList](dataDef: D, dv: DataVyper[D]) extends Type {
|
||||
def toArgsVyper: String =
|
||||
dv.toVyperDefinitions(dataDef).mkString(", ")
|
||||
|
||||
def funcDef[Ret <: Type](name: String, ret: Ret)(body: ProductType[D] ⇒ Expr.Return[Ret]): FuncDef[D, Ret] =
|
||||
def funcDef[Ret <: Type](name: String, ret: Ret)(body: ProductType[D] ⇒ Free[Expr, Ret]): FuncDef[D, Ret] =
|
||||
new FuncDef[D, Ret](name, this, Some(ret), body)
|
||||
|
||||
}
|
||||
|
||||
object ProductType {
|
||||
|
||||
def apply[D <: HList](dataDef: D)(implicit dv: DataVyper[D]): ProductType[D] =
|
||||
new ProductType[D](dataDef, dv)
|
||||
}
|
||||
}
|
||||
|
@ -2,4 +2,4 @@ package fluence.hackethberlin.types
|
||||
|
||||
trait Type {
|
||||
def toVyper: String
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,6 @@ package fluence.hackethberlin.types
|
||||
sealed trait Void extends Type
|
||||
|
||||
// TODO: should it exist as an instance?
|
||||
case object Void extends Type {
|
||||
case object Void extends Void {
|
||||
override def toVyper: String = ""
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user