mirror of
https://github.com/fluencelabs/hackethberlin
synced 2025-04-25 01:12: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"
|
scalaVersion := "2.12.6"
|
||||||
|
|
||||||
|
resolvers += Resolver.sonatypeRepo("releases")
|
||||||
|
|
||||||
|
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
|
||||||
|
|
||||||
version := "0.1"
|
version := "0.1"
|
||||||
fork in Test := true
|
fork in Test := true
|
||||||
parallelExecution in Test := false
|
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
|
package fluence.hackethberlin
|
||||||
|
|
||||||
sealed trait Expr[T <: types.Type] {
|
import types._
|
||||||
def toVyper(depth: Int): String
|
|
||||||
|
|
||||||
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] {
|
sealed trait InlineExpr[T <: types.Type] extends Expr[T] {
|
||||||
override def toVyper(depth: Int): String = spaces(depth) + toInlineVyper
|
|
||||||
|
|
||||||
def toInlineVyper: String
|
|
||||||
|
|
||||||
def toReturn: Expr.Return[T] = Expr.Return[T](this)
|
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 {
|
object Expr {
|
||||||
case class Ref[T <: types.Type](name: String) extends InlineExpr[T] {
|
case class Ref[T <: types.Type](name: String, boxedValue: T) extends InlineExpr[T] {
|
||||||
override def toInlineVyper: String = name
|
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] {
|
case class Return[T <: types.Type](ret: InlineExpr[T]) extends Expr[T] {
|
||||||
override def toVyper(depth: Int): String =
|
override def boxedValue: T = ret.boxedValue
|
||||||
spaces(depth) + "return "+ret.toInlineVyper
|
|
||||||
|
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
|
package fluence.hackethberlin
|
||||||
|
|
||||||
|
import cats.Monad
|
||||||
import fluence.hackethberlin.types.{DataVyper, ProductType}
|
import fluence.hackethberlin.types.{DataVyper, ProductType}
|
||||||
import shapeless._
|
import shapeless._
|
||||||
|
import cats.free.Free
|
||||||
|
import cats.syntax.functor._
|
||||||
|
|
||||||
class FuncDef[Args <: HList, Ret <: types.Type](
|
class FuncDef[Args <: HList, Ret <: types.Type](
|
||||||
name: String,
|
name: String,
|
||||||
argsDef: ProductType[Args],
|
argsDef: ProductType[Args],
|
||||||
ret: Option[Ret],
|
ret: Option[Ret],
|
||||||
body: ProductType[Args] ⇒ Expr[Ret],
|
body: ProductType[Args] ⇒ Free[Expr, Ret],
|
||||||
decorators: Set[Decorator] = Set.empty
|
decorators: Set[Decorator] = Set.empty
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
def bodyVyper: String =
|
||||||
|
body(argsDef).foldMap(CodeChunk.fromExpr).run._1.toVyper(1)
|
||||||
|
|
||||||
def toVyper: String =
|
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] =
|
def @:(decorator: Decorator): FuncDef[Args, Ret] =
|
||||||
new FuncDef[Args, Ret](name, argsDef, ret, body, decorators + decorator)
|
new FuncDef[Args, Ret](name, argsDef, ret, body, decorators + decorator)
|
||||||
@ -24,13 +30,13 @@ object FuncDef {
|
|||||||
name: String,
|
name: String,
|
||||||
argsDef: Args,
|
argsDef: Args,
|
||||||
ret: Ret
|
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)
|
new FuncDef(name, ProductType(argsDef), Some(ret), body)
|
||||||
|
|
||||||
def apply[Args <: HList: DataVyper](
|
def apply[Args <: HList: DataVyper](
|
||||||
name: String,
|
name: String,
|
||||||
argsDef: Args
|
argsDef: Args
|
||||||
)(body: ProductType[Args] ⇒ Expr[types.Void]): FuncDef[Args, types.Void] =
|
)(body: ProductType[Args] ⇒ Free[Expr, Unit]): FuncDef[Args, types.Void] =
|
||||||
new FuncDef(name, ProductType(argsDef), None, body)
|
new FuncDef(name, ProductType(argsDef), None, args ⇒ body(args).map(_ ⇒ types.Void))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package fluence.hackethberlin
|
|||||||
import shapeless._
|
import shapeless._
|
||||||
import types._
|
import types._
|
||||||
import Decorator._
|
import Decorator._
|
||||||
|
import cats.free.Free
|
||||||
import syntax.singleton._
|
import syntax.singleton._
|
||||||
|
|
||||||
object MakeVyperApp extends App {
|
object MakeVyperApp extends App {
|
||||||
@ -27,7 +28,7 @@ object MakeVyperApp extends App {
|
|||||||
"myFunc",
|
"myFunc",
|
||||||
('addr ->> address) :: HNil,
|
('addr ->> address) :: HNil,
|
||||||
address
|
address
|
||||||
)(args ⇒ args.ref('addr).toReturn)
|
)(args ⇒ Free.liftF(args.ref('addr).toReturn))
|
||||||
|
|
||||||
val recordStruct = ProductType(
|
val recordStruct = ProductType(
|
||||||
('record_address ->> address) :: ('other_some ->> uint256) :: HNil
|
('record_address ->> address) :: ('other_some ->> uint256) :: HNil
|
||||||
@ -41,6 +42,21 @@ object MakeVyperApp extends App {
|
|||||||
|
|
||||||
println(func.toVyper)
|
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
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,13 +34,17 @@ object DataVyper extends LowPriorityDataVyperImplicits {
|
|||||||
|
|
||||||
def apply[T](implicit dataVyper: DataVyper[T]): DataVyper[T] = dataVyper
|
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]] {
|
new DataVyper[FieldType[K, T @@ Indexed]] {
|
||||||
override def toVyperDefinitions(data: FieldType[K, T @@ Indexed]): List[String] =
|
override def toVyperDefinitions(data: FieldType[K, T @@ Indexed]): List[String] =
|
||||||
s"${wk.value.name}: indexed(${data.toVyper})" :: Nil
|
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]] {
|
new DataVyper[FieldType[K, T @@ Public]] {
|
||||||
override def toVyperDefinitions(data: FieldType[K, T @@ Public]): List[String] =
|
override def toVyperDefinitions(data: FieldType[K, T @@ Public]): List[String] =
|
||||||
s"${wk.value.name}: public(${data.toVyper})" :: Nil
|
s"${wk.value.name}: public(${data.toVyper})" :: Nil
|
||||||
|
@ -9,6 +9,7 @@ abstract sealed class PrimitiveType(name: String) extends Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object PrimitiveType {
|
object PrimitiveType {
|
||||||
|
|
||||||
trait Defs {
|
trait Defs {
|
||||||
case object address extends PrimitiveType("address")
|
case object address extends PrimitiveType("address")
|
||||||
case object bool extends PrimitiveType("bool")
|
case object bool extends PrimitiveType("bool")
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package fluence.hackethberlin.types
|
package fluence.hackethberlin.types
|
||||||
|
|
||||||
|
import cats.free.Free
|
||||||
import fluence.hackethberlin.{Expr, FuncDef}
|
import fluence.hackethberlin.{Expr, FuncDef}
|
||||||
import shapeless.{HList, Witness}
|
import shapeless.{HList, Witness}
|
||||||
import shapeless.ops.record.Selector
|
import shapeless.ops.record.Selector
|
||||||
@ -7,7 +8,7 @@ import shapeless.ops.record.Selector
|
|||||||
class ProductType[D <: HList](dataDef: D, dv: DataVyper[D]) extends Type {
|
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] =
|
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)
|
Expr.Ref[V](k.value.name, selector(dataDef))
|
||||||
|
|
||||||
// type in type definition somewhere
|
// type in type definition somewhere
|
||||||
override def toVyper: String =
|
override def toVyper: String =
|
||||||
@ -21,12 +22,13 @@ class ProductType[D <: HList](dataDef: D, dv: DataVyper[D]) extends Type {
|
|||||||
def toArgsVyper: String =
|
def toArgsVyper: String =
|
||||||
dv.toVyperDefinitions(dataDef).mkString(", ")
|
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)
|
new FuncDef[D, Ret](name, this, Some(ret), body)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object ProductType {
|
object ProductType {
|
||||||
|
|
||||||
def apply[D <: HList](dataDef: D)(implicit dv: DataVyper[D]): ProductType[D] =
|
def apply[D <: HList](dataDef: D)(implicit dv: DataVyper[D]): ProductType[D] =
|
||||||
new ProductType[D](dataDef, dv)
|
new ProductType[D](dataDef, dv)
|
||||||
}
|
}
|
@ -3,6 +3,6 @@ package fluence.hackethberlin.types
|
|||||||
sealed trait Void extends Type
|
sealed trait Void extends Type
|
||||||
|
|
||||||
// TODO: should it exist as an instance?
|
// TODO: should it exist as an instance?
|
||||||
case object Void extends Type {
|
case object Void extends Void {
|
||||||
override def toVyper: String = ""
|
override def toVyper: String = ""
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user