Merge pull request #4 from fluencelabs/gen-ts

Generate basic TypeScript file
This commit is contained in:
Dmitry Kurinskiy 2021-03-19 16:47:08 +03:00 committed by GitHub
commit 6a67fa175e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 1256 additions and 841 deletions

View 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;
}

View File

@ -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"
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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+`
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}

View File

@ -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(_))
}

View File

@ -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

View File

@ -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)
}
}

View File

@ -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)
}
}
)
}
}

View File

@ -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 ""

View File

@ -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

View 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)))
}

View File

@ -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))
}
}

View 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"))
}

View 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
}
}

View 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

View 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)
)
)
)
}

View 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)
}
}

View 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

View 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
}

View File

@ -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]) {

View File

@ -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[_]] {}

View File

@ -1,3 +1,3 @@
package aqua.ast
package aqua.parser
case class Indent(indent: String = "")

View File

@ -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 {

View File

@ -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 {

View 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)
}
}

View 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)
}
}

View 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+`
}

View File

@ -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 {

View 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)
}
}
}

View 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)
}
}

View File

@ -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) {

View 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(_))
}

View File

@ -0,0 +1,7 @@
package aqua.parser.expr
import aqua.parser.Expr
case class RootExpr[F[_]]() extends Expr[F]
object RootExpr

View 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)
}
}

View File

@ -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)
}
}

View File

@ -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]] =

View 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]
}
}

View File

@ -1,4 +1,4 @@
package aqua.ast
package aqua.semantics
import cats.free.Free
import cats.syntax.flatMap._

View File

@ -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
}

View File

@ -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
}

View 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
}

View 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)
}
}

View 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)
}
}

View 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))
}

View 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)
}
)
}

View 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)
}
}

View 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]
)
}

View 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
})
)
}

View 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)
}
}

View 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
}

View 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)
}
}

View 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)
}
)
}

View File

@ -1,4 +1,4 @@
package aqua.ast.algebra
package aqua.semantics.rules
import aqua.parser.lexer.Token

View File

@ -1,4 +1,4 @@
package aqua.ast.algebra
package aqua.semantics.rules
import aqua.parser.lexer.Token
import cats.data.State

View File

@ -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]

View File

@ -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] =

View File

@ -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]]
) {

View File

@ -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]

View File

@ -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]

View File

@ -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] =

View File

@ -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))
}

View File

@ -1,4 +1,4 @@
package aqua.ast.algebra.scope
package aqua.semantics.rules.scope
import aqua.parser.lexer.Value
import cats.InjectK

View File

@ -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.~>

View File

@ -1,4 +1,4 @@
package aqua.ast.algebra.scope
package aqua.semantics.rules.scope
import aqua.parser.lexer.Value

View File

@ -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]

View File

@ -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

View File

@ -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)

View File

@ -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")))
)
}

View File

@ -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
)
)
}

View File

@ -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

View File

@ -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 {

View File

@ -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(

View File

@ -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)