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
|
uses: ./.github/workflows/tests.yml
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.ref }}
|
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:
|
env:
|
||||||
FORCE_COLOR: true
|
FORCE_COLOR: true
|
||||||
NOX_IMAGE: "${{ inputs.nox-image }}"
|
|
||||||
FLUENCE_ENV: "${{ inputs.fluence-env }}"
|
FLUENCE_ENV: "${{ inputs.fluence-env }}"
|
||||||
|
FCLI_V_NOX: "${{ inputs.nox-image }}"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
aqua:
|
aqua:
|
||||||
@ -64,14 +64,17 @@ jobs:
|
|||||||
repository: fluencelabs/aqua
|
repository: fluencelabs/aqua
|
||||||
ref: ${{ inputs.ref }}
|
ref: ${{ inputs.ref }}
|
||||||
|
|
||||||
- name: Pull nox image
|
- name: Setup fcli
|
||||||
run: docker pull docker.fluence.dev/nox:feat-vm-425-aquavm-mem-limits-from-config-2_4983_1@sha256:71bc65e096931ad1abc92b166b0033f01a718084d0f275d070ea495353da2d89
|
uses: fluencelabs/setup-fluence@v1
|
||||||
|
|
||||||
- name: Run nox
|
|
||||||
uses: isbang/compose-action@v1.5.1
|
|
||||||
with:
|
with:
|
||||||
compose-file: ".github/e2e/docker-compose.yml"
|
artifact: fcli
|
||||||
down-flags: "--volumes"
|
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
|
- name: Cache Scala
|
||||||
uses: coursier/cache-action@v6
|
uses: coursier/cache-action@v6
|
||||||
|
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,5 +1,21 @@
|
|||||||
# Changelog
|
# 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)
|
## [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,
|
noXor = false,
|
||||||
targetType = "air",
|
targetType = "air",
|
||||||
tracing = false,
|
tracing = false,
|
||||||
noEmptyResponse = false,
|
noEmptyResponse = true,
|
||||||
}) {
|
}) {
|
||||||
return new AquaConfig(
|
return new AquaConfig(
|
||||||
logLevel,
|
logLevel,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@fluencelabs/aqua-api",
|
"name": "@fluencelabs/aqua-api",
|
||||||
"version": "0.14.2",
|
"version": "0.14.4",
|
||||||
"description": "Aqua API",
|
"description": "Aqua API",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
@ -72,7 +72,7 @@ object AquaConfig {
|
|||||||
noXor = cjs.noXor.getOrElse(false),
|
noXor = cjs.noXor.getOrElse(false),
|
||||||
noRelay = cjs.noRelay.getOrElse(false),
|
noRelay = cjs.noRelay.getOrElse(false),
|
||||||
tracing = cjs.tracing.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"
|
export bugLNG346
|
||||||
use timeout, someString from "hack.aqua" as P
|
|
||||||
|
|
||||||
export timeout
|
ability Promise:
|
||||||
|
yield() -> string
|
||||||
|
|
||||||
func timeout() -> string:
|
func done_nil() -> string:
|
||||||
res <- P.timeout()
|
<- ""
|
||||||
b = someString()
|
|
||||||
a = P.someString()
|
func done() -> Promise:
|
||||||
<- res
|
<- 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
|
export SuperFoo
|
||||||
|
|
||||||
const DECLARE_CONST = "declare_const"
|
const DECLARE_CONST = "declare_const"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import BundleJS.*
|
import BundleJS.*
|
||||||
|
|
||||||
val aquaVersion = "0.14.2"
|
val aquaVersion = "0.14.4"
|
||||||
|
|
||||||
val scalaV = "3.4.0"
|
val scalaV = "3.4.0"
|
||||||
val catsV = "2.10.0"
|
val catsV = "2.10.0"
|
||||||
|
@ -87,6 +87,25 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
|||||||
inside(funcs)(test)
|
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 {
|
"aqua compiler" should "compile a simple snippet to the right context" in {
|
||||||
|
|
||||||
val src = Map(
|
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 {
|
it should "create right topology" in {
|
||||||
val src = Map(
|
val src = Map(
|
||||||
"index.aqua" ->
|
"index.aqua" ->
|
||||||
@ -502,4 +502,385 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
|
|||||||
main.body.equalsOrShowDiff(expected) should be(true)
|
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": {},
|
"prettier": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fluencelabs/aqua-api": "0.14.2",
|
"@fluencelabs/aqua-api": "0.14.4",
|
||||||
"@fluencelabs/aqua-lib": "0.10.2",
|
"@fluencelabs/aqua-lib": "0.10.2",
|
||||||
"@types/jest": "29.5.11",
|
"@types/jest": "29.5.11",
|
||||||
"@types/node": "18.19.10",
|
"@types/node": "18.19.10",
|
||||||
|
@ -41,6 +41,7 @@ import {
|
|||||||
returnSrvAsAbilityCall,
|
returnSrvAsAbilityCall,
|
||||||
} from "../examples/abilityCall.js";
|
} from "../examples/abilityCall.js";
|
||||||
import { bugLNG314Call, bugLNG338Call } from "../examples/abilityClosureCall.js";
|
import { bugLNG314Call, bugLNG338Call } from "../examples/abilityClosureCall.js";
|
||||||
|
import { bugLNG346Call } from "../examples/abilityClosureRenameCall.js";
|
||||||
import {
|
import {
|
||||||
nilLengthCall,
|
nilLengthCall,
|
||||||
nilLiteralCall,
|
nilLiteralCall,
|
||||||
@ -670,6 +671,11 @@ describe("Testing examples", () => {
|
|||||||
expect(result).toEqual("job done");
|
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 () => {
|
it("functors.aqua LNG-119 bug", async () => {
|
||||||
let result = await bugLng119Call();
|
let result = await bugLng119Call();
|
||||||
expect(result).toEqual([1]);
|
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",
|
"name": "@fluencelabs/aqua-language-server-api",
|
||||||
"version": "0.14.2",
|
"version": "0.14.4",
|
||||||
"description": "Aqua Language Server API",
|
"description": "Aqua Language Server API",
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -507,9 +507,7 @@ object ArrowInliner extends Logging {
|
|||||||
* are prohibited because they are used inside **this function**.
|
* are prohibited because they are used inside **this function**.
|
||||||
*/
|
*/
|
||||||
defineNames <- StateT.liftF(
|
defineNames <- StateT.liftF(
|
||||||
fn.body.definesVarNames.map(
|
fn.body.definesVarNames
|
||||||
_ -- argNames -- capturedNames
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
defineRenames <- Mangler[S].findAndForbidNames(defineNames)
|
defineRenames <- Mangler[S].findAndForbidNames(defineNames)
|
||||||
canonStreamsWithNames <- canonStreamVariables(args)
|
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 Full(name, value) => Full(name.mapK(fk), value.mapK(fk))
|
||||||
case Short(variable) => Short(variable.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 {
|
object NamedArg {
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
package aqua.parser.lexer
|
package aqua.parser.lexer
|
||||||
|
|
||||||
|
import aqua.parser.lexer.CallArrowToken.CallBraces
|
||||||
|
import aqua.parser.lexer.NamedArg.namedArgs
|
||||||
import aqua.parser.lexer.Token.*
|
import aqua.parser.lexer.Token.*
|
||||||
import aqua.parser.lift.LiftParser
|
import aqua.parser.lift.LiftParser
|
||||||
import aqua.parser.lift.LiftParser.*
|
import aqua.parser.lift.LiftParser.*
|
||||||
import aqua.parser.lift.Span
|
import aqua.parser.lift.Span
|
||||||
import aqua.parser.lift.Span.{P0ToSpan, PToSpan}
|
import aqua.parser.lift.Span.{P0ToSpan, PToSpan}
|
||||||
import aqua.types.LiteralType
|
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.data.{NonEmptyList, NonEmptyMap}
|
||||||
import cats.parse.{Numbers, Parser as P, Parser0 as P0}
|
import cats.parse.{Numbers, Parser as P, Parser0 as P0}
|
||||||
import cats.syntax.comonad.*
|
import cats.syntax.comonad.*
|
||||||
import cats.syntax.functor.*
|
import cats.syntax.functor.*
|
||||||
import cats.{Comonad, Functor}
|
import cats.{Comonad, Functor}
|
||||||
|
import cats.~>
|
||||||
import scala.language.postfixOps
|
import scala.language.postfixOps
|
||||||
|
|
||||||
sealed trait PropertyOp[F[_]] extends Token[F] {
|
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))
|
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
|
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 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 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](
|
case class IntoCopy[F[_]: Comonad](
|
||||||
@ -56,6 +58,27 @@ case class IntoCopy[F[_]: Comonad](
|
|||||||
|
|
||||||
override def mapK[K[_]: Comonad](fk: F ~> K): IntoCopy[K] =
|
override def mapK[K[_]: Comonad](fk: F ~> K): IntoCopy[K] =
|
||||||
copy(fk(point), args.map(_.mapK(fk)))
|
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 {
|
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]] =
|
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]]] =
|
val ops: P[NonEmptyList[PropertyOp[Span.S]]] =
|
||||||
parseOp.rep
|
parseOp.rep
|
||||||
|
@ -121,9 +121,11 @@ case class ArrowTypeToken[S[_]: Comonad](
|
|||||||
args.map { case (n, t) => (n.map(_.mapK(fk)), t.mapK(fk)) },
|
args.map { case (n, t) => (n.map(_.mapK(fk)), t.mapK(fk)) },
|
||||||
res.map(_.mapK(fk)),
|
res.map(_.mapK(fk)),
|
||||||
abilities.map(_.mapK(fk))
|
abilities.map(_.mapK(fk))
|
||||||
)
|
)
|
||||||
def argTypes: List[TypeToken[S]] = abilities ++ args.map(_._2)
|
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 {
|
object ArrowTypeToken {
|
||||||
@ -136,9 +138,9 @@ object ArrowTypeToken {
|
|||||||
).map(_.toList)
|
).map(_.toList)
|
||||||
|
|
||||||
// {SomeAb, SecondAb} for NamedTypeToken
|
// {SomeAb, SecondAb} for NamedTypeToken
|
||||||
def abilities(): P0[List[NamedTypeToken[S]]] =
|
def abilities(): P0[List[NamedTypeToken[S]]] = (
|
||||||
(`{` *> comma(`Class`.surroundedBy(`/s*`).lift.map(NamedTypeToken(_)))
|
`{` *> comma(NamedTypeToken.dotted).map(_.toList) <* `}`
|
||||||
.map(_.toList) <* `}`).?.map(_.getOrElse(List.empty))
|
).?.map(_.getOrElse(List.empty))
|
||||||
|
|
||||||
def `arrowdef`(argTypeP: P[TypeToken[Span.S]]): P[ArrowTypeToken[Span.S]] =
|
def `arrowdef`(argTypeP: P[TypeToken[Span.S]]): P[ArrowTypeToken[Span.S]] =
|
||||||
((abilities() ~ comma0(argTypeP)).with1 ~ ` -> `.lift ~
|
((abilities() ~ comma0(argTypeP)).with1 ~ ` -> `.lift ~
|
||||||
|
@ -42,112 +42,105 @@ case class PropertyToken[F[_]: Comonad](
|
|||||||
name.forall(c => !c.isLetter || c.isUpper)
|
name.forall(c => !c.isLetter || c.isUpper)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method tries to convert property token to
|
* Try to transform this token to imported ability access
|
||||||
* property token with dotted var name inside value token.
|
* e.g. in `Some.Imported.Module.Ab.innerAb.call(...)`:
|
||||||
*
|
* - `Some.Imported.Module` is imported module name
|
||||||
* Next properties pattern is untouched:
|
* - `Ab.innerAb.call(...)` is ability access
|
||||||
* Class (field)*
|
* so it should be handled as `(Some.Imported.Module.Ab).innerAb.call(...)`
|
||||||
*
|
* ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
* Next properties pattern is transformed:
|
* ability name inside `VarToken` as one string
|
||||||
* (Class)* (CONST | field) ..props..
|
* 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
|
||||||
* this part is transformed to dotted name.
|
* 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 {
|
def toAbility: List[(NamedTypeToken[F], ValueToken[F])] =
|
||||||
case VarToken(name) =>
|
value match {
|
||||||
// Pattern `Class (field)*` is ability access
|
// NOTE: guard against recursion: if dot is alredy in the name, do not transform
|
||||||
// and should not be transformed
|
case VarToken(name) if !name.value.contains(".") =>
|
||||||
val isAbility = isClass(name.value) && properties.forall {
|
val fields = properties.toList.takeWhile {
|
||||||
case f @ IntoField(_) => isField(f.value)
|
case IntoField(_) => true
|
||||||
case _ => true
|
case _ => false
|
||||||
}
|
}.collect { case f @ IntoField(_) => f.value }.toList
|
||||||
|
val names = name.value +: fields
|
||||||
|
|
||||||
if (isAbility) none
|
fields.inits
|
||||||
else {
|
// do not use the last field
|
||||||
// Gather prefix of properties that are IntoField
|
// those cases are handled in `toCallArrow` and `toNamedValue`
|
||||||
val props = name.value +: properties.toList.view.map {
|
.drop(1)
|
||||||
case IntoField(name) => name.extract.some
|
.map { init =>
|
||||||
case _ => none
|
// Length of the import name
|
||||||
}.takeWhile(_.isDefined).flatten.toList
|
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
|
importAbility -> token
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
.collect { case (_, idx) => idx }
|
.toList
|
||||||
|
// test shorter prefixes first
|
||||||
|
.reverse
|
||||||
|
case _ => Nil
|
||||||
|
}
|
||||||
|
|
||||||
lastSuitable.map(last =>
|
/**
|
||||||
val newProps = NonEmptyList.fromList(
|
* Try to convert this token into `CallArrowToken`
|
||||||
properties.toList.drop(last + 1)
|
* 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(".")
|
.asTypeToken
|
||||||
val varToken = VarToken(name.rename(newName))
|
|
||||||
|
|
||||||
newProps.fold(varToken)(props => PropertyToken(varToken, props))
|
CallArrowToken(
|
||||||
|
imported.some,
|
||||||
|
funcName,
|
||||||
|
args
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case _ => none
|
case _ => none
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method tries to convert property token to
|
* Try to convert this token into `NamedValueToken`,
|
||||||
* call arrow token.
|
* e.g. `Some.Imported.Module.DefinedAbility(...)`
|
||||||
*
|
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
* Next properties pattern is transformed:
|
* type name
|
||||||
* (Class)+ arrow()
|
|
||||||
* ^^^^^^^
|
|
||||||
* this part is transformed to ability name.
|
|
||||||
*/
|
*/
|
||||||
private def toCallArrow: Option[CallArrowToken[F]] = value match {
|
def toNamedValue: Option[NamedValueToken[F]] =
|
||||||
case VarToken(name) =>
|
(value, properties.last) match {
|
||||||
val ability = properties.init.traverse {
|
case (v @ VarToken(name), IntoApply(args)) =>
|
||||||
case f @ IntoField(_) => f.value.some
|
properties.init.traverse {
|
||||||
case _ => none
|
case IntoField(name) => name.extract.some
|
||||||
}.map(
|
case _ => none
|
||||||
name.value +: _
|
}.map { props =>
|
||||||
).filter(
|
val typeName = name
|
||||||
_.forall(isClass)
|
.rename(
|
||||||
).map(props => name.rename(props.mkString(".")))
|
(name.value +: props).mkString(".")
|
||||||
|
)
|
||||||
|
.asTypeToken
|
||||||
|
|
||||||
(properties.last, ability) match {
|
NamedValueToken(typeName, args.extract)
|
||||||
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
|
|
||||||
case _ => none
|
case _ => none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@ -37,7 +37,7 @@ importers:
|
|||||||
version: 1.9.1
|
version: 1.9.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@fluencelabs/aqua-api':
|
'@fluencelabs/aqua-api':
|
||||||
specifier: 0.14.2
|
specifier: 0.14.4
|
||||||
version: link:../api/api-npm
|
version: link:../api/api-npm
|
||||||
'@fluencelabs/aqua-lib':
|
'@fluencelabs/aqua-lib':
|
||||||
specifier: 0.10.2
|
specifier: 0.10.2
|
||||||
|
@ -72,7 +72,7 @@ class HeaderHandler[S[_]: Comonad, C](using
|
|||||||
.toValidNec(
|
.toValidNec(
|
||||||
error(
|
error(
|
||||||
tkn,
|
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
|
package aqua.semantics.rules
|
||||||
|
|
||||||
|
import aqua.errors.Errors.internalError
|
||||||
import aqua.helpers.syntax.optiont.*
|
import aqua.helpers.syntax.optiont.*
|
||||||
import aqua.parser.lexer.*
|
import aqua.parser.lexer.*
|
||||||
import aqua.parser.lexer.InfixToken.{BoolOp, CmpOp, EqOp, MathOp, Op as InfOp}
|
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))
|
idx <- OptionT(op.idx.fold(LiteralRaw.Zero.some.pure)(valueToRaw))
|
||||||
valueType <- OptionT(T.resolveIntoIndex(op, rootType, idx.`type`))
|
valueType <- OptionT(T.resolveIntoIndex(op, rootType, idx.`type`))
|
||||||
} yield IntoIndexRaw(idx, valueType)).value
|
} 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]] =
|
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
|
* so here we try to differentiate them and adjust property
|
||||||
* token accordingly.
|
* token accordingly.
|
||||||
*/
|
*/
|
||||||
prop.leadingName.fold(default)(name =>
|
|
||||||
A.isDefinedAbility(name)
|
val callArrow = OptionT
|
||||||
.flatMap(isDefined =>
|
.fromOption(prop.toCallArrow)
|
||||||
prop.adjust
|
.filterF(ca =>
|
||||||
.filter(_ => isDefined)
|
ca.ability.fold(false.pure)(
|
||||||
.fold(default)(valueToRaw)
|
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) =>
|
case dvt @ NamedValueToken(typeName, fields) =>
|
||||||
(for {
|
(for {
|
||||||
|
@ -19,7 +19,7 @@ trait TypesAlgebra[S[_], Alg[_]] {
|
|||||||
|
|
||||||
def resolveArrowDef(arrowDef: ArrowTypeToken[S]): Alg[Option[ArrowType]]
|
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(
|
def defineAbilityType(
|
||||||
name: NamedTypeToken[S],
|
name: NamedTypeToken[S],
|
||||||
|
@ -76,14 +76,18 @@ class TypesInterpreter[S[_], X](using
|
|||||||
}.as(none)
|
}.as(none)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def resolveServiceType(name: NamedTypeToken[S]): State[X, Option[ServiceType]] =
|
override def resolveServiceType(
|
||||||
resolveType(name).flatMap {
|
name: NamedTypeToken[S],
|
||||||
|
mustBeDefined: Boolean = true
|
||||||
|
): State[X, Option[ServiceType]] =
|
||||||
|
resolveType(name, mustBeDefined).flatMap {
|
||||||
case Some(serviceType: ServiceType) =>
|
case Some(serviceType: ServiceType) =>
|
||||||
serviceType.some.pure
|
serviceType.some.pure
|
||||||
case Some(t) =>
|
case Some(t) if mustBeDefined =>
|
||||||
report.error(name, s"Type `$t` is not a service").as(none)
|
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)
|
report.error(name, s"Type `${name.value}` is not defined").as(none)
|
||||||
|
case _ => none.pure
|
||||||
}
|
}
|
||||||
|
|
||||||
override def defineAbilityType(
|
override def defineAbilityType(
|
||||||
|
Loading…
Reference in New Issue
Block a user