mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2025-06-29 07:41:35 +00:00
Implement wrapper compiler
This commit is contained in:
27
packages/core/aqua-wrapper/package.json
Normal file
27
packages/core/aqua-wrapper/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "@fluencelabs/aqua-wrapper",
|
||||||
|
"type": "module",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Tool for generating aqua wrapper",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Fluence Labs",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@fluencelabs/aqua-api": "0.12.0",
|
||||||
|
"@fluencelabs/aqua-lib": "0.7.3",
|
||||||
|
"@fluencelabs/interfaces": "workspace:*",
|
||||||
|
"@fluencelabs/js-client": "*",
|
||||||
|
"@fluencelabs/registry": "0.8.7",
|
||||||
|
"@fluencelabs/spell": "0.5.20",
|
||||||
|
"@fluencelabs/trust-graph": "0.4.7",
|
||||||
|
"ts-pattern": "5.0.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "5.1.6",
|
||||||
|
"vitest": "0.29.7"
|
||||||
|
}
|
||||||
|
}
|
98
packages/core/aqua-wrapper/src/common.ts
Normal file
98
packages/core/aqua-wrapper/src/common.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ArrowType, NonArrowType, ProductType } from '@fluencelabs/interfaces';
|
||||||
|
import { match, P } from 'ts-pattern';
|
||||||
|
import { getFuncArgs } from './utils.js';
|
||||||
|
|
||||||
|
export function genTypeName(t: NonArrowType, name: string): readonly [string | undefined, string] {
|
||||||
|
const genType = typeToTs(t);
|
||||||
|
return match(t)
|
||||||
|
.with(
|
||||||
|
{ tag: 'nil' },
|
||||||
|
() => [undefined, 'void'] as const
|
||||||
|
).with(
|
||||||
|
{ tag: 'struct' },
|
||||||
|
() => [`export type ${name} = ${genType}`, name] as const
|
||||||
|
).with(
|
||||||
|
{ tag: P.union('labeledProduct', 'unlabeledProduct') },
|
||||||
|
(item) => {
|
||||||
|
const args = item.tag === 'labeledProduct'
|
||||||
|
? Object.values(item.fields)
|
||||||
|
: item.items;
|
||||||
|
|
||||||
|
if (args.length === 1) {
|
||||||
|
return genTypeName(args[0], name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [`export type ${name} = ${genType}`, name] as const;
|
||||||
|
},
|
||||||
|
).otherwise(() => [undefined, genType] as const);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function typeToTs(t: NonArrowType | ArrowType<NonArrowType> | ProductType<NonArrowType>): string {
|
||||||
|
return match(t)
|
||||||
|
.with(
|
||||||
|
{ tag: 'nil' },
|
||||||
|
() => 'null'
|
||||||
|
).with(
|
||||||
|
{ tag: 'option' },
|
||||||
|
({ type }) => typeToTs(type) + ' | null'
|
||||||
|
).with(
|
||||||
|
{ tag: 'scalar' },
|
||||||
|
({ name }) => match(name)
|
||||||
|
.with(P.union('u8', 'u16', 'u32', 'u64', 'i8', 'i16', 'i32', 'i64', 'f32', 'f64'), () => 'number')
|
||||||
|
.with('bool', () => 'boolean')
|
||||||
|
.with('string', () => 'string')
|
||||||
|
.with(P._, () => 'any').exhaustive()
|
||||||
|
).with(
|
||||||
|
{ tag: 'array' },
|
||||||
|
({ type }) => typeToTs(type) + '[]'
|
||||||
|
).with(
|
||||||
|
{ tag: 'struct' },
|
||||||
|
({ fields }) => `{ ${Object.entries(fields).map(([field, type]) => `${field}: ${typeToTs(type)};`).join(' ')} }`
|
||||||
|
).with(
|
||||||
|
{ tag: 'labeledProduct' },
|
||||||
|
({ fields }) => `{ ${Object.entries(fields).map(([field, type]) => `${field}: ${typeToTs(type)};`).join(' ')} }`
|
||||||
|
).with(
|
||||||
|
{ tag: 'unlabeledProduct' },
|
||||||
|
({ items }) => `[${items.map(item => typeToTs(item)).join(', ')}]`
|
||||||
|
).with(
|
||||||
|
{ tag: 'arrow' },
|
||||||
|
({ tag, domain, codomain }) => {
|
||||||
|
const retType = codomain.tag === 'nil'
|
||||||
|
? 'void'
|
||||||
|
: codomain.items.length === 1
|
||||||
|
? typeToTs(codomain.items[0])
|
||||||
|
: typeToTs(codomain);
|
||||||
|
|
||||||
|
const args = getFuncArgs(domain).map(([name, type]) => ([name, typeToTs(type)]));
|
||||||
|
|
||||||
|
const generic = args.length === 0 ? 'null' : args.map(([name]) => `'${name}'`).join(' | ');
|
||||||
|
args.push(['callParams', `CallParams$$<${generic}>`]);
|
||||||
|
|
||||||
|
const funcArgs = args.map(([name, type]) => `${name}: ${type}`).join(', ');
|
||||||
|
|
||||||
|
return `(${funcArgs}) => ${retType} | Promise<${retType}>`;
|
||||||
|
}
|
||||||
|
).with(
|
||||||
|
{ tag: 'topType' },
|
||||||
|
() => 'unknown'
|
||||||
|
).with(
|
||||||
|
{ tag: 'bottomType' },
|
||||||
|
() => 'never'
|
||||||
|
).exhaustive();
|
||||||
|
}
|
17
packages/core/aqua-wrapper/src/constants.ts
Normal file
17
packages/core/aqua-wrapper/src/constants.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const CLIENT = 'IFluenceClient$$';
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe } from 'vitest';
|
||||||
|
|
||||||
|
describe('Aqua to js/ts compiler', () => {
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,87 @@
|
|||||||
|
aqua Main
|
||||||
|
|
||||||
|
use DECLARE_CONST, decl_bar from "imports_exports/declare.aqua" as Declare
|
||||||
|
|
||||||
|
export handleAb, SomeService, bug214, checkAbCalls
|
||||||
|
|
||||||
|
service SomeService("wed"):
|
||||||
|
getStr(s: string) -> string
|
||||||
|
|
||||||
|
ability SomeAb:
|
||||||
|
someArrow(s: string) -> string, string
|
||||||
|
str: string
|
||||||
|
|
||||||
|
ability SecondAb:
|
||||||
|
arrow(s: string) -> string
|
||||||
|
num: u32
|
||||||
|
|
||||||
|
func funcStr(s: string) -> string, string:
|
||||||
|
strInFunc <- SomeService.getStr(Declare.DECLARE_CONST)
|
||||||
|
strInFunc2 <- SomeService.getStr(s)
|
||||||
|
<- strInFunc, strInFunc2
|
||||||
|
|
||||||
|
func handleSecAb {SomeAb, SecondAb}() -> string, string, string, u32:
|
||||||
|
SomeAb.someArrow("eferfrfrf")
|
||||||
|
b, c <- SomeAb.someArrow("efre")
|
||||||
|
d <- SecondAb.arrow(SomeAb.str)
|
||||||
|
<- b, c, d, SecondAb.num
|
||||||
|
|
||||||
|
func returnAb(s: string) -> SomeAb:
|
||||||
|
SomeAb = SomeAb(someArrow = funcStr, str = s)
|
||||||
|
<- SomeAb
|
||||||
|
|
||||||
|
func handleAb(fff: string) -> string, string, string, u32:
|
||||||
|
SomeAb = returnAb(fff)
|
||||||
|
SecondAb = SecondAb(arrow = funcStr, num = 12)
|
||||||
|
res1, res2, res3, res4 <- handleSecAb{SomeAb, SecondAb}()
|
||||||
|
<- res1, res2, res3, res4
|
||||||
|
|
||||||
|
data Struct:
|
||||||
|
int: i8
|
||||||
|
|
||||||
|
ability Simple:
|
||||||
|
st: Struct
|
||||||
|
arrow(x: i8) -> bool
|
||||||
|
|
||||||
|
ability Complex:
|
||||||
|
simple: Simple
|
||||||
|
field: string
|
||||||
|
|
||||||
|
func foo{Complex, Simple}() -> bool, bool:
|
||||||
|
closure = () -> bool:
|
||||||
|
<- Simple.st.int >= 0
|
||||||
|
res <- closure()
|
||||||
|
<- Complex.simple.arrow(
|
||||||
|
Complex.simple.st.int
|
||||||
|
), res
|
||||||
|
|
||||||
|
func bug214() -> bool, bool:
|
||||||
|
closure = (x: i8) -> bool:
|
||||||
|
<- x > 0
|
||||||
|
|
||||||
|
MyComplex = Complex(
|
||||||
|
simple = Simple(
|
||||||
|
st = Struct(int = 0),
|
||||||
|
arrow = closure
|
||||||
|
),
|
||||||
|
field = "complex"
|
||||||
|
)
|
||||||
|
|
||||||
|
res1, res2 <- foo{MyComplex, MyComplex.simple}()
|
||||||
|
<- res1, res2
|
||||||
|
|
||||||
|
ability SSS:
|
||||||
|
arrow(x: i8) -> bool
|
||||||
|
|
||||||
|
ability CCCC:
|
||||||
|
arrow(x: i8) -> bool
|
||||||
|
simple: SSS
|
||||||
|
|
||||||
|
func checkAbCalls() -> bool, bool:
|
||||||
|
closure = (x: i8) -> bool:
|
||||||
|
<- x > 20
|
||||||
|
|
||||||
|
MySSS = SSS(arrow = closure)
|
||||||
|
MyCCCC = CCCC(simple = MySSS, arrow = MySSS.arrow)
|
||||||
|
|
||||||
|
<- MySSS.arrow(42), MyCCCC.arrow(12)
|
@ -0,0 +1,24 @@
|
|||||||
|
data SomeData:
|
||||||
|
value: string
|
||||||
|
otherValue: u64
|
||||||
|
|
||||||
|
data SubData:
|
||||||
|
someStr: string
|
||||||
|
someNum: i32
|
||||||
|
|
||||||
|
data SecondData:
|
||||||
|
value: string
|
||||||
|
complex: SubData
|
||||||
|
|
||||||
|
data ThirdData:
|
||||||
|
value: string
|
||||||
|
complex: SomeData
|
||||||
|
|
||||||
|
service ComplexService("op-ha"):
|
||||||
|
call(d: SomeData, sd: SecondData) -> SubData
|
||||||
|
identity() -> SecondData
|
||||||
|
|
||||||
|
func doSmth(d: SomeData, d2: SomeData, sd: SecondData, c: SubData, SecondData -> ThirdData) -> ThirdData:
|
||||||
|
res <- ComplexService.call(d, sd)
|
||||||
|
res2 <- c(res, sd)
|
||||||
|
<- res2
|
@ -0,0 +1,13 @@
|
|||||||
|
data Prod:
|
||||||
|
value: string
|
||||||
|
|
||||||
|
service OpHa("op"):
|
||||||
|
array(a: string, b: string) -> []string
|
||||||
|
identity(a: string) -> string
|
||||||
|
|
||||||
|
func doSmth(arg: Prod) -> []string:
|
||||||
|
v = arg.value
|
||||||
|
a <- OpHa.identity(v)
|
||||||
|
b = "hello"
|
||||||
|
res <- OpHa.array(a, b)
|
||||||
|
<- res
|
@ -0,0 +1,65 @@
|
|||||||
|
aqua Bool
|
||||||
|
|
||||||
|
export main, compareStreams, compareStructs, Effector
|
||||||
|
|
||||||
|
service Effector("effector"):
|
||||||
|
effect(name: string) -> bool
|
||||||
|
|
||||||
|
func foo(x: i8) -> bool:
|
||||||
|
y = x + 1
|
||||||
|
<- y < 5
|
||||||
|
|
||||||
|
func bar(x: i8) -> i8:
|
||||||
|
y = x - 1
|
||||||
|
<- y
|
||||||
|
|
||||||
|
func compareStreams(peer: string) -> bool:
|
||||||
|
s1: *i8
|
||||||
|
s2: *i8
|
||||||
|
|
||||||
|
on peer:
|
||||||
|
s1 <<- bar(43)
|
||||||
|
s2 <<- bar(43)
|
||||||
|
|
||||||
|
<- s1 == s2
|
||||||
|
|
||||||
|
data Struct:
|
||||||
|
field: i8
|
||||||
|
str: string
|
||||||
|
|
||||||
|
func compareStructs(peer: string, str: string) -> bool:
|
||||||
|
on peer:
|
||||||
|
st1 = Struct(field = 42, str = str)
|
||||||
|
st2 = Struct(field = 24, str = str)
|
||||||
|
|
||||||
|
<- st1 == st2
|
||||||
|
|
||||||
|
func main(peer: string) -> []bool:
|
||||||
|
res: *bool
|
||||||
|
|
||||||
|
on peer:
|
||||||
|
a = 1 + 2
|
||||||
|
b = 2 - 1
|
||||||
|
res <<- true || false && true -- true
|
||||||
|
res <<- (true || false) && true -- true
|
||||||
|
res <<- foo(3) && b > 0 || a > 4 -- true
|
||||||
|
res <<- bar(a) > 2 || true -- true
|
||||||
|
res <<- foo(4) && bar(2) < 2 -- false
|
||||||
|
res <<- !foo(10) && !!true -- true
|
||||||
|
res <<- !(bar(2) < 1) || !!(a < 2) -- true
|
||||||
|
res <<- bar(42) == bar(40 + 2) && foo(10) -- false
|
||||||
|
res <<- bar(2) < 5 || bar(2) != 1 -- true
|
||||||
|
|
||||||
|
-- Effector is only registered on init_peer
|
||||||
|
res <<- true || Effector.effect("impossible") -- true
|
||||||
|
res <<- !!false && Effector.effect("impossible") -- false
|
||||||
|
res <<- foo(0) || Effector.effect("impossible") -- true
|
||||||
|
res <<- foo(10) && Effector.effect("impossible") -- false
|
||||||
|
res <<- Effector.effect("true") || true -- true
|
||||||
|
res <<- Effector.effect("true") && false -- false
|
||||||
|
res <<- !foo(10) || Effector.effect("impossible") -- true
|
||||||
|
res <<- !(1 < 2) && !Effector.effect("impossible") -- false
|
||||||
|
res <<- !(bar(5) == 5) || Effector.effect("impossible") -- true
|
||||||
|
res <<- bar(5) != 4 && Effector.effect("impossible") -- false
|
||||||
|
|
||||||
|
<- res
|
@ -0,0 +1,16 @@
|
|||||||
|
import "println.aqua"
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
-- functions like `c` are called an 'arrow function' in Aqua
|
||||||
|
-- `c` passed to a function from a client, so, it could be called only on a client
|
||||||
|
func passFunctionAsArg(node: string, str: string, c: string -> string):
|
||||||
|
on node:
|
||||||
|
Peer.identify()
|
||||||
|
-- we go here back on a client
|
||||||
|
res <- c(str)
|
||||||
|
-- then return on a node
|
||||||
|
Peer.identify()
|
||||||
|
print(res)
|
||||||
|
|
||||||
|
func reproArgsBug426(log: string -> (), arg: string):
|
||||||
|
log(arg)
|
@ -0,0 +1,14 @@
|
|||||||
|
data Record:
|
||||||
|
relay_id: []string
|
||||||
|
peer_id: string
|
||||||
|
|
||||||
|
service Ser("ser"):
|
||||||
|
getRecord: -> Record
|
||||||
|
|
||||||
|
func bugLng79(log: string -> ()) -> u32:
|
||||||
|
stream: *Record
|
||||||
|
stream <- Ser.getRecord()
|
||||||
|
someone = stream[0]
|
||||||
|
on someone.peer_id via someone.relay_id:
|
||||||
|
a = 1 + 1
|
||||||
|
<- a
|
@ -0,0 +1,18 @@
|
|||||||
|
aqua ClosureReturnRename
|
||||||
|
|
||||||
|
export lng193Bug
|
||||||
|
|
||||||
|
func getClosure(arg: u16, peer: string) -> u16 -> u16:
|
||||||
|
on peer:
|
||||||
|
closure = (x: u16) -> u16:
|
||||||
|
<- arg + x
|
||||||
|
<- closure
|
||||||
|
|
||||||
|
func lng193Bug(peer: string, closurePeer: string) -> u16:
|
||||||
|
on peer:
|
||||||
|
c = getClosure(42, closurePeer)
|
||||||
|
b = c
|
||||||
|
a = b
|
||||||
|
res1 = a(1) + a(2) -- Call two times for
|
||||||
|
res2 = b(3) + b(4) -- bug to appear
|
||||||
|
<- res1 + res2
|
@ -0,0 +1,73 @@
|
|||||||
|
module Closure declares *
|
||||||
|
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
export LocalSrv, closureIn, closureOut, closureBig, closureOut2, lng58Bug
|
||||||
|
|
||||||
|
service MyOp("op"):
|
||||||
|
identity(s: string) -> string
|
||||||
|
|
||||||
|
service LocalSrv("local_srv"):
|
||||||
|
inside: -> ()
|
||||||
|
|
||||||
|
func closureIn(peer1: string) -> string:
|
||||||
|
variable = "const"
|
||||||
|
co on peer1:
|
||||||
|
p1Id <- MyOp.identity("co on")
|
||||||
|
closure = (s: string) -> string:
|
||||||
|
if s == "in":
|
||||||
|
LocalSrv.inside()
|
||||||
|
p2Id <- MyOp.identity(s)
|
||||||
|
<- p2Id
|
||||||
|
p <- closure("in")
|
||||||
|
<- p
|
||||||
|
|
||||||
|
func closureOut(peer2: string) -> Info:
|
||||||
|
on peer2:
|
||||||
|
closure = (s: string) -> Info:
|
||||||
|
if s == "in":
|
||||||
|
LocalSrv.inside()
|
||||||
|
p2Id <- Peer.identify()
|
||||||
|
<- p2Id
|
||||||
|
p2Id <- closure("on")
|
||||||
|
<- p2Id
|
||||||
|
|
||||||
|
func closureOut2(peer2: string) -> Info:
|
||||||
|
closure = func (s: string) -> Info:
|
||||||
|
if s == "in":
|
||||||
|
LocalSrv.inside()
|
||||||
|
p2Id <- Peer.identify()
|
||||||
|
<- p2Id
|
||||||
|
on peer2:
|
||||||
|
p2Id <- closure("on")
|
||||||
|
<- p2Id
|
||||||
|
|
||||||
|
|
||||||
|
func closureBig(peer1: string, peer2: string) -> string, string:
|
||||||
|
variable = "const"
|
||||||
|
co on peer1:
|
||||||
|
p1Id <- MyOp.identity("co on")
|
||||||
|
closure = func (s: string) -> string:
|
||||||
|
p2Id: *string
|
||||||
|
if s == "in":
|
||||||
|
p2 <- MyOp.identity(s)
|
||||||
|
p2Id <<- p2
|
||||||
|
else:
|
||||||
|
p2Info <- Peer.identify()
|
||||||
|
p2Id <<- p2Info.external_addresses!0
|
||||||
|
<- p2Id!
|
||||||
|
p <- closure("in")
|
||||||
|
on peer2:
|
||||||
|
p2Id <- closure("on")
|
||||||
|
<- p, p2Id
|
||||||
|
|
||||||
|
func lng58Bug() -> string:
|
||||||
|
status: *string
|
||||||
|
waiting = ():
|
||||||
|
avava: *string
|
||||||
|
avava <<- "frerf"
|
||||||
|
status <<- "ok"
|
||||||
|
|
||||||
|
waiting()
|
||||||
|
|
||||||
|
<- status!
|
@ -0,0 +1,13 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service CoService("coservice-id"):
|
||||||
|
call: -> string
|
||||||
|
|
||||||
|
-- here we go to another node and not waiting for execution there
|
||||||
|
-- all `ParService.call()` will be executed instantly
|
||||||
|
func coFunc( node: string, c: Info -> () ):
|
||||||
|
y <- CoService.call()
|
||||||
|
on node:
|
||||||
|
t <- Peer.identify()
|
||||||
|
co c(t)
|
||||||
|
x <- CoService.call()
|
@ -0,0 +1,43 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
func arraySugar(n: u32, m: u32) -> []u32, []u32:
|
||||||
|
arr = [1,2,n]
|
||||||
|
str: *u32
|
||||||
|
for i <- [4,5,m]:
|
||||||
|
str <<- i
|
||||||
|
<- arr, str
|
||||||
|
|
||||||
|
func streamSugar(n: u32, m: u32) -> []u32, []u32:
|
||||||
|
arr = *[1,2,n]
|
||||||
|
str: *u32
|
||||||
|
for i <- *[4,5,m]:
|
||||||
|
str <<- i
|
||||||
|
<- arr, str
|
||||||
|
|
||||||
|
func optionSugar(numSome: ?u32, strSome: ?string, numNone: ?u32, strNone: ?string) -> []u32, []string, []string:
|
||||||
|
arr = ?[numNone!, numSome!]
|
||||||
|
str: *string
|
||||||
|
str2 = ?[strNone!, strNone!, strNone!, strNone!, strNone!]
|
||||||
|
for i <- ?[strSome!,strNone!, "random string"]:
|
||||||
|
str <<- i
|
||||||
|
|
||||||
|
for i <- ?[strNone!,strNone!]:
|
||||||
|
str <<- i
|
||||||
|
<- arr, str, str2
|
||||||
|
|
||||||
|
service OpO("op"):
|
||||||
|
identity: string -> string
|
||||||
|
|
||||||
|
service GetArr("getArr"):
|
||||||
|
getArr: -> []string
|
||||||
|
|
||||||
|
func getNeighbours() -> []string:
|
||||||
|
nodes <- GetArr.getArr()
|
||||||
|
<- nodes
|
||||||
|
|
||||||
|
func bugLNG59() -> string:
|
||||||
|
nodes <- getNeighbours()
|
||||||
|
n = nodes[1]
|
||||||
|
on n via [HOST_PEER_ID]:
|
||||||
|
res <- OpO.identity("some str")
|
||||||
|
<- res
|
@ -0,0 +1,40 @@
|
|||||||
|
import "helloWorld.aqua"
|
||||||
|
import "println.aqua"
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
import "func.aqua"
|
||||||
|
|
||||||
|
service TestS("some-id"):
|
||||||
|
t: string -> string
|
||||||
|
multiline( -- comments
|
||||||
|
a: string, -- comments
|
||||||
|
b: string, -- comments
|
||||||
|
c: bool -- comments
|
||||||
|
) -> string -- comments
|
||||||
|
|
||||||
|
-- just a lot of imports and calls
|
||||||
|
func doStuff( -- comments
|
||||||
|
a: string, -- comments
|
||||||
|
b: string, -- comments
|
||||||
|
c: bool,
|
||||||
|
d: bool, e: []string, g: []string, str: string -- comments
|
||||||
|
) -> []string: -- comments
|
||||||
|
stream: *string
|
||||||
|
stream <- TestS.t(str)
|
||||||
|
par Println.print(a)
|
||||||
|
par on a:
|
||||||
|
Peer.identify()
|
||||||
|
on a:
|
||||||
|
on b:
|
||||||
|
if c:
|
||||||
|
if d:
|
||||||
|
for eEl <- e:
|
||||||
|
for gEl <- g:
|
||||||
|
stream <- TestS.t(gEl) -- comments
|
||||||
|
stream <- TestS.t(eEl)
|
||||||
|
stream <- TestS.t(eEl)
|
||||||
|
stream <- TestS.multiline( -- comments
|
||||||
|
a, -- comments
|
||||||
|
b, -- comments
|
||||||
|
c -- comments
|
||||||
|
) -- comments
|
||||||
|
<- stream
|
@ -0,0 +1,33 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service Getter("test"):
|
||||||
|
createStr: u32 -> string
|
||||||
|
|
||||||
|
service OpO("op"):
|
||||||
|
identity: string -> string
|
||||||
|
|
||||||
|
service OpN("op"):
|
||||||
|
identity: i32 -> i32
|
||||||
|
|
||||||
|
-- a question mark means that this constant could be rewritten before this definition
|
||||||
|
const ANOTHER_CONST ?= "default-str"
|
||||||
|
const UNIQUE_CONST ?= 5
|
||||||
|
|
||||||
|
func callConstant() -> []string:
|
||||||
|
res: *string
|
||||||
|
res <- Getter.createStr(UNIQUE_CONST)
|
||||||
|
res <- OpO.identity(ANOTHER_CONST)
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func timestampAndTtl() -> u32, u64:
|
||||||
|
Op.noop()
|
||||||
|
<- PARTICLE_TTL, PARTICLE_TIMESTAMP
|
||||||
|
|
||||||
|
const A = 2
|
||||||
|
const B = -3
|
||||||
|
|
||||||
|
func compareConstants():
|
||||||
|
if A == B:
|
||||||
|
OpN.identity(A)
|
||||||
|
else:
|
||||||
|
OpN.identity(B)
|
@ -0,0 +1,17 @@
|
|||||||
|
-- set `PeerId` name to be a type alias for `string` type
|
||||||
|
alias PeerId : string
|
||||||
|
|
||||||
|
-- define data structure (ADT)
|
||||||
|
data NodeId:
|
||||||
|
peerId: PeerId
|
||||||
|
name: string
|
||||||
|
|
||||||
|
-- define service `NodeIdGetter` that will be callable on local client via `somesrv` service id
|
||||||
|
service NodeIdGetter("somesrv"):
|
||||||
|
get: -> NodeId
|
||||||
|
|
||||||
|
-- showcases a function that gets data structure from a local service,
|
||||||
|
-- and then retrieves aliased data type from that structure
|
||||||
|
func getAliasedData() -> PeerId:
|
||||||
|
res <- NodeIdGetter.get()
|
||||||
|
<- res.peerId
|
@ -0,0 +1,20 @@
|
|||||||
|
service Peer("peer"):
|
||||||
|
is_connected: string -> bool
|
||||||
|
|
||||||
|
service Op("op"):
|
||||||
|
identity: -> ()
|
||||||
|
|
||||||
|
data User:
|
||||||
|
peer_id: string
|
||||||
|
relay_id: string
|
||||||
|
name: string
|
||||||
|
|
||||||
|
service Test("test"):
|
||||||
|
getUserList: -> []User
|
||||||
|
doSomething: -> bool
|
||||||
|
|
||||||
|
func betterMessage(relay: string):
|
||||||
|
on relay:
|
||||||
|
isOnline <- Peer.is_connected(relay)
|
||||||
|
if isOnline:
|
||||||
|
Test.doSomething()
|
@ -0,0 +1,24 @@
|
|||||||
|
import "println.aqua"
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
-- showcases `for` instruction that compiles to `fold` in AIR
|
||||||
|
func iterateAndPrint(strings: []string):
|
||||||
|
for s <- strings:
|
||||||
|
print(s)
|
||||||
|
|
||||||
|
func iterateAndPrintParallel(nodes: []string, c: Info -> ()):
|
||||||
|
for s <- nodes par:
|
||||||
|
on s:
|
||||||
|
ads <- Peer.identify()
|
||||||
|
c(ads)
|
||||||
|
|
||||||
|
func to_i_64(i: u32) -> i64:
|
||||||
|
<- i
|
||||||
|
|
||||||
|
func forBug499() -> []i64:
|
||||||
|
num = 5
|
||||||
|
numbers: *i64
|
||||||
|
for i <- [""]:
|
||||||
|
ali64 <- to_i_64(num)
|
||||||
|
numbers <<- ali64
|
||||||
|
<- numbers
|
@ -0,0 +1,19 @@
|
|||||||
|
module FoldJoin
|
||||||
|
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
export getTwoResults
|
||||||
|
|
||||||
|
service Op2("op"):
|
||||||
|
identity(s: u64)
|
||||||
|
|
||||||
|
func getTwoResults(node: string) -> []u64:
|
||||||
|
on node:
|
||||||
|
nodes <- Kademlia.neighborhood(%init_peer_id%, nil, nil)
|
||||||
|
res: *u64
|
||||||
|
for n <- nodes par:
|
||||||
|
on n:
|
||||||
|
try:
|
||||||
|
res <- Peer.timestamp_sec()
|
||||||
|
join res!2
|
||||||
|
<- res
|
@ -0,0 +1,6 @@
|
|||||||
|
service TestSrv("test-service-id"):
|
||||||
|
str: -> string
|
||||||
|
|
||||||
|
func testFunc() -> string:
|
||||||
|
res <- TestSrv.str()
|
||||||
|
<- res
|
@ -0,0 +1,39 @@
|
|||||||
|
module Funcs declares main, A, calc
|
||||||
|
|
||||||
|
export main, A, calc, calc2, ifCalc
|
||||||
|
|
||||||
|
service A("a"):
|
||||||
|
getJ(i: u32) -> u32
|
||||||
|
|
||||||
|
func main(log: string, []u32 -> ()) -> u32:
|
||||||
|
closure = (i: []u32, j: u32) -> u32:
|
||||||
|
some <- A.getJ(i[j])
|
||||||
|
<- some
|
||||||
|
closure2 = func (i: []u32, j: u32) -> u32:
|
||||||
|
some <- A.getJ(i[j])
|
||||||
|
<- some
|
||||||
|
arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
|
||||||
|
idx1 <- A.getJ(arr[A.getJ(3) + 2]) -- 5
|
||||||
|
idx2 <- A.getJ(arr[A.getJ(3) + 3] + arr[A.getJ(1) - 1] - 3) -- 3
|
||||||
|
<- A.getJ(arr[(idx1 + idx2) + closure(arr, 2) + closure2(arr, 3)]) -- should be 13
|
||||||
|
|
||||||
|
|
||||||
|
func calc(log: string, []u32 -> ()) -> u32:
|
||||||
|
arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
|
||||||
|
num <- A.getJ((5-2)*3-3) -- 6
|
||||||
|
log("calc 2", [num])
|
||||||
|
<- arr[num] -- should be 6
|
||||||
|
|
||||||
|
func calc2(log: string, []u32 -> ()) -> u32:
|
||||||
|
arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
|
||||||
|
num <- A.getJ((5-2) * 3 - 3 ** (A.getJ(5 + 5) - A.getJ(3 ** (3 - 1)))) -- 6
|
||||||
|
<- arr[num + num - A.getJ(num) - 3] -- should be 3
|
||||||
|
|
||||||
|
func ifCalc() -> u64:
|
||||||
|
arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
|
||||||
|
res: *u64
|
||||||
|
if A.getJ(8 - 2) + A.getJ(4 % 2) > arr[5 - 3 + A.getJ(3)] - 2:
|
||||||
|
res <<- 1
|
||||||
|
else:
|
||||||
|
res <<- 2
|
||||||
|
<- res!0
|
@ -0,0 +1,6 @@
|
|||||||
|
func lng119Bug() -> []u32:
|
||||||
|
nums = [1,2,3,4,5]
|
||||||
|
results: *u32
|
||||||
|
results <<- 1
|
||||||
|
join results[nums.length-5]
|
||||||
|
<- results
|
@ -0,0 +1,6 @@
|
|||||||
|
service StringExtra("service-id"):
|
||||||
|
addNameToHello: string -> string
|
||||||
|
|
||||||
|
func helloWorld(name: string) -> string:
|
||||||
|
res <- StringExtra.addNameToHello(name)
|
||||||
|
<- res
|
@ -0,0 +1,36 @@
|
|||||||
|
import "println.aqua"
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service OpR("op"):
|
||||||
|
identity(s: string) -> string
|
||||||
|
|
||||||
|
func ifElseCall(condition: bool):
|
||||||
|
if condition:
|
||||||
|
Println.print("it is true")
|
||||||
|
else:
|
||||||
|
Println.print("it is false")
|
||||||
|
|
||||||
|
func ifElseNumCall(condition: u32):
|
||||||
|
if condition == 1:
|
||||||
|
Println.print("it is 1")
|
||||||
|
else:
|
||||||
|
Println.print("it is not 1")
|
||||||
|
|
||||||
|
func ifCorrectXorWrap(node: string) -> string:
|
||||||
|
service_id: *string
|
||||||
|
on node:
|
||||||
|
res <- OpR.identity("1234")
|
||||||
|
if res == "":
|
||||||
|
service_id <<- "0x"
|
||||||
|
else:
|
||||||
|
service_id <<- "1x"
|
||||||
|
<- service_id!
|
||||||
|
|
||||||
|
func bugLNG69(other_node: PeerId) -> bool:
|
||||||
|
on other_node:
|
||||||
|
Op.noop()
|
||||||
|
|
||||||
|
if false:
|
||||||
|
Op.noop()
|
||||||
|
|
||||||
|
<- true
|
@ -0,0 +1,15 @@
|
|||||||
|
module FooBars declares decl_foo, decl_bar, SuperFoo, DECLARE_CONST, DECLARE_CONST2
|
||||||
|
export SuperFoo
|
||||||
|
|
||||||
|
const DECLARE_CONST = "declare_const"
|
||||||
|
const DECLARE_CONST2 = "declare_const2"
|
||||||
|
|
||||||
|
service SuperFoo("super_foo"):
|
||||||
|
small_foo() -> string
|
||||||
|
|
||||||
|
func decl_foo() -> string:
|
||||||
|
res1 <- SuperFoo.small_foo()
|
||||||
|
<- res1
|
||||||
|
|
||||||
|
func decl_bar() -> string:
|
||||||
|
<- "declare all bar"
|
@ -0,0 +1,16 @@
|
|||||||
|
module Export declares foobar, foo
|
||||||
|
|
||||||
|
import Op as Noop from "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
func bar() -> string:
|
||||||
|
<- " I am MyFooBar bar"
|
||||||
|
|
||||||
|
func foo() -> string:
|
||||||
|
<- "I am MyFooBar foo"
|
||||||
|
|
||||||
|
func foobar() -> []string:
|
||||||
|
Noop.noop()
|
||||||
|
res: *string
|
||||||
|
res <- foo()
|
||||||
|
res <- bar()
|
||||||
|
<- res
|
@ -0,0 +1,8 @@
|
|||||||
|
-- exports3.aqua
|
||||||
|
module Export3 declares *
|
||||||
|
|
||||||
|
import Op as Noop from "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
func foo() -> string:
|
||||||
|
Noop.noop()
|
||||||
|
<- "I am MyFooBar foo"
|
@ -0,0 +1,18 @@
|
|||||||
|
module Exports declares some_string, MyExportSrv, EXPORT_CONST, some_random_func
|
||||||
|
|
||||||
|
import Op as Noop from "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
export some_string as string_from_lib
|
||||||
|
export MyExportSrv
|
||||||
|
|
||||||
|
const EXPORT_CONST = "export_const"
|
||||||
|
|
||||||
|
service MyExportSrv("my_export_srv"):
|
||||||
|
another_str() -> string
|
||||||
|
|
||||||
|
func some_string() -> string:
|
||||||
|
Noop.noop()
|
||||||
|
<- "some_string_func"
|
||||||
|
|
||||||
|
func some_random_func() -> string:
|
||||||
|
<- "wow, so random"
|
@ -0,0 +1,2 @@
|
|||||||
|
service OneMore:
|
||||||
|
more_call()
|
@ -0,0 +1,18 @@
|
|||||||
|
module Import
|
||||||
|
import foobar from "export2.aqua"
|
||||||
|
|
||||||
|
use foo as f from "export2.aqua" as Exp
|
||||||
|
|
||||||
|
import "gen/OneMore.aqua"
|
||||||
|
|
||||||
|
import OneMore as OM from "gen/OneMore.aqua"
|
||||||
|
|
||||||
|
export foo_wrapper as wrap, foobar as barfoo
|
||||||
|
|
||||||
|
func foo_wrapper() -> string:
|
||||||
|
z <- Exp.f()
|
||||||
|
OneMore "hello"
|
||||||
|
OneMore.more_call()
|
||||||
|
OM "ohmygod"
|
||||||
|
OM.more_call()
|
||||||
|
<- z
|
@ -0,0 +1,12 @@
|
|||||||
|
-- imports3.aqua
|
||||||
|
module Import3 declares *
|
||||||
|
import Op as Noop from "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
export foo_wrapper
|
||||||
|
|
||||||
|
use "export3.aqua"
|
||||||
|
|
||||||
|
func foo_wrapper() -> string:
|
||||||
|
Noop.noop()
|
||||||
|
z <- Export3.foo()
|
||||||
|
<- z
|
@ -0,0 +1,6 @@
|
|||||||
|
import decl_foo, decl_bar from "declare.aqua"
|
||||||
|
use DECLARE_CONST, SuperFoo, DECLARE_CONST2 as DC2 from "declare.aqua" as Declare
|
||||||
|
import Op as Noop from "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
import some_string, MyExportSrv, EXPORT_CONST, some_random_func from "exports.aqua"
|
||||||
|
|
||||||
|
export some_string as some_str, some_random_func, MyExportSrv, EXPORT_CONST
|
@ -0,0 +1,23 @@
|
|||||||
|
import decl_foo, decl_bar from "declare.aqua"
|
||||||
|
use DECLARE_CONST, SuperFoo, DECLARE_CONST2 as DC2 from "declare.aqua" as Declare
|
||||||
|
import Op as Noop from "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
import some_string, MyExportSrv, EXPORT_CONST from "exports.aqua"
|
||||||
|
use "export3.aqua"
|
||||||
|
|
||||||
|
service StringService("string_service"):
|
||||||
|
concat(a: string, b: string) -> string
|
||||||
|
|
||||||
|
func concat_foobars() -> string:
|
||||||
|
Noop.noop()
|
||||||
|
Export3.foo()
|
||||||
|
res1 <- decl_foo()
|
||||||
|
res2 <- decl_bar()
|
||||||
|
res3 <- StringService.concat(res1, res2)
|
||||||
|
res4 <- Declare.SuperFoo.small_foo()
|
||||||
|
Noop.noop()
|
||||||
|
res5 <- StringService.concat(res3, res4)
|
||||||
|
res6 <- StringService.concat(res5, EXPORT_CONST)
|
||||||
|
res7 <- StringService.concat(res6, Declare.DECLARE_CONST)
|
||||||
|
Noop.noop()
|
||||||
|
res8 <- StringService.concat(res7, Declare.DC2)
|
||||||
|
<- res8
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
alias SomeString : string
|
||||||
|
|
||||||
|
data SomeResult:
|
||||||
|
one: SomeString
|
||||||
|
two: u32
|
||||||
|
|
||||||
|
service SubService("sub_service"):
|
||||||
|
sub(s: SomeString) -> SomeResult
|
||||||
|
|
||||||
|
func subImport() -> SomeResult:
|
||||||
|
res <- SubService.sub("some thing")
|
||||||
|
<- res
|
@ -0,0 +1,26 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
func joinIdxLocal(idx: i16, nodes: []string) -> []string:
|
||||||
|
nodes2: *string
|
||||||
|
for node <- nodes par:
|
||||||
|
nodes2 <<- node
|
||||||
|
join nodes2[idx], nodes
|
||||||
|
<- nodes2
|
||||||
|
|
||||||
|
func joinIdxRelay(idx: i16, nodes: []string) -> []string:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
nodes2: *string
|
||||||
|
for node <- nodes par:
|
||||||
|
nodes2 <<- node
|
||||||
|
join nodes2[idx], nodes
|
||||||
|
<- nodes2
|
||||||
|
|
||||||
|
func joinIdx(idx: i16, nodes: []string) -> []Info:
|
||||||
|
infos: *Info
|
||||||
|
nodes2: *string
|
||||||
|
for node <- nodes par:
|
||||||
|
on node:
|
||||||
|
infos <- Peer.identify()
|
||||||
|
nodes2 <<- node
|
||||||
|
join infos[idx-1+1], nodes2[idx-1+1]
|
||||||
|
<- infos
|
@ -0,0 +1,79 @@
|
|||||||
|
aqua Math
|
||||||
|
|
||||||
|
export test1, test2, testI16, testI32, testI64, testU64
|
||||||
|
|
||||||
|
func test1() -> u64:
|
||||||
|
res = 1 + 2 - 3 * 5 - 2 * 3 / 2 + 5
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func test2() -> u64:
|
||||||
|
res = 2 ** 2 ** (2 * 2 - 2) + 2 - 3 * 5 - 2 * 3 / 2 + 5 + (4 % 2 - 2)
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func getI8() -> i8:
|
||||||
|
<- -8
|
||||||
|
|
||||||
|
func getI16() -> i16:
|
||||||
|
<- -16
|
||||||
|
|
||||||
|
func getI32() -> i32:
|
||||||
|
<- -32
|
||||||
|
|
||||||
|
func getI64() -> i64:
|
||||||
|
<- -64
|
||||||
|
|
||||||
|
func getU8() -> u8:
|
||||||
|
<- 8
|
||||||
|
|
||||||
|
func getU16() -> u16:
|
||||||
|
<- 16
|
||||||
|
|
||||||
|
func getU32() -> u32:
|
||||||
|
<- 32
|
||||||
|
|
||||||
|
func getU64() -> u64:
|
||||||
|
<- 64
|
||||||
|
|
||||||
|
func testI16(peer: string) -> []i16:
|
||||||
|
res: *i16
|
||||||
|
|
||||||
|
on peer:
|
||||||
|
res <<- getI16() + getI16()
|
||||||
|
res <<- getI8() * getU8()
|
||||||
|
res <<- getI8() % getI16()
|
||||||
|
res <<- getI16() - getI8()
|
||||||
|
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func testI32(peer: string) -> []i32:
|
||||||
|
res: *i32
|
||||||
|
|
||||||
|
on peer:
|
||||||
|
res <<- getI32() + getU16()
|
||||||
|
res <<- getI16() * getU16()
|
||||||
|
res <<- getI8() % getU16()
|
||||||
|
res <<- getI16() - getI32()
|
||||||
|
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func testI64(peer: string) -> []i64:
|
||||||
|
res: *i64
|
||||||
|
|
||||||
|
on peer:
|
||||||
|
res <<- getI32() + getU32()
|
||||||
|
res <<- getI16() * getU32()
|
||||||
|
res <<- getI64() % getI64()
|
||||||
|
res <<- getU8() - getI64()
|
||||||
|
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func testU64(peer: string) -> []u64:
|
||||||
|
res: *u64
|
||||||
|
|
||||||
|
on peer:
|
||||||
|
res <<- getU32() + getU64()
|
||||||
|
res <<- getU64() * getU64()
|
||||||
|
res <<- getU64() % getU16()
|
||||||
|
res <<- getU8() - getU64()
|
||||||
|
|
||||||
|
<- res
|
@ -0,0 +1,22 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service GetStr("multiret-test"):
|
||||||
|
retStr: string -> string
|
||||||
|
|
||||||
|
service GetNum("multiret-num"):
|
||||||
|
retNum: -> u8
|
||||||
|
|
||||||
|
const SOME_NUM = 5
|
||||||
|
const SOME_STR = "some-str"
|
||||||
|
|
||||||
|
func tupleFunc() -> string, u8:
|
||||||
|
str <- GetStr.retStr(SOME_STR)
|
||||||
|
n <- GetNum.retNum()
|
||||||
|
<- str, n
|
||||||
|
|
||||||
|
func multiReturnFunc(somethingToReturn: []u8, smthOption: ?string) -> []string, u8, string, []u8, ?string, u8 :
|
||||||
|
res: *string
|
||||||
|
res <- GetStr.retStr(SOME_STR)
|
||||||
|
res <- GetStr.retStr("random-str")
|
||||||
|
res, tNum <- tupleFunc()
|
||||||
|
<- res, SOME_NUM, SOME_STR, somethingToReturn, smthOption, tNum
|
@ -0,0 +1,18 @@
|
|||||||
|
data NestedType:
|
||||||
|
val: string
|
||||||
|
|
||||||
|
data NestedStruct:
|
||||||
|
one: NestedType
|
||||||
|
|
||||||
|
service Test("service"):
|
||||||
|
test1() -> NestedStruct
|
||||||
|
test2(arg1: NestedType, arg2: string) -> NestedStruct
|
||||||
|
|
||||||
|
func test3() -> NestedType:
|
||||||
|
res <- Test.test1()
|
||||||
|
<- res.one
|
||||||
|
|
||||||
|
func test() -> NestedStruct:
|
||||||
|
struct <- test3()
|
||||||
|
res <- Test.test2(struct, struct.val)
|
||||||
|
<- res
|
@ -0,0 +1,12 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service OpH("opa"):
|
||||||
|
identity(s: string) -> string
|
||||||
|
|
||||||
|
func a(b: string) -> string:
|
||||||
|
c <- OpH.identity(b)
|
||||||
|
<- c
|
||||||
|
|
||||||
|
func d(e: string) -> string:
|
||||||
|
f <- a(e)
|
||||||
|
<- f
|
@ -0,0 +1,40 @@
|
|||||||
|
aqua StructCreation declares getObj, getObjRelay, getObjAssign
|
||||||
|
|
||||||
|
export getObj, getObjRelay, getObjAssign
|
||||||
|
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
data InnerObj:
|
||||||
|
arr: []string
|
||||||
|
num: u32
|
||||||
|
|
||||||
|
data SomeObj:
|
||||||
|
str: string
|
||||||
|
num: u64
|
||||||
|
inner: InnerObj
|
||||||
|
|
||||||
|
service OpNum("op"):
|
||||||
|
identity(n: u32) -> u32
|
||||||
|
|
||||||
|
service OpStr("op"):
|
||||||
|
identity(n: string) -> string
|
||||||
|
|
||||||
|
service OpArr("op"):
|
||||||
|
identity(arr: []string) -> []string
|
||||||
|
|
||||||
|
func getObj() -> SomeObj:
|
||||||
|
<- SomeObj(str = OpStr.identity("some str"), num = 5, inner = InnerObj(arr = ["a", "b", "c"], num = 6))
|
||||||
|
|
||||||
|
func getObjRelay() -> SomeObj:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
obj = SomeObj(str = "diff str", num = 5, inner = InnerObj(arr = OpArr.identity(["a", "b", "c"]), num = 6))
|
||||||
|
Op.noop()
|
||||||
|
<- obj.copy(str = "some str")
|
||||||
|
|
||||||
|
func getObjAssign() -> SomeObj, SomeObj, u32:
|
||||||
|
obj = SomeObj(str = "first str",
|
||||||
|
num = OpNum.identity(5),
|
||||||
|
inner = InnerObj(arr = ["d", "e", "f"], num = 7)
|
||||||
|
)
|
||||||
|
copiedObj = obj.copy(str = "some str", inner = obj.inner.copy(arr = ["a", "b", "c"])).copy(num = 6)
|
||||||
|
<- obj, copiedObj, copiedObj.inner.copy(arr = ["g"]).arr.length
|
@ -0,0 +1,12 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
func getPeerExternalAddresses(otherNodePeerId: string) -> []string:
|
||||||
|
on otherNodePeerId:
|
||||||
|
res <- Peer.identify()
|
||||||
|
<- res.external_addresses
|
||||||
|
|
||||||
|
-- it is possible to use `via` to built complex routes
|
||||||
|
func getDistantAddresses(target: string, viaNode: string) -> []string:
|
||||||
|
on target via viaNode:
|
||||||
|
res <- Peer.identify()
|
||||||
|
<- res.external_addresses
|
@ -0,0 +1,39 @@
|
|||||||
|
service Test("test-service"):
|
||||||
|
fail(err: string)
|
||||||
|
|
||||||
|
func onPropagate(peer: string, relay: string) -> u16:
|
||||||
|
res: *u16
|
||||||
|
on peer via relay:
|
||||||
|
res <<- 0 + 1
|
||||||
|
Test.fail("propagated error")
|
||||||
|
res <<- 0 + 2
|
||||||
|
|
||||||
|
join res[3] -- Unreachable
|
||||||
|
|
||||||
|
<- res[3]
|
||||||
|
|
||||||
|
func nestedOnPropagate(peer: string, relay: string, iPeer: string, iRelay: string, friend: string) -> u16:
|
||||||
|
res: *u16
|
||||||
|
on iPeer via iRelay:
|
||||||
|
res <<- 40 + 2
|
||||||
|
on friend:
|
||||||
|
res <<- 2 + 40
|
||||||
|
on peer via relay:
|
||||||
|
Test.fail("propagated error")
|
||||||
|
res <<- 30 + 7
|
||||||
|
|
||||||
|
join res[3] -- Unreachable
|
||||||
|
|
||||||
|
<- res[3]
|
||||||
|
|
||||||
|
func seqOnPropagate(peer: string, relay: string, iPeer: string, iRelay: string) -> u16:
|
||||||
|
res: *u16
|
||||||
|
on iPeer via iRelay:
|
||||||
|
res <<- 40 + 2
|
||||||
|
on peer via relay:
|
||||||
|
Test.fail("propagated error")
|
||||||
|
res <<- 30 + 7
|
||||||
|
|
||||||
|
join res[2] -- Unreachable
|
||||||
|
|
||||||
|
<- res[2]
|
@ -0,0 +1,25 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service SomeS("test2"):
|
||||||
|
getStr: ?string -> ?string
|
||||||
|
getStr1: -> ?string
|
||||||
|
getStr2: string -> string
|
||||||
|
checkU32(u: ?u32)
|
||||||
|
|
||||||
|
func checkU32AndU8(a: ?u8):
|
||||||
|
SomeS.checkU32(a)
|
||||||
|
|
||||||
|
func useOptional(opt: ?string) -> string:
|
||||||
|
res <- SomeS.getStr(opt)
|
||||||
|
for i <- opt:
|
||||||
|
SomeS.getStr2(i)
|
||||||
|
<- res!
|
||||||
|
|
||||||
|
func returnOptional() -> ?string:
|
||||||
|
res <- SomeS.getStr1()
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func returnNone() -> ?string:
|
||||||
|
result: *string
|
||||||
|
Op.noop()
|
||||||
|
<- result
|
@ -0,0 +1,21 @@
|
|||||||
|
service OptionString("opt_str"):
|
||||||
|
checkOption(str: ?string) -> string
|
||||||
|
|
||||||
|
func emptyString() -> ?string:
|
||||||
|
valueEmpty: ?string
|
||||||
|
<- valueEmpty
|
||||||
|
|
||||||
|
func checkEmpty() -> string:
|
||||||
|
empty <- emptyString()
|
||||||
|
res <- OptionString.checkOption(empty)
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func stringAsOption(str: string) -> ?string:
|
||||||
|
valueEmpty: ?string
|
||||||
|
valueEmpty <<- str
|
||||||
|
<- valueEmpty
|
||||||
|
|
||||||
|
func checkNoneEmpty(str: string) -> string:
|
||||||
|
nonEmpty <- stringAsOption(str)
|
||||||
|
res <- OptionString.checkOption(nonEmpty)
|
||||||
|
<- res
|
@ -0,0 +1,34 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service ParService("parservice-id"):
|
||||||
|
call: -> string
|
||||||
|
|
||||||
|
-- here we go to another node and not waiting for execution there
|
||||||
|
-- all `ParService.call()` will be executed instantly
|
||||||
|
func parFunc( node: string, c: Info -> () ):
|
||||||
|
y <- ParService.call()
|
||||||
|
par on node:
|
||||||
|
t <- Peer.identify()
|
||||||
|
c(t)
|
||||||
|
par x <- ParService.call()
|
||||||
|
|
||||||
|
func testTimeout(nodes: []string) -> string:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
|
||||||
|
results: *Info
|
||||||
|
|
||||||
|
for node <- nodes par:
|
||||||
|
on node:
|
||||||
|
results <- Peer.identify()
|
||||||
|
|
||||||
|
timeout: *string
|
||||||
|
join results[999]
|
||||||
|
par timeout <- Peer.timeout(400, "timeout")
|
||||||
|
|
||||||
|
status: *string
|
||||||
|
if timeout == nil:
|
||||||
|
status <<- "ok"
|
||||||
|
else:
|
||||||
|
status <<- timeout!
|
||||||
|
|
||||||
|
<- status!
|
@ -0,0 +1,26 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service NumOp("op"):
|
||||||
|
identity(n: u64) -> u64
|
||||||
|
|
||||||
|
data PeerRelay:
|
||||||
|
peer: string
|
||||||
|
relay: string
|
||||||
|
|
||||||
|
func testParSeq(peer1: string, peer2: string, peer3: string, relay1: string, relay2: string, relay3: string) -> string:
|
||||||
|
pr1 = PeerRelay(peer = peer1, relay = relay1)
|
||||||
|
pr2 = PeerRelay(peer = peer2, relay = relay2)
|
||||||
|
pr3 = PeerRelay(peer = peer3, relay = relay3)
|
||||||
|
peers = [pr1, pr2, pr3]
|
||||||
|
stream: *u64
|
||||||
|
stream2: *u64
|
||||||
|
parseq p <- peers on p.peer via p.relay:
|
||||||
|
stream <- Peer.timestamp_ms()
|
||||||
|
|
||||||
|
for p <- peers par:
|
||||||
|
on p.peer via p.relay:
|
||||||
|
join stream[peers.length - 1]
|
||||||
|
stream2 <<- Peer.timestamp_ms()
|
||||||
|
|
||||||
|
join stream2[peers.length - 1]
|
||||||
|
<- "ok"
|
@ -0,0 +1,24 @@
|
|||||||
|
import Op from "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service AquaDHT("test-dht"):
|
||||||
|
put_host_value(key: string, value: string, service_id: []string) -> string
|
||||||
|
|
||||||
|
func putHostValue(key: string, value: string, service_id: ?string) -> string:
|
||||||
|
res <- AquaDHT.put_host_value(key, value, service_id)
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func create_client_util(service_id: string) -> string:
|
||||||
|
res <- putHostValue("client-util", service_id, nil)
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func wait(successful: *bool, n: i16):
|
||||||
|
join successful[n - 1]
|
||||||
|
|
||||||
|
func bugLNG60(node: string) -> bool:
|
||||||
|
successful: *bool
|
||||||
|
nodes = [node]
|
||||||
|
for n <- nodes:
|
||||||
|
successful <<- true
|
||||||
|
|
||||||
|
wait(successful, 1)
|
||||||
|
<- true
|
@ -0,0 +1,5 @@
|
|||||||
|
service Println("println-service-id"):
|
||||||
|
print: string -> ()
|
||||||
|
|
||||||
|
func print(str: string):
|
||||||
|
Println.print(str)
|
@ -0,0 +1,9 @@
|
|||||||
|
service OpA("pop"):
|
||||||
|
get_str() -> string
|
||||||
|
|
||||||
|
func get_results() -> []string:
|
||||||
|
results: *string
|
||||||
|
results <<- "hello"
|
||||||
|
str <- OpA.get_str()
|
||||||
|
results <<- str
|
||||||
|
<- results
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
service YesNoService("yesno"):
|
||||||
|
get() -> string
|
||||||
|
|
||||||
|
func recursiveStream() -> []string, []string:
|
||||||
|
result: *string
|
||||||
|
loop: *string
|
||||||
|
loop <<- "yes"
|
||||||
|
for l <- loop:
|
||||||
|
if l == "yes":
|
||||||
|
loop <- YesNoService.get()
|
||||||
|
result <<- "success"
|
||||||
|
<- result, loop
|
@ -0,0 +1,25 @@
|
|||||||
|
aqua RenameVars
|
||||||
|
|
||||||
|
export rename_s
|
||||||
|
|
||||||
|
func append_func(s: *string):
|
||||||
|
s <<- "ok"
|
||||||
|
|
||||||
|
func append(s: string, closure: *string -> ()) -> *string:
|
||||||
|
status: *string
|
||||||
|
|
||||||
|
append_func(status)
|
||||||
|
closure(status)
|
||||||
|
|
||||||
|
<- status
|
||||||
|
|
||||||
|
func rename_s() -> []string:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
append_closure = (s: *string):
|
||||||
|
s <<- "ok"
|
||||||
|
-- s inside append_func and append_closure
|
||||||
|
-- are not related to this s and should be
|
||||||
|
-- renamed to `status` and not `s-<n>`
|
||||||
|
s = "s"
|
||||||
|
res <- append(s, append_closure)
|
||||||
|
<- res
|
@ -0,0 +1,33 @@
|
|||||||
|
aqua ReturnArrow
|
||||||
|
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
export callReturnedArrow, callReturnedChainArrow
|
||||||
|
|
||||||
|
func returnCall(arg: string) -> string -> string, string:
|
||||||
|
str <- Op.concat_strings(arg, " literal")
|
||||||
|
closure = (s: string) -> string, string:
|
||||||
|
<- s, Op.concat_strings(s, str)
|
||||||
|
<- closure
|
||||||
|
|
||||||
|
func callReturnedArrow(argForFunc: string, argForClosure: string) -> string, string:
|
||||||
|
a = returnCall(argForFunc)
|
||||||
|
b, c <- a(argForClosure)
|
||||||
|
<- b, c
|
||||||
|
|
||||||
|
func secondReturnCall(arg: string) -> (string -> string, string), (string -> string, string), (string -> string, string):
|
||||||
|
str <- Op.concat_strings(arg, " second literal")
|
||||||
|
closure = (s: string) -> string, string:
|
||||||
|
<- s, Op.concat_strings(s, str)
|
||||||
|
b = closure
|
||||||
|
a = returnCall(" from second")
|
||||||
|
<- b, closure, a
|
||||||
|
|
||||||
|
func callReturnedChainArrow(argForFirst: string, argForSecond: string) -> string, string, string, string, string, string, string, string:
|
||||||
|
first = returnCall(argForFirst)
|
||||||
|
second, third, fourth <- secondReturnCall(argForSecond)
|
||||||
|
a, b <- first("first")
|
||||||
|
c, d <- second("second")
|
||||||
|
e, f <- third("third")
|
||||||
|
g, h <- fourth("fourth")
|
||||||
|
<- a, b, c, d, e, f, g, h
|
@ -0,0 +1,2 @@
|
|||||||
|
func returnLiteral() -> string:
|
||||||
|
<- "some literal"
|
@ -0,0 +1,69 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
import "println.aqua"
|
||||||
|
|
||||||
|
service Stringer("stringer-id"):
|
||||||
|
returnString: string -> string
|
||||||
|
|
||||||
|
func checkStreams(ch: []string) -> []string:
|
||||||
|
stream: *string
|
||||||
|
stream <- Stringer.returnString("first")
|
||||||
|
stream <- Stringer.returnString("second")
|
||||||
|
for b <- ch:
|
||||||
|
stream <- Stringer.returnString(b)
|
||||||
|
<- stream
|
||||||
|
|
||||||
|
func getStream() -> *u32:
|
||||||
|
nums = *[1,2,3,4]
|
||||||
|
<- nums
|
||||||
|
|
||||||
|
func returnStreamFromFunc() -> *u32:
|
||||||
|
nums <- getStream()
|
||||||
|
<- nums
|
||||||
|
|
||||||
|
func stringNil() -> *string:
|
||||||
|
valueNil: *string
|
||||||
|
<- valueNil
|
||||||
|
|
||||||
|
func returnNil() -> *string:
|
||||||
|
relayNil <- stringNil()
|
||||||
|
<- relayNil
|
||||||
|
|
||||||
|
func returnNilLiteral() -> *string:
|
||||||
|
<- nil
|
||||||
|
|
||||||
|
func returnNilLength() -> u32:
|
||||||
|
arr = nil
|
||||||
|
<- arr.length
|
||||||
|
|
||||||
|
func stringNone() -> ?string:
|
||||||
|
valueNone: ?string
|
||||||
|
<- valueNone
|
||||||
|
|
||||||
|
func returnNone() -> ?string:
|
||||||
|
relayNone <- stringNone()
|
||||||
|
<- relayNone
|
||||||
|
|
||||||
|
func streamFunctor(arr: []string) -> string:
|
||||||
|
stream: *[]string
|
||||||
|
stream <<- ["123"]
|
||||||
|
a = stream[arr.length - 1][0]
|
||||||
|
<- a
|
||||||
|
|
||||||
|
func streamAssignment(arr: []string) -> string:
|
||||||
|
stream: *[]u32
|
||||||
|
stream <<- [0]
|
||||||
|
a = stream[arr.length - 1][0]
|
||||||
|
b = arr[a]
|
||||||
|
<- b
|
||||||
|
|
||||||
|
func streamIntFunctor(arr: []u32) -> string:
|
||||||
|
stream: *[]string
|
||||||
|
stream <<- ["123"]
|
||||||
|
a = stream[arr[0]][arr[0]]
|
||||||
|
<- a
|
||||||
|
|
||||||
|
func streamJoin(arr: []string) -> string:
|
||||||
|
streamJ: *[]string
|
||||||
|
streamJ <<- ["111", "222"]
|
||||||
|
streamJ <<- ["333", "444"]
|
||||||
|
<- streamJ[arr.length][1]
|
@ -0,0 +1,10 @@
|
|||||||
|
service TestService("test-service"):
|
||||||
|
get_records(key: string) -> []string
|
||||||
|
|
||||||
|
func append_records(peer: string, srum: *[]string):
|
||||||
|
srum <- TestService.get_records(peer)
|
||||||
|
|
||||||
|
func retrieve_records(peer: string) -> [][]string:
|
||||||
|
records: *[]string
|
||||||
|
append_records(peer, records)
|
||||||
|
<- records
|
@ -0,0 +1,7 @@
|
|||||||
|
module Ret declares *
|
||||||
|
|
||||||
|
export someFunc
|
||||||
|
|
||||||
|
func someFunc(cb: []string -> ()):
|
||||||
|
ifaces: *string
|
||||||
|
cb(ifaces)
|
@ -0,0 +1,46 @@
|
|||||||
|
export accumRes, bugLNG63, bugLNG63_2
|
||||||
|
|
||||||
|
func toOpt(s: string) -> ?string:
|
||||||
|
str: *string
|
||||||
|
str <<- s
|
||||||
|
<- str
|
||||||
|
|
||||||
|
func accumRes() -> *?string:
|
||||||
|
res_accum: *?string
|
||||||
|
a <- toOpt("a")
|
||||||
|
res_accum <<- a
|
||||||
|
res_accum <- toOpt("b")
|
||||||
|
res_accum <<- nil
|
||||||
|
<- res_accum
|
||||||
|
|
||||||
|
func returnCanStream() -> string:
|
||||||
|
status: *string
|
||||||
|
status <<- "ok"
|
||||||
|
stat = status!
|
||||||
|
<- stat
|
||||||
|
|
||||||
|
service Op1("op"):
|
||||||
|
array_length(array: []string) -> u32
|
||||||
|
|
||||||
|
func bugLNG63() -> string:
|
||||||
|
res <- returnCanStream()
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func returnMultipleStreamResults() -> string, []string, []string, []string:
|
||||||
|
status: *string
|
||||||
|
status <<- "ok"
|
||||||
|
stat = status!
|
||||||
|
<- stat, status, [status!, stat], [status!, "no", status!]
|
||||||
|
|
||||||
|
func bugLNG63_2() -> string, []string, []string:
|
||||||
|
res, res2, res3, res4 <- returnMultipleStreamResults()
|
||||||
|
<- res, res2, res4
|
||||||
|
|
||||||
|
func bugLNG63_3() -> string, u32, []u32:
|
||||||
|
status: *string
|
||||||
|
status <<- "ok"
|
||||||
|
stat = status!
|
||||||
|
num: *u32
|
||||||
|
num <<- 2
|
||||||
|
res = [Op1.array_length(status), num!]
|
||||||
|
<- status!, Op1.array_length(status), [Op1.array_length(status), 3, num!]
|
@ -0,0 +1,10 @@
|
|||||||
|
func streamFold(arr: []string) -> []string:
|
||||||
|
res: *string
|
||||||
|
for n <- arr:
|
||||||
|
res <<- n
|
||||||
|
<- res
|
||||||
|
|
||||||
|
func streamRes(arr: []string) -> []string, []string:
|
||||||
|
res: *string
|
||||||
|
res2 <- streamFold(arr)
|
||||||
|
<- res, res2
|
@ -0,0 +1,16 @@
|
|||||||
|
data DT:
|
||||||
|
field: string
|
||||||
|
|
||||||
|
service DTGetter("get-dt"):
|
||||||
|
get_dt(s: string) -> DT
|
||||||
|
|
||||||
|
func use_name1(name: string) -> string:
|
||||||
|
results <- DTGetter.get_dt(name)
|
||||||
|
<- results.field
|
||||||
|
|
||||||
|
func use_name2(name: string) -> []string:
|
||||||
|
results: *string
|
||||||
|
results <- use_name1(name)
|
||||||
|
results <- use_name1(name)
|
||||||
|
results <- use_name1(name)
|
||||||
|
<- results
|
@ -0,0 +1,83 @@
|
|||||||
|
aqua StreamExports
|
||||||
|
|
||||||
|
export FailureSrv, streamIf, streamTry, streamFor, streamComplex
|
||||||
|
|
||||||
|
service FailureSrv("failure"):
|
||||||
|
fail(msg: string)
|
||||||
|
|
||||||
|
func streamIf() -> i8:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
if true:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 1
|
||||||
|
else:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 2
|
||||||
|
|
||||||
|
if false:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 3
|
||||||
|
else:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 4
|
||||||
|
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 5
|
||||||
|
|
||||||
|
<- stream!
|
||||||
|
|
||||||
|
func streamTry() -> i8:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
try:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 1
|
||||||
|
FailureSrv.fail("try")
|
||||||
|
catch e:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 2
|
||||||
|
FailureSrv.fail("catch")
|
||||||
|
otherwise:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 3
|
||||||
|
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 4
|
||||||
|
|
||||||
|
<- stream!
|
||||||
|
|
||||||
|
func streamFor() -> i8:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
for i <- [1, 2, 3]:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- i
|
||||||
|
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 4
|
||||||
|
|
||||||
|
<- stream!
|
||||||
|
|
||||||
|
func streamComplex() -> i8:
|
||||||
|
on HOST_PEER_ID:
|
||||||
|
for i <- [1, 2, 3]:
|
||||||
|
try:
|
||||||
|
if i == 2:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- i
|
||||||
|
FailureSrv.fail("if")
|
||||||
|
else:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- i
|
||||||
|
|
||||||
|
stream: *i8
|
||||||
|
stream <<- i + 3
|
||||||
|
catch e:
|
||||||
|
stream: *i8
|
||||||
|
stream <<- i + 6
|
||||||
|
|
||||||
|
stream: *i8
|
||||||
|
stream <<- i + 9
|
||||||
|
|
||||||
|
stream: *i8
|
||||||
|
stream <<- 13
|
||||||
|
|
||||||
|
<- stream!
|
@ -0,0 +1,35 @@
|
|||||||
|
aqua Aaa
|
||||||
|
|
||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
export structuralTypingTest
|
||||||
|
|
||||||
|
data WideData:
|
||||||
|
s: string
|
||||||
|
n: u32
|
||||||
|
|
||||||
|
data ExactData:
|
||||||
|
s: string
|
||||||
|
|
||||||
|
ability ExactAbility:
|
||||||
|
s: string
|
||||||
|
arr(s: string, s2: string, s3: string, s4: string) -> string
|
||||||
|
exact: ExactData
|
||||||
|
|
||||||
|
ability WideAbility:
|
||||||
|
s: string
|
||||||
|
arr(s: string, s2: string, s3: string, s4: string) -> string
|
||||||
|
g: string
|
||||||
|
exact: WideData
|
||||||
|
|
||||||
|
func ss(s1: string, s2: string, s3: string, s4: string) -> string:
|
||||||
|
<- Op.concat_strings(Op.concat_strings(Op.concat_strings(s1, s2), s3), s4)
|
||||||
|
|
||||||
|
func main{ExactAbility}(someData: ExactData, secondData: ExactData) -> string:
|
||||||
|
<- ExactAbility.arr(someData.s, ExactAbility.exact.s, secondData.s, ExactAbility.s)
|
||||||
|
|
||||||
|
func structuralTypingTest() -> string:
|
||||||
|
wd = WideData(s = "some_string", n = 32)
|
||||||
|
|
||||||
|
WAbility = WideAbility(s = "ab_string", g = "", arr = ss, exact = wd)
|
||||||
|
<- main{WAbility}(wd, WAbility.exact)
|
@ -0,0 +1,11 @@
|
|||||||
|
import "imports_exports/subImport.aqua"
|
||||||
|
|
||||||
|
service ConcatSubs("concat_subs"):
|
||||||
|
get_some(s: SomeString, sr: SomeResult) -> SomeResult
|
||||||
|
|
||||||
|
func subImportUsage(s: SomeString) -> SomeResult:
|
||||||
|
sr1 <- SubService.sub(s)
|
||||||
|
sr2 <- subImport()
|
||||||
|
result <- ConcatSubs.get_some(sr1.one, sr2)
|
||||||
|
<- result
|
||||||
|
|
@ -0,0 +1,12 @@
|
|||||||
|
aqua TopBottom
|
||||||
|
|
||||||
|
export S, topBottom
|
||||||
|
|
||||||
|
-- this file should just compile
|
||||||
|
|
||||||
|
service S(""):
|
||||||
|
top(t: ⊤) -> ⊤
|
||||||
|
bottom(b: ⊥) -> ⊥
|
||||||
|
|
||||||
|
func topBottom(t: ⊤, b: ⊥) -> ⊤, ⊥:
|
||||||
|
<- S.top(t), S.bottom(b)
|
@ -0,0 +1,53 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service Testo("testo"):
|
||||||
|
getString: string -> string
|
||||||
|
|
||||||
|
service LocalPrint("lp"):
|
||||||
|
print: string -> ()
|
||||||
|
|
||||||
|
service Opop("op"):
|
||||||
|
identity(s: string) -> string
|
||||||
|
|
||||||
|
|
||||||
|
func topologyTest(me: string, myRelay: string, friend: string, friendRelay: string) -> string:
|
||||||
|
on friend via friendRelay:
|
||||||
|
str2 <- Testo.getString("friends string via")
|
||||||
|
par LocalPrint.print("my string in par")
|
||||||
|
LocalPrint.print(str2)
|
||||||
|
<- "finish"
|
||||||
|
|
||||||
|
func topologyBug205(node_id: string, n2: ?string) -> []string:
|
||||||
|
nodes: *PeerId
|
||||||
|
on node_id:
|
||||||
|
a <- Op.identity(n2)
|
||||||
|
nodes <<- a!
|
||||||
|
on node_id:
|
||||||
|
for n <- nodes par:
|
||||||
|
on n:
|
||||||
|
Peer.identify()
|
||||||
|
<- nodes
|
||||||
|
|
||||||
|
service IOp("op"):
|
||||||
|
identity: string -> string
|
||||||
|
|
||||||
|
func topologyBug394(peer: string, peer2: string, peer3: string) -> string:
|
||||||
|
-- execute computation on a Peer in the network
|
||||||
|
on peer:
|
||||||
|
comp <- IOp.identity(%init_peer_id%)
|
||||||
|
|
||||||
|
-- send the result to target browser in the background
|
||||||
|
co on peer2 via peer3:
|
||||||
|
res <- IOp.identity(%init_peer_id%)
|
||||||
|
|
||||||
|
-- send the result to the initiator
|
||||||
|
<- comp
|
||||||
|
|
||||||
|
func topologyBug427(peers: []string) -> []string:
|
||||||
|
results: *string
|
||||||
|
for peer <- peers par:
|
||||||
|
on peer:
|
||||||
|
results <- Opop.identity("some string")
|
||||||
|
|
||||||
|
join results[1]
|
||||||
|
<- results
|
@ -0,0 +1,25 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
service Unexisted("unex"):
|
||||||
|
getStr() -> string
|
||||||
|
|
||||||
|
data LastError:
|
||||||
|
instruction: string
|
||||||
|
message: string
|
||||||
|
peer_id: string
|
||||||
|
|
||||||
|
service OpA("op"):
|
||||||
|
identity(s: string) -> string
|
||||||
|
|
||||||
|
func tryCatchTest(node_id: string) -> []string:
|
||||||
|
on node_id:
|
||||||
|
f: *string
|
||||||
|
try:
|
||||||
|
f <- Unexisted.getStr()
|
||||||
|
catch err:
|
||||||
|
c: *string
|
||||||
|
f <- OpA.identity(err.message)
|
||||||
|
-- check if the call takes place on the node
|
||||||
|
i <- Peer.identify()
|
||||||
|
f <- OpA.identity(i.external_addresses!)
|
||||||
|
<- f
|
@ -0,0 +1,19 @@
|
|||||||
|
service Unexisted("unex"):
|
||||||
|
getStr() -> string
|
||||||
|
|
||||||
|
data LastError:
|
||||||
|
instruction: string
|
||||||
|
msg: string
|
||||||
|
peer_id: string
|
||||||
|
|
||||||
|
service OpE("op"):
|
||||||
|
identity(s: string) -> string
|
||||||
|
|
||||||
|
func tryOtherwiseTest(node_id: string) -> string:
|
||||||
|
on node_id:
|
||||||
|
f: *string
|
||||||
|
try:
|
||||||
|
f <- Unexisted.getStr()
|
||||||
|
otherwise:
|
||||||
|
f <- OpE.identity("error")
|
||||||
|
<- f!
|
@ -0,0 +1,17 @@
|
|||||||
|
import "@fluencelabs/aqua-lib/builtin.aqua"
|
||||||
|
|
||||||
|
func viaArr(node_id: string, viaAr: []string) -> Info:
|
||||||
|
on node_id via viaAr:
|
||||||
|
p <- Peer.identify()
|
||||||
|
<- p
|
||||||
|
|
||||||
|
|
||||||
|
func viaStream(node_id: string, viaStr: *string) -> Info:
|
||||||
|
on node_id via viaStr:
|
||||||
|
p <- Peer.identify()
|
||||||
|
<- p
|
||||||
|
|
||||||
|
func viaOpt(relay: string, node_id: string, viaOpt: ?string) -> Info:
|
||||||
|
on node_id via viaOpt:
|
||||||
|
p <- Peer.identify()
|
||||||
|
<- p
|
46
packages/core/aqua-wrapper/src/generate/function.ts
Normal file
46
packages/core/aqua-wrapper/src/generate/function.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AquaFunction } from '@fluencelabs/aqua-api/aqua-api.js';
|
||||||
|
import { capitalize, getFuncArgs, recursiveRenameLaquaProps } from '../utils.js';
|
||||||
|
import { genTypeName } from '../common.js';
|
||||||
|
import { CLIENT } from '../constants.js';
|
||||||
|
import { TypeGenerator } from './interfaces.js';
|
||||||
|
|
||||||
|
export class FunctionGenerator {
|
||||||
|
constructor(
|
||||||
|
private typeGenerator: TypeGenerator
|
||||||
|
) {}
|
||||||
|
|
||||||
|
generate(functions: Record<string, AquaFunction>) {
|
||||||
|
return Object.values(functions).map(func => this.generateFunction(func)).join('\n\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateFunction(func: AquaFunction) {
|
||||||
|
const scriptConstName = func.funcDef.functionName + '_script';
|
||||||
|
return `export const ${scriptConstName} = \`
|
||||||
|
${func.script}\`
|
||||||
|
|
||||||
|
${this.typeGenerator.funcType(func)}
|
||||||
|
export function ${func.funcDef.functionName}(${this.typeGenerator.type('...args', 'any[]')}) {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
${JSON.stringify(recursiveRenameLaquaProps(func.funcDef), null, 4)},
|
||||||
|
${scriptConstName}
|
||||||
|
)
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
}
|
32
packages/core/aqua-wrapper/src/generate/header.ts
Normal file
32
packages/core/aqua-wrapper/src/generate/header.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default function(isJs: boolean, aquaVersion: string) {
|
||||||
|
return `/**
|
||||||
|
*
|
||||||
|
* This file is auto-generated. Do not edit manually: changes may be erased.
|
||||||
|
* Generated by Aqua compiler: https://github.com/fluencelabs/aqua/.
|
||||||
|
* If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
|
||||||
|
* Aqua version: ${aquaVersion}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
${!isJs ? 'import type { IFluenceClient as IFluenceClient$$, CallParams as CallParams$$ } from \'@fluencelabs/js-client\';' : ''}
|
||||||
|
|
||||||
|
import {
|
||||||
|
v5_callFunction as callFunction$$,
|
||||||
|
v5_registerService as registerService$$,
|
||||||
|
} from '@fluencelabs/js-client';`;
|
||||||
|
}
|
40
packages/core/aqua-wrapper/src/generate/index.ts
Normal file
40
packages/core/aqua-wrapper/src/generate/index.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import header from './header.js';
|
||||||
|
import { getAquaApiVersion } from '../utils.js';
|
||||||
|
import { FunctionGenerator } from './function.js';
|
||||||
|
import { CompilationResult } from '@fluencelabs/aqua-api/aqua-api.js';
|
||||||
|
import { JSTypeGenerator, TSTypeGenerator } from './interfaces.js';
|
||||||
|
import { ServiceGenerator } from './service.js';
|
||||||
|
|
||||||
|
type OutputType = 'js' | 'ts';
|
||||||
|
|
||||||
|
export default function ({ services, functions }: CompilationResult, outputType: OutputType) {
|
||||||
|
const typeGenerator = outputType === 'js' ? new JSTypeGenerator() : new TSTypeGenerator();
|
||||||
|
return `/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
${header(outputType === 'js', getAquaApiVersion())}
|
||||||
|
|
||||||
|
// Services
|
||||||
|
${new ServiceGenerator(typeGenerator).generate(services)}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
${new FunctionGenerator(typeGenerator).generate(functions)}
|
||||||
|
|
||||||
|
/* eslint-enable */
|
||||||
|
`
|
||||||
|
};
|
125
packages/core/aqua-wrapper/src/generate/interfaces.ts
Normal file
125
packages/core/aqua-wrapper/src/generate/interfaces.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AquaFunction, CompilationResult } from '@fluencelabs/aqua-api/aqua-api.js';
|
||||||
|
import { CLIENT } from '../constants.js';
|
||||||
|
import { FunctionCallDef, ServiceDef } from '@fluencelabs/interfaces';
|
||||||
|
import { genTypeName, typeToTs } from '../common.js';
|
||||||
|
import { capitalize, getFuncArgs } from '../utils.js';
|
||||||
|
|
||||||
|
export interface TypeGenerator {
|
||||||
|
type(field: string, type: string): string;
|
||||||
|
generic(field: string, type: string): string;
|
||||||
|
bang(field: string): string;
|
||||||
|
funcType(funcDef: AquaFunction): string;
|
||||||
|
serviceType(srvName: string, srvDef: ServiceDef): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TSTypeGenerator implements TypeGenerator {
|
||||||
|
bang(field: string): string {
|
||||||
|
return `${field}!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
generic(field: string, type: string): string {
|
||||||
|
return `${field}<${type}>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
type(field: string, type: string): string {
|
||||||
|
return `${field}: ${type}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
funcType({ funcDef }: AquaFunction): string {
|
||||||
|
const args = getFuncArgs(funcDef.arrow.domain).map(([name, type]) => {
|
||||||
|
const [typeDesc, t] = genTypeName(type, capitalize(funcDef.functionName) + 'Arg' + capitalize(name));
|
||||||
|
return [typeDesc, `${name}: ${t}`] as const;
|
||||||
|
});
|
||||||
|
args.push([undefined, `config?: {ttl?: number}`]);
|
||||||
|
|
||||||
|
const argsDefs = args.map(([, def]) => " " + def);
|
||||||
|
const argsDesc = args.filter(([desc]) => desc !== undefined).map(([desc]) => desc);
|
||||||
|
|
||||||
|
const functionOverloads = [
|
||||||
|
argsDefs.join(',\n'),
|
||||||
|
[` peer: ${CLIENT}`, ...argsDefs].join(',\n')
|
||||||
|
];
|
||||||
|
|
||||||
|
const [resTypeDesc, resType] = genTypeName(funcDef.arrow.codomain, capitalize(funcDef.functionName) + "Result");
|
||||||
|
|
||||||
|
return [
|
||||||
|
argsDesc.join('\n'),
|
||||||
|
resTypeDesc || "",
|
||||||
|
functionOverloads.flatMap(fo => [
|
||||||
|
`export function ${funcDef.functionName}(`,
|
||||||
|
fo,
|
||||||
|
`): Promise<${resType}>;`,
|
||||||
|
''
|
||||||
|
]).join('\n')
|
||||||
|
].filter(s => s !== '').join('\n\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceType(srvName: string, srvDef: ServiceDef): string {
|
||||||
|
const members = srvDef.functions.tag === 'nil' ? [] : Object.entries(srvDef.functions.fields);
|
||||||
|
|
||||||
|
const interfaceDefs = members
|
||||||
|
.map(([name, arrow]) => {
|
||||||
|
return ` ${name}: ${typeToTs(arrow)};`;
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
const interfaces = [`export interface ${srvName}Def {`, interfaceDefs, '}'].join('\n');
|
||||||
|
|
||||||
|
const peerDecl = `peer: ${CLIENT}`;
|
||||||
|
const serviceDecl = `service: ${srvName}Def`;
|
||||||
|
const serviceIdDecl = `serviceId: string`;
|
||||||
|
const registerServiceArgs = [
|
||||||
|
[serviceDecl],
|
||||||
|
[serviceIdDecl, serviceDecl],
|
||||||
|
[peerDecl, serviceDecl],
|
||||||
|
[peerDecl, serviceIdDecl, serviceDecl]
|
||||||
|
];
|
||||||
|
|
||||||
|
return [interfaces, ...registerServiceArgs.map(registerServiceArg => {
|
||||||
|
const args = registerServiceArg.join(', ');
|
||||||
|
return `export function register${srvName}(${args}): void;`
|
||||||
|
})].join('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class JSTypeGenerator implements TypeGenerator {
|
||||||
|
bang(field: string): string {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
generic(field: string, type: string): string {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
type(field: string, type: string): string {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
funcType(): string {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceType(): string {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntityGenerator {
|
||||||
|
generate(compilationResult: CompilationResult): string;
|
||||||
|
}
|
64
packages/core/aqua-wrapper/src/generate/service.ts
Normal file
64
packages/core/aqua-wrapper/src/generate/service.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ServiceDef } from '@fluencelabs/interfaces';
|
||||||
|
import { recursiveRenameLaquaProps } from '../utils.js';
|
||||||
|
import { TypeGenerator } from './interfaces.js';
|
||||||
|
|
||||||
|
interface DefaultServiceId {
|
||||||
|
s_Some__f_value?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ServiceGenerator {
|
||||||
|
constructor(
|
||||||
|
private typeGenerator: TypeGenerator
|
||||||
|
) {}
|
||||||
|
|
||||||
|
generate(services: Record<string, ServiceDef>): string {
|
||||||
|
const generated = Object.entries(services).map(([srvName, srvDef]) => this.generateService(srvName, srvDef)).join('\n\n');
|
||||||
|
|
||||||
|
return generated + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateService(srvName: string, srvDef: ServiceDef) {
|
||||||
|
return [
|
||||||
|
this.typeGenerator.serviceType(srvName, srvDef),
|
||||||
|
this.generateRegisterServiceOverload(srvName, srvDef)
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateRegisterServiceOverload(srvName: string, srvDef: ServiceDef) {
|
||||||
|
return [
|
||||||
|
`export function register${srvName}(${this.typeGenerator.type('...args', 'any[]')}) {`,
|
||||||
|
' registerService$$(',
|
||||||
|
' args,',
|
||||||
|
` ${this.serviceToJson(srvDef)}`,
|
||||||
|
' );',
|
||||||
|
'}'
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
private serviceToJson(service: ServiceDef): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
...(
|
||||||
|
(service.defaultServiceId as DefaultServiceId)?.s_Some__f_value
|
||||||
|
? { defaultServiceId: (service.defaultServiceId as DefaultServiceId).s_Some__f_value }
|
||||||
|
: {}
|
||||||
|
),
|
||||||
|
functions: recursiveRenameLaquaProps(service.functions)
|
||||||
|
}, null, 4);
|
||||||
|
}
|
||||||
|
}
|
123
packages/core/aqua-wrapper/src/index.ts
Normal file
123
packages/core/aqua-wrapper/src/index.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { compileFromPath } from '@fluencelabs/aqua-api';
|
||||||
|
import type { ArrowType, LabeledProductType, ProductType, ServiceDef } from '@fluencelabs/interfaces';
|
||||||
|
import assert from 'assert';
|
||||||
|
import { match, P } from 'ts-pattern';
|
||||||
|
import {
|
||||||
|
ArrayType,
|
||||||
|
BottomType,
|
||||||
|
NilType,
|
||||||
|
NonArrowType,
|
||||||
|
OptionType,
|
||||||
|
ScalarType,
|
||||||
|
StructType,
|
||||||
|
TopType,
|
||||||
|
UnlabeledProductType
|
||||||
|
} from '@fluencelabs/interfaces';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import generate from './generate/index.js';
|
||||||
|
|
||||||
|
const res = await compileFromPath({
|
||||||
|
filePath: './src/generate/__test__/sources/abilities.aqua',
|
||||||
|
imports: ['./node_modules'],
|
||||||
|
targetType: 'ts'
|
||||||
|
});
|
||||||
|
|
||||||
|
// const data = generate(res, 'ts');
|
||||||
|
|
||||||
|
fs.writeFileSync('./src/generate/__test__/snapshots/abilities.ts', res.generatedSources[0].tsSource);
|
||||||
|
|
||||||
|
|
||||||
|
process.exit();
|
||||||
|
|
||||||
|
|
||||||
|
type GetTsTypeFromScalar<T extends ScalarType> = T['name'] extends 'u8' | 'u16' | 'u32' | 'u64' | 'i8' | 'i16' | 'i32' | 'i64' | 'f32' | 'f64'
|
||||||
|
? number
|
||||||
|
: T['name'] extends 'bool'
|
||||||
|
? boolean
|
||||||
|
: T['name'] extends 'string'
|
||||||
|
? string
|
||||||
|
: never;
|
||||||
|
|
||||||
|
type MapTuple<T> = { [K in keyof T]: T[K] extends NonArrowType ? GetTsType<T[K]> : never }
|
||||||
|
|
||||||
|
type GetTsType<T extends NonArrowType> = T extends NilType
|
||||||
|
? null
|
||||||
|
: T extends ArrayType
|
||||||
|
? GetTsType<T['type']>[]
|
||||||
|
: T extends StructType
|
||||||
|
? { [K in keyof T]: GetTsType<T> }
|
||||||
|
: T extends OptionType
|
||||||
|
? GetTsType<T['type']> | null
|
||||||
|
: T extends ScalarType
|
||||||
|
? GetTsTypeFromScalar<T>
|
||||||
|
: T extends TopType
|
||||||
|
? unknown
|
||||||
|
: T extends BottomType
|
||||||
|
? never
|
||||||
|
: T extends Exclude<UnlabeledProductType<infer H>, NilType>
|
||||||
|
? MapTuple<H>
|
||||||
|
: T extends Exclude<LabeledProductType<infer H>, NilType>
|
||||||
|
? H extends NonArrowType
|
||||||
|
? { [K in keyof T['fields']]: GetTsType<H> }
|
||||||
|
: never
|
||||||
|
: never;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const struct = {
|
||||||
|
"tag" : "unlabeledProduct",
|
||||||
|
"items" : [
|
||||||
|
{
|
||||||
|
"tag" : "struct",
|
||||||
|
"name" : "RemoveResult",
|
||||||
|
"fields" : {
|
||||||
|
"error" : {
|
||||||
|
"tag" : "option",
|
||||||
|
"type" : {
|
||||||
|
"tag" : "scalar",
|
||||||
|
"name" : "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"success" : {
|
||||||
|
"tag" : "scalar",
|
||||||
|
"name" : "bool"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] as Array<SomeNonArrowTypes>
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type tt = GetTsType<typeof struct>;
|
||||||
|
|
||||||
|
const services = res.services as Record<string, ServiceDef>
|
||||||
|
|
||||||
|
const service = services['Srv'];
|
||||||
|
|
||||||
|
if (service.functions.tag === 'nil') {
|
||||||
|
throw new Error('nil');
|
||||||
|
}
|
||||||
|
|
||||||
|
const codomain = service.functions.fields['reload'].domain;
|
||||||
|
console.log(service.functions);
|
||||||
|
console.log(service);
|
||||||
|
// console.log(codomain);
|
||||||
|
// assert(codomain.tag === 'labeledProduct');
|
||||||
|
console.log(JSON.stringify(codomain));
|
60
packages/core/aqua-wrapper/src/utils.ts
Normal file
60
packages/core/aqua-wrapper/src/utils.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import pkg from '../package.json' assert { type: 'json' };
|
||||||
|
import { ArrowType, NonArrowType, ProductType } from '@fluencelabs/interfaces';
|
||||||
|
|
||||||
|
export function getAquaApiVersion() {
|
||||||
|
return pkg.dependencies['@fluencelabs/aqua-api'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFuncArgs(domain: ProductType<NonArrowType>): [string, NonArrowType][] {
|
||||||
|
if (domain.tag === 'labeledProduct') {
|
||||||
|
return Object.entries(domain.fields).map(([label, type]) => [label, type]);
|
||||||
|
} else if (domain.tag === 'unlabeledProduct') {
|
||||||
|
return domain.items.map((type, index) => ['arg' + index, type]);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recursiveRenameLaquaProps(obj: unknown): unknown {
|
||||||
|
if (typeof obj !== 'object' || obj === null) return obj;
|
||||||
|
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(item => recursiveRenameLaquaProps(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.getOwnPropertyNames(obj).reduce((acc, prop) => {
|
||||||
|
let accessProp = prop;
|
||||||
|
if (prop.includes('Laqua_js')) {
|
||||||
|
// Last part of the property separated by "_" is a correct name
|
||||||
|
const refinedProperty = prop.split('_').pop()!;
|
||||||
|
if (refinedProperty in obj) {
|
||||||
|
accessProp = refinedProperty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[accessProp]: recursiveRenameLaquaProps(obj[accessProp as keyof typeof obj])
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function capitalize(str: string) {
|
||||||
|
return str.slice(0, 1).toUpperCase() + str.slice(1);
|
||||||
|
}
|
9
packages/core/aqua-wrapper/tsconfig.json
Normal file
9
packages/core/aqua-wrapper/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist"],
|
||||||
|
}
|
@ -13,9 +13,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
type SomeNonArrowTypes = ScalarType | OptionType | ArrayType | StructType | TopType | BottomType;
|
type SimpleTypes = ScalarType | OptionType | ArrayType | StructType | TopType | BottomType | NilType;
|
||||||
|
|
||||||
export type NonArrowType = SomeNonArrowTypes | ProductType<SomeNonArrowTypes>;
|
export type NonArrowType = SimpleTypes | ProductType<SimpleTypes>;
|
||||||
|
|
||||||
export type TopType = {
|
export type TopType = {
|
||||||
/**
|
/**
|
||||||
@ -108,8 +108,7 @@ export type StructType = {
|
|||||||
fields: { [key: string]: NonArrowType };
|
fields: { [key: string]: NonArrowType };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LabeledProductType<T> =
|
export type LabeledProductType<T> = {
|
||||||
| {
|
|
||||||
/**
|
/**
|
||||||
* Type descriptor. Used for pattern-matching
|
* Type descriptor. Used for pattern-matching
|
||||||
*/
|
*/
|
||||||
@ -119,11 +118,9 @@ export type LabeledProductType<T> =
|
|||||||
* Labelled product fields
|
* Labelled product fields
|
||||||
*/
|
*/
|
||||||
fields: { [key: string]: T };
|
fields: { [key: string]: T };
|
||||||
}
|
};
|
||||||
| NilType;
|
|
||||||
|
|
||||||
export type UnlabeledProductType<T> =
|
export type UnlabeledProductType<T> = {
|
||||||
| {
|
|
||||||
/**
|
/**
|
||||||
* Type descriptor. Used for pattern-matching
|
* Type descriptor. Used for pattern-matching
|
||||||
*/
|
*/
|
||||||
@ -133,10 +130,9 @@ export type UnlabeledProductType<T> =
|
|||||||
* Items in unlabelled product
|
* Items in unlabelled product
|
||||||
*/
|
*/
|
||||||
items: Array<T>;
|
items: Array<T>;
|
||||||
}
|
};
|
||||||
| NilType;
|
|
||||||
|
|
||||||
export type ProductType<T> = UnlabeledProductType<T> | LabeledProductType<T>;
|
export type ProductType<T> = UnlabeledProductType<T> | LabeledProductType<T> | NilType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ArrowType is a profunctor pointing its domain to codomain.
|
* ArrowType is a profunctor pointing its domain to codomain.
|
||||||
@ -233,12 +229,12 @@ export interface ServiceDef {
|
|||||||
/**
|
/**
|
||||||
* Default service id. If the service has no default id the value should be undefined
|
* Default service id. If the service has no default id the value should be undefined
|
||||||
*/
|
*/
|
||||||
defaultServiceId?: string;
|
defaultServiceId?: {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of functions which the service consists of
|
* List of functions which the service consists of
|
||||||
*/
|
*/
|
||||||
functions: LabeledProductType<ArrowWithoutCallbacks>;
|
functions: LabeledProductType<ArrowWithoutCallbacks> | NilType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
72
pnpm-lock.yaml
generated
72
pnpm-lock.yaml
generated
@ -126,6 +126,40 @@ importers:
|
|||||||
specifier: 6.1.1
|
specifier: 6.1.1
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
|
|
||||||
|
packages/core/aqua-wrapper:
|
||||||
|
dependencies:
|
||||||
|
'@fluencelabs/aqua-api':
|
||||||
|
specifier: 0.12.0
|
||||||
|
version: 0.12.0
|
||||||
|
'@fluencelabs/aqua-lib':
|
||||||
|
specifier: 0.7.3
|
||||||
|
version: 0.7.3
|
||||||
|
'@fluencelabs/interfaces':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../interfaces
|
||||||
|
'@fluencelabs/js-client':
|
||||||
|
specifier: '*'
|
||||||
|
version: link:../js-client
|
||||||
|
'@fluencelabs/registry':
|
||||||
|
specifier: 0.8.7
|
||||||
|
version: 0.8.7
|
||||||
|
'@fluencelabs/spell':
|
||||||
|
specifier: 0.5.20
|
||||||
|
version: 0.5.20
|
||||||
|
'@fluencelabs/trust-graph':
|
||||||
|
specifier: 0.4.7
|
||||||
|
version: 0.4.7
|
||||||
|
ts-pattern:
|
||||||
|
specifier: 5.0.5
|
||||||
|
version: 5.0.5
|
||||||
|
devDependencies:
|
||||||
|
typescript:
|
||||||
|
specifier: 5.1.6
|
||||||
|
version: 5.1.6
|
||||||
|
vitest:
|
||||||
|
specifier: 0.29.7
|
||||||
|
version: 0.29.7
|
||||||
|
|
||||||
packages/core/interfaces:
|
packages/core/interfaces:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@fluencelabs/avm':
|
'@fluencelabs/avm':
|
||||||
@ -3792,7 +3826,6 @@ packages:
|
|||||||
|
|
||||||
/@fluencelabs/aqua-api@0.12.0:
|
/@fluencelabs/aqua-api@0.12.0:
|
||||||
resolution: {integrity: sha512-8D1SfmBDm0mmg3tuYrlpU8L6+bRlCSVRkhlU4CXMJFSMiVMrSF2WV+KFTP4GcOB3N4pNOONEwHMQo4xNWwzGhg==}
|
resolution: {integrity: sha512-8D1SfmBDm0mmg3tuYrlpU8L6+bRlCSVRkhlU4CXMJFSMiVMrSF2WV+KFTP4GcOB3N4pNOONEwHMQo4xNWwzGhg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@fluencelabs/aqua-api@0.9.3:
|
/@fluencelabs/aqua-api@0.9.3:
|
||||||
resolution: {integrity: sha512-ieM2e7qMXgm9BPSSd2fxVbqLlYkR/a/aVTAQXO8gdx2rKKFqnTgFX4gpSOTxrrCMshi8OnXfd2OZi1hsJHTnKA==}
|
resolution: {integrity: sha512-ieM2e7qMXgm9BPSSd2fxVbqLlYkR/a/aVTAQXO8gdx2rKKFqnTgFX4gpSOTxrrCMshi8OnXfd2OZi1hsJHTnKA==}
|
||||||
@ -3812,6 +3845,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-ifjtCM93KO3LhzPkMxqmXhwLmrg/scjOiyTihEVg7ns5N+BVzaK1eWzdOdqGdl9ZVoah43pdlQUepEo7VdRmsw==}
|
resolution: {integrity: sha512-ifjtCM93KO3LhzPkMxqmXhwLmrg/scjOiyTihEVg7ns5N+BVzaK1eWzdOdqGdl9ZVoah43pdlQUepEo7VdRmsw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@fluencelabs/aqua-lib@0.7.0:
|
||||||
|
resolution: {integrity: sha512-mJEaxfAQb6ogVM4l4qw7INK6kvLA2Y161ErwL7IVeVSkKXIeYq/qio2p2au35LYvhBNsKc7XP2qc0uztCmxZzA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fluencelabs/aqua-lib@0.7.3:
|
||||||
|
resolution: {integrity: sha512-+JVbWmHeGB+X/BSqmk6/B0gwWJ4bEAxkepVTN8l0mVrJ5zRRmYaCKVplWy6Z3W012m3VVK3A1o3rm/fgfVrQkw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@fluencelabs/aqua@0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@4.7.2):
|
/@fluencelabs/aqua@0.9.1-374(jest@27.5.1)(node-fetch@3.3.2)(typescript@4.7.2):
|
||||||
resolution: {integrity: sha512-jF6oVE4h7bP/dQArKEfsy4UxbQbzACfVIBY/TFUL5D3np4ssjxrh15Y3gl1PwSWjlaPcDeFvAuStmcqfYQmLqQ==}
|
resolution: {integrity: sha512-jF6oVE4h7bP/dQArKEfsy4UxbQbzACfVIBY/TFUL5D3np4ssjxrh15Y3gl1PwSWjlaPcDeFvAuStmcqfYQmLqQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -4097,6 +4138,29 @@ packages:
|
|||||||
'@fluencelabs/trust-graph': 3.0.4
|
'@fluencelabs/trust-graph': 3.0.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@fluencelabs/registry@0.8.7:
|
||||||
|
resolution: {integrity: sha512-43bmb1v4p5ORvaiLBrUAl+hRPo3luxxBVrJgqTvipJa2OEg2wCRA/Wo9s4M7Lchnv3NoYLOyNTzNyFopQRKILA==}
|
||||||
|
dependencies:
|
||||||
|
'@fluencelabs/aqua-lib': 0.7.0
|
||||||
|
'@fluencelabs/trust-graph': 0.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fluencelabs/spell@0.5.20:
|
||||||
|
resolution: {integrity: sha512-QFbknWwALLUWMzpWkFt34McuwTz9xwQuiPP1zXqhPqVZ1J6g8F3gwHHtzgHFW5Z7WrRmwsL+IQtFJy8YZubhDw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fluencelabs/trust-graph@0.4.1:
|
||||||
|
resolution: {integrity: sha512-V/6ts4q/Y0uKMS6orVpPyxfdd99YFMkm9wN9U2IFtlBUWNsQZG369FK9qEizwsSRCqTchMHYs8Vh4wgZ2uRfuQ==}
|
||||||
|
dependencies:
|
||||||
|
'@fluencelabs/aqua-lib': 0.7.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fluencelabs/trust-graph@0.4.7:
|
||||||
|
resolution: {integrity: sha512-e4TxWimUh9GBWjqSO8WGsSqjZfyIs6f39/8Pzfo6PCcNoSf8FPaaO817Pw4FmAXYEKR1IalIUX3CDdym3NlHWw==}
|
||||||
|
dependencies:
|
||||||
|
'@fluencelabs/aqua-lib': 0.7.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@fluencelabs/trust-graph@3.0.4:
|
/@fluencelabs/trust-graph@3.0.4:
|
||||||
resolution: {integrity: sha512-4CWe/dBuZwrj5iU6mTrLz5JCSy5v1fw7dYjD65Pz05xWAbLH2jw72YIJfbMX0utzb1qiM8CooXv1XKPgutCIHQ==}
|
resolution: {integrity: sha512-4CWe/dBuZwrj5iU6mTrLz5JCSy5v1fw7dYjD65Pz05xWAbLH2jw72YIJfbMX0utzb1qiM8CooXv1XKPgutCIHQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -19892,6 +19956,10 @@ packages:
|
|||||||
/ts-pattern@3.3.3:
|
/ts-pattern@3.3.3:
|
||||||
resolution: {integrity: sha512-Z5EFi6g6wyX3uDFHqxF5W5c5h663oZg9O6aOiAT7fqNu0HPSfCxtHzrQ7SblTy738Mrg2Ezorky8H5aUOm8Pvg==}
|
resolution: {integrity: sha512-Z5EFi6g6wyX3uDFHqxF5W5c5h663oZg9O6aOiAT7fqNu0HPSfCxtHzrQ7SblTy738Mrg2Ezorky8H5aUOm8Pvg==}
|
||||||
|
|
||||||
|
/ts-pattern@5.0.5:
|
||||||
|
resolution: {integrity: sha512-tL0w8U/pgaacOmkb9fRlYzWEUDCfVjjv9dD4wHTgZ61MjhuMt46VNWTG747NqW6vRzoWIKABVhFSOJ82FvXrfA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/tsconfck@2.1.1(typescript@4.7.2):
|
/tsconfck@2.1.1(typescript@4.7.2):
|
||||||
resolution: {integrity: sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww==}
|
resolution: {integrity: sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww==}
|
||||||
engines: {node: ^14.13.1 || ^16 || >=18}
|
engines: {node: ^14.13.1 || ^16 || >=18}
|
||||||
@ -20566,7 +20634,7 @@ packages:
|
|||||||
'@vitest/runner': 0.29.7
|
'@vitest/runner': 0.29.7
|
||||||
'@vitest/spy': 0.29.7
|
'@vitest/spy': 0.29.7
|
||||||
'@vitest/utils': 0.29.7
|
'@vitest/utils': 0.29.7
|
||||||
acorn: 8.9.0
|
acorn: 8.10.0
|
||||||
acorn-walk: 8.2.0
|
acorn-walk: 8.2.0
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
chai: 4.3.7
|
chai: 4.3.7
|
||||||
|
Reference in New Issue
Block a user