mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Merge pull request #4 from fluencelabs/gen-ts
Generate basic TypeScript file
This commit is contained in:
commit
6a67fa175e
47
src/main/resources/example.ts
Normal file
47
src/main/resources/example.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { FluenceClient, PeerIdB58 } from '@fluencelabs/fluence';
|
||||
import { RequestFlowBuilder } from '@fluencelabs/fluence/dist/api.unstable';
|
||||
export async function getTime(client: FluenceClient, peerId: PeerIdB58, ret: (time: number) => void): Promise<string> {
|
||||
let request;
|
||||
const promise = new Promise<string>((resolve, reject) => {
|
||||
request = new RequestFlowBuilder()
|
||||
.withRawScript(
|
||||
`
|
||||
text of the generated script
|
||||
on many
|
||||
lines
|
||||
`,
|
||||
)
|
||||
.configHandler((h) => {
|
||||
h.on('getRelayService', 'getRelay', () => {
|
||||
return client.relayPeerId;
|
||||
});
|
||||
h.on('getRelayService', 'hasReleay', () => {
|
||||
return client.relayPeerId !== undefined;
|
||||
});
|
||||
h.on('nameForParamsGetterService', 'getPeerID', () => {
|
||||
return peerId;
|
||||
});
|
||||
h.on('nameForServiceIdGenertedForPlaceWhereRetIsCalled', 'retProbably', (args) => {
|
||||
(ret as any).apply(args);
|
||||
});
|
||||
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;
|
||||
}
|
@ -1,23 +1,22 @@
|
||||
package aqua
|
||||
|
||||
import aqua.ast.gen.{Gen, ScriptGen}
|
||||
import aqua.ast.{Ast, Compiler}
|
||||
import aqua.model.{Model, ScriptModel}
|
||||
import aqua.parser.Ast
|
||||
import cats.data.ValidatedNel
|
||||
import aqua.parser.lift.Span
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
import aqua.semantics.Semantics
|
||||
|
||||
object Aqua {
|
||||
|
||||
def parse(input: String): ValidatedNel[AquaError, Ast[Span.F]] =
|
||||
Ast.fromString[Span.F](input)
|
||||
|
||||
def compile(input: String): ValidatedNel[AquaError, Gen] =
|
||||
parse(input).andThen(ast => Compiler.compile(ast).leftMap(_.map(ts => CompilerError(ts._1.unit._1, ts._2))))
|
||||
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]] =
|
||||
compile(input).map {
|
||||
case g: ScriptGen => g.generateAir
|
||||
case _ => Queue.empty
|
||||
def generate(input: String): ValidatedNel[AquaError, String] =
|
||||
validate(input).map {
|
||||
case g: ScriptModel => g.generateTypescript
|
||||
case _ => "//No input given"
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,11 @@ package aqua
|
||||
import cats.data.Validated
|
||||
import cats.effect.{ExitCode, IO, IOApp}
|
||||
import fs2.io.file.Files
|
||||
import fs2.{text, Stream}
|
||||
import cats.implicits._
|
||||
import fs2.text
|
||||
|
||||
import java.io.{File, PrintWriter}
|
||||
import scala.io.Source
|
||||
import java.nio.file.{Path, Paths}
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import cats.syntax.traverse._
|
||||
|
||||
final case class ParseArgsException(private val message: String, private val cause: Throwable = None.orNull)
|
||||
extends Exception(message, cause)
|
||||
@ -51,22 +50,21 @@ object AquaGen extends IOApp {
|
||||
def convertAqua(files: List[File], outputDir: Path): IO[List[Unit]] = {
|
||||
(for {
|
||||
file <- files
|
||||
} yield {
|
||||
Files[IO]
|
||||
.readAll(file.toPath, 4096)
|
||||
.through(text.utf8Decode)
|
||||
.map(text =>
|
||||
Aqua.generate(text) match {
|
||||
case Validated.Valid(v) ⇒
|
||||
v.mkString("\n")
|
||||
case Validated.Invalid(errs) ⇒
|
||||
errs.map(_.showForConsole(text)).toList.mkString("\n")
|
||||
}
|
||||
)
|
||||
.through(text.utf8Encode)
|
||||
.through(Files[IO].writeAll(outputDir.resolve(file.getName + ".result")))
|
||||
.compile
|
||||
.drain
|
||||
}).sequence
|
||||
} yield Files[IO]
|
||||
.readAll(file.toPath, 4096)
|
||||
.through(text.utf8Decode)
|
||||
.map(text =>
|
||||
Aqua.generate(text) match {
|
||||
case Validated.Valid(v) ⇒
|
||||
v
|
||||
case Validated.Invalid(errs) ⇒
|
||||
errs.map(_.showForConsole(text)).map(println)
|
||||
""
|
||||
}
|
||||
)
|
||||
.through(text.utf8Encode)
|
||||
.through(Files[IO].writeAll(outputDir.resolve(file.getName + ".js")))
|
||||
.compile
|
||||
.drain).sequence
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{ArrowTypeToken, Name}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class ArrowTypeExpr[F[_]](name: Name[F], `type`: ArrowTypeToken[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg], A: AbilitiesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
T.resolveArrowDef(`type`).flatMap {
|
||||
case Some(t) => A.defineArrow(name, t) as Gen.noop
|
||||
case None => Gen.error.lift
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object ArrowTypeExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[Expr[F]] =
|
||||
((Name.p[F] <* ` : `) ~ ArrowTypeToken.`arrowdef`[F]).map {
|
||||
case (name, t) => ArrowTypeExpr(name, t)
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.{Gen, ServiceCallGen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Name, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class CoalgebraExpr[F[_]](
|
||||
variable: Option[Name[F]],
|
||||
ability: Option[Ability[F]],
|
||||
funcName: Name[F],
|
||||
args: List[Value[F]]
|
||||
) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
N: NamesAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg]
|
||||
): Prog[Alg, Gen] =
|
||||
ability
|
||||
.fold(N.readArrow(funcName))(A.getArrow(_, funcName))
|
||||
.flatMap {
|
||||
case Some(at) =>
|
||||
V.checkArguments(at.`type`, args) >> variable
|
||||
.fold(Free.pure[Alg, Boolean](true))(exportVar =>
|
||||
at.`type`.res.fold(
|
||||
// TODO: error! we're trying to export variable, but function has no export type
|
||||
Free.pure[Alg, Boolean](false)
|
||||
)(resType => N.define(exportVar, resType))
|
||||
) >> at.gen[F, Alg](args, variable).widen[Gen]
|
||||
case None =>
|
||||
Gen.error.lift[Alg]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object CoalgebraExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[CoalgebraExpr[F]] =
|
||||
((Name.p[F] <* ` <- `).backtrack.?.with1 ~
|
||||
((Ability.ab[F] <* `.`).?.with1 ~
|
||||
Name.p[F] ~
|
||||
comma0(Value.`value`[F]).between(`(`, `)`))).map {
|
||||
case (variable, ((ability, funcName), args)) =>
|
||||
CoalgebraExpr(variable, ability, funcName, args)
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.CustomTypeToken
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class DataStructExpr[F[_]](name: CustomTypeToken[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
N: NamesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg]
|
||||
): Prog[Alg, Gen] =
|
||||
Prog.after((_: Gen) =>
|
||||
T.purgeFields(name).flatMap {
|
||||
case Some(fields) => T.defineDataType(name, fields) as Gen.noop // TODO it's not air gen, but ts gen
|
||||
case None => Gen.error.lift
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
object DataStructExpr extends Expr.AndIndented(FieldTypeExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[DataStructExpr[F]] =
|
||||
`data` *> ` ` *> CustomTypeToken.ct[F].map(DataStructExpr(_)) <* ` : \n+`
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.Ast.Tree
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.{Expr, Indent, Prog}
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.scope.PeerIdAlgebra
|
||||
import aqua.ast.algebra.types.{ArrowType, DataType, Type, TypesAlgebra}
|
||||
import aqua.ast.gen.DataView.InitPeerId
|
||||
import aqua.ast.gen.{AirContext, AirGen, ArrowGen, DataView, FuncBodyGen, FuncGen, Gen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value, VarLambda}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.free.{Cofree, Free}
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
import cats.{Applicative, Comonad, Eval}
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTypeToken[F]], retValue: Option[Value[F]])
|
||||
extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
T: TypesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
P: PeerIdAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Prog[Alg, Gen] =
|
||||
Prog.around(
|
||||
A.beginScope(name) >> Applicative[Free[Alg, *]]
|
||||
.product(
|
||||
// Collect argument types, define local variables
|
||||
args
|
||||
.foldLeft(
|
||||
// Begin scope -- for mangling
|
||||
N.beginScope(name).as[Queue[Type]](Queue.empty)
|
||||
) {
|
||||
case (f, Arg(argName, argType)) =>
|
||||
// Resolve arg type, remember it
|
||||
f.flatMap(acc =>
|
||||
T.resolveType(argType).flatMap {
|
||||
case Some(t: ArrowType) =>
|
||||
N.defineArrow(argName, ArrowGen.arg(argName.value, t), isRoot = false).as(acc.enqueue(t))
|
||||
case Some(t) =>
|
||||
N.define(argName, t).as(acc.enqueue(t))
|
||||
case None =>
|
||||
Free.pure(acc)
|
||||
}
|
||||
)
|
||||
}
|
||||
.map(_.toList),
|
||||
// Resolve return type
|
||||
ret.fold(Free.pure[Alg, Option[Type]](None))(T.resolveType(_))
|
||||
)
|
||||
.map(argsAndRes => ArrowType(argsAndRes._1, argsAndRes._2)),
|
||||
(funcArrow: ArrowType, bodyGen: Gen) =>
|
||||
// Check return value type
|
||||
((funcArrow.res, retValue) match {
|
||||
case (Some(t), Some(v)) =>
|
||||
V.resolveType(v).flatMap {
|
||||
case Some(vt) => T.ensureTypeMatches(v, t, vt).void
|
||||
case None => Free.pure[Alg, Unit](())
|
||||
}
|
||||
case _ =>
|
||||
Free.pure[Alg, Unit](())
|
||||
})
|
||||
// Erase arguments and internal variables
|
||||
>> A.endScope() >> N.endScope() >> (bodyGen match {
|
||||
case bg: AirGen if ret.isDefined == retValue.isDefined =>
|
||||
val argNames = args.map(_.name.value)
|
||||
N.defineArrow(
|
||||
name,
|
||||
ArrowGen.func(funcArrow, argNames, retValue.map(ArrowGen.valueToData), FuncBodyGen(bg)),
|
||||
isRoot = true
|
||||
) as FuncGen(
|
||||
name.value,
|
||||
Eval.later {
|
||||
bg.generate(
|
||||
AirContext(
|
||||
data = argNames
|
||||
.zip(funcArrow.args)
|
||||
.collect { //TODO preload these variables
|
||||
case (an, _: DataType) =>
|
||||
an -> DataView.Variable(an)
|
||||
}
|
||||
.toMap,
|
||||
arrows = argNames
|
||||
.zip(funcArrow.args)
|
||||
.collect {
|
||||
case (an, _: ArrowType) =>
|
||||
an -> new ArrowGen.SrvCallableOnPeer(InitPeerId, DataView.StringScalar("callback"), an)
|
||||
}
|
||||
.toMap,
|
||||
vars = argNames.toSet
|
||||
)
|
||||
)
|
||||
._2
|
||||
},
|
||||
FuncBodyGen(bg)
|
||||
)
|
||||
case _ => Gen.noop.lift
|
||||
})
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
object FuncExpr extends Expr.AndIndented(OnExpr, AbilityIdExpr, ReturnExpr, CoalgebraExpr, ParExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
||||
((`func` *> ` ` *> Name.p[F]) ~ comma0(Arg.p)
|
||||
.between(`(`, `)`) ~ (` -> ` *> DataTypeToken.`datatypedef`).? <* ` : \n+`).map {
|
||||
case ((name, args), ret) => FuncExpr(name, args, ret, None)
|
||||
}
|
||||
|
||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): Parser[Tree[F]] =
|
||||
super.ast(ps).flatMap { tree =>
|
||||
tree.head match {
|
||||
case funcExpr: FuncExpr[F] if funcExpr.ret.isDefined =>
|
||||
tree.tail.value.lastOption.map(_.head) match {
|
||||
case Some(re: ReturnExpr[F]) =>
|
||||
Parser.pure(
|
||||
Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail)
|
||||
)
|
||||
case _ =>
|
||||
Parser.failWith(
|
||||
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
|
||||
)
|
||||
}
|
||||
|
||||
case _ => Parser.pure(tree)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.scope.PeerIdAlgebra
|
||||
import aqua.ast.gen.{AirGen, ArrowGen, Gen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Value
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class OnExpr[F[_]](peerId: Value[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
P: PeerIdAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Prog[Alg, Gen] =
|
||||
Prog.around(
|
||||
V.ensureIsString(peerId) >> P.onPeerId(peerId) >> A.beginScope(peerId),
|
||||
(_: Unit, ops: Gen) =>
|
||||
A.endScope() >> P.erasePeerId() as (ops match {
|
||||
case air: AirGen =>
|
||||
air.wrap(c => (c.copy(peerId = ArrowGen.valueToData(peerId)), _.copy(peerId = c.peerId)))
|
||||
case _ => ops
|
||||
})
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
object OnExpr extends Expr.AndIndented(CoalgebraExpr, AbilityIdExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[OnExpr[F]] =
|
||||
(`on` *> ` ` *> Value.`value`[F] <* ` : \n+`).map { peerId =>
|
||||
OnExpr(peerId)
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Value
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class ReturnExpr[F[_]](value: Value[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit V: ValuesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
V.resolveType(value).as(Gen.noop)
|
||||
|
||||
}
|
||||
|
||||
object ReturnExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[Expr[F]] =
|
||||
(`<-` *> ` ` *> Value.`value`[F]).map(ReturnExpr(_))
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.gen.{Gen, ScriptGen}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import cats.syntax.semigroup._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
case class RootExpr[F[_]]() extends Expr[F] {
|
||||
|
||||
def program[Alg[_]]: Prog[Alg, Gen] =
|
||||
Prog.after(a => (a |+| ScriptGen(Queue.empty)).lift)
|
||||
}
|
||||
|
||||
object RootExpr
|
@ -1,53 +0,0 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.{ArrowGen, Gen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.apply._
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class ServiceExpr[F[_]](name: Ability[F], id: Option[Value[F]]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
A: AbilitiesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg]
|
||||
): Prog[Alg, Gen] =
|
||||
Prog.around(
|
||||
A.beginScope(name),
|
||||
(_: Unit, body: Gen) =>
|
||||
(A.purgeArrows(name) <* A.endScope()).flatMap {
|
||||
case Some(nel) =>
|
||||
A.defineService(
|
||||
name,
|
||||
nel.map(kv => kv._1.value -> ArrowGen.service(name.value, kv._1.value, kv._2)).toNem
|
||||
) >>
|
||||
id.fold(Free.pure[Alg, Gen](Gen.noop))(idV =>
|
||||
V.ensureIsString(idV) >> A.setServiceId(name, idV) as Gen.noop
|
||||
)
|
||||
case None =>
|
||||
Gen.error.lift
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
object ServiceExpr extends Expr.AndIndented(ArrowTypeExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[ServiceExpr[F]] =
|
||||
(`service` *> ` ` *> Ability.ab[F] ~ Value.`value`[F].between(`(`, `)`).backtrack.? <* ` : \n+`).map {
|
||||
case (name, id) => ServiceExpr(name, id)
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package aqua.ast.gen
|
||||
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import DataView.InitPeerId
|
||||
import aqua.parser.lexer.{IntoArray, IntoField, LambdaOp, Literal, Name, Value, VarLambda}
|
||||
import cats.free.Free
|
||||
|
||||
abstract class ArrowGen(val `type`: ArrowType) {
|
||||
|
||||
def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen]
|
||||
}
|
||||
|
||||
object ArrowGen {
|
||||
|
||||
private def opsToLens[F[_]](ops: List[LambdaOp[F]]): String =
|
||||
ops match {
|
||||
case Nil => ""
|
||||
case (_: IntoArray[F]) :: tail => "[@" + opsToLens(tail) + "]"
|
||||
case (f: IntoField[F]) :: tail => "." + f.value + opsToLens(tail)
|
||||
}
|
||||
|
||||
def valueToData[F[_]](v: Value[F]): DataView =
|
||||
v match {
|
||||
case l: Literal[F] => DataView.StringScalar(l.value)
|
||||
case VarLambda(name, Nil) => DataView.Variable(name.value)
|
||||
case VarLambda(name, ops) => DataView.VarLens(name.value, opsToLens(ops))
|
||||
}
|
||||
|
||||
private def argsToData[F[_]](args: List[Value[F]]): List[DataView] = args.map(valueToData)
|
||||
|
||||
trait Callable {
|
||||
def toCallGen(args: List[DataView], result: Option[String]): AirGen
|
||||
}
|
||||
|
||||
class FuncCallable(argNames: List[String], retValue: Option[DataView], bodyGen: FuncBodyGen) extends Callable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
bodyGen.op
|
||||
.wrap(c =>
|
||||
(
|
||||
c.copy(data = c.data ++ argNames.zip(args)),
|
||||
_.copy(data = c.data ++ result.zip(retValue))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class SrvCallable(srvId: DataView, fnName: String) extends Callable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
ServiceCallGen(srvId, fnName, args, result)
|
||||
}
|
||||
|
||||
class SrvCallableOnPeer(peerId: DataView, srvId: DataView, fnName: String) extends Callable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
ServiceCallGen(srvId, fnName, args, result).wrap(ctx => (ctx.copy(peerId = peerId), _.copy(peerId = ctx.peerId)))
|
||||
}
|
||||
|
||||
def func(`type`: ArrowType, argNames: List[String], retValue: Option[DataView], bodyGen: FuncBodyGen): ArrowGen =
|
||||
new ArrowGen(`type`) {
|
||||
|
||||
override def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen] =
|
||||
Free.pure[Alg, AirGen](
|
||||
new FuncCallable(argNames, retValue, bodyGen).toCallGen(argsToData(args), result.map(_.value))
|
||||
)
|
||||
}
|
||||
|
||||
def service(name: String, fnName: String, `type`: ArrowType): ArrowGen =
|
||||
new ArrowGen(`type`) {
|
||||
|
||||
override def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen] =
|
||||
// TODO it's really weird that we're losing token here
|
||||
A.getServiceId(name).map {
|
||||
case Some(sid) =>
|
||||
new SrvCallable(valueToData(sid), fnName).toCallGen(argsToData(args), result.map(_.value))
|
||||
case None =>
|
||||
NullGen
|
||||
}
|
||||
}
|
||||
|
||||
def arg(name: String, `type`: ArrowType): ArrowGen =
|
||||
new ArrowGen(`type`) {
|
||||
|
||||
override def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen] =
|
||||
Free.pure[Alg, AirGen](
|
||||
new AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = {
|
||||
println(Console.YELLOW + ctx + Console.RESET)
|
||||
ctx.arrows(name).toCallGen(argsToData(args), result.map(_.value)).generate(ctx)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package aqua.ast.gen
|
||||
package aqua.generator
|
||||
|
||||
import cats.Show
|
||||
import cats.syntax.show._
|
||||
@ -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 ⇒ ""
|
@ -1,10 +1,10 @@
|
||||
package aqua.ast.gen
|
||||
package aqua.generator
|
||||
|
||||
import DataView.InitPeerId
|
||||
|
||||
case class AirContext(
|
||||
data: Map[String, DataView] = Map.empty,
|
||||
arrows: Map[String, ArrowGen.Callable] = Map.empty,
|
||||
arrows: Map[String, ArrowCallable] = Map.empty,
|
||||
peerId: DataView = InitPeerId,
|
||||
vars: Set[String] = Set.empty,
|
||||
instrCounter: Int = 0
|
41
src/main/scala/aqua/generator/ArrowCallable.scala
Normal file
41
src/main/scala/aqua/generator/ArrowCallable.scala
Normal file
@ -0,0 +1,41 @@
|
||||
package aqua.generator
|
||||
|
||||
import aqua.semantics.{ArrowType, DataType}
|
||||
|
||||
sealed trait ArrowCallable {
|
||||
def toCallGen(args: List[DataView], result: Option[String]): AirGen
|
||||
}
|
||||
|
||||
class FuncCallable(argNames: List[(String, Either[DataType, ArrowType])], retValue: Option[DataView], bodyGen: AirGen)
|
||||
extends ArrowCallable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
bodyGen.wrap { c =>
|
||||
val argsFull = argNames.zip(args)
|
||||
val argsToData = argsFull.collect { case ((n, Left(_)), v) =>
|
||||
n -> v
|
||||
}
|
||||
// TODO: here we need to collect ArrowCallable's
|
||||
val argsToArrows = argsFull.collect { case ((n, Right(_)), v) =>
|
||||
n -> v
|
||||
}
|
||||
|
||||
(
|
||||
c.copy(data = c.data ++ argsToData),
|
||||
_.copy(data = c.data ++ result.zip(retValue))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SrvCallable(srvId: DataView, fnName: String) extends ArrowCallable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
ServiceCallGen(srvId, fnName, args, result)
|
||||
}
|
||||
|
||||
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,43 +1,8 @@
|
||||
package aqua.ast.gen
|
||||
package aqua.generator
|
||||
|
||||
import cats.{Eval, Semigroup}
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.show._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
sealed trait Gen {
|
||||
def lift[F[_]]: Free[F, Gen] = Free.pure(this)
|
||||
}
|
||||
|
||||
object Gen {
|
||||
|
||||
implicit object GenSemigroup extends Semigroup[Gen] {
|
||||
|
||||
override def combine(x: Gen, y: Gen): Gen =
|
||||
(x, y) match {
|
||||
case (x: ScriptGen, y: ScriptGen) => y.copy(funcs = y.funcs.enqueueAll(x.funcs))
|
||||
case (x: FuncGen, y: FuncGen) => ScriptGen(Queue(x, y))
|
||||
case (x: FuncGen, y: ScriptGen) => y.copy(funcs = y.funcs.enqueue(x))
|
||||
case (x: ScriptGen, y: FuncGen) => x.copy(funcs = x.funcs.enqueue(y))
|
||||
case (x: AirGen, y: FuncBodyGen) => y.copy(op = SeqGen(x, y.op))
|
||||
case (x: AirGen, y: ParGen) => ParGen(Some(x), y.right)
|
||||
case (x: AirGen, y: AirGen) => SeqGen(x, y)
|
||||
|
||||
case (NoopGen, _) => y
|
||||
case (_, NoopGen) => x
|
||||
|
||||
case (_, y) =>
|
||||
println(Console.RED + s"drop x: ${x} in favor of y: $y" + Console.RESET)
|
||||
y
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def noop: Gen = NoopGen
|
||||
def error: Gen = NoopGen
|
||||
}
|
||||
sealed trait Gen
|
||||
|
||||
trait AirGen extends Gen {
|
||||
self =>
|
||||
@ -58,12 +23,9 @@ case object NullGen extends AirGen {
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = (ctx, Air.Null)
|
||||
}
|
||||
|
||||
case object NoopGen extends Gen
|
||||
|
||||
case class SeqGen(left: AirGen, right: AirGen) extends AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = {
|
||||
println(Console.BLUE + ctx + Console.RESET)
|
||||
val (c, l) = left.generate(ctx)
|
||||
right.generate(c).swap.map(_.incr).swap.map(Air.Seq(l, _))
|
||||
}
|
||||
@ -104,24 +66,11 @@ case class ServiceCallGen(
|
||||
}
|
||||
}
|
||||
|
||||
case class FuncBodyGen(op: AirGen) extends Gen
|
||||
case class ParGen(left: AirGen, right: AirGen) extends AirGen {
|
||||
|
||||
case class FuncGen(name: String, air: Eval[Air], body: FuncBodyGen) extends Gen {
|
||||
def generateAir: Air = air.memoize.value
|
||||
}
|
||||
|
||||
case class ScriptGen(funcs: Queue[FuncGen]) extends Gen {
|
||||
|
||||
def generateAir: Queue[String] =
|
||||
funcs.map(_.generateAir.show)
|
||||
}
|
||||
|
||||
case class ParGen(left: Option[AirGen], right: AirGen) extends AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) =
|
||||
left.fold(right.generate(ctx)) { l =>
|
||||
val (lc, la) = l.generate(ctx)
|
||||
val (rc, ra) = right.generate(ctx.incr)
|
||||
(lc.mergePar(rc).incr, Air.Par(la, ra))
|
||||
}
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = {
|
||||
val (lc, la) = left.generate(ctx)
|
||||
val (rc, ra) = right.generate(ctx.incr)
|
||||
(lc.mergePar(rc).incr, Air.Par(la, ra))
|
||||
}
|
||||
}
|
16
src/main/scala/aqua/generator/TypescriptFile.scala
Normal file
16
src/main/scala/aqua/generator/TypescriptFile.scala
Normal file
@ -0,0 +1,16 @@
|
||||
package aqua.generator
|
||||
|
||||
import cats.Show
|
||||
|
||||
case class TypescriptFile(funcs: Seq[TypescriptFunc])
|
||||
|
||||
object TypescriptFile {
|
||||
|
||||
val Header: String =
|
||||
"""import { FluenceClient, PeerIdB58 } from '@fluencelabs/fluence';
|
||||
|import { RequestFlowBuilder } from '@fluencelabs/fluence/dist/api.unstable';
|
||||
|""".stripMargin
|
||||
|
||||
implicit val show: Show[TypescriptFile] =
|
||||
Show.show(tf => Header + "\n\n" + tf.funcs.map(_.generateTypescript).mkString("\n\n"))
|
||||
}
|
87
src/main/scala/aqua/generator/TypescriptFunc.scala
Normal file
87
src/main/scala/aqua/generator/TypescriptFunc.scala
Normal file
@ -0,0 +1,87 @@
|
||||
package aqua.generator
|
||||
|
||||
import aqua.model.FuncModel
|
||||
import aqua.semantics.{ArrayType, ArrowType, DataType, Type}
|
||||
import cats.syntax.show._
|
||||
|
||||
case class TypescriptFunc(func: FuncModel, tsAir: Air) {
|
||||
|
||||
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 =
|
||||
func.args.map {
|
||||
case (n, Left(t)) => s"${n}: " + typeToTs(t)
|
||||
case (n, Right(at)) => s"${n}: " + typeToTs(at)
|
||||
}.mkString(", ")
|
||||
|
||||
def generateTypescript: String = {
|
||||
|
||||
val returnCallback = func.ret.map { case (dv, t) =>
|
||||
s"""h.on('${func.callbackService}', '${func.respFuncName}', (args) => {
|
||||
| const [res] = args;
|
||||
| resolve(res);
|
||||
|});
|
||||
|""".stripMargin
|
||||
|
||||
}
|
||||
|
||||
val setCallbacks = func.args.map {
|
||||
case (argName, Left(t)) =>
|
||||
s"""h.on('${func.getDataService}', '$argName', () => {return $argName;});"""
|
||||
case (argName, Right(at)) =>
|
||||
s"""h.on('${func.callbackService}', '$argName', (${argsToTs(at)}) => {return $argName(${argsCallToTs(
|
||||
at
|
||||
)});});"""
|
||||
}.mkString("\n")
|
||||
|
||||
s"""
|
||||
|export async function ${func.name}(client: FluenceClient, ${argsTypescript}): Promise<${func.ret
|
||||
.map(_._2)
|
||||
.fold("void")(typeToTs)}> {
|
||||
| let request;
|
||||
| const promise = new Promise<string>((resolve, reject) => {
|
||||
| request = new RequestFlowBuilder()
|
||||
| .withRawScript(
|
||||
| `
|
||||
|${tsAir.show}
|
||||
| `,
|
||||
| )
|
||||
| .configHandler((h) => {
|
||||
| h.on('${func.getDataService}', 'relay', () => {
|
||||
| return client.relayPeerId;
|
||||
| });
|
||||
| h.on('getRelayService', 'hasReleay', () => {// Not Used
|
||||
| return client.relayPeerId !== undefined;
|
||||
| });
|
||||
| $setCallbacks
|
||||
| ${returnCallback.getOrElse("")}
|
||||
| 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
|
||||
}
|
||||
|
||||
}
|
7
src/main/scala/aqua/model/AbilityModel.scala
Normal file
7
src/main/scala/aqua/model/AbilityModel.scala
Normal file
@ -0,0 +1,7 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.generator.DataView
|
||||
|
||||
sealed trait AbilityModel extends Model
|
||||
|
||||
case class ServiceModel(name: String, id: DataView) extends AbilityModel
|
103
src/main/scala/aqua/model/FuncModel.scala
Normal file
103
src/main/scala/aqua/model/FuncModel.scala
Normal file
@ -0,0 +1,103 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.generator.DataView.{InitPeerId, StringScalar}
|
||||
import aqua.generator.{
|
||||
Air,
|
||||
AirContext,
|
||||
AirGen,
|
||||
ArrowCallable,
|
||||
DataView,
|
||||
FuncCallable,
|
||||
SrvCallableOnPeer,
|
||||
TypescriptFunc
|
||||
}
|
||||
import aqua.semantics.{ArrowType, DataType, Type}
|
||||
import cats.data.{Chain, NonEmptyChain}
|
||||
|
||||
case class FuncModel(
|
||||
name: String,
|
||||
args: List[(String, Either[DataType, ArrowType])],
|
||||
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, ret.map(_._1), bodyGen)
|
||||
|
||||
def airContext(acc: Map[String, ArrowCallable]): AirContext =
|
||||
AirContext(
|
||||
data = args.collect { 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(acc))
|
||||
._2
|
||||
|
||||
def generateTs(acc: Map[String, ArrowCallable]): TypescriptFunc =
|
||||
TypescriptFunc(this, generateTsAir(acc))
|
||||
|
||||
val respFuncName = "response"
|
||||
|
||||
val returnCallback: Option[FuncOp] = ret.map { case (dv, t) =>
|
||||
viaRelay(
|
||||
CoalgebraModel(
|
||||
Some(ServiceModel(callbackService, StringScalar("\"" + callbackService + "\""))),
|
||||
respFuncName,
|
||||
(dv, t) :: Nil,
|
||||
None
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
def generateTsAir(acc: Map[String, ArrowCallable]): Air =
|
||||
SeqModel(
|
||||
NonEmptyChain
|
||||
.fromChainAppend(
|
||||
Chain.fromSeq(
|
||||
args.collect { case (argName, Left(_)) =>
|
||||
getDataOp(argName)
|
||||
} :+ getDataOp("relay")
|
||||
),
|
||||
body
|
||||
)
|
||||
.appendChain(Chain.fromSeq(returnCallback.toSeq))
|
||||
).toAirGen.generate(airContext(acc))._2
|
||||
|
||||
def getDataOp(name: String): FuncOp =
|
||||
CoalgebraModel(
|
||||
Some(ServiceModel(getDataService, StringScalar("\"" + getDataService + "\""))),
|
||||
name,
|
||||
Nil,
|
||||
Some(name)
|
||||
)
|
||||
|
||||
def viaRelay(op: FuncOp): FuncOp =
|
||||
OnModel(
|
||||
DataView.Variable("relay"),
|
||||
SeqModel(
|
||||
NonEmptyChain(
|
||||
CoalgebraModel(
|
||||
Some(ServiceModel("op", StringScalar("\"op\""))),
|
||||
"identity",
|
||||
Nil,
|
||||
None
|
||||
),
|
||||
OnModel(InitPeerId, op)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
55
src/main/scala/aqua/model/FuncOp.scala
Normal file
55
src/main/scala/aqua/model/FuncOp.scala
Normal file
@ -0,0 +1,55 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.generator.{AirContext, AirGen, DataView, ParGen, SeqGen, SrvCallable}
|
||||
import aqua.semantics.Type
|
||||
import cats.data.{NonEmptyChain, NonEmptyList}
|
||||
import cats.kernel.Semigroup
|
||||
|
||||
sealed trait FuncOp extends Model {
|
||||
def toAirGen: AirGen
|
||||
}
|
||||
|
||||
object FuncOp {
|
||||
|
||||
implicit object MergeOps extends Semigroup[FuncOp] {
|
||||
|
||||
override def combine(x: FuncOp, y: FuncOp): FuncOp = (x, y) match {
|
||||
case (l: ParModel, r: ParModel) => ParModel(l.ops ++ r.ops.toList)
|
||||
case (l, r: ParModel) => ParModel(l :: r.ops)
|
||||
case (l: SeqModel, r: SeqModel) => SeqModel(l.ops ++ r.ops)
|
||||
case (l: SeqModel, r) => SeqModel(l.ops.append(r))
|
||||
case (l, r) => SeqModel(NonEmptyChain(l, r))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SeqModel(ops: NonEmptyChain[FuncOp]) extends FuncOp {
|
||||
override def toAirGen: AirGen = ops.map(_.toAirGen).reduceLeft(SeqGen)
|
||||
}
|
||||
|
||||
case class ParModel(ops: NonEmptyList[FuncOp]) extends FuncOp {
|
||||
override def toAirGen: AirGen = ops.map(_.toAirGen).reduceLeft(ParGen)
|
||||
}
|
||||
|
||||
case class OnModel(peerId: DataView, op: FuncOp) extends FuncOp {
|
||||
|
||||
override def toAirGen: AirGen =
|
||||
op.toAirGen.wrap(ctx => (ctx.copy(peerId = peerId), _.copy(peerId = ctx.peerId)))
|
||||
}
|
||||
|
||||
case class CoalgebraModel(
|
||||
ability: Option[AbilityModel],
|
||||
funcName: String,
|
||||
args: List[(DataView, Type)],
|
||||
exportTo: Option[String]
|
||||
) extends FuncOp {
|
||||
|
||||
def toAirGen: AirGen =
|
||||
ability match {
|
||||
case Some(ServiceModel(_, id)) =>
|
||||
new SrvCallable(id, funcName).toCallGen(args.map(_._1), exportTo)
|
||||
case None =>
|
||||
(ctx: AirContext) => ctx.arrows(funcName).toCallGen(args.map(_._1), exportTo).generate(ctx)
|
||||
}
|
||||
|
||||
}
|
33
src/main/scala/aqua/model/Model.scala
Normal file
33
src/main/scala/aqua/model/Model.scala
Normal file
@ -0,0 +1,33 @@
|
||||
package aqua.model
|
||||
|
||||
import cats.kernel.Semigroup
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
trait Model
|
||||
|
||||
object Model {
|
||||
def empty: Model = EmptyModel
|
||||
def error: Model = EmptyModel
|
||||
|
||||
implicit object MergeModels extends Semigroup[Model] {
|
||||
|
||||
override def combine(x: Model, y: Model): Model = (x, y) match {
|
||||
case (l: FuncOp, r: FuncOp) =>
|
||||
FuncOp.MergeOps.combine(l, r)
|
||||
case (l: ScriptModel, r: ScriptModel) => ScriptModel(l.funcs ++ r.funcs)
|
||||
case (l: FuncModel, r: FuncModel) => ScriptModel(Queue(l, r))
|
||||
case (l: ScriptModel, r: FuncModel) => ScriptModel(l.funcs.appended(r))
|
||||
case (l: FuncModel, r: ScriptModel) => ScriptModel(r.funcs.prepended(l))
|
||||
case (_, r: ScriptModel) => r
|
||||
case (l: ScriptModel, _) => l
|
||||
case (_, r: FuncModel) => r
|
||||
case (l: FuncModel, _) => l
|
||||
case (EmptyModel, EmptyModel) => EmptyModel
|
||||
case (EmptyModel, r) => r
|
||||
case (l, EmptyModel) => l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object EmptyModel extends Model
|
32
src/main/scala/aqua/model/ScriptModel.scala
Normal file
32
src/main/scala/aqua/model/ScriptModel.scala
Normal file
@ -0,0 +1,32 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.generator.{ArrowCallable, TypescriptFile, TypescriptFunc}
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
import cats.syntax.show._
|
||||
|
||||
case class ScriptModel(funcs: Queue[FuncModel]) extends Model {
|
||||
|
||||
def enqueue(m: Model): ScriptModel = m match {
|
||||
case f: FuncModel => copy(funcs.enqueue(f))
|
||||
case _ => this
|
||||
}
|
||||
|
||||
def generateAir: Queue[String] =
|
||||
funcs
|
||||
.foldLeft((Map.empty[String, ArrowCallable], Queue.empty[String])) { case ((funcsAcc, outputAcc), func) =>
|
||||
funcsAcc.updated(func.name, func.callable) -> outputAcc.enqueue(func.generateAir(funcsAcc).show)
|
||||
}
|
||||
._2
|
||||
|
||||
def generateTypescript: String =
|
||||
TypescriptFile(
|
||||
funcs
|
||||
.foldLeft((Map.empty[String, ArrowCallable], Queue.empty[TypescriptFunc])) {
|
||||
case ((funcsAcc, outputAcc), func) =>
|
||||
funcsAcc.updated(func.name, func.callable) -> outputAcc.enqueue(func.generateTs(funcsAcc))
|
||||
}
|
||||
._2
|
||||
).show
|
||||
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package aqua.ast
|
||||
package aqua.parser
|
||||
|
||||
import aqua.ast.expr.{AliasExpr, DataStructExpr, FuncExpr, RootExpr, ServiceExpr}
|
||||
import aqua.{AquaError, SyntaxError}
|
||||
import aqua.parser.expr._
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.{Comonad, Eval}
|
||||
import aqua.{AquaError, SyntaxError}
|
||||
import cats.data.{NonEmptyList, Validated, ValidatedNel}
|
||||
import cats.free.Cofree
|
||||
import cats.parse.{Parser => P, Parser0 => P0}
|
||||
import aqua.parser.lexer.Token._
|
||||
import cats.data.{NonEmptyList, Validated, ValidatedNel}
|
||||
import cats.{Comonad, Eval}
|
||||
|
||||
case class Ast[F[_]](tree: Ast.Tree[F]) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
package aqua.ast
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.free.Cofree
|
||||
import cats.{Comonad, Eval}
|
||||
import cats.parse.{Parser => P}
|
||||
import aqua.parser.lexer.Token._
|
||||
import cats.{Comonad, Eval}
|
||||
|
||||
trait Expr[F[_]] {}
|
||||
|
@ -1,3 +1,3 @@
|
||||
package aqua.ast
|
||||
package aqua.parser
|
||||
|
||||
case class Indent(indent: String = "")
|
@ -1,23 +1,13 @@
|
||||
package aqua.ast.expr
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class AbilityIdExpr[F[_]](ability: Ability[F], id: Value[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit A: AbilitiesAlgebra[F, Alg], V: ValuesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
V.ensureIsString(id) >> A.setServiceId(ability, id) as Gen.noop
|
||||
|
||||
}
|
||||
case class AbilityIdExpr[F[_]](ability: Ability[F], id: Value[F]) extends Expr[F]
|
||||
|
||||
object AbilityIdExpr extends Expr.Leaf {
|
||||
|
@ -1,25 +1,13 @@
|
||||
package aqua.ast.expr
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{CustomTypeToken, TypeToken}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class AliasExpr[F[_]](name: CustomTypeToken[F], target: TypeToken[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
T.resolveType(target).flatMap {
|
||||
case Some(t) => T.defineAlias(name, t) as Gen.noop
|
||||
case None => Gen.error.lift
|
||||
}
|
||||
|
||||
}
|
||||
case class AliasExpr[F[_]](name: CustomTypeToken[F], target: TypeToken[F]) extends Expr[F]
|
||||
|
||||
object AliasExpr extends Expr.Leaf {
|
||||
|
18
src/main/scala/aqua/parser/expr/ArrowTypeExpr.scala
Normal file
18
src/main/scala/aqua/parser/expr/ArrowTypeExpr.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{ArrowTypeToken, Name}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
|
||||
case class ArrowTypeExpr[F[_]](name: Name[F], `type`: ArrowTypeToken[F]) extends Expr[F] {}
|
||||
|
||||
object ArrowTypeExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[Expr[F]] =
|
||||
((Name.p[F] <* ` : `) ~ ArrowTypeToken.`arrowdef`[F]).map {
|
||||
case (name, t) => ArrowTypeExpr(name, t)
|
||||
}
|
||||
}
|
28
src/main/scala/aqua/parser/expr/CoalgebraExpr.scala
Normal file
28
src/main/scala/aqua/parser/expr/CoalgebraExpr.scala
Normal file
@ -0,0 +1,28 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Name, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser => P}
|
||||
|
||||
case class CoalgebraExpr[F[_]](
|
||||
variable: Option[Name[F]],
|
||||
ability: Option[Ability[F]],
|
||||
funcName: Name[F],
|
||||
args: List[Value[F]]
|
||||
) extends Expr[F]
|
||||
|
||||
object CoalgebraExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[CoalgebraExpr[F]] =
|
||||
((Name.p[F] <* ` <- `).backtrack.?.with1 ~
|
||||
((Ability.ab[F] <* `.`).?.with1 ~
|
||||
Name.p[F] ~
|
||||
comma0(Value.`value`[F]).between(`(`, `)`))).map {
|
||||
case (variable, ((ability, funcName), args)) =>
|
||||
CoalgebraExpr(variable, ability, funcName, args)
|
||||
}
|
||||
|
||||
}
|
16
src/main/scala/aqua/parser/expr/DataStructExpr.scala
Normal file
16
src/main/scala/aqua/parser/expr/DataStructExpr.scala
Normal file
@ -0,0 +1,16 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.CustomTypeToken
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
|
||||
case class DataStructExpr[F[_]](name: CustomTypeToken[F]) extends Expr[F]
|
||||
|
||||
object DataStructExpr extends Expr.AndIndented(FieldTypeExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[DataStructExpr[F]] =
|
||||
`data` *> ` ` *> CustomTypeToken.ct[F].map(DataStructExpr(_)) <* ` : \n+`
|
||||
}
|
@ -1,25 +1,13 @@
|
||||
package aqua.ast.expr
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{DataTypeToken, Name}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class FieldTypeExpr[F[_]](name: Name[F], `type`: DataTypeToken[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
T.resolveType(`type`).flatMap {
|
||||
case Some(t) => T.defineField(name, t) as Gen.noop
|
||||
case None => Gen.error.lift
|
||||
}
|
||||
|
||||
}
|
||||
case class FieldTypeExpr[F[_]](name: Name[F], `type`: DataTypeToken[F]) extends Expr[F]
|
||||
|
||||
object FieldTypeExpr extends Expr.Leaf {
|
||||
|
41
src/main/scala/aqua/parser/expr/FuncExpr.scala
Normal file
41
src/main/scala/aqua/parser/expr/FuncExpr.scala
Normal file
@ -0,0 +1,41 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Ast.Tree
|
||||
import aqua.parser.{Expr, Indent}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.free.Cofree
|
||||
import cats.parse.Parser
|
||||
import cats.Comonad
|
||||
|
||||
case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTypeToken[F]], retValue: Option[Value[F]])
|
||||
extends Expr[F]
|
||||
|
||||
object FuncExpr extends Expr.AndIndented(OnExpr, AbilityIdExpr, ReturnExpr, CoalgebraExpr, ParExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
||||
((`func` *> ` ` *> Name.p[F]) ~ comma0(Arg.p)
|
||||
.between(`(`, `)`) ~ (` -> ` *> DataTypeToken.`datatypedef`).? <* ` : \n+`).map {
|
||||
case ((name, args), ret) => FuncExpr(name, args, ret, None)
|
||||
}
|
||||
|
||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): Parser[Tree[F]] =
|
||||
super.ast(ps).flatMap { tree =>
|
||||
tree.head match {
|
||||
case funcExpr: FuncExpr[F] if funcExpr.ret.isDefined =>
|
||||
tree.tail.value.lastOption.map(_.head) match {
|
||||
case Some(re: ReturnExpr[F]) =>
|
||||
Parser.pure(
|
||||
Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail)
|
||||
)
|
||||
case _ =>
|
||||
Parser.failWith(
|
||||
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
|
||||
)
|
||||
}
|
||||
|
||||
case _ => Parser.pure(tree)
|
||||
}
|
||||
}
|
||||
}
|
18
src/main/scala/aqua/parser/expr/OnExpr.scala
Normal file
18
src/main/scala/aqua/parser/expr/OnExpr.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Value
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser => P}
|
||||
|
||||
case class OnExpr[F[_]](peerId: Value[F]) extends Expr[F]
|
||||
|
||||
object OnExpr extends Expr.AndIndented(CoalgebraExpr, AbilityIdExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[OnExpr[F]] =
|
||||
(`on` *> ` ` *> Value.`value`[F] <* ` : \n+`).map { peerId =>
|
||||
OnExpr(peerId)
|
||||
}
|
||||
}
|
@ -1,21 +1,13 @@
|
||||
package aqua.ast.expr
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.ast.gen.{AirGen, Gen, ParGen}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
|
||||
case class ParExpr[F[_]](point: F[Unit]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]]: Prog[Alg, Gen] =
|
||||
Prog.after[Alg, Gen] {
|
||||
case g: AirGen => ParGen(left = None, right = g).lift
|
||||
case g => g.lift
|
||||
}
|
||||
}
|
||||
case class ParExpr[F[_]](point: F[Unit]) extends Expr[F]
|
||||
|
||||
object ParExpr extends Expr.AndThen(OnExpr, CoalgebraExpr) {
|
||||
|
16
src/main/scala/aqua/parser/expr/ReturnExpr.scala
Normal file
16
src/main/scala/aqua/parser/expr/ReturnExpr.scala
Normal file
@ -0,0 +1,16 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Value
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
|
||||
case class ReturnExpr[F[_]](value: Value[F]) extends Expr[F]
|
||||
|
||||
object ReturnExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[Expr[F]] =
|
||||
(`<-` *> ` ` *> Value.`value`[F]).map(ReturnExpr(_))
|
||||
}
|
7
src/main/scala/aqua/parser/expr/RootExpr.scala
Normal file
7
src/main/scala/aqua/parser/expr/RootExpr.scala
Normal file
@ -0,0 +1,7 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
|
||||
case class RootExpr[F[_]]() extends Expr[F]
|
||||
|
||||
object RootExpr
|
18
src/main/scala/aqua/parser/expr/ServiceExpr.scala
Normal file
18
src/main/scala/aqua/parser/expr/ServiceExpr.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
|
||||
case class ServiceExpr[F[_]](name: Ability[F], id: Option[Value[F]]) extends Expr[F] {}
|
||||
|
||||
object ServiceExpr extends Expr.AndIndented(ArrowTypeExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[ServiceExpr[F]] =
|
||||
(`service` *> ` ` *> Ability.ab[F] ~ Value.`value`[F].between(`(`, `)`).backtrack.? <* ` : \n+`).map {
|
||||
case (name, id) => ServiceExpr(name, id)
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.ast.algebra.types.ScalarType
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import aqua.semantics.ScalarType
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.functor._
|
||||
@ -36,9 +36,8 @@ object BasicTypeToken {
|
||||
|
||||
def `basictypedef`[F[_]: LiftParser: Comonad]: P[BasicTypeToken[F]] =
|
||||
P.oneOf(
|
||||
ScalarType.all.map(n ⇒ P.string(n.name).as(n)).toList
|
||||
)
|
||||
.lift
|
||||
ScalarType.all.map(n ⇒ P.string(n.name).as(n)).toList
|
||||
).lift
|
||||
.map(BasicTypeToken(_))
|
||||
}
|
||||
|
||||
@ -64,8 +63,8 @@ object ArrowTypeToken {
|
||||
def `arrowdef`[F[_]: LiftParser: Comonad]: P[ArrowTypeToken[F]] =
|
||||
(comma0(DataTypeToken.`datatypedef`).with1 ~ ` -> `.lift ~
|
||||
(DataTypeToken.`datatypedef`
|
||||
.map(Some(_)) | P.string("()").as(None))).map {
|
||||
case ((args, point), res) ⇒ ArrowTypeToken(point, args, res)
|
||||
.map(Some(_)) | P.string("()").as(None))).map { case ((args, point), res) ⇒
|
||||
ArrowTypeToken(point, args, res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.ast.algebra.types.LiteralType
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import aqua.semantics.LiteralType
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.parse.{Numbers, Parser => P}
|
||||
import cats.syntax.functor._
|
||||
@ -25,8 +25,8 @@ object Value {
|
||||
val notLambdaSymbols = Set(' ', ',', '\n', ')', ':')
|
||||
|
||||
def varLambda[F[_]: LiftParser: Comonad]: P[VarLambda[F]] =
|
||||
(Name.p[F] ~ LambdaOp.ops[F].?).map {
|
||||
case (n, l) ⇒ VarLambda(n, l.fold[List[LambdaOp[F]]](Nil)(_.toList))
|
||||
(Name.p[F] ~ LambdaOp.ops[F].?).map { case (n, l) ⇒
|
||||
VarLambda(n, l.fold[List[LambdaOp[F]]](Nil)(_.toList))
|
||||
}
|
||||
|
||||
def bool[F[_]: LiftParser: Functor: Comonad]: P[Literal[F]] =
|
||||
|
37
src/main/scala/aqua/semantics/ExprSem.scala
Normal file
37
src/main/scala/aqua/semantics/ExprSem.scala
Normal file
@ -0,0 +1,37 @@
|
||||
package aqua.semantics
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.expr._
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.scope.PeerIdAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.semantics.expr._
|
||||
|
||||
object ExprSem {
|
||||
|
||||
def getProg[F[_], G[_]](
|
||||
expr: Expr[F]
|
||||
)(implicit
|
||||
A: AbilitiesAlgebra[F, G],
|
||||
N: NamesAlgebra[F, G],
|
||||
P: PeerIdAlgebra[F, G],
|
||||
T: TypesAlgebra[F, G]
|
||||
): Prog[G, Model] =
|
||||
expr match {
|
||||
case expr: AbilityIdExpr[F] => new AbilityIdSem(expr).program[G]
|
||||
case expr: AliasExpr[F] => new AliasSem(expr).program[G]
|
||||
case expr: ArrowTypeExpr[F] => new ArrowTypeSem(expr).program[G]
|
||||
case expr: CoalgebraExpr[F] => new CoalgebraSem(expr).program[G]
|
||||
case expr: DataStructExpr[F] => new DataStructSem(expr).program[G]
|
||||
case expr: FieldTypeExpr[F] => new FieldTypeSem(expr).program[G]
|
||||
case expr: FuncExpr[F] => new FuncSem(expr).program[G]
|
||||
case expr: OnExpr[F] => new OnSem(expr).program[G]
|
||||
case expr: ParExpr[F] => new ParSem(expr).program[G]
|
||||
case expr: ReturnExpr[F] => new ReturnSem(expr).program[G]
|
||||
case expr: ServiceExpr[F] => new ServiceSem(expr).program[G]
|
||||
case expr: RootExpr[F] => new RootSem(expr).program[G]
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package aqua.ast
|
||||
package aqua.semantics
|
||||
|
||||
import cats.free.Free
|
||||
import cats.syntax.flatMap._
|
@ -1,13 +1,13 @@
|
||||
package aqua.ast
|
||||
package aqua.semantics
|
||||
|
||||
import aqua.ast.algebra.ReportError
|
||||
import aqua.ast.algebra.abilities.{AbilitiesAlgebra, AbilitiesInterpreter, AbilitiesState, AbilityOp}
|
||||
import aqua.ast.algebra.names.{NameOp, NamesAlgebra, NamesInterpreter, NamesState}
|
||||
import aqua.ast.algebra.scope.{PeerIdAlgebra, PeerIdInterpreter, PeerIdOp, PeerIdState}
|
||||
import aqua.ast.algebra.types.{TypeOp, TypesAlgebra, TypesInterpreter, TypesState}
|
||||
import aqua.ast.expr._
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.model.Model
|
||||
import aqua.parser.lexer.Token
|
||||
import aqua.parser.{Ast, Expr}
|
||||
import aqua.semantics.rules.ReportError
|
||||
import aqua.semantics.rules.abilities.{AbilitiesAlgebra, AbilitiesInterpreter, AbilitiesState, AbilityOp}
|
||||
import aqua.semantics.rules.names.{NameOp, NamesAlgebra, NamesInterpreter, NamesState}
|
||||
import aqua.semantics.rules.scope.{PeerIdAlgebra, PeerIdInterpreter, PeerIdOp, PeerIdState}
|
||||
import aqua.semantics.rules.types.{TypeOp, TypesAlgebra, TypesInterpreter, TypesState}
|
||||
import cats.Eval
|
||||
import cats.arrow.FunctionK
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
@ -20,51 +20,28 @@ import cats.syntax.semigroup._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
object Compiler {
|
||||
|
||||
private def exprToProg[F[_], G[_]](
|
||||
expr: Expr[F]
|
||||
)(implicit
|
||||
A: AbilitiesAlgebra[F, G],
|
||||
N: NamesAlgebra[F, G],
|
||||
P: PeerIdAlgebra[F, G],
|
||||
T: TypesAlgebra[F, G]
|
||||
): Prog[G, Gen] =
|
||||
expr match {
|
||||
case expr: AbilityIdExpr[F] => expr.program[G]
|
||||
case expr: AliasExpr[F] => expr.program[G]
|
||||
case expr: ArrowTypeExpr[F] => expr.program[G]
|
||||
case expr: CoalgebraExpr[F] => expr.program[G]
|
||||
case expr: DataStructExpr[F] => expr.program[G]
|
||||
case expr: FieldTypeExpr[F] => expr.program[G]
|
||||
case expr: FuncExpr[F] => expr.program[G]
|
||||
case expr: OnExpr[F] => expr.program[G]
|
||||
case expr: ParExpr[F] => expr.program[G]
|
||||
case expr: ReturnExpr[F] => expr.program[G]
|
||||
case expr: ServiceExpr[F] => expr.program[G]
|
||||
case expr: RootExpr[F] => expr.program[G]
|
||||
}
|
||||
object Semantics {
|
||||
|
||||
def folder[F[_], G[_]](implicit
|
||||
A: AbilitiesAlgebra[F, G],
|
||||
N: NamesAlgebra[F, G],
|
||||
P: PeerIdAlgebra[F, G],
|
||||
T: TypesAlgebra[F, G]
|
||||
): (Expr[F], List[Free[G, Gen]]) => Eval[Free[G, Gen]] = {
|
||||
case (expr, inners) =>
|
||||
Eval later exprToProg[F, G](expr)
|
||||
.apply(
|
||||
inners
|
||||
.reduceLeftOption[Free[G, Gen]]((a, b) => (a, b).mapN(_ |+| _))
|
||||
.getOrElse(Free.pure(Gen.noop))
|
||||
)
|
||||
): (Expr[F], List[Free[G, Model]]) => Eval[Free[G, Model]] = { case (expr, inners) =>
|
||||
Eval later ExprSem
|
||||
.getProg[F, G](expr)
|
||||
.apply(
|
||||
inners
|
||||
.reduceLeftOption[Free[G, Model]]((a, b) => (a, b).mapN(_ |+| _))
|
||||
.getOrElse(Free.pure(Model.empty))
|
||||
)
|
||||
}
|
||||
|
||||
type Alg0[F[_], A] = EitherK[AbilityOp[F, *], NameOp[F, *], A]
|
||||
type Alg1[F[_], A] = EitherK[PeerIdOp[F, *], Alg0[F, *], A]
|
||||
type Alg[F[_], A] = EitherK[TypeOp[F, *], Alg1[F, *], A]
|
||||
|
||||
def transpile[F[_]](ast: Ast[F]): Free[Alg[F, *], Gen] =
|
||||
def transpile[F[_]](ast: Ast[F]): Free[Alg[F, *], Model] =
|
||||
ast.cata(folder[F, Alg[F, *]]).value
|
||||
|
||||
case class CompilerState[F[_]](
|
||||
@ -75,7 +52,7 @@ object Compiler {
|
||||
types: TypesState[F] = TypesState[F]()
|
||||
)
|
||||
|
||||
def interpret[F[_]](free: Free[Alg[F, *], Gen]): State[CompilerState[F], Gen] = {
|
||||
def interpret[F[_]](free: Free[Alg[F, *], Model]): State[CompilerState[F], Model] = {
|
||||
import monocle.macros.syntax.all._
|
||||
|
||||
implicit val re: ReportError[F, CompilerState[F]] =
|
||||
@ -104,12 +81,11 @@ object Compiler {
|
||||
free.foldMap[State[CompilerState[F], *]](interpreter)
|
||||
}
|
||||
|
||||
def compile[F[_]](ast: Ast[F]): ValidatedNel[(Token[F], String), Gen] =
|
||||
def validate[F[_]](ast: Ast[F]): ValidatedNel[(Token[F], String), Model] =
|
||||
(transpile[F] _ andThen interpret[F])(ast)
|
||||
.run(CompilerState[F]())
|
||||
.map {
|
||||
case (state, gen) =>
|
||||
NonEmptyList.fromList(state.errors.toList).fold[ValidatedNel[(Token[F], String), Gen]](Valid(gen))(Invalid(_))
|
||||
.map { case (state, gen) =>
|
||||
NonEmptyList.fromList(state.errors.toList).fold[ValidatedNel[(Token[F], String), Model]](Valid(gen))(Invalid(_))
|
||||
}
|
||||
.value
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package aqua.ast.algebra.types
|
||||
package aqua.semantics
|
||||
|
||||
import cats.PartialOrder
|
||||
import cats.data.NonEmptyMap
|
||||
@ -48,7 +48,7 @@ object ScalarType {
|
||||
}
|
||||
}
|
||||
|
||||
case class LiteralType private (oneOf: Set[ScalarType], name: String) extends Type {
|
||||
case class LiteralType private (oneOf: Set[ScalarType], name: String) extends DataType {
|
||||
override def toString: String = name
|
||||
}
|
||||
|
15
src/main/scala/aqua/semantics/expr/AbilityIdSem.scala
Normal file
15
src/main/scala/aqua/semantics/expr/AbilityIdSem.scala
Normal file
@ -0,0 +1,15 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.AbilityIdExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
class AbilityIdSem[F[_]](val expr: AbilityIdExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit A: AbilitiesAlgebra[F, Alg], V: ValuesAlgebra[F, Alg]): Prog[Alg, Model] =
|
||||
V.ensureIsString(expr.id) >> A.setServiceId(expr.ability, expr.id) as Model.empty
|
||||
}
|
17
src/main/scala/aqua/semantics/expr/AliasSem.scala
Normal file
17
src/main/scala/aqua/semantics/expr/AliasSem.scala
Normal file
@ -0,0 +1,17 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.AliasExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
|
||||
class AliasSem[F[_]](val expr: AliasExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Model] =
|
||||
T.resolveType(expr.target).flatMap {
|
||||
case Some(t) => T.defineAlias(expr.name, t) as Model.empty
|
||||
case None => Free.pure[Alg, Model](Model.error)
|
||||
}
|
||||
}
|
19
src/main/scala/aqua/semantics/expr/ArrowTypeSem.scala
Normal file
19
src/main/scala/aqua/semantics/expr/ArrowTypeSem.scala
Normal file
@ -0,0 +1,19 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.ArrowTypeExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
|
||||
class ArrowTypeSem[F[_]](val expr: ArrowTypeExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg], A: AbilitiesAlgebra[F, Alg]): Prog[Alg, Model] =
|
||||
T.resolveArrowDef(expr.`type`).flatMap {
|
||||
case Some(t) => A.defineArrow(expr.name, t) as Model.empty
|
||||
case None => Free.pure[Alg, Model](Model.error)
|
||||
}
|
||||
|
||||
}
|
83
src/main/scala/aqua/semantics/expr/CoalgebraSem.scala
Normal file
83
src/main/scala/aqua/semantics/expr/CoalgebraSem.scala
Normal file
@ -0,0 +1,83 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.generator.DataView
|
||||
import aqua.model.{CoalgebraModel, Model, ServiceModel}
|
||||
import aqua.parser.expr.CoalgebraExpr
|
||||
import aqua.semantics.{ArrowType, Prog, Type}
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.free.Free
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.apply._
|
||||
|
||||
class CoalgebraSem[F[_]](val expr: CoalgebraExpr[F]) extends AnyVal {
|
||||
|
||||
import expr._
|
||||
|
||||
private def freeUnit[Alg[_]]: Free[Alg, Unit] = Free.pure[Alg, Unit](())
|
||||
|
||||
private def checkArgsRes[Alg[_]](
|
||||
at: ArrowType
|
||||
)(implicit N: NamesAlgebra[F, Alg], V: ValuesAlgebra[F, Alg]): Free[Alg, List[(DataView, Type)]] =
|
||||
V.checkArguments(at, args) >> variable
|
||||
.fold(freeUnit[Alg])(exportVar =>
|
||||
at.res.fold(
|
||||
// TODO: error! we're trying to export variable, but function has no export type
|
||||
freeUnit[Alg]
|
||||
)(resType => N.define(exportVar, resType).void)
|
||||
) >> args.foldLeft(Free.pure[Alg, List[(DataView, Type)]](Nil)) { case (acc, v) =>
|
||||
(acc, V.resolveType(v)).mapN((a, b) => a ++ b.map(ValuesAlgebra.valueToData(v) -> _))
|
||||
}
|
||||
|
||||
private def toModel[Alg[_]](implicit
|
||||
N: NamesAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg]
|
||||
): Free[Alg, Option[CoalgebraModel]] =
|
||||
ability match {
|
||||
case Some(ab) =>
|
||||
(A.getArrow(ab, funcName), A.getServiceId(ab)).mapN {
|
||||
case (Some(at), Some(sid)) =>
|
||||
Option(at -> sid) // Here we assume that Ability is a Service that must be resolved
|
||||
case _ => None
|
||||
}.flatMap(_.fold(Free.pure[Alg, Option[CoalgebraModel]](None)) { case (arrowType, serviceId) =>
|
||||
checkArgsRes(arrowType)
|
||||
.map(argsResolved =>
|
||||
CoalgebraModel(
|
||||
ability = Some(ServiceModel(ab.value, ValuesAlgebra.valueToData(serviceId))),
|
||||
funcName = funcName.value,
|
||||
args = argsResolved,
|
||||
exportTo = variable.map(_.value)
|
||||
)
|
||||
)
|
||||
.map(Option(_))
|
||||
})
|
||||
case None =>
|
||||
N.readArrow(funcName)
|
||||
.flatMap(_.fold(Free.pure[Alg, Option[CoalgebraModel]](None)) { arrowType =>
|
||||
checkArgsRes(arrowType)
|
||||
.map(argsResolved =>
|
||||
CoalgebraModel(
|
||||
ability = None,
|
||||
funcName = funcName.value,
|
||||
args = argsResolved,
|
||||
exportTo = variable.map(_.value)
|
||||
)
|
||||
)
|
||||
.map(Option(_))
|
||||
})
|
||||
}
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
N: NamesAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] =
|
||||
toModel[Alg].map(_.getOrElse(Model.error))
|
||||
|
||||
}
|
24
src/main/scala/aqua/semantics/expr/DataStructSem.scala
Normal file
24
src/main/scala/aqua/semantics/expr/DataStructSem.scala
Normal file
@ -0,0 +1,24 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.DataStructExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
|
||||
class DataStructSem[F[_]](val expr: DataStructExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
N: NamesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] =
|
||||
Prog.after((_: Model) =>
|
||||
T.purgeFields(expr.name).flatMap {
|
||||
case Some(fields) => T.defineDataType(expr.name, fields) as Model.empty // TODO it's not air gen, but ts gen
|
||||
case None => Free.pure[Alg, Model](Model.error)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
19
src/main/scala/aqua/semantics/expr/FieldTypeSem.scala
Normal file
19
src/main/scala/aqua/semantics/expr/FieldTypeSem.scala
Normal file
@ -0,0 +1,19 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.generator.Gen
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.FieldTypeExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
|
||||
class FieldTypeSem[F[_]](val expr: FieldTypeExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Model] =
|
||||
T.resolveType(expr.`type`).flatMap {
|
||||
case Some(t) => T.defineField(expr.name, t) as Model.empty
|
||||
case None => Free.pure[Alg, Model](Model.error)
|
||||
}
|
||||
|
||||
}
|
109
src/main/scala/aqua/semantics/expr/FuncSem.scala
Normal file
109
src/main/scala/aqua/semantics/expr/FuncSem.scala
Normal file
@ -0,0 +1,109 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.{FuncModel, FuncOp, Model}
|
||||
import aqua.parser.expr.FuncExpr
|
||||
import aqua.parser.lexer.Arg
|
||||
import aqua.semantics.{ArrowType, DataType, Prog, Type}
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.scope.PeerIdAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.Applicative
|
||||
import cats.free.Free
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
||||
import expr._
|
||||
|
||||
def before[Alg[_]](implicit
|
||||
T: TypesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
P: PeerIdAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, ArrowType] =
|
||||
A.beginScope(name) >> Applicative[Free[Alg, *]]
|
||||
.product(
|
||||
// Collect argument types, define local variables
|
||||
args
|
||||
.foldLeft(
|
||||
// Begin scope -- for mangling
|
||||
N.beginScope(name).as[Queue[Type]](Queue.empty)
|
||||
) { case (f, Arg(argName, argType)) =>
|
||||
// Resolve arg type, remember it
|
||||
f.flatMap(acc =>
|
||||
T.resolveType(argType).flatMap {
|
||||
case Some(t: ArrowType) =>
|
||||
N.defineArrow(argName, t, isRoot = false).as(acc.enqueue(t))
|
||||
case Some(t) =>
|
||||
N.define(argName, t).as(acc.enqueue(t))
|
||||
case None =>
|
||||
Free.pure(acc)
|
||||
}
|
||||
)
|
||||
}
|
||||
.map(_.toList),
|
||||
// Resolve return type
|
||||
ret.fold(Free.pure[Alg, Option[Type]](None))(T.resolveType(_))
|
||||
)
|
||||
.map(argsAndRes => ArrowType(argsAndRes._1, argsAndRes._2))
|
||||
|
||||
def after[Alg[_]](funcArrow: ArrowType, bodyGen: Model)(implicit
|
||||
T: TypesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
P: PeerIdAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, Model] =
|
||||
// Check return value type
|
||||
((funcArrow.res, retValue) match {
|
||||
case (Some(t), Some(v)) =>
|
||||
V.resolveType(v).flatMap {
|
||||
case Some(vt) => T.ensureTypeMatches(v, t, vt).void
|
||||
case None => Free.pure[Alg, Unit](())
|
||||
}
|
||||
case _ =>
|
||||
Free.pure[Alg, Unit](())
|
||||
|
||||
// Erase arguments and internal variables
|
||||
}) >> A.endScope() >> N.endScope() >> (bodyGen match {
|
||||
case bg: FuncOp if ret.isDefined == retValue.isDefined =>
|
||||
val argNames = args.map(_.name.value)
|
||||
|
||||
val model = FuncModel(
|
||||
name = name.value,
|
||||
args = argNames
|
||||
.zip(funcArrow.args)
|
||||
.map {
|
||||
case (n, dt: DataType) => n -> Left(dt)
|
||||
case (n, at: ArrowType) => n -> Right(at)
|
||||
},
|
||||
ret = retValue.map(ValuesAlgebra.valueToData).flatMap(vd => funcArrow.res.map(vd -> _)),
|
||||
body = bg
|
||||
)
|
||||
|
||||
N.defineArrow(
|
||||
name,
|
||||
funcArrow,
|
||||
isRoot = true
|
||||
) as model
|
||||
case _ => Free.pure[Alg, Model](Model.error)
|
||||
})
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
T: TypesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
P: PeerIdAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] =
|
||||
Prog.around(
|
||||
before[Alg],
|
||||
after[Alg]
|
||||
)
|
||||
|
||||
}
|
28
src/main/scala/aqua/semantics/expr/OnSem.scala
Normal file
28
src/main/scala/aqua/semantics/expr/OnSem.scala
Normal file
@ -0,0 +1,28 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.{FuncOp, Model, OnModel}
|
||||
import aqua.parser.expr.OnExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.scope.PeerIdAlgebra
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
class OnSem[F[_]](val expr: OnExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
P: PeerIdAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] =
|
||||
Prog.around(
|
||||
V.ensureIsString(expr.peerId) >> P.onPeerId(expr.peerId) >> A.beginScope(expr.peerId),
|
||||
(_: Unit, ops: Model) =>
|
||||
A.endScope() >> P.erasePeerId() as (ops match {
|
||||
case op: FuncOp =>
|
||||
OnModel(ValuesAlgebra.valueToData(expr.peerId), op)
|
||||
case _ => Model.error
|
||||
})
|
||||
)
|
||||
}
|
16
src/main/scala/aqua/semantics/expr/ParSem.scala
Normal file
16
src/main/scala/aqua/semantics/expr/ParSem.scala
Normal file
@ -0,0 +1,16 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.{FuncOp, Model, ParModel}
|
||||
import aqua.parser.expr.ParExpr
|
||||
import aqua.semantics.Prog
|
||||
import cats.data.NonEmptyList
|
||||
import cats.free.Free
|
||||
|
||||
class ParSem[F[_]](val expr: ParExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]]: Prog[Alg, Model] =
|
||||
Prog.after[Alg, Model] {
|
||||
case g: FuncOp => Free.pure[Alg, Model](ParModel(NonEmptyList.of(g)))
|
||||
case g => Free.pure[Alg, Model](g)
|
||||
}
|
||||
}
|
13
src/main/scala/aqua/semantics/expr/ReturnSem.scala
Normal file
13
src/main/scala/aqua/semantics/expr/ReturnSem.scala
Normal file
@ -0,0 +1,13 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.ReturnExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import cats.syntax.functor._
|
||||
|
||||
class ReturnSem[F[_]](val expr: ReturnExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit V: ValuesAlgebra[F, Alg]): Prog[Alg, Model] =
|
||||
V.resolveType(expr.value) as Model.empty
|
||||
}
|
15
src/main/scala/aqua/semantics/expr/RootSem.scala
Normal file
15
src/main/scala/aqua/semantics/expr/RootSem.scala
Normal file
@ -0,0 +1,15 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.{Model, ScriptModel}
|
||||
import aqua.parser.expr.RootExpr
|
||||
import aqua.semantics.Prog
|
||||
import cats.free.Free
|
||||
|
||||
class RootSem[F[_]](val expr: RootExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]]: Prog[Alg, Model] =
|
||||
Prog.after {
|
||||
case sm: ScriptModel => Free.pure[Alg, Model](sm)
|
||||
case _ => Free.pure[Alg, Model](Model.error)
|
||||
}
|
||||
}
|
40
src/main/scala/aqua/semantics/expr/ServiceSem.scala
Normal file
40
src/main/scala/aqua/semantics/expr/ServiceSem.scala
Normal file
@ -0,0 +1,40 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.parser.expr.ServiceExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import cats.free.Free
|
||||
import cats.syntax.apply._
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
class ServiceSem[F[_]](val expr: ServiceExpr[F]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
A: AbilitiesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] =
|
||||
Prog.around(
|
||||
A.beginScope(expr.name),
|
||||
(_: Unit, body: Model) =>
|
||||
(A.purgeArrows(expr.name) <* A.endScope()).flatMap {
|
||||
case Some(nel) =>
|
||||
A.defineService(
|
||||
expr.name,
|
||||
nel.map(kv => kv._1.value -> kv._2).toNem
|
||||
) >>
|
||||
expr.id.fold(Free.pure[Alg, Model](Model.empty))(idV =>
|
||||
V.ensureIsString(idV) >> A.setServiceId(expr.name, idV) as Model.empty
|
||||
)
|
||||
case None =>
|
||||
Free.pure(Model.error)
|
||||
|
||||
}
|
||||
)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package aqua.ast.algebra
|
||||
package aqua.semantics.rules
|
||||
|
||||
import aqua.parser.lexer.Token
|
||||
|
@ -1,4 +1,4 @@
|
||||
package aqua.ast.algebra
|
||||
package aqua.semantics.rules
|
||||
|
||||
import aqua.parser.lexer.Token
|
||||
import cats.data.State
|
@ -1,8 +1,10 @@
|
||||
package aqua.ast.algebra
|
||||
package aqua.semantics.rules
|
||||
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.types.{ArrowType, LiteralType, Type, TypesAlgebra}
|
||||
import aqua.parser.lexer.{Literal, Token, Value, VarLambda}
|
||||
import aqua.generator.DataView
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.parser.lexer.{IntoArray, IntoField, LambdaOp, Literal, Token, Value, VarLambda}
|
||||
import aqua.semantics.{ArrowType, LiteralType, Type}
|
||||
import cats.free.Free
|
||||
import cats.syntax.apply._
|
||||
|
||||
@ -52,22 +54,37 @@ class ValuesAlgebra[F[_], Alg[_]](implicit N: NamesAlgebra[F, Alg], T: TypesAlge
|
||||
.zip(arr.args)
|
||||
.foldLeft(
|
||||
Free.pure[Alg, Boolean](true)
|
||||
) {
|
||||
case (f, (ft, t)) =>
|
||||
(
|
||||
f,
|
||||
ft.flatMap {
|
||||
case None => Free.pure(false)
|
||||
case Some((tkn, valType)) =>
|
||||
T.ensureTypeMatches(tkn, t, valType)
|
||||
}
|
||||
).mapN(_ && _)
|
||||
) { case (f, (ft, t)) =>
|
||||
(
|
||||
f,
|
||||
ft.flatMap {
|
||||
case None => Free.pure(false)
|
||||
case Some((tkn, valType)) =>
|
||||
T.ensureTypeMatches(tkn, t, valType)
|
||||
}
|
||||
).mapN(_ && _)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object ValuesAlgebra {
|
||||
|
||||
private def opsToLens[F[_]](ops: List[LambdaOp[F]]): String =
|
||||
ops match {
|
||||
case Nil => ""
|
||||
case (_: IntoArray[F]) :: tail => "[@" + opsToLens(tail) + "]"
|
||||
case (f: IntoField[F]) :: tail => "." + f.value + opsToLens(tail)
|
||||
}
|
||||
|
||||
def valueToData[F[_]](v: Value[F]): DataView =
|
||||
v match {
|
||||
case l: Literal[F] => DataView.StringScalar(l.value)
|
||||
case VarLambda(name, Nil) => DataView.Variable(name.value)
|
||||
case VarLambda(name, ops) => DataView.VarLens(name.value, opsToLens(ops))
|
||||
}
|
||||
|
||||
private def argsToData[F[_]](args: List[Value[F]]): List[DataView] = args.map(valueToData)
|
||||
|
||||
implicit def deriveValuesAlgebra[F[_], Alg[_]](implicit
|
||||
N: NamesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg]
|
@ -1,8 +1,7 @@
|
||||
package aqua.ast.algebra.abilities
|
||||
package aqua.semantics.rules.abilities
|
||||
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Ability, Name, Token, Value}
|
||||
import aqua.semantics.ArrowType
|
||||
import cats.InjectK
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import cats.free.Free
|
||||
@ -15,16 +14,16 @@ class AbilitiesAlgebra[F[_], Alg[_]](implicit A: InjectK[AbilityOp[F, *], Alg])
|
||||
def purgeArrows(token: Token[F]): Free[Alg, Option[NonEmptyList[(Name[F], ArrowType)]]] =
|
||||
Free.liftInject[Alg](PurgeArrows[F](token))
|
||||
|
||||
def defineService(name: Ability[F], arrows: NonEmptyMap[String, ArrowGen]): Free[Alg, Boolean] =
|
||||
def defineService(name: Ability[F], arrows: NonEmptyMap[String, ArrowType]): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineService[F](name, arrows))
|
||||
|
||||
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowGen]] =
|
||||
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowType]] =
|
||||
Free.liftInject[Alg](GetArrow[F](name, arrow))
|
||||
|
||||
def setServiceId(name: Ability[F], id: Value[F]): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](SetServiceId[F](name, id))
|
||||
|
||||
def getServiceId(name: String): Free[Alg, Option[Value[F]]] =
|
||||
def getServiceId(name: Ability[F]): Free[Alg, Option[Value[F]]] =
|
||||
Free.liftInject[Alg](GetServiceId[F](name))
|
||||
|
||||
def beginScope(token: Token[F]): Free[Alg, Unit] =
|
@ -1,21 +1,19 @@
|
||||
package aqua.ast.algebra.abilities
|
||||
package aqua.semantics.rules.abilities
|
||||
|
||||
import aqua.ast.algebra.{ReportError, StackInterpreter}
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Ability, Name, Token, Value}
|
||||
import aqua.semantics.rules.{ReportError, StackInterpreter}
|
||||
import aqua.parser.lexer.{Name, Token, Value}
|
||||
import aqua.semantics.ArrowType
|
||||
import cats.data.{NonEmptyList, NonEmptyMap, State}
|
||||
import cats.~>
|
||||
import cats.syntax.functor._
|
||||
import monocle.Lens
|
||||
import monocle.macros.GenLens
|
||||
import monocle.macros.syntax.all._
|
||||
|
||||
class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], error: ReportError[F, X])
|
||||
extends StackInterpreter[F, X, AbilitiesState[F], AbilityStackFrame[F]](GenLens[AbilitiesState[F]](_.stack))
|
||||
with (AbilityOp[F, *] ~> State[X, *]) {
|
||||
|
||||
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowGen]]] =
|
||||
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowType]]] =
|
||||
getState.map(_.services.get(name))
|
||||
|
||||
override def apply[A](fa: AbilityOp[F, A]): State[X, A] =
|
||||
@ -42,10 +40,10 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
|
||||
report(
|
||||
ga.arrow,
|
||||
s"Service found, but arrow is undefined, available: ${arrows.value.keys.toNonEmptyList.toList.mkString(", ")}"
|
||||
).as(Option.empty[ArrowGen])
|
||||
).as(Option.empty[ArrowType])
|
||||
)(a => State.pure(Some(a)))
|
||||
case None =>
|
||||
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowGen])
|
||||
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowType])
|
||||
}
|
||||
|
||||
case s: SetServiceId[F] =>
|
||||
@ -61,17 +59,10 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
|
||||
|
||||
case s: GetServiceId[F] =>
|
||||
getState.flatMap(st =>
|
||||
st.stack.flatMap(_.serviceIds.get(s.name)).headOption orElse st.rootServiceIds.get(s.name) match {
|
||||
st.stack.flatMap(_.serviceIds.get(s.name.value)).headOption orElse st.rootServiceIds.get(s.name.value) match {
|
||||
case None =>
|
||||
st.stack.headOption
|
||||
.map(_.token)
|
||||
.fold(
|
||||
// TODO this should be an impossible error
|
||||
State.pure[X, Option[Value[F]]](Option.empty[Value[F]])
|
||||
)(t =>
|
||||
report(t, s"Service ID unresolved, use `${s.name} id` expression to set it")
|
||||
.as(Option.empty[Value[F]])
|
||||
)
|
||||
report(s.name, s"Service ID unresolved, use `${s.name} id` expression to set it")
|
||||
.as(Option.empty[Value[F]])
|
||||
|
||||
case v => State.pure(v)
|
||||
}
|
||||
@ -99,7 +90,7 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
|
||||
|
||||
case class AbilitiesState[F[_]](
|
||||
stack: List[AbilityStackFrame[F]] = Nil,
|
||||
services: Map[String, NonEmptyMap[String, ArrowGen]] = Map.empty,
|
||||
services: Map[String, NonEmptyMap[String, ArrowType]] = Map.empty,
|
||||
rootServiceIds: Map[String, Value[F]] = Map.empty[String, Value[F]]
|
||||
) {
|
||||
|
@ -1,8 +1,7 @@
|
||||
package aqua.ast.algebra.abilities
|
||||
package aqua.semantics.rules.abilities
|
||||
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Ability, Name, Token, Value}
|
||||
import aqua.semantics.ArrowType
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
|
||||
sealed trait AbilityOp[F[_], T]
|
||||
@ -11,13 +10,13 @@ case class DefineArrow[F[_]](arrow: Name[F], `type`: ArrowType) extends AbilityO
|
||||
|
||||
case class PurgeArrows[F[_]](token: Token[F]) extends AbilityOp[F, Option[NonEmptyList[(Name[F], ArrowType)]]]
|
||||
|
||||
case class DefineService[F[_]](name: Ability[F], arrows: NonEmptyMap[String, ArrowGen]) extends AbilityOp[F, Boolean]
|
||||
case class DefineService[F[_]](name: Ability[F], arrows: NonEmptyMap[String, ArrowType]) extends AbilityOp[F, Boolean]
|
||||
|
||||
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowGen]]
|
||||
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowType]]
|
||||
|
||||
case class SetServiceId[F[_]](name: Ability[F], id: Value[F]) extends AbilityOp[F, Boolean]
|
||||
|
||||
case class GetServiceId[F[_]](name: String) extends AbilityOp[F, Option[Value[F]]]
|
||||
case class GetServiceId[F[_]](name: Ability[F]) extends AbilityOp[F, Option[Value[F]]]
|
||||
|
||||
case class BeginScope[F[_]](token: Token[F]) extends AbilityOp[F, Unit]
|
||||
|
@ -1,18 +1,17 @@
|
||||
package aqua.ast.algebra.names
|
||||
package aqua.semantics.rules.names
|
||||
|
||||
import aqua.ast.algebra.types.Type
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Name, Token}
|
||||
import aqua.semantics.{ArrowType, Type}
|
||||
|
||||
sealed trait NameOp[F[_], T]
|
||||
|
||||
case class ReadName[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
||||
|
||||
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowGen]]
|
||||
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowType]]
|
||||
|
||||
case class DefineName[F[_]](name: Name[F], `type`: Type) extends NameOp[F, Boolean]
|
||||
|
||||
case class DefineArrow[F[_]](name: Name[F], gen: ArrowGen, isRoot: Boolean) extends NameOp[F, Boolean]
|
||||
case class DefineArrow[F[_]](name: Name[F], gen: ArrowType, isRoot: Boolean) extends NameOp[F, Boolean]
|
||||
|
||||
case class BeginScope[F[_]](token: Token[F]) extends NameOp[F, Unit]
|
||||
|
@ -1,8 +1,7 @@
|
||||
package aqua.ast.algebra.names
|
||||
package aqua.semantics.rules.names
|
||||
|
||||
import aqua.ast.algebra.types.{ArrowType, Type}
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Name, Token}
|
||||
import aqua.semantics.{ArrowType, Type}
|
||||
import cats.InjectK
|
||||
import cats.free.Free
|
||||
|
||||
@ -11,13 +10,13 @@ class NamesAlgebra[F[_], Alg[_]](implicit V: InjectK[NameOp[F, *], Alg]) {
|
||||
def read(name: Name[F]): Free[Alg, Option[Type]] =
|
||||
Free.liftInject[Alg](ReadName(name))
|
||||
|
||||
def readArrow(name: Name[F]): Free[Alg, Option[ArrowGen]] =
|
||||
def readArrow(name: Name[F]): Free[Alg, Option[ArrowType]] =
|
||||
Free.liftInject[Alg](ReadArrow(name))
|
||||
|
||||
def define(name: Name[F], `type`: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineName(name, `type`))
|
||||
|
||||
def defineArrow(name: Name[F], gen: ArrowGen, isRoot: Boolean): Free[Alg, Boolean] =
|
||||
def defineArrow(name: Name[F], gen: ArrowType, isRoot: Boolean): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineArrow(name, gen, isRoot))
|
||||
|
||||
def beginScope(token: Token[F]): Free[Alg, Unit] =
|
@ -1,9 +1,8 @@
|
||||
package aqua.ast.algebra.names
|
||||
package aqua.semantics.rules.names
|
||||
|
||||
import aqua.ast.algebra.types.Type
|
||||
import aqua.ast.algebra.{ReportError, StackInterpreter}
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.semantics.rules.{ReportError, StackInterpreter}
|
||||
import aqua.parser.lexer.Token
|
||||
import aqua.semantics.{ArrowType, Type}
|
||||
import cats.data.State
|
||||
import cats.~>
|
||||
import monocle.Lens
|
||||
@ -19,11 +18,11 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
getState.map { st =>
|
||||
st.stack.collectFirst {
|
||||
case frame if frame.names.contains(name) => frame.names(name)
|
||||
case frame if frame.arrows.contains(name) => frame.arrows(name).`type`
|
||||
} orElse st.rootArrows.get(name).map(_.`type`)
|
||||
case frame if frame.arrows.contains(name) => frame.arrows(name)
|
||||
} orElse st.rootArrows.get(name)
|
||||
}
|
||||
|
||||
def readArrow(name: String): S[Option[ArrowGen]] =
|
||||
def readArrow(name: String): S[Option[ArrowType]] =
|
||||
getState.map { st =>
|
||||
st.stack.flatMap(_.arrows.get(name)).headOption orElse st.rootArrows.get(name)
|
||||
}
|
||||
@ -42,7 +41,7 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
case None =>
|
||||
getState.flatMap(st =>
|
||||
report(ra.name, "Undefined arrow, available: " + st.allNames.mkString(", "))
|
||||
.as(Option.empty[ArrowGen])
|
||||
.as(Option.empty[ArrowType])
|
||||
)
|
||||
}
|
||||
|
||||
@ -75,7 +74,7 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
}).asInstanceOf[State[X, A]]
|
||||
}
|
||||
|
||||
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootArrows: Map[String, ArrowGen] = Map.empty) {
|
||||
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootArrows: Map[String, ArrowType] = Map.empty) {
|
||||
|
||||
def allNames: LazyList[String] =
|
||||
LazyList.from(stack).flatMap(s => s.names.keys ++ s.arrows.keys).appendedAll(rootArrows.keys)
|
||||
@ -87,8 +86,8 @@ case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootArrows: Map[St
|
||||
case class NamesFrame[F[_]](
|
||||
token: Token[F],
|
||||
names: Map[String, Type] = Map.empty,
|
||||
arrows: Map[String, ArrowGen] = Map.empty
|
||||
arrows: Map[String, ArrowType] = Map.empty
|
||||
) {
|
||||
def addName(n: String, t: Type): NamesFrame[F] = copy[F](names = names.updated(n, t))
|
||||
def addArrow(n: String, g: ArrowGen): NamesFrame[F] = copy[F](arrows = arrows.updated(n, g))
|
||||
def addArrow(n: String, g: ArrowType): NamesFrame[F] = copy[F](arrows = arrows.updated(n, g))
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package aqua.ast.algebra.scope
|
||||
package aqua.semantics.rules.scope
|
||||
|
||||
import aqua.parser.lexer.Value
|
||||
import cats.InjectK
|
@ -1,6 +1,6 @@
|
||||
package aqua.ast.algebra.scope
|
||||
package aqua.semantics.rules.scope
|
||||
|
||||
import aqua.ast.algebra.{ReportError, StackInterpreter}
|
||||
import aqua.semantics.rules.{ReportError, StackInterpreter}
|
||||
import aqua.parser.lexer.Value
|
||||
import cats.data.State
|
||||
import cats.~>
|
@ -1,4 +1,4 @@
|
||||
package aqua.ast.algebra.scope
|
||||
package aqua.semantics.rules.scope
|
||||
|
||||
import aqua.parser.lexer.Value
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.ast.algebra.types
|
||||
package aqua.semantics.rules.types
|
||||
|
||||
import aqua.parser.lexer.{ArrowDef, ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import aqua.semantics.{ArrowType, Type}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
|
||||
sealed trait TypeOp[F[_], T]
|
@ -1,6 +1,7 @@
|
||||
package aqua.ast.algebra.types
|
||||
package aqua.semantics.rules.types
|
||||
|
||||
import aqua.parser.lexer.{ArrowDef, ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import aqua.semantics.{ArrowType, Type}
|
||||
import cats.InjectK
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import cats.free.Free
|
@ -1,6 +1,6 @@
|
||||
package aqua.ast.algebra.types
|
||||
package aqua.semantics.rules.types
|
||||
|
||||
import aqua.ast.algebra.ReportError
|
||||
import aqua.semantics.rules.ReportError
|
||||
import aqua.parser.lexer.{
|
||||
ArrayTypeToken,
|
||||
ArrowTypeToken,
|
||||
@ -13,6 +13,7 @@ import aqua.parser.lexer.{
|
||||
Token,
|
||||
TypeToken
|
||||
}
|
||||
import aqua.semantics.{ArrayType, ArrowType, DataType, ProductType, Type}
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap, State, ValidatedNel}
|
||||
import cats.~>
|
||||
@ -49,8 +50,8 @@ class TypesInterpreter[F[_], X](implicit lens: Lens[X, TypesState[F]], error: Re
|
||||
case Valid(t) => State.pure[X, Option[ArrowType]](Some(t))
|
||||
case Invalid(errs) =>
|
||||
errs
|
||||
.foldLeft[S[Option[ArrowType]]](State.pure(None)) {
|
||||
case (n, (tkn, hint)) => report(tkn, hint) >> n
|
||||
.foldLeft[S[Option[ArrowType]]](State.pure(None)) { case (n, (tkn, hint)) =>
|
||||
report(tkn, hint) >> n
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,17 +103,17 @@ case class TypesState[F[_]](
|
||||
def resolveTypeToken(tt: TypeToken[F]): Option[Type] =
|
||||
tt match {
|
||||
case ArrayTypeToken(_, dtt) =>
|
||||
resolveTypeToken(dtt).collect {
|
||||
case it: DataType => ArrayType(it)
|
||||
resolveTypeToken(dtt).collect { case it: DataType =>
|
||||
ArrayType(it)
|
||||
}
|
||||
case ctt: CustomTypeToken[F] => strict.get(ctt.value)
|
||||
case btt: BasicTypeToken[F] => Some(btt.value)
|
||||
case ArrowTypeToken(_, args, res) =>
|
||||
val strictArgs = args.map(resolveTypeToken).collect {
|
||||
case Some(dt: DataType) => dt
|
||||
val strictArgs = args.map(resolveTypeToken).collect { case Some(dt: DataType) =>
|
||||
dt
|
||||
}
|
||||
val strictRes = res.flatMap(resolveTypeToken).collect {
|
||||
case dt: DataType => dt
|
||||
val strictRes = res.flatMap(resolveTypeToken).collect { case dt: DataType =>
|
||||
dt
|
||||
}
|
||||
Option.when(strictRes.isDefined == res.isDefined && strictArgs.length == args.length)(
|
||||
ArrowType(strictArgs, strictRes)
|
@ -1,14 +1,13 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.ast.Indent
|
||||
import aqua.ast.algebra.types.LiteralType
|
||||
import aqua.ast.expr.{AbilityIdExpr, CoalgebraExpr, FuncExpr, OnExpr}
|
||||
import aqua.parser.expr.{AbilityIdExpr, CoalgebraExpr, FuncExpr, OnExpr}
|
||||
import aqua.parser.lexer.{Ability, IntoField, Literal, Name, VarLambda}
|
||||
import cats.data.NonEmptyList
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.semantics.LiteralType
|
||||
import cats.Id
|
||||
|
||||
import scala.language.implicitConversions
|
||||
@ -43,21 +42,23 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
)
|
||||
|
||||
parseExpr("func(arg.doSomething.and.doSomethingElse)") should be(
|
||||
CoalgebraExpr[Id](None, None, Name[Id]("func"),
|
||||
List(toVar("arg", List("doSomething", "and", "doSomethingElse")))
|
||||
)
|
||||
CoalgebraExpr[Id](None, None, Name[Id]("func"), List(toVar("arg", List("doSomething", "and", "doSomethingElse"))))
|
||||
)
|
||||
|
||||
parseExpr("Ab.func(arg.doSomething.and.doSomethingElse, arg2.someFunc)") should be(
|
||||
CoalgebraExpr[Id](None, Some(toAb("Ab")), Name[Id]("func"),
|
||||
List(toVar("arg", List("doSomething", "and", "doSomethingElse")),
|
||||
toVar("arg2", List("someFunc"))
|
||||
)
|
||||
CoalgebraExpr[Id](
|
||||
None,
|
||||
Some(toAb("Ab")),
|
||||
Name[Id]("func"),
|
||||
List(toVar("arg", List("doSomething", "and", "doSomethingElse")), toVar("arg2", List("someFunc")))
|
||||
)
|
||||
)
|
||||
|
||||
parseExpr("x <- func(arg.doSomething)") should be(
|
||||
CoalgebraExpr[Id](Some(toName("x")), None, Name[Id]("func"),
|
||||
CoalgebraExpr[Id](
|
||||
Some(toName("x")),
|
||||
None,
|
||||
Name[Id]("func"),
|
||||
List(
|
||||
toVar("arg", List("doSomething"))
|
||||
)
|
||||
@ -67,40 +68,33 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
"abilities" should "be parsed" in {
|
||||
parseAbId("Ab a") should be(
|
||||
AbilityIdExpr[Id](toAb("Ab"), toVar("a", List()),
|
||||
)
|
||||
AbilityIdExpr[Id](toAb("Ab"), toVar("a", List()))
|
||||
)
|
||||
|
||||
parseAbId("Ab \"a\"") should be(
|
||||
AbilityIdExpr[Id](toAb("Ab"), Literal[Id]("\"a\"", LiteralType.string),
|
||||
)
|
||||
AbilityIdExpr[Id](toAb("Ab"), Literal[Id]("\"a\"", LiteralType.string))
|
||||
)
|
||||
|
||||
parseAbId("Ab 1") should be(
|
||||
AbilityIdExpr[Id](toAb("Ab"), Literal[Id]("1", LiteralType.number),
|
||||
)
|
||||
AbilityIdExpr[Id](toAb("Ab"), Literal[Id]("1", LiteralType.number))
|
||||
)
|
||||
|
||||
parseAbId("Ab a.id") should be(
|
||||
AbilityIdExpr[Id](toAb("Ab"), toVar("a", List("id")),
|
||||
)
|
||||
AbilityIdExpr[Id](toAb("Ab"), toVar("a", List("id")))
|
||||
)
|
||||
}
|
||||
|
||||
"on" should "be parsed" in {
|
||||
parseOn("on peer:\n") should be(
|
||||
OnExpr[Id](toVar("peer", List()),
|
||||
)
|
||||
OnExpr[Id](toVar("peer", List()))
|
||||
)
|
||||
|
||||
parseOn("on peer.id:\n") should be(
|
||||
OnExpr[Id](toVar("peer", List("id")),
|
||||
)
|
||||
OnExpr[Id](toVar("peer", List("id")))
|
||||
)
|
||||
|
||||
parseOn("on peer.id:\n") should be(
|
||||
OnExpr[Id](toVar("peer", List("id")),
|
||||
)
|
||||
OnExpr[Id](toVar("peer", List("id")))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,31 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.ast.algebra.types.ScalarType.{bool, u64}
|
||||
import aqua.ast.algebra.types.{LiteralType, ScalarType}
|
||||
import aqua.ast.expr.FuncExpr
|
||||
import aqua.parser.lexer.{Ability, Arg, ArrowTypeToken, BasicTypeToken, CustomTypeToken, Literal, Name, TypeToken, VarLambda}
|
||||
import aqua.semantics.ScalarType.{bool, u64}
|
||||
import aqua.parser.expr.FuncExpr
|
||||
import aqua.parser.lexer.{
|
||||
Ability,
|
||||
Arg,
|
||||
ArrowTypeToken,
|
||||
BasicTypeToken,
|
||||
CustomTypeToken,
|
||||
Literal,
|
||||
Name,
|
||||
TypeToken,
|
||||
VarLambda
|
||||
}
|
||||
import cats.data.NonEmptyList
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.semantics.ScalarType
|
||||
import cats.Id
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
class FuncSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
import aqua.ast.algebra.types.ScalarType.{string, u32}
|
||||
import aqua.semantics.ScalarType.{string, u32}
|
||||
|
||||
implicit def scToBt(sc: ScalarType): BasicTypeToken[Id] = BasicTypeToken[Id](sc)
|
||||
|
||||
@ -40,14 +50,20 @@ class FuncSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
FuncExpr(toName("some"), List(toCustomArg("peer", "PeerId"), toArg("other", arrowToken)), None, None)
|
||||
)
|
||||
|
||||
val arrowToken2 = ArrowTypeToken[Id]((), List(BasicTypeToken[Id](u32), BasicTypeToken[Id](u64)), Some(BasicTypeToken[Id](bool)))
|
||||
val arrowToken2 =
|
||||
ArrowTypeToken[Id]((), List(BasicTypeToken[Id](u32), BasicTypeToken[Id](u64)), Some(BasicTypeToken[Id](bool)))
|
||||
funcExpr("func some(peer: PeerId, other: u32, u64 -> bool):\n") should be(
|
||||
FuncExpr(toName("some"), List(toCustomArg("peer", "PeerId"), toArg("other", arrowToken2)), None, None)
|
||||
)
|
||||
|
||||
val arrowToken3 = ArrowTypeToken[Id]((), List(BasicTypeToken[Id](u32)), None)
|
||||
funcExpr("func getTime(peer: PeerId, ret: u32 -> ()) -> string:\n") should be(
|
||||
FuncExpr(toName("getTime"), List(toCustomArg("peer", "PeerId"), toArg("ret", arrowToken3)), Some(BasicTypeToken[Id](string)), None)
|
||||
FuncExpr(
|
||||
toName("getTime"),
|
||||
List(toCustomArg("peer", "PeerId"), toArg("ret", arrowToken3)),
|
||||
Some(BasicTypeToken[Id](string)),
|
||||
None
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.ast.algebra.types.ScalarType
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.semantics.ScalarType
|
||||
import cats.Id
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
@ -1,10 +1,10 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.ast.algebra.types.LiteralType
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.semantics.LiteralType
|
||||
import cats.Id
|
||||
|
||||
class ValueSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package aqua.ast
|
||||
package aqua.semantics
|
||||
|
||||
import aqua.ast.expr.ArrowTypeExpr
|
||||
import aqua.ast.algebra.types.ScalarType
|
||||
import aqua.parser.expr.ArrowTypeExpr
|
||||
import aqua.parser.lexer.{ArrowTypeToken, BasicTypeToken, CustomTypeToken, DataTypeToken, Name}
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
@ -9,6 +8,7 @@ import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits._
|
||||
import cats.Id
|
||||
|
||||
// TODO move it to parser
|
||||
class ArrowTypeExprSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
"arrow type parser" should "parse" in {
|
||||
ArrowTypeExpr.p[Id].parseAll("func: A -> u32").right.value should be(
|
@ -1,16 +1,16 @@
|
||||
package aqua.ast.algebra
|
||||
package aqua.semantics.rules
|
||||
|
||||
import aqua.ast.algebra.types.{ArrayType, ArrowType, DataType, LiteralType, ProductType, Type}
|
||||
import aqua.semantics.{ArrayType, ArrowType, DataType, LiteralType, ProductType, Type}
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import cats.syntax.partialOrder._
|
||||
import aqua.ast.algebra.types.Type.typesPartialOrder
|
||||
import aqua.semantics.Type.typesPartialOrder
|
||||
import cats.data.NonEmptyMap
|
||||
import cats.kernel.PartialOrder
|
||||
|
||||
class TypeSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
import aqua.ast.algebra.types.ScalarType._
|
||||
import aqua.semantics.ScalarType._
|
||||
|
||||
def `[]`(t: DataType): DataType = ArrayType(t)
|
||||
|
Loading…
Reference in New Issue
Block a user