mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Generate typescript as a whole
This commit is contained in:
parent
61781dd5bd
commit
7fef0d3906
@ -16,9 +16,9 @@ object Aqua {
|
||||
def validate(input: String): ValidatedNel[AquaError, Model] =
|
||||
parse(input).andThen(ast => Semantics.validate(ast).leftMap(_.map(ts => CompilerError(ts._1.unit._1, ts._2))))
|
||||
|
||||
def generate(input: String): ValidatedNel[AquaError, Queue[String]] =
|
||||
def generate(input: String): ValidatedNel[AquaError, String] =
|
||||
validate(input).map {
|
||||
case g: ScriptModel => g.generateAir
|
||||
case _ => Queue.empty
|
||||
case g: ScriptModel => g.generateTypescript
|
||||
case _ => "//No input given"
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ object Air {
|
||||
private def show(depth: Int, air: Air): String = {
|
||||
def showNext(a: Air) = show(depth + 1, a)
|
||||
|
||||
val space = "\t" * depth
|
||||
val space = " " * depth
|
||||
s"$space(${air.keyword.value}" +
|
||||
(air match {
|
||||
case Air.Null ⇒ ""
|
||||
|
@ -25,5 +25,6 @@ class SrvCallable(srvId: DataView, fnName: String) extends ArrowCallable {
|
||||
class SrvCallableOnPeer(peerId: DataView, srvId: DataView, fnName: String) extends ArrowCallable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
// TODO: hop via relay, if needed!
|
||||
ServiceCallGen(srvId, fnName, args, result).wrap(ctx => (ctx.copy(peerId = peerId), _.copy(peerId = ctx.peerId)))
|
||||
}
|
||||
|
@ -1,35 +1,132 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.generator.DataView.InitPeerId
|
||||
import aqua.generator.DataView.{InitPeerId, StringScalar}
|
||||
import aqua.generator.{Air, AirContext, AirGen, ArrowCallable, DataView, FuncCallable, SrvCallableOnPeer}
|
||||
import aqua.semantics.{ArrowType, DataType}
|
||||
import aqua.semantics.{ArrayType, ArrowType, DataType, Type}
|
||||
import cats.data.{Chain, NonEmptyChain}
|
||||
import cats.syntax.show._
|
||||
|
||||
case class FuncModel(
|
||||
name: String,
|
||||
args: List[(String, Either[DataType, ArrowType])],
|
||||
ret: Option[DataView],
|
||||
ret: Option[(DataView, Type)],
|
||||
body: FuncOp
|
||||
) extends Model {
|
||||
|
||||
def bodyGen: AirGen = body.toAirGen
|
||||
|
||||
def getDataService: String = "getDataSrv"
|
||||
def callbackService: String = "callbackSrv"
|
||||
|
||||
def callable: ArrowCallable =
|
||||
new FuncCallable(args.map(_._1), ret, bodyGen)
|
||||
new FuncCallable(args.map(_._1), ret.map(_._1), bodyGen)
|
||||
|
||||
def typeToTs(t: Type): String = t match {
|
||||
case ArrayType(t) => typeToTs(t) + "[]"
|
||||
case dt: DataType => "any" // TODO render types
|
||||
case at: ArrowType =>
|
||||
s"(${argsToTs(at)}) => ${at.res
|
||||
.fold("void")(_ => "any")}"
|
||||
}
|
||||
|
||||
def argsToTs(at: ArrowType): String =
|
||||
at.args.map(typeToTs).zipWithIndex.map(_.swap).map(kv => "arg" + kv._1 + ": " + kv._2).mkString(", ")
|
||||
|
||||
def argsCallToTs(at: ArrowType): String =
|
||||
at.args.zipWithIndex.map(_._2).map("arg" + _).mkString(", ")
|
||||
|
||||
def argsTypescript: String =
|
||||
args.map {
|
||||
case (n, Left(t)) => s"${n}: " + typeToTs(t)
|
||||
case (n, Right(at)) => s"${n}: " + typeToTs(at)
|
||||
}.mkString(", ")
|
||||
|
||||
def airContext(acc: Map[String, ArrowCallable]): AirContext =
|
||||
AirContext(
|
||||
data = args.collect { //TODO preload these variables
|
||||
case (an, Left(_)) =>
|
||||
an -> DataView.Variable(an)
|
||||
}.toMap,
|
||||
arrows = acc ++ args.collect { case (an, Right(_)) =>
|
||||
an -> new SrvCallableOnPeer(InitPeerId, DataView.StringScalar(callbackService), an)
|
||||
}.toMap,
|
||||
vars = args.map(_._1).toSet
|
||||
)
|
||||
|
||||
def generateAir(acc: Map[String, ArrowCallable]): Air =
|
||||
bodyGen
|
||||
.generate(
|
||||
AirContext(
|
||||
data = args.collect { //TODO preload these variables
|
||||
case (an, Left(_)) =>
|
||||
an -> DataView.Variable(an)
|
||||
}.toMap,
|
||||
arrows = acc ++ args.collect { case (an, Right(_)) =>
|
||||
an -> new SrvCallableOnPeer(InitPeerId, DataView.StringScalar("callback"), an)
|
||||
}.toMap,
|
||||
vars = args.map(_._1).toSet
|
||||
)
|
||||
)
|
||||
.generate(airContext(acc))
|
||||
._2
|
||||
|
||||
def generateTypescript(acc: Map[String, ArrowCallable]): String = {
|
||||
def getDataOp(name: String): FuncOp =
|
||||
CoalgebraModel(
|
||||
Some(ServiceModel(getDataService, StringScalar("\"" + getDataService + "\""))),
|
||||
name,
|
||||
Nil,
|
||||
Some(name)
|
||||
)
|
||||
|
||||
val air = SeqModel(
|
||||
NonEmptyChain.fromChainAppend(
|
||||
Chain.fromSeq(
|
||||
args.collect { case (argName, Left(_)) =>
|
||||
getDataOp(name)
|
||||
}
|
||||
),
|
||||
body
|
||||
)
|
||||
).toAirGen.generate(airContext(acc))._2.show
|
||||
|
||||
val setCallbacks = args.map {
|
||||
case (argName, Left(t)) =>
|
||||
s"""h.on('$getDataService', '$argName', () => {return $argName;});"""
|
||||
case (argName, Right(at)) =>
|
||||
s"""h.on('$callbackService', '$argName', (${argsToTs(at)}) => {return $argName(${argsCallToTs(at)});});"""
|
||||
}.mkString("\n")
|
||||
|
||||
s"""
|
||||
|export async function ${name}(client: FluenceClient, ${argsTypescript}): Promise<${ret
|
||||
.map(_._2)
|
||||
.fold("void")(typeToTs)}> {
|
||||
| let request;
|
||||
| const promise = new Promise<string>((resolve, reject) => {
|
||||
| request = new RequestFlowBuilder()
|
||||
| .withRawScript(
|
||||
| `
|
||||
|$air
|
||||
| `,
|
||||
| )
|
||||
| .configHandler((h) => {
|
||||
| h.on('getRelayService', 'getRelay', () => {
|
||||
| return client.relayPeerId;
|
||||
| });
|
||||
| h.on('getRelayService', 'hasReleay', () => {
|
||||
| return client.relayPeerId !== undefined;
|
||||
| });
|
||||
| $setCallbacks
|
||||
| h.on('nameForServiceWhichResolvesPromise', 'callbackOrAnythingReally', (args) => {
|
||||
| // args is an array of all the arguments to function.
|
||||
| // Extract the right one from the args. If there is only 1 item, you can always use
|
||||
| // the costruct below
|
||||
| const [res] = args;
|
||||
| resolve(res);
|
||||
| });
|
||||
| h.on('nameOfServiceWhereToSendXorError', 'errorProbably', (args) => {
|
||||
| // assuming error is the single argument
|
||||
| const [err] = args;
|
||||
| reject(err);
|
||||
| });
|
||||
| })
|
||||
| .handleTimeout(() => {
|
||||
| reject('message for timeout');
|
||||
| })
|
||||
| .build();
|
||||
| });
|
||||
| await client.initiateFlow(request);
|
||||
| return promise;
|
||||
|}
|
||||
""".stripMargin
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,4 +19,15 @@ case class ScriptModel(funcs: Queue[FuncModel]) extends Model {
|
||||
}
|
||||
._2
|
||||
|
||||
def generateTypescript: String =
|
||||
"""import { FluenceClient, PeerIdB58 } from '@fluencelabs/fluence';
|
||||
|import { RequestFlowBuilder } from '@fluencelabs/fluence/dist/api.unstable';
|
||||
|
|
||||
|""".stripMargin ++ funcs
|
||||
.foldLeft((Map.empty[String, ArrowCallable], Queue.empty[String])) { case ((funcsAcc, outputAcc), func) =>
|
||||
funcsAcc.updated(func.name, func.callable) -> outputAcc.enqueue(func.generateTypescript(funcsAcc))
|
||||
}
|
||||
._2
|
||||
.mkString("\n\n")
|
||||
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
||||
case (n, dt: DataType) => n -> Left(dt)
|
||||
case (n, at: ArrowType) => n -> Right(at)
|
||||
},
|
||||
ret = retValue.map(ValuesAlgebra.valueToData),
|
||||
ret = retValue.map(ValuesAlgebra.valueToData).flatMap(vd => funcArrow.res.map(vd -> _)),
|
||||
body = bg
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user