Introduce new for non iterable scalars (#248)

This commit is contained in:
Mike Voronov 2022-04-20 11:43:46 +03:00 committed by GitHub
parent c2bfad7f79
commit 69a42cf111
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 473 additions and 47 deletions

View File

@ -1,3 +1,11 @@
## Version 0.23.0 (2021-04-19)
[PR 248](https://github.com/fluencelabs/aquavm/pull/248):
Introduced new for scalars
[PR 244](https://github.com/fluencelabs/aquavm/pull/244):
Stack size was increased to 50 MiB
## Version 0.22.0 (2021-04-14)
[PR 243](https://github.com/fluencelabs/aquavm/pull/243):

4
Cargo.lock generated
View File

@ -13,7 +13,7 @@ dependencies = [
[[package]]
name = "air"
version = "0.22.0"
version = "0.23.0"
dependencies = [
"air-execution-info-collector",
"air-interpreter-data",
@ -52,7 +52,7 @@ version = "0.1.0"
[[package]]
name = "air-interpreter"
version = "0.22.0"
version = "0.23.0"
dependencies = [
"air",
"air-log-targets",

View File

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

View File

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

View File

@ -82,7 +82,7 @@ fn apply_scalar_impl(
) -> ExecutionResult<ValueAggregate> {
use crate::execution_step::ScalarRef;
let scalar = exec_ctx.scalars.get(scalar_name)?;
let scalar = exec_ctx.scalars.get_value(scalar_name)?;
let mut result = match scalar {
ScalarRef::Value(result) => result.clone(),

View File

@ -213,12 +213,12 @@ fn check_output_name(output: &ast::CallOutputValue<'_>, exec_ctx: &ExecutionCtx<
_ => return Ok(()),
};
match exec_ctx.scalars.get(scalar_name) {
match exec_ctx.scalars.get_value(scalar_name) {
Ok(ScalarRef::Value(_)) => {
if exec_ctx.scalars.shadowing_allowed() {
if exec_ctx.scalars.variable_could_be_set(scalar_name) {
Ok(())
} else {
Err(UncatchableError::MultipleVariablesFound(scalar_name.to_string()).into())
Err(UncatchableError::ShadowingIsNotAllowed(scalar_name.to_string()).into())
}
}
Ok(ScalarRef::IterableValue(_)) => Err(UncatchableError::IterableShadowing(scalar_name.to_string()).into()),

View File

@ -71,7 +71,7 @@ fn create_scalar_iterable<'ctx>(
exec_ctx: &ExecutionCtx<'ctx>,
variable_name: &str,
) -> ExecutionResult<FoldIterableScalar> {
match exec_ctx.scalars.get(variable_name)? {
match exec_ctx.scalars.get_value(variable_name)? {
ScalarRef::Value(call_result) => from_call_result(call_result.clone(), variable_name),
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().unwrap();
@ -115,7 +115,7 @@ fn create_scalar_lambda_iterable<'ctx>(
) -> ExecutionResult<FoldIterableScalar> {
use crate::execution_step::lambda_applier::select_from_scalar;
match exec_ctx.scalars.get(scalar_name)? {
match exec_ctx.scalars.get_value(scalar_name)? {
ScalarRef::Value(variable) => {
let jvalues = select_from_scalar(&variable.result, lambda.iter(), exec_ctx)?;
let tetraplet = variable.tetraplet.deref().clone();

View File

@ -32,9 +32,17 @@ impl<'i> super::ExecutableInstruction<'i> for New<'i> {
// any error. It's highly important to distinguish between global and restricted streams
// at the end of execution to make a correct data.
let instruction_result = self.instruction.execute(exec_ctx, trace_ctx);
epilog(self, exec_ctx);
let epilog_result = epilog(self, exec_ctx);
instruction_result
match (instruction_result, epilog_result) {
(Ok(()), Ok(())) => Ok(()),
// instruction error has higher priority over epilog result error,
// because epilog returns "utility" errors that normally (meaning that AquaVM
// scalar handling code doesn't contain errors) shouldn't happen,
// additionally see test new_with_randomly_set_scalars_in_fold_2
(err @ Err(_), _) => err,
(_, err @ Err(_)) => err,
}
}
}
@ -45,20 +53,21 @@ fn prolog<'i>(new: &New<'i>, exec_ctx: &mut ExecutionCtx<'i>) {
let iteration = exec_ctx.tracker.new_tracker.get_iteration(position);
exec_ctx.streams.meet_scope_start(stream.name, new.span, iteration);
}
// noop
Variable::Scalar(_) => {}
Variable::Scalar(scalar) => exec_ctx.scalars.meet_new_start(scalar.name),
}
exec_ctx.tracker.meet_new(position);
}
fn epilog<'i>(new: &New<'i>, exec_ctx: &mut ExecutionCtx<'i>) {
fn epilog<'i>(new: &New<'i>, exec_ctx: &mut ExecutionCtx<'i>) -> ExecutionResult<()> {
let position = new.span.left;
match &new.variable {
Variable::Stream(stream) => exec_ctx
.streams
.meet_scope_end(stream.name.to_string(), position as u32),
// noop
Variable::Scalar(_) => {}
Variable::Stream(stream) => {
exec_ctx
.streams
.meet_scope_end(stream.name.to_string(), position as u32);
Ok(())
}
Variable::Scalar(scalar) => exec_ctx.scalars.meet_new_end(scalar.name),
}
}

View File

@ -82,6 +82,11 @@ pub enum CatchableError {
/// This error type is produced by a fail instruction that tries to throw a scalar that have inappropriate type.
#[error(transparent)]
InvalidLastErrorObjectError(#[from] LastErrorObjectError),
/// A new with this variable name was met and right after that it was accessed
/// that is prohibited.
#[error("variable with name '{0}' was cleared by new and then wasn't set")]
VariableWasNotInitializedAfterNew(String),
}
impl From<LambdaError> for Rc<CatchableError> {

View File

@ -55,9 +55,16 @@ pub enum UncatchableError {
#[error("ap result {0:?} doesn't match with corresponding instruction")]
ApResultNotCorrespondToInstr(MergerApResult),
/// Multiple values for such name found.
#[error("multiple variables found for name '{0}' in data")]
MultipleVariablesFound(String),
/// Variable shadowing is not allowed, usually it's thrown when a AIR tries to assign value
/// for a variable not in a fold block or in a global scope but not right after new.
#[error("trying to shadow variable '{0}', but shadowing is allowed only inside fold blocks")]
ShadowingIsNotAllowed(String),
/// This error occurred when new tries to pop up a variable at the end, but scalar state doesn't
/// contain an appropriate variable. It should be considered as an internal error and shouldn't
/// be caught by a xor instruction.
#[error("new end block tries to pop up a variable '{scalar_name}' that wasn't defined at depth {depth}")]
ScalarsStateCorrupted { scalar_name: String, depth: usize },
}
impl ToErrorCode for UncatchableError {

View File

@ -103,12 +103,19 @@ pub(crate) struct Scalars<'i> {
pub(crate) struct SparseCell {
/// Scope depth where the value was set.
pub(crate) depth: usize,
pub(crate) value: ValueAggregate,
pub(crate) value: Option<ValueAggregate>,
}
impl SparseCell {
pub(crate) fn new(depth: usize, value: ValueAggregate) -> Self {
Self { depth, value }
pub(crate) fn from_value(depth: usize, value: ValueAggregate) -> Self {
Self {
depth,
value: Some(value),
}
}
pub(crate) fn from_met_new(depth: usize) -> Self {
Self { depth, value: None }
}
}
@ -118,28 +125,29 @@ impl<'i> Scalars<'i> {
pub(crate) fn set_value(&mut self, name: impl Into<String>, value: ValueAggregate) -> ExecutionResult<bool> {
use std::collections::hash_map::Entry::{Occupied, Vacant};
let shadowing_allowed = self.shadowing_allowed();
match self.non_iterable_variables.entry(name.into()) {
let name = name.into();
let variable_could_be_set = self.variable_could_be_set(&name);
match self.non_iterable_variables.entry(name) {
Vacant(entry) => {
let cell = SparseCell::new(self.current_depth, value);
let cell = SparseCell::from_value(self.current_depth, value);
let cells = NonEmpty::new(cell);
entry.insert(cells);
Ok(false)
}
Occupied(entry) => {
if !shadowing_allowed {
return Err(UncatchableError::MultipleVariablesFound(entry.key().clone()).into());
if !variable_could_be_set {
return Err(UncatchableError::ShadowingIsNotAllowed(entry.key().clone()).into());
}
let values = entry.into_mut();
let last_cell = values.last_mut();
if last_cell.depth == self.current_depth {
// just rewrite a value if fold level is the same
last_cell.value = value;
last_cell.value = Some(value);
Ok(true)
} else {
let new_cell = SparseCell::new(self.current_depth, value);
let new_cell = SparseCell::from_value(self.current_depth, value);
values.push(new_cell);
Ok(false)
}
@ -167,7 +175,7 @@ impl<'i> Scalars<'i> {
self.iterable_variables.remove(name);
}
pub(crate) fn get_value(&'i self, name: &str) -> ExecutionResult<&'i ValueAggregate> {
pub(crate) fn get_non_iterable_value(&'i self, name: &str) -> ExecutionResult<Option<&'i ValueAggregate>> {
self.non_iterable_variables
.get(name)
.and_then(|values| {
@ -175,12 +183,12 @@ impl<'i> Scalars<'i> {
let value_not_invalidated = !self.invalidated_depths.contains(&last_cell.depth);
if value_not_invalidated {
Some(&last_cell.value)
Some(last_cell.value.as_ref())
} else {
None
}
})
.ok_or_else(|| Rc::new(CatchableError::VariableNotFound(name.to_string())).into())
.ok_or_else(|| ExecutionError::Catchable(Rc::new(CatchableError::VariableNotFound(name.to_string()))))
}
pub(crate) fn get_iterable_mut(&mut self, name: &str) -> ExecutionResult<&mut FoldState<'i>> {
@ -189,13 +197,14 @@ impl<'i> Scalars<'i> {
.ok_or_else(|| UncatchableError::FoldStateNotFound(name.to_string()).into())
}
pub(crate) fn get(&'i self, name: &str) -> ExecutionResult<ScalarRef<'i>> {
let value = self.get_value(name);
pub(crate) fn get_value(&'i self, name: &str) -> ExecutionResult<ScalarRef<'i>> {
let value = self.get_non_iterable_value(name);
let iterable_value = self.iterable_variables.get(name);
match (value, iterable_value) {
(Err(_), None) => Err(CatchableError::VariableNotFound(name.to_string()).into()),
(Ok(value), None) => Ok(ScalarRef::Value(value)),
(Ok(None), _) => Err(CatchableError::VariableWasNotInitializedAfterNew(name.to_string()).into()),
(Ok(Some(value)), None) => Ok(ScalarRef::Value(value)),
(Err(_), Some(iterable_value)) => Ok(ScalarRef::IterableValue(iterable_value)),
(Ok(_), Some(_)) => unreachable!("this is checked on the parsing stage"),
}
@ -223,6 +232,61 @@ impl<'i> Scalars<'i> {
self.cleanup_obsolete_values();
}
pub(crate) fn meet_new_start(&mut self, scalar_name: &str) {
use std::collections::hash_map::Entry::{Occupied, Vacant};
let new_cell = SparseCell::from_met_new(self.current_depth);
match self.non_iterable_variables.entry(scalar_name.to_string()) {
Vacant(entry) => {
let ne_vec = NonEmpty::new(new_cell);
entry.insert(ne_vec);
}
Occupied(entry) => {
let entry = entry.into_mut();
entry.push(new_cell);
}
}
}
pub(crate) fn meet_new_end(&mut self, scalar_name: &str) -> ExecutionResult<()> {
let current_depth = self.current_depth;
let should_remove_values = self
.non_iterable_variables
.get_mut(scalar_name)
.and_then(|values| {
// carefully check that we're popping up an appropriate value,
// returning None means an error here
match values.pop() {
Some(value) if value.depth == current_depth => Some(false),
Some(_) => None,
// None means that the value was last in a row
None if values.last().depth == current_depth => Some(true),
None => None,
}
})
.ok_or_else(|| UncatchableError::ScalarsStateCorrupted {
scalar_name: scalar_name.to_string(),
depth: self.current_depth,
})
.map_err(Into::<ExecutionError>::into)?;
if should_remove_values {
self.non_iterable_variables.remove(scalar_name);
}
Ok(())
}
pub(crate) fn variable_could_be_set(&self, variable_name: &str) -> bool {
if self.shadowing_allowed() {
return true;
}
match self.non_iterable_variables.get(variable_name) {
Some(values) => values.last().value.is_none(),
None => false,
}
}
pub(crate) fn shadowing_allowed(&self) -> bool {
// shadowing is allowed only inside a fold block, 0 here means that execution flow
// is in a global scope
@ -265,8 +329,8 @@ impl<'i> fmt::Display for Scalars<'i> {
writeln!(f, "fold_block_id: {}", self.current_depth)?;
for (name, _) in self.non_iterable_variables.iter() {
let value = self.get_value(name);
if let Ok(last_value) = value {
let value = self.get_non_iterable_value(name);
if let Ok(Some(last_value)) = value {
writeln!(f, "{} => {}", name, last_value.result)?;
}
}

View File

@ -43,7 +43,7 @@ pub(crate) fn select_from_stream<'value, 'i>(
}));
}
ValueAccessor::FieldAccessByScalar { scalar_name } => {
let scalar = exec_ctx.scalars.get(scalar_name)?;
let scalar = exec_ctx.scalars.get_value(scalar_name)?;
lambda_to_execution_error!(try_scalar_ref_as_idx(scalar))?
}
ValueAccessor::Error => unreachable!("should not execute if parsing succeeded. QED."),
@ -74,7 +74,7 @@ pub(crate) fn select_from_scalar<'value, 'accessor, 'i>(
value = lambda_to_execution_error!(try_jvalue_with_field_name(value, *field_name))?;
}
ValueAccessor::FieldAccessByScalar { scalar_name } => {
let scalar = exec_ctx.scalars.get(scalar_name)?;
let scalar = exec_ctx.scalars.get_value(scalar_name)?;
value = lambda_to_execution_error!(select_by_scalar(value, scalar))?;
}
ValueAccessor::Error => unreachable!("should not execute if parsing succeeded. QED."),

View File

@ -92,7 +92,7 @@ pub(crate) fn resolve_variable<'ctx, 'i>(
use crate::execution_step::boxed_value::StreamJvaluableIngredients;
match variable {
Variable::Scalar { name, .. } => Ok(ctx.scalars.get(name)?.into_jvaluable()),
Variable::Scalar { name, .. } => Ok(ctx.scalars.get_value(name)?.into_jvaluable()),
Variable::Stream {
name,
generation,

View File

@ -14,6 +14,8 @@
* limitations under the License.
*/
use air::CatchableError;
use air::ExecutionError;
use air_test_utils::prelude::*;
use fstrings::f;
@ -210,3 +212,80 @@ fn local_and_global_scalars() {
];
assert_eq!(actual_trace, expected_trace);
}
#[test]
fn new_with_randomly_set_scalars_in_fold_1() {
let test_peer_id_1 = "test_peer_id_1";
let mut test_vm_1 = create_avm(set_variable_call_service(json!([1, 2, 3])), test_peer_id_1);
let test_peer_id_2 = "test_peer_id_2";
let script = f!(r#"
(seq
(call "{test_peer_id_1}" ("" "") [] iterable)
(fold iterable iterator
(seq
(seq
(call "{test_peer_id_1}" ("" "") [] scalar)
(new scalar
(seq
(seq
(par
(call "{test_peer_id_2}" ("" "") [] scalar)
(null)
)
(next iterator)
)
(par
(call "{test_peer_id_2}" ("" "") [scalar])
(null)
)
)
)
)
(call "{test_peer_id_1}" ("" "") [scalar])
)
)
)"#);
let result = call_vm!(test_vm_1, "", &script, "", "");
assert_eq!(result.ret_code, 0)
}
#[test]
fn new_with_randomly_set_scalars_in_fold_2() {
let test_peer_id_1 = "test_peer_id_1";
let mut test_vm_1 = create_avm(set_variable_call_service(json!([1, 2, 3])), test_peer_id_1);
let test_peer_id_2 = "test_peer_id_2";
let variable_name = "scalar";
let script = f!(r#"
(seq
(call "{test_peer_id_1}" ("" "") [] iterable)
(fold iterable iterator
(seq
(seq
(call "{test_peer_id_1}" ("" "") [] {variable_name})
(new {variable_name}
(seq
(seq
(par
(call "{test_peer_id_2}" ("" "") [] {variable_name})
(null)
)
(next iterator)
)
(call "{test_peer_id_1}" ("" "") [{variable_name}])
)
)
)
(call "{test_peer_id_1}" ("" "") [{variable_name}])
)
)
)"#);
let result = call_vm!(test_vm_1, "", &script, "", "");
let expected_error = ExecutionError::Catchable(rc!(CatchableError::VariableWasNotInitializedAfterNew(
variable_name.to_string()
)));
assert!(check_error(&result, expected_error));
}

View File

@ -103,7 +103,7 @@ fn duplicate_variables() {
let result = call_vm!(vm, "asd", script, "", "");
let expected_error = UncatchableError::MultipleVariablesFound(variable_name.to_string());
let expected_error = UncatchableError::ShadowingIsNotAllowed(variable_name.to_string());
assert!(check_error(&result, expected_error));
assert!(result.next_peer_pks.is_empty());
}

View File

@ -271,3 +271,258 @@ fn new_with_errors() {
};
assert_eq!(actual_global_streams, expected_global_streams);
}
#[test]
fn new_with_global_scalars() {
let set_variable_peer_id = "set_variable_peer_id";
let variables_mapping = maplit::hashmap! {
"global".to_string() => json!(1),
"scoped".to_string() => json!(2),
};
let mut set_variable_vm = create_avm(
set_variables_call_service(variables_mapping, VariableOptionSource::Argument(0)),
set_variable_peer_id,
);
let variable_receiver_peer_id = "variable_receiver_peer_id";
let mut variable_receiver = create_avm(echo_call_service(), variable_receiver_peer_id);
let script = f!(r#"
(seq
(seq
(call "{set_variable_peer_id}" ("" "") ["global"] scalar)
(new scalar
(seq
(call "{set_variable_peer_id}" ("" "") ["scoped"] scalar)
(call "{variable_receiver_peer_id}" ("" "") [scalar])
)
)
)
(call "{variable_receiver_peer_id}" ("" "") [scalar])
)"#);
let result = checked_call_vm!(set_variable_vm, "", &script, "", "");
let result = checked_call_vm!(variable_receiver, "", &script, "", result.data);
let actual_trace = trace_from_result(&result);
let expected_trace = vec![
executed_state::scalar_number(1),
executed_state::scalar_number(2),
executed_state::scalar_number(2),
executed_state::scalar_number(1),
];
assert_eq!(actual_trace, expected_trace);
}
const GET_ITERABLE_ACTION_NAME: &'static str = "get_iterable_action_name";
const OUTSIDE_ACTION_NAME: &'static str = "outside_new";
const INSIDE_ACTION_NAME: &'static str = "inside_new";
const OUTPUT_ACTION_NAME: &'static str = "output";
fn prepare_new_test_call_service() -> CallServiceClosure {
let outside_new_id = std::cell::Cell::new(0u32);
let inside_new_id = std::cell::Cell::new(10u32);
Box::new(move |mut params| {
let action = params.arguments.remove(0);
let action = action.as_str().unwrap();
match action {
GET_ITERABLE_ACTION_NAME => CallServiceResult::ok(json!([1, 2, 3])),
OUTSIDE_ACTION_NAME => {
let outside_result = outside_new_id.get();
outside_new_id.set(outside_result + 1);
CallServiceResult::ok(json!(outside_result))
}
INSIDE_ACTION_NAME => {
let inside_result = inside_new_id.get();
inside_new_id.set(inside_result + 1);
CallServiceResult::ok(json!(inside_result))
}
OUTPUT_ACTION_NAME => {
let second_argument = params.arguments.remove(0);
CallServiceResult::ok(second_argument)
}
action_name => {
println!("unknown action: {:?}", action_name);
CallServiceResult::err(1, json!("no such action"))
}
}
})
}
#[test]
fn new_with_scalars_in_lfold_with_outside_next() {
let test_peer_id = "test_peer_id";
let test_call_service = prepare_new_test_call_service();
let mut test_vm = create_avm(test_call_service, test_peer_id);
let script = f!(r#"
(seq
(call "{test_peer_id}" ("" "") ["{GET_ITERABLE_ACTION_NAME}"] iterable)
(fold iterable iterator
(seq
(seq
(seq
(call "{test_peer_id}" ("" "") ["{OUTSIDE_ACTION_NAME}"] scalar)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
(new scalar
(seq
(call "{test_peer_id}" ("" "") ["{INSIDE_ACTION_NAME}"] scalar)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
)
)
(seq
(next iterator)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
)
)
)
"#);
let result = checked_call_vm!(test_vm, "", &script, "", "");
let actual_trace = trace_from_result(&result);
let expected_trace = vec![
executed_state::scalar(json!([1, 2, 3])),
executed_state::scalar_number(0),
executed_state::scalar_number(0),
executed_state::scalar_number(10),
executed_state::scalar_number(10),
executed_state::scalar_number(1),
executed_state::scalar_number(1),
executed_state::scalar_number(11),
executed_state::scalar_number(11),
executed_state::scalar_number(2),
executed_state::scalar_number(2),
executed_state::scalar_number(12),
executed_state::scalar_number(12),
executed_state::scalar_number(2),
executed_state::scalar_number(1),
executed_state::scalar_number(0),
];
assert_eq!(actual_trace, expected_trace);
}
#[test]
fn new_with_scalars_in_rfold_with_outside_next() {
let test_peer_id = "test_peer_id";
let test_call_service = prepare_new_test_call_service();
let mut test_vm = create_avm(test_call_service, test_peer_id);
let script = f!(r#"
(seq
(call "{test_peer_id}" ("" "") ["{GET_ITERABLE_ACTION_NAME}"] iterable)
(fold iterable iterator
(seq
(next iterator)
(seq
(seq
(call "{test_peer_id}" ("" "") ["{OUTSIDE_ACTION_NAME}"] scalar)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
(seq
(new scalar
(seq
(call "{test_peer_id}" ("" "") ["{INSIDE_ACTION_NAME}"] scalar)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
)
)
)
)
"#);
let result = checked_call_vm!(test_vm, "", &script, "", "");
let actual_trace = trace_from_result(&result);
let expected_trace = vec![
executed_state::scalar(json!([1, 2, 3])),
executed_state::scalar_number(0),
executed_state::scalar_number(0),
executed_state::scalar_number(10),
executed_state::scalar_number(10),
executed_state::scalar_number(0),
executed_state::scalar_number(1),
executed_state::scalar_number(1),
executed_state::scalar_number(11),
executed_state::scalar_number(11),
executed_state::scalar_number(1),
executed_state::scalar_number(2),
executed_state::scalar_number(2),
executed_state::scalar_number(12),
executed_state::scalar_number(12),
executed_state::scalar_number(2),
];
assert_eq!(actual_trace, expected_trace);
}
#[test]
fn new_with_scalars_in_fold_with_inside_next() {
let test_peer_id = "test_peer_id";
let test_call_service = prepare_new_test_call_service();
let mut test_vm = create_avm(test_call_service, test_peer_id);
let script = f!(r#"
(seq
(call "{test_peer_id}" ("" "") ["{GET_ITERABLE_ACTION_NAME}"] iterable)
(fold iterable iterator
(seq
(seq
(seq
(call "{test_peer_id}" ("" "") ["{OUTSIDE_ACTION_NAME}"] scalar)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
(new scalar
(seq
(call "{test_peer_id}" ("" "") ["{INSIDE_ACTION_NAME}"] scalar)
(seq
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
(seq
(next iterator)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
)
)
)
)
(call "{test_peer_id}" ("" "") ["{OUTPUT_ACTION_NAME}" scalar])
)
)
)
"#);
let result = checked_call_vm!(test_vm, "", &script, "", "");
let actual_trace = trace_from_result(&result);
let expected_trace = vec![
executed_state::scalar(json!([1, 2, 3])),
executed_state::scalar_number(0),
executed_state::scalar_number(0),
executed_state::scalar_number(10),
executed_state::scalar_number(10),
executed_state::scalar_number(1),
executed_state::scalar_number(1),
executed_state::scalar_number(11),
executed_state::scalar_number(11),
executed_state::scalar_number(2),
executed_state::scalar_number(2),
executed_state::scalar_number(12),
executed_state::scalar_number(12),
executed_state::scalar_number(12),
executed_state::scalar_number(2),
executed_state::scalar_number(11),
executed_state::scalar_number(1),
executed_state::scalar_number(10),
executed_state::scalar_number(0),
];
assert_eq!(actual_trace, expected_trace);
}

View File

@ -95,7 +95,7 @@ fn xor_multiple_variables_found() {
let result = call_vm!(set_variables_vm, "asd", &script, "", "");
let expected_error = UncatchableError::MultipleVariablesFound(variable_name.to_string());
let expected_error = UncatchableError::ShadowingIsNotAllowed(variable_name.to_string());
assert!(check_error(&result, expected_error));
}

View File

@ -70,7 +70,6 @@ fn iterators_cant_be_restricted() {
let errors = validator.finalize();
assert_eq!(errors.len(), 1);
println!("{:?}", errors);
let error = &errors[0].error;
let parser_error = match error {
ParseError::User { error } => error,