mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 14:40:17 +00:00
Merge branch 'chore/use-fcli-for-nox' into renovate/fluencelabs-js-client-0.x
# Conflicts: # .github/workflows/tests.yml
This commit is contained in:
commit
9b4865f8a8
134
.github/e2e/docker-compose.yml
vendored
134
.github/e2e/docker-compose.yml
vendored
@ -1,134 +0,0 @@
|
||||
networks:
|
||||
nox:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 10.50.10.0/24
|
||||
|
||||
services:
|
||||
nox-1:
|
||||
image: ${NOX_IMAGE}
|
||||
ports:
|
||||
- 7771:7771
|
||||
- 9991:9991
|
||||
command:
|
||||
- --aqua-pool-size=2
|
||||
- -t=7771
|
||||
- -w=9991
|
||||
- -x=10.50.10.10
|
||||
- --external-maddrs
|
||||
- /dns4/nox-1/tcp/7771
|
||||
- /dns4/nox-1/tcp/9991/ws
|
||||
- --allow-private-ips
|
||||
- --local
|
||||
# - --bootstraps=/dns/nox-1/tcp/7771
|
||||
# 12D3KooWBM3SdXWqGaawQDGQ6JprtwswEg3FWGvGhmgmMez1vRbR
|
||||
- -k=hK62afickoeP2uZbmSkAYXxxqP8ozq16VRN7qfTP719EHC5V5tjrtW57BSjUr8GvsEXmJRbtejUWyPZ2rZMyQdq
|
||||
networks:
|
||||
nox:
|
||||
ipv4_address: 10.50.10.10
|
||||
|
||||
nox-2:
|
||||
image: ${NOX_IMAGE}
|
||||
ports:
|
||||
- 7772:7772
|
||||
- 9992:9992
|
||||
command:
|
||||
- --aqua-pool-size=2
|
||||
- -t=7772
|
||||
- -w=9992
|
||||
- -x=10.50.10.20
|
||||
- --external-maddrs
|
||||
- /dns4/nox-2/tcp/7772
|
||||
- /dns4/nox-2/tcp/9992/ws
|
||||
- --allow-private-ips
|
||||
- --bootstraps=/dns/nox-1/tcp/7771
|
||||
# 12D3KooWQdpukY3p2DhDfUfDgphAqsGu5ZUrmQ4mcHSGrRag6gQK
|
||||
- -k=2WijTVdhVRzyZamWjqPx4V4iNMrajegNMwNa2PmvPSZV6RRpo5M2fsPWdQr22HVRubuJhhSw8BrWiGt6FPhFAuXy
|
||||
networks:
|
||||
nox:
|
||||
ipv4_address: 10.50.10.20
|
||||
|
||||
nox-3:
|
||||
image: ${NOX_IMAGE}
|
||||
ports:
|
||||
- 7773:7773
|
||||
- 9993:9993
|
||||
command:
|
||||
- --aqua-pool-size=2
|
||||
- -t=7773
|
||||
- -w=9993
|
||||
- -x=10.50.10.30
|
||||
- --external-maddrs
|
||||
- /dns4/nox-3/tcp/7773
|
||||
- /dns4/nox-3/tcp/9993/ws
|
||||
- --allow-private-ips
|
||||
- --bootstraps=/dns/nox-1/tcp/7771
|
||||
# 12D3KooWRT8V5awYdEZm6aAV9HWweCEbhWd7df4wehqHZXAB7yMZ
|
||||
- -k=2n2wBVanBeu2GWtvKBdrYK9DJAocgG3PrTUXMharq6TTfxqTL4sLdXL9BF23n6rsnkAY5pR9vBtx2uWYDQAiZdrX
|
||||
networks:
|
||||
nox:
|
||||
ipv4_address: 10.50.10.30
|
||||
|
||||
nox-4:
|
||||
image: ${NOX_IMAGE}
|
||||
ports:
|
||||
- 7774:7774
|
||||
- 9994:9994
|
||||
command:
|
||||
- --aqua-pool-size=2
|
||||
- -t=7774
|
||||
- -w=9994
|
||||
- -x=10.50.10.40
|
||||
- --external-maddrs
|
||||
- /dns4/nox-4/tcp/7774
|
||||
- /dns4/nox-4/tcp/9994/ws
|
||||
- --allow-private-ips
|
||||
- --bootstraps=/dns/nox-1/tcp/7771
|
||||
# 12D3KooWBzLSu9RL7wLP6oUowzCbkCj2AGBSXkHSJKuq4wwTfwof
|
||||
- -k=4zp8ucAikkjB8CmkufYiFBW4QCDUCbQG7yMjviX7W8bMyN5rfChQ2Pi5QCWThrCTbAm9uq5nbFbxtFcNZq3De4dX
|
||||
networks:
|
||||
nox:
|
||||
ipv4_address: 10.50.10.40
|
||||
|
||||
nox-5:
|
||||
image: ${NOX_IMAGE}
|
||||
ports:
|
||||
- 7775:7775
|
||||
- 9995:9995
|
||||
command:
|
||||
- --aqua-pool-size=2
|
||||
- -t=7775
|
||||
- -w=9995
|
||||
- -x=10.50.10.50
|
||||
- --external-maddrs
|
||||
- /dns4/nox-5/tcp/7775
|
||||
- /dns4/nox-5/tcp/9995/ws
|
||||
- --allow-private-ips
|
||||
- --bootstraps=/dns/nox-1/tcp/7771
|
||||
# 12D3KooWBf6hFgrnXwHkBnwPGMysP3b1NJe5HGtAWPYfwmQ2MBiU
|
||||
- -k=3ry26rm5gkJXvdqRH4FoM3ezWq4xVVsBQF7wtKq4E4pbuaa6p1F84tNqifUS7DdfJL9hs2gcdW64Wc342vHZHMUp
|
||||
networks:
|
||||
nox:
|
||||
ipv4_address: 10.50.10.50
|
||||
|
||||
nox-6:
|
||||
image: ${NOX_IMAGE}
|
||||
ports:
|
||||
- 7776:7776
|
||||
- 9996:9996
|
||||
command:
|
||||
- --aqua-pool-size=2
|
||||
- -t=7776
|
||||
- -w=9996
|
||||
- --bootstraps=/dns/nox-1/tcp/7771
|
||||
- -x=10.50.10.60
|
||||
- --external-maddrs
|
||||
- /dns4/nox-6/tcp/7776
|
||||
- /dns4/nox-6/tcp/9996/ws
|
||||
- --allow-private-ips
|
||||
# 12D3KooWPisGn7JhooWhggndz25WM7vQ2JmA121EV8jUDQ5xMovJ
|
||||
- -k=5Qh8bB1sF28uLPwr3HTvEksCeC6mAWQvebCfcgv9y6j4qKwSzNKm2tzLUg4nACUEo2KZpBw11gNCnwaAdM7o1pEn
|
||||
networks:
|
||||
nox:
|
||||
ipv4_address: 10.50.10.60
|
2
.github/release-please/manifest.json
vendored
2
.github/release-please/manifest.json
vendored
@ -1,3 +1,3 @@
|
||||
{
|
||||
".": "0.14.2"
|
||||
".": "0.14.4"
|
||||
}
|
||||
|
1
.github/workflows/run-tests.yml
vendored
1
.github/workflows/run-tests.yml
vendored
@ -32,3 +32,4 @@ jobs:
|
||||
uses: ./.github/workflows/tests.yml
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
nox-image: "docker.fluence.dev/nox:renovate-avm_4905_1"
|
||||
|
19
.github/workflows/tests.yml
vendored
19
.github/workflows/tests.yml
vendored
@ -22,8 +22,8 @@ on:
|
||||
|
||||
env:
|
||||
FORCE_COLOR: true
|
||||
NOX_IMAGE: "${{ inputs.nox-image }}"
|
||||
FLUENCE_ENV: "${{ inputs.fluence-env }}"
|
||||
FCLI_V_NOX: "${{ inputs.nox-image }}"
|
||||
|
||||
jobs:
|
||||
aqua:
|
||||
@ -64,14 +64,17 @@ jobs:
|
||||
repository: fluencelabs/aqua
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Pull nox image
|
||||
run: docker pull docker.fluence.dev/nox:feat-vm-425-aquavm-mem-limits-from-config-2_4983_1@sha256:71bc65e096931ad1abc92b166b0033f01a718084d0f275d070ea495353da2d89
|
||||
|
||||
- name: Run nox
|
||||
uses: isbang/compose-action@v1.5.1
|
||||
- name: Setup fcli
|
||||
uses: fluencelabs/setup-fluence@v1
|
||||
with:
|
||||
compose-file: ".github/e2e/docker-compose.yml"
|
||||
down-flags: "--volumes"
|
||||
artifact: fcli
|
||||
version: unstable
|
||||
|
||||
- name: Init local env with fcli
|
||||
run: fluence local init --no-input
|
||||
|
||||
- name: Run nox network
|
||||
run: fluence local up
|
||||
|
||||
- name: Cache Scala
|
||||
uses: coursier/cache-action@v6
|
||||
|
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## [0.14.4](https://github.com/fluencelabs/aqua/compare/aqua-v0.14.3...aqua-v0.14.4) (2024-02-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** Bug in renaming [LNG-346] ([#1094](https://github.com/fluencelabs/aqua/issues/1094)) ([d7fef3d](https://github.com/fluencelabs/aqua/commit/d7fef3db5fda6c2dfeacac84c3cff2188538a35a))
|
||||
* **compiler:** Import abilities with `use` [LNG-324] ([#1077](https://github.com/fluencelabs/aqua/issues/1077)) ([a6c8e75](https://github.com/fluencelabs/aqua/commit/a6c8e75c270efd358908f285310f1f1d177a65fb))
|
||||
|
||||
## [0.14.3](https://github.com/fluencelabs/aqua/compare/aqua-v0.14.2...aqua-v0.14.3) (2024-02-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** Change `noEmptyResponse` default to `true` ([#1093](https://github.com/fluencelabs/aqua/issues/1093)) ([23aba18](https://github.com/fluencelabs/aqua/commit/23aba18c7d7fb86acd2470474f776f00a78ee9c6))
|
||||
* **language-server:** Name clashing in LSP [LNG-342] ([#1089](https://github.com/fluencelabs/aqua/issues/1089)) ([3e9d385](https://github.com/fluencelabs/aqua/commit/3e9d3856685f74a6be5d0aa288cd7e4f95010901))
|
||||
|
||||
## [0.14.2](https://github.com/fluencelabs/aqua/compare/aqua-v0.14.1...aqua-v0.14.2) (2024-02-21)
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@ function getConfig({
|
||||
noXor = false,
|
||||
targetType = "air",
|
||||
tracing = false,
|
||||
noEmptyResponse = false,
|
||||
noEmptyResponse = true,
|
||||
}) {
|
||||
return new AquaConfig(
|
||||
logLevel,
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fluencelabs/aqua-api",
|
||||
"version": "0.14.2",
|
||||
"version": "0.14.4",
|
||||
"description": "Aqua API",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
|
@ -72,7 +72,7 @@ object AquaConfig {
|
||||
noXor = cjs.noXor.getOrElse(false),
|
||||
noRelay = cjs.noRelay.getOrElse(false),
|
||||
tracing = cjs.tracing.getOrElse(false),
|
||||
noEmptyResponse = cjs.noEmptyResponse.getOrElse(false)
|
||||
noEmptyResponse = cjs.noEmptyResponse.getOrElse(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,48 @@
|
||||
aqua Job declares *
|
||||
aqua Main
|
||||
|
||||
import someString from "hack"
|
||||
use timeout, someString from "hack.aqua" as P
|
||||
export bugLNG346
|
||||
|
||||
export timeout
|
||||
ability Promise:
|
||||
yield() -> string
|
||||
|
||||
func timeout() -> string:
|
||||
res <- P.timeout()
|
||||
b = someString()
|
||||
a = P.someString()
|
||||
<- res
|
||||
func done_nil() -> string:
|
||||
<- ""
|
||||
|
||||
func done() -> Promise:
|
||||
<- Promise(yield = done_nil)
|
||||
|
||||
ability Compute:
|
||||
yield() -> string
|
||||
|
||||
alias WorkerYield: -> string
|
||||
alias Yield: WorkerYield -> Promise
|
||||
|
||||
func wait_for() -> Yield:
|
||||
wait = func (cb: -> string) -> Promise:
|
||||
yield = func () -> string:
|
||||
e <- cb()
|
||||
<- e
|
||||
<- Promise(yield = yield)
|
||||
<- wait
|
||||
|
||||
ability Function:
|
||||
run(dealId: string) -> string
|
||||
|
||||
func simple{Compute}(yield: Yield) -> Function:
|
||||
deal_run = func () -> string:
|
||||
c_yield = func () -> string:
|
||||
<- Compute.yield()
|
||||
yieeld <- yield(c_yield)
|
||||
res <- yieeld.yield()
|
||||
<- res
|
||||
<- Function(run = deal_run)
|
||||
|
||||
func bugLNG346() -> string:
|
||||
res: *string
|
||||
yieeld = func () -> string:
|
||||
res <<- "hello"
|
||||
<- ""
|
||||
c = Compute(yield = yieeld)
|
||||
fn = simple{c}(wait_for())
|
||||
r <- fn.run("")
|
||||
<- res!
|
@ -1,4 +1,4 @@
|
||||
module DeclareModule declares decl_foo, decl_bar, SuperFoo, DECLARE_CONST, DECLARE_CONST2
|
||||
aqua DeclareModule declares decl_foo, decl_bar, SuperFoo, DECLARE_CONST, DECLARE_CONST2
|
||||
export SuperFoo
|
||||
|
||||
const DECLARE_CONST = "declare_const"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import BundleJS.*
|
||||
|
||||
val aquaVersion = "0.14.2"
|
||||
val aquaVersion = "0.14.4"
|
||||
|
||||
val scalaV = "3.4.0"
|
||||
val catsV = "2.10.0"
|
||||
|
@ -87,6 +87,25 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
inside(funcs)(test)
|
||||
)
|
||||
|
||||
def through(peer: ValueModel) =
|
||||
MakeRes.hop(peer)
|
||||
|
||||
val relay = VarRaw("-relay-", ScalarType.string)
|
||||
|
||||
def getDataSrv(name: String, varName: String, t: Type) = {
|
||||
CallServiceRes(
|
||||
LiteralModel.quote("getDataSrv"),
|
||||
name,
|
||||
CallRes(Nil, Some(CallModel.Export(varName, t))),
|
||||
LiteralModel.fromRaw(ValueRaw.InitPeerId)
|
||||
).leaf
|
||||
}
|
||||
|
||||
private val init = LiteralModel.fromRaw(ValueRaw.InitPeerId)
|
||||
|
||||
private def join(vm: VarModel, size: ValueModel) =
|
||||
ResBuilder.join(vm, size, init)
|
||||
|
||||
"aqua compiler" should "compile a simple snippet to the right context" in {
|
||||
|
||||
val src = Map(
|
||||
@ -115,25 +134,6 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
}
|
||||
}
|
||||
|
||||
def through(peer: ValueModel) =
|
||||
MakeRes.hop(peer)
|
||||
|
||||
val relay = VarRaw("-relay-", ScalarType.string)
|
||||
|
||||
def getDataSrv(name: String, varName: String, t: Type) = {
|
||||
CallServiceRes(
|
||||
LiteralModel.quote("getDataSrv"),
|
||||
name,
|
||||
CallRes(Nil, Some(CallModel.Export(varName, t))),
|
||||
LiteralModel.fromRaw(ValueRaw.InitPeerId)
|
||||
).leaf
|
||||
}
|
||||
|
||||
private val init = LiteralModel.fromRaw(ValueRaw.InitPeerId)
|
||||
|
||||
private def join(vm: VarModel, size: ValueModel) =
|
||||
ResBuilder.join(vm, size, init)
|
||||
|
||||
it should "create right topology" in {
|
||||
val src = Map(
|
||||
"index.aqua" ->
|
||||
@ -502,4 +502,385 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
||||
main.body.equalsOrShowDiff(expected) should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
val moduleNames = List("Test", "Imp", "Sub", "Path").inits
|
||||
.takeWhile(_.nonEmpty)
|
||||
.map(_.mkString("."))
|
||||
.toList
|
||||
|
||||
it should "import function with `use`" in {
|
||||
def test(name: String, rename: Option[String]) = {
|
||||
val src = Map(
|
||||
"main.aqua" ->
|
||||
s"""aqua Main
|
||||
|export main
|
||||
|use "import.aqua"${rename.fold("")(" as " + _)}
|
||||
|func main() -> i32:
|
||||
| <- ${rename.getOrElse(name)}.foo()
|
||||
|""".stripMargin
|
||||
)
|
||||
val imports = Map(
|
||||
"import.aqua" ->
|
||||
s"""aqua $name declares foo
|
||||
|func foo() -> i32:
|
||||
| <- 42
|
||||
|""".stripMargin
|
||||
)
|
||||
|
||||
val transformCfg = TransformConfig(relayVarName = None)
|
||||
|
||||
insideRes(src, imports, transformCfg)(
|
||||
"main"
|
||||
) { case main :: _ =>
|
||||
val expected = XorRes.wrap(
|
||||
respCall(transformCfg, LiteralModel.number(42), initPeer),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
|
||||
main.body.equalsOrShowDiff(expected) should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
moduleNames.foreach { name =>
|
||||
val rename = "Imported"
|
||||
|
||||
withClue(s"Testing $name") {
|
||||
test(name, None)
|
||||
}
|
||||
withClue(s"Testing $name as $rename") {
|
||||
test(name, rename.some)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "import service with `use`" in {
|
||||
def test(name: String, rename: Option[String]) = {
|
||||
val srvName = rename.getOrElse(name) + ".Srv"
|
||||
val src = Map(
|
||||
"main.aqua" ->
|
||||
s"""aqua Main
|
||||
|export main
|
||||
|use "import.aqua"${rename.fold("")(" as " + _)}
|
||||
|
|
||||
|func main() -> i32:
|
||||
| a <- $srvName.call()
|
||||
| $srvName "res-id"
|
||||
| b <- $srvName.call()
|
||||
| <- a + b
|
||||
|""".stripMargin
|
||||
)
|
||||
val imports = Map(
|
||||
"import.aqua" ->
|
||||
s"""aqua $name declares *
|
||||
|service Srv("def-id"):
|
||||
| call() -> i32
|
||||
|""".stripMargin
|
||||
)
|
||||
|
||||
val transformCfg = TransformConfig(relayVarName = None)
|
||||
|
||||
insideRes(src, imports, transformCfg)(
|
||||
"main"
|
||||
) { case main :: _ =>
|
||||
def call(id: String, exp: CallModel.Export) =
|
||||
CallServiceRes(
|
||||
LiteralModel.quote(id),
|
||||
"call",
|
||||
CallRes(Nil, Some(exp)),
|
||||
initPeer
|
||||
).leaf
|
||||
|
||||
val a = CallModel.Export("ret", ScalarType.i32)
|
||||
val b = CallModel.Export("ret-0", ScalarType.i32)
|
||||
val add = CallModel.Export("add", ScalarType.i32)
|
||||
val expected = XorRes.wrap(
|
||||
SeqRes.wrap(
|
||||
call("def-id", a),
|
||||
call("res-id", b),
|
||||
CallServiceRes(
|
||||
LiteralModel.quote("math"),
|
||||
"add",
|
||||
CallRes(List(a.asVar, b.asVar), Some(add)),
|
||||
initPeer
|
||||
).leaf,
|
||||
respCall(transformCfg, add.asVar, initPeer)
|
||||
),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
|
||||
main.body.equalsOrShowDiff(expected) should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
moduleNames.foreach { name =>
|
||||
val rename = "Imported"
|
||||
|
||||
withClue(s"Testing $name") {
|
||||
test(name, None)
|
||||
}
|
||||
withClue(s"Testing $name as $rename") {
|
||||
test(name, rename.some)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "import ability with `use`" in {
|
||||
def test(name: String, rename: Option[String]) = {
|
||||
val abName = rename.getOrElse(name) + ".Ab"
|
||||
val src = Map(
|
||||
"main.aqua" ->
|
||||
s"""aqua Main
|
||||
|export main
|
||||
|use "import.aqua"${rename.fold("")(" as " + _)}
|
||||
|func useAb{$abName}() -> i32:
|
||||
| <- $abName.a
|
||||
|
|
||||
|func main() -> i32:
|
||||
| ab = $abName(a = 42)
|
||||
| <- useAb{ab}()
|
||||
|""".stripMargin
|
||||
)
|
||||
val imports = Map(
|
||||
"import.aqua" ->
|
||||
s"""aqua $name declares *
|
||||
|ability Ab:
|
||||
| a: i32
|
||||
|""".stripMargin
|
||||
)
|
||||
|
||||
val transformCfg = TransformConfig(relayVarName = None)
|
||||
|
||||
insideRes(src, imports, transformCfg)(
|
||||
"main"
|
||||
) { case main :: _ =>
|
||||
val ap = CallModel.Export("literal_ap", LiteralType.unsigned)
|
||||
val props = ap.copy(name = "literal_props")
|
||||
val expected = XorRes.wrap(
|
||||
SeqRes.wrap(
|
||||
// NOTE: Result of compilation is inefficient
|
||||
ApRes(LiteralModel.number(42), ap).leaf,
|
||||
ApRes(ap.asVar, props).leaf,
|
||||
respCall(transformCfg, props.asVar, initPeer)
|
||||
),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
|
||||
main.body.equalsOrShowDiff(expected) should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
moduleNames.foreach { name =>
|
||||
val rename = "Imported"
|
||||
|
||||
withClue(s"Testing $name") {
|
||||
test(name, None)
|
||||
}
|
||||
withClue(s"Testing $name as $rename") {
|
||||
test(name, rename.some)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "import ability (nested) with `use`" in {
|
||||
def test(name: String, rename: Option[String]) = {
|
||||
val impName = rename.getOrElse(name)
|
||||
val abName = impName + ".Ab"
|
||||
val src = Map(
|
||||
"main.aqua" ->
|
||||
s"""aqua Main
|
||||
|export main
|
||||
|use "import.aqua"${rename.fold("")(" as " + _)}
|
||||
|func useAb{$abName}() -> i32:
|
||||
| <- $abName.ab1.ab0.call($abName.ab1.ab0.a)
|
||||
|
|
||||
|func main() -> i32:
|
||||
| id = (x: i32) -> i32:
|
||||
| <- x
|
||||
| ab0 = $impName.Ab0(a = 42, call = id)
|
||||
| ab1 = $impName.Ab1(ab0 = ab0)
|
||||
| ab = $abName(ab1 = ab1)
|
||||
| <- useAb{ab}()
|
||||
|""".stripMargin
|
||||
)
|
||||
val imports = Map(
|
||||
"import.aqua" ->
|
||||
s"""aqua $name declares *
|
||||
|ability Ab0:
|
||||
| a: i32
|
||||
| call(x: i32) -> i32
|
||||
|
|
||||
|ability Ab1:
|
||||
| ab0: Ab0
|
||||
|
|
||||
|ability Ab:
|
||||
| ab1: Ab1
|
||||
|""".stripMargin
|
||||
)
|
||||
|
||||
val transformCfg = TransformConfig(relayVarName = None)
|
||||
|
||||
insideRes(src, imports, transformCfg)(
|
||||
"main"
|
||||
) { case main :: _ =>
|
||||
val ap = CallModel.Export("literal_ap", LiteralType.unsigned)
|
||||
val props = ap.copy(name = "literal_props")
|
||||
val expected = XorRes.wrap(
|
||||
SeqRes.wrap(
|
||||
// NOTE: Result of compilation is inefficient
|
||||
ApRes(LiteralModel.number(42), ap).leaf,
|
||||
ApRes(ap.asVar, props).leaf,
|
||||
respCall(transformCfg, props.asVar, initPeer)
|
||||
),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
|
||||
main.body.equalsOrShowDiff(expected) should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
moduleNames.foreach { name =>
|
||||
val rename = "Imported"
|
||||
|
||||
withClue(s"Testing $name") {
|
||||
test(name, None)
|
||||
}
|
||||
withClue(s"Testing $name as $rename") {
|
||||
test(name, rename.some)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it should "import abilities in chain of imports" in {
|
||||
case class Imp(header: String, rename: Option[String] = None) {
|
||||
val as = rename.fold("")(" as " + _)
|
||||
val name = rename.getOrElse(header)
|
||||
|
||||
override def toString: String = s"$header$as"
|
||||
}
|
||||
|
||||
def test(hierarchy: List[Imp]) = {
|
||||
hierarchy.nonEmpty should be(true)
|
||||
|
||||
def genImp(header: String, imported: Imp, path: String): String = {
|
||||
s"""aqua ${header} declares *
|
||||
|use "${path}"${imported.as}
|
||||
|
|
||||
|ability Inner:
|
||||
| ab: ${imported.name}.Outer
|
||||
|
|
||||
|ability Outer:
|
||||
| ab: Inner
|
||||
|
|
||||
|func create{${imported.name}.Outer}() -> Inner:
|
||||
| ab = Inner(ab = ${imported.name}.Outer)
|
||||
| <- ab
|
||||
|""".stripMargin
|
||||
}
|
||||
|
||||
val base = Imp("Base")
|
||||
val basePath = "base.aqua"
|
||||
val baseCode = s"""aqua Base declares *
|
||||
|
|
||||
|ability Outer:
|
||||
| a: i32
|
||||
| call(x: i32) -> i32
|
||||
|""".stripMargin
|
||||
|
||||
val withPaths = hierarchy.zipWithIndex.map { case (imp, idx) =>
|
||||
imp -> s"import$idx.aqua"
|
||||
}
|
||||
val nexts = withPaths.tail :+ (base -> basePath)
|
||||
val imports = withPaths
|
||||
.zip(nexts)
|
||||
.map { case ((curImp, curPath), (nextImp, nextPath)) =>
|
||||
curPath -> genImp(curImp.header, nextImp, nextPath)
|
||||
}
|
||||
.appended(basePath -> baseCode)
|
||||
.toMap
|
||||
|
||||
val importStmts = withPaths.map { case (imp, path) =>
|
||||
s"use \"${path}\"${imp.as}"
|
||||
}.prepended(s"use \"${basePath}\"")
|
||||
val createStmts = hierarchy.reverse.zipWithIndex.flatMap { case (imp, idx) =>
|
||||
s"abIn${idx + 1} = ${imp.name}.create{abOut$idx}()" ::
|
||||
s"abOut${idx + 1} = ${imp.name}.Outer(ab = abIn${idx + 1})" ::
|
||||
Nil
|
||||
}.prepended("abOut0 = Base.Outer(a = 42, call = id)")
|
||||
|
||||
val lastAb = s"abOut${hierarchy.size}" + ".ab".repeat(hierarchy.size * 2)
|
||||
val main = s"""aqua Main
|
||||
|export main
|
||||
|${importStmts.mkString("\n")}
|
||||
|
|
||||
|func main() -> i32:
|
||||
| id = (x: i32) -> i32:
|
||||
| <- x
|
||||
| ${createStmts.mkString("\n ")}
|
||||
| <- $lastAb.call($lastAb.a)
|
||||
|""".stripMargin
|
||||
|
||||
val src = Map(
|
||||
"main.aqua" -> main
|
||||
)
|
||||
|
||||
val transformCfg = TransformConfig(relayVarName = None)
|
||||
|
||||
insideRes(src, imports, transformCfg)(
|
||||
"main"
|
||||
) { case main :: _ =>
|
||||
val ap = CallModel.Export("literal_ap", LiteralType.unsigned)
|
||||
val props = ap.copy(name = "literal_props")
|
||||
val expected = XorRes.wrap(
|
||||
SeqRes.wrap(
|
||||
// NOTE: Result of compilation is inefficient
|
||||
ApRes(LiteralModel.number(42), ap).leaf,
|
||||
ApRes(ap.asVar, props).leaf,
|
||||
respCall(transformCfg, props.asVar, initPeer)
|
||||
),
|
||||
errorCall(transformCfg, 0, initPeer)
|
||||
)
|
||||
|
||||
main.body.equalsOrShowDiff(expected) should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Simple
|
||||
(1 to 10).map(i => (1 to i).map(n => Imp(s"Imp$n")).toList).foreach { h =>
|
||||
withClue(s"Testing ${h.mkString(" -> ")}") {
|
||||
test(h)
|
||||
}
|
||||
}
|
||||
|
||||
// With renaming
|
||||
(1 to 10)
|
||||
.map(i =>
|
||||
(1 to i)
|
||||
.map(n =>
|
||||
// Rename every second one
|
||||
Imp(s"Imp$n", s"Renamed$n".some.filter(_ => n % 2 == 0))
|
||||
)
|
||||
.toList
|
||||
)
|
||||
.foreach { h =>
|
||||
withClue(s"Testing ${h.mkString(" -> ")}") {
|
||||
test(h)
|
||||
}
|
||||
}
|
||||
|
||||
// With subpath
|
||||
(1 to 10)
|
||||
.map(i =>
|
||||
(1 to i)
|
||||
.map(n => s"Imp$n")
|
||||
.inits
|
||||
.takeWhile(_.nonEmpty)
|
||||
.map(p => Imp(p.mkString(".")))
|
||||
.toList
|
||||
)
|
||||
.foreach { h =>
|
||||
withClue(s"Testing ${h.mkString(" -> ")}") {
|
||||
test(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
48
integration-tests/aqua/examples/abilitiesClosureRename.aqua
Normal file
48
integration-tests/aqua/examples/abilitiesClosureRename.aqua
Normal file
@ -0,0 +1,48 @@
|
||||
aqua AbilitiesClosureRename
|
||||
|
||||
export bugLNG346
|
||||
|
||||
ability Promise:
|
||||
yield() -> string
|
||||
|
||||
func done_nil() -> string:
|
||||
<- ""
|
||||
|
||||
func done() -> Promise:
|
||||
<- Promise(yield = done_nil)
|
||||
|
||||
ability Compute:
|
||||
yield() -> string
|
||||
|
||||
alias WorkerYield: -> string
|
||||
alias Yield: WorkerYield -> Promise
|
||||
|
||||
func wait_for() -> Yield:
|
||||
wait = func (cb: -> string) -> Promise:
|
||||
yield = func () -> string:
|
||||
e <- cb()
|
||||
<- e
|
||||
<- Promise(yield = yield)
|
||||
<- wait
|
||||
|
||||
ability Function:
|
||||
run(dealId: string) -> string
|
||||
|
||||
func simple{Compute}(yield: Yield) -> Function:
|
||||
deal_run = func () -> string:
|
||||
c_yield = func () -> string:
|
||||
<- Compute.yield()
|
||||
yieeld <- yield(c_yield)
|
||||
res <- yieeld.yield()
|
||||
<- res
|
||||
<- Function(run = deal_run)
|
||||
|
||||
func bugLNG346() -> string:
|
||||
res: *string
|
||||
yieeld = func () -> string:
|
||||
res <<- "hello"
|
||||
<- ""
|
||||
c = Compute(yield = yieeld)
|
||||
fn = simple{c}(wait_for())
|
||||
r <- fn.run("")
|
||||
<- res!
|
@ -29,7 +29,7 @@
|
||||
},
|
||||
"prettier": {},
|
||||
"devDependencies": {
|
||||
"@fluencelabs/aqua-api": "0.14.2",
|
||||
"@fluencelabs/aqua-api": "0.14.4",
|
||||
"@fluencelabs/aqua-lib": "0.10.2",
|
||||
"@types/jest": "29.5.11",
|
||||
"@types/node": "18.19.10",
|
||||
|
@ -41,6 +41,7 @@ import {
|
||||
returnSrvAsAbilityCall,
|
||||
} from "../examples/abilityCall.js";
|
||||
import { bugLNG314Call, bugLNG338Call } from "../examples/abilityClosureCall.js";
|
||||
import { bugLNG346Call } from "../examples/abilityClosureRenameCall.js";
|
||||
import {
|
||||
nilLengthCall,
|
||||
nilLiteralCall,
|
||||
@ -670,6 +671,11 @@ describe("Testing examples", () => {
|
||||
expect(result).toEqual("job done");
|
||||
});
|
||||
|
||||
it("abilitiesClosureRename.aqua bug LNG-346", async () => {
|
||||
let result = await bugLNG346Call();
|
||||
expect(result).toEqual("hello");
|
||||
});
|
||||
|
||||
it("functors.aqua LNG-119 bug", async () => {
|
||||
let result = await bugLng119Call();
|
||||
expect(result).toEqual([1]);
|
||||
|
@ -0,0 +1,8 @@
|
||||
import {
|
||||
bugLNG346
|
||||
} from "../compiled/examples/abilitiesClosureRename.js";
|
||||
|
||||
export async function bugLNG346Call(): Promise<string> {
|
||||
return await bugLNG346();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fluencelabs/aqua-language-server-api",
|
||||
"version": "0.14.2",
|
||||
"version": "0.14.4",
|
||||
"description": "Aqua Language Server API",
|
||||
"type": "commonjs",
|
||||
"files": [
|
||||
|
@ -507,9 +507,7 @@ object ArrowInliner extends Logging {
|
||||
* are prohibited because they are used inside **this function**.
|
||||
*/
|
||||
defineNames <- StateT.liftF(
|
||||
fn.body.definesVarNames.map(
|
||||
_ -- argNames -- capturedNames
|
||||
)
|
||||
fn.body.definesVarNames
|
||||
)
|
||||
defineRenames <- Mangler[S].findAndForbidNames(defineNames)
|
||||
canonStreamsWithNames <- canonStreamVariables(args)
|
||||
|
@ -35,6 +35,11 @@ enum NamedArg[F[_]] extends Token[F] {
|
||||
case Full(name, value) => Full(name.mapK(fk), value.mapK(fk))
|
||||
case Short(variable) => Short(variable.mapK(fk))
|
||||
}
|
||||
|
||||
override def toString: String = this match {
|
||||
case Full(name, value) => s"$name = $value"
|
||||
case Short(variable) => variable.toString
|
||||
}
|
||||
}
|
||||
|
||||
object NamedArg {
|
||||
|
@ -1,20 +1,20 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lexer.CallArrowToken.CallBraces
|
||||
import aqua.parser.lexer.NamedArg.namedArgs
|
||||
import aqua.parser.lexer.Token.*
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser.*
|
||||
import aqua.parser.lift.Span
|
||||
import aqua.parser.lift.Span.{P0ToSpan, PToSpan}
|
||||
import aqua.types.LiteralType
|
||||
import aqua.parser.lexer.CallArrowToken.CallBraces
|
||||
import aqua.parser.lexer.NamedArg.namedArgs
|
||||
|
||||
import cats.~>
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import cats.parse.{Numbers, Parser as P, Parser0 as P0}
|
||||
import cats.syntax.comonad.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.~>
|
||||
import scala.language.postfixOps
|
||||
|
||||
sealed trait PropertyOp[F[_]] extends Token[F] {
|
||||
@ -36,7 +36,7 @@ case class IntoField[F[_]: Comonad](name: F[String]) extends PropertyOp[F] {
|
||||
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): PropertyOp[K] = copy(fk(name))
|
||||
|
||||
def value: String = name.extract
|
||||
lazy val value: String = name.extract
|
||||
|
||||
override def toString: String = name.extract
|
||||
}
|
||||
@ -46,6 +46,8 @@ case class IntoIndex[F[_]: Comonad](point: F[Unit], idx: Option[ValueToken[F]])
|
||||
override def as[T](v: T): F[T] = point.as(v)
|
||||
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): IntoIndex[K] = copy(fk(point), idx.map(_.mapK(fk)))
|
||||
|
||||
override def toString: String = s"[$idx]"
|
||||
}
|
||||
|
||||
case class IntoCopy[F[_]: Comonad](
|
||||
@ -56,6 +58,27 @@ case class IntoCopy[F[_]: Comonad](
|
||||
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): IntoCopy[K] =
|
||||
copy(fk(point), args.map(_.mapK(fk)))
|
||||
|
||||
override def toString: String = s".copy(${args.map(_.toString).toList.mkString(", ")})"
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: This is parsed when we have parens after a name, but `IntoArrow` failed to parse.
|
||||
* This is a case of imported named type, e.g. `Some.Imported.Module.DefinedAbility(...)`
|
||||
* It is transformed into `NamedTypeValue` in `ValuesAlgebra`
|
||||
* TODO: Eliminate `IntoArrow`, unify it with this property
|
||||
*/
|
||||
case class IntoApply[F[_]: Comonad](
|
||||
argsF: F[NonEmptyList[NamedArg[F]]]
|
||||
) extends PropertyOp[F] {
|
||||
lazy val args: NonEmptyList[NamedArg[F]] = argsF.extract
|
||||
|
||||
override def as[T](v: T): F[T] = argsF.as(v)
|
||||
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): IntoApply[K] =
|
||||
copy(fk(argsF.map(_.map(_.mapK(fk)))))
|
||||
|
||||
override def toString: String = s"(${args.map(_.toString).toList.mkString(", ")})"
|
||||
}
|
||||
|
||||
object PropertyOp {
|
||||
@ -87,8 +110,19 @@ object PropertyOp {
|
||||
}
|
||||
}
|
||||
|
||||
private val parseApply: P[PropertyOp[Span.S]] =
|
||||
namedArgs.lift.map(IntoApply.apply)
|
||||
|
||||
private val parseOp: P[PropertyOp[Span.S]] =
|
||||
P.oneOf(parseCopy.backtrack :: parseArrow.backtrack :: parseField :: parseIdx :: Nil)
|
||||
P.oneOf(
|
||||
// NOTE: order is important here
|
||||
// intoApply has lower priority than intoArrow
|
||||
parseCopy.backtrack ::
|
||||
parseArrow.backtrack ::
|
||||
parseField ::
|
||||
parseIdx ::
|
||||
parseApply.backtrack :: Nil
|
||||
)
|
||||
|
||||
val ops: P[NonEmptyList[PropertyOp[Span.S]]] =
|
||||
parseOp.rep
|
||||
|
@ -121,9 +121,11 @@ case class ArrowTypeToken[S[_]: Comonad](
|
||||
args.map { case (n, t) => (n.map(_.mapK(fk)), t.mapK(fk)) },
|
||||
res.map(_.mapK(fk)),
|
||||
abilities.map(_.mapK(fk))
|
||||
)
|
||||
)
|
||||
def argTypes: List[TypeToken[S]] = abilities ++ args.map(_._2)
|
||||
lazy val absWithArgs: List[(Option[Name[S]], TypeToken[S])] = abilities.map(n => Some(n.asName) -> n) ++ args
|
||||
|
||||
lazy val absWithArgs: List[(Option[Name[S]], TypeToken[S])] =
|
||||
abilities.map(n => Some(n.asName) -> n) ++ args
|
||||
}
|
||||
|
||||
object ArrowTypeToken {
|
||||
@ -136,9 +138,9 @@ object ArrowTypeToken {
|
||||
).map(_.toList)
|
||||
|
||||
// {SomeAb, SecondAb} for NamedTypeToken
|
||||
def abilities(): P0[List[NamedTypeToken[S]]] =
|
||||
(`{` *> comma(`Class`.surroundedBy(`/s*`).lift.map(NamedTypeToken(_)))
|
||||
.map(_.toList) <* `}`).?.map(_.getOrElse(List.empty))
|
||||
def abilities(): P0[List[NamedTypeToken[S]]] = (
|
||||
`{` *> comma(NamedTypeToken.dotted).map(_.toList) <* `}`
|
||||
).?.map(_.getOrElse(List.empty))
|
||||
|
||||
def `arrowdef`(argTypeP: P[TypeToken[Span.S]]): P[ArrowTypeToken[Span.S]] =
|
||||
((abilities() ~ comma0(argTypeP)).with1 ~ ` -> `.lift ~
|
||||
|
@ -42,112 +42,105 @@ case class PropertyToken[F[_]: Comonad](
|
||||
name.forall(c => !c.isLetter || c.isUpper)
|
||||
|
||||
/**
|
||||
* This method tries to convert property token to
|
||||
* property token with dotted var name inside value token.
|
||||
*
|
||||
* Next properties pattern is untouched:
|
||||
* Class (field)*
|
||||
*
|
||||
* Next properties pattern is transformed:
|
||||
* (Class)* (CONST | field) ..props..
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
* this part is transformed to dotted name.
|
||||
* Try to transform this token to imported ability access
|
||||
* e.g. in `Some.Imported.Module.Ab.innerAb.call(...)`:
|
||||
* - `Some.Imported.Module` is imported module name
|
||||
* - `Ab.innerAb.call(...)` is ability access
|
||||
* so it should be handled as `(Some.Imported.Module.Ab).innerAb.call(...)`
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
* ability name inside `VarToken` as one string
|
||||
* but we don't know this in advance, so this method returns
|
||||
* a list of all possible (imported module name, ability access value token) pairs
|
||||
* so calling code can check what prefix is valid imported module name and
|
||||
* handle the corresponding ability access value token.
|
||||
*/
|
||||
private def toDottedName: Option[ValueToken[F]] = value match {
|
||||
case VarToken(name) =>
|
||||
// Pattern `Class (field)*` is ability access
|
||||
// and should not be transformed
|
||||
val isAbility = isClass(name.value) && properties.forall {
|
||||
case f @ IntoField(_) => isField(f.value)
|
||||
case _ => true
|
||||
}
|
||||
def toAbility: List[(NamedTypeToken[F], ValueToken[F])] =
|
||||
value match {
|
||||
// NOTE: guard against recursion: if dot is alredy in the name, do not transform
|
||||
case VarToken(name) if !name.value.contains(".") =>
|
||||
val fields = properties.toList.takeWhile {
|
||||
case IntoField(_) => true
|
||||
case _ => false
|
||||
}.collect { case f @ IntoField(_) => f.value }.toList
|
||||
val names = name.value +: fields
|
||||
|
||||
if (isAbility) none
|
||||
else {
|
||||
// Gather prefix of properties that are IntoField
|
||||
val props = name.value +: properties.toList.view.map {
|
||||
case IntoField(name) => name.extract.some
|
||||
case _ => none
|
||||
}.takeWhile(_.isDefined).flatten.toList
|
||||
fields.inits
|
||||
// do not use the last field
|
||||
// those cases are handled in `toCallArrow` and `toNamedValue`
|
||||
.drop(1)
|
||||
.map { init =>
|
||||
// Length of the import name
|
||||
val importLength = init.length + 1
|
||||
// Length of the imported name
|
||||
val nameLength = importLength + 1
|
||||
val newProps = NonEmptyList.fromList(
|
||||
properties.toList.drop(importLength)
|
||||
)
|
||||
val newName = name.rename(names.take(nameLength).mkString("."))
|
||||
val importAbility = name.rename(names.take(importLength).mkString(".")).asTypeToken
|
||||
|
||||
val propsWithIndex = props.zipWithIndex
|
||||
val varToken = VarToken(newName)
|
||||
val token = newProps.fold(varToken)(ps => PropertyToken(varToken, ps))
|
||||
|
||||
// Find first property that is not Class
|
||||
val classesTill = propsWithIndex.find { case (name, _) =>
|
||||
!isClass(name)
|
||||
}.collect { case (_, idx) =>
|
||||
idx
|
||||
}.getOrElse(props.length)
|
||||
|
||||
// Find last property after classes
|
||||
// that is CONST or field
|
||||
val lastSuitable = propsWithIndex
|
||||
.take(classesTill)
|
||||
.findLast { case (name, _) =>
|
||||
isConst(name) || isField(name)
|
||||
importAbility -> token
|
||||
}
|
||||
.collect { case (_, idx) => idx }
|
||||
.toList
|
||||
// test shorter prefixes first
|
||||
.reverse
|
||||
case _ => Nil
|
||||
}
|
||||
|
||||
lastSuitable.map(last =>
|
||||
val newProps = NonEmptyList.fromList(
|
||||
properties.toList.drop(last + 1)
|
||||
/**
|
||||
* Try to convert this token into `CallArrowToken`
|
||||
* e.g. `Some.Imported.Module.call(...)`
|
||||
* ^^^^^^^^^^^^^^^^^^^^ ^^^^
|
||||
* ability name function name
|
||||
*/
|
||||
def toCallArrow: Option[CallArrowToken[F]] = (
|
||||
value,
|
||||
properties.last
|
||||
) match {
|
||||
case (VarToken(name), IntoArrow(funcName, args)) =>
|
||||
properties.init.traverse {
|
||||
case IntoField(name) => name.extract.some
|
||||
case _ => none
|
||||
}.map { fields =>
|
||||
val imported = name
|
||||
.rename(
|
||||
(name.value +: fields).mkString(".")
|
||||
)
|
||||
val newName = props.take(last + 1).mkString(".")
|
||||
val varToken = VarToken(name.rename(newName))
|
||||
.asTypeToken
|
||||
|
||||
newProps.fold(varToken)(props => PropertyToken(varToken, props))
|
||||
CallArrowToken(
|
||||
imported.some,
|
||||
funcName,
|
||||
args
|
||||
)
|
||||
}
|
||||
case _ => none
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tries to convert property token to
|
||||
* call arrow token.
|
||||
*
|
||||
* Next properties pattern is transformed:
|
||||
* (Class)+ arrow()
|
||||
* ^^^^^^^
|
||||
* this part is transformed to ability name.
|
||||
* Try to convert this token into `NamedValueToken`,
|
||||
* e.g. `Some.Imported.Module.DefinedAbility(...)`
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
* type name
|
||||
*/
|
||||
private def toCallArrow: Option[CallArrowToken[F]] = value match {
|
||||
case VarToken(name) =>
|
||||
val ability = properties.init.traverse {
|
||||
case f @ IntoField(_) => f.value.some
|
||||
case _ => none
|
||||
}.map(
|
||||
name.value +: _
|
||||
).filter(
|
||||
_.forall(isClass)
|
||||
).map(props => name.rename(props.mkString(".")))
|
||||
def toNamedValue: Option[NamedValueToken[F]] =
|
||||
(value, properties.last) match {
|
||||
case (v @ VarToken(name), IntoApply(args)) =>
|
||||
properties.init.traverse {
|
||||
case IntoField(name) => name.extract.some
|
||||
case _ => none
|
||||
}.map { props =>
|
||||
val typeName = name
|
||||
.rename(
|
||||
(name.value +: props).mkString(".")
|
||||
)
|
||||
.asTypeToken
|
||||
|
||||
(properties.last, ability) match {
|
||||
case (IntoArrow(funcName, args), Some(ability)) =>
|
||||
CallArrowToken(
|
||||
ability.asTypeToken.some,
|
||||
funcName,
|
||||
args
|
||||
).some
|
||||
case _ => none
|
||||
}
|
||||
case _ => none
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a hacky method to adjust parsing result
|
||||
* to format that was used previously.
|
||||
* This method tries to convert property token to
|
||||
* call arrow token or property token with
|
||||
* dotted var name inside value token.
|
||||
*
|
||||
* @return Some(token) if token was adjusted, None otherwise
|
||||
*/
|
||||
def adjust: Option[ValueToken[F]] =
|
||||
toCallArrow.orElse(toDottedName)
|
||||
|
||||
lazy val leadingName: Option[NamedTypeToken[F]] =
|
||||
value match {
|
||||
case VarToken(name) => name.asTypeToken.some
|
||||
NamedValueToken(typeName, args.extract)
|
||||
}
|
||||
case _ => none
|
||||
}
|
||||
}
|
||||
|
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@ -37,7 +37,7 @@ importers:
|
||||
version: 1.9.1
|
||||
devDependencies:
|
||||
'@fluencelabs/aqua-api':
|
||||
specifier: 0.14.2
|
||||
specifier: 0.14.4
|
||||
version: link:../api/api-npm
|
||||
'@fluencelabs/aqua-lib':
|
||||
specifier: 0.10.2
|
||||
|
@ -72,7 +72,7 @@ class HeaderHandler[S[_]: Comonad, C](using
|
||||
.toValidNec(
|
||||
error(
|
||||
tkn,
|
||||
s"Used module has no `module` header. Please add `module` header or use ... as ModuleName, or switch to import"
|
||||
s"Used module has no `aqua` header. Please add `aqua` header or use ... as ModuleName, or switch to import"
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package aqua.semantics.rules
|
||||
|
||||
import aqua.errors.Errors.internalError
|
||||
import aqua.helpers.syntax.optiont.*
|
||||
import aqua.parser.lexer.*
|
||||
import aqua.parser.lexer.InfixToken.{BoolOp, CmpOp, EqOp, MathOp, Op as InfOp}
|
||||
@ -85,6 +86,8 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using
|
||||
idx <- OptionT(op.idx.fold(LiteralRaw.Zero.some.pure)(valueToRaw))
|
||||
valueType <- OptionT(T.resolveIntoIndex(op, rootType, idx.`type`))
|
||||
} yield IntoIndexRaw(idx, valueType)).value
|
||||
case op: IntoApply[S] =>
|
||||
internalError("Unexpected. `IntoApply` expected to be transformed into `NamedValueToken`")
|
||||
}
|
||||
|
||||
def valueToRaw(v: ValueToken[S]): Alg[Option[ValueRaw]] =
|
||||
@ -129,14 +132,29 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using
|
||||
* so here we try to differentiate them and adjust property
|
||||
* token accordingly.
|
||||
*/
|
||||
prop.leadingName.fold(default)(name =>
|
||||
A.isDefinedAbility(name)
|
||||
.flatMap(isDefined =>
|
||||
prop.adjust
|
||||
.filter(_ => isDefined)
|
||||
.fold(default)(valueToRaw)
|
||||
|
||||
val callArrow = OptionT
|
||||
.fromOption(prop.toCallArrow)
|
||||
.filterF(ca =>
|
||||
ca.ability.fold(false.pure)(
|
||||
A.isDefinedAbility
|
||||
)
|
||||
)
|
||||
)
|
||||
.widen[ValueToken[S]]
|
||||
|
||||
val ability = OptionT(
|
||||
prop.toAbility.findM { case (ab, _) =>
|
||||
// Test if name is an import
|
||||
A.isDefinedAbility(ab)
|
||||
}
|
||||
).map { case (_, token) => token }
|
||||
|
||||
val namedValue = OptionT
|
||||
.fromOption(prop.toNamedValue)
|
||||
.filterF(nv => T.resolveType(nv.typeName, mustBeDefined = false).map(_.isDefined))
|
||||
.widen[ValueToken[S]]
|
||||
|
||||
callArrow.orElse(ability).orElse(namedValue).foldF(default)(valueToRaw)
|
||||
|
||||
case dvt @ NamedValueToken(typeName, fields) =>
|
||||
(for {
|
||||
|
@ -19,7 +19,7 @@ trait TypesAlgebra[S[_], Alg[_]] {
|
||||
|
||||
def resolveArrowDef(arrowDef: ArrowTypeToken[S]): Alg[Option[ArrowType]]
|
||||
|
||||
def resolveServiceType(name: NamedTypeToken[S]): Alg[Option[ServiceType]]
|
||||
def resolveServiceType(name: NamedTypeToken[S], mustBeDefined: Boolean = true): Alg[Option[ServiceType]]
|
||||
|
||||
def defineAbilityType(
|
||||
name: NamedTypeToken[S],
|
||||
|
@ -76,14 +76,18 @@ class TypesInterpreter[S[_], X](using
|
||||
}.as(none)
|
||||
}
|
||||
|
||||
override def resolveServiceType(name: NamedTypeToken[S]): State[X, Option[ServiceType]] =
|
||||
resolveType(name).flatMap {
|
||||
override def resolveServiceType(
|
||||
name: NamedTypeToken[S],
|
||||
mustBeDefined: Boolean = true
|
||||
): State[X, Option[ServiceType]] =
|
||||
resolveType(name, mustBeDefined).flatMap {
|
||||
case Some(serviceType: ServiceType) =>
|
||||
serviceType.some.pure
|
||||
case Some(t) =>
|
||||
case Some(t) if mustBeDefined =>
|
||||
report.error(name, s"Type `$t` is not a service").as(none)
|
||||
case None =>
|
||||
case None if mustBeDefined =>
|
||||
report.error(name, s"Type `${name.value}` is not defined").as(none)
|
||||
case _ => none.pure
|
||||
}
|
||||
|
||||
override def defineAbilityType(
|
||||
|
Loading…
Reference in New Issue
Block a user