2020-11-03 17:43:58 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2020 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.
|
|
|
|
*/
|
|
|
|
|
2021-01-22 18:54:05 +03:00
|
|
|
use crate::ast;
|
|
|
|
use ast::Instruction;
|
2020-11-03 17:43:58 +03:00
|
|
|
|
|
|
|
use fstrings::f;
|
2020-11-10 17:30:49 +03:00
|
|
|
use std::rc::Rc;
|
2020-11-03 17:43:58 +03:00
|
|
|
|
|
|
|
fn parse(source_code: &str) -> Instruction {
|
2020-11-05 16:50:09 +03:00
|
|
|
*crate::parse(source_code).expect("parsing failed")
|
2020-11-03 17:43:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_seq() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
let source_code = r#"
|
|
|
|
(seq
|
2020-11-09 14:44:04 +03:00
|
|
|
(call peerid function [] output)
|
|
|
|
(call "id" "f" ["hello" name])
|
2020-11-03 17:43:58 +03:00
|
|
|
)
|
|
|
|
"#;
|
|
|
|
let instruction = parse(source_code);
|
|
|
|
let expected = seq(
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Variable("peerid")),
|
|
|
|
function_part: FuncName(Variable("function")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-09 14:44:04 +03:00
|
|
|
output: Scalar("output"),
|
2020-11-03 17:43:58 +03:00
|
|
|
}),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("id")),
|
|
|
|
function_part: FuncName(Literal("f")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Literal("hello"), Variable("name")]),
|
2020-11-09 14:44:04 +03:00
|
|
|
output: None,
|
2020-11-03 17:43:58 +03:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_seq_seq() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
let source_code = r#"
|
|
|
|
(seq
|
|
|
|
(seq
|
2020-11-09 14:44:04 +03:00
|
|
|
(call peerid function [])
|
|
|
|
(call (peerid serviceA) ("serviceB" function) [])
|
2020-11-03 17:43:58 +03:00
|
|
|
)
|
2020-11-09 14:44:04 +03:00
|
|
|
(call "id" "f" ["hello" name] output[])
|
2020-11-03 17:43:58 +03:00
|
|
|
)
|
|
|
|
"#;
|
|
|
|
let instruction = parse(source_code);
|
|
|
|
let expected = seq(
|
|
|
|
seq(
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Variable("peerid")),
|
|
|
|
function_part: FuncName(Variable("function")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-09 14:44:04 +03:00
|
|
|
output: None,
|
2020-11-03 17:43:58 +03:00
|
|
|
}),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPkWithServiceId(Variable("peerid"), Variable("serviceA")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal("serviceB"), Variable("function")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-09 14:44:04 +03:00
|
|
|
output: None,
|
2020-11-03 17:43:58 +03:00
|
|
|
}),
|
|
|
|
),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("id")),
|
|
|
|
function_part: FuncName(Literal("f")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Literal("hello"), Variable("name")]),
|
2020-11-09 14:44:04 +03:00
|
|
|
output: Accumulator("output"),
|
2020-11-03 17:43:58 +03:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_json_path() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
let source_code = r#"
|
|
|
|
(call id.$.a "f" ["hello" name] void[])
|
|
|
|
"#;
|
|
|
|
let instruction = parse(source_code);
|
|
|
|
let expected = Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(JsonPath {
|
|
|
|
variable: "id",
|
|
|
|
path: "$.a",
|
|
|
|
}),
|
|
|
|
function_part: FuncName(Literal("f")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Literal("hello"), Variable("name")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Accumulator("void"),
|
|
|
|
});
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_json_path_complex() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
let source_code = r#"
|
|
|
|
(seq
|
|
|
|
(call m.$.[1] "f" [] void)
|
2020-11-05 15:13:11 +03:00
|
|
|
(call m.$.abc["c"].cde[a][0].cde["bcd"] "f" [] void)
|
2020-11-03 17:43:58 +03:00
|
|
|
)
|
|
|
|
"#;
|
|
|
|
let instruction = parse(source_code);
|
|
|
|
let expected = seq(
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(JsonPath {
|
|
|
|
variable: "m",
|
|
|
|
path: "$.[1]",
|
|
|
|
}),
|
|
|
|
function_part: FuncName(Literal("f")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("void"),
|
|
|
|
}),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(JsonPath {
|
|
|
|
variable: "m",
|
2020-11-05 15:13:11 +03:00
|
|
|
path: r#"$.abc["c"].cde[a][0].cde["bcd"]"#,
|
2020-11-03 17:43:58 +03:00
|
|
|
}),
|
|
|
|
function_part: FuncName(Literal("f")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("void"),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
2020-11-05 15:13:11 +03:00
|
|
|
#[test]
|
|
|
|
fn json_path_square_braces() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-11-05 15:13:11 +03:00
|
|
|
let source_code = r#"
|
|
|
|
(call u.$["peer_id"] ("return" "") [u.$["peer_id"].cde[0]["abc"].abc u.$["name"]] void[])
|
|
|
|
"#;
|
|
|
|
let instruction = parse(source_code);
|
|
|
|
let expected = Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(JsonPath {
|
|
|
|
variable: "u",
|
|
|
|
path: r#"$["peer_id"]"#,
|
|
|
|
}),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal("return"), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![
|
2020-11-05 15:13:11 +03:00
|
|
|
JsonPath {
|
|
|
|
variable: "u",
|
|
|
|
path: r#"$["peer_id"].cde[0]["abc"].abc"#,
|
|
|
|
},
|
|
|
|
JsonPath {
|
|
|
|
variable: "u",
|
|
|
|
path: r#"$["name"]"#,
|
|
|
|
},
|
2020-12-22 21:05:04 +03:00
|
|
|
]),
|
2020-11-05 15:13:11 +03:00
|
|
|
output: Accumulator("void"),
|
|
|
|
});
|
|
|
|
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
#[test]
|
|
|
|
fn parse_null() {
|
|
|
|
let source_code = r#"
|
|
|
|
(seq
|
|
|
|
(null)
|
|
|
|
|
|
|
|
( null )
|
|
|
|
)
|
|
|
|
"#;
|
|
|
|
let instruction = parse(source_code);
|
2021-01-22 18:54:05 +03:00
|
|
|
let expected = Instruction::Seq(ast::Seq(Box::new(null()), Box::new(null())));
|
2020-11-03 17:43:58 +03:00
|
|
|
assert_eq!(instruction, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn source_seq_with(name: &'static str) -> String {
|
|
|
|
f!(r#"
|
|
|
|
(seq
|
|
|
|
({name}
|
|
|
|
(seq (null) (null))
|
|
|
|
(null)
|
|
|
|
)
|
|
|
|
({name} (null) (seq (null) (null)) )
|
|
|
|
)
|
|
|
|
"#)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_seq_par_xor_seq() {
|
|
|
|
for name in &["xor", "par", "seq"] {
|
|
|
|
let source_code = source_seq_with(name);
|
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let instr = binary_instruction(*name);
|
|
|
|
let expected = seq(instr(seqnn(), null()), instr(null(), seqnn()));
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_fold() {
|
|
|
|
let source_code = r#"
|
|
|
|
(fold iterable i
|
|
|
|
(null)
|
|
|
|
)
|
|
|
|
"#;
|
|
|
|
let instruction = parse(&source_code.as_ref());
|
2021-01-22 18:54:05 +03:00
|
|
|
let expected = fold(ast::IterableValue::Variable("iterable"), "i", null());
|
2020-11-03 17:43:58 +03:00
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn source_fold_with(name: &str) -> String {
|
|
|
|
f!(r#"(fold iterable i
|
|
|
|
({name} (null) (null))
|
|
|
|
)"#)
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn parse_fold_with_xor_par_seq() {
|
|
|
|
for name in &["xor", "par", "seq"] {
|
|
|
|
let source_code = source_fold_with(name);
|
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let instr = binary_instruction(*name);
|
2020-12-22 21:05:04 +03:00
|
|
|
let expected = fold(
|
2021-01-22 18:54:05 +03:00
|
|
|
ast::IterableValue::Variable("iterable"),
|
2020-12-22 21:05:04 +03:00
|
|
|
"i",
|
|
|
|
instr(null(), null()),
|
|
|
|
);
|
2020-11-03 17:43:58 +03:00
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 14:31:53 +03:00
|
|
|
#[test]
|
2020-12-28 00:12:11 +03:00
|
|
|
fn parse_init_peer_id() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-12-28 00:12:11 +03:00
|
|
|
let peer_id = String::from("some_peer_id");
|
|
|
|
let source_code = format!(
|
|
|
|
r#"
|
2020-11-11 14:31:53 +03:00
|
|
|
(seq
|
2020-12-28 00:12:11 +03:00
|
|
|
(call "{}" ("local_service_id" "local_fn_name") [])
|
2020-11-11 14:31:53 +03:00
|
|
|
(call %init_peer_id% ("service_id" "fn_name") [])
|
2020-12-28 00:12:11 +03:00
|
|
|
)"#,
|
|
|
|
peer_id
|
|
|
|
);
|
|
|
|
|
2020-11-11 14:31:53 +03:00
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let expected = seq(
|
|
|
|
Instruction::Call(Call {
|
2021-01-22 18:54:05 +03:00
|
|
|
peer_part: PeerPk(Literal(&peer_id)),
|
2020-11-11 14:31:53 +03:00
|
|
|
function_part: ServiceIdWithFuncName(
|
|
|
|
Literal("local_service_id"),
|
|
|
|
Literal("local_fn_name"),
|
|
|
|
),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-11 14:31:53 +03:00
|
|
|
output: None,
|
|
|
|
}),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(InitPeerId),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal("service_id"), Literal("fn_name")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-11 14:31:53 +03:00
|
|
|
output: None,
|
|
|
|
}),
|
|
|
|
);
|
2020-12-28 00:12:11 +03:00
|
|
|
|
2020-11-11 14:31:53 +03:00
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
#[test]
|
|
|
|
fn seq_par_call() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-12-28 00:12:11 +03:00
|
|
|
let peer_id = String::from("some_peer_id");
|
|
|
|
let source_code = format!(
|
|
|
|
r#"
|
2020-11-03 17:43:58 +03:00
|
|
|
(seq
|
|
|
|
(par
|
2020-12-28 00:12:11 +03:00
|
|
|
(call "{0}" ("local_service_id" "local_fn_name") [] result_1)
|
|
|
|
(call "{0}" ("service_id" "fn_name") [] g)
|
2020-11-03 17:43:58 +03:00
|
|
|
)
|
2020-12-28 00:12:11 +03:00
|
|
|
(call "{0}" ("local_service_id" "local_fn_name") [] result_2)
|
|
|
|
)"#,
|
|
|
|
peer_id,
|
|
|
|
);
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let expected = seq(
|
|
|
|
par(
|
|
|
|
Instruction::Call(Call {
|
2021-01-22 18:54:05 +03:00
|
|
|
peer_part: PeerPk(Literal(&peer_id)),
|
2020-11-03 17:43:58 +03:00
|
|
|
function_part: ServiceIdWithFuncName(
|
|
|
|
Literal("local_service_id"),
|
|
|
|
Literal("local_fn_name"),
|
|
|
|
),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("result_1"),
|
|
|
|
}),
|
|
|
|
Instruction::Call(Call {
|
2020-12-28 00:12:11 +03:00
|
|
|
peer_part: PeerPk(Literal(&peer_id)),
|
2020-11-03 17:43:58 +03:00
|
|
|
function_part: ServiceIdWithFuncName(Literal("service_id"), Literal("fn_name")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("g"),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
Instruction::Call(Call {
|
2021-01-22 18:54:05 +03:00
|
|
|
peer_part: PeerPk(Literal(&peer_id)),
|
2020-11-03 17:43:58 +03:00
|
|
|
function_part: ServiceIdWithFuncName(
|
|
|
|
Literal("local_service_id"),
|
|
|
|
Literal("local_fn_name"),
|
|
|
|
),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("result_2"),
|
|
|
|
}),
|
|
|
|
);
|
2020-12-28 00:12:11 +03:00
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn seq_with_empty_and_dash() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
let source_code = r#"
|
|
|
|
(seq
|
|
|
|
(seq
|
|
|
|
(seq
|
|
|
|
(call "set_variables" ("" "") ["module-bytes"] module-bytes)
|
|
|
|
(call "set_variables" ("" "") ["module_config"] module_config)
|
|
|
|
)
|
|
|
|
(call "set_variables" ("" "") ["blueprint"] blueprint)
|
|
|
|
)
|
|
|
|
(seq
|
|
|
|
(call "A" ("add_module" "") [module-bytes module_config] module)
|
|
|
|
(seq
|
|
|
|
(call "A" ("add_blueprint" "") [blueprint] blueprint_id)
|
|
|
|
(seq
|
|
|
|
(call "A" ("create" "") [blueprint_id] service_id)
|
|
|
|
(call "remote_peer_id" ("" "") [service_id] client_result)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
"#;
|
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let expected = seq(
|
|
|
|
seq(
|
|
|
|
seq(
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("set_variables")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Literal("module-bytes")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("module-bytes"),
|
|
|
|
}),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("set_variables")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Literal("module_config")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("module_config"),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("set_variables")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Literal("blueprint")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("blueprint"),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
seq(
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("A")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal("add_module"), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Variable("module-bytes"), Variable("module_config")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("module"),
|
|
|
|
}),
|
|
|
|
seq(
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("A")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal("add_blueprint"), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Variable("blueprint")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("blueprint_id"),
|
|
|
|
}),
|
|
|
|
seq(
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("A")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal("create"), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Variable("blueprint_id")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("service_id"),
|
|
|
|
}),
|
|
|
|
Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Literal("remote_peer_id")),
|
|
|
|
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![Variable("service_id")]),
|
2020-11-03 17:43:58 +03:00
|
|
|
output: Scalar("client_result"),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
2020-11-09 14:44:04 +03:00
|
|
|
#[test]
|
|
|
|
fn no_output() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Call;
|
2021-01-27 00:37:58 +03:00
|
|
|
use ast::CallArgValue::*;
|
|
|
|
use ast::CallOutputValue::*;
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::FunctionPart::*;
|
|
|
|
use ast::PeerPart::*;
|
|
|
|
|
2020-11-09 14:44:04 +03:00
|
|
|
let source_code = r#"
|
|
|
|
(call peer (service fname) [])
|
|
|
|
"#;
|
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let expected = Instruction::Call(Call {
|
|
|
|
peer_part: PeerPk(Variable("peer")),
|
|
|
|
function_part: ServiceIdWithFuncName(Variable("service"), Variable("fname")),
|
2020-12-22 21:05:04 +03:00
|
|
|
args: Rc::new(vec![]),
|
2020-11-09 14:44:04 +03:00
|
|
|
output: None,
|
|
|
|
});
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
2020-11-10 17:30:49 +03:00
|
|
|
#[test]
|
|
|
|
fn fold_json_path() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Fold;
|
|
|
|
use ast::IterableValue::*;
|
|
|
|
|
2020-11-10 17:30:49 +03:00
|
|
|
let source_code = r#"
|
2020-11-24 12:40:54 +03:00
|
|
|
; comment
|
|
|
|
(fold members.$.["users"] m (null)) ;;; comment
|
|
|
|
;;; comment
|
|
|
|
"#;
|
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let expected = Instruction::Fold(Fold {
|
|
|
|
iterable: JsonPath {
|
|
|
|
variable: "members",
|
|
|
|
path: "$.[\"users\"]",
|
|
|
|
},
|
|
|
|
iterator: "m",
|
|
|
|
instruction: Rc::new(null()),
|
|
|
|
});
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn comments() {
|
2021-01-22 18:54:05 +03:00
|
|
|
use ast::Fold;
|
|
|
|
use ast::IterableValue::*;
|
|
|
|
|
2020-11-24 12:40:54 +03:00
|
|
|
let source_code = r#"
|
|
|
|
; comment
|
|
|
|
(fold members.$.["users"] m (null)) ;;; comment ;;?()()
|
|
|
|
;;; comme;?!.$. nt[][][][()()()null;$::!
|
2020-11-10 17:30:49 +03:00
|
|
|
"#;
|
|
|
|
let instruction = parse(&source_code.as_ref());
|
|
|
|
let expected = Instruction::Fold(Fold {
|
|
|
|
iterable: JsonPath {
|
|
|
|
variable: "members",
|
|
|
|
path: "$.[\"users\"]",
|
|
|
|
},
|
|
|
|
iterator: "m",
|
|
|
|
instruction: Rc::new(null()),
|
|
|
|
});
|
|
|
|
assert_eq!(instruction, expected);
|
|
|
|
}
|
|
|
|
|
2020-11-03 17:43:58 +03:00
|
|
|
// Test DSL
|
|
|
|
|
|
|
|
fn seq<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
2021-01-22 18:54:05 +03:00
|
|
|
Instruction::Seq(ast::Seq(Box::new(l), Box::new(r)))
|
2020-11-03 17:43:58 +03:00
|
|
|
}
|
|
|
|
fn par<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
2021-01-22 18:54:05 +03:00
|
|
|
Instruction::Par(ast::Par(Box::new(l), Box::new(r)))
|
2020-11-03 17:43:58 +03:00
|
|
|
}
|
|
|
|
fn xor<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
2021-01-22 18:54:05 +03:00
|
|
|
Instruction::Xor(ast::Xor(Box::new(l), Box::new(r)))
|
2020-11-03 17:43:58 +03:00
|
|
|
}
|
|
|
|
fn seqnn() -> Instruction<'static> {
|
|
|
|
seq(null(), null())
|
|
|
|
}
|
|
|
|
fn null() -> Instruction<'static> {
|
2021-01-22 18:54:05 +03:00
|
|
|
Instruction::Null(ast::Null)
|
2020-11-03 17:43:58 +03:00
|
|
|
}
|
2020-11-10 17:30:49 +03:00
|
|
|
fn fold<'a>(
|
2021-01-22 18:54:05 +03:00
|
|
|
iterable: ast::IterableValue<'a>,
|
2020-11-10 17:30:49 +03:00
|
|
|
iterator: &'a str,
|
|
|
|
instruction: Instruction<'a>,
|
|
|
|
) -> Instruction<'a> {
|
2021-01-22 18:54:05 +03:00
|
|
|
Instruction::Fold(ast::Fold {
|
2020-11-03 17:43:58 +03:00
|
|
|
iterable,
|
|
|
|
iterator,
|
|
|
|
instruction: std::rc::Rc::new(instruction),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
fn binary_instruction<'a, 'b>(
|
|
|
|
name: &'a str,
|
|
|
|
) -> impl Fn(Instruction<'b>, Instruction<'b>) -> Instruction<'b> {
|
|
|
|
match name {
|
|
|
|
"xor" => |l, r| xor(l, r),
|
|
|
|
"par" => |l, r| par(l, r),
|
|
|
|
"seq" => |l, r| seq(l, r),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|