mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 14:40:17 +00:00
fix(compiler): Create restrictions in inliner [LNG-346] (#1099)
This commit is contained in:
parent
320b516807
commit
14748c7646
@ -128,7 +128,7 @@ class CallPreparer(
|
||||
|
||||
FuncArrow(
|
||||
config.functionWrapperName,
|
||||
SeqTag.wrap((getters.map(_.leaf) :+ body :+ finisherService.leaf): _*),
|
||||
SeqTag.wrap(getters.map(_.leaf) :+ body :+ finisherService.leaf*),
|
||||
// no arguments and returns "ok" string
|
||||
ArrowType(NilType, returnCodomain),
|
||||
ret,
|
||||
|
@ -1,15 +1,39 @@
|
||||
aqua Main
|
||||
aqua A
|
||||
|
||||
export main
|
||||
export streamTry, streamFor
|
||||
|
||||
service Srv("srv"):
|
||||
call(x: i32) -> i32
|
||||
service FailureSrv("failure"):
|
||||
fail(msg: string)
|
||||
|
||||
func main(a: i32, b: i32) -> i32:
|
||||
res: *i32
|
||||
if a > b:
|
||||
on "peer" via "relay":
|
||||
res <- Srv.call(a)
|
||||
func streamTry() -> i8:
|
||||
on HOST_PEER_ID:
|
||||
try:
|
||||
stream: *i8
|
||||
anotherStream = stream
|
||||
stream <<- 1
|
||||
anotherStream <<- 1
|
||||
FailureSrv.fail("try")
|
||||
catch e:
|
||||
stream = *[88,88,88]
|
||||
stream <<- 2
|
||||
FailureSrv.fail("catch")
|
||||
otherwise:
|
||||
stream: *i8
|
||||
stream <<- 3
|
||||
|
||||
<- res!
|
||||
stream: *i8
|
||||
stream <<- 4
|
||||
|
||||
<- stream!
|
||||
|
||||
service StreamService("test-service"):
|
||||
store(numbers: []u32, n: u32)
|
||||
|
||||
func callService(stream: *u32, n: u32):
|
||||
stream <<- 1
|
||||
StreamService.store(stream, n)
|
||||
|
||||
func streamFor():
|
||||
arr = [1,2,3,4,5]
|
||||
for a <- arr:
|
||||
callService(*[], a)
|
@ -41,11 +41,11 @@ func checkKeepArg() -> []string, []string:
|
||||
<- a, y
|
||||
|
||||
-- failing Aqua code:
|
||||
service TestService("test-service"):
|
||||
service TestServiceRestrict("test-service"):
|
||||
get_records(key: string) -> []string
|
||||
|
||||
func append_records(peer: string, srum: *[]string):
|
||||
srum <- TestService.get_records(peer)
|
||||
srum <- TestServiceRestrict.get_records(peer)
|
||||
|
||||
func retrieve_records(peer: string) -> [][]string:
|
||||
records: *[]string
|
||||
|
@ -5,11 +5,11 @@ func some_string() -> string:
|
||||
<- "some_string_func"
|
||||
|
||||
|
||||
service TestService("test-service"):
|
||||
service TestServiceRename("test-service"):
|
||||
get_records(key: string) -> []string
|
||||
|
||||
func append_records(peer: string, srum: *[]string):
|
||||
srum <- TestService.get_records(peer)
|
||||
srum <- TestServiceRename.get_records(peer)
|
||||
|
||||
func retrieve_records(peer: string) -> [][]string:
|
||||
records: *[]string
|
||||
|
@ -169,11 +169,10 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
|
||||
val expected =
|
||||
XorRes.wrap(
|
||||
RestrictionRes("results", resultsType).wrap(
|
||||
SeqRes.wrap(
|
||||
getDataSrv("-relay-", "-relay-", ScalarType.string),
|
||||
getDataSrv("peers", peers.name, peers.`type`),
|
||||
RestrictionRes(results.name, resultsType).wrap(
|
||||
SeqRes.wrap(
|
||||
ParRes.wrap(
|
||||
FoldRes
|
||||
.lastNever(peer.name, peers)
|
||||
@ -215,10 +214,9 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
ApRes(
|
||||
canonResult,
|
||||
CallModel.Export(flatResult.name, flatResult.`type`)
|
||||
).leaf
|
||||
)
|
||||
),
|
||||
).leaf,
|
||||
respCall(transformCfg, flatResult, initPeer)
|
||||
)
|
||||
),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
@ -352,8 +350,7 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
val resFlatVM = VarModel("-res-flat-0", ArrayType(ScalarType.string))
|
||||
|
||||
val expected = XorRes.wrap(
|
||||
SeqRes.wrap(
|
||||
RestrictionRes(resVM.name, resStreamType).wrap(
|
||||
RestrictionRes(resVM.name, resVM.`type`).wrap(
|
||||
SeqRes.wrap(
|
||||
// res <- foo()
|
||||
ApRes(
|
||||
@ -375,10 +372,9 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
ApRes(
|
||||
VarModel(resCanonVM.name, resCanonVM.`type`),
|
||||
CallModel.Export(resFlatVM.name, resFlatVM.`type`)
|
||||
).leaf
|
||||
)
|
||||
),
|
||||
).leaf,
|
||||
respCall(transformCfg, resFlatVM, initPeer)
|
||||
)
|
||||
),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
@ -424,18 +420,16 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
).leaf
|
||||
|
||||
val expected = XorRes.wrap(
|
||||
RestrictionRes(streamName, streamType).wrap(
|
||||
SeqRes.wrap(
|
||||
getDataSrv("-relay-", "-relay-", ScalarType.string),
|
||||
getDataSrv("i", argName, argType),
|
||||
RestrictionRes(streamName, streamType).wrap(
|
||||
SeqRes.wrap(
|
||||
ApRes(LiteralModel.quote("a"), CallModel.Export(streamName, streamType)).leaf,
|
||||
ApRes(LiteralModel.quote("b"), CallModel.Export(streamName, streamType)).leaf,
|
||||
join(VarModel(streamName, streamType), arg),
|
||||
decrement
|
||||
)
|
||||
),
|
||||
decrement,
|
||||
emptyRespCall(transformCfg, initPeer)
|
||||
)
|
||||
),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
|
@ -1,18 +1,18 @@
|
||||
aqua Test
|
||||
|
||||
export test, TestService
|
||||
export test, TestServiceClosureArrowCapture
|
||||
|
||||
service TestService:
|
||||
service TestServiceClosureArrowCapture:
|
||||
call(s: string) -> string
|
||||
|
||||
ability TestAbility:
|
||||
arrow(s: string) -> string
|
||||
|
||||
func returnCapture() -> string -> string:
|
||||
TestService "test-service"
|
||||
TestServiceClosureArrowCapture "test-service"
|
||||
|
||||
closure = (s: string) -> string:
|
||||
<- TestService.call(s)
|
||||
<- TestServiceClosureArrowCapture.call(s)
|
||||
|
||||
closure1 = closure
|
||||
closure2 = closure1
|
||||
@ -26,7 +26,7 @@ func returnCapture() -> string -> string:
|
||||
s1 <- closure(s) -- capture closure
|
||||
s2 <- closure3(s1) -- capture renamed closure
|
||||
s3 <- Ab.arrow(s2) -- capture ability
|
||||
s4 <- TestService.call(s3) -- capture service
|
||||
s4 <- TestServiceClosureArrowCapture.call(s3) -- capture service
|
||||
<- s4
|
||||
|
||||
<- capture
|
||||
|
49
integration-tests/aqua/examples/closureStreamScopes.aqua
Normal file
49
integration-tests/aqua/examples/closureStreamScopes.aqua
Normal file
@ -0,0 +1,49 @@
|
||||
aqua ClosureStreamScopes
|
||||
|
||||
export simpleTest, complexTest
|
||||
|
||||
ability Join:
|
||||
join1() -> []string
|
||||
|
||||
ability Fork:
|
||||
fork() -> Join
|
||||
|
||||
func simpleTest() -> []string:
|
||||
|
||||
fork = () -> Join:
|
||||
in: *string
|
||||
join1 = () -> []string:
|
||||
|
||||
in <<- "something in nested"
|
||||
|
||||
<- ["result"]
|
||||
in <<- "something in"
|
||||
<- Join(join1)
|
||||
f = Fork(fork)
|
||||
|
||||
j = f.fork()
|
||||
<- j.join1()
|
||||
|
||||
func fork() -> Join:
|
||||
in: *string
|
||||
out: *string
|
||||
join1 = () -> []string:
|
||||
inJoin: *string
|
||||
for i <- in rec:
|
||||
inJoin <<- i
|
||||
for o <- out rec:
|
||||
inJoin <<- o
|
||||
join in!
|
||||
par join out!
|
||||
<- inJoin
|
||||
in <<- "something in INSIDE"
|
||||
out <<- "something out INSIDE"
|
||||
<- Join(join1)
|
||||
|
||||
func complexTest() -> []string, []string:
|
||||
out: *string
|
||||
f = Fork(fork = fork)
|
||||
j <- f.fork()
|
||||
strs <- j.join1()
|
||||
out <<- "something out OUTSIDE"
|
||||
<- strs, out
|
@ -1,8 +1,8 @@
|
||||
aqua MultiRec
|
||||
|
||||
export TestService, multiRecStream
|
||||
export TestServiceMultiRec, multiRecStream
|
||||
|
||||
service TestService("test-srv"):
|
||||
service TestServiceMultiRec("test-srv"):
|
||||
handle(i: i32) -> []i32
|
||||
|
||||
func multiRecStream(init: i32, target: i32) -> []i32:
|
||||
@ -11,7 +11,7 @@ func multiRecStream(init: i32, target: i32) -> []i32:
|
||||
|
||||
loop <<- init
|
||||
for l <- loop rec:
|
||||
news <- TestService.handle(l)
|
||||
news <- TestServiceMultiRec.handle(l)
|
||||
for n <- news:
|
||||
loop <<- n
|
||||
if l == target:
|
||||
|
@ -1,8 +1,8 @@
|
||||
aqua Test
|
||||
|
||||
export test, testCapture, TestService
|
||||
export test, testCapture, TestServiceAsAbility
|
||||
|
||||
service TestService("default-id"):
|
||||
service TestServiceAsAbility("default-id"):
|
||||
getId() -> string
|
||||
concatId(s: string) -> string
|
||||
|
||||
@ -20,14 +20,14 @@ func test() -> []string:
|
||||
result: *string
|
||||
|
||||
-- Test service
|
||||
result <- TestService.concatId("call")
|
||||
capture = TestService.concatId
|
||||
result <- TestServiceAsAbility.concatId("call")
|
||||
capture = TestServiceAsAbility.concatId
|
||||
result <- capture("capture call")
|
||||
result <- acceptClosure(TestService.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestService}("accept ability call")
|
||||
result <- acceptClosure(TestServiceAsAbility.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestServiceAsAbility}("accept ability call")
|
||||
|
||||
-- Test renamed service
|
||||
Renamed = TestService
|
||||
Renamed = TestServiceAsAbility
|
||||
result <- Renamed.concatId("call")
|
||||
captureRenamed = Renamed.concatId
|
||||
result <- captureRenamed("capture call")
|
||||
@ -35,15 +35,15 @@ func test() -> []string:
|
||||
result <- acceptAbility{Renamed}("accept ability call")
|
||||
|
||||
-- Test resolved service
|
||||
TestService "resolved-id-1"
|
||||
result <- TestService.concatId("call")
|
||||
captureResolved = TestService.concatId
|
||||
TestServiceAsAbility "resolved-id-1"
|
||||
result <- TestServiceAsAbility.concatId("call")
|
||||
captureResolved = TestServiceAsAbility.concatId
|
||||
result <- captureResolved("capture call")
|
||||
result <- acceptClosure(TestService.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestService}("accept ability call")
|
||||
result <- acceptClosure(TestServiceAsAbility.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestServiceAsAbility}("accept ability call")
|
||||
|
||||
-- Test renamed resolved service
|
||||
Renamed1 = TestService
|
||||
Renamed1 = TestServiceAsAbility
|
||||
result <- Renamed1.concatId("call")
|
||||
captureRenamed1 = Renamed1.concatId
|
||||
result <- captureRenamed1("capture call")
|
||||
@ -59,8 +59,8 @@ func test() -> []string:
|
||||
|
||||
-- Test resolved in scope service
|
||||
for i <- ["iter-id-1", "iter-id-2"]:
|
||||
TestService i
|
||||
RenamedI = TestService
|
||||
TestServiceAsAbility i
|
||||
RenamedI = TestServiceAsAbility
|
||||
result <- RenamedI.concatId("call")
|
||||
captureI = RenamedI.concatId
|
||||
result <- captureI("capture call")
|
||||
@ -68,28 +68,28 @@ func test() -> []string:
|
||||
result <- acceptAbility{RenamedI}("accept ability call")
|
||||
|
||||
-- Test resolved service again (should save id)
|
||||
result <- TestService.concatId("call")
|
||||
captureAgain = TestService.concatId
|
||||
result <- TestServiceAsAbility.concatId("call")
|
||||
captureAgain = TestServiceAsAbility.concatId
|
||||
result <- captureAgain("capture call")
|
||||
result <- acceptClosure(TestService.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestService}("accept ability call")
|
||||
result <- acceptClosure(TestServiceAsAbility.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestServiceAsAbility}("accept ability call")
|
||||
|
||||
-- Test re resolved service in same scope
|
||||
TestService "resolved-id-2"
|
||||
result <- TestService.concatId("call")
|
||||
captureReResolved = TestService.concatId
|
||||
TestServiceAsAbility "resolved-id-2"
|
||||
result <- TestServiceAsAbility.concatId("call")
|
||||
captureReResolved = TestServiceAsAbility.concatId
|
||||
result <- captureReResolved("capture call")
|
||||
result <- acceptClosure(TestService.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestService}("accept ability call")
|
||||
result <- acceptClosure(TestServiceAsAbility.concatId, "accept closure call")
|
||||
result <- acceptAbility{TestServiceAsAbility}("accept ability call")
|
||||
|
||||
<- result
|
||||
|
||||
func callCapture{MatchingAbility}() -> string, string:
|
||||
TestService "resolved-id-in-capture"
|
||||
res1 <- TestService.concatId("in capture")
|
||||
TestServiceAsAbility "resolved-id-in-capture"
|
||||
res1 <- TestServiceAsAbility.concatId("in capture")
|
||||
res2 <- MatchingAbility.concatId("in capture")
|
||||
<- res1, res2
|
||||
|
||||
func testCapture() -> string, string:
|
||||
res1, res2 <- callCapture{TestService}()
|
||||
res1, res2 <- callCapture{TestServiceAsAbility}()
|
||||
<- res1, res2
|
@ -23,6 +23,7 @@ import { registerPrintln } from "../compiled/examples/println.js";
|
||||
import { helloWorldCall } from "../examples/helloWorldCall.js";
|
||||
import { foldBug499Call, foldCall } from "../examples/foldCall.js";
|
||||
import { bugNG69Call, ifCall, ifWrapCall } from "../examples/ifCall.js";
|
||||
import { simpleStreamScopeCall, complexStreamScopeCall } from "../examples/closureStreamScopesCall.js";
|
||||
import { ifPropagateErrorsCall } from "../examples/ifPropagateErrors.js";
|
||||
import { parCall, testTimeoutCall } from "../examples/parCall.js";
|
||||
import { complexCall } from "../examples/complex.js";
|
||||
@ -767,6 +768,17 @@ describe("Testing examples", () => {
|
||||
expect(streamCaptureResult).toEqual(["one", "two", "three"]);
|
||||
});
|
||||
|
||||
it("closureStreamScopes.aqua simple", async () => {
|
||||
let result = await simpleStreamScopeCall();
|
||||
// it is not hanging
|
||||
expect(result).toEqual(["result"]);
|
||||
});
|
||||
|
||||
it("closureStreamScopes.aqua complex", async () => {
|
||||
let result = await complexStreamScopeCall();
|
||||
expect(result).toEqual([["something in INSIDE", "something out INSIDE"], ["something out OUTSIDE"]]);
|
||||
});
|
||||
|
||||
// TODO: Unskip this after LNG-226 is fixed
|
||||
it.skip("streamCapture.aqua return", async () => {
|
||||
let streamCaptureResult = await streamCaptureReturnCall();
|
||||
|
@ -1,10 +1,10 @@
|
||||
import {
|
||||
test,
|
||||
registerTestService,
|
||||
registerTestServiceClosureArrowCapture,
|
||||
} from "../compiled/examples/closureArrowCapture.js";
|
||||
|
||||
export async function closureArrowCaptureCall(s: string) {
|
||||
registerTestService("test-service", {
|
||||
registerTestServiceClosureArrowCapture("test-service", {
|
||||
call: (s: string) => {
|
||||
return "call: " + s;
|
||||
},
|
||||
|
12
integration-tests/src/examples/closureStreamScopesCall.ts
Normal file
12
integration-tests/src/examples/closureStreamScopesCall.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import {
|
||||
simpleTest,
|
||||
complexTest
|
||||
} from "../compiled/examples/closureStreamScopes.js";
|
||||
|
||||
export async function complexStreamScopeCall(): Promise<[string[], string[]]> {
|
||||
return complexTest();
|
||||
}
|
||||
|
||||
export async function simpleStreamScopeCall(): Promise<string[]> {
|
||||
return simpleTest();
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
multiRecStream,
|
||||
registerTestService,
|
||||
registerTestServiceMultiRec,
|
||||
} from "../../compiled/examples/recursiveStreams/multiRec.js";
|
||||
|
||||
export async function multiRecStreamCall(
|
||||
@ -8,7 +8,7 @@ export async function multiRecStreamCall(
|
||||
target: number,
|
||||
handle: (i: number) => number[],
|
||||
): Promise<number[]> {
|
||||
registerTestService({ handle });
|
||||
registerTestServiceMultiRec({ handle });
|
||||
|
||||
return await multiRecStream(init, target);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {
|
||||
test,
|
||||
testCapture,
|
||||
registerTestService,
|
||||
registerTestServiceAsAbility,
|
||||
} from "../compiled/examples/servicesAsAbilities.js";
|
||||
|
||||
const serviceIds = {
|
||||
@ -37,7 +37,7 @@ export const expectedServiceResults = serviceIdsSequence.flatMap((id) =>
|
||||
|
||||
export async function servicesAsAbilitiesCall() {
|
||||
Object.entries(serviceIds).forEach(([_key, id], _idx) =>
|
||||
registerTestService(id, {
|
||||
registerTestServiceAsAbility(id, {
|
||||
concatId: (s: string) => {
|
||||
return `${id}: ${s}`;
|
||||
},
|
||||
@ -57,7 +57,7 @@ export const expectedServiceCaptureResults = [
|
||||
|
||||
export async function servicesAsAbilitiesCaptureCall() {
|
||||
["resolved-id-in-capture", "default-id"].forEach((id) =>
|
||||
registerTestService(id, {
|
||||
registerTestServiceAsAbility(id, {
|
||||
concatId: (s: string) => {
|
||||
return `${id}: ${s}`;
|
||||
},
|
||||
|
@ -77,7 +77,7 @@ object TypeJs {
|
||||
def typeList(types: Iterable[(String, Type)]): Dictionary[TypeJs] =
|
||||
js.Dictionary(types.map { case (n, t) =>
|
||||
(n, TypeJs.fromType(t))
|
||||
}.toSeq: _*)
|
||||
}.toSeq*)
|
||||
|
||||
def fromType(t: Type): TypeJs = {
|
||||
t match
|
||||
|
@ -9,9 +9,11 @@ import aqua.raw.value.{ValueRaw, VarRaw}
|
||||
import aqua.types.*
|
||||
|
||||
import cats.data.{Chain, IndexedStateT, State, StateT}
|
||||
import cats.free.Cofree
|
||||
import cats.kernel.Semigroup
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.bifunctor.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.foldable.*
|
||||
import cats.syntax.option.*
|
||||
import cats.syntax.semigroup.*
|
||||
@ -146,6 +148,7 @@ object ArrowInliner extends Logging {
|
||||
outsideDeclaredStreams: Set[String]
|
||||
): State[S, InlineResult] = for {
|
||||
callableFuncBodyNoTopology <- TagInliner.handleTree(fn.body)
|
||||
|
||||
callableFuncBody =
|
||||
fn.capturedTopology
|
||||
.fold(SeqModel)(ApplyTopologyModel.apply)
|
||||
@ -173,14 +176,15 @@ object ArrowInliner extends Logging {
|
||||
|
||||
// find and get resolved arrows if we return them from the function
|
||||
returnedArrows = rets.collect { case VarModel(name, _: ArrowType, _) => name }.toSet
|
||||
arrowsToSave <- Arrows[S].pickArrows(returnedArrows)
|
||||
arrowsFromClosures <- Arrows[S].pickArrows(returnedArrows)
|
||||
arrowsToSave = arrowsFromAbilities ++ arrowsFromClosures
|
||||
|
||||
body = SeqModel.wrap(callableFuncBody :: ops)
|
||||
} yield InlineResult(
|
||||
body,
|
||||
rets,
|
||||
varsFromAbilities,
|
||||
arrowsFromAbilities ++ arrowsToSave
|
||||
arrowsToSave
|
||||
)
|
||||
|
||||
/**
|
||||
@ -236,7 +240,7 @@ object ArrowInliner extends Logging {
|
||||
case arrow @ (_, ValueModel.Arrow(_, _)) =>
|
||||
arrow.some
|
||||
case (_, m) =>
|
||||
internalError(s"($m) cannot be an arrow")
|
||||
internalError(s"($m) cannot be an arrow for '$abilityName' ability")
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +272,7 @@ object ArrowInliner extends Logging {
|
||||
case (_, ValueModel.Arrow(vm, _)) =>
|
||||
arrows.get(vm.name).map(vm.name -> _)
|
||||
case (_, m) =>
|
||||
internalError(s"($m) cannot be an arrow")
|
||||
internalError(s"($m) cannot be an arrow for '$name' ability")
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,14 +328,10 @@ object ArrowInliner extends Logging {
|
||||
* Correctly rename captured values and arrows of a function
|
||||
*
|
||||
* @param fn Function
|
||||
* @param exports Exports state before calling/inlining
|
||||
* @param arrows Arrows state before calling/inlining
|
||||
* @return Renamed values and arrows
|
||||
*/
|
||||
def renameCaptured[S: Mangler](
|
||||
fn: FuncArrow,
|
||||
exports: Map[String, ValueModel],
|
||||
arrows: Map[String, FuncArrow]
|
||||
fn: FuncArrow
|
||||
): State[S, (Renamed[ValueModel], Renamed[FuncArrow])] = {
|
||||
// Gather abilities related values
|
||||
val abilitiesValues = fn.capturedValues.collect {
|
||||
@ -418,7 +418,7 @@ object ArrowInliner extends Logging {
|
||||
otherValues
|
||||
)
|
||||
otherArrowsValuesRenamed = Renamed(
|
||||
otherValuesRenamed.renames.filterKeys(otherArrowsValues.keySet).toMap,
|
||||
otherValuesRenamed.renames.view.filterKeys(otherArrowsValues.keySet).toMap,
|
||||
otherArrowsValues.renamed(otherValuesRenamed.renames)
|
||||
)
|
||||
|
||||
@ -481,9 +481,6 @@ object ArrowInliner extends Logging {
|
||||
): State[S, (FuncArrow, OpModel.Tree)] = for {
|
||||
args <- ArgsCall(fn.arrowType.domain, call.args).pure[State[S, *]]
|
||||
|
||||
argNames = args.argNames
|
||||
capturedNames = fn.capturedValues.keySet ++ fn.capturedArrows.keySet
|
||||
|
||||
/**
|
||||
* Substitute all arguments inside function body.
|
||||
* Data arguments could be passed as variables or values (expressions),
|
||||
@ -497,7 +494,7 @@ object ArrowInliner extends Logging {
|
||||
arrowRenames = args.arrowArgsRenames
|
||||
abRenames = args.abilityArgsRenames
|
||||
|
||||
captured <- renameCaptured(fn, exports, arrows)
|
||||
captured <- renameCaptured(fn)
|
||||
(capturedValues, capturedArrows) = captured
|
||||
|
||||
/**
|
||||
@ -523,11 +520,6 @@ object ArrowInliner extends Logging {
|
||||
renamedCanonStreams ++
|
||||
streamRenames
|
||||
|
||||
/**
|
||||
* TODO: Optimize resolve.
|
||||
* It seems that resolving whole `exports`
|
||||
* and `arrows` is not necessary.
|
||||
*/
|
||||
arrowsResolved = arrows ++ capturedArrows.renamed
|
||||
exportsResolved = exports ++ data.renamed ++ capturedValues.renamed
|
||||
|
||||
|
@ -79,33 +79,48 @@ object TagInliner extends Logging {
|
||||
prefix: Option[OpModel.Tree] = None
|
||||
) extends TagInlined[S](prefix)
|
||||
|
||||
/**
|
||||
* Tag inlining emitted computation
|
||||
* that envelopes children computation
|
||||
*
|
||||
* @param model computation producing model based on children computation
|
||||
*/
|
||||
case Around[S](
|
||||
model: Chain[State[S, OpModel.Tree]] => State[S, OpModel.Tree],
|
||||
prefix: Option[OpModel.Tree] = None
|
||||
) extends TagInlined[S](prefix)
|
||||
|
||||
/**
|
||||
* Finalize inlining, construct a tree
|
||||
*
|
||||
* @param children Children results
|
||||
* @return Result of inlining
|
||||
*/
|
||||
def build(children: Chain[OpModel.Tree]): State[T, OpModel.Tree] = {
|
||||
def toSeqModel(tree: OpModel.Tree | Chain[OpModel.Tree]): State[T, OpModel.Tree] = {
|
||||
val treeChain = tree match {
|
||||
case c: Chain[OpModel.Tree] => c
|
||||
def build(children: Chain[State[T, OpModel.Tree]]): State[T, OpModel.Tree] = {
|
||||
def prefixSeq(sub: OpModel.Tree | Chain[OpModel.Tree]) = {
|
||||
val tree = sub match {
|
||||
case t: OpModel.Tree => Chain.one(t)
|
||||
case c: Chain[OpModel.Tree] => c
|
||||
}
|
||||
|
||||
State.pure(SeqModel.wrap(Chain.fromOption(prefix) ++ treeChain))
|
||||
SeqModel.wrap(Chain.fromOption(prefix) ++ tree)
|
||||
}
|
||||
|
||||
this match {
|
||||
case Empty(_) =>
|
||||
toSeqModel(children)
|
||||
children.sequence.map(prefixSeq)
|
||||
case Single(model, _) =>
|
||||
toSeqModel(model.wrap(children))
|
||||
children.sequence.map(model.wrap).map(prefixSeq)
|
||||
case Mapping(toModel, _) =>
|
||||
toSeqModel(toModel(children))
|
||||
children.sequence.map(toModel).map(prefixSeq)
|
||||
case After(model, _) =>
|
||||
model.flatMap(m => toSeqModel(m.wrap(children)))
|
||||
for {
|
||||
c <- children.sequence
|
||||
m <- model
|
||||
} yield prefixSeq(m.wrap(c))
|
||||
case Around(model, _) =>
|
||||
model(children).map(prefixSeq)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,26 +181,6 @@ object TagInliner extends Logging {
|
||||
}
|
||||
}
|
||||
|
||||
private def flatCanonStream[S: Mangler](
|
||||
canonV: VarModel,
|
||||
op: Option[OpModel.Tree]
|
||||
): State[S, (ValueModel, Option[OpModel.Tree])] = {
|
||||
if (canonV.properties.nonEmpty) {
|
||||
val apName = canonV.name + "_flatten"
|
||||
Mangler[S].findAndForbidName(apName).map { apN =>
|
||||
val apV = VarModel(apN, canonV.`type`)
|
||||
val apOp = FlattenModel(canonV, apN).leaf
|
||||
(
|
||||
apV,
|
||||
combineOpsWithSeq(op, apOp.some)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
State.pure((canonV, op))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a single [[RawTag]] that may lead to many changes, including calling [[ArrowInliner]]
|
||||
*
|
||||
@ -206,40 +201,13 @@ object TagInliner extends Logging {
|
||||
)
|
||||
|
||||
case IfTag(valueRaw) =>
|
||||
IfTagInliner(valueRaw).inlined.map(inlined =>
|
||||
TagInlined.Mapping(
|
||||
toModel = inlined.toModel,
|
||||
prefix = inlined.prefix
|
||||
)
|
||||
)
|
||||
IfTagInliner(valueRaw).inlined
|
||||
|
||||
case TryTag => pure(XorModel)
|
||||
case TryTag =>
|
||||
TryTagInliner.inlined
|
||||
|
||||
case ForTag(item, iterable, mode) =>
|
||||
for {
|
||||
vp <- valueToModel(iterable)
|
||||
flattened <- mode match {
|
||||
case ForTag.Mode.RecMode => State.pure(vp)
|
||||
case _ => flat(vp._1, vp._2)
|
||||
}
|
||||
(v, p) = flattened
|
||||
n <- Mangler[S].findAndForbidName(item)
|
||||
elementType = iterable.`type` match {
|
||||
case b: CollectionType => b.element
|
||||
case _ =>
|
||||
internalError(
|
||||
s"non-box type variable '$iterable' in 'for' expression."
|
||||
)
|
||||
}
|
||||
_ <- Exports[S].resolved(item, VarModel(n, elementType))
|
||||
modeModel = mode match {
|
||||
case ForTag.Mode.SeqMode | ForTag.Mode.TryMode => ForModel.Mode.Null
|
||||
case ForTag.Mode.ParMode | ForTag.Mode.RecMode => ForModel.Mode.Never
|
||||
}
|
||||
} yield TagInlined.Single(
|
||||
model = ForModel(n, v, modeModel),
|
||||
prefix = p
|
||||
)
|
||||
ForTagInliner(item, iterable, mode).inlined
|
||||
|
||||
case PushToStreamTag(operand, exportTo) =>
|
||||
(
|
||||
@ -369,24 +337,13 @@ object TagInliner extends Logging {
|
||||
}
|
||||
} yield model.fold(TagInlined.Empty())(m => TagInlined.Single(model = m))
|
||||
|
||||
case RestrictionTag(name, typ) =>
|
||||
// Rename restriction after children are inlined with new exports
|
||||
TagInlined
|
||||
.After(
|
||||
for {
|
||||
exps <- Exports[S].exports
|
||||
model = exps.get(name).collect { case VarModel(n, _, _) =>
|
||||
RestrictionModel(n, typ)
|
||||
}
|
||||
} yield model.getOrElse(RestrictionModel(name, typ))
|
||||
)
|
||||
.pure
|
||||
|
||||
case DeclareStreamTag(value) =>
|
||||
value match
|
||||
case VarRaw(name, t) =>
|
||||
Exports[S].resolved(name, VarModel(name, t)).as(TagInlined.Empty())
|
||||
case _ => none
|
||||
case VarRaw(name, t: StreamType) =>
|
||||
for {
|
||||
_ <- Exports[S].resolved(name, VarModel(name, t))
|
||||
} yield TagInlined.Empty()
|
||||
case _ => internalError(s"Cannot declare $value as stream, because it is not a stream type")
|
||||
|
||||
case ServiceIdTag(id, serviceType, name) =>
|
||||
for {
|
||||
@ -448,7 +405,7 @@ object TagInliner extends Logging {
|
||||
for {
|
||||
headInlined <- f(cf.head)
|
||||
tail <- StateT.liftF(cf.tail)
|
||||
children <- tail.traverse(traverseS[S](_, f))
|
||||
children = tail.map(traverseS[S](_, f))
|
||||
inlined <- headInlined.build(children)
|
||||
} yield inlined
|
||||
|
||||
|
@ -7,6 +7,7 @@ import aqua.types.*
|
||||
|
||||
import cats.data.State
|
||||
import cats.instances.list.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.option.*
|
||||
import cats.syntax.show.*
|
||||
@ -20,6 +21,7 @@ import cats.syntax.traverse.*
|
||||
*/
|
||||
trait Arrows[S] extends Scoped[S] {
|
||||
self =>
|
||||
|
||||
def save(name: String, arrow: FuncArrow): State[S, Unit]
|
||||
|
||||
/**
|
||||
@ -44,8 +46,7 @@ trait Arrows[S] extends Scoped[S] {
|
||||
/**
|
||||
* Save arrows to the state [[S]]
|
||||
*
|
||||
* @param arrows
|
||||
* Resolved arrows, accessible by key name which could differ from arrow's name
|
||||
* @param arrows Resolved arrows, accessible by key name which could differ from arrow's name
|
||||
*/
|
||||
final def resolved(arrows: Map[String, FuncArrow]): State[S, Unit] =
|
||||
arrows.toList.traverse(save).void
|
||||
@ -53,22 +54,18 @@ trait Arrows[S] extends Scoped[S] {
|
||||
/**
|
||||
* All arrows available for use in scope
|
||||
*/
|
||||
val arrows: State[S, Map[String, FuncArrow]]
|
||||
def arrows: State[S, Map[String, FuncArrow]]
|
||||
|
||||
/**
|
||||
* Pick a subset of arrows by names
|
||||
*
|
||||
* @param names
|
||||
* What arrows should be taken
|
||||
* @param names What arrows should be taken
|
||||
*/
|
||||
def pickArrows(names: Set[String]): State[S, Map[String, FuncArrow]] =
|
||||
arrows.map(_.view.filterKeys(names).toMap)
|
||||
|
||||
/**
|
||||
* Take arrows selected by the function call arguments
|
||||
*
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
def argsArrows(args: ArgsCall): State[S, Map[String, FuncArrow]] =
|
||||
arrows.map(args.arrowArgsMap)
|
||||
@ -76,26 +73,21 @@ trait Arrows[S] extends Scoped[S] {
|
||||
/**
|
||||
* Changes the [[S]] type to [[R]]
|
||||
*
|
||||
* @param f
|
||||
* Lens getter
|
||||
* @param g
|
||||
* Lens setter
|
||||
* @tparam R
|
||||
* New state type
|
||||
* @param f Lens getter
|
||||
* @param g Lens setter
|
||||
*/
|
||||
def transformS[R](f: R => S, g: (R, S) => R): Arrows[R] = new Arrows[R] {
|
||||
|
||||
override def save(name: String, arrow: FuncArrow): State[R, Unit] =
|
||||
self.save(name, arrow).transformS(f, g)
|
||||
|
||||
override val arrows: State[R, Map[String, FuncArrow]] = self.arrows.transformS(f, g)
|
||||
override def arrows: State[R, Map[String, FuncArrow]] = self.arrows.transformS(f, g)
|
||||
|
||||
override val purge: State[R, R] =
|
||||
override protected def purge: State[R, R] =
|
||||
self.purgeR(f, g)
|
||||
|
||||
override protected def fill(s: R): State[R, Unit] =
|
||||
self.fillR(s, f, g)
|
||||
|
||||
override protected def set(r: R): State[R, Unit] =
|
||||
self.setR(f, g)(r)
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +111,7 @@ object Arrows {
|
||||
}
|
||||
}
|
||||
|
||||
def apply[S](implicit arrows: Arrows[S]): Arrows[S] = arrows
|
||||
def apply[S](using arrows: Arrows[S]): Arrows[S] = arrows
|
||||
|
||||
// Default implementation with the most straightforward state – just a Map
|
||||
object Simple extends Arrows[Map[String, FuncArrow]] {
|
||||
@ -127,16 +119,13 @@ object Arrows {
|
||||
override def save(name: String, arrow: FuncArrow): State[Map[String, FuncArrow], Unit] =
|
||||
State.modify(_ + (name -> arrow))
|
||||
|
||||
override val arrows: State[Map[String, FuncArrow], Map[String, FuncArrow]] =
|
||||
override def arrows: State[Map[String, FuncArrow], Map[String, FuncArrow]] =
|
||||
State.get
|
||||
|
||||
override val purge: State[Map[String, FuncArrow], Map[String, FuncArrow]] =
|
||||
for {
|
||||
s <- State.get
|
||||
_ <- State.set(Map.empty)
|
||||
} yield s
|
||||
State.get <* State.set(Map.empty)
|
||||
|
||||
override protected def fill(s: Map[String, FuncArrow]): State[Map[String, FuncArrow], Unit] =
|
||||
override def set(s: Map[String, FuncArrow]): State[Map[String, FuncArrow], Unit] =
|
||||
State.set(s)
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package aqua.model.inline.state
|
||||
|
||||
import aqua.model.ValueModel.Ability
|
||||
import aqua.model.ValueModel.{Ability, Stream}
|
||||
import aqua.model.{LiteralModel, ValueModel, VarModel}
|
||||
import aqua.types.StreamType
|
||||
import aqua.types.{AbilityType, GeneralAbilityType, NamedType}
|
||||
|
||||
import cats.data.{NonEmptyList, State}
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.traverse.*
|
||||
|
||||
/**
|
||||
* Exports – trace values available in the scope
|
||||
@ -49,11 +52,6 @@ trait Exports[S] extends Scoped[S] {
|
||||
*/
|
||||
def getLastVarName(name: String): State[S, Option[String]]
|
||||
|
||||
/**
|
||||
* Rename names in variables
|
||||
*/
|
||||
def renameVariables(renames: Map[String, String]): State[S, Unit]
|
||||
|
||||
/**
|
||||
* Resolve the whole map of exports
|
||||
* @param exports
|
||||
@ -76,7 +74,20 @@ trait Exports[S] extends Scoped[S] {
|
||||
/**
|
||||
* Get all the values available in the scope
|
||||
*/
|
||||
val exports: State[S, Map[String, ValueModel]]
|
||||
def exports: State[S, Map[String, ValueModel]]
|
||||
|
||||
def deleteStreams(names: Set[String]): State[S, Unit]
|
||||
|
||||
def streams: State[S, Map[String, StreamType]]
|
||||
|
||||
def streamScope[T](inside: State[S, T]): State[S, (T, Map[String, StreamType])] =
|
||||
for {
|
||||
streamsBefore <- streams
|
||||
tree <- inside
|
||||
streamsAfter <- streams
|
||||
streams = streamsAfter.removedAll(streamsBefore.keySet)
|
||||
_ <- deleteStreams(streams.keySet)
|
||||
} yield (tree, streams)
|
||||
|
||||
final def gather(names: Seq[String]): State[S, Map[String, ValueModel]] =
|
||||
exports.map(Exports.gatherFrom(names, _))
|
||||
@ -92,6 +103,12 @@ trait Exports[S] extends Scoped[S] {
|
||||
override def resolved(exports: Map[String, ValueModel]): State[R, Unit] =
|
||||
self.resolved(exports).transformS(f, g)
|
||||
|
||||
override def streams: State[R, Map[String, StreamType]] =
|
||||
self.streams.transformS(f, g)
|
||||
|
||||
override def deleteStreams(names: Set[String]): State[R, Unit] =
|
||||
self.deleteStreams(names).transformS(f, g)
|
||||
|
||||
override def resolveAbilityField(
|
||||
abilityExportName: String,
|
||||
fieldName: String,
|
||||
@ -105,23 +122,20 @@ trait Exports[S] extends Scoped[S] {
|
||||
override def getLastVarName(name: String): State[R, Option[String]] =
|
||||
self.getLastVarName(name).transformS(f, g)
|
||||
|
||||
override def renameVariables(renames: Map[String, String]): State[R, Unit] =
|
||||
self.renameVariables(renames).transformS(f, g)
|
||||
|
||||
override def getKeys: State[R, Set[String]] =
|
||||
self.getKeys.transformS(f, g)
|
||||
|
||||
override def getAbilityField(name: String, field: String): State[R, Option[ValueModel]] =
|
||||
self.getAbilityField(name, field).transformS(f, g)
|
||||
|
||||
override val exports: State[R, Map[String, ValueModel]] =
|
||||
override def exports: State[R, Map[String, ValueModel]] =
|
||||
self.exports.transformS(f, g)
|
||||
|
||||
override val purge: State[R, R] =
|
||||
override protected def purge: State[R, R] =
|
||||
self.purgeR(f, g)
|
||||
|
||||
override protected def fill(s: R): State[R, Unit] =
|
||||
self.fillR(s, f, g)
|
||||
override protected def set(r: R): State[R, Unit] =
|
||||
self.setR(f, g)(r)
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +180,16 @@ object Exports {
|
||||
}
|
||||
}
|
||||
|
||||
object Simple extends Exports[Map[String, ValueModel]] {
|
||||
/**
|
||||
* @param values list of all values in scope.
|
||||
* @param streams list of opened streams. Merged between states.
|
||||
*/
|
||||
case class ExportsState(
|
||||
values: Map[String, ValueModel] = Map.empty,
|
||||
streams: Map[String, StreamType] = Map.empty
|
||||
)
|
||||
|
||||
object Simple extends Exports[ExportsState] {
|
||||
|
||||
// Make links from one set of abilities to another (for ability assignment)
|
||||
private def getAbilityPairs(
|
||||
@ -192,69 +215,80 @@ object Exports {
|
||||
override def resolved(
|
||||
exportName: String,
|
||||
value: ValueModel
|
||||
): State[Map[String, ValueModel], Unit] = State.modify { state =>
|
||||
): State[ExportsState, Unit] = State.modify { state =>
|
||||
value match {
|
||||
case Ability(vm, at) if vm.properties.isEmpty =>
|
||||
val pairs = getAbilityPairs(vm.name, exportName, at, state)
|
||||
state ++ pairs.toList.toMap + (exportName -> value)
|
||||
case _ => state + (exportName -> value)
|
||||
val pairs = getAbilityPairs(vm.name, exportName, at, state.values)
|
||||
state.copy(values = state.values ++ pairs.toList.toMap + (exportName -> value))
|
||||
case Stream(VarModel(streamName, _, _), st) if exportName == streamName =>
|
||||
state.copy(
|
||||
values = state.values + (exportName -> value),
|
||||
streams = state.streams + (exportName -> st)
|
||||
)
|
||||
case _ => state.copy(values = state.values + (exportName -> value))
|
||||
}
|
||||
}
|
||||
|
||||
override def getLastVarName(name: String): State[Map[String, ValueModel], Option[String]] =
|
||||
State.get.map(st => getLastValue(name, st).collect { case VarModel(name, _, _) => name })
|
||||
override def getLastVarName(name: String): State[ExportsState, Option[String]] =
|
||||
State.get.map(st =>
|
||||
getLastValue(name, st.values).collect { case VarModel(name, _, _) => name }
|
||||
)
|
||||
|
||||
override def resolved(exports: Map[String, ValueModel]): State[Map[String, ValueModel], Unit] =
|
||||
State.modify(_ ++ exports)
|
||||
override def resolved(exports: Map[String, ValueModel]): State[ExportsState, Unit] =
|
||||
State.modify(st => st.copy(values = st.values ++ exports))
|
||||
|
||||
override def streams: State[ExportsState, Map[String, StreamType]] =
|
||||
State.get.map(_.streams)
|
||||
|
||||
override def deleteStreams(names: Set[String]): State[ExportsState, Unit] =
|
||||
State.modify(st => st.copy(streams = st.streams -- names))
|
||||
|
||||
override def resolveAbilityField(
|
||||
abilityExportName: String,
|
||||
fieldName: String,
|
||||
value: ValueModel
|
||||
): State[Map[String, ValueModel], Unit] =
|
||||
State.modify(_ + (AbilityType.fullName(abilityExportName, fieldName) -> value))
|
||||
): State[ExportsState, Unit] =
|
||||
State.modify(st =>
|
||||
st.copy(values = st.values + (AbilityType.fullName(abilityExportName, fieldName) -> value))
|
||||
)
|
||||
|
||||
override def copyWithAbilityPrefix(
|
||||
prefix: String,
|
||||
newPrefix: String
|
||||
): State[Map[String, ValueModel], Unit] =
|
||||
): State[ExportsState, Unit] =
|
||||
State.modify { state =>
|
||||
state.flatMap {
|
||||
val newValues = state.values.flatMap {
|
||||
case (k, v) if k.startsWith(prefix) =>
|
||||
List(k.replaceFirst(prefix, newPrefix) -> v, k -> v)
|
||||
case (k, v) => List(k -> v)
|
||||
}
|
||||
state.copy(values = newValues)
|
||||
}
|
||||
|
||||
override def renameVariables(
|
||||
renames: Map[String, String]
|
||||
): State[Map[String, ValueModel], Unit] =
|
||||
State.modify {
|
||||
_.map {
|
||||
case (k, vm @ VarModel(name, _, _)) if renames.contains(name) =>
|
||||
k -> vm.copy(name = renames.getOrElse(name, name))
|
||||
case (k, v) => k -> v
|
||||
}
|
||||
}
|
||||
|
||||
override def getKeys: State[Map[String, ValueModel], Set[String]] = State.get.map(_.keySet)
|
||||
override def getKeys: State[ExportsState, Set[String]] = State.get.map(_.values.keySet)
|
||||
|
||||
override def getAbilityField(
|
||||
name: String,
|
||||
field: String
|
||||
): State[Map[String, ValueModel], Option[ValueModel]] =
|
||||
State.get.map(_.get(AbilityType.fullName(name, field)))
|
||||
): State[ExportsState, Option[ValueModel]] =
|
||||
State.get.map(_.values.get(AbilityType.fullName(name, field)))
|
||||
|
||||
override val exports: State[Map[String, ValueModel], Map[String, ValueModel]] =
|
||||
State.get
|
||||
override val exports: State[ExportsState, Map[String, ValueModel]] =
|
||||
State.get.map(_.values)
|
||||
|
||||
override val purge: State[Map[String, ValueModel], Map[String, ValueModel]] =
|
||||
override val purge: State[ExportsState, ExportsState] =
|
||||
for {
|
||||
s <- State.get
|
||||
_ <- State.set(Map.empty)
|
||||
} yield s
|
||||
st <- State.get
|
||||
// HACK: refactor
|
||||
_ <- State.modify[ExportsState](st => ExportsState(streams = st.streams))
|
||||
} yield st
|
||||
|
||||
override protected def fill(s: Map[String, ValueModel]): State[Map[String, ValueModel], Unit] =
|
||||
State.set(s)
|
||||
override def set(s: ExportsState): State[ExportsState, Unit] = {
|
||||
for {
|
||||
st <- State.get
|
||||
// HACK: refactor
|
||||
_ <- State.set(s.copy(streams = st.streams ++ s.streams))
|
||||
} yield {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.model.inline.state
|
||||
|
||||
import aqua.mangler.ManglerState
|
||||
import aqua.model.inline.state.Exports.ExportsState
|
||||
import aqua.model.inline.state.{Arrows, Counter, Exports, Mangler}
|
||||
import aqua.model.{FuncArrow, ValueModel}
|
||||
import aqua.raw.arrow.FuncRaw
|
||||
@ -26,7 +27,7 @@ import scribe.Logging
|
||||
*/
|
||||
case class InliningState(
|
||||
noNames: ManglerState = ManglerState(),
|
||||
resolvedExports: Map[String, ValueModel] = Map.empty,
|
||||
resolvedExports: ExportsState = ExportsState(),
|
||||
resolvedArrows: Map[String, FuncArrow] = Map.empty,
|
||||
instructionCounter: Int = 0,
|
||||
config: Config.Values = Config.Values.default
|
||||
|
@ -1,39 +1,39 @@
|
||||
package aqua.model.inline.state
|
||||
|
||||
import cats.data.State
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.functor.*
|
||||
|
||||
/**
|
||||
* Common transformations to make an isolated scope for the state [[S]]
|
||||
* @tparam S State
|
||||
*/
|
||||
trait Scoped[S] {
|
||||
// Remove everything from the state
|
||||
val purge: State[S, S]
|
||||
|
||||
// Put [[s]] to the state
|
||||
protected def fill(s: S): State[S, Unit]
|
||||
|
||||
/**
|
||||
* Clear the state, run [[scoped]], then recover the initial state
|
||||
* @param scoped What to run with empty [[S]]
|
||||
* @tparam T Return type
|
||||
* @return Value returned by [[scoped]]
|
||||
*/
|
||||
def scope[T](scoped: State[S, T]): State[S, T] =
|
||||
for {
|
||||
r <- purge
|
||||
t <- scoped
|
||||
_ <- fill(r)
|
||||
_ <- set(r)
|
||||
} yield t
|
||||
|
||||
// For transformS
|
||||
protected def purgeR[R](f: R => S, g: (R, S) => R): State[R, R] =
|
||||
for {
|
||||
r <- State.get[R]
|
||||
s <- purge.transformS(f, g)
|
||||
} yield g(r, s)
|
||||
protected def purge: State[S, S]
|
||||
|
||||
protected def set(s: S): State[S, Unit]
|
||||
|
||||
protected final def purgeR[R](f: R => S, g: (R, S) => R): State[R, R] =
|
||||
(State.get[R], purge.transformS(f, g)).mapN(g)
|
||||
|
||||
protected final def setR[R](f: R => S, g: (R, S) => R)(r: R): State[R, Unit] =
|
||||
set(f(r)).transformS(f, g)
|
||||
|
||||
private final def get: State[S, S] = for {
|
||||
s <- purge
|
||||
_ <- set(s)
|
||||
} yield s
|
||||
|
||||
// For transformS
|
||||
protected def fillR[R](s: R, f: R => S, g: (R, S) => R): State[R, Unit] =
|
||||
fill(f(s)).transformS(f, g)
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package aqua.model.inline.tag
|
||||
|
||||
import aqua.errors.Errors.internalError
|
||||
import aqua.helpers.syntax.reader.*
|
||||
import aqua.model.*
|
||||
import aqua.model.ValueModel
|
||||
import aqua.model.inline.Inline.parDesugarPrefixOpt
|
||||
import aqua.model.inline.RawValueInliner.valueToModel
|
||||
import aqua.model.inline.TagInliner.TagInlined
|
||||
import aqua.model.inline.TagInliner.flat
|
||||
import aqua.model.inline.state.*
|
||||
import aqua.raw.ops.ForTag
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.types.CollectionType
|
||||
import aqua.types.StreamType
|
||||
|
||||
import cats.Eval
|
||||
import cats.data.Reader
|
||||
import cats.data.{Chain, State}
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
|
||||
final case class ForTagInliner(
|
||||
item: String,
|
||||
iterable: ValueRaw,
|
||||
mode: ForTag.Mode
|
||||
) {
|
||||
|
||||
def inlined[S: Mangler: Exports: Arrows: Config]: State[S, TagInlined[S]] = for {
|
||||
vp <- valueToModel(iterable)
|
||||
flattened <- mode match {
|
||||
case ForTag.Mode.RecMode => State.pure(vp)
|
||||
case _ => flat.tupled(vp)
|
||||
}
|
||||
(v, p) = flattened
|
||||
n <- Mangler[S].findAndForbidName(item)
|
||||
elementType = iterable.`type` match {
|
||||
case b: CollectionType => b.element
|
||||
case _ =>
|
||||
internalError(
|
||||
s"non-box type variable '$iterable' in 'for' expression."
|
||||
)
|
||||
}
|
||||
_ <- Exports[S].resolved(item, VarModel(n, elementType))
|
||||
modeModel = mode match {
|
||||
case ForTag.Mode.SeqMode | ForTag.Mode.TryMode => ForModel.Mode.Null
|
||||
case ForTag.Mode.ParMode | ForTag.Mode.RecMode => ForModel.Mode.Never
|
||||
}
|
||||
model = ForModel(n, v, modeModel)
|
||||
} yield TagInlined.Around(
|
||||
model = StreamRestrictions.restrictStreams(model.wrap),
|
||||
prefix = p
|
||||
)
|
||||
}
|
@ -5,13 +5,13 @@ import aqua.model.*
|
||||
import aqua.model.ValueModel
|
||||
import aqua.model.inline.Inline.parDesugarPrefixOpt
|
||||
import aqua.model.inline.RawValueInliner.valueToModel
|
||||
import aqua.model.inline.TagInliner.canonicalizeIfStream
|
||||
import aqua.model.inline.TagInliner.{TagInlined, canonicalizeIfStream}
|
||||
import aqua.model.inline.state.*
|
||||
import aqua.raw.value.ApplyBinaryOpRaw.Op as BinOp
|
||||
import aqua.raw.value.{ApplyBinaryOpRaw, ValueRaw}
|
||||
import aqua.types.StreamType
|
||||
|
||||
import cats.Eval
|
||||
import cats.data.Reader
|
||||
import cats.data.{Chain, State}
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
@ -21,8 +21,8 @@ final case class IfTagInliner(
|
||||
) {
|
||||
import IfTagInliner.*
|
||||
|
||||
def inlined[S: Mangler: Exports: Arrows: Config]: State[S, IfTagInlined] = for {
|
||||
cond <- (valueRaw match {
|
||||
def inlined[S: Mangler: Exports: Arrows: Config]: State[S, TagInlined[S]] = for {
|
||||
cond <- valueRaw match {
|
||||
// Optimize in case last operation is equality check
|
||||
case ApplyBinaryOpRaw(op @ (BinOp.Eq | BinOp.Neq), left, right, _) =>
|
||||
(
|
||||
@ -44,13 +44,15 @@ final case class IfTagInliner(
|
||||
|
||||
(prefix, valueModel, compareModel, shouldMatch)
|
||||
}
|
||||
})
|
||||
}
|
||||
(prefix, leftValue, rightValue, shouldMatch) = cond
|
||||
noProp <- Config[S].noErrorPropagation.toState
|
||||
model = if (noProp) toModelNoProp else toModel
|
||||
} yield IfTagInlined(
|
||||
prefix,
|
||||
model(leftValue, rightValue, shouldMatch)
|
||||
modelByChildren = model(leftValue, rightValue, shouldMatch)
|
||||
stateModel = StreamRestrictions.restrictStreams[S](modelByChildren)
|
||||
} yield TagInlined.Around(
|
||||
prefix = prefix,
|
||||
model = stateModel
|
||||
)
|
||||
|
||||
private def toModelNoProp(
|
||||
@ -185,11 +187,6 @@ final case class IfTagInliner(
|
||||
|
||||
object IfTagInliner {
|
||||
|
||||
final case class IfTagInlined(
|
||||
prefix: Option[OpModel.Tree],
|
||||
toModel: Chain[OpModel.Tree] => OpModel.Tree
|
||||
)
|
||||
|
||||
private def restrictErrors(
|
||||
name: String*
|
||||
)(tree: OpModel.Tree): OpModel.Tree =
|
||||
|
@ -0,0 +1,29 @@
|
||||
package aqua.model.inline.tag
|
||||
|
||||
import aqua.model.inline.state.{Arrows, Config, Exports, Mangler}
|
||||
import aqua.model.{OpModel, RestrictionModel}
|
||||
import aqua.types.StreamType
|
||||
|
||||
import cats.data.{Chain, State}
|
||||
import cats.syntax.traverse.*
|
||||
|
||||
object StreamRestrictions {
|
||||
|
||||
// restrict streams that are generated in a tree
|
||||
def restrictStreams[S: Mangler: Exports: Arrows: Config](
|
||||
childrenToModel: Chain[OpModel.Tree] => OpModel.Tree
|
||||
)(children: Chain[State[S, OpModel.Tree]]): State[S, OpModel.Tree] =
|
||||
children.traverse(restrictStreamsAround).map(childrenToModel)
|
||||
|
||||
/**
|
||||
* Restrict streams that are generated in a tree
|
||||
*/
|
||||
private def restrictStreamsAround[S: Mangler: Exports: Arrows: Config](
|
||||
getTree: State[S, OpModel.Tree]
|
||||
): State[S, OpModel.Tree] =
|
||||
Exports[S].streamScope(getTree).map { case (tree, streams) =>
|
||||
streams.toList.foldLeft(tree) { case (acc, (name, st)) =>
|
||||
RestrictionModel(name, st).wrap(acc)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package aqua.model.inline.tag
|
||||
|
||||
import aqua.model.inline.state.{Arrows, Config, Exports, Mangler}
|
||||
import aqua.model.inline.TagInliner.TagInlined
|
||||
import aqua.model.XorModel
|
||||
import cats.data.State
|
||||
|
||||
object TryTagInliner {
|
||||
def inlined[S: Mangler: Exports: Arrows: Config]: State[S, TagInlined[S]] =
|
||||
State.pure(TagInlined.Around(model = StreamRestrictions.restrictStreams(XorModel.wrap)))
|
||||
}
|
@ -134,11 +134,9 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
.callArrow[InliningState](
|
||||
FuncArrow(
|
||||
"stream-callback",
|
||||
RestrictionTag(streamVar.name, streamType).wrap(
|
||||
SeqTag.wrap(
|
||||
DeclareStreamTag(streamVar).leaf,
|
||||
CallArrowRawTag.func("cb", Call(streamVar :: Nil, Nil)).leaf
|
||||
)
|
||||
),
|
||||
ArrowType(
|
||||
ProductType.labelled(
|
||||
@ -166,7 +164,6 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
.value
|
||||
|
||||
model.equalsOrShowDiff(
|
||||
RestrictionModel(streamVar.name, streamType).wrap(
|
||||
MetaModel
|
||||
.CallArrowModel("cb")
|
||||
.wrap(
|
||||
@ -182,7 +179,6 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
).leaf
|
||||
)
|
||||
)
|
||||
)
|
||||
) should be(true)
|
||||
|
||||
}
|
||||
@ -283,7 +279,8 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
* stream <<- "asd"
|
||||
* <- stream
|
||||
*/
|
||||
it should "rename restricted stream correctly" in {
|
||||
// IGNORED: streams are not restricted in function bodies for now
|
||||
it should "rename restricted stream correctly" ignore {
|
||||
val streamType = StreamType(ScalarType.string)
|
||||
val someStr = VarRaw("someStr", streamType)
|
||||
|
||||
@ -319,7 +316,6 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
|
||||
val newFunc = FuncArrow(
|
||||
"newFunc",
|
||||
RestrictionTag(streamVar.name, streamType).wrap(
|
||||
SeqTag.wrap(
|
||||
CallArrowRawTag
|
||||
.func(
|
||||
@ -342,7 +338,6 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
ReturnTag(
|
||||
NonEmptyList.one(flatStreamVar)
|
||||
).leaf
|
||||
)
|
||||
),
|
||||
ArrowType(
|
||||
ProductType(Nil),
|
||||
@ -440,7 +435,6 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
|
||||
val testReturnStream = FuncArrow(
|
||||
"testReturnStream",
|
||||
RestrictionTag(streamVar.name, streamType).wrap(
|
||||
SeqTag.wrap(
|
||||
CallArrowRawTag
|
||||
.func(
|
||||
@ -463,7 +457,6 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
ReturnTag(
|
||||
NonEmptyList.one(flatStreamVar)
|
||||
).leaf
|
||||
)
|
||||
),
|
||||
ArrowType(
|
||||
ProductType(Nil),
|
||||
@ -883,11 +876,9 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
.callArrow[InliningState](
|
||||
FuncArrow(
|
||||
"stream-callback",
|
||||
RestrictionTag(streamVar.name, streamType).wrap(
|
||||
SeqTag.wrap(
|
||||
DeclareStreamTag(streamVar).leaf,
|
||||
CallArrowRawTag.func("cb", Call(streamVarLambda :: Nil, Nil)).leaf
|
||||
)
|
||||
),
|
||||
ArrowType(
|
||||
ProductType.labelled(
|
||||
@ -1399,7 +1390,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
.one(
|
||||
outterRes
|
||||
)
|
||||
).leaf: _*
|
||||
).leaf*
|
||||
)
|
||||
|
||||
val outer = FuncArrow(
|
||||
|
@ -3,6 +3,7 @@ package aqua.model.inline
|
||||
import aqua.mangler.ManglerState
|
||||
import aqua.model.*
|
||||
import aqua.model.inline.raw.StreamGateInliner
|
||||
import aqua.model.inline.state.Exports.ExportsState
|
||||
import aqua.model.inline.state.InliningState
|
||||
import aqua.raw.value.*
|
||||
import aqua.types.*
|
||||
@ -204,7 +205,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
valueToModel[InliningState](`raw res.c`)
|
||||
.runA(
|
||||
InliningState(resolvedExports =
|
||||
Map("res" -> VarModel("a", aType, Chain.one(IntoFieldModel("b", bType))))
|
||||
ExportsState(Map("res" -> VarModel("a", aType, Chain.one(IntoFieldModel("b", bType)))))
|
||||
)
|
||||
)
|
||||
.value shouldBe (
|
||||
@ -608,7 +609,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
expr <- genAllExprs(perm)
|
||||
} {
|
||||
val state = InliningState(
|
||||
resolvedExports = vars.map(v => v.name -> VarModel.fromVarRaw(v)).toMap
|
||||
resolvedExports = ExportsState(vars.map(v => v.name -> VarModel.fromVarRaw(v)).toMap)
|
||||
)
|
||||
val (model, inline) = valueToModel[InliningState](expr).runA(state).value
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
package aqua.model.inline
|
||||
|
||||
import aqua.model.ForModel
|
||||
import aqua.model.ValueModel
|
||||
import aqua.model.*
|
||||
import aqua.model.inline.TagInliner.TagInlined
|
||||
import aqua.model.inline.state.Exports.ExportsState
|
||||
import aqua.model.inline.state.InliningState
|
||||
import aqua.model.{LiteralModel, OpModel, SeqModel}
|
||||
import aqua.raw.ops.ForTag
|
||||
import aqua.raw.ops.{Call, CanonicalizeTag, FlattenTag}
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.raw.value.VarRaw
|
||||
import aqua.raw.ops.{Call, CanonicalizeTag, FlattenTag, ForTag}
|
||||
import aqua.raw.value.{ValueRaw, VarRaw}
|
||||
import aqua.types.{ScalarType, StreamType}
|
||||
|
||||
import cats.data.{Chain, State}
|
||||
import cats.syntax.show.*
|
||||
import org.scalatest.Inside
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
@ -28,7 +26,7 @@ class TagInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
.run(InliningState())
|
||||
.value
|
||||
|
||||
state.resolvedExports(canonTo) shouldBe LiteralModel(
|
||||
state.resolvedExports.values(canonTo) shouldBe LiteralModel(
|
||||
ValueRaw.Nil.value,
|
||||
ValueRaw.Nil.baseType
|
||||
)
|
||||
@ -48,7 +46,7 @@ class TagInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
.run(InliningState())
|
||||
.value
|
||||
|
||||
state.resolvedExports(canonTo) shouldBe LiteralModel(
|
||||
state.resolvedExports.values(canonTo) shouldBe LiteralModel(
|
||||
ValueRaw.Nil.value,
|
||||
ValueRaw.Nil.baseType
|
||||
)
|
||||
@ -68,15 +66,20 @@ class TagInlinerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
.tagToModel[InliningState](tag)
|
||||
.run(
|
||||
InliningState(
|
||||
resolvedExports = Map(
|
||||
resolvedExports = ExportsState(
|
||||
Map(
|
||||
iterableRaw.name -> iterableModel
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.value
|
||||
|
||||
inside(inlined) { case TagInlined.Single(ForModel(_, iter, ForModel.Mode.Never), _) =>
|
||||
inside(inlined) { case TagInlined.Around(st, _) =>
|
||||
inside(st(Chain.empty).runA(state).value.head) {
|
||||
case ForModel(_, iter, ForModel.Mode.Never) =>
|
||||
iter shouldBe iterableModel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,9 @@ case class FuncRaw(
|
||||
|
||||
override def rawPartType: Type = arrow.`type`
|
||||
|
||||
// vars that we capture from external space (outer functions, etc)
|
||||
lazy val capturedVars: Set[String] = {
|
||||
val freeBodyVars = arrow.body.usesVarNames.value
|
||||
val freeBodyVars: Set[String] = arrow.body.usesVarNames.value
|
||||
val argsNames = arrow.`type`.domain
|
||||
.toLabelledList()
|
||||
.map { case (name, _) => name }
|
||||
|
@ -4,6 +4,7 @@ import aqua.raw.arrow.FuncRaw
|
||||
import aqua.raw.value.{CallArrowRaw, CallServiceRaw, ValueRaw, VarRaw}
|
||||
import aqua.tree.{TreeNode, TreeNodeCompanion}
|
||||
import aqua.types.*
|
||||
|
||||
import cats.Show
|
||||
import cats.data.{Chain, NonEmptyList}
|
||||
import cats.free.Cofree
|
||||
@ -158,14 +159,6 @@ case class NextTag(item: String) extends RawTag {
|
||||
override def mapValues(f: ValueRaw => ValueRaw): RawTag = this
|
||||
}
|
||||
|
||||
case class RestrictionTag(name: String, `type`: Type) extends SeqGroupTag {
|
||||
|
||||
override def restrictsVarNames: Set[String] = Set(name)
|
||||
|
||||
override def renameExports(map: Map[String, String]): RawTag =
|
||||
copy(name = map.getOrElse(name, name))
|
||||
}
|
||||
|
||||
case class ForTag(item: String, iterable: ValueRaw, mode: ForTag.Mode) extends SeqGroupTag {
|
||||
|
||||
override def restrictsVarNames: Set[String] = Set(item)
|
||||
|
@ -1,11 +1,10 @@
|
||||
package aqua.raw.ops
|
||||
|
||||
import aqua.raw.value.{LiteralRaw, ValueRaw}
|
||||
|
||||
import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw}
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
import cats.syntax.all.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.foldable.*
|
||||
import cats.syntax.semigroup.*
|
||||
import cats.{Eval, Semigroup}
|
||||
@ -46,11 +45,7 @@ trait RawTagGivens {
|
||||
Eval.later(acc.foldLeft(tag.definesVarNames)(_ ++ _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variable names used by this tree
|
||||
* but not exported in it (free variables).
|
||||
*/
|
||||
def usesVarNames: Eval[Set[String]] =
|
||||
def exportedAndUsesNames: Eval[(Set[String], Set[String])] =
|
||||
Cofree
|
||||
.cata(tree)((tag, childs: Chain[(Set[String], Set[String])]) =>
|
||||
Eval.later {
|
||||
@ -60,8 +55,19 @@ trait RawTagGivens {
|
||||
(exports, uses)
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Get all variable names used by this tree
|
||||
* but not exported in it (free variables).
|
||||
*/
|
||||
def usesVarNames: Eval[Set[String]] =
|
||||
exportedAndUsesNames
|
||||
.map { case (_, uses) => uses }
|
||||
|
||||
def exportsVarNames: Eval[Set[String]] =
|
||||
exportedAndUsesNames
|
||||
.map { case (exports, _) => exports }
|
||||
|
||||
private def collect[A](pf: PartialFunction[RawTag, A]): Eval[Chain[A]] =
|
||||
Cofree.cata(tree)((tag, acc: Chain[Chain[A]]) =>
|
||||
Eval.later(Chain.fromOption(pf.lift(tag)) ++ acc.flatten)
|
||||
|
@ -172,13 +172,6 @@ object ForModel {
|
||||
ForModel(item, iterable, Mode.Null)
|
||||
}
|
||||
|
||||
// TODO how is it used? remove, if it's not
|
||||
case class DeclareStreamModel(value: ValueModel) extends NoExecModel {
|
||||
override def toString: String = s"declare $value"
|
||||
|
||||
override def usesVarNames: Set[String] = value.usesVarNames
|
||||
}
|
||||
|
||||
// key must be only string or number
|
||||
case class InsertKeyValueModel(
|
||||
key: ValueModel,
|
||||
|
@ -1,24 +1,24 @@
|
||||
package aqua.model.transform.topology
|
||||
|
||||
import aqua.model.transform.ModelBuilder
|
||||
import aqua.model.*
|
||||
import aqua.res.*
|
||||
import aqua.raw.ops.Call
|
||||
import aqua.raw.value.{IntoIndexRaw, LiteralRaw, VarRaw}
|
||||
import aqua.types.{LiteralType, ScalarType, StreamType}
|
||||
import aqua.types.ArrayType
|
||||
import aqua.raw.ConstantRaw.initPeerId
|
||||
import aqua.model.ForModel
|
||||
import aqua.model.transform.ModelBuilder
|
||||
import aqua.raw.ConstantRaw.initPeerId
|
||||
import aqua.raw.ops.Call
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.raw.value.{IntoIndexRaw, LiteralRaw, VarRaw}
|
||||
import aqua.res.*
|
||||
import aqua.types.ArrayType
|
||||
import aqua.types.{LiteralType, ScalarType, StreamType}
|
||||
|
||||
import cats.Eval
|
||||
import cats.data.{Chain, NonEmptyList}
|
||||
import cats.data.Chain.*
|
||||
import cats.data.{Chain, NonEmptyList}
|
||||
import cats.free.Cofree
|
||||
import cats.syntax.option.*
|
||||
import cats.syntax.show.*
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import cats.syntax.show.*
|
||||
import cats.syntax.option.*
|
||||
|
||||
class TopologySpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
@ -481,7 +481,7 @@ class TopologySpec extends AnyFlatSpec with Matchers {
|
||||
val streamRawEl = VarRaw("stream", StreamType(ScalarType.string)).withProperty(
|
||||
IntoIndexRaw(LiteralRaw("2", ScalarType.u32), ScalarType.string)
|
||||
)
|
||||
val stream = ValueModel.fromRaw(streamRaw)
|
||||
val stream = VarModel(streamRaw.name, streamRaw.baseType)
|
||||
val streamEl = ValueModel.fromRaw(streamRawEl)
|
||||
|
||||
val (joinModel, joinRes) = joinModelRes(streamEl)
|
||||
@ -499,7 +499,6 @@ class TopologySpec extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
)
|
||||
val init = SeqModel.wrap(
|
||||
DeclareStreamModel(stream).leaf,
|
||||
OnModel(initPeer, Chain.one(relay)).wrap(
|
||||
foldModel +:
|
||||
joinModel :+
|
||||
@ -534,10 +533,7 @@ class TopologySpec extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
)
|
||||
val expected = SeqRes.wrap(
|
||||
Chain(
|
||||
through(relay),
|
||||
foldRes
|
||||
) ++
|
||||
foldRes +:
|
||||
joinRes :+
|
||||
callRes(3, initPeer, None, stream :: Nil)
|
||||
)
|
||||
@ -552,13 +548,12 @@ class TopologySpec extends AnyFlatSpec with Matchers {
|
||||
val streamRawEl = VarRaw("stream", StreamType(ScalarType.string)).withProperty(
|
||||
IntoIndexRaw(LiteralRaw("2", ScalarType.u32), ScalarType.string)
|
||||
)
|
||||
val stream = ValueModel.fromRaw(streamRaw)
|
||||
val stream = VarModel(streamRaw.name, streamRaw.baseType)
|
||||
val streamEl = ValueModel.fromRaw(streamRawEl)
|
||||
|
||||
val (joinModel, joinRes) = joinModelRes(streamEl)
|
||||
|
||||
val init = SeqModel.wrap(
|
||||
DeclareStreamModel(stream).leaf,
|
||||
OnModel(initPeer, Chain.one(relay)).wrap(
|
||||
foldPar(
|
||||
"i",
|
||||
@ -608,10 +603,7 @@ class TopologySpec extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
)
|
||||
val expected = SeqRes.wrap(
|
||||
Chain(
|
||||
through(relay),
|
||||
fold
|
||||
) ++
|
||||
fold +:
|
||||
joinRes :+
|
||||
callRes(3, initPeer, None, stream :: Nil)
|
||||
)
|
||||
|
@ -55,26 +55,12 @@ class ArrowSem[S[_]](val expr: ArrowExpr[S]) extends AnyVal {
|
||||
N: NamesAlgebra[S, Alg],
|
||||
M: ManglerAlgebra[Alg]
|
||||
): Alg[Raw] = for {
|
||||
streamsInScope <- N.streamsDefinedWithinScope()
|
||||
retValues <- T.endArrowScope(expr.arrowTypeExpr)
|
||||
// TODO: wrap with local on...via...
|
||||
retsAndCodomain = retValues zip funcArrow.codomain.toList
|
||||
(streamThatReturnAsStreamVars, streamThatReturnAsStreamNames) = retsAndCodomain.collect {
|
||||
case (vr @ VarRaw(name, StreamType(_)), StreamType(_)) => (vr, name)
|
||||
case (vr @ StreamRaw(_, name, _), StreamType(_)) => (vr, name)
|
||||
}.unzip
|
||||
// streams that return as streams and derived to another variable
|
||||
derivedStreamRetValues <- N
|
||||
.getDerivedFrom(streamThatReturnAsStreamVars.map(_.varNames))
|
||||
.map(_.flatten.toSet)
|
||||
|
||||
res <- bodyGen match {
|
||||
case FuncOp(bodyModel) =>
|
||||
val streamArgNames = funcArrow.domain.labelledStreams.map { case (name, _) => name }
|
||||
|
||||
// Remove arguments, and values returned as streams
|
||||
val localStreams = streamsInScope -- streamArgNames --
|
||||
streamThatReturnAsStreamNames.toSet -- derivedStreamRetValues
|
||||
|
||||
// process stream that returns as not streams and all Apply*Raw
|
||||
retsAndCodomain.traverse {
|
||||
@ -124,13 +110,7 @@ class ArrowSem[S[_]](val expr: ArrowExpr[S]) extends AnyVal {
|
||||
val bodyModified = SeqTag.wrap(
|
||||
bodyModel +: bodyRets
|
||||
)
|
||||
|
||||
// wrap streams with restrictions
|
||||
val bodyWithRestrictions =
|
||||
localStreams.foldLeft(bodyModified) { case (bm, (streamName, streamType)) =>
|
||||
RestrictionTag(streamName, streamType).wrap(bm)
|
||||
}
|
||||
ArrowRaw(funcArrow, retVals, bodyWithRestrictions)
|
||||
ArrowRaw(funcArrow, retVals, bodyModified)
|
||||
}
|
||||
|
||||
case _ => Raw.error("Invalid arrow body").pure[Alg]
|
||||
|
@ -1,13 +1,14 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{AssignmentTag, FuncOp, SeqTag, TryTag}
|
||||
import aqua.parser.expr.func.CatchExpr
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{AssignmentTag, FuncOp, SeqTag, TryTag}
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.locations.LocationsAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
|
||||
import cats.Monad
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.flatMap.*
|
||||
@ -15,7 +16,7 @@ import cats.syntax.functor.*
|
||||
|
||||
class CatchSem[S[_]](val expr: CatchExpr[S]) extends AnyVal {
|
||||
|
||||
def program[Alg[_]: Monad](implicit
|
||||
def program[Alg[_]: Monad](using
|
||||
N: NamesAlgebra[S, Alg],
|
||||
A: AbilitiesAlgebra[S, Alg],
|
||||
L: LocationsAlgebra[S, Alg]
|
||||
@ -26,16 +27,15 @@ class CatchSem[S[_]](val expr: CatchExpr[S]) extends AnyVal {
|
||||
(_, g: Raw) =>
|
||||
g match {
|
||||
case FuncOp(op) =>
|
||||
for {
|
||||
restricted <- FuncOpSem.restrictStreamsInScope(op)
|
||||
tag = TryTag.Catch
|
||||
TryTag.Catch
|
||||
.wrap(
|
||||
SeqTag.wrap(
|
||||
AssignmentTag(ValueRaw.error, expr.name.value).leaf,
|
||||
restricted
|
||||
op
|
||||
)
|
||||
)
|
||||
} yield tag.toFuncOp
|
||||
.toFuncOp
|
||||
.pure
|
||||
case _ =>
|
||||
Raw.error("Wrong body of the `catch` expression").pure
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{FuncOp, IfTag, TryTag}
|
||||
import aqua.parser.expr.func.ElseOtherwiseExpr
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{FuncOp, IfTag, TryTag}
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.locations.LocationsAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
|
||||
import cats.Monad
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.Monad
|
||||
|
||||
class ElseOtherwiseSem[S[_]](val expr: ElseOtherwiseExpr[S]) extends AnyVal {
|
||||
|
||||
@ -23,15 +23,14 @@ class ElseOtherwiseSem[S[_]](val expr: ElseOtherwiseExpr[S]) extends AnyVal {
|
||||
.after((ops: Raw) =>
|
||||
ops match {
|
||||
case FuncOp(op) =>
|
||||
for {
|
||||
restricted <- FuncOpSem.restrictStreamsInScope(op)
|
||||
tag = expr.kind
|
||||
expr.kind
|
||||
.fold(
|
||||
ifElse = IfTag.Else,
|
||||
ifOtherwise = TryTag.Otherwise
|
||||
)
|
||||
.wrap(restricted)
|
||||
} yield tag.toFuncOp
|
||||
.wrap(op)
|
||||
.toFuncOp
|
||||
.pure
|
||||
case _ =>
|
||||
val name = expr.kind.fold("`else`", "`otherwise`")
|
||||
Raw.error(s"Wrong body of the $name expression").pure
|
||||
|
@ -7,7 +7,6 @@ import aqua.raw.ops.*
|
||||
import aqua.raw.ops.ForTag.Mode
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.expr.func.FuncOpSem
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
@ -38,7 +37,6 @@ class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal {
|
||||
(iterable, ops: Raw) =>
|
||||
(iterable, ops) match {
|
||||
case (Some(vm), FuncOp(op)) =>
|
||||
FuncOpSem.restrictStreamsInScope(op).map { restricted =>
|
||||
val mode = expr.mode.fold(ForTag.Mode.SeqMode) {
|
||||
case ForExpr.Mode.ParMode => ForTag.Mode.ParMode
|
||||
case ForExpr.Mode.TryMode => ForTag.Mode.TryMode
|
||||
@ -54,7 +52,7 @@ class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal {
|
||||
|
||||
val forTag = ForTag(expr.item.value, vm, mode).wrap(
|
||||
innerTag.wrap(
|
||||
restricted,
|
||||
op,
|
||||
NextTag(expr.item.value).leaf
|
||||
)
|
||||
)
|
||||
@ -67,8 +65,7 @@ class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal {
|
||||
case _ => forTag
|
||||
}
|
||||
|
||||
result.toFuncOp
|
||||
}
|
||||
result.toFuncOp.pure
|
||||
case _ => Raw.error("Wrong body of the `for` expression").pure[F]
|
||||
}
|
||||
)
|
||||
|
@ -1,21 +0,0 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{RawTag, RestrictionTag}
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import cats.{FlatMap, Functor, Monad}
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.flatMap.*
|
||||
|
||||
object FuncOpSem {
|
||||
|
||||
def restrictStreamsInScope[S[_], Alg[_]: Monad](
|
||||
tree: RawTag.Tree
|
||||
)(using N: NamesAlgebra[S, Alg]): Alg[RawTag.Tree] = N
|
||||
.streamsDefinedWithinScope()
|
||||
.map(streams =>
|
||||
streams.toList
|
||||
.foldLeft(tree) { case (tree, (streamName, streamType)) =>
|
||||
RestrictionTag(streamName, streamType).wrap(tree)
|
||||
}
|
||||
)
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{FuncOp, IfTag}
|
||||
import aqua.parser.expr.func.IfExpr
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{FuncOp, IfTag}
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.locations.LocationsAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.types.ScalarType
|
||||
import aqua.types.Type
|
||||
|
||||
import cats.Monad
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.traverse.*
|
||||
import aqua.types.ScalarType
|
||||
|
||||
class IfSem[S[_]](val expr: IfExpr[S]) extends AnyVal {
|
||||
|
||||
@ -46,10 +46,7 @@ class IfSem[S[_]](val expr: IfExpr[S]) extends AnyVal {
|
||||
(value, ops: Raw) =>
|
||||
(value, ops) match {
|
||||
case (Some(vr), FuncOp(op)) =>
|
||||
for {
|
||||
restricted <- FuncOpSem.restrictStreamsInScope(op)
|
||||
tag = IfTag(vr).wrap(restricted)
|
||||
} yield tag.toFuncOp
|
||||
IfTag(vr).wrap(op).toFuncOp.pure
|
||||
case (None, _) => Raw.error("`if` expression errored in matching types").pure
|
||||
case _ => Raw.error("Wrong body of the `if` expression").pure
|
||||
}
|
||||
|
@ -56,26 +56,26 @@ class ParSeqSem[S[_]](val expr: ParSeqExpr[S]) extends AnyVal {
|
||||
): F[Raw] =
|
||||
V.valueToRaw(expr.peerId).map((_, iterableVM, ops)).flatMap {
|
||||
case (Some(peerId), Some(vm), FuncOp(op)) =>
|
||||
for {
|
||||
restricted <- FuncOpSem.restrictStreamsInScope(op)
|
||||
onTag = OnTag(
|
||||
val onTag = OnTag(
|
||||
peerId = peerId,
|
||||
via = Chain.fromSeq(viaVM),
|
||||
strategy = OnTag.ReturnStrategy.Relay.some
|
||||
)
|
||||
|
||||
/**
|
||||
* `parseq` => par (`never` as `last` in `fold`)
|
||||
* So that peer initiating `parseq` would not continue execution past it
|
||||
*/
|
||||
tag = ForTag
|
||||
ForTag
|
||||
.par(expr.item.value, vm)
|
||||
.wrap(
|
||||
ParTag.wrap(
|
||||
onTag.wrap(restricted),
|
||||
onTag.wrap(op),
|
||||
NextTag(expr.item.value).leaf
|
||||
)
|
||||
)
|
||||
} yield tag.toFuncOp
|
||||
.toFuncOp
|
||||
.pure
|
||||
case (None, _, _) => Raw.error("ParSeqSem: could not resolve `peerId`").pure
|
||||
case (_, None, _) => Raw.error("ParSeqSem: could not resolve `iterable`").pure
|
||||
case (_, _, _) => Raw.error("ParSeqSem: wrong body of `parseq` block").pure
|
||||
|
@ -1,8 +1,8 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{FuncOp, TryTag}
|
||||
import aqua.parser.expr.func.TryExpr
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{FuncOp, TryTag}
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
@ -10,9 +10,9 @@ import aqua.semantics.rules.locations.LocationsAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
|
||||
import cats.Monad
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.Monad
|
||||
|
||||
class TrySem[S[_]](val expr: TryExpr[S]) extends AnyVal {
|
||||
|
||||
@ -27,10 +27,7 @@ class TrySem[S[_]](val expr: TryExpr[S]) extends AnyVal {
|
||||
.after((ops: Raw) =>
|
||||
ops match {
|
||||
case FuncOp(op) =>
|
||||
for {
|
||||
restricted <- FuncOpSem.restrictStreamsInScope(op)
|
||||
tag = TryTag.wrap(restricted)
|
||||
} yield tag.toFuncOp
|
||||
TryTag.wrap(op).toFuncOp.pure
|
||||
case _ =>
|
||||
Raw.error("Wrong body of the `try` expression").pure[Alg]
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package aqua.semantics.rules.names
|
||||
|
||||
import aqua.parser.lexer.{LiteralToken, Name, Token, ValueToken}
|
||||
import aqua.types.{ArrowType, StreamType, Type}
|
||||
|
||||
import cats.InjectK
|
||||
|
||||
trait NamesAlgebra[S[_], Alg[_]] {
|
||||
@ -25,8 +26,6 @@ trait NamesAlgebra[S[_], Alg[_]] {
|
||||
|
||||
def defineArrow(name: Name[S], gen: ArrowType, isRoot: Boolean): Alg[Boolean]
|
||||
|
||||
def streamsDefinedWithinScope(): Alg[Map[String, StreamType]]
|
||||
|
||||
def beginScope(token: Token[S]): Alg[Unit]
|
||||
|
||||
def endScope(): Alg[Unit]
|
||||
|
@ -168,13 +168,6 @@ class NamesInterpreter[S[_], X](using
|
||||
)
|
||||
}
|
||||
|
||||
override def streamsDefinedWithinScope(): SX[Map[String, StreamType]] =
|
||||
mapStackHead(Map.empty) { frame =>
|
||||
frame -> frame.names.collect { case (n, st @ StreamType(_)) =>
|
||||
n -> st
|
||||
}
|
||||
}
|
||||
|
||||
override def beginScope(token: Token[S]): SX[Unit] =
|
||||
stackInt.beginScope(NamesState.Frame(token))
|
||||
|
||||
|
@ -142,7 +142,6 @@ class SemanticsSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
val streamType = StreamType(ScalarType.string)
|
||||
val stream = VarRaw(name, streamType)
|
||||
|
||||
RestrictionTag(stream.name, streamType).wrap(
|
||||
SeqTag.wrap(
|
||||
DeclareStreamTag(stream).leaf,
|
||||
PushToStreamTag(
|
||||
@ -150,7 +149,6 @@ class SemanticsSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
Call.Export(name, streamType)
|
||||
).leaf
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// use it to fix https://github.com/fluencelabs/aqua/issues/90
|
||||
|
Loading…
Reference in New Issue
Block a user