mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 14:40:17 +00:00
perf(compiler): Inliner optimization [LNG-322] (#1047)
This commit is contained in:
parent
27704a9169
commit
abcb63db3b
@ -6,7 +6,6 @@ import aqua.compiler.AquaCompiled
|
||||
import aqua.files.FileModuleId
|
||||
|
||||
import cats.data.Chain
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.effect.{IO, IOApp}
|
||||
import fs2.io.file.{Files, Path}
|
||||
import fs2.{Stream, text}
|
||||
@ -14,14 +13,16 @@ import fs2.{Stream, text}
|
||||
object Test extends IOApp.Simple {
|
||||
|
||||
override def run: IO[Unit] = {
|
||||
|
||||
APICompilation
|
||||
.compilePath(
|
||||
"./aqua-src/antithesis.aqua",
|
||||
Imports.fromMap(Map("/" -> Map("" -> List("./aqua")))),
|
||||
AquaAPIConfig(targetType = TypeScriptType),
|
||||
TypeScriptBackend(false, "IFluenceClient$$")
|
||||
)
|
||||
.flatMap { res =>
|
||||
).timed
|
||||
.flatMap { case (duration, res) =>
|
||||
println("Compilation time: " + duration.toMillis)
|
||||
val (warnings, result) = res.value.run
|
||||
|
||||
IO.delay {
|
||||
|
@ -1,40 +1,33 @@
|
||||
aqua M
|
||||
|
||||
export bugLng317
|
||||
export returnSrvAsAbility
|
||||
|
||||
service MyOp("op"):
|
||||
identity(s: string) -> string
|
||||
ability MyAb:
|
||||
call() -> string
|
||||
|
||||
ability WorkerJob:
|
||||
runOnSingleWorker(w: string) -> []string
|
||||
service MySrv("default-id"):
|
||||
call() -> string
|
||||
|
||||
func runJob(j: -> []string) -> []string:
|
||||
<- j()
|
||||
func mySrvDefault() -> MyAb:
|
||||
<- MySrv
|
||||
|
||||
func disjoint_run{WorkerJob}() -> -> []string:
|
||||
run = func () -> []string:
|
||||
r <- WorkerJob.runOnSingleWorker("a")
|
||||
<- r
|
||||
<- run
|
||||
func mySrvResolved() -> MyAb:
|
||||
MySrv "resolved-id"
|
||||
<- MySrv
|
||||
|
||||
func empty() -> string:
|
||||
a = "empty"
|
||||
<- a
|
||||
func mySrvThird() -> MyAb:
|
||||
MySrv "third-id"
|
||||
<- MySrv
|
||||
|
||||
func bugLng317() -> []string:
|
||||
func useMyAb{MyAb}() -> string:
|
||||
<- MyAb.call()
|
||||
|
||||
res: *string
|
||||
|
||||
outer = () -> string:
|
||||
<- empty()
|
||||
|
||||
clos = () -> -> []string:
|
||||
job2 = () -> []string:
|
||||
res <- outer()
|
||||
res <- MyOp.identity("identity")
|
||||
<- res
|
||||
<- job2
|
||||
worker_job = WorkerJob(runOnSingleWorker = clos())
|
||||
subnet_job <- disjoint_run{worker_job}()
|
||||
finalRes <- runJob(subnet_job)
|
||||
<- finalRes
|
||||
func returnSrvAsAbility() -> []string:
|
||||
result: *string
|
||||
MySrvDefault <- mySrvDefault()
|
||||
MySrvResolved <- mySrvResolved()
|
||||
MySrvThird <- mySrvThird()
|
||||
result <- useMyAb{MySrvDefault}()
|
||||
result <- useMyAb{MySrvResolved}()
|
||||
result <- useMyAb{MySrvThird}()
|
||||
<- result
|
@ -120,42 +120,77 @@ object Air {
|
||||
|
||||
case class Comment(comment: String, air: Air) extends Air(Keyword.NA)
|
||||
|
||||
private def show(depth: Int, air: Air): String = {
|
||||
def showNext(a: Air) = show(depth + 1, a)
|
||||
private def showInternal(space: String, sb: StringBuilder, air: Air): Unit = {
|
||||
|
||||
val space = " " * depth
|
||||
def showNext(a: Air): Unit = showInternal(space + " ", sb, a)
|
||||
|
||||
air match {
|
||||
case Air.Comment(c, a) =>
|
||||
space + "; " + c.replace("\n", "\n" + space + "; ") + "\n" +
|
||||
show(depth, a)
|
||||
sb.append(space)
|
||||
.append("; ")
|
||||
.append(c.replace("\n", "\n" + space + "; "))
|
||||
.append("\n")
|
||||
|
||||
showInternal(space, sb, a)
|
||||
|
||||
case _ =>
|
||||
s"$space(${air.keyword.value}" +
|
||||
sb.append(s"$space(${air.keyword.value}")
|
||||
(air match {
|
||||
case Air.Null ⇒ ""
|
||||
case Air.Never ⇒ ""
|
||||
case Air.Next(label) ⇒ s" $label"
|
||||
case Air.New(item, inst) ⇒ s" ${item.show}\n${showNext(inst)}$space"
|
||||
case Air.Null ⇒
|
||||
case Air.Never ⇒
|
||||
case Air.Next(label) ⇒ sb.append(s" $label")
|
||||
case Air.New(item, inst) ⇒
|
||||
sb.append(s" ${item.show}\n")
|
||||
showNext(inst)
|
||||
sb.append(space)
|
||||
case Air.Fold(iter, label, inst, lastInst) ⇒
|
||||
val l = show(depth + 1, lastInst)
|
||||
s" ${iter.show} $label\n${showNext(inst)}$l$space"
|
||||
sb.append(" ").append(s" ${iter.show} $label\n")
|
||||
showNext(inst)
|
||||
showNext(lastInst)
|
||||
sb.append(space)
|
||||
case Air.Match(left, right, inst) ⇒
|
||||
s" ${left.show} ${right.show}\n${showNext(inst)}$space"
|
||||
sb.append(s" ${left.show} ${right.show}\n")
|
||||
showNext(inst)
|
||||
sb.append(space)
|
||||
case Air.Mismatch(left, right, inst) ⇒
|
||||
s" ${left.show} ${right.show}\n${showNext(inst)}$space"
|
||||
case Air.Par(l, r) ⇒ s"\n${showNext(l)}${showNext(r)}$space"
|
||||
case Air.Seq(l, r) ⇒ s"\n${showNext(l)}${showNext(r)}$space"
|
||||
case Air.Xor(l, r) ⇒ s"\n${showNext(l)}${showNext(r)}$space"
|
||||
sb.append(s" ${left.show} ${right.show}\n")
|
||||
showNext(inst)
|
||||
sb.append(space)
|
||||
case Air.Par(l, r) ⇒
|
||||
sb.append("\n")
|
||||
showNext(l)
|
||||
showNext(r)
|
||||
sb.append(space)
|
||||
case Air.Seq(l, r) ⇒
|
||||
sb.append("\n")
|
||||
showNext(l)
|
||||
showNext(r)
|
||||
sb.append(space)
|
||||
case Air.Xor(l, r) ⇒
|
||||
sb.append("\n")
|
||||
showNext(l)
|
||||
showNext(r)
|
||||
sb.append(space)
|
||||
case Air.Call(triplet, args, res) ⇒
|
||||
s" ${triplet.show} [${args.map(_.show).mkString(" ")}]${res.fold("")(" " + _)}"
|
||||
case Air.Ap(operand, result) ⇒ s" ${operand.show} $result"
|
||||
case Air.ApStreamMap(key, operand, result) ⇒ s" (${key.show} ${operand.show}) $result"
|
||||
case Air.Fail(operand) => s" ${operand.show}"
|
||||
case Air.Canon(operand, peerId, result) ⇒ s" ${peerId.show} ${operand.show} $result"
|
||||
sb.append(s" ${triplet.show} [${args.map(_.show).mkString(" ")}]${res.fold("")(" " + _)}")
|
||||
case Air.Ap(operand, result) ⇒
|
||||
sb.append(s" ${operand.show} $result")
|
||||
case Air.ApStreamMap(key, operand, result) ⇒
|
||||
sb.append(s" (${key.show} ${operand.show}) $result")
|
||||
case Air.Fail(operand) => sb.append(s" ${operand.show}")
|
||||
case Air.Canon(operand, peerId, result) ⇒
|
||||
sb.append(s" ${peerId.show} ${operand.show} $result")
|
||||
case Air.Comment(_, _) => ";; Should not be displayed"
|
||||
}) + ")\n"
|
||||
})
|
||||
sb.append(")\n")
|
||||
}
|
||||
}
|
||||
|
||||
private def show(depth: Int, air: Air): String = {
|
||||
val sb = StringBuilder()
|
||||
val space = " " * depth
|
||||
showInternal(space, sb, air)
|
||||
sb.result()
|
||||
}
|
||||
|
||||
implicit val s: Show[Air] = Show.show(show(0, _))
|
||||
|
15
build.sbt
15
build.sbt
@ -188,7 +188,7 @@ lazy val inline = crossProject(JVMPlatform, JSPlatform)
|
||||
.crossType(CrossType.Pure)
|
||||
.in(file("model/inline"))
|
||||
.settings(commons)
|
||||
.dependsOn(raw, model)
|
||||
.dependsOn(raw, model, mangler)
|
||||
|
||||
lazy val transform = crossProject(JVMPlatform, JSPlatform)
|
||||
.withoutSuffixFor(JVMPlatform)
|
||||
@ -207,7 +207,7 @@ lazy val semantics = crossProject(JVMPlatform, JSPlatform)
|
||||
"dev.optics" %%% "monocle-macro" % monocleV
|
||||
)
|
||||
)
|
||||
.dependsOn(raw, parser, errors)
|
||||
.dependsOn(raw, parser, errors, mangler)
|
||||
|
||||
lazy val compiler = crossProject(JVMPlatform, JSPlatform)
|
||||
.withoutSuffixFor(JVMPlatform)
|
||||
@ -253,6 +253,17 @@ lazy val logging = crossProject(JVMPlatform, JSPlatform)
|
||||
)
|
||||
)
|
||||
|
||||
lazy val mangler = crossProject(JVMPlatform, JSPlatform)
|
||||
.withoutSuffixFor(JVMPlatform)
|
||||
.crossType(CrossType.Pure)
|
||||
.in(file("utils/mangler"))
|
||||
.settings(commons)
|
||||
.settings(
|
||||
libraryDependencies ++= Seq(
|
||||
"org.typelevel" %%% "cats-core" % catsV
|
||||
)
|
||||
)
|
||||
|
||||
lazy val constants = crossProject(JVMPlatform, JSPlatform)
|
||||
.withoutSuffixFor(JVMPlatform)
|
||||
.crossType(CrossType.Pure)
|
||||
|
@ -1,30 +1,19 @@
|
||||
package aqua.compiler
|
||||
|
||||
import aqua.backend.Backend
|
||||
import aqua.compiler.AquaError.{ParserError as AquaParserError, *}
|
||||
import aqua.linker.{AquaModule, Linker, Modules}
|
||||
import aqua.model.AquaContext
|
||||
import aqua.parser.lift.{LiftParser, Span}
|
||||
import aqua.parser.{Ast, ParserError}
|
||||
import aqua.raw.RawPart.Parts
|
||||
import aqua.raw.{RawContext, RawPart}
|
||||
import aqua.res.AquaRes
|
||||
import aqua.semantics.header.{HeaderHandler, HeaderSem, Picker}
|
||||
import aqua.semantics.{CompilerState, Semantics}
|
||||
import aqua.semantics.{SemanticError, SemanticWarning}
|
||||
import aqua.semantics.header.{HeaderHandler, Picker}
|
||||
import aqua.semantics.{SemanticError, Semantics}
|
||||
|
||||
import cats.arrow.FunctionK
|
||||
import cats.data.*
|
||||
import cats.data.Validated.{Invalid, Valid, validNec}
|
||||
import cats.parse.Parser0
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.either.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.monoid.*
|
||||
import cats.syntax.semigroup.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.{Comonad, Functor, Monad, Monoid, Order, ~>}
|
||||
import cats.{Comonad, Monad, Monoid, Order, ~>}
|
||||
import scribe.Logging
|
||||
|
||||
class AquaCompiler[F[_]: Monad, E, I: Order, S[_]: Comonad, C: Monoid: Picker](
|
||||
|
@ -1,33 +1,22 @@
|
||||
package aqua.compiler
|
||||
|
||||
import aqua.backend.Backend
|
||||
import aqua.compiler.AquaError.*
|
||||
import aqua.backend.{AirFunction, Backend}
|
||||
import aqua.linker.{AquaModule, Linker, Modules}
|
||||
import aqua.model.AquaContext
|
||||
import aqua.parser.lift.{LiftParser, Span}
|
||||
import aqua.parser.{Ast, ParserError}
|
||||
import aqua.raw.RawPart.Parts
|
||||
import aqua.raw.{RawContext, RawPart}
|
||||
import aqua.res.AquaRes
|
||||
import aqua.raw.RawContext
|
||||
import aqua.semantics.RawSemantics
|
||||
import aqua.semantics.header.{HeaderHandler, HeaderSem}
|
||||
import aqua.semantics.{CompilerState, RawSemantics, Semantics}
|
||||
|
||||
import cats.data.*
|
||||
import cats.data.Validated.{invalid, validNec, Invalid, Valid}
|
||||
import cats.parse.Parser0
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.foldable.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.monoid.*
|
||||
import cats.syntax.semigroup.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.either.*
|
||||
import cats.{~>, Comonad, Monad, Monoid, Order}
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.{Comonad, Monad, Monoid, Order}
|
||||
import scribe.Logging
|
||||
|
||||
import scala.collection.MapView
|
||||
|
||||
object CompilerAPI extends Logging {
|
||||
|
||||
private def toAquaProcessed[I: Order, E, S[_]: Comonad](
|
||||
|
@ -1,5 +1,6 @@
|
||||
package aqua.model.inline.state
|
||||
|
||||
import aqua.mangler.ManglerState
|
||||
import aqua.model.{FuncArrow, ValueModel}
|
||||
import aqua.model.inline.state.{Arrows, Counter, Exports, Mangler}
|
||||
import aqua.raw.arrow.FuncRaw
|
||||
@ -23,7 +24,7 @@ import scribe.Logging
|
||||
* for [[Counter]]
|
||||
*/
|
||||
case class InliningState(
|
||||
noNames: Set[String] = Set.empty,
|
||||
noNames: ManglerState = ManglerState(),
|
||||
resolvedExports: Map[String, ValueModel] = Map.empty,
|
||||
resolvedArrows: Map[String, FuncArrow] = Map.empty,
|
||||
instructionCounter: Int = 0
|
||||
@ -35,7 +36,7 @@ object InliningState {
|
||||
Counter.Simple.transformS(_.instructionCounter, (acc, i) => acc.copy(instructionCounter = i))
|
||||
|
||||
given Mangler[InliningState] =
|
||||
Mangler.Simple.transformS(_.noNames, (acc, nn) => acc.copy(noNames = nn))
|
||||
Mangler[ManglerState].transformS(_.noNames, (acc, nn) => acc.copy(noNames = nn))
|
||||
|
||||
given Arrows[InliningState] =
|
||||
Arrows.Simple.transformS(_.resolvedArrows, (acc, aa) => acc.copy(resolvedArrows = aa))
|
||||
|
@ -1,65 +1,36 @@
|
||||
package aqua.model.inline.state
|
||||
|
||||
import cats.data.State
|
||||
import aqua.mangler.ManglerState
|
||||
|
||||
trait Mangler[S] {
|
||||
self =>
|
||||
def getForbiddenNames: State[S, Set[String]]
|
||||
|
||||
def findNewNames(introduce: Set[String]): State[S, Map[String, String]]
|
||||
|
||||
def findNewName(introduce: String): State[S, String] =
|
||||
findNewNames(Set(introduce)).map(_.getOrElse(introduce, introduce))
|
||||
|
||||
def findAndForbidName(introduce: String): State[S, String] =
|
||||
for {
|
||||
n <- findNewName(introduce)
|
||||
_ <- forbid(Set(n))
|
||||
} yield n
|
||||
findAndForbidNames(Set(introduce)).map(_.getOrElse(introduce, introduce))
|
||||
|
||||
def findAndForbidNames(introduce: Set[String]): State[S, Map[String, String]] =
|
||||
for {
|
||||
n <- findNewNames(introduce)
|
||||
_ <- forbid(introduce ++ n.values.toSet)
|
||||
} yield n
|
||||
def findAndForbidNames(introduce: Set[String]): State[S, Map[String, String]]
|
||||
|
||||
def forbid(names: Set[String]): State[S, Unit]
|
||||
|
||||
def forbidName(name: String): State[S, Unit] =
|
||||
forbid(Set(name))
|
||||
|
||||
def transformS[R](f: R => S, g: (R, S) => R): Mangler[R] =
|
||||
new Mangler[R] {
|
||||
|
||||
val getForbiddenNames: State[R, Set[String]] =
|
||||
self.getForbiddenNames.transformS(f, g)
|
||||
|
||||
def findNewNames(introduce: Set[String]): State[R, Map[String, String]] =
|
||||
self.findNewNames(introduce).transformS(f, g)
|
||||
|
||||
def forbid(names: Set[String]): State[R, Unit] =
|
||||
self.forbid(names).transformS(f, g)
|
||||
|
||||
def findAndForbidNames(introduce: Set[String]): State[R, Map[String, String]] =
|
||||
self.findAndForbidNames(introduce).transformS(f, g)
|
||||
}
|
||||
}
|
||||
|
||||
object Mangler {
|
||||
def apply[S](implicit mangler: Mangler[S]): Mangler[S] = mangler
|
||||
def apply[S](using mangler: Mangler[S]): Mangler[S] = mangler
|
||||
|
||||
implicit object Simple extends Mangler[Set[String]] {
|
||||
val getForbiddenNames: State[Set[String], Set[String]] = State.get
|
||||
given Mangler[ManglerState] with {
|
||||
def findAndForbidNames(introduce: Set[String]): State[ManglerState, Map[String, String]] =
|
||||
State.apply(_.findNewNames(introduce))
|
||||
|
||||
def findNewNames(introduce: Set[String]): State[Set[String], Map[String, String]] =
|
||||
getForbiddenNames.map(forbidden =>
|
||||
(forbidden intersect introduce).foldLeft(Map.empty[String, String]) { case (acc, name) =>
|
||||
acc + (name -> LazyList
|
||||
.from(0)
|
||||
.map(name + "-" + _)
|
||||
.dropWhile(n => forbidden(n) || introduce(n) || acc.contains(n))
|
||||
.head)
|
||||
}
|
||||
)
|
||||
|
||||
def forbid(names: Set[String]): State[Set[String], Unit] =
|
||||
State.modify(_ ++ names)
|
||||
def forbid(names: Set[String]): State[ManglerState, Unit] =
|
||||
State.modify(st => st.forbid(names))
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
package aqua.model.inline
|
||||
|
||||
import aqua.mangler.ManglerState
|
||||
import aqua.model.inline.state.Mangler
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class ManglerSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
"mangler" should "rename right" in {
|
||||
val mangler = Mangler[ManglerState]
|
||||
|
||||
val results = for {
|
||||
res <- mangler.findAndForbidNames(Set("first", "second"))
|
||||
} yield res
|
||||
|
||||
val res = results.runA(ManglerState()).value
|
||||
res shouldBe Map()
|
||||
}
|
||||
|
||||
"mangler" should "rename right if already have renamed" in {
|
||||
val mangler = Mangler[ManglerState]
|
||||
|
||||
val results = for {
|
||||
res1 <- mangler.findAndForbidNames(Set("first", "first-0", "first-1"))
|
||||
res2 <- mangler.findAndForbidNames(Set("first"))
|
||||
res3 <- mangler.findAndForbidNames(Set("first-0"))
|
||||
res4 <- mangler.findAndForbidNames(Set("first-1"))
|
||||
res5 <- mangler.findAndForbidNames(Set("first-2"))
|
||||
} yield (res1, res2, res3, res4, res5)
|
||||
|
||||
val (r1, r2, r3, r4, r5) = results.runA(ManglerState()).value
|
||||
r1 shouldBe Map()
|
||||
r2 shouldBe Map("first" -> "first-2")
|
||||
r3 shouldBe Map("first-0" -> "first-0-0")
|
||||
r4 shouldBe Map("first-1" -> "first-1-0")
|
||||
r5 shouldBe Map("first-2" -> "first-2-0")
|
||||
}
|
||||
|
||||
"mangler" should "rename multiple times right" in {
|
||||
val mangler = Mangler[ManglerState]
|
||||
|
||||
val results = for {
|
||||
res <- mangler.findAndForbidNames(Set("first", "second"))
|
||||
res2 <- mangler.findAndForbidNames(Set("first", "second"))
|
||||
res3 <- mangler.findAndForbidNames(Set("first"))
|
||||
res4 <- mangler.findAndForbidNames(Set("first", "second"))
|
||||
res5 <- mangler.findAndForbidNames(Set("second"))
|
||||
} yield (res, res2, res3, res4, res5)
|
||||
|
||||
val (r1, r2, r3, r4, r5) = results.runA(ManglerState()).value
|
||||
r1 shouldBe Map()
|
||||
r2 shouldBe Map("first" -> "first-0", "second" -> "second-0")
|
||||
r3 shouldBe Map("first" -> "first-1")
|
||||
r4 shouldBe Map("first" -> "first-2", "second" -> "second-1")
|
||||
r5 shouldBe Map("second" -> "second-2")
|
||||
}
|
||||
|
||||
"mangler" should "forbid and rename right" in {
|
||||
val mangler = Mangler[ManglerState]
|
||||
|
||||
val results = for {
|
||||
_ <- mangler.forbid(Set("first", "second"))
|
||||
res1 <- mangler.findAndForbidNames(Set("first", "second"))
|
||||
res2 <- mangler.findAndForbidNames(Set("first"))
|
||||
_ <- mangler.forbid(Set("first"))
|
||||
_ <- mangler.forbid(Set("first", "second"))
|
||||
_ <- mangler.forbid(Set("second"))
|
||||
res3 <- mangler.findAndForbidNames(Set("second"))
|
||||
res4 <- mangler.findAndForbidNames(Set("second", "first"))
|
||||
} yield (res1, res2, res3, res4)
|
||||
|
||||
val (r1, r2, r3, r4) = results.runA(ManglerState()).value
|
||||
r1 shouldBe Map("first" -> "first-0", "second" -> "second-0")
|
||||
r2 shouldBe Map("first" -> "first-1")
|
||||
r3 shouldBe Map("second" -> "second-1")
|
||||
r4 shouldBe Map("first" -> "first-2", "second" -> "second-2")
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +1,28 @@
|
||||
package aqua.model.inline
|
||||
|
||||
import aqua.model.inline.raw.{ApplyPropertiesRawInliner, StreamGateInliner}
|
||||
import aqua.mangler.ManglerState
|
||||
import aqua.model.*
|
||||
import aqua.model.inline.raw.StreamGateInliner
|
||||
import aqua.model.inline.state.InliningState
|
||||
import aqua.raw.value.{ApplyPropertyRaw, FunctorRaw, IntoIndexRaw, LiteralRaw, VarRaw}
|
||||
import aqua.types.*
|
||||
import aqua.raw.value.*
|
||||
|
||||
import aqua.types.*
|
||||
import cats.Eval
|
||||
import cats.data.NonEmptyMap
|
||||
import cats.data.Chain
|
||||
import cats.syntax.show.*
|
||||
import cats.syntax.foldable.*
|
||||
import cats.data.{Chain, NonEmptyMap}
|
||||
import cats.free.Cofree
|
||||
import scala.collection.immutable.SortedMap
|
||||
import scala.math
|
||||
import cats.syntax.foldable.*
|
||||
import org.scalatest.Inside
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.Inside
|
||||
|
||||
import scala.collection.immutable.SortedMap
|
||||
import scala.math
|
||||
|
||||
class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
|
||||
import RawValueInliner.valueToModel
|
||||
|
||||
def toMangler(noNames: Set[String]) = ManglerState(noNames.map(_ -> 0).toMap)
|
||||
|
||||
def join(stream: VarModel, size: ValueModel) =
|
||||
stream match {
|
||||
case VarModel(
|
||||
@ -188,7 +188,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
"raw value inliner" should "desugarize a single non-recursive raw value" in {
|
||||
// x[y]
|
||||
valueToModel[InliningState](`raw x[y]`)
|
||||
.runA(InliningState(noNames = Set("x", "y")))
|
||||
.runA(InliningState(noNames = toMangler(Set("x", "y"))))
|
||||
.value shouldBe (
|
||||
VarModel(
|
||||
"x",
|
||||
@ -200,7 +200,6 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
|
||||
// TODO: unignore and fix after stream restrictions will be implemented
|
||||
ignore /*"raw value inliner"*/ should "unfold an IntoField PropertyModel" in {
|
||||
import aqua.model.inline.state.Mangler.Simple
|
||||
// a.field1.field2
|
||||
valueToModel[InliningState](`raw res.c`)
|
||||
.runA(
|
||||
@ -222,7 +221,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
val (resVal, resTree) = valueToModel[InliningState](
|
||||
`raw x[ys[0]]`
|
||||
)
|
||||
.runA(InliningState(noNames = Set("x", "ys")))
|
||||
.runA(InliningState(noNames = toMangler(Set("x", "ys"))))
|
||||
.value
|
||||
|
||||
resVal should be(
|
||||
@ -250,7 +249,9 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
it should "desugarize properties with functors x[ys[ys.length]][2] and make proper flattener tags" in {
|
||||
val (resVal, resTree) = valueToModel[InliningState](
|
||||
`x[xs[ys.length]][xss[yss.length]]`
|
||||
).runA(InliningState(noNames = Set("x", "ys", "xs", "yss", "xss"))).value
|
||||
).runA(
|
||||
InliningState(noNames = toMangler(Set("x", "ys", "xs", "yss", "xss")))
|
||||
).value
|
||||
|
||||
resVal should be(
|
||||
VarModel(
|
||||
@ -325,7 +326,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
val (resVal, resTree) = valueToModel[InliningState](
|
||||
`raw x[ys[0]][ys[1]]`
|
||||
)
|
||||
.runA(InliningState(noNames = Set("x", "ys")))
|
||||
.runA(InliningState(noNames = toMangler(Set("x", "ys"))))
|
||||
.value
|
||||
|
||||
resVal should be(
|
||||
@ -371,7 +372,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
IntoIndexRaw(idxRaw, ScalarType.string)
|
||||
)
|
||||
|
||||
val initState = InliningState(noNames = Set("x", "ys"))
|
||||
val initState = InliningState(noNames = toMangler(Set("x", "ys")))
|
||||
|
||||
// Here retrieve how size is inlined
|
||||
val (afterSizeState, (sizeModel, sizeTree)) =
|
||||
@ -420,7 +421,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
)
|
||||
|
||||
val (resVal, resTree) = valueToModel[InliningState](streamWithProps)
|
||||
.runA(InliningState(noNames = Set("x", "ys")))
|
||||
.runA(InliningState(noNames = toMangler(Set("x", "ys"))))
|
||||
.value
|
||||
}
|
||||
|
||||
@ -428,7 +429,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
val (resVal, resTree) = valueToModel[InliningState](
|
||||
`raw x[zs[ys[0]]][ys[1]]`
|
||||
)
|
||||
.runA(InliningState(noNames = Set("x", "ys", "zs")))
|
||||
.runA(InliningState(noNames = toMangler(Set("x", "ys", "zs"))))
|
||||
.value
|
||||
|
||||
// This is x[zs-0][ys-0]
|
||||
|
@ -10,7 +10,6 @@ import cats.data.Chain
|
||||
import cats.data.NonEmptyMap
|
||||
import cats.syntax.monoid.*
|
||||
import cats.syntax.option.*
|
||||
|
||||
import scala.collection.immutable.SortedMap
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,8 @@ case class FileSpan(name: String, locationMap: Eval[LocationMap], span: Span) {
|
||||
* @return FileSpan.Focus
|
||||
*/
|
||||
def focus(ctx: Int): Option[FileSpan.Focus] =
|
||||
span.focus(locationMap.value, ctx).map(FileSpan.Focus(name, locationMap, ctx, _))
|
||||
span.
|
||||
focus(locationMap.value, ctx).map(FileSpan.Focus(name, locationMap, ctx, _))
|
||||
|
||||
override def hashCode(): Int = (name, span).hashCode()
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
package aqua.semantics
|
||||
|
||||
import aqua.mangler.ManglerState
|
||||
import aqua.parser.lexer.Token
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.RawContext
|
||||
import aqua.semantics.rules.abilities.AbilitiesState
|
||||
import aqua.semantics.rules.definitions.DefinitionsState
|
||||
import aqua.semantics.rules.locations.LocationsState
|
||||
import aqua.semantics.rules.mangler.ManglerState
|
||||
import aqua.semantics.rules.names.NamesState
|
||||
import aqua.semantics.rules.report.ReportState
|
||||
import aqua.semantics.rules.types.TypesState
|
||||
|
@ -1,9 +1,8 @@
|
||||
package aqua.semantics
|
||||
|
||||
import aqua.parser.Ast
|
||||
import aqua.semantics.SemanticError
|
||||
|
||||
import cats.data.{Chain, EitherNec, EitherT, NonEmptyChain, ValidatedNec, Writer}
|
||||
import cats.data.{Chain, EitherT, NonEmptyChain, Writer}
|
||||
|
||||
trait Semantics[S[_], C] {
|
||||
|
||||
|
@ -31,11 +31,11 @@ class ServiceIdSem[S[_]](val expr: ServiceIdExpr[S]) extends AnyVal {
|
||||
)
|
||||
serviceType <- EitherT.fromOptionF(
|
||||
T.resolveServiceType(expr.service),
|
||||
Raw.error("Can not resolve service type")
|
||||
Raw.error("Cannot resolve service type")
|
||||
)
|
||||
name <- EitherT.fromOptionF(
|
||||
A.renameService(expr.service),
|
||||
Raw.error("Can not set service ID")
|
||||
Raw.error("Cannot set service ID")
|
||||
)
|
||||
_ <- EitherT.liftF(
|
||||
N.derive(
|
||||
|
@ -21,8 +21,9 @@ case class LocationsState[S[_]](
|
||||
name: String,
|
||||
token: Token[S]
|
||||
): List[VariableInfo[S]] = {
|
||||
if (!vars.exists(_.definition.name == name))
|
||||
logger.error(s"Unexpected. Cannot add occurrence for $name")
|
||||
// TODO: this code lasts too long, but we can find errors in it.
|
||||
// if (!vars.exists(_.definition.name == name))
|
||||
// logger.error(s"Unexpected. Cannot add occurrence for $name")
|
||||
|
||||
vars.updateFirst(_.definition.name == name, v => v.copy(occurrences = token +: v.occurrences))
|
||||
}
|
||||
|
@ -1,27 +1,17 @@
|
||||
package aqua.semantics.rules.mangler
|
||||
|
||||
import aqua.mangler.ManglerState
|
||||
|
||||
import cats.data.State
|
||||
import monocle.Lens
|
||||
import monocle.macros.GenLens
|
||||
|
||||
class ManglerInterpreter[X](using
|
||||
lens: Lens[X, ManglerState]
|
||||
) extends ManglerAlgebra[State[X, *]] {
|
||||
|
||||
override def rename(name: String): State[X, String] =
|
||||
for {
|
||||
s <- get
|
||||
newName = LazyList
|
||||
.from(0)
|
||||
.map(i => s"$name-$i")
|
||||
.dropWhile(s.isForbidden)
|
||||
.head
|
||||
_ <- modify(_.forbid(newName))
|
||||
} yield newName
|
||||
apply(_.forbidAndRename(name))
|
||||
|
||||
private lazy val get: State[X, ManglerState] =
|
||||
State.get[X].map(lens.get)
|
||||
|
||||
private def modify(f: ManglerState => ManglerState): State[X, Unit] =
|
||||
State.modify[X](lens.modify(f))
|
||||
private def apply[A](f: ManglerState => (ManglerState, A)): State[X, A] =
|
||||
State.apply(lens.modifyF(f andThen (_.swap)) andThen (_.swap))
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
package aqua.semantics.rules.mangler
|
||||
|
||||
import cats.kernel.Monoid
|
||||
|
||||
final case class ManglerState(
|
||||
forbidden: Set[String] = Set.empty
|
||||
) {
|
||||
|
||||
def isForbidden(name: String): Boolean =
|
||||
forbidden.contains(name)
|
||||
|
||||
def forbid(name: String): ManglerState =
|
||||
copy(forbidden = forbidden + name)
|
||||
}
|
||||
|
||||
object ManglerState {
|
||||
|
||||
given Monoid[ManglerState] with {
|
||||
override val empty: ManglerState = ManglerState()
|
||||
|
||||
override def combine(x: ManglerState, y: ManglerState): ManglerState =
|
||||
ManglerState(forbidden = x.forbidden ++ y.forbidden)
|
||||
}
|
||||
}
|
@ -6,10 +6,10 @@ import scribe.{Level, Logger}
|
||||
object LogFormatter {
|
||||
|
||||
val formatter: Formatter =
|
||||
formatter"$date ${string("[")}$levelColored${string("]")} $messages$mdc"
|
||||
formatter"$date $timeStamp ${string("[")}$levelColored${string("]")} $messages$mdc"
|
||||
|
||||
val formatterWithFilename: Formatter =
|
||||
formatter"$date $fileName ${string("[")}$levelColored${string("]")} $messages$mdc"
|
||||
formatter"$date $timeStamp $fileName ${string("[")}$levelColored${string("]")} $messages$mdc"
|
||||
|
||||
def initLogger(level: Option[Level]): Logger = {
|
||||
scribe.Logger.root
|
||||
|
65
utils/mangler/src/main/scala/aqua/mangler/ManglerState.scala
Normal file
65
utils/mangler/src/main/scala/aqua/mangler/ManglerState.scala
Normal file
@ -0,0 +1,65 @@
|
||||
package aqua.mangler
|
||||
|
||||
import cats.Monoid
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
case class ManglerState(namesNumbers: Map[String, Int] = Map.empty) {
|
||||
|
||||
private def genName(name: String, n: Int) =
|
||||
s"$name-$n"
|
||||
|
||||
// find unique names that have not yet been used
|
||||
def findNewNames(introduce: Set[String]): (ManglerState, Map[String, String]) = {
|
||||
introduce.foldLeft(this, Map.empty[String, String]) {
|
||||
case ((state, newNames), name) =>
|
||||
val namesNumbers = state.namesNumbers
|
||||
if (!namesNumbers.contains(name)) {
|
||||
val newState = state.copy(
|
||||
namesNumbers = namesNumbers
|
||||
.updated(name, 0)
|
||||
)
|
||||
|
||||
(newState, newNames)
|
||||
} else {
|
||||
val (newNumber, newName) = LazyList
|
||||
.from(namesNumbers.getOrElse(name, 0))
|
||||
.map(n => n -> genName(name, n))
|
||||
.dropWhile { case (_, newName) =>
|
||||
namesNumbers.contains(newName)
|
||||
}
|
||||
.head
|
||||
val newState = copy(
|
||||
namesNumbers = namesNumbers
|
||||
.updated(name, newNumber + 1)
|
||||
.updated(newName, 0)
|
||||
)
|
||||
|
||||
(newState, newNames + (name -> newName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add names to used list
|
||||
def forbid(names: Set[String]): ManglerState = {
|
||||
val newLastNumbers = names.map(n => n -> namesNumbers.getOrElse(n, 0)).toMap
|
||||
copy(namesNumbers = newLastNumbers ++ namesNumbers)
|
||||
}
|
||||
|
||||
// forbid name and return unique
|
||||
def forbidAndRename(name: String): (ManglerState, String) = {
|
||||
val set = Set(name)
|
||||
val (newState, newNames) = forbid(set).findNewNames(set)
|
||||
(newState, newNames(name))
|
||||
}
|
||||
}
|
||||
|
||||
object ManglerState {
|
||||
|
||||
given Monoid[ManglerState] with {
|
||||
override val empty: ManglerState = ManglerState()
|
||||
|
||||
override def combine(x: ManglerState, y: ManglerState): ManglerState =
|
||||
ManglerState(namesNumbers = x.namesNumbers ++ y.namesNumbers)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user