feat(all): reduce stream usage scope (#298)

This PR intended to reduce stream usage scope in order to make AquaVM truly deterministic.

Refs: #297.

Co-authored-by: Ivan Boldyrev <ivan@fluence.one>
Co-authored-by: Anatoly Laskaris <github_me@nahsi.dev>
This commit is contained in:
Mike Voronov 2022-11-30 17:38:32 +03:00 committed by GitHub
parent 30967626e3
commit 9fe7afb897
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 2537 additions and 2192 deletions

View File

@ -1,3 +1,11 @@
## Version 0.32.0 (2022-11-25)
[PR 298](https://github.com/fluencelabs/aquavm/pull/298):
Reduce stream scopes in order to prohibit nondeterministic behaviour
[PR 366](https://github.com/fluencelabs/aquavm/pull/366):
Save order between current generations
## Version 0.31.0 (2022-10-11)
[PR 362](https://github.com/fluencelabs/aquavm/pull/362):

4
Cargo.lock generated
View File

@ -13,7 +13,7 @@ dependencies = [
[[package]]
name = "air"
version = "0.31.2"
version = "0.32.0"
dependencies = [
"air-execution-info-collector",
"air-interpreter-data",
@ -84,7 +84,7 @@ dependencies = [
[[package]]
name = "air-interpreter"
version = "0.31.0"
version = "0.32.0"
dependencies = [
"air",
"air-interpreter-interface",

View File

@ -1,6 +1,6 @@
[package]
name = "air-interpreter"
version = "0.31.0"
version = "0.32.0"
description = "Crate-wrapper for air"
authors = ["Fluence Labs"]
edition = "2018"

View File

@ -1,6 +1,6 @@
[package]
name = "air"
version = "0.31.2"
version = "0.32.0"
description = "Interpreter of AIR scripts intended to coordinate request flow in the Fluence network"
authors = ["Fluence Labs"]
edition = "2018"

View File

@ -38,7 +38,9 @@ pub(super) fn apply_to_arg(
Boolean(value) => apply_const(*value, exec_ctx, trace_ctx),
EmptyArray => apply_const(serde_json::json!([]), exec_ctx, trace_ctx),
Scalar(scalar) => apply_scalar(scalar, exec_ctx, trace_ctx, should_touch_trace)?,
ScalarWithLambda(scalar) => apply_scalar_wl(scalar, exec_ctx, trace_ctx)?,
CanonStream(canon_stream) => apply_canon_stream(canon_stream, exec_ctx, trace_ctx)?,
CanonStreamWithLambda(canon_stream) => apply_canon_stream_wl(canon_stream, exec_ctx, trace_ctx)?,
};
Ok(result)
@ -67,27 +69,14 @@ fn apply_last_error<'i>(
}
fn apply_scalar(
scalar: &ast::ScalarWithLambda<'_>,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
should_touch_trace: bool,
) -> ExecutionResult<ValueAggregate> {
// TODO: refactor this code after boxed value
match &scalar.lambda {
Some(lambda) => apply_scalar_wl_impl(scalar.name, lambda, exec_ctx, trace_ctx),
None => apply_scalar_impl(scalar.name, exec_ctx, trace_ctx, should_touch_trace),
}
}
fn apply_scalar_impl(
scalar_name: &str,
ast_scalar: &ast::Scalar<'_>,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
should_touch_trace: bool,
) -> ExecutionResult<ValueAggregate> {
use crate::execution_step::ScalarRef;
let scalar = exec_ctx.scalars.get_value(scalar_name)?;
let scalar = exec_ctx.scalars.get_value(ast_scalar.name)?;
let mut result = match scalar {
ScalarRef::Value(result) => result.clone(),
@ -104,14 +93,13 @@ fn apply_scalar_impl(
Ok(result)
}
fn apply_scalar_wl_impl(
scalar_name: &str,
lambda: &LambdaAST<'_>,
fn apply_scalar_wl(
ast_scalar: &ast::ScalarWithLambda<'_>,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
) -> ExecutionResult<ValueAggregate> {
let variable = Variable::scalar(scalar_name);
let (jvalue, tetraplet) = apply_lambda(variable, lambda, exec_ctx)?;
let variable = Variable::scalar(ast_scalar.name);
let (jvalue, tetraplet) = apply_lambda(variable, &ast_scalar.lambda, exec_ctx)?;
let tetraplet = Rc::new(tetraplet);
let result = ValueAggregate::new(Rc::new(jvalue), tetraplet, trace_ctx.trace_pos());
@ -119,45 +107,32 @@ fn apply_scalar_wl_impl(
}
fn apply_canon_stream(
canon_stream: &ast::CanonStreamWithLambda<'_>,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
) -> ExecutionResult<ValueAggregate> {
match &canon_stream.lambda {
Some(lambda) => apply_canon_stream_with_lambda(canon_stream.name, lambda, exec_ctx, trace_ctx),
None => apply_canon_stream_without_lambda(canon_stream.name, exec_ctx, trace_ctx),
}
}
fn apply_canon_stream_with_lambda(
stream_name: &str,
lambda: &LambdaAST<'_>,
ast_stream: &ast::CanonStream<'_>,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
) -> ExecutionResult<ValueAggregate> {
// TODO: refactor this code after boxed value
use crate::execution_step::boxed_value::JValuable;
let canon_stream = exec_ctx.scalars.get_canon_stream(stream_name)?;
let (result, tetraplet) = JValuable::apply_lambda_with_tetraplets(&canon_stream, lambda, exec_ctx)?;
let position = trace_ctx.trace_pos();
let value = ValueAggregate::new(Rc::new(result.into_owned()), Rc::new(tetraplet), position);
Ok(value)
}
fn apply_canon_stream_without_lambda(
stream_name: &str,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
) -> ExecutionResult<ValueAggregate> {
use crate::execution_step::boxed_value::JValuable;
let canon_stream = exec_ctx.scalars.get_canon_stream(stream_name)?;
// TODO: refactor this code after boxed value
let canon_stream = exec_ctx.scalars.get_canon_stream(ast_stream.name)?;
let value = JValuable::as_jvalue(&canon_stream).into_owned();
let tetraplet = canon_stream.tetraplet().clone();
let position = trace_ctx.trace_pos();
let value = ValueAggregate::new(Rc::new(value), tetraplet, position);
Ok(value)
}
fn apply_canon_stream_wl(
ast_stream: &ast::CanonStreamWithLambda<'_>,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
) -> ExecutionResult<ValueAggregate> {
// TODO: refactor this code after boxed value
use crate::execution_step::boxed_value::JValuable;
let canon_stream = exec_ctx.scalars.get_canon_stream(ast_stream.name)?;
let (result, tetraplet) = JValuable::apply_lambda_with_tetraplets(&canon_stream, &ast_stream.lambda, exec_ctx)?;
let position = trace_ctx.trace_pos();
let value = ValueAggregate::new(Rc::new(result.into_owned()), Rc::new(tetraplet), position);
Ok(value)
}

View File

@ -40,11 +40,11 @@ impl<'i> super::ExecutableInstruction<'i> for Call<'i> {
log_instruction!(call, exec_ctx, trace_ctx);
exec_ctx.tracker.meet_call();
let resolved_call = joinable!(ResolvedCall::new(self, exec_ctx), exec_ctx)
let resolved_call = joinable!(ResolvedCall::new(self, exec_ctx), exec_ctx, ())
.map_err(|e| set_last_error(self, exec_ctx, e, None))?;
let tetraplet = resolved_call.as_tetraplet();
joinable!(resolved_call.execute(self, exec_ctx, trace_ctx), exec_ctx)
joinable!(resolved_call.execute(self, exec_ctx, trace_ctx), exec_ctx, ())
.map_err(|e| set_last_error(self, exec_ctx, e, Some(tetraplet)))
}
}

View File

@ -40,7 +40,7 @@ use std::rc::Rc;
#[derive(Debug, Clone, PartialEq)]
pub(super) struct ResolvedCall<'i> {
tetraplet: RcSecurityTetraplet,
function_arg_paths: Rc<Vec<ast::Value<'i>>>,
function_arg_paths: Rc<Vec<ast::ImmutableValue<'i>>>,
output: ast::CallOutputValue<'i>,
}

View File

@ -25,12 +25,12 @@ use polyplets::ResolvedTriplet;
/// Resolve variables, literals, etc in the `Triplet`, and build a `ResolvedTriplet`.
pub(crate) fn resolve<'i>(triplet: &ast::Triplet<'i>, ctx: &ExecutionCtx<'i>) -> ExecutionResult<ResolvedTriplet> {
let ast::Triplet {
peer_pk,
peer_id: peer_pk,
service_id,
function_name,
} = triplet;
let peer_pk = resolve_to_string(peer_pk, ctx)?;
let peer_pk = resolve_peer_id_to_string(peer_pk, ctx)?;
let service_id = resolve_to_string(service_id, ctx)?;
let function_name = resolve_to_string(function_name, ctx)?;
@ -41,33 +41,58 @@ pub(crate) fn resolve<'i>(triplet: &ast::Triplet<'i>, ctx: &ExecutionCtx<'i>) ->
})
}
/// Resolve peer id to string by either resolving variable from `ExecutionCtx`, taking literal value, or etc.
// TODO: return Rc<String> to avoid excess cloning
// TODO: move this function into resolve in boxed value PR
pub(crate) fn resolve_peer_id_to_string<'i>(
value: &ast::ResolvableToPeerIdVariable<'i>,
exec_ctx: &ExecutionCtx<'i>,
) -> ExecutionResult<String> {
use crate::execution_step::resolver;
use ast::ResolvableToPeerIdVariable::*;
let ((jvalue, _), name) = match value {
InitPeerId => return Ok(exec_ctx.run_parameters.init_peer_id.to_string()),
Literal(value) => return Ok(value.to_string()),
Scalar(scalar) => (resolver::resolve_ast_scalar(scalar, exec_ctx)?, scalar.name),
ScalarWithLambda(scalar) => (resolver::resolve_ast_scalar_wl(scalar, exec_ctx)?, scalar.name),
CanonStreamWithLambda(canon_stream) => (
resolver::resolve_ast_canon_wl(canon_stream, exec_ctx)?,
canon_stream.name,
),
};
try_jvalue_to_string(jvalue, name)
}
/// Resolve value to string by either resolving variable from `ExecutionCtx`, taking literal value, or etc.
// TODO: return Rc<String> to avoid excess cloning
// TODO: move this function into resolve in boxed value PR
pub(crate) fn resolve_to_string<'i>(
value: &ast::CallInstrValue<'i>,
ctx: &ExecutionCtx<'i>,
value: &ast::ResolvableToStringVariable<'i>,
exec_ctx: &ExecutionCtx<'i>,
) -> ExecutionResult<String> {
use crate::execution_step::resolver::resolve_ast_variable_wl;
use ast::CallInstrValue::*;
use crate::execution_step::resolver;
use ast::ResolvableToStringVariable::*;
let resolved = match value {
InitPeerId => ctx.run_parameters.init_peer_id.to_string(),
Literal(value) => value.to_string(),
Variable(variable) => {
let (resolved, _) = resolve_ast_variable_wl(variable, ctx)?;
try_jvalue_to_string(resolved, variable)?
}
let ((jvalue, _), name) = match value {
Literal(value) => return Ok(value.to_string()),
Scalar(scalar) => (resolver::resolve_ast_scalar(scalar, exec_ctx)?, scalar.name),
ScalarWithLambda(scalar) => (resolver::resolve_ast_scalar_wl(scalar, exec_ctx)?, scalar.name),
CanonStreamWithLambda(canon_stream) => (
resolver::resolve_ast_canon_wl(canon_stream, exec_ctx)?,
canon_stream.name,
),
};
Ok(resolved)
try_jvalue_to_string(jvalue, name)
}
fn try_jvalue_to_string(jvalue: JValue, variable: &ast::VariableWithLambda<'_>) -> ExecutionResult<String> {
fn try_jvalue_to_string(jvalue: JValue, variable_name: impl Into<String>) -> ExecutionResult<String> {
match jvalue {
JValue::String(s) => Ok(s),
_ => Err(CatchableError::IncompatibleJValueType {
variable_name: variable.name().to_string(),
variable_name: variable_name.into(),
actual_value: jvalue,
expected_value_type: "string",
}

View File

@ -71,7 +71,7 @@ fn handle_unseen_canon(
exec_ctx: &mut ExecutionCtx<'_>,
trace_ctx: &mut TraceHandler,
) -> ExecutionResult<()> {
let peer_id = crate::execution_step::air::resolve_to_string(&ast_canon.peer_pk, exec_ctx)?;
let peer_id = crate::execution_step::air::resolve_peer_id_to_string(&ast_canon.peer_id, exec_ctx)?;
if exec_ctx.run_parameters.current_peer_id.as_str() != peer_id {
exec_ctx.subgraph_complete = false;

View File

@ -17,20 +17,24 @@
use crate::execution_step::air::ExecutionResult;
use crate::execution_step::execution_context::ExecutionCtx;
use crate::execution_step::resolver::prepare_last_error;
use crate::execution_step::resolver::resolve_ast_variable;
use crate::execution_step::resolver::resolve_ast_variable_wl;
use crate::JValue;
use air_parser::ast;
use std::borrow::Cow;
#[tracing::instrument(skip_all)]
pub(crate) fn are_matchable_eq<'ctx>(
left: &ast::Value<'_>,
right: &ast::Value<'_>,
left: &ast::ImmutableValue<'_>,
right: &ast::ImmutableValue<'_>,
exec_ctx: &'ctx ExecutionCtx<'_>,
) -> ExecutionResult<bool> {
use ast::Value::*;
use ast::ImmutableValue::*;
match (left, right) {
// TODO: introduce traits to refactor this in boxed values
(InitPeerId, InitPeerId) => Ok(true),
(InitPeerId, matchable) | (matchable, InitPeerId) => compare_matchable(
matchable,
@ -78,6 +82,27 @@ pub(crate) fn are_matchable_eq<'ctx>(
}
(Variable(left_variable), Variable(right_variable)) => {
let (left_value, _) = resolve_ast_variable(left_variable, exec_ctx)?;
let (right_value, _) = resolve_ast_variable(right_variable, exec_ctx)?;
Ok(left_value == right_value)
}
(Variable(left_variable), VariableWithLambda(right_variable)) => {
let (left_value, _) = resolve_ast_variable(left_variable, exec_ctx)?;
let (right_value, _) = resolve_ast_variable_wl(right_variable, exec_ctx)?;
Ok(left_value == right_value)
}
(VariableWithLambda(left_variable), Variable(right_variable)) => {
let (left_value, _) = resolve_ast_variable_wl(left_variable, exec_ctx)?;
let (right_value, _) = resolve_ast_variable(right_variable, exec_ctx)?;
Ok(left_value == right_value)
}
(VariableWithLambda(left_variable), VariableWithLambda(right_variable)) => {
let (left_value, _) = resolve_ast_variable_wl(left_variable, exec_ctx)?;
let (right_value, _) = resolve_ast_variable_wl(right_variable, exec_ctx)?;
@ -86,15 +111,14 @@ pub(crate) fn are_matchable_eq<'ctx>(
}
}
use std::borrow::Cow;
type Comparator<'a> = Box<dyn Fn(Cow<'_, JValue>) -> bool + 'a>;
fn compare_matchable<'ctx>(
matchable: &ast::Value<'_>,
matchable: &ast::ImmutableValue<'_>,
exec_ctx: &'ctx ExecutionCtx<'_>,
comparator: Comparator<'ctx>,
) -> ExecutionResult<bool> {
use ast::Value::*;
use ast::ImmutableValue::*;
match matchable {
InitPeerId => {
@ -131,6 +155,10 @@ fn compare_matchable<'ctx>(
Ok(comparator(Cow::Owned(jvalue)))
}
Variable(variable) => {
let (jvalue, _) = resolve_ast_variable(variable, exec_ctx)?;
Ok(comparator(Cow::Owned(jvalue)))
}
VariableWithLambda(variable) => {
let (jvalue, _) = resolve_ast_variable_wl(variable, exec_ctx)?;
Ok(comparator(Cow::Owned(jvalue)))
}

View File

@ -17,8 +17,9 @@
use super::ExecutionCtx;
use super::ExecutionResult;
use super::TraceHandler;
use crate::execution_step::boxed_value::Variable;
use crate::execution_step::execution_context::check_error_object;
use crate::execution_step::resolver::{apply_lambda, resolve_ast_scalar_wl};
use crate::execution_step::resolver;
use crate::execution_step::CatchableError;
use crate::execution_step::LastError;
use crate::execution_step::RcSecurityTetraplet;
@ -30,8 +31,6 @@ use air_parser::ast;
use air_parser::ast::Fail;
use polyplets::SecurityTetraplet;
use crate::execution_step::boxed_value::Variable;
use air_lambda_ast::LambdaAST;
use std::rc::Rc;
impl<'i> super::ExecutableInstruction<'i> for Fail<'i> {
@ -40,19 +39,29 @@ impl<'i> super::ExecutableInstruction<'i> for Fail<'i> {
match self {
Fail::Scalar(scalar) => fail_with_scalar(scalar, exec_ctx),
Fail::ScalarWithLambda(scalar) => fail_with_scalar_wl(scalar, exec_ctx),
&Fail::Literal {
ret_code,
error_message,
} => fail_with_literals(ret_code, error_message, self, exec_ctx),
Fail::CanonStream { name, lambda } => fail_with_canon_stream(name, lambda, exec_ctx),
Fail::CanonStreamWithLambda(canon_stream) => fail_with_canon_stream(canon_stream, exec_ctx),
// bubble last error up
Fail::LastError => fail_with_last_error(exec_ctx),
}
}
}
fn fail_with_scalar<'i>(scalar: &ast::ScalarWithLambda<'i>, exec_ctx: &mut ExecutionCtx<'i>) -> ExecutionResult<()> {
let (value, mut tetraplet) = resolve_ast_scalar_wl(scalar, exec_ctx)?;
fn fail_with_scalar<'i>(scalar: &ast::Scalar<'i>, exec_ctx: &mut ExecutionCtx<'i>) -> ExecutionResult<()> {
let (value, mut tetraplet) = resolver::resolve_ast_scalar(scalar, exec_ctx)?;
// tetraplets always have one element here and it'll be refactored after boxed value
let tetraplet = tetraplet.remove(0);
check_error_object(&value).map_err(CatchableError::InvalidLastErrorObjectError)?;
fail_with_error_object(exec_ctx, Rc::new(value), Some(tetraplet))
}
fn fail_with_scalar_wl<'i>(scalar: &ast::ScalarWithLambda<'i>, exec_ctx: &mut ExecutionCtx<'i>) -> ExecutionResult<()> {
let (value, mut tetraplet) = resolver::resolve_ast_scalar_wl(scalar, exec_ctx)?;
// tetraplets always have one element here and it'll be refactored after boxed value
let tetraplet = tetraplet.remove(0);
check_error_object(&value).map_err(CatchableError::InvalidLastErrorObjectError)?;
@ -79,14 +88,13 @@ fn fail_with_literals(
fail_with_error_object(exec_ctx, Rc::new(error_object), Some(literal_tetraplet))
}
fn fail_with_canon_stream<'i>(
name: &'i str,
lambda: &LambdaAST<'i>,
exec_ctx: &mut ExecutionCtx<'i>,
fn fail_with_canon_stream(
ast_canon: &ast::CanonStreamWithLambda<'_>,
exec_ctx: &mut ExecutionCtx<'_>,
) -> ExecutionResult<()> {
let variable = Variable::CanonStream { name };
let variable = Variable::CanonStream { name: ast_canon.name };
let (value, tetraplet) = apply_lambda(variable, lambda, exec_ctx)?;
let (value, tetraplet) = resolver::apply_lambda(variable, &ast_canon.lambda, exec_ctx)?;
// tetraplets always have one element here and it'll be refactored after boxed value
check_error_object(&value).map_err(CatchableError::InvalidLastErrorObjectError)?;

View File

@ -37,19 +37,48 @@ pub(crate) enum FoldIterableScalar {
ScalarBased(IterableValue),
}
/// Constructs iterable value for given scalar iterable.
pub(crate) fn construct_scalar_iterable_value<'ctx>(
iterable: &ast::ScalarWithLambda<'ctx>,
exec_ctx: &ExecutionCtx<'ctx>,
/// Creates iterable value for given scalar iterable.
pub(crate) fn create_scalar_iterable(
exec_ctx: &ExecutionCtx<'_>,
variable_name: &str,
) -> ExecutionResult<FoldIterableScalar> {
match &iterable.lambda {
None => create_scalar_iterable(exec_ctx, iterable.name),
Some(lambda) => create_scalar_lambda_iterable(exec_ctx, iterable.name, lambda),
match exec_ctx.scalars.get_value(variable_name)? {
ScalarRef::Value(call_result) => from_value(call_result.clone(), variable_name),
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().expect(PEEK_ALLOWED_ON_NON_EMPTY);
let call_result = iterable_value.into_resolved_result();
from_value(call_result, variable_name)
}
}
}
/// Constructs iterable value for given canon stream.
pub(crate) fn construct_canon_stream_iterable_value<'ctx>(
/// Creates iterable value for given scalar with lambda iterable.
pub(crate) fn create_scalar_wl_iterable<'ctx>(
scalar_iterable: &ast::ScalarWithLambda<'ctx>,
exec_ctx: &ExecutionCtx<'ctx>,
) -> ExecutionResult<FoldIterableScalar> {
use crate::execution_step::lambda_applier::select_by_lambda_from_scalar;
let scalar_name = scalar_iterable.name;
let lambda = &scalar_iterable.lambda;
match exec_ctx.scalars.get_value(scalar_name)? {
ScalarRef::Value(variable) => {
let jvalues = select_by_lambda_from_scalar(&variable.result, lambda, exec_ctx)?;
let tetraplet = variable.tetraplet.deref().clone();
from_jvalue(jvalues, tetraplet, lambda)
}
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().unwrap();
let jvalue = iterable_value.apply_lambda(lambda, exec_ctx)?;
let tetraplet = to_tetraplet(&iterable_value);
from_jvalue(jvalue, tetraplet, lambda)
}
}
}
/// Creates iterable value for given canon stream.
pub(crate) fn create_canon_stream_iterable_value<'ctx>(
ast_canon_stream: &ast::CanonStream<'ctx>,
exec_ctx: &ExecutionCtx<'ctx>,
) -> ExecutionResult<FoldIterableScalar> {
@ -86,17 +115,6 @@ pub(crate) fn construct_stream_iterable_values(
.collect::<Vec<_>>()
}
fn create_scalar_iterable(exec_ctx: &ExecutionCtx<'_>, variable_name: &str) -> ExecutionResult<FoldIterableScalar> {
match exec_ctx.scalars.get_value(variable_name)? {
ScalarRef::Value(call_result) => from_value(call_result.clone(), variable_name),
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().expect(PEEK_ALLOWED_ON_NON_EMPTY);
let call_result = iterable_value.into_resolved_result();
from_value(call_result, variable_name)
}
}
}
/// Constructs iterable value from resolved call result.
fn from_value(call_result: ValueAggregate, variable_name: &str) -> ExecutionResult<FoldIterableScalar> {
let len = match &call_result.result.deref() {
@ -124,29 +142,6 @@ fn from_value(call_result: ValueAggregate, variable_name: &str) -> ExecutionResu
Ok(iterable)
}
fn create_scalar_lambda_iterable(
exec_ctx: &ExecutionCtx<'_>,
scalar_name: &str,
lambda: &LambdaAST<'_>,
) -> ExecutionResult<FoldIterableScalar> {
use crate::execution_step::lambda_applier::select_by_lambda_from_scalar;
match exec_ctx.scalars.get_value(scalar_name)? {
ScalarRef::Value(variable) => {
let jvalues = select_by_lambda_from_scalar(&variable.result, lambda, exec_ctx)?;
let tetraplet = variable.tetraplet.deref().clone();
from_jvalue(jvalues, tetraplet, lambda)
}
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().expect(PEEK_ALLOWED_ON_NON_EMPTY);
let jvalue = iterable_value.apply_lambda(lambda, exec_ctx)?;
let tetraplet = to_tetraplet(&iterable_value);
from_jvalue(jvalue, tetraplet, lambda)
}
}
}
/// Construct IterableValue from the result and given triplet.
fn from_jvalue(
jvalue: Cow<'_, JValue>,

View File

@ -35,10 +35,13 @@ impl<'i> ExecutableInstruction<'i> for FoldScalar<'i> {
let iterable = match &self.iterable {
FoldScalarIterable::Scalar(scalar) => {
joinable!(construct_scalar_iterable_value(scalar, exec_ctx), exec_ctx)?
joinable!(create_scalar_iterable(exec_ctx, scalar.name), exec_ctx, ())?
}
FoldScalarIterable::ScalarWithLambda(scalar) => {
joinable!(create_scalar_wl_iterable(scalar, exec_ctx), exec_ctx, ())?
}
FoldScalarIterable::CanonStream(canon_stream) => {
joinable!(construct_canon_stream_iterable_value(canon_stream, exec_ctx), exec_ctx)?
joinable!(create_canon_stream_iterable_value(canon_stream, exec_ctx), exec_ctx, ())?
}
// just do nothing on an empty array
FoldScalarIterable::EmptyArray => return Ok(()),

View File

@ -31,7 +31,8 @@ impl<'i> super::ExecutableInstruction<'i> for Match<'i> {
let are_values_equal = joinable!(
are_matchable_eq(&self.left_value, &self.right_value, exec_ctx),
exec_ctx
exec_ctx,
()
)?;
if !are_values_equal {

View File

@ -31,7 +31,8 @@ impl<'i> super::ExecutableInstruction<'i> for MisMatch<'i> {
let are_values_equal = joinable!(
are_matchable_eq(&self.left_value, &self.right_value, exec_ctx),
exec_ctx
exec_ctx,
()
)?;
if are_values_equal {

View File

@ -32,7 +32,7 @@ mod par;
mod seq;
mod xor;
pub(crate) use call::triplet::resolve_to_string;
pub(crate) use call::triplet::resolve_peer_id_to_string;
pub(crate) use fold::FoldState;
use super::boxed_value::ScalarRef;
@ -141,11 +141,11 @@ macro_rules! log_instruction {
/// This macro converts joinable errors to Ok and sets subgraph complete to false.
#[macro_export]
macro_rules! joinable {
($cmd:expr, $exec_ctx:expr) => {
($cmd:expr, $exec_ctx:expr, $ok_result:expr) => {
match $cmd {
Err(e) if e.is_joinable() => {
$exec_ctx.subgraph_complete = false;
return Ok(());
return Ok($ok_result);
}
v => v,
}

View File

@ -22,6 +22,7 @@ pub(crate) enum Variable<'i> {
Scalar {
name: &'i str,
},
#[allow(dead_code)] // it will be used in BoxedValues
Stream {
name: &'i str,
generation: Generation,
@ -37,38 +38,28 @@ impl<'i> Variable<'i> {
Self::Scalar { name }
}
pub(crate) fn stream(name: &'i str, generation: Generation, position: AirPos) -> Self {
Self::Stream {
name,
generation,
position,
}
}
pub(crate) fn canon_stream(name: &'i str) -> Self {
Self::CanonStream { name }
}
}
impl<'i> From<&ast::Variable<'i>> for Variable<'i> {
fn from(ast_variable: &ast::Variable<'i>) -> Self {
use ast::Variable::*;
impl<'i> From<&ast::ImmutableVariable<'i>> for Variable<'i> {
fn from(ast_variable: &ast::ImmutableVariable<'i>) -> Self {
use ast::ImmutableVariable::*;
match ast_variable {
Scalar(scalar) => Self::scalar(scalar.name),
Stream(stream) => Self::stream(stream.name, Generation::Last, stream.position),
CanonStream(canon_stream) => Self::canon_stream(canon_stream.name),
}
}
}
impl<'i> From<&ast::VariableWithLambda<'i>> for Variable<'i> {
fn from(ast_variable: &ast::VariableWithLambda<'i>) -> Self {
use ast::VariableWithLambda::*;
impl<'i> From<&ast::ImmutableVariableWithLambda<'i>> for Variable<'i> {
fn from(ast_variable: &ast::ImmutableVariableWithLambda<'i>) -> Self {
use ast::ImmutableVariableWithLambda::*;
match ast_variable {
Scalar(scalar) => Self::scalar(scalar.name),
Stream(stream) => Self::stream(stream.name, Generation::Last, stream.position),
CanonStream(canon_stream) => Self::canon_stream(canon_stream.name),
}
}

View File

@ -31,10 +31,10 @@ use std::rc::Rc;
/// Resolve value to called function arguments.
pub(crate) fn resolve_to_args<'i>(
value: &ast::Value<'i>,
value: &ast::ImmutableValue<'i>,
ctx: &ExecutionCtx<'i>,
) -> ExecutionResult<(JValue, RcSecurityTetraplets)> {
use ast::Value::*;
use ast::ImmutableValue::*;
match value {
InitPeerId => prepare_const(ctx.run_parameters.init_peer_id.as_str(), ctx),
@ -45,7 +45,8 @@ pub(crate) fn resolve_to_args<'i>(
Boolean(value) => prepare_const(*value, ctx),
Number(value) => prepare_const(value, ctx),
EmptyArray => prepare_const(json!([]), ctx),
Variable(variable) => resolve_ast_variable_wl(variable, ctx),
Variable(variable) => resolve_ast_variable(variable, ctx),
VariableWithLambda(variable) => resolve_ast_variable_wl(variable, ctx),
}
}
@ -119,22 +120,37 @@ pub(crate) fn resolve_variable<'ctx, 'i>(
}
#[tracing::instrument(level = "trace", skip(exec_ctx))]
pub(crate) fn resolve_ast_variable_wl<'ctx, 'i>(
ast_variable: &ast::VariableWithLambda<'_>,
pub(crate) fn resolve_ast_variable<'ctx, 'i>(
ast_variable: &ast::ImmutableVariable<'_>,
exec_ctx: &'ctx ExecutionCtx<'i>,
) -> ExecutionResult<(JValue, RcSecurityTetraplets)> {
let variable: Variable<'_> = ast_variable.into();
match ast_variable.lambda() {
Some(lambda) => apply_lambda(variable, lambda, exec_ctx).map(|(value, tetraplet)| {
let tetraplet = Rc::new(tetraplet);
(value, vec![tetraplet])
}),
None => {
let value = resolve_variable(variable, exec_ctx)?;
let tetraplets = value.as_tetraplets();
Ok((value.into_jvalue(), tetraplets))
}
}
let value = resolve_variable(variable, exec_ctx)?;
let tetraplets = value.as_tetraplets();
Ok((value.into_jvalue(), tetraplets))
}
#[tracing::instrument(level = "trace", skip(exec_ctx))]
pub(crate) fn resolve_ast_variable_wl<'ctx, 'i>(
ast_variable: &ast::ImmutableVariableWithLambda<'_>,
exec_ctx: &'ctx ExecutionCtx<'i>,
) -> ExecutionResult<(JValue, RcSecurityTetraplets)> {
let variable: Variable<'_> = ast_variable.into();
apply_lambda(variable, ast_variable.lambda(), exec_ctx).map(|(value, tetraplet)| {
let tetraplet = Rc::new(tetraplet);
(value, vec![tetraplet])
})
}
#[tracing::instrument(level = "trace", skip(exec_ctx))]
pub(crate) fn resolve_ast_scalar<'ctx, 'i>(
ast_scalar: &ast::Scalar<'_>,
exec_ctx: &'ctx ExecutionCtx<'i>,
) -> ExecutionResult<(JValue, RcSecurityTetraplets)> {
// TODO: wrap lambda path with Rc to make this clone cheaper
let variable = ast::ImmutableVariable::Scalar(ast_scalar.clone());
resolve_ast_variable(&variable, exec_ctx)
}
#[tracing::instrument(level = "trace", skip(exec_ctx))]
@ -143,7 +159,17 @@ pub(crate) fn resolve_ast_scalar_wl<'ctx, 'i>(
exec_ctx: &'ctx ExecutionCtx<'i>,
) -> ExecutionResult<(JValue, RcSecurityTetraplets)> {
// TODO: wrap lambda path with Rc to make this clone cheaper
let variable = ast::VariableWithLambda::Scalar(ast_scalar.clone());
let variable = ast::ImmutableVariableWithLambda::Scalar(ast_scalar.clone());
resolve_ast_variable_wl(&variable, exec_ctx)
}
#[tracing::instrument(level = "trace", skip(exec_ctx))]
pub(crate) fn resolve_ast_canon_wl<'ctx, 'i>(
ast_canon: &ast::CanonStreamWithLambda<'_>,
exec_ctx: &'ctx ExecutionCtx<'i>,
) -> ExecutionResult<(JValue, RcSecurityTetraplets)> {
// TODO: wrap lambda path with Rc to make this clone cheaper
let variable = ast::ImmutableVariableWithLambda::CanonStream(ast_canon.clone());
resolve_ast_variable_wl(&variable, exec_ctx)
}

View File

@ -178,9 +178,15 @@ fn stream_merge() {
(call "A" ("get_providers" "") [] $providers)
(seq
(call "A" ("get_providers" "") [] $providers)
(seq
(call "B" ("" "2") [$providers] $void)
(call "B" ("" "3") [$void] $void)
(seq
(seq
(canon "B" $providers #providers)
(call "B" ("" "2") [#providers] $void)
)
(seq
(canon "B" $void #void)
(call "B" ("" "3") [#void] $void)
)
)
)
)

View File

@ -64,34 +64,6 @@ fn dont_wait_on_json_path() {
assert_eq!(result.next_peer_pks, vec![test_params.init_peer_id.to_string()]);
}
#[test]
fn wait_on_stream_json_path_by_id() {
let local_peer_id = "local_peer_id";
let mut local_vm = create_avm(unit_call_service(), local_peer_id);
let non_join_stream_script = f!(r#"
(par
(call "{local_peer_id}" ("" "") [] $status)
(call "{local_peer_id}" ("history" "add") [$status.$[0]!])
)"#);
let result = checked_call_vm!(local_vm, <_>::default(), non_join_stream_script, "", "");
let actual_trace = trace_from_result(&result);
assert_eq!(actual_trace.len(), 3);
let join_stream_script = f!(r#"
(par
(call "{local_peer_id}" ("" "") [] $status)
(call "{local_peer_id}" ("history" "add") [$status.$[1]!]) ; $status stream here has only one value
)"#);
let result = checked_call_vm!(local_vm, <_>::default(), join_stream_script, "", "");
let actual_trace = trace_from_result(&result);
assert_eq!(actual_trace.len(), 2); // par and the first call emit traces, second call doesn't
}
#[test]
fn wait_on_empty_stream_json_path() {
let local_peer_id = "local_peer_id";
@ -108,13 +80,17 @@ fn wait_on_empty_stream_json_path() {
)
)
)
(call "{local_peer_id}" ("" "") [$ns.$.[0] $ns.$.[1] $ns])
(seq
(canon "{local_peer_id}" $ns #ns)
(call "{local_peer_id}" ("" "") [#ns.$.[0] #ns.$.[1] #ns])
)
)"#);
let result = checked_call_vm!(local_vm, <_>::default(), join_stream_script, "", "");
print_trace(&result, "");
let actual_trace = trace_from_result(&result);
assert_eq!(actual_trace.len(), 1); // only the first call should produce a trace
assert_eq!(actual_trace.len(), 2); // only the first call and canon should produce a trace
}
#[test]
@ -249,26 +225,19 @@ fn fold_with_join_behaviour() {
#[test]
fn canon_with_empty_behaviour() {
let peer_1_id = "peer_1_id";
let peer_2_id = "peer_2_id";
let peer_id = "peer_id";
let mut peer_2 = create_avm(unit_call_service(), peer_2_id);
let mut peer_2 = create_avm(unit_call_service(), peer_id);
let script = f!(r#"
(par
(call "{peer_1_id}" ("" "") [] $stream)
(canon "{peer_2_id}" $stream #canon_stream))
(canon "{peer_id}" $stream #canon_stream)
"#);
let result = checked_call_vm!(peer_2, <_>::default(), script, "", "");
let actual_trace = trace_from_result(&result);
let expected_trace = vec![
executed_state::par(1, 1),
executed_state::request_sent_by(peer_2_id),
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_2_id", "service_id": ""}, "values": []}),
),
];
let expected_trace = vec![executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id", "service_id": ""}, "values": []}),
)];
assert_eq!(actual_trace, expected_trace);
}

View File

@ -148,7 +148,10 @@ fn flattening_empty_values() {
let script = f!(r#"
(seq
(call "{set_variable_peer_id}" ("" "") [] $stream)
(call "{local_peer_id}" ("" "") [$stream.$.[1]!]) ; here $stream.$.[1] returns an empty array
(seq
(canon "{local_peer_id}" $stream #stream)
(call "{local_peer_id}" ("" "") [#stream.$.[1]!]) ; here #stream.$.[1] returns an empty array
)
)
"#);

View File

@ -71,7 +71,10 @@ fn length_functor_for_stream() {
(seq
(ap 1 $stream)
(ap 1 $stream))
(call %init_peer_id% ("" "") [$stream.length]) ; behaviour = echo
(seq
(canon %init_peer_id% $stream #stream)
(call %init_peer_id% ("" "") [#stream.length]) ; behaviour = echo
)
)
"#;
@ -85,6 +88,21 @@ fn length_functor_for_stream() {
let expected_trace = vec![
executed_state::ap(0),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""},
"values": [
{
"result": 1,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""},
"trace_pos": 0,
},
{
"result": 1,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""},
"trace_pos": 1,
},
]
})),
executed_state::scalar_number(2),
];
assert_eq!(actual_trace, expected_trace);
@ -94,7 +112,10 @@ fn length_functor_for_stream() {
fn length_functor_for_empty_stream() {
let script = r#"
(new $stream
(call %init_peer_id% ("" "") [$stream.length]) ; behaviour = echo
(seq
(canon %init_peer_id% $stream #canon_stream)
(call %init_peer_id% ("" "") [#canon_stream.length]) ; behaviour = echo
)
)
"#;
@ -105,7 +126,13 @@ fn length_functor_for_empty_stream() {
let result = executor.execute_one(init_peer_id).unwrap();
let actual_trace = trace_from_result(&result);
let expected_trace = vec![executed_state::scalar_number(0)];
let expected_trace = vec![
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""},
"values": []} ),
),
executed_state::scalar_number(0),
];
assert_eq!(actual_trace, expected_trace);
}

View File

@ -135,7 +135,10 @@ fn lambda_with_number_stream() {
)
)
)
(call "{local_peer_id}" ("" "") [$stream.$.[number_accessor]])
(seq
(canon "{local_peer_id}" $stream #canon_stream)
(call "{local_peer_id}" ("" "") [#canon_stream.$.[number_accessor]])
)
)
"#);
@ -143,7 +146,7 @@ fn lambda_with_number_stream() {
let result = checked_call_vm!(local_vm, <_>::default(), script, "", result.data);
let actual_trace = trace_from_result(&result);
assert_eq!(&actual_trace[5.into()], &executed_state::scalar_number(2));
assert_eq!(&actual_trace[6.into()], &executed_state::scalar_number(2));
}
#[test]
@ -180,7 +183,10 @@ fn lambda_with_number_stream_and_followed_scalar() {
)
)
)
(call "{local_peer_id}" ("" "") [$stream.$.[number_accessor].field_1]) ;; get the 2nd value and then access its field
(seq
(canon "{local_peer_id}" $stream #canon_stream)
(call "{local_peer_id}" ("" "") [#canon_stream.$.[number_accessor].field_1]) ;; get the 2nd value and then access its field
)
)
"#);
@ -188,7 +194,7 @@ fn lambda_with_number_stream_and_followed_scalar() {
let result = checked_call_vm!(local_vm, <_>::default(), script, "", result.data);
let actual_trace = trace_from_result(&result);
assert_eq!(&actual_trace[6.into()], &executed_state::scalar_number(checkable_value));
assert_eq!(&actual_trace[7.into()], &executed_state::scalar_number(checkable_value));
}
#[test]
@ -223,8 +229,11 @@ fn lambda_with_scalar_join() {
assert_eq!(&trace[3.into()], &executed_state::request_sent_by("set_variable"));
}
#[ignore]
// after 0.32 version AIR is no longer supports lambdas over stream,
// although this test could be useful in the future for functors
#[test]
fn lambda_with_stream_join() {
fn lambda_with_canon_stream_join() {
let set_variable_peer_id = "set_variable";
let variables = maplit::hashmap! {
"number_accessor".to_string() => json!(1),
@ -252,7 +261,10 @@ fn lambda_with_stream_join() {
)
)
)
(call "{local_peer_id}" ("" "") [$stream.$.[number_accessor]])
(seq
(canon "{local_peer_id}" $stream #stream)
(call "{local_peer_id}" ("" "") [#stream.$.[number_accessor]])
)
)
"#);
@ -261,7 +273,7 @@ fn lambda_with_stream_join() {
let actual_trace = trace_from_result(&result);
assert_eq!(
&actual_trace[6.into()],
&executed_state::request_sent_by("set_variable")
&actual_trace[7.into()],
&executed_state::request_sent_by("set_variable"),
);
}

View File

@ -51,7 +51,9 @@ fn ap_with_fold() {
(null))))
(seq
(call "{local_vm_peer_id}" ("op" "noop") [])
(call "{local_vm_peer_id}" ("return" "") [$inner]))))
(seq
(canon "{local_vm_peer_id}" $inner #canon_stream)
(call "{local_vm_peer_id}" ("return" "") [#canon_stream])))))
"#);
let result = checked_call_vm!(set_variable_vm, <_>::default(), &script, "", "");

View File

@ -154,12 +154,15 @@ fn merging_fold_iterations_extensively_2() {
)
)
)
(call "p1" ("test" "print") [$pid-num-arrs]) ; behaviour = echo
(seq
(canon "p1" $pid-num-arrs #pid-num-arrs-1)
(call "p1" ("test" "print") [#pid-num-arrs-1]) ; behaviour = echo
)
)
(seq
(seq
(canon "p1" $pid-num-arrs #pid-num-arrs)
(call "p1" ("test" "print") [$pid-num-arrs]) ; behaviour = echo
(canon "p1" $pid-num-arrs #pid-num-arrs-2)
(call "p1" ("test" "print") [#pid-num-arrs-2]) ; behaviour = echo
)
(new $result
(fold $pid-num-arrs pid-num-arr

View File

@ -405,7 +405,10 @@ fn recursive_stream_fold_with_n_service_call() {
)
)
)
(call %init_peer_id% ("op" "identity") [$result] result-fix)
(seq
(canon %init_peer_id% $result #canon_stream)
(call %init_peer_id% ("op" "identity") [#canon_stream] result-fix)
)
)
)
)

View File

@ -34,13 +34,20 @@ fn empty_stream() {
})
}
let mut vm = create_avm(arg_type_check_closure(), "A");
let vm_peer_id = "vm_peer_id";
let mut vm = create_avm(arg_type_check_closure(), vm_peer_id);
let script = r#"
let script = f!(r#"
(seq
(call "A" ("" "") [$stream] $other_stream)
(par
(call "unknown_peer" ("" "") [] $stream) ; to make validator happy
(seq
(canon "{vm_peer_id}" $stream #canon_stream)
(call "{vm_peer_id}" ("" "") [#canon_stream] $other_stream)
)
)
(null)
)"#;
)"#);
let _ = checked_call_vm!(vm, <_>::default(), script, "", "");
}

View File

@ -59,14 +59,30 @@ fn ap_with_string_literal() {
let script = f!(r#"
(seq
(ap "{some_string}" $stream)
(call "{vm_1_peer_id}" ("" "") [$stream])
)
(seq
(canon "{vm_1_peer_id}" $stream #canon_stream)
(call "{vm_1_peer_id}" ("" "") [#canon_stream])))
"#);
let result = checked_call_vm!(vm_1, <_>::default(), script, "", "");
let actual_trace = trace_from_result(&result);
let expected_state = vec![executed_state::ap(0), executed_state::scalar(json!([some_string]))];
let expected_state = vec![
executed_state::ap(0),
executed_state::canon(json!(
{
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [
{
"result": "some_string",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 0
}
]
}
)),
executed_state::scalar(json!([some_string])),
];
assert_eq!(actual_trace, expected_state);
assert!(result.next_peer_pks.is_empty());
@ -80,14 +96,28 @@ fn ap_with_bool_literal() {
let script = f!(r#"
(seq
(ap true $stream)
(call "{vm_1_peer_id}" ("" "") [$stream])
)
(seq
(canon "{vm_1_peer_id}" $stream #canon_stream)
(call "{vm_1_peer_id}" ("" "") [#canon_stream])))
"#);
let result = checked_call_vm!(vm_1, <_>::default(), script, "", "");
let actual_trace = trace_from_result(&result);
let expected_state = vec![executed_state::ap(0), executed_state::scalar(json!([true]))];
let expected_state = vec![
executed_state::ap(0),
executed_state::canon(json!( {
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [
{
"result": true,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 0
}
]
})),
executed_state::scalar(json!([true])),
];
assert_eq!(actual_trace, expected_state);
assert!(result.next_peer_pks.is_empty());
@ -101,14 +131,28 @@ fn ap_with_number_literal() {
let script = f!(r#"
(seq
(ap 100 $stream)
(call "{vm_1_peer_id}" ("" "") [$stream])
)
(seq
(canon "{vm_1_peer_id}" $stream #canon_stream)
(call "{vm_1_peer_id}" ("" "") [#canon_stream])))
"#);
let result = checked_call_vm!(vm_1, <_>::default(), script, "", "");
let actual_trace = trace_from_result(&result);
let expected_state = vec![executed_state::ap(0), executed_state::scalar(json!([100]))];
let expected_state = vec![
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [
{
"result": 100,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 0
}
]
})),
executed_state::scalar(json!([100])),
];
assert_eq!(actual_trace, expected_state);
assert!(result.next_peer_pks.is_empty());
@ -122,14 +166,28 @@ fn ap_with_last_error() {
let script = f!(r#"
(seq
(ap %last_error% $stream)
(call "{vm_1_peer_id}" ("" "") [$stream])
)
(seq
(canon "{vm_1_peer_id}" $stream #canon_stream)
(call "{vm_1_peer_id}" ("" "") [#canon_stream])))
"#);
let result = checked_call_vm!(vm_1, <_>::default(), script, "", "");
let actual_trace = trace_from_result(&result);
let expected_state = vec![executed_state::ap(0), executed_state::scalar(json!([null]))];
let expected_state = vec![
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [
{
"result": null,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 0
}
]
})),
executed_state::scalar(json!([null])),
];
assert_eq!(actual_trace, expected_state);
assert!(result.next_peer_pks.is_empty());
@ -190,10 +248,10 @@ fn ap_with_dst_stream() {
(seq
(seq
(call "{vm_1_peer_id}" ("" "") ["scalar_1_result"] scalar_1)
(ap scalar_1 $stream)
)
(call "{vm_2_peer_id}" ("" "") [$stream])
)
(ap scalar_1 $stream))
(seq
(canon "{vm_2_peer_id}" $stream #canon_stream)
(call "{vm_2_peer_id}" ("" "") [#canon_stream])))
"#);
let result = checked_call_vm!(vm_1, <_>::default(), &script, "", "");
@ -203,6 +261,16 @@ fn ap_with_dst_stream() {
let expected_state = vec![
executed_state::scalar(json!({ "field": test_value })),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_2_peer_id", "service_id": ""},
"values": [
{
"result": {"field": "scalar_2"},
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"trace_pos": 1
}
]
})),
executed_state::scalar(json!([{ "field": test_value }])),
];
@ -227,7 +295,9 @@ fn ap_canon_stream_with_lambda() {
(canon "{vm_1_peer_id}" $stream #canon_stream)
(seq
(ap #canon_stream.$.[1] $stream_2)
(call "{vm_1_peer_id}" ("" "") [$stream_2]))))
(seq
(canon "{vm_1_peer_id}" $stream_2 #canon_stream_2)
(call "{vm_1_peer_id}" ("" "") [#canon_stream_2])))))
"#);
let result = checked_call_vm!(vm_1, <_>::default(), &script, "", "");
@ -238,10 +308,22 @@ fn ap_canon_stream_with_lambda() {
executed_state::stream_number(1, 1),
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [{"result": 0, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""}, "trace_pos": 0},
{"result": 1, "tetraplet": {"function_name": "some_function_name", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": "some_service_name"}, "trace_pos": 1}]}),
"values": [{"result": 0, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""}, "trace_pos": 0},
{"result": 1, "tetraplet": {"function_name": "some_function_name", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": "some_service_name"}, "trace_pos": 1}]}),
),
executed_state::ap(0),
executed_state::canon(json!(
{
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [
{
"result": 1,
"tetraplet": {"function_name": "some_function_name", "json_path": ".$.[1]", "peer_pk": "vm_1_peer_id", "service_id": "some_service_name"},
"trace_pos": 3,
}
]
}
)),
executed_state::scalar(json!([1])),
];
assert_eq!(actual_trace, expected_state);
@ -272,10 +354,13 @@ fn ap_canon_stream() {
(canon "{vm_1_peer_id}" $stream #canon_stream)
(seq
(ap #canon_stream $stream_2)
(call "{vm_1_peer_id}" ("" "") [$stream_2]))))
(seq
(canon "{vm_1_peer_id}" $stream_2 #canon_stream_2)
(call "{vm_1_peer_id}" ("" "") [#canon_stream_2])))))
"#);
let result = checked_call_vm!(vm_1, <_>::default(), &script, "", "");
print_trace(&result, "");
let actual_trace = trace_from_result(&result);
let expected_state = vec![
@ -283,10 +368,22 @@ fn ap_canon_stream() {
executed_state::stream_number(1, 1),
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [{"result": 0, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""}, "trace_pos": 0},
{"result": 1, "tetraplet": {"function_name": "some_function_name", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": "some_service_name"}, "trace_pos": 1}]}),
"values": [{"result": 0, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""}, "trace_pos": 0},
{"result": 1, "tetraplet": {"function_name": "some_function_name", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": "some_service_name"}, "trace_pos": 1}]}),
),
executed_state::ap(0),
executed_state::canon(json!(
{
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [
{
"result": [0, 1],
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"trace_pos": 3,
}
]
}
)),
executed_state::scalar(json!([[0, 1]])),
];
assert_eq!(actual_trace, expected_state);

View File

@ -161,7 +161,9 @@ fn canon_stream_can_be_created_from_aps() {
(canon "{vm_1_peer_id}" $stream #canon_stream)
(seq
(ap #canon_stream $stream_2)
(call "{vm_2_peer_id}" ("" "") [$stream_2]))))
(seq
(canon "{vm_2_peer_id}" $stream_2 #canon_stream_2)
(call "{vm_2_peer_id}" ("" "") [#canon_stream_2])))))
"#);
let result_1 = checked_call_vm!(vm_1, <_>::default(), &script, "", "");
@ -267,14 +269,21 @@ fn canon_empty_not_writable_stream() {
let mut vm = create_avm(echo_call_service(), peer_id);
let script = f!(r#"
(canon "{peer_id}" $stream #canon_stream)
(par
(call "unwkown_peer_id" ("" "") [] $stream)
(canon "{peer_id}" $stream #canon_stream)
)
"#);
let result = checked_call_vm!(vm, <_>::default(), &script, "", "");
let actual_trace = trace_from_result(&result);
let expected_trace = vec![executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id", "service_id": ""}, "values": []} ),
)];
let expected_trace = vec![
executed_state::par(1, 1),
executed_state::request_sent_by(peer_id),
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id", "service_id": ""}, "values": []} ),
),
];
assert_eq!(actual_trace, expected_trace);
}

View File

@ -306,7 +306,10 @@ fn issue_165() {
)
(ap 2 $results)
)
(call "{echo_peer_id}" ("callbackSrv" "response") [$results.$.[0]!])
(seq
(canon "{echo_peer_id}" $results #results)
(call "{echo_peer_id}" ("callbackSrv" "response") [#results.$.[0]!])
)
)
)
"#);

View File

@ -109,7 +109,10 @@ fn several_restrictions() {
(new $stream
(call "{vm_peer_id}" ("" "") ["test"] $stream)
)
(call "{vm_peer_id}" ("" "") [$stream])
(seq
(canon "{vm_peer_id}" $stream #canon_stream)
(call "{vm_peer_id}" ("" "") [#canon_stream])
)
)
)"#);
@ -118,6 +121,12 @@ fn several_restrictions() {
let actual_trace = trace_from_result(&result);
let expected_trace = vec![
executed_state::stream_string("test", 0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
]
})),
executed_state::scalar(json!([])),
];
assert_eq!(actual_trace, expected_trace);
@ -139,16 +148,28 @@ fn check_influence_to_not_restricted() {
)
(ap "more" $a)
)
(call "{vm_peer_id}" ("op" "identity") [$a] a-fix)
(seq
(canon "{vm_peer_id}" $a #a)
(call "{vm_peer_id}" ("op" "identity") [#a] a-fix)
)
)
)
(seq
(seq
(call "{vm_peer_id}" ("callbackSrv" "response") [$a0]) ;; should be non-empty
(call "{vm_peer_id}" ("callbackSrv" "response") [$a1]) ;; should be non-empty
(seq
(canon "{vm_peer_id}" $a0 #a0)
(call "{vm_peer_id}" ("callbackSrv" "response") [#a0]) ;; should be non-empty
)
(seq
(canon "{vm_peer_id}" $a1 #a1)
(call "{vm_peer_id}" ("callbackSrv" "response") [#a1]) ;; should be non-empty
)
)
(seq
(call "{vm_peer_id}" ("callbackSrv" "response") [$a]) ;; should be empty
(seq
(canon "{vm_peer_id}" $a #aa)
(call "{vm_peer_id}" ("callbackSrv" "response") [#aa]) ;; should be empty
)
(call "{vm_peer_id}" ("callbackSrv" "response") [a-fix]) ;; should be empty
)
)
@ -162,9 +183,48 @@ fn check_influence_to_not_restricted() {
executed_state::ap(0),
executed_state::ap(0),
executed_state::ap(0),
executed_state::canon(json!(
{
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "more",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 2
}
]
}
)),
executed_state::scalar(json!(["more"])),
executed_state::canon(json!(
{
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "push more",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 0
}
]
}
)),
executed_state::scalar(json!(["push more"])),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "push more",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 1
}
]
})),
executed_state::scalar(json!(["push more"])),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
]
})),
executed_state::scalar(json!([])),
executed_state::scalar(json!(["more"])),
];
@ -187,7 +247,10 @@ fn new_in_fold_with_ap() {
(new $s1
(seq
(ap "none" $s1)
(call "{vm_peer_id}" ("" "") [$s1] s-fix1) ;; should contains only "none" on each iteration
(seq
(canon "{vm_peer_id}" $s1 #canon_s1)
(call "{vm_peer_id}" ("" "") [#canon_s1] s-fix1) ;; should contains only "none" on each iteration
)
)
)
(next x)
@ -203,14 +266,64 @@ fn new_in_fold_with_ap() {
let expected_trace = vec![
executed_state::scalar(json!([1, 2, 3, 4, 5])),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "none",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 1
}
]
})),
executed_state::scalar_string_array(vec!["none"]),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "none",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 4
}
]
})),
executed_state::scalar_string_array(vec!["none"]),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "none",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 7
}
]
})),
executed_state::scalar_string_array(vec!["none"]),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "none",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 10
}
]
})),
executed_state::scalar_string_array(vec!["none"]),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""},
"values": [
{
"result": "none",
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "", "service_id": ""},
"trace_pos": 13
}
]
})),
executed_state::scalar_string_array(vec!["none"]),
];
assert_eq!(actual_trace, expected_trace);

View File

@ -27,8 +27,31 @@ fn issue_177() {
let variables = maplit::hashmap! {
"-relay-".to_string() => json!(relay_peer_id),
"noop".to_string() => json!([]),
"string_to_parse_iter".to_string() => json!("CovLVG4fQcqVPcweSGV5ANQ8NQ2hJnVQrFJJPyQvdKmMDDNDuYYveDy4ncnmDbsvRFA5FcG"),
"neighborhood".to_string() => json!(["12D3KooWGzNvhSDsgFoHwpWHAyPf1kcTYCGeRBPfznL8J6qdyu2H","12D3KooWJbJFaZ3k5sNd8DjQgg3aERoKtBAnirEvPV8yp76kEXHB","12D3KooWBSdm6TkqnEFrgBuSkpVE3dR1kr6952DsWQRNwJZjFZBv","12D3KooWKnRcsTpYx9axkJ6d69LPfpPXrkVLe96skuPTAo76LLVH","12D3KooWHCJbJKGDfCgHSoCuK9q4STyRnVveqLoXAPBbXHTZx9Cv","12D3KooWMhVpgfQxBLkQkJed8VFNvgN4iE6MD7xCybb1ZYWW2Gtz","12D3KooWF7gjXhQ4LaKj6j7ntxsPpGk34psdQicN2KNfBi9bFKXg","12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb","12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9","12D3KooWHk9BjDQBUqnavciRPhAYFvqKBe4ZiPPvde7vDaqgn5er","12D3KooWDcpWuyrMTDinqNgmXAuRdfd2mTdY9VoXZSAet2pDzh6r","12D3KooWCKCeqLPSgMnDjyFsJuWqREDtKNHx1JEBiwaMXhCLNTRb","12D3KooWMigkP4jkVyufq5JnDJL6nXvyjeaDNpRfEZqQhsG3sYCU","12D3KooWB9P1xmV3c7ZPpBemovbwCiRRTKd3Kq2jsVPQN4ZukDfy","12D3KooWAKNos2KogexTXhrkMZzFYpLHuWJ4PgoAhurSAv7o5CWA","12D3KooWDUszU2NeWyUVjCXhGEt1MoZrhvdmaQQwtZUriuGN1jTr","12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA","12D3KooWEFFCZnar1cUJQ3rMWjvPQg6yMV2aXWs2DkJNSRbduBWn","12D3KooWHBG9oaVx4i3vi6c1rSBUm7MLBmyGmmbHoZ23pmjDCnvK","12D3KooWFpQ7LHxcC9FEBUh3k4nSCC12jBhijJv3gJbi7wsNYzJ5"]),
"string_to_parse_iter".to_string() => json!(
"CovLVG4fQcqVPcweSGV5ANQ8NQ2hJnVQrFJJPyQvdKmMDDNDuYYveDy4ncnmDbsvRFA5FcG"
),
"neighborhood".to_string() => json!([
"12D3KooWGzNvhSDsgFoHwpWHAyPf1kcTYCGeRBPfznL8J6qdyu2H",
"12D3KooWJbJFaZ3k5sNd8DjQgg3aERoKtBAnirEvPV8yp76kEXHB",
"12D3KooWBSdm6TkqnEFrgBuSkpVE3dR1kr6952DsWQRNwJZjFZBv",
"12D3KooWKnRcsTpYx9axkJ6d69LPfpPXrkVLe96skuPTAo76LLVH",
"12D3KooWHCJbJKGDfCgHSoCuK9q4STyRnVveqLoXAPBbXHTZx9Cv",
"12D3KooWMhVpgfQxBLkQkJed8VFNvgN4iE6MD7xCybb1ZYWW2Gtz",
"12D3KooWF7gjXhQ4LaKj6j7ntxsPpGk34psdQicN2KNfBi9bFKXg",
"12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb",
"12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9",
"12D3KooWHk9BjDQBUqnavciRPhAYFvqKBe4ZiPPvde7vDaqgn5er",
"12D3KooWDcpWuyrMTDinqNgmXAuRdfd2mTdY9VoXZSAet2pDzh6r",
"12D3KooWCKCeqLPSgMnDjyFsJuWqREDtKNHx1JEBiwaMXhCLNTRb",
"12D3KooWMigkP4jkVyufq5JnDJL6nXvyjeaDNpRfEZqQhsG3sYCU",
"12D3KooWB9P1xmV3c7ZPpBemovbwCiRRTKd3Kq2jsVPQN4ZukDfy",
"12D3KooWAKNos2KogexTXhrkMZzFYpLHuWJ4PgoAhurSAv7o5CWA",
"12D3KooWDUszU2NeWyUVjCXhGEt1MoZrhvdmaQQwtZUriuGN1jTr",
"12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA",
"12D3KooWEFFCZnar1cUJQ3rMWjvPQg6yMV2aXWs2DkJNSRbduBWn",
"12D3KooWHBG9oaVx4i3vi6c1rSBUm7MLBmyGmmbHoZ23pmjDCnvK",
"12D3KooWFpQ7LHxcC9FEBUh3k4nSCC12jBhijJv3gJbi7wsNYzJ5"
]),
};
let mut client = create_avm(

View File

@ -32,7 +32,10 @@ fn par_ap_behaviour() {
(call "{relay_id}" ("peer" "timeout") [join_it] $result) ; behaviour=unit
(ap "fast_result" $result)
)
(call "{client_id}" ("op" "return") [$result.$[0]]) ; behaviour=unit
(seq
(canon "{client_id}" $result #result)
(call "{client_id}" ("op" "return") [#result.$[0]]) ; behaviour=unit
)
)
)
"#);

View File

@ -17,7 +17,8 @@
use air_test_utils::prelude::*;
#[test]
// test for github.com/fluencelabs/aquavm/issues/206
#[ignore] // this test is not actual because streams are prohibited to be used as match operands
// test for github.com/fluencelabs/aquavm/issues/206
fn issue_206() {
let peer_1_id = "peer_1_id";
let mut peer_1 = create_avm(echo_call_service(), peer_1_id);

View File

@ -23,38 +23,44 @@ fn issue_211() {
let peer_1_id = "peer_1_id";
let script = f!(r#"
(xor
(seq
(seq
(seq
(xor
(seq
(null)
(call %init_peer_id% ("getDataSrv" "idx") [] idx) ; ok=2
)
(call %init_peer_id% ("getDataSrv" "nodes") [] nodes) ; ok = [1,2,3]
)
(new $nodes2
(seq
(seq
(par
(fold nodes node
(par
(ap node $nodes2)
(next node)
)
)
(null)
(seq
(seq
(seq
(null)
(call %init_peer_id% ("getdatasrv" "idx") [] idx) ; ok=2
)
(call %init_peer_id% ("getdatasrv" "nodes") [] nodes) ; ok = [1,2,3]
)
(new $nodes2
(seq
(seq
(par
(fold nodes node
(par
(ap node $nodes2)
(next node)
)
)
(null)
)
(seq
(canon %init_peer_id% $nodes2 #nodes2_0)
(call %init_peer_id% ("op" "noop") [#nodes2_0.$.[idx]! nodes]) ; ok="expected result"
)
)
(seq
(canon %init_peer_id% $nodes2 #nodes2_1)
(call %init_peer_id% ("op" "identity") [#nodes2_1] nodes2-fix) ; ok="expected result"
)
)
)
)
(call %init_peer_id% ("op" "noop") [$nodes2.$.[idx] nodes]) ; ok="expected result"
)
(call %init_peer_id% ("op" "identity") [$nodes2] nodes2-fix) ; ok="expected result"
(null)
)
)
)
(null)
(call %init_peer_id% ("errorhandlingsrv" "error") [%last_error% 2]) ; ok="error"
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2]) ; ok="error"
)
"#);
let run_params = TestRunParameters::from_init_peer_id(peer_1_id);
@ -74,7 +80,47 @@ fn issue_211() {
executed_state::ap(0),
executed_state::par(1, 0),
executed_state::ap(0),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_1_id", "service_id": ""},
"values": [
{
"result": 1,
"tetraplet": {"function_name": "nodes", "json_path": "", "peer_pk": "peer_1_id", "service_id": "getdatasrv..1"},
"trace_pos": 4
},
{
"result": 2,
"tetraplet": {"function_name": "nodes", "json_path": "", "peer_pk": "peer_1_id", "service_id": "getdatasrv..1"},
"trace_pos": 6
},
{
"result": 3,
"tetraplet": {"function_name": "nodes", "json_path": "", "peer_pk": "peer_1_id", "service_id": "getdatasrv..1"},
"trace_pos": 8
},
]
})),
executed_state::scalar_string("expected result"),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_1_id", "service_id": ""},
"values": [
{
"result": 1,
"tetraplet": {"function_name": "nodes", "json_path": "", "peer_pk": "peer_1_id", "service_id": "getdatasrv..1"},
"trace_pos": 4
},
{
"result": 2,
"tetraplet": {"function_name": "nodes", "json_path": "", "peer_pk": "peer_1_id", "service_id": "getdatasrv..1"},
"trace_pos": 6
},
{
"result": 3,
"tetraplet": {"function_name": "nodes", "json_path": "", "peer_pk": "peer_1_id", "service_id": "getdatasrv..1"},
"trace_pos": 8
},
]
})),
executed_state::scalar_string("expected result"),
];

View File

@ -38,7 +38,10 @@ fn issue_302() {
(call "{peer_id_2}" ("" "") [1] $stream)
(seq
(call "{peer_id_3}" ("" "") [0] $stream)
(call "{peer_id_2}" ("" "") [$stream])
(seq
(canon "{peer_id_2}" $stream #stream)
(call "{peer_id_2}" ("" "") [#stream])
)
)
)
)
@ -52,10 +55,30 @@ fn issue_302() {
let actual_trace = trace_from_result(&result_4);
let expected_trace = vec![
executed_state::par(1, 3),
executed_state::par(1, 4),
executed_state::stream_number(2, 1),
executed_state::stream_number(1, 0),
executed_state::stream_number(0, 2),
executed_state::canon(json!({
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_2", "service_id": ""},
"values": [
{
"result": 1,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_2", "service_id": ""},
"trace_pos": 2
},
{
"result": 2,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_1", "service_id": ""},
"trace_pos": 1
},
{
"result": 0,
"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_3", "service_id": ""},
"trace_pos": 3
},
]
})),
executed_state::scalar(json!([1, 2, 0])),
];
assert_eq!(actual_trace.deref(), expected_trace);

View File

@ -29,7 +29,12 @@ fn issue_331() {
(seq
(seq
(seq
(call %init_peer_id% ("op" "array_length") [$status] array_length)
(seq
(new $status
(canon %init_peer_id% $status #status)
)
(call %init_peer_id% ("op" "array_length") [#status] array_length)
)
(ap array_length $array-inline)
)
(seq

View File

@ -43,7 +43,10 @@ fn issue_356() {
)
)
)
(call "client" ("return" "") [$external_addresses neighs_inner] x) ; ok = null
(seq
(canon "client" $external_addresses #external_addresses)
(call "client" ("return" "") [#external_addresses neighs_inner] x) ; ok = null
)
)
)
"#;

View File

@ -39,11 +39,17 @@
)
)
(par
(call %init_peer_id% ("op" "identity") [$res.$.[19]!])
(seq
(canon %init_peer_id% $res #res)
(call %init_peer_id% ("op" "identity") [#res.$.[19]!])
)
(call %init_peer_id% ("peer" "timeout") [1000 "timeout"])
)
)
(call %init_peer_id% ("op" "identity") [$res] res-fix)
(seq
(canon %init_peer_id% $res #res)
(call %init_peer_id% ("op" "identity") [#res] res-fix)
)
)
)
)

View File

@ -18,23 +18,37 @@ mod impls;
mod traits;
use super::CanonStream;
use super::CanonStreamWithLambda;
use super::ImmutableVariable;
use super::ImmutableVariableWithLambda;
use super::Scalar;
use super::ScalarWithLambda;
use super::Stream;
use super::VariableWithLambda;
use air_lambda_ast::LambdaAST;
use crate::ast::CanonStreamWithLambda;
use serde::Deserialize;
use serde::Serialize;
// TODO: rename CallInstrValue, since it'd used by the canon instruction
/// Contains all variable variants that could be resolved to a peer id.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum CallInstrValue<'i> {
pub enum ResolvableToPeerIdVariable<'i> {
InitPeerId,
Literal(&'i str),
Variable(VariableWithLambda<'i>),
Scalar(Scalar<'i>),
ScalarWithLambda(ScalarWithLambda<'i>),
// canon without lambda can't be resolved to a string, since it represents an array of values
CanonStreamWithLambda(CanonStreamWithLambda<'i>),
}
/// Contains all variable variants that could be resolved to a string type.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum ResolvableToStringVariable<'i> {
Literal(&'i str),
Scalar(Scalar<'i>),
ScalarWithLambda(ScalarWithLambda<'i>),
// canon without lambda can't be resolved to a string, since it represents an array of values
CanonStreamWithLambda(CanonStreamWithLambda<'i>),
}
/// Triplet represents a location of the executable code in the network.
@ -42,16 +56,16 @@ pub enum CallInstrValue<'i> {
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Triplet<'i> {
#[serde(borrow)]
pub peer_pk: CallInstrValue<'i>,
pub peer_id: ResolvableToPeerIdVariable<'i>,
#[serde(borrow)]
pub service_id: CallInstrValue<'i>,
pub service_id: ResolvableToStringVariable<'i>,
#[serde(borrow)]
pub function_name: CallInstrValue<'i>,
pub function_name: ResolvableToStringVariable<'i>,
}
/// Represents all values that is possible to set in AIR scripts.
/// Represents all immutable values that is possible to set in AIR scripts.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Value<'i> {
pub enum ImmutableValue<'i> {
InitPeerId,
LastError(Option<LambdaAST<'i>>),
Timestamp,
@ -60,7 +74,8 @@ pub enum Value<'i> {
Number(Number),
Boolean(bool),
EmptyArray, // only empty arrays are allowed now
Variable(VariableWithLambda<'i>),
Variable(ImmutableVariable<'i>),
VariableWithLambda(ImmutableVariableWithLambda<'i>),
}
#[derive(Serialize, Debug, PartialEq, Eq, Clone)]
@ -82,8 +97,10 @@ pub enum ApArgument<'i> {
Number(Number),
Boolean(bool),
EmptyArray,
Scalar(ScalarWithLambda<'i>),
CanonStream(CanonStreamWithLambda<'i>),
Scalar(Scalar<'i>),
ScalarWithLambda(ScalarWithLambda<'i>),
CanonStream(CanonStream<'i>),
CanonStreamWithLambda(CanonStreamWithLambda<'i>),
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
@ -103,7 +120,9 @@ pub enum Number {
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum FoldScalarIterable<'i> {
#[serde(borrow)]
Scalar(ScalarWithLambda<'i>),
Scalar(Scalar<'i>),
#[serde(borrow)]
ScalarWithLambda(ScalarWithLambda<'i>),
// it's important not to have lambda here
#[serde(borrow)]
CanonStream(CanonStream<'i>),

View File

@ -15,6 +15,7 @@
*/
use super::*;
use std::fmt;
impl fmt::Display for ApResult<'_> {
@ -28,9 +29,9 @@ impl fmt::Display for ApResult<'_> {
}
}
impl fmt::Display for Value<'_> {
impl fmt::Display for ImmutableValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Value::*;
use ImmutableValue::*;
match self {
InitPeerId => write!(f, "%init_peer_id%"),
@ -42,18 +43,34 @@ impl fmt::Display for Value<'_> {
Boolean(bool) => write!(f, "{}", bool),
EmptyArray => write!(f, "[]"),
Variable(variable) => write!(f, "{}", variable),
VariableWithLambda(variable) => write!(f, "{}", variable),
}
}
}
impl fmt::Display for CallInstrValue<'_> {
impl fmt::Display for ResolvableToPeerIdVariable<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use CallInstrValue::*;
use ResolvableToPeerIdVariable::*;
match self {
InitPeerId => write!(f, "%init_peer_id%"),
Literal(literal) => write!(f, r#""{}""#, literal),
Variable(variable) => write!(f, "{}", variable),
Scalar(scalar) => write!(f, "{}", scalar),
ScalarWithLambda(scalar) => write!(f, "{}", scalar),
CanonStreamWithLambda(canon_stream) => write!(f, "{}", canon_stream),
}
}
}
impl fmt::Display for ResolvableToStringVariable<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ResolvableToStringVariable::*;
match self {
Literal(literal) => write!(f, r#""{}""#, literal),
Scalar(scalar) => write!(f, "{}", scalar),
ScalarWithLambda(scalar) => write!(f, "{}", scalar),
CanonStreamWithLambda(canon_stream) => write!(f, "{}", canon_stream),
}
}
}
@ -84,7 +101,9 @@ impl fmt::Display for ApArgument<'_> {
Boolean(bool) => write!(f, "{}", bool),
EmptyArray => write!(f, "[]"),
Scalar(scalar) => write!(f, "{}", scalar),
ScalarWithLambda(scalar) => write!(f, "{}", scalar),
CanonStream(canon_stream) => write!(f, "{}", canon_stream),
CanonStreamWithLambda(canon_stream) => write!(f, "{}", canon_stream),
}
}
}
@ -94,7 +113,7 @@ impl fmt::Display for Triplet<'_> {
write!(
f,
"{} ({} {})",
self.peer_pk, self.service_id, self.function_name
self.peer_id, self.service_id, self.function_name
)
}
}
@ -125,7 +144,8 @@ impl fmt::Display for FoldScalarIterable<'_> {
use FoldScalarIterable::*;
match self {
Scalar(variable) => write!(f, "{}", variable),
Scalar(scalar) => write!(f, "{}", scalar),
ScalarWithLambda(scalar) => write!(f, "{}", scalar),
CanonStream(canon_stream) => write!(f, "{}", canon_stream),
EmptyArray => write!(f, "[]"),
}

View File

@ -18,8 +18,9 @@ mod impls;
mod traits;
use super::*;
use air_lambda_ast::LambdaAST;
use serde::Serialize;
use std::rc::Rc;
// TODO: sort instruction in alphanumeric order
@ -48,7 +49,7 @@ pub enum Instruction<'i> {
#[derive(Serialize, Debug, PartialEq)]
pub struct Call<'i> {
pub triplet: Triplet<'i>,
pub args: Rc<Vec<Value<'i>>>,
pub args: Rc<Vec<ImmutableValue<'i>>>,
pub output: CallOutputValue<'i>,
}
@ -62,7 +63,7 @@ pub struct Ap<'i> {
/// (canon peer_id $stream #canon_stream)
#[derive(Serialize, Debug, PartialEq, Eq)]
pub struct Canon<'i> {
pub peer_pk: CallInstrValue<'i>,
pub peer_id: ResolvableToPeerIdVariable<'i>,
pub stream: Stream<'i>,
pub canon_stream: CanonStream<'i>,
}
@ -82,32 +83,31 @@ pub struct Xor<'i>(pub Box<Instruction<'i>>, pub Box<Instruction<'i>>);
/// (match left_value right_value instruction)
#[derive(Serialize, Debug, PartialEq)]
pub struct Match<'i> {
pub left_value: Value<'i>,
pub right_value: Value<'i>,
pub left_value: ImmutableValue<'i>,
pub right_value: ImmutableValue<'i>,
pub instruction: Box<Instruction<'i>>,
}
/// (mismatch left_value right_value instruction)
#[derive(Serialize, Debug, PartialEq)]
pub struct MisMatch<'i> {
pub left_value: Value<'i>,
pub right_value: Value<'i>,
pub left_value: ImmutableValue<'i>,
pub right_value: ImmutableValue<'i>,
pub instruction: Box<Instruction<'i>>,
}
/// (fail 1337 "error message")
/// (fail %last_error%)
/// (fail value)
#[derive(Serialize, Debug, PartialEq, Eq)]
pub enum Fail<'i> {
Scalar(ScalarWithLambda<'i>),
Scalar(Scalar<'i>),
ScalarWithLambda(ScalarWithLambda<'i>),
Literal {
ret_code: i64,
error_message: &'i str,
},
CanonStream {
name: &'i str,
lambda: LambdaAST<'i>,
},
CanonStreamWithLambda(CanonStreamWithLambda<'i>),
LastError,
}

View File

@ -25,7 +25,7 @@ impl<'i> Ap<'i> {
impl<'i> Call<'i> {
pub fn new(
triplet: Triplet<'i>,
args: Rc<Vec<Value<'i>>>,
args: Rc<Vec<ImmutableValue<'i>>>,
output: CallOutputValue<'i>,
) -> Self {
Self {
@ -38,12 +38,12 @@ impl<'i> Call<'i> {
impl<'i> Canon<'i> {
pub fn new(
peer_pk: CallInstrValue<'i>,
peer_id: ResolvableToPeerIdVariable<'i>,
stream: Stream<'i>,
canon_stream: CanonStream<'i>,
) -> Self {
Self {
peer_pk,
peer_id,
stream,
canon_stream,
}
@ -79,8 +79,8 @@ impl<'i> Xor<'i> {
impl<'i> Match<'i> {
pub fn new(
left_value: Value<'i>,
right_value: Value<'i>,
left_value: ImmutableValue<'i>,
right_value: ImmutableValue<'i>,
instruction: Box<Instruction<'i>>,
) -> Self {
Self {
@ -93,8 +93,8 @@ impl<'i> Match<'i> {
impl<'i> MisMatch<'i> {
pub fn new(
left_value: Value<'i>,
right_value: Value<'i>,
left_value: ImmutableValue<'i>,
right_value: ImmutableValue<'i>,
instruction: Box<Instruction<'i>>,
) -> Self {
Self {

View File

@ -57,7 +57,7 @@ impl fmt::Display for Canon<'_> {
write!(
f,
"canon {} {} {}",
self.peer_pk, self.stream, self.canon_stream
self.peer_id, self.stream, self.canon_stream
)
}
}
@ -72,12 +72,13 @@ impl fmt::Display for Fail<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Fail::Scalar(scalar) => write!(f, "fail {}", scalar),
Fail::ScalarWithLambda(scalar) => write!(f, "fail {}", scalar),
Fail::Literal {
ret_code,
error_message,
} => write!(f, r#"fail {} "{}""#, ret_code, error_message),
Fail::CanonStream { name, lambda, .. } => {
write!(f, "fail {}.$.{}", name, lambda)
Fail::CanonStreamWithLambda(stream) => {
write!(f, "fail {}", stream)
}
Fail::LastError => write!(f, "fail %last_error%"),
}

View File

@ -14,14 +14,15 @@
* limitations under the License.
*/
use crate::ast::Value;
use crate::ast::ImmutableValue;
use air_lambda_ast::LambdaAST;
use air_lambda_ast::ValueAccessor;
#[test]
// https://github.com/fluencelabs/aquavm/issues/263
fn issue_263() {
let val = Value::LastError(Some(
let val = ImmutableValue::LastError(Some(
LambdaAST::try_from_accessors(vec![ValueAccessor::FieldAccessByName {
field_name: "message",
}])

View File

@ -23,72 +23,59 @@ use air_lambda_parser::LambdaAST;
use serde::Deserialize;
use serde::Serialize;
/// A scalar value without lambda.
/// A scalar value without a lambda.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Scalar<'i> {
pub name: &'i str,
pub position: AirPos,
}
/// A scalar value with possible lambda expression.
/// A scalar value with a lambda expression.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct ScalarWithLambda<'i> {
pub name: &'i str,
#[serde(borrow)]
pub lambda: Option<LambdaAST<'i>>,
pub lambda: LambdaAST<'i>,
pub position: AirPos,
}
/// A stream without lambda.
/// A stream without a lambda.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Stream<'i> {
pub name: &'i str,
pub position: AirPos,
}
/// A stream with possible lambda expression.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct StreamWithLambda<'i> {
pub name: &'i str,
#[serde(borrow)]
pub lambda: Option<LambdaAST<'i>>,
pub position: AirPos,
}
/// A canonicalized stream without lambda.
/// A canonicalized stream without a lambda.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct CanonStream<'i> {
pub name: &'i str,
pub position: AirPos,
}
/// A canonicalized stream with lambda.
/// A canonicalized stream with a lambda.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct CanonStreamWithLambda<'i> {
pub name: &'i str,
#[serde(borrow)]
pub lambda: Option<LambdaAST<'i>>,
pub lambda: LambdaAST<'i>,
pub position: AirPos,
}
/// A variable that could be either scalar or stream without lambda.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum Variable<'i> {
pub enum ImmutableVariable<'i> {
#[serde(borrow)]
Scalar(Scalar<'i>),
#[serde(borrow)]
Stream(Stream<'i>),
#[serde(borrow)]
CanonStream(CanonStream<'i>),
}
/// A variable that could be either scalar or stream with possible lambda expression.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum VariableWithLambda<'i> {
pub enum ImmutableVariableWithLambda<'i> {
#[serde(borrow)]
Scalar(ScalarWithLambda<'i>),
#[serde(borrow)]
Stream(StreamWithLambda<'i>),
#[serde(borrow)]
CanonStream(CanonStreamWithLambda<'i>),
}

View File

@ -16,10 +16,9 @@
use super::*;
use air_lambda_parser::LambdaAST;
use air_lambda_parser::ValueAccessor;
impl<'i> ScalarWithLambda<'i> {
pub fn new(name: &'i str, lambda: Option<LambdaAST<'i>>, position: AirPos) -> Self {
pub fn new(name: &'i str, lambda: LambdaAST<'i>, position: AirPos) -> Self {
Self {
name,
lambda,
@ -27,36 +26,13 @@ impl<'i> ScalarWithLambda<'i> {
}
}
pub(crate) fn from_value_path(
#[cfg(test)]
pub(crate) fn from_raw_lambda(
name: &'i str,
accessors: Vec<ValueAccessor<'i>>,
lambda: Vec<air_lambda_parser::ValueAccessor<'i>>,
position: AirPos,
) -> Self {
let lambda = LambdaAST::try_from_accessors(accessors).ok();
Self {
name,
lambda,
position,
}
}
}
impl<'i> StreamWithLambda<'i> {
pub fn new(name: &'i str, lambda: Option<LambdaAST<'i>>, position: AirPos) -> Self {
Self {
name,
lambda,
position,
}
}
#[allow(dead_code)]
pub(crate) fn from_value_path(
name: &'i str,
accessors: Vec<ValueAccessor<'i>>,
position: AirPos,
) -> Self {
let lambda = LambdaAST::try_from_accessors(accessors).ok();
let lambda = LambdaAST::try_from_accessors(lambda).unwrap();
Self {
name,
lambda,
@ -72,7 +48,7 @@ impl<'i> CanonStream<'i> {
}
impl<'i> CanonStreamWithLambda<'i> {
pub fn new(name: &'i str, lambda: Option<LambdaAST<'i>>, position: AirPos) -> Self {
pub fn new(name: &'i str, lambda: LambdaAST<'i>, position: AirPos) -> Self {
Self {
name,
lambda,
@ -93,82 +69,53 @@ impl<'i> Stream<'i> {
}
}
impl<'i> Variable<'i> {
impl<'i> ImmutableVariable<'i> {
pub fn scalar(name: &'i str, position: AirPos) -> Self {
Self::Scalar(Scalar::new(name, position))
}
pub fn stream(name: &'i str, position: AirPos) -> Self {
Self::Stream(Stream::new(name, position))
pub fn canon_stream(name: &'i str, position: AirPos) -> Self {
Self::CanonStream(CanonStream::new(name, position))
}
pub fn name(&self) -> &'i str {
match self {
Variable::Scalar(scalar) => scalar.name,
Variable::Stream(stream) => stream.name,
Variable::CanonStream(stream) => stream.name,
ImmutableVariable::Scalar(scalar) => scalar.name,
ImmutableVariable::CanonStream(stream) => stream.name,
}
}
}
impl<'i> VariableWithLambda<'i> {
pub fn scalar(name: &'i str, position: AirPos) -> Self {
Self::Scalar(ScalarWithLambda::new(name, None, position))
impl<'i> ImmutableVariableWithLambda<'i> {
pub fn scalar(name: &'i str, lambda: LambdaAST<'i>, position: AirPos) -> Self {
Self::Scalar(ScalarWithLambda::new(name, lambda, position))
}
pub fn scalar_wl(name: &'i str, lambda: LambdaAST<'i>, position: AirPos) -> Self {
Self::Scalar(ScalarWithLambda::new(name, Some(lambda), position))
}
pub fn stream(name: &'i str, position: AirPos) -> Self {
Self::Stream(StreamWithLambda::new(name, None, position))
}
pub fn stream_wl(name: &'i str, lambda: LambdaAST<'i>, position: AirPos) -> Self {
Self::Stream(StreamWithLambda::new(name, Some(lambda), position))
}
pub fn canon_stream(name: &'i str, position: AirPos) -> Self {
Self::CanonStream(CanonStreamWithLambda::new(name, None, position))
}
pub fn canon_stream_wl(name: &'i str, lambda: LambdaAST<'i>, position: AirPos) -> Self {
Self::CanonStream(CanonStreamWithLambda::new(name, Some(lambda), position))
pub fn canon_stream(name: &'i str, lambda: LambdaAST<'i>, position: AirPos) -> Self {
Self::CanonStream(CanonStreamWithLambda::new(name, lambda, position))
}
pub fn name(&self) -> &'i str {
match self {
VariableWithLambda::Scalar(scalar) => scalar.name,
VariableWithLambda::Stream(stream) => stream.name,
VariableWithLambda::CanonStream(canon_stream) => canon_stream.name,
ImmutableVariableWithLambda::Scalar(scalar) => scalar.name,
ImmutableVariableWithLambda::CanonStream(canon_stream) => canon_stream.name,
}
}
pub fn lambda(&self) -> &Option<LambdaAST<'i>> {
pub fn lambda(&self) -> &LambdaAST<'i> {
match self {
VariableWithLambda::Scalar(scalar) => &scalar.lambda,
VariableWithLambda::Stream(stream) => &stream.lambda,
VariableWithLambda::CanonStream(canon_stream) => &canon_stream.lambda,
ImmutableVariableWithLambda::Scalar(scalar) => &scalar.lambda,
ImmutableVariableWithLambda::CanonStream(canon_stream) => &canon_stream.lambda,
}
}
#[allow(dead_code)]
#[cfg(test)]
pub(crate) fn from_raw_value_path(
name: &'i str,
lambda: Vec<ValueAccessor<'i>>,
lambda: Vec<air_lambda_parser::ValueAccessor<'i>>,
position: AirPos,
) -> Self {
let scalar = ScalarWithLambda::from_value_path(name, lambda, position);
let scalar = ScalarWithLambda::from_raw_lambda(name, lambda, position);
Self::Scalar(scalar)
}
#[allow(dead_code)]
pub(crate) fn from_raw_lambda_stream(
name: &'i str,
lambda: Vec<ValueAccessor<'i>>,
position: AirPos,
) -> Self {
let stream = StreamWithLambda::from_value_path(name, lambda, position);
Self::Stream(stream)
}
}

View File

@ -25,10 +25,7 @@ impl fmt::Display for Scalar<'_> {
impl fmt::Display for ScalarWithLambda<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.lambda {
Some(lambda) => write!(f, "{}{}", self.name, lambda),
None => write!(f, "{}", self.name),
}
write!(f, "{}{}", self.name, self.lambda)
}
}
@ -44,43 +41,29 @@ impl fmt::Display for CanonStream<'_> {
}
}
impl fmt::Display for StreamWithLambda<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.lambda {
Some(lambda) => write!(f, "{}{}", self.name, lambda),
None => write!(f, "{}", self.name),
}
}
}
impl fmt::Display for CanonStreamWithLambda<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.lambda {
Some(lambda) => write!(f, "{}{}", self.name, lambda),
None => write!(f, "{}", self.name),
}
write!(f, "{}{}", self.name, self.lambda)
}
}
impl fmt::Display for Variable<'_> {
impl fmt::Display for ImmutableVariable<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Variable::*;
use ImmutableVariable::*;
match self {
Scalar(scalar) => write!(f, "{}", scalar),
Stream(stream) => write!(f, "{}", stream),
CanonStream(canon_stream) => write!(f, "{}", canon_stream),
}
}
}
impl fmt::Display for VariableWithLambda<'_> {
impl fmt::Display for ImmutableVariableWithLambda<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use VariableWithLambda::*;
use ImmutableVariableWithLambda::*;
match self {
Scalar(scalar) => write!(f, "{}", scalar),
Stream(stream) => write!(f, "{}", stream),
CanonStream(canon_stream) => write!(f, "{}", canon_stream),
}
}

View File

@ -25,8 +25,8 @@ Instr: Box<Instruction<'input>> = {
Box::new(Instruction::Call(call))
},
<left: @L> "(" canon <peer_pk:CallInstrValue> <stream:StreamArgument> <canon_stream:CanonStreamArgument> ")" <right: @R> => {
let canon = Canon::new(peer_pk, stream, canon_stream);
<left: @L> "(" canon <peer_id:ResolvableToPeerIdVariable> <stream:StreamArgument> <canon_stream:CanonStreamArgument> ")" <right: @R> => {
let canon = Canon::new(peer_id, stream, canon_stream);
let span = Span::new(left, right);
validator.met_canon(&canon, span);
@ -113,13 +113,13 @@ Instr: Box<Instruction<'input>> = {
! => { errors.push(<>); Box::new(Instruction::Error) },
}
Args: Vec<Value<'input>> = {
Args: Vec<ImmutableValue<'input>> = {
"[" <args:(<Arg>)*> "]" => args
}
Triplet: Triplet<'input> = {
<peer_pk:PeerId> "(" <service_id:ServiceId> <function_name:Function> ")" => Triplet {
peer_pk,
<peer_id:PeerId> "(" <service_id:ServiceId> <function_name:Function> ")" => Triplet {
peer_id,
service_id,
function_name
}
@ -136,42 +136,42 @@ CallOutput: CallOutputValue<'input> = {
};
FailBody: Fail<'input> = {
<scalar:Scalar> => Fail::Scalar(ScalarWithLambda::new(scalar.0, None, scalar.1)),
<scalar:ScalarWithLambda> => Fail::Scalar(ScalarWithLambda::new(scalar.0, Some(scalar.1), scalar.2)),
<scalar:Scalar> => Fail::Scalar(Scalar::new(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => Fail::ScalarWithLambda(ScalarWithLambda::new(scalar.0, scalar.1, scalar.2)),
<ret_code:I64> <error_message:Literal> => Fail::Literal {
ret_code,
error_message,
},
<canon_stream:CanonStreamWithLambda> => Fail::CanonStream {
name: canon_stream.0,
lambda: canon_stream.1,
},
<canon_stream:CanonStreamWithLambda> => Fail::CanonStreamWithLambda(CanonStreamWithLambda::new(canon_stream.0, canon_stream.1, canon_stream.2)),
<left: @L> <l:LastError> <right: @R> => {
Fail::LastError
}
}
FoldScalarIterable: FoldScalarIterable<'input> = {
<scalar:Scalar> => FoldScalarIterable::Scalar(ScalarWithLambda::new(scalar.0, None, scalar.1)),
<scalar:ScalarWithLambda> => FoldScalarIterable::Scalar(ScalarWithLambda::new(scalar.0, Some(scalar.1), scalar.2)),
<scalar:Scalar> => FoldScalarIterable::Scalar(Scalar::new(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => FoldScalarIterable::ScalarWithLambda(ScalarWithLambda::new(scalar.0, scalar.1, scalar.2)),
<canon_stream:CanonStream> => FoldScalarIterable::CanonStream(CanonStream::new(canon_stream.0, canon_stream.1)),
"[" "]" => FoldScalarIterable::EmptyArray,
};
Function = CallInstrValue;
PeerId = CallInstrValue;
ServiceId = CallInstrValue;
PeerId = ResolvableToPeerIdVariable;
Function = ResolvableToStringVariable;
ServiceId = ResolvableToStringVariable;
// TODO: call triplet should receive only streams with lambdas
CallInstrValue: CallInstrValue<'input> = {
InitPeerId => CallInstrValue::InitPeerId,
<l:Literal> => CallInstrValue::Literal(l),
<scalar:Scalar> => CallInstrValue::Variable(VariableWithLambda::scalar(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => CallInstrValue::Variable(VariableWithLambda::scalar_wl(scalar.0, scalar.1, scalar.2)),
<stream:Stream> => CallInstrValue::Variable(VariableWithLambda::stream(stream.0, stream.1)),
<stream:StreamWithLambda> => CallInstrValue::Variable(VariableWithLambda::stream_wl(stream.0, stream.1, stream.2)),
<canon_stream:CanonStream> => CallInstrValue::Variable(VariableWithLambda::canon_stream(canon_stream.0, canon_stream.1)),
<canon_stream:CanonStreamWithLambda> => CallInstrValue::Variable(VariableWithLambda::canon_stream_wl(canon_stream.0, canon_stream.1, canon_stream.2)),
ResolvableToPeerIdVariable: ResolvableToPeerIdVariable<'input> = {
InitPeerId => ResolvableToPeerIdVariable::InitPeerId,
<literal:Literal> => ResolvableToPeerIdVariable::Literal(literal),
<scalar:Scalar> => ResolvableToPeerIdVariable::Scalar(Scalar::new(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => ResolvableToPeerIdVariable::ScalarWithLambda(ScalarWithLambda::new(scalar.0, scalar.1, scalar.2)),
<canon_stream:CanonStreamWithLambda> => ResolvableToPeerIdVariable::CanonStreamWithLambda(CanonStreamWithLambda::new(canon_stream.0, canon_stream.1, canon_stream.2)),
}
ResolvableToStringVariable: ResolvableToStringVariable<'input> = {
<literal:Literal> => ResolvableToStringVariable::Literal(literal),
<scalar:Scalar> => ResolvableToStringVariable::Scalar(Scalar::new(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => ResolvableToStringVariable::ScalarWithLambda(ScalarWithLambda::new(scalar.0, scalar.1, scalar.2)),
<canon_stream:CanonStreamWithLambda> => ResolvableToStringVariable::CanonStreamWithLambda(CanonStreamWithLambda::new(canon_stream.0, canon_stream.1, canon_stream.2)),
}
NewArgument: NewArgument<'input> = {
@ -187,22 +187,20 @@ Number: Number = {
Arg = Value;
Value: Value<'input> = {
InitPeerId => Value::InitPeerId,
<LastError> => Value::LastError(None),
<le:LastErrorWithLambda> => Value::LastError(Some(le)),
<l:Literal> => Value::Literal(l),
Timestamp => Value::Timestamp,
TTL => Value::TTL,
<n:Number> => Value::Number(n),
<b:Boolean> => Value::Boolean(b),
"[" "]" => Value::EmptyArray,
<scalar:Scalar> => Value::Variable(VariableWithLambda::scalar(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => Value::Variable(VariableWithLambda::scalar_wl(scalar.0, scalar.1, scalar.2)),
<stream:Stream> => Value::Variable(VariableWithLambda::stream(stream.0, stream.1)),
<stream:StreamWithLambda> => Value::Variable(VariableWithLambda::stream_wl(stream.0, stream.1, stream.2)),
<canon_stream:CanonStream> => Value::Variable(VariableWithLambda::canon_stream(canon_stream.0, canon_stream.1)),
<canon_stream:CanonStreamWithLambda> => Value::Variable(VariableWithLambda::canon_stream_wl(canon_stream.0, canon_stream.1, canon_stream.2)),
Value: ImmutableValue<'input> = {
InitPeerId => ImmutableValue::InitPeerId,
<LastError> => ImmutableValue::LastError(None),
<le:LastErrorWithLambda> => ImmutableValue::LastError(Some(le)),
<l:Literal> => ImmutableValue::Literal(l),
Timestamp => ImmutableValue::Timestamp,
TTL => ImmutableValue::TTL,
<n:Number> => ImmutableValue::Number(n),
<b:Boolean> => ImmutableValue::Boolean(b),
"[" "]" => ImmutableValue::EmptyArray,
<scalar:Scalar> => ImmutableValue::Variable(ImmutableVariable::scalar(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => ImmutableValue::VariableWithLambda(ImmutableVariableWithLambda::scalar(scalar.0, scalar.1, scalar.2)),
<canon_stream:CanonStream> => ImmutableValue::Variable(ImmutableVariable::canon_stream(canon_stream.0, canon_stream.1)),
<canon_stream:CanonStreamWithLambda> => ImmutableValue::VariableWithLambda(ImmutableVariableWithLambda::canon_stream(canon_stream.0, canon_stream.1, canon_stream.2)),
}
ApArgument: ApArgument<'input> = {
@ -215,10 +213,10 @@ ApArgument: ApArgument<'input> = {
<n:Number> => ApArgument::Number(n),
<b:Boolean> => ApArgument::Boolean(b),
"[" "]" => ApArgument::EmptyArray,
<scalar:Scalar> => ApArgument::Scalar(ScalarWithLambda::new(scalar.0, None, scalar.1)),
<scalar:ScalarWithLambda> => ApArgument::Scalar(ScalarWithLambda::new(scalar.0, Some(scalar.1), scalar.2)),
<canon_stream:CanonStream> => ApArgument::CanonStream(CanonStreamWithLambda::new(canon_stream.0, None, canon_stream.1)),
<canon_stream:CanonStreamWithLambda> => ApArgument::CanonStream(CanonStreamWithLambda::new(canon_stream.0, Some(canon_stream.1), canon_stream.2)),
<scalar:Scalar> => ApArgument::Scalar(Scalar::new(scalar.0, scalar.1)),
<scalar:ScalarWithLambda> => ApArgument::ScalarWithLambda(ScalarWithLambda::new(scalar.0, scalar.1, scalar.2)),
<canon_stream:CanonStream> => ApArgument::CanonStream(CanonStream::new(canon_stream.0, canon_stream.1)),
<canon_stream:CanonStreamWithLambda> => ApArgument::CanonStreamWithLambda(CanonStreamWithLambda::new(canon_stream.0, canon_stream.1, canon_stream.2)),
}
StreamArgument: Stream<'input> = {
@ -242,7 +240,6 @@ extern {
Scalar => Token::Scalar { name:<&'input str>, position: <AirPos> },
ScalarWithLambda => Token::ScalarWithLambda { name: <&'input str>, lambda: <LambdaAST<'input>>, position: <AirPos> },
Stream => Token::Stream { name: <&'input str>, position: <AirPos> },
StreamWithLambda => Token::StreamWithLambda {name: <&'input str>, lambda:<LambdaAST<'input>>, position: <AirPos>},
CanonStream => Token::CanonStream { name: <&'input str>, position: <AirPos> },
CanonStreamWithLambda => Token::CanonStreamWithLambda {name: <&'input str>, lambda:<LambdaAST<'input>>, position: <AirPos>},

File diff suppressed because it is too large Load Diff

View File

@ -215,25 +215,6 @@ fn canon_stream() {
);
}
#[test]
fn stream_with_functor() {
let stream_name = "$stream";
let stream_with_functor: String = f!("{stream_name}.length");
lexer_test(
&stream_with_functor,
Single(Ok((
0.into(),
Token::StreamWithLambda {
name: stream_name,
lambda: LambdaAST::Functor(Functor::Length),
position: 0.into(),
},
stream_with_functor.len().into(),
))),
);
}
#[test]
fn canon_stream_with_functor() {
let canon_stream_name = "#canon_stream";

View File

@ -157,7 +157,7 @@ fn ap_with_canon_stream() {
let actual = parse(&source_code);
let expected = ap(
ApArgument::CanonStream(CanonStreamWithLambda::new(canon_stream, None, 13.into())),
ApArgument::CanonStream(CanonStream::new(canon_stream, 13.into())),
ApResult::Scalar(Scalar::new(scalar, 27.into())),
);
@ -174,11 +174,9 @@ fn ap_with_canon_stream_with_lambda() {
let actual = parse(&source_code);
let expected = ap(
ApArgument::CanonStream(CanonStreamWithLambda::new(
ApArgument::CanonStreamWithLambda(CanonStreamWithLambda::new(
canon_stream,
Some(
LambdaAST::try_from_accessors(vec![ValueAccessor::ArrayAccess { idx: 0 }]).unwrap(),
),
LambdaAST::try_from_accessors(vec![ValueAccessor::ArrayAccess { idx: 0 }]).unwrap(),
13.into(),
)),
ApResult::Scalar(Scalar::new(scalar, 33.into())),

View File

@ -34,16 +34,16 @@ fn parse_json_path() {
let instruction = parse(source_code);
let expected = call(
CallInstrValue::Variable(VariableWithLambda::from_raw_value_path(
ResolvableToPeerIdVariable::ScalarWithLambda(ScalarWithLambda::from_raw_lambda(
"peer_id",
vec![ValueAccessor::FieldAccessByName { field_name: "a" }],
15.into(),
)),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![
Value::Literal("hello"),
Value::Variable(VariableWithLambda::scalar("name", 68.into())),
ImmutableValue::Literal("hello"),
ImmutableValue::Variable(ImmutableVariable::scalar("name", 68.into())),
]),
CallOutputValue::Stream(Stream::new("$void", 74.into())),
);
@ -58,13 +58,13 @@ fn parse_empty_array() {
let actual = parse(source_code);
let expected = call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 15.into())),
CallInstrValue::Variable(VariableWithLambda::scalar("service_id", 24.into())),
CallInstrValue::Literal("function_name"),
ResolvableToPeerIdVariable::Scalar(Scalar::new("peer_id", 15.into())),
ResolvableToStringVariable::Scalar(Scalar::new("service_id", 24.into())),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![
Value::Literal(""),
Value::EmptyArray,
Value::Variable(VariableWithLambda::scalar("arg", 59.into())),
ImmutableValue::Literal(""),
ImmutableValue::EmptyArray,
ImmutableValue::Variable(ImmutableVariable::scalar("arg", 59.into())),
]),
CallOutputValue::None,
);
@ -80,13 +80,13 @@ fn parse_empty_array_2() {
let actual = parse(source_code);
let expected = call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 15.into())),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToPeerIdVariable::Scalar(Scalar::new("peer_id", 15.into())),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![
Value::Variable(VariableWithLambda::scalar("k", 55.into())),
Value::EmptyArray,
Value::EmptyArray,
ImmutableValue::Variable(ImmutableVariable::scalar("k", 55.into())),
ImmutableValue::EmptyArray,
ImmutableValue::EmptyArray,
]),
CallOutputValue::None,
);
@ -146,36 +146,6 @@ fn parse_undefined_stream_without_json_path() {
assert!(errors.is_empty());
}
#[test]
fn parse_undefined_stream_with_lambda() {
let source_code = r#"
(call "" ("" "") [$stream.$.json_path])
"#;
let lexer = crate::AIRLexer::new(source_code);
let parser = crate::AIRParser::new();
let mut errors = Vec::new();
let mut validator = crate::parser::VariableValidator::new();
parser
.parse(source_code, &mut errors, &mut validator, lexer)
.expect("parser shouldn't fail");
let errors = validator.finalize();
assert_eq!(errors.len(), 1);
let error = &errors[0].error;
let parser_error = match error {
ParseError::User { error } => error,
_ => panic!("unexpected error type"),
};
assert!(matches!(
parser_error,
ParserError::UndefinedVariable { .. }
));
}
#[test]
fn parse_lambda_complex() {
let source_code = r#"
@ -187,18 +157,18 @@ fn parse_lambda_complex() {
let instruction = parse(source_code);
let expected = seq(
call(
CallInstrValue::Variable(VariableWithLambda::from_raw_value_path(
ResolvableToPeerIdVariable::ScalarWithLambda(ScalarWithLambda::from_raw_lambda(
"m",
vec![ValueAccessor::ArrayAccess { idx: 1 }],
32.into(),
)),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![]),
CallOutputValue::Scalar(Scalar::new("void", 75.into())),
),
call(
CallInstrValue::Variable(VariableWithLambda::from_raw_value_path(
ResolvableToPeerIdVariable::ScalarWithLambda(ScalarWithLambda::from_raw_lambda(
"m",
vec![
ValueAccessor::FieldAccessByName { field_name: "abc" },
@ -211,8 +181,8 @@ fn parse_lambda_complex() {
],
99.into(),
)),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![]),
CallOutputValue::Scalar(Scalar::new("void", 162.into())),
),
@ -231,7 +201,7 @@ fn parse_lambda_with_scalars_complex() {
let instruction = parse(source_code);
let expected = seq(
call(
CallInstrValue::Variable(VariableWithLambda::from_raw_value_path(
ResolvableToPeerIdVariable::ScalarWithLambda(ScalarWithLambda::from_raw_lambda(
"m",
vec![
ValueAccessor::ArrayAccess { idx: 1 },
@ -244,13 +214,13 @@ fn parse_lambda_with_scalars_complex() {
],
32.into(),
)),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![]),
CallOutputValue::Scalar(Scalar::new("void", 97.into())),
),
call(
CallInstrValue::Variable(VariableWithLambda::from_raw_value_path(
ResolvableToPeerIdVariable::ScalarWithLambda(ScalarWithLambda::from_raw_lambda(
"m",
vec![
ValueAccessor::FieldAccessByName { field_name: "abc" },
@ -269,8 +239,8 @@ fn parse_lambda_with_scalars_complex() {
],
121.into(),
)),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![]),
CallOutputValue::Scalar(Scalar::new("void", 205.into())),
),
@ -285,17 +255,17 @@ fn json_path_square_braces() {
"#;
let instruction = parse(source_code);
let expected = call(
CallInstrValue::Variable(VariableWithLambda::from_raw_value_path(
ResolvableToPeerIdVariable::ScalarWithLambda(ScalarWithLambda::from_raw_lambda(
"u",
vec![ValueAccessor::FieldAccessByName {
field_name: "peer_id",
}],
15.into(),
)),
CallInstrValue::Literal("return"),
CallInstrValue::Literal(""),
ResolvableToStringVariable::Literal("return"),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![
Value::Variable(VariableWithLambda::from_raw_value_path(
ImmutableValue::VariableWithLambda(ImmutableVariableWithLambda::from_raw_value_path(
"u",
vec![
ValueAccessor::ArrayAccess { idx: 1 },
@ -306,7 +276,7 @@ fn json_path_square_braces() {
],
43.into(),
)),
Value::Variable(VariableWithLambda::from_raw_value_path(
ImmutableValue::VariableWithLambda(ImmutableVariableWithLambda::from_raw_value_path(
"u",
vec![ValueAccessor::FieldAccessByName { field_name: "name" }],
64.into(),
@ -333,16 +303,16 @@ fn parse_init_peer_id() {
let instruction = parse(&source_code);
let expected = seq(
call(
CallInstrValue::Literal(peer_id),
CallInstrValue::Literal("local_service_id"),
CallInstrValue::Literal("local_fn_name"),
ResolvableToPeerIdVariable::Literal(peer_id),
ResolvableToStringVariable::Literal("local_service_id"),
ResolvableToStringVariable::Literal("local_fn_name"),
Rc::new(vec![]),
CallOutputValue::None,
),
call(
CallInstrValue::InitPeerId,
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("fn_name"),
ResolvableToPeerIdVariable::InitPeerId,
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("fn_name"),
Rc::new(vec![]),
CallOutputValue::None,
),
@ -359,10 +329,10 @@ fn parse_timestamp() {
let instruction = parse(source_code);
let expected = call(
CallInstrValue::Literal("peer_id"),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("fn_name"),
Rc::new(vec![Value::Timestamp]),
ResolvableToPeerIdVariable::Literal("peer_id"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("fn_name"),
Rc::new(vec![ImmutableValue::Timestamp]),
CallOutputValue::None,
);
@ -377,10 +347,10 @@ fn parse_ttl() {
let instruction = parse(source_code);
let expected = call(
CallInstrValue::Literal("peer_id"),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("fn_name"),
Rc::new(vec![Value::TTL]),
ResolvableToPeerIdVariable::Literal("peer_id"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("fn_name"),
Rc::new(vec![ImmutableValue::TTL]),
CallOutputValue::None,
);
@ -400,10 +370,10 @@ fn parse_last_error() {
let instruction = parse(&source_code);
let expected = seq(
call(
CallInstrValue::InitPeerId,
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("fn_name"),
Rc::new(vec![Value::LastError(None)]),
ResolvableToPeerIdVariable::InitPeerId,
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("fn_name"),
Rc::new(vec![ImmutableValue::LastError(None)]),
CallOutputValue::None,
),
null(),
@ -423,13 +393,12 @@ fn canon_stream_in_args() {
let instruction = parse(&source_code);
let expected = call(
CallInstrValue::InitPeerId,
CallInstrValue::Literal(service_id),
CallInstrValue::Literal(function_name),
Rc::new(vec![Value::Variable(VariableWithLambda::canon_stream(
canon_stream,
66.into(),
))]),
ResolvableToPeerIdVariable::InitPeerId,
ResolvableToStringVariable::Literal(service_id),
ResolvableToStringVariable::Literal(function_name),
Rc::new(vec![ImmutableValue::Variable(
ImmutableVariable::canon_stream(canon_stream, 66.into()),
)]),
CallOutputValue::None,
);
@ -445,16 +414,20 @@ fn canon_stream_in_triplet() {
(call {canon_stream} ("{service_id}" "{function_name}") [])
"#);
let instruction = parse(&source_code);
let expected = call(
CallInstrValue::Variable(VariableWithLambda::canon_stream(canon_stream, 19.into())),
CallInstrValue::Literal(service_id),
CallInstrValue::Literal(function_name),
Rc::new(vec![]),
CallOutputValue::None,
);
let lexer = crate::AIRLexer::new(&source_code);
assert_eq!(instruction, expected);
let parser = crate::AIRParser::new();
let mut errors = Vec::new();
let mut validator = crate::parser::VariableValidator::new();
parser
.parse(&source_code, &mut errors, &mut validator, lexer)
.expect("parser shouldn't fail");
assert_eq!(errors.len(), 1);
assert!(matches!(
&errors[0].error,
ParseError::UnrecognizedToken { .. }
));
}
#[test]
@ -469,7 +442,7 @@ fn canon_stream_with_lambda_in_triplet() {
let instruction = parse(&source_code);
let expected = call(
CallInstrValue::Variable(VariableWithLambda::canon_stream_wl(
ResolvableToPeerIdVariable::CanonStreamWithLambda(CanonStreamWithLambda::new(
canon_stream,
LambdaAST::try_from_accessors(vec![
ValueAccessor::ArrayAccess { idx: 0 },
@ -478,8 +451,8 @@ fn canon_stream_with_lambda_in_triplet() {
.unwrap(),
19.into(),
)),
CallInstrValue::Literal(service_id),
CallInstrValue::Literal(function_name),
ResolvableToStringVariable::Literal(service_id),
ResolvableToStringVariable::Literal(function_name),
Rc::new(vec![]),
CallOutputValue::None,
);
@ -503,24 +476,24 @@ fn seq_par_call() {
let expected = seq(
par(
call(
CallInstrValue::Literal(peer_id),
CallInstrValue::Literal("local_service_id"),
CallInstrValue::Literal("local_fn_name"),
ResolvableToPeerIdVariable::Literal(peer_id),
ResolvableToStringVariable::Literal("local_service_id"),
ResolvableToStringVariable::Literal("local_fn_name"),
Rc::new(vec![]),
CallOutputValue::Scalar(Scalar::new("result_1", 108.into())),
),
call(
CallInstrValue::Literal(peer_id),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("fn_name"),
ResolvableToPeerIdVariable::Literal(peer_id),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("fn_name"),
Rc::new(vec![]),
CallOutputValue::Scalar(Scalar::new("g", 183.into())),
),
),
call(
CallInstrValue::Literal(peer_id),
CallInstrValue::Literal("local_service_id"),
CallInstrValue::Literal("local_fn_name"),
ResolvableToPeerIdVariable::Literal(peer_id),
ResolvableToStringVariable::Literal("local_service_id"),
ResolvableToStringVariable::Literal("local_fn_name"),
Rc::new(vec![]),
CallOutputValue::Scalar(Scalar::new("result_2", 273.into())),
),
@ -558,47 +531,50 @@ fn seq_with_empty_and_dash() {
seq(
seq(
call(
CallInstrValue::Literal("set_variables"),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
Rc::new(vec![Value::Literal("module-bytes")]),
ResolvableToPeerIdVariable::Literal("set_variables"),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![ImmutableValue::Literal("module-bytes")]),
CallOutputValue::Scalar(Scalar::new("module-bytes", 119.into())),
),
call(
CallInstrValue::Literal("set_variables"),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
Rc::new(vec![Value::Literal("module_config")]),
ResolvableToPeerIdVariable::Literal("set_variables"),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![ImmutableValue::Literal("module_config")]),
CallOutputValue::Scalar(Scalar::new("module_config", 201.into())),
),
),
call(
CallInstrValue::Literal("set_variables"),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
Rc::new(vec![Value::Literal("blueprint")]),
ResolvableToPeerIdVariable::Literal("set_variables"),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![ImmutableValue::Literal("blueprint")]),
CallOutputValue::Scalar(Scalar::new("blueprint", 294.into())),
),
),
seq(
call(
CallInstrValue::Literal("A"),
CallInstrValue::Literal("add_module"),
CallInstrValue::Literal(""),
ResolvableToPeerIdVariable::Literal("A"),
ResolvableToStringVariable::Literal("add_module"),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![
Value::Variable(VariableWithLambda::scalar("module-bytes", 381.into())),
Value::Variable(VariableWithLambda::scalar("module_config", 394.into())),
ImmutableValue::Variable(ImmutableVariable::scalar("module-bytes", 381.into())),
ImmutableValue::Variable(ImmutableVariable::scalar(
"module_config",
394.into(),
)),
]),
CallOutputValue::Scalar(Scalar::new("module", 409.into())),
),
seq(
Instruction::Call(Call {
triplet: Triplet {
peer_pk: CallInstrValue::Literal("A"),
service_id: CallInstrValue::Literal("add_blueprint"),
function_name: CallInstrValue::Literal(""),
peer_id: ResolvableToPeerIdVariable::Literal("A"),
service_id: ResolvableToStringVariable::Literal("add_blueprint"),
function_name: ResolvableToStringVariable::Literal(""),
},
args: Rc::new(vec![Value::Variable(VariableWithLambda::scalar(
args: Rc::new(vec![ImmutableValue::Variable(ImmutableVariable::scalar(
"blueprint",
490.into(),
))]),
@ -606,20 +582,20 @@ fn seq_with_empty_and_dash() {
}),
seq(
call(
CallInstrValue::Literal("A"),
CallInstrValue::Literal("create"),
CallInstrValue::Literal(""),
Rc::new(vec![Value::Variable(VariableWithLambda::scalar(
ResolvableToPeerIdVariable::Literal("A"),
ResolvableToStringVariable::Literal("create"),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![ImmutableValue::Variable(ImmutableVariable::scalar(
"blueprint_id",
589.into(),
))]),
CallOutputValue::Scalar(Scalar::new("service_id", 603.into())),
),
call(
CallInstrValue::Literal("remote_peer_id"),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
Rc::new(vec![Value::Variable(VariableWithLambda::scalar(
ResolvableToPeerIdVariable::Literal("remote_peer_id"),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![ImmutableValue::Variable(ImmutableVariable::scalar(
"service_id",
671.into(),
))]),
@ -642,9 +618,9 @@ fn no_output() {
let actual = parse(source_code);
let expected = call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer", 15.into())),
CallInstrValue::Variable(VariableWithLambda::scalar("service", 21.into())),
CallInstrValue::Variable(VariableWithLambda::scalar("fname", 29.into())),
ResolvableToPeerIdVariable::Scalar(Scalar::new("peer", 15.into())),
ResolvableToStringVariable::Scalar(Scalar::new("service", 21.into())),
ResolvableToStringVariable::Scalar(Scalar::new("fname", 29.into())),
Rc::new(vec![]),
CallOutputValue::None,
);

View File

@ -32,7 +32,7 @@ fn canon_with_literal_peer_id() {
let actual = parse(&source_code);
let expected = canon(
CallInstrValue::Literal(peer_id),
ResolvableToPeerIdVariable::Literal(peer_id),
Stream::new(stream, 26.into()),
CanonStream::new(canon_stream, 34.into()),
);
@ -51,7 +51,7 @@ fn canon_with_variable_peer_id() {
let actual = parse(&source_code);
let expected = canon(
CallInstrValue::Variable(VariableWithLambda::scalar(peer_id, 16.into())),
ResolvableToPeerIdVariable::Scalar(Scalar::new(peer_id, 16.into())),
Stream::new(stream, 24.into()),
CanonStream::new(canon_stream, 32.into()),
);

View File

@ -18,14 +18,14 @@ use crate::ast::*;
use std::rc::Rc;
pub(super) fn call<'i>(
peer_pk: CallInstrValue<'i>,
service_id: CallInstrValue<'i>,
function_name: CallInstrValue<'i>,
args: Rc<Vec<Value<'i>>>,
peer_pk: ResolvableToPeerIdVariable<'i>,
service_id: ResolvableToStringVariable<'i>,
function_name: ResolvableToStringVariable<'i>,
args: Rc<Vec<ImmutableValue<'i>>>,
output: CallOutputValue<'i>,
) -> Instruction<'i> {
let triplet = Triplet {
peer_pk,
peer_id: peer_pk,
service_id,
function_name,
};
@ -73,10 +73,14 @@ pub(super) fn null() -> Instruction<'static> {
Instruction::Null(Null)
}
pub(super) fn fail_scalar(scalar: ScalarWithLambda) -> Instruction<'_> {
pub(super) fn fail_scalar(scalar: Scalar) -> Instruction<'_> {
Instruction::Fail(Fail::Scalar(scalar))
}
pub(super) fn fail_scalar_wl(scalar: ScalarWithLambda) -> Instruction<'_> {
Instruction::Fail(Fail::ScalarWithLambda(scalar))
}
pub(super) fn fail_literals(ret_code: i64, error_message: &str) -> Instruction<'_> {
Instruction::Fail(Fail::Literal {
ret_code,
@ -89,7 +93,7 @@ pub(super) fn fail_last_error() -> Instruction<'static> {
}
pub(super) fn fold_scalar_variable<'i>(
scalar: ScalarWithLambda<'i>,
scalar: Scalar<'i>,
iterator: Scalar<'i>,
instruction: Instruction<'i>,
last_instruction: Option<Instruction<'i>>,
@ -104,6 +108,22 @@ pub(super) fn fold_scalar_variable<'i>(
})
}
pub(super) fn fold_scalar_variable_wl<'i>(
scalar: ScalarWithLambda<'i>,
iterator: Scalar<'i>,
instruction: Instruction<'i>,
last_instruction: Option<Instruction<'i>>,
span: Span,
) -> Instruction<'i> {
Instruction::FoldScalar(FoldScalar {
iterable: FoldScalarIterable::ScalarWithLambda(scalar),
iterator,
instruction: Rc::new(instruction),
last_instruction: last_instruction.map(Rc::new),
span,
})
}
pub(super) fn fold_scalar_canon_stream<'i>(
canon_stream: CanonStream<'i>,
iterator: Scalar<'i>,
@ -152,8 +172,8 @@ pub(super) fn fold_stream<'i>(
}
pub(super) fn match_<'i>(
left_value: Value<'i>,
right_value: Value<'i>,
left_value: ImmutableValue<'i>,
right_value: ImmutableValue<'i>,
instruction: Instruction<'i>,
) -> Instruction<'i> {
Instruction::Match(Match {
@ -164,8 +184,8 @@ pub(super) fn match_<'i>(
}
pub(super) fn mismatch<'i>(
left_value: Value<'i>,
right_value: Value<'i>,
left_value: ImmutableValue<'i>,
right_value: ImmutableValue<'i>,
instruction: Instruction<'i>,
) -> Instruction<'i> {
Instruction::MisMatch(MisMatch {
@ -180,12 +200,12 @@ pub(super) fn ap<'i>(argument: ApArgument<'i>, result: ApResult<'i>) -> Instruct
}
pub(super) fn canon<'i>(
peer_pk: CallInstrValue<'i>,
peer_pk: ResolvableToPeerIdVariable<'i>,
stream: Stream<'i>,
canon_stream: CanonStream<'i>,
) -> Instruction<'i> {
Instruction::Canon(Canon {
peer_pk,
peer_id: peer_pk,
stream,
canon_stream,
})

View File

@ -16,6 +16,7 @@
use super::dsl::*;
use super::parse;
use crate::ast::Scalar;
use crate::ast::ScalarWithLambda;
use air_lambda_ast::LambdaAST;
@ -47,7 +48,7 @@ fn parse_fail_scalars() {
(fail scalar)
"#;
let instruction = parse(source_code);
let expected = fail_scalar(ScalarWithLambda::new("scalar", None, 18.into()));
let expected = fail_scalar(Scalar::new("scalar", 18.into()));
assert_eq!(instruction, expected)
}
@ -57,14 +58,12 @@ fn parse_fail_scalar_with_lambda() {
(fail scalar.$.field_accessor)
"#;
let instruction = parse(source_code);
let expected = fail_scalar(ScalarWithLambda::new(
let expected = fail_scalar_wl(ScalarWithLambda::new(
"scalar",
Some(
LambdaAST::try_from_accessors(vec![ValueAccessor::FieldAccessByName {
field_name: "field_accessor",
}])
.unwrap(),
),
LambdaAST::try_from_accessors(vec![ValueAccessor::FieldAccessByName {
field_name: "field_accessor",
}])
.unwrap(),
18.into(),
));
assert_eq!(instruction, expected)

View File

@ -272,7 +272,7 @@ fn parse_fold() {
"#;
let instruction = parse(&source_code);
let expected = fold_scalar_variable(
ScalarWithLambda::new("iterable", None, 15.into()),
Scalar::new("iterable", 15.into()),
Scalar::new("i", 24.into()),
null(),
None,
@ -291,7 +291,7 @@ fn fold_with_scalar_and_last_instruction() {
"#;
let instruction = parse(&source_code);
let expected = fold_scalar_variable(
ScalarWithLambda::new("iterable", None, 15.into()),
Scalar::new("iterable", 15.into()),
Scalar::new("i", 24.into()),
null(),
Some(null()),
@ -309,8 +309,8 @@ fn fold_json_path() {
"#;
let instruction = parse(source_code);
let expected = fold_scalar_variable(
ScalarWithLambda::from_value_path(
let expected = fold_scalar_variable_wl(
ScalarWithLambda::from_raw_lambda(
"members",
vec![ValueAccessor::ArrayAccess { idx: 123321 }],
33.into(),
@ -405,8 +405,8 @@ fn comments() {
;;; comme;?!.$. nt[][][][()()()null;$::!
"#;
let instruction = parse(source_code);
let expected = fold_scalar_variable(
ScalarWithLambda::from_value_path(
let expected = fold_scalar_variable_wl(
ScalarWithLambda::from_raw_lambda(
"members",
vec![
ValueAccessor::FieldAccessByName {
@ -436,7 +436,7 @@ fn parse_fold_with_xor_par_seq() {
let instruction = parse(&source_code);
let instr = binary_instruction(*name);
let expected = fold_scalar_variable(
ScalarWithLambda::new("iterable", None, 6.into()),
Scalar::new("iterable", 6.into()),
Scalar::new("i", 15.into()),
instr(null(), null()),
None,

View File

@ -31,8 +31,8 @@ fn parse_match() {
"#;
let instruction = parse(&source_code);
let expected = match_(
Value::Variable(VariableWithLambda::scalar("v1", 16.into())),
Value::Variable(VariableWithLambda::scalar("v2", 19.into())),
ImmutableValue::Variable(ImmutableVariable::scalar("v1", 16.into())),
ImmutableValue::Variable(ImmutableVariable::scalar("v2", 19.into())),
null(),
);
assert_eq!(instruction, expected);
@ -50,12 +50,12 @@ fn parse_match_with_canon_stream() {
let instruction = parse(&source_code);
let expected = match_(
Value::Variable(VariableWithLambda::canon_stream_wl(
ImmutableValue::VariableWithLambda(ImmutableVariableWithLambda::canon_stream(
canon_stream,
LambdaAST::try_from_accessors(vec![ValueAccessor::ArrayAccess { idx: 0 }]).unwrap(),
16.into(),
)),
Value::Variable(VariableWithLambda::scalar("v2", 36.into())),
ImmutableValue::Variable(ImmutableVariable::scalar("v2", 36.into())),
null(),
);
assert_eq!(instruction, expected);
@ -70,8 +70,8 @@ fn parse_match_with_init_peer_id() {
"#;
let instruction = parse(&source_code);
let expected = match_(
Value::Variable(VariableWithLambda::scalar("v1", 16.into())),
Value::InitPeerId,
ImmutableValue::Variable(ImmutableVariable::scalar("v1", 16.into())),
ImmutableValue::InitPeerId,
null(),
);
assert_eq!(instruction, expected);
@ -86,8 +86,8 @@ fn parse_match_with_timestamp() {
"#;
let instruction = parse(source_code);
let expected = match_(
Value::Timestamp,
Value::Variable(VariableWithLambda::scalar("v1", 28.into())),
ImmutableValue::Timestamp,
ImmutableValue::Variable(ImmutableVariable::scalar("v1", 28.into())),
null(),
);
assert_eq!(instruction, expected);
@ -102,8 +102,8 @@ fn parse_match_with_ttl() {
"#;
let instruction = parse(source_code);
let expected = match_(
Value::TTL,
Value::Variable(VariableWithLambda::scalar("v1", 22.into())),
ImmutableValue::TTL,
ImmutableValue::Variable(ImmutableVariable::scalar("v1", 22.into())),
null(),
);
assert_eq!(instruction, expected);
@ -118,8 +118,8 @@ fn parse_mismatch() {
"#;
let instruction = parse(&source_code);
let expected = mismatch(
Value::Variable(VariableWithLambda::scalar("v1", 19.into())),
Value::Variable(VariableWithLambda::scalar("v2", 22.into())),
ImmutableValue::Variable(ImmutableVariable::scalar("v1", 19.into())),
ImmutableValue::Variable(ImmutableVariable::scalar("v2", 22.into())),
null(),
);
assert_eq!(instruction, expected);
@ -133,8 +133,8 @@ fn match_with_bool() {
)
"#;
let left_value = Value::Variable(VariableWithLambda::scalar("isOnline", 17.into()));
let right_value = Value::Boolean(true);
let left_value = ImmutableValue::Variable(ImmutableVariable::scalar("isOnline", 17.into()));
let right_value = ImmutableValue::Boolean(true);
let null = null();
let expected = match_(left_value, right_value, null);
@ -150,8 +150,8 @@ fn mismatch_with_bool() {
)
"#;
let left_value = Value::Boolean(true);
let right_value = Value::Variable(VariableWithLambda::scalar("isOnline", 25.into()));
let left_value = ImmutableValue::Boolean(true);
let right_value = ImmutableValue::Variable(ImmutableVariable::scalar("isOnline", 25.into()));
let null = null();
let expected = mismatch(left_value, right_value, null);
@ -167,8 +167,8 @@ fn match_with_empty_array() {
)
"#;
let left_value = Value::Variable(VariableWithLambda::scalar("variable", 17.into()));
let right_value = Value::EmptyArray;
let left_value = ImmutableValue::Variable(ImmutableVariable::scalar("variable", 17.into()));
let right_value = ImmutableValue::EmptyArray;
let instr = null();
let expected = match_(left_value, right_value, instr);
@ -181,8 +181,8 @@ fn match_with_empty_array() {
)
"#;
let left_value = Value::EmptyArray;
let right_value = Value::Variable(VariableWithLambda::scalar("variable", 20.into()));
let left_value = ImmutableValue::EmptyArray;
let right_value = ImmutableValue::Variable(ImmutableVariable::scalar("variable", 20.into()));
let instr = null();
let expected = match_(left_value, right_value, instr);
@ -198,8 +198,8 @@ fn mismatch_with_empty_array() {
)
"#;
let left_value = Value::Variable(VariableWithLambda::scalar("variable", 20.into()));
let right_value = Value::EmptyArray;
let left_value = ImmutableValue::Variable(ImmutableVariable::scalar("variable", 20.into()));
let right_value = ImmutableValue::EmptyArray;
let instr = null();
let expected = mismatch(left_value, right_value, instr);
@ -212,8 +212,8 @@ fn mismatch_with_empty_array() {
)
"#;
let left_value = Value::EmptyArray;
let right_value = Value::Variable(VariableWithLambda::scalar("variable", 23.into()));
let left_value = ImmutableValue::EmptyArray;
let right_value = ImmutableValue::Variable(ImmutableVariable::scalar("variable", 23.into()));
let instr = null();
let expected = mismatch(left_value, right_value, instr);

View File

@ -32,16 +32,16 @@ fn parse_seq() {
let instruction = parse(source_code);
let expected = par(
call(
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
ResolvableToPeerIdVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![]),
CallOutputValue::None,
),
call(
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
ResolvableToPeerIdVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![]),
CallOutputValue::None,
),
@ -64,24 +64,24 @@ fn parse_par_par() {
let expected = par(
par(
call(
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
ResolvableToPeerIdVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![]),
CallOutputValue::None,
),
call(
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
ResolvableToPeerIdVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![]),
CallOutputValue::None,
),
),
call(
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
ResolvableToPeerIdVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
ResolvableToStringVariable::Literal(""),
Rc::new(vec![]),
CallOutputValue::None,
),

View File

@ -32,20 +32,20 @@ fn parse_seq() {
let instruction = parse(source_code);
let expected = seq(
call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 32.into())),
CallInstrValue::Variable(VariableWithLambda::scalar("service_id", 41.into())),
CallInstrValue::Variable(VariableWithLambda::scalar("function_name", 52.into())),
Rc::new(vec![Value::EmptyArray, Value::EmptyArray]),
ResolvableToPeerIdVariable::Scalar(Scalar::new("peer_id", 32.into())),
ResolvableToStringVariable::Scalar(Scalar::new("service_id", 41.into())),
ResolvableToStringVariable::Scalar(Scalar::new("function_name", 52.into())),
Rc::new(vec![ImmutableValue::EmptyArray, ImmutableValue::EmptyArray]),
CallOutputValue::Scalar(Scalar::new("output", 75.into())),
),
call(
CallInstrValue::Literal("peer_id"),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToPeerIdVariable::Literal("peer_id"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![
Value::Literal("hello"),
Value::EmptyArray,
Value::Variable(VariableWithLambda::scalar("name", 154.into())),
ImmutableValue::Literal("hello"),
ImmutableValue::EmptyArray,
ImmutableValue::Variable(ImmutableVariable::scalar("name", 154.into())),
]),
CallOutputValue::None,
),
@ -68,27 +68,27 @@ fn parse_seq_seq() {
let expected = seq(
seq(
call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 53.into())),
CallInstrValue::Variable(VariableWithLambda::scalar("service_id", 62.into())),
CallInstrValue::Variable(VariableWithLambda::scalar("function_name", 73.into())),
ResolvableToPeerIdVariable::Scalar(Scalar::new("peer_id", 53.into())),
ResolvableToStringVariable::Scalar(Scalar::new("service_id", 62.into())),
ResolvableToStringVariable::Scalar(Scalar::new("function_name", 73.into())),
Rc::new(vec![]),
CallOutputValue::None,
),
call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 114.into())),
CallInstrValue::Literal("service_B"),
CallInstrValue::Variable(VariableWithLambda::scalar("function_name", 135.into())),
ResolvableToPeerIdVariable::Scalar(Scalar::new("peer_id", 114.into())),
ResolvableToStringVariable::Literal("service_B"),
ResolvableToStringVariable::Scalar(Scalar::new("function_name", 135.into())),
Rc::new(vec![]),
CallOutputValue::None,
),
),
call(
CallInstrValue::Literal("peer_id"),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("function_name"),
ResolvableToPeerIdVariable::Literal("peer_id"),
ResolvableToStringVariable::Literal("service_id"),
ResolvableToStringVariable::Literal("function_name"),
Rc::new(vec![
Value::Literal("hello"),
Value::Variable(VariableWithLambda::scalar("name", 236.into())),
ImmutableValue::Literal("hello"),
ImmutableValue::Variable(ImmutableVariable::scalar("name", 236.into())),
]),
CallOutputValue::Stream(Stream::new("$output", 242.into())),
),

View File

@ -25,8 +25,8 @@ use air_lambda_ast::LambdaAST;
use air_lambda_ast::ValueAccessor;
use lalrpop_util::ErrorRecovery;
use lalrpop_util::ParseError;
use multimap::MultiMap;
use std::collections::HashMap;
use std::ops::Deref;
@ -66,9 +66,9 @@ impl<'i> VariableValidator<'i> {
}
pub(super) fn met_call(&mut self, call: &Call<'i>, span: Span) {
self.met_call_instr_value(&call.triplet.peer_pk, span);
self.met_call_instr_value(&call.triplet.service_id, span);
self.met_call_instr_value(&call.triplet.function_name, span);
self.met_peer_id_resolvable_value(&call.triplet.peer_id, span);
self.met_string_resolvable_value(&call.triplet.service_id, span);
self.met_string_resolvable_value(&call.triplet.function_name, span);
self.met_args(call.args.deref(), span);
@ -99,13 +99,9 @@ impl<'i> VariableValidator<'i> {
use FoldScalarIterable::*;
match &fold.iterable {
Scalar(variable) => {
self.met_variable_name(variable.name, span);
self.met_maybe_lambda(&variable.lambda, span);
}
CanonStream(canon_stream) => {
self.met_variable_name(canon_stream.name, span);
}
Scalar(scalar) => self.met_scalar(scalar, span),
ScalarWithLambda(scalar) => self.met_scalar_wl(scalar, span),
CanonStream(canon_stream) => self.met_canon_stream(canon_stream, span),
EmptyArray => {}
};
self.met_iterator_definition(&fold.iterator, span);
@ -142,13 +138,11 @@ impl<'i> VariableValidator<'i> {
| ApArgument::Literal(_)
| ApArgument::EmptyArray
| ApArgument::LastError(_) => {}
ApArgument::Scalar(scalar) => {
self.met_variable_name(scalar.name, span);
self.met_maybe_lambda(&scalar.lambda, span);
}
ApArgument::CanonStream(canon_stream) => {
self.met_variable_name(canon_stream.name, span);
self.met_maybe_lambda(&canon_stream.lambda, span);
ApArgument::Scalar(scalar) => self.met_scalar(scalar, span),
ApArgument::ScalarWithLambda(scalar) => self.met_scalar_wl(scalar, span),
ApArgument::CanonStream(canon_stream) => self.met_canon_stream(canon_stream, span),
ApArgument::CanonStreamWithLambda(canon_stream) => {
self.met_canon_stream_wl(canon_stream, span)
}
}
self.met_variable_name_definition(ap.result.name(), span);
@ -164,34 +158,78 @@ impl<'i> VariableValidator<'i> {
.build()
}
fn met_args(&mut self, args: &[Value<'i>], span: Span) {
fn met_args(&mut self, args: &[ImmutableValue<'i>], span: Span) {
for arg in args {
self.met_instr_arg_value(arg, span);
}
}
fn met_call_instr_value(&mut self, instr_value: &CallInstrValue<'i>, span: Span) {
if let CallInstrValue::Variable(variable) = instr_value {
self.met_variable_wl(variable, span);
fn met_peer_id_resolvable_value(
&mut self,
variable: &ResolvableToPeerIdVariable<'i>,
span: Span,
) {
use ResolvableToPeerIdVariable::*;
match variable {
InitPeerId | Literal(_) => {}
Scalar(scalar) => self.met_scalar(scalar, span),
ScalarWithLambda(scalar) => self.met_scalar_wl(scalar, span),
CanonStreamWithLambda(stream) => self.met_canon_stream_wl(stream, span),
}
}
fn met_instr_arg_value(&mut self, instr_arg_value: &Value<'i>, span: Span) {
if let Value::Variable(variable) = instr_arg_value {
// skipping streams without lambdas here allows treating non-defined streams as empty arrays
if let VariableWithLambda::Stream(stream) = variable {
if stream.lambda.is_none() {
return;
}
}
fn met_string_resolvable_value(
&mut self,
variable: &ResolvableToStringVariable<'i>,
span: Span,
) {
use ResolvableToStringVariable::*;
self.met_variable_wl(variable, span);
match variable {
Literal(_) => {}
Scalar(scalar) => self.met_scalar(scalar, span),
ScalarWithLambda(scalar) => self.met_scalar_wl(scalar, span),
CanonStreamWithLambda(stream) => self.met_canon_stream_wl(stream, span),
}
}
fn met_variable_wl(&mut self, variable: &VariableWithLambda<'i>, span: Span) {
fn met_instr_arg_value(&mut self, instr_arg_value: &ImmutableValue<'i>, span: Span) {
use ImmutableValue::*;
match instr_arg_value {
InitPeerId | LastError(_) | Timestamp | TTL | Literal(_) | Number(_) | Boolean(_)
| EmptyArray => {}
Variable(variable) => self.met_variable(variable, span),
VariableWithLambda(variable) => self.met_variable_wl(variable, span),
}
}
fn met_variable(&mut self, variable: &ImmutableVariable<'i>, span: Span) {
self.met_variable_name(variable.name(), span);
self.met_maybe_lambda(variable.lambda(), span);
}
fn met_variable_wl(&mut self, variable: &ImmutableVariableWithLambda<'i>, span: Span) {
self.met_variable_name(variable.name(), span);
self.met_lambda(variable.lambda(), span);
}
fn met_scalar(&mut self, scalar: &Scalar<'i>, span: Span) {
self.met_variable_name(scalar.name, span);
}
fn met_scalar_wl(&mut self, scalar: &ScalarWithLambda<'i>, span: Span) {
self.met_variable_name(scalar.name, span);
self.met_lambda(&scalar.lambda, span);
}
fn met_canon_stream(&mut self, stream: &CanonStream<'i>, span: Span) {
self.met_variable_name(stream.name, span);
}
fn met_canon_stream_wl(&mut self, stream: &CanonStreamWithLambda<'i>, span: Span) {
self.met_variable_name(stream.name, span);
self.met_lambda(&stream.lambda, span);
}
fn met_variable_name(&mut self, name: &'i str, span: Span) {
@ -200,14 +238,6 @@ impl<'i> VariableValidator<'i> {
}
}
fn met_maybe_lambda(&mut self, lambda: &Option<LambdaAST<'i>>, span: Span) {
let lambda = match lambda {
Some(lambda) => lambda,
None => return,
};
self.met_lambda(lambda, span)
}
fn met_lambda(&mut self, lambda: &LambdaAST<'i>, span: Span) {
let accessors = match lambda {
LambdaAST::ValuePath(accessors) => accessors,
@ -256,17 +286,18 @@ impl<'i> VariableValidator<'i> {
}
}
fn met_matchable(&mut self, matchable: &Value<'i>, span: Span) {
fn met_matchable(&mut self, matchable: &ImmutableValue<'i>, span: Span) {
match matchable {
Value::InitPeerId
| Value::Timestamp
| Value::TTL
| Value::Number(_)
| Value::Boolean(_)
| Value::Literal(_)
| Value::LastError(_)
| Value::EmptyArray => {}
Value::Variable(variable) => self.met_variable_wl(variable, span),
ImmutableValue::InitPeerId
| ImmutableValue::Timestamp
| ImmutableValue::TTL
| ImmutableValue::Number(_)
| ImmutableValue::Boolean(_)
| ImmutableValue::Literal(_)
| ImmutableValue::LastError(_)
| ImmutableValue::EmptyArray => {}
ImmutableValue::Variable(variable) => self.met_variable(variable, span),
ImmutableValue::VariableWithLambda(variable) => self.met_variable_wl(variable, span),
}
}

View File

@ -49,7 +49,7 @@ fn fmt_indent(output: &mut impl io::Write, indent: usize) -> io::Result<()> {
write!(output, "{:indent$}", "", indent = indent)
}
struct CallArgs<'ctx, 'i>(&'ctx [ast::Value<'i>]);
struct CallArgs<'ctx, 'i>(&'ctx [ast::ImmutableValue<'i>]);
impl<'ctx, 'i> Display for CallArgs<'ctx, 'i> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -65,7 +65,7 @@ impl<'ctx, 'i> Display for CallTriplet<'ctx, 'i> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"{} ({}, {})",
self.0.peer_pk, self.0.service_id, self.0.function_name
self.0.peer_id, self.0.service_id, self.0.function_name
))
}
}