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