perf(compiler): Inliner optimization [LNG-322] (#1047)

This commit is contained in:
Dima 2024-01-22 13:08:06 +03:00 committed by GitHub
parent 27704a9169
commit abcb63db3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 313 additions and 211 deletions

View File

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

View File

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

View File

@ -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)
case _ =>
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.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"
}
sb.append(space)
.append("; ")
.append(c.replace("\n", "\n" + space + "; "))
.append("\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, _))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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