diff --git a/aqua-src/antithesis.aqua b/aqua-src/antithesis.aqua index 72ac4e01..684ac9b6 100644 --- a/aqua-src/antithesis.aqua +++ b/aqua-src/antithesis.aqua @@ -2,11 +2,23 @@ service Console("run-console"): print(s: string) func main(): - ss: *string - dd: *string - peerId = "peerId" - relay = "relay" - parsec s <- ss on peerId via relay: - Console.print(s) - for d <- dd par: - Console.print(d) + -- NewConsole = Console.??id??("new id") + -- NewConsole.print("") + + Console "new id" + NewAb = Ab(print = Console.print) + + + Console.print("sfre") + + for i <- incr: + Console "inside for id" + Console.print("sfre") + + + Console "new id" + Console.print("sfre") + + Console "inside for id" + -- Console -> ConsoleNew + Console.print("sfre") diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala index 5242beb4..48089d58 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala @@ -18,7 +18,7 @@ object MakeAbilityRawInliner extends RawInliner[AbilityRaw] { fields: NonEmptyMap[String, (ValueModel, Inline)] ): State[S, Unit] = { for { - res <- fields.toNel.traverse { + _ <- fields.toNel.traverse { case (n, (Ability(abilityName, _, _), _)) => val leftName = AbilityType.fullName(name, n) Exports[S].copyWithAbilityPrefix(abilityName, leftName) diff --git a/model/raw/src/main/scala/aqua/raw/arrow/ArrowRaw.scala b/model/raw/src/main/scala/aqua/raw/arrow/ArrowRaw.scala index 4216988c..19454057 100644 --- a/model/raw/src/main/scala/aqua/raw/arrow/ArrowRaw.scala +++ b/model/raw/src/main/scala/aqua/raw/arrow/ArrowRaw.scala @@ -10,3 +10,8 @@ case class ArrowRaw( ret: List[ValueRaw], body: RawTag.Tree ) extends Raw + +// func -internal-(): + // AssignemntTag(res1, CallArrowRaw("serviceId")) +// res1 <- CallArrowRaw("serviceId") +// <- res1 diff --git a/model/raw/src/main/scala/aqua/raw/arrow/FuncRaw.scala b/model/raw/src/main/scala/aqua/raw/arrow/FuncRaw.scala index b7813cde..ff75a23f 100644 --- a/model/raw/src/main/scala/aqua/raw/arrow/FuncRaw.scala +++ b/model/raw/src/main/scala/aqua/raw/arrow/FuncRaw.scala @@ -1,6 +1,5 @@ package aqua.raw.arrow -import aqua.raw.value.ValueRaw import aqua.raw.RawPart import aqua.types.Type diff --git a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala index dfa5ee7b..8e42584d 100644 --- a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala +++ b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala @@ -277,15 +277,6 @@ object EmptyTag extends NoExecTag { override def mapValues(f: ValueRaw => ValueRaw): RawTag = this } -case class AbilityIdTag( - value: ValueRaw, - service: String -) extends NoExecTag { - - override def mapValues(f: ValueRaw => ValueRaw): RawTag = - AbilityIdTag(value.map(f), service) -} - case class PushToStreamTag(operand: ValueRaw, exportTo: Call.Export) extends RawTag { override def exportsVarNames: Set[String] = Set(exportTo.name) diff --git a/model/raw/src/main/scala/aqua/raw/value/ValueRaw.scala b/model/raw/src/main/scala/aqua/raw/value/ValueRaw.scala index 6e634c1c..d2237d47 100644 --- a/model/raw/src/main/scala/aqua/raw/value/ValueRaw.scala +++ b/model/raw/src/main/scala/aqua/raw/value/ValueRaw.scala @@ -95,6 +95,17 @@ case class ApplyGateRaw(name: String, streamType: StreamType, idx: ValueRaw) ext override def varNames: Set[String] = Set(name) ++ idx.varNames } +case class ServiceFuncRaw(name: String, baseType: ArrowType) extends ValueRaw { + override def map(f: ValueRaw => ValueRaw): ValueRaw = f(this) + + override def renameVars(map: Map[String, String]): ValueRaw = + copy(map.getOrElse(name, name)) + + override def toString: String = s"var{$name: " + baseType + s"}" + + override def varNames: Set[String] = Set(name) +} + case class VarRaw(name: String, baseType: Type) extends ValueRaw { override def map(f: ValueRaw => ValueRaw): ValueRaw = f(this) @@ -164,8 +175,10 @@ case class MakeStructRaw(fields: NonEmptyMap[String, ValueRaw], structType: Stru copy(fields = fields.map(_.renameVars(map))) } -case class AbilityRaw(fieldsAndArrows: NonEmptyMap[String, ValueRaw], abilityType: AbilityType) - extends ValueRaw { +case class AbilityRaw( + fieldsAndArrows: NonEmptyMap[String, ValueRaw], + abilityType: AbilityType +) extends ValueRaw { override def baseType: Type = abilityType @@ -234,6 +247,27 @@ object ApplyUnaryOpRaw { } } +case class ServiceCallDefinitionRaw( + name: String, + baseType: ArrowType, + serviceId: ValueRaw +) extends ValueRaw { + override def `type`: Type = baseType.codomain.uncons.map(_._1).getOrElse(baseType) + + override def map(f: ValueRaw => ValueRaw): ValueRaw = + this + + override def varNames: Set[String] = Set.empty + + override def renameVars(map: Map[String, String]): ValueRaw = + copy( + serviceId = serviceId.renameVars(map) + ) + + override def toString: String = + s"(service calldef ($serviceId $name) $baseType)" +} + case class CallArrowRaw( // TODO: ability should hold a type, not name ability: Option[String], diff --git a/model/src/main/scala/aqua/model/AquaContext.scala b/model/src/main/scala/aqua/model/AquaContext.scala index 6de18da7..f88c0dac 100644 --- a/model/src/main/scala/aqua/model/AquaContext.scala +++ b/model/src/main/scala/aqua/model/AquaContext.scala @@ -2,10 +2,9 @@ package aqua.model import aqua.raw.arrow.FuncRaw import aqua.raw.ops.CallArrowRawTag -import aqua.raw.value.ValueRaw -import aqua.raw.value.CallArrowRaw +import aqua.raw.value.{AbilityRaw, CallArrowRaw, LiteralRaw, ValueRaw, VarRaw} import aqua.raw.{ConstantRaw, RawContext, RawPart, ServiceRaw, TypeRaw} -import aqua.types.{StructType, Type} +import aqua.types.{AbilityType, StructType, Type} import cats.Monoid import cats.data.NonEmptyMap import cats.data.Chain @@ -140,7 +139,7 @@ object AquaContext extends Logging { .get(rawContext) .fold { logger.trace(s"Compiling ${rawContext.module}, cache has ${cache.size} entries") - + println("raw parts: " + rawContext.parts) val (newCtx, newCache) = rawContext.parts .foldLeft[(AquaContext, Cache)] { // Laziness unefficiency happens here @@ -165,11 +164,23 @@ object AquaContext extends Logging { // Actually this should have no effect, as constants are resolved by semantics val (pctx, pcache) = fromRawContext(partContext, ctxCache) logger.trace("Got " + c.name + " from raw") + val values = c.value match { + // it could be only for services with default service ids +// case AbilityRaw(fieldsAndArrows, abilityType, Some(LiteralRaw(v, _))) => +// fieldsAndArrows.flatMap { +// case VarRaw(n, t) => +// Some(CallArrowRaw(None, AbilityType.fullName(abilityType.name, n), )) +// case _ => None +// } + case _ => + if (c.allowOverrides && pctx.values.contains(c.name)) Map.empty + else Map(c.name -> ValueModel.fromRaw(c.value).resolveWith(pctx.allValues)) + } + val add = blank .copy(values = - if (c.allowOverrides && pctx.values.contains(c.name)) Map.empty - else Map(c.name -> ValueModel.fromRaw(c.value).resolveWith(pctx.allValues)) + values ) (ctx |+| add, pcache) diff --git a/model/src/main/scala/aqua/model/ValueModel.scala b/model/src/main/scala/aqua/model/ValueModel.scala index 408eb742..38479614 100644 --- a/model/src/main/scala/aqua/model/ValueModel.scala +++ b/model/src/main/scala/aqua/model/ValueModel.scala @@ -48,7 +48,9 @@ object ValueModel { VarModel(name, t) case LiteralRaw(value, t) => LiteralModel(value, t) - case _ => ??? + case p => + println("catch: " + p) + ??? } object Ability { diff --git a/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala index b4a635d8..d918f3d6 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala @@ -20,7 +20,7 @@ case class ArrowExpr[F[_]](arrowTypeExpr: ArrowTypeToken[F]) object ArrowExpr extends Expr.AndIndented { val funcChildren: List[Expr.Lexem] = - AbilityIdExpr :: + ServiceIdExpr :: PushToStreamExpr :: ForExpr :: Expr.defer(OnExpr) :: diff --git a/parser/src/main/scala/aqua/parser/expr/func/AbilityIdExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ServiceIdExpr.scala similarity index 59% rename from parser/src/main/scala/aqua/parser/expr/func/AbilityIdExpr.scala rename to parser/src/main/scala/aqua/parser/expr/func/ServiceIdExpr.scala index 36c4263b..401db732 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/AbilityIdExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ServiceIdExpr.scala @@ -1,7 +1,7 @@ package aqua.parser.expr.func import aqua.parser.Expr -import aqua.parser.expr.func.AbilityIdExpr +import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.Token.* import aqua.parser.lexer.{Ability, NamedTypeToken, ValueToken} import aqua.parser.lift.LiftParser @@ -10,19 +10,19 @@ import cats.{Comonad, ~>} import aqua.parser.lift.Span import aqua.parser.lift.Span.{P0ToSpan, PToSpan} -case class AbilityIdExpr[F[_]](ability: NamedTypeToken[F], id: ValueToken[F]) - extends Expr[F](AbilityIdExpr, ability) { +case class ServiceIdExpr[F[_]](ability: NamedTypeToken[F], id: ValueToken[F]) + extends Expr[F](ServiceIdExpr, ability) { - def mapK[K[_]: Comonad](fk: F ~> K): AbilityIdExpr[K] = + def mapK[K[_]: Comonad](fk: F ~> K): ServiceIdExpr[K] = copy(ability.copy(fk(ability.name)), id.mapK(fk)) } -object AbilityIdExpr extends Expr.Leaf { +object ServiceIdExpr extends Expr.Leaf { - override val p: P[AbilityIdExpr[Span.S]] = + override val p: P[ServiceIdExpr[Span.S]] = ((NamedTypeToken.dotted <* ` `) ~ ValueToken.`value`).map { case (ability, id) => - AbilityIdExpr(ability, id) + ServiceIdExpr(ability, id) } } diff --git a/parser/src/test/scala/aqua/AquaSpec.scala b/parser/src/test/scala/aqua/AquaSpec.scala index e0c53262..ed89d9e4 100644 --- a/parser/src/test/scala/aqua/AquaSpec.scala +++ b/parser/src/test/scala/aqua/AquaSpec.scala @@ -118,8 +118,8 @@ trait AquaSpec extends EitherValues { def parseUse(str: String): UseFromExpr[Id] = UseFromExpr.p.parseAll(str).value.mapK(spanToId) - def parseAbId(str: String): AbilityIdExpr[Id] = - AbilityIdExpr.p.parseAll(str).value.mapK(spanToId) + def parseAbId(str: String): ServiceIdExpr[Id] = + ServiceIdExpr.p.parseAll(str).value.mapK(spanToId) def parseOn(str: String): OnExpr[Id] = OnExpr.p.parseAll(str).value.mapK(spanToId) diff --git a/parser/src/test/scala/aqua/parser/FuncExprSpec.scala b/parser/src/test/scala/aqua/parser/FuncExprSpec.scala index 7c1ddce6..ce2a61be 100644 --- a/parser/src/test/scala/aqua/parser/FuncExprSpec.scala +++ b/parser/src/test/scala/aqua/parser/FuncExprSpec.scala @@ -2,7 +2,7 @@ package aqua.parser import aqua.AquaSpec import aqua.parser.expr.* -import aqua.parser.expr.func.{AbilityIdExpr, ArrowExpr, CallArrowExpr, IfExpr, OnExpr, ReturnExpr} +import aqua.parser.expr.func.{ServiceIdExpr, ArrowExpr, CallArrowExpr, IfExpr, OnExpr, ReturnExpr} import aqua.parser.lexer.{ ArrowTypeToken, BasicTypeToken, @@ -123,7 +123,7 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with Inside with Inspectors ) ) ) - ifBody(1).head.mapK(spanToId) should be(AbilityIdExpr(toNamedType("Peer"), toStr("some id"))) + ifBody(1).head.mapK(spanToId) should be(ServiceIdExpr(toNamedType("Peer"), toStr("some id"))) ifBody(2).head.mapK(spanToId) should be( CallArrowExpr(Nil, CallArrowToken("call", List(toBool(true)))) ) diff --git a/parser/src/test/scala/aqua/parser/AbilityIdExprSpec.scala b/parser/src/test/scala/aqua/parser/ServiceIdExprSpec.scala similarity index 58% rename from parser/src/test/scala/aqua/parser/AbilityIdExprSpec.scala rename to parser/src/test/scala/aqua/parser/ServiceIdExprSpec.scala index fb94aa7f..68ee3b5a 100644 --- a/parser/src/test/scala/aqua/parser/AbilityIdExprSpec.scala +++ b/parser/src/test/scala/aqua/parser/ServiceIdExprSpec.scala @@ -1,31 +1,31 @@ package aqua.parser import aqua.AquaSpec -import aqua.parser.expr.func.AbilityIdExpr +import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.LiteralToken import aqua.types.LiteralType import cats.Id import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -class AbilityIdExprSpec extends AnyFlatSpec with Matchers with AquaSpec { +class ServiceIdExprSpec extends AnyFlatSpec with Matchers with AquaSpec { import AquaSpec._ "abilities" should "be parsed" in { parseAbId("Ab a") should be( - AbilityIdExpr[Id](toNamedType("Ab"), toVar("a")) + ServiceIdExpr[Id](toNamedType("Ab"), toVar("a")) ) parseAbId("Ab \"a\"") should be( - AbilityIdExpr[Id](toNamedType("Ab"), LiteralToken[Id]("\"a\"", LiteralType.string)) + ServiceIdExpr[Id](toNamedType("Ab"), LiteralToken[Id]("\"a\"", LiteralType.string)) ) parseAbId("Ab 1") should be( - AbilityIdExpr[Id](toNamedType("Ab"), toNumber(1)) + ServiceIdExpr[Id](toNamedType("Ab"), toNumber(1)) ) parseAbId("Ab a.id") should be( - AbilityIdExpr[Id](toNamedType("Ab"), toVarLambda("a", List("id"))) + ServiceIdExpr[Id](toNamedType("Ab"), toVarLambda("a", List("id"))) ) } diff --git a/parser/src/test/scala/aqua/parser/head/FromSpec.scala b/parser/src/test/scala/aqua/parser/head/FromSpec.scala index 7bd8b9c1..16e65fbb 100644 --- a/parser/src/test/scala/aqua/parser/head/FromSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/FromSpec.scala @@ -1,7 +1,7 @@ package aqua.parser.head import aqua.AquaSpec -import aqua.parser.expr.func.AbilityIdExpr +import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} import aqua.parser.lift.LiftParser.Implicits.* import aqua.types.LiteralType diff --git a/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala b/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala index b3399a60..36128ca4 100644 --- a/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala @@ -1,7 +1,7 @@ package aqua.parser.head import aqua.AquaSpec -import aqua.parser.expr.func.AbilityIdExpr +import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} import aqua.parser.lift.LiftParser.Implicits.* import aqua.types.LiteralType diff --git a/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala b/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala index ea73f959..e7881142 100644 --- a/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala @@ -1,7 +1,7 @@ package aqua.parser.head import aqua.AquaSpec -import aqua.parser.expr.func.AbilityIdExpr +import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} import aqua.types.LiteralType import cats.Id diff --git a/parser/src/test/scala/aqua/parser/head/UseSpec.scala b/parser/src/test/scala/aqua/parser/head/UseSpec.scala index 15bdfdc4..a4321452 100644 --- a/parser/src/test/scala/aqua/parser/head/UseSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/UseSpec.scala @@ -1,7 +1,7 @@ package aqua.parser.head import aqua.AquaSpec -import aqua.parser.expr.func.AbilityIdExpr +import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} import aqua.parser.lift.LiftParser.Implicits.* import aqua.types.LiteralType diff --git a/semantics/src/main/scala/aqua/semantics/ExprSem.scala b/semantics/src/main/scala/aqua/semantics/ExprSem.scala index 7fd390f8..7873db74 100644 --- a/semantics/src/main/scala/aqua/semantics/ExprSem.scala +++ b/semantics/src/main/scala/aqua/semantics/ExprSem.scala @@ -27,7 +27,7 @@ object ExprSem { L: LocationsAlgebra[S, G] ): Prog[G, Raw] = expr match { - case expr: AbilityIdExpr[S] => new AbilityIdSem(expr).program[G] + case expr: ServiceIdExpr[S] => new ServiceIdSem(expr).program[G] case expr: AssignmentExpr[S] => new AssignmentSem(expr).program[G] case expr: PushToStreamExpr[S] => new PushToStreamSem(expr).program[G] case expr: AliasExpr[S] => new AliasSem(expr).program[G] diff --git a/semantics/src/main/scala/aqua/semantics/expr/ServiceSem.scala b/semantics/src/main/scala/aqua/semantics/expr/ServiceSem.scala index 0844547b..b3eb0a26 100644 --- a/semantics/src/main/scala/aqua/semantics/expr/ServiceSem.scala +++ b/semantics/src/main/scala/aqua/semantics/expr/ServiceSem.scala @@ -1,21 +1,119 @@ package aqua.semantics.expr import aqua.parser.expr.ServiceExpr -import aqua.raw.{Raw, ServiceRaw} +import aqua.raw.arrow.{ArrowRaw, FuncRaw} +import aqua.raw.ops.CallArrowRawTag +import aqua.raw.value.{AbilityRaw, CallArrowRaw, ValueRaw, VarRaw} +import aqua.raw.{ConstantRaw, Raw, RawPart, ServiceRaw, TypeRaw} import aqua.semantics.Prog import aqua.semantics.rules.ValuesAlgebra import aqua.semantics.rules.abilities.AbilitiesAlgebra import aqua.semantics.rules.definitions.DefinitionsAlgebra import aqua.semantics.rules.names.NamesAlgebra import aqua.semantics.rules.types.TypesAlgebra +import aqua.types.{AbilityType, ArrowType} import cats.syntax.apply.* import cats.syntax.flatMap.* import cats.syntax.functor.* import cats.syntax.applicative.* +import cats.syntax.traverse.* import cats.Monad +import cats.data.Chain class ServiceSem[S[_]](val expr: ServiceExpr[S]) extends AnyVal { + def createAbilityValue[Alg[_]: Monad](id: ValueRaw, abilityType: AbilityType)(implicit + A: AbilitiesAlgebra[S, Alg], + N: NamesAlgebra[S, Alg], + T: TypesAlgebra[S, Alg], + V: ValuesAlgebra[S, Alg], + D: DefinitionsAlgebra[S, Alg] + ) = {} + + // service AbServType("defaultId"): + // ... + + + // AbServType(func1 = ...'defaultId', func2 = ...'defaultId') + // AbServType.func1() + + // VarRaw(Serv.-default-id-, "defaultId") + // Serv "new id" + // VarRaw(Serv.-default-id-, "new id") + + /* + ability Ab: + fff: string -> string + eee: string -> string + + service Serv: + fff: string -> string + + service Eserv: + eee: string -> string + + func nested{Ab}: + ... + + someNewFunc{AbVal}(): + Serv "freferf" + AbVal.fff() + + AbVal.eee() + + func main(): + + + Serv "aaa" + Serv.fff() + + Eserv "bbb" + + Serv "zzz" + Serv.fff() + + nested{Serv}() + AbVal = Ab(fff = Serv.fff, Eserv.eee) + someNewFunc{AbVal}() + */ + + + + // ... + /* + func main(): + AbServType "some id" + AbServType(func1 = ...'some id', func2 = ...'some id') + + CallServiceModel('some id') + + AbServType "some id2" + AbServType(func1 = ...'some id2', func2 = ...'some id2') + + VarRaw(name, arrowType) -> Arrows FuncRaw(name, arrowType) + FuncRaw(name, arrowType, body = ServiceCall) + */ + + private def toFuncRaw(name: String, abilityName: String, serviceId: ValueRaw, t: ArrowType): FuncRaw = { + val args = t.domain.toLabelledList().map(st => VarRaw(st._1, st._2)) + val rett = t.codomain.toList.headOption + val ret = rett.map(t => VarRaw("ret", t)) + val raw = CallArrowRaw(None, name, args, t, Some(serviceId)) + val body = ret match { + case Some(vr) => + val callExpr = aqua.raw.ops.Call.Export(vr.name, vr.baseType) + CallArrowRawTag(callExpr :: Nil, raw) + + case None => + CallArrowRawTag(Nil, raw) + + } + + val arrow = ArrowRaw(t, ret.toList, body.leaf) + val fullName = AbilityType.fullName(abilityName, name) + FuncRaw(fullName, arrow) + } + def program[Alg[_]: Monad](implicit A: AbilitiesAlgebra[S, Alg], N: NamesAlgebra[S, Alg], @@ -23,34 +121,34 @@ class ServiceSem[S[_]](val expr: ServiceExpr[S]) extends AnyVal { V: ValuesAlgebra[S, Alg], D: DefinitionsAlgebra[S, Alg] ): Prog[Alg, Raw] = - Prog.after( - _ => - D.purgeArrows(expr.name).flatMap { - case Some(nel) => - val arrows = nel.map(kv => kv._1.value -> (kv._1, kv._2)).toNem - for { - defaultId <- expr.id - .map(v => V.valueToRaw(v)) - .getOrElse(None.pure[Alg]) - defineResult <- A.defineService( - expr.name, - arrows, - defaultId - ) - _ <- (expr.id zip defaultId) - .fold(().pure[Alg])(idV => - (V.ensureIsString(idV._1) >> A.setServiceId(expr.name, idV._1, idV._2)).map(_ => - () - ) - ) - } yield - if (defineResult) { - ServiceRaw(expr.name.value, arrows.map(_._2), defaultId) - } else Raw.empty("Service not created due to validation errors") + Prog.after(_ => + D.purgeArrows(expr.name).flatMap { + case Some(nel) => + val arrows = nel.map(kv => kv._1.value -> kv._2).toNem + val abType = AbilityType(expr.name.value, arrows) + for { + _ <- T.defineNamedType(expr.name, abType) + defaultId <- expr.id + .map(v => V.valueToRaw(v)) + .getOrElse(None.pure[Alg]) + _ <- expr.id.traverse(id => V.ensureIsString(id)) - case None => - Raw.error("Service has no arrows, fails").pure[Alg] + serviceArrows = defaultId match { + case Some(did) => + val funcs = arrows.mapBoth { + case (funcName, t) => funcName -> toFuncRaw(funcName, expr.name.value, did, t) + } + funcs.toNel.toList.map(_._2) + case None => Nil + } + } yield { + println("serviceArrows: " + serviceArrows) + val tr = TypeRaw(expr.name.value, abType) + RawPart.Parts(Chain.fromSeq(serviceArrows) :+ tr) + } + case None => + Raw.error("Service has no arrows, fails").pure[Alg] - } + } ) } diff --git a/semantics/src/main/scala/aqua/semantics/expr/func/AbilityIdSem.scala b/semantics/src/main/scala/aqua/semantics/expr/func/ServiceIdSem.scala similarity index 67% rename from semantics/src/main/scala/aqua/semantics/expr/func/AbilityIdSem.scala rename to semantics/src/main/scala/aqua/semantics/expr/func/ServiceIdSem.scala index 3e62b52a..f56ad86a 100644 --- a/semantics/src/main/scala/aqua/semantics/expr/func/AbilityIdSem.scala +++ b/semantics/src/main/scala/aqua/semantics/expr/func/ServiceIdSem.scala @@ -1,8 +1,8 @@ package aqua.semantics.expr.func +import aqua.parser.expr.func.ServiceIdExpr import aqua.raw.Raw -import aqua.raw.ops.AbilityIdTag -import aqua.parser.expr.func.AbilityIdExpr +import aqua.raw.ops.EmptyTag import aqua.semantics.Prog import aqua.semantics.rules.ValuesAlgebra import aqua.semantics.rules.abilities.AbilitiesAlgebra @@ -11,7 +11,7 @@ import cats.syntax.applicative.* import cats.syntax.flatMap.* import cats.syntax.functor.* -class AbilityIdSem[S[_]](val expr: AbilityIdExpr[S]) extends AnyVal { +class ServiceIdSem[S[_]](val expr: ServiceIdExpr[S]) extends AnyVal { def program[Alg[_]: Monad](implicit A: AbilitiesAlgebra[S, Alg], @@ -21,10 +21,7 @@ class AbilityIdSem[S[_]](val expr: AbilityIdExpr[S]) extends AnyVal { expr.id ) >>= { case Some(id) => - A.setServiceId(expr.ability, expr.id, id) as (AbilityIdTag( - id, - expr.ability.value - ).funcOpLeaf: Raw) + A.setServiceId(expr.ability, expr.id, id) as (EmptyTag.funcOpLeaf: Raw) case _ => Raw.error("Cannot resolve ability ID").pure[Alg] } } diff --git a/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala b/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala index c1848daa..d9a8c386 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala @@ -4,11 +4,13 @@ import aqua.parser.lexer.* import aqua.parser.lexer.InfixToken.{BoolOp, CmpOp, EqOp, MathOp, Op as InfOp} import aqua.parser.lexer.PrefixToken.Op as PrefOp import aqua.raw.value.* +import aqua.raw.ServiceRaw +import aqua.raw.arrow.{ArrowRaw, FuncRaw} +import aqua.raw.ops.{AssignmentTag, CallArrowRawTag} import aqua.semantics.rules.abilities.AbilitiesAlgebra import aqua.semantics.rules.names.NamesAlgebra import aqua.semantics.rules.types.TypesAlgebra import aqua.types.* - import cats.Monad import cats.data.Chain import cats.syntax.applicative.* @@ -48,6 +50,8 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit def resolveType(v: ValueToken[S]): Alg[Option[Type]] = valueToRaw(v).map(_.map(_.`type`)) + // + private def resolveSingleProperty(rootType: Type, op: PropertyOp[S]): Alg[Option[PropertyRaw]] = op match { case op: IntoField[S] => @@ -81,11 +85,23 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit LiteralRaw(l.value, t).some.pure[Alg] case VarToken(name) => - N.read(name).flatMap { + N.read(name, false).flatMap { case Some(t) => VarRaw(name.value, t).some.pure[Alg] case None => - None.pure[Alg] + A.getServiceByName(name).flatMap { + case Some(ServiceRaw(sName, arrows, Some(did))) => + val t = AbilityType(sName, arrows) + + N.define(name, t).map(_ => VarRaw(name.value, t).some) + case _ => + // to report an error + N.read(name).flatMap { + case Some(t) => VarRaw(name.value, t).some.pure[Alg] + case None => None.pure[Alg] + } + } + } case prop @ PropertyToken(value, properties) => @@ -121,10 +137,10 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit StructType(typeName.value, rf.map(_.`type`)), Some(MakeStructRaw(rf, struct)) ) - case scope @ AbilityType(_, _) => + case ability @ AbilityType(_, _) => ( AbilityType(typeName.value, rf.map(_.`type`)), - Some(AbilityRaw(rf, scope)) + Some(AbilityRaw(rf, ability)) ) } ) @@ -339,7 +355,7 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit callArrowFromAbility(ab.asName, at, callArrow.funcName).pure case _ => (A.getArrow(ab, callArrow.funcName), A.getServiceId(ab)).mapN { - case (Some(at), Right(sid)) => + case (Some(at), Right(sid, name)) => CallArrowRaw .service( abilityName = ab.value, diff --git a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesAlgebra.scala b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesAlgebra.scala index 1627f99c..745e93d6 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesAlgebra.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesAlgebra.scala @@ -1,6 +1,7 @@ package aqua.semantics.rules.abilities -import aqua.parser.lexer.{Ability, NamedTypeToken, Name, Token, ValueToken} +import aqua.parser.lexer.{Ability, Name, NamedTypeToken, Token, ValueToken} +import aqua.raw.ServiceRaw import aqua.raw.value.ValueRaw import aqua.types.ArrowType import cats.InjectK @@ -19,6 +20,9 @@ trait AbilitiesAlgebra[S[_], Alg[_]] { def setServiceId(name: NamedTypeToken[S], id: ValueToken[S], vm: ValueRaw): Alg[Boolean] def getServiceId(name: NamedTypeToken[S]): Alg[Either[Boolean, ValueRaw]] + def getServiceIdByName(name: String): Alg[Option[ValueRaw]] + + def getServiceByName(name: Name[S]): Alg[Option[ServiceRaw]] def beginScope(token: Token[S]): Alg[Unit] diff --git a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala index 6ff60c63..8406117e 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala @@ -6,7 +6,7 @@ import aqua.raw.{RawContext, ServiceRaw} import aqua.semantics.Levenshtein import aqua.semantics.rules.errors.ReportErrors import aqua.semantics.rules.locations.LocationsAlgebra -import aqua.semantics.rules.{StackInterpreter, abilities} +import aqua.semantics.rules.{abilities, StackInterpreter} import aqua.types.ArrowType import cats.data.{NonEmptyMap, State} import cats.syntax.functor.* @@ -41,24 +41,28 @@ class AbilitiesInterpreter[S[_], X](implicit } case None => - arrows.toNel.map(_._2).collect { - case (n, arr) if arr.codomain.length > 1 => - report(n, "Service functions cannot have multiple results") - }.sequence.flatMap{ _ => - modify(s => - s.copy( - services = s.services - .updated(name.value, ServiceRaw(name.value, arrows.map(_._2), defaultId)), - definitions = s.definitions.updated(name.value, name) - ) - ).flatMap { _ => - locations.addTokenWithFields( - name.value, - name, - arrows.toNel.toList.map(t => t._1 -> t._2._1) - ) - }.as(true) - } + arrows.toNel + .map(_._2) + .collect { + case (n, arr) if arr.codomain.length > 1 => + report(n, "Service functions cannot have multiple results") + } + .sequence + .flatMap { _ => + modify(s => + s.copy( + services = s.services + .updated(name.value, ServiceRaw(name.value, arrows.map(_._2), defaultId)), + definitions = s.definitions.updated(name.value, name) + ) + ).flatMap { _ => + locations.addTokenWithFields( + name.value, + name, + arrows.toNel.toList.map(t => t._1 -> t._2._1) + ) + }.as(true) + } } // adds location from token to its definition @@ -116,6 +120,22 @@ class AbilitiesInterpreter[S[_], X](implicit report(name, "Service with this name is not registered, can't set its ID").as(false) } + def getServiceIdByName(name: String): SX[Option[ValueRaw]] = + getService(name).flatMap { + case Some(_) => + getState.map(st => + st.stack + .flatMap(_.serviceIds.get(name).map(_._2)) + .headOption orElse st.rootServiceIds + .get( + name + ) + .map(_._2) orElse st.services.get(name).flatMap(_.defaultId) + ) + case None => + State.pure(None) + } + override def getServiceId(name: NamedTypeToken[S]): SX[Either[Boolean, ValueRaw]] = getService(name.value).flatMap { case Some(_) => @@ -147,6 +167,9 @@ class AbilitiesInterpreter[S[_], X](implicit } } + def getServiceByName(name: Name[S]): SX[Option[ServiceRaw]] = + getService(name.value) + override def beginScope(token: Token[S]): SX[Unit] = stackInt.beginScope(AbilitiesState.Frame[S](token)) diff --git a/semantics/src/main/scala/aqua/semantics/rules/names/NamesAlgebra.scala b/semantics/src/main/scala/aqua/semantics/rules/names/NamesAlgebra.scala index 1c605d19..cd22e984 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/names/NamesAlgebra.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/names/NamesAlgebra.scala @@ -10,7 +10,11 @@ trait NamesAlgebra[S[_], Alg[_]] { def readArrow(name: Name[S]): Alg[Option[ArrowType]] - def define(name: Name[S], `type`: Type): Alg[Boolean] + /** + * + * @param canOverride internal flag that is used for overriding services by serviceId + */ + def define(name: Name[S], `type`: Type, canOverride: Boolean = false): Alg[Boolean] def derive(name: Name[S], `type`: Type, derivedFrom: Set[String]): Alg[Boolean] diff --git a/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala b/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala index de703b88..699fd40e 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/names/NamesInterpreter.scala @@ -28,7 +28,7 @@ class NamesInterpreter[S[_], X](implicit private def readName(name: String): SX[Option[Type]] = getState.map { st => - st.stack.collectFirst { + st.stack.collectFirst { case frame if frame.names.contains(name) => frame.names(name) case frame if frame.arrows.contains(name) => frame.arrows(name) } orElse st.rootArrows.get(name) orElse st.rootValues.get(name) @@ -84,17 +84,19 @@ class NamesInterpreter[S[_], X](implicit .headOption orElse st.rootArrows.get(name) } - override def define(name: Name[S], `type`: Type): SX[Boolean] = + override def define(name: Name[S], `type`: Type, canOverride: Boolean = false): SX[Boolean] = readName(name.value).flatMap { - case Some(_) => + case Some(_) if !canOverride => getState.map(_.definitions.get(name.value).exists(_ == name)).flatMap { case true => State.pure(false) case false => report(name, "This name was already defined in the scope").as(false) } - case None => + case _ => mapStackHead( - report(name, "Cannot define a variable in the root scope") - .as(false) + getState.map { st => + st.rootValues.updated(name.value, `type`) + true + } )(fr => fr.addName(name, `type`) -> true).flatTap(_ => locations.addToken(name.value, name)) }