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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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