Improve the scalars storing scheme (#162)

This commit is contained in:
Mike Voronov 2021-10-20 23:35:46 +03:00 committed by GitHub
parent 1c55d34981
commit 18f4c0036f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 368 additions and 354 deletions

12
Cargo.lock generated
View File

@ -291,9 +291,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.7.1"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byteorder"
@ -935,9 +935,9 @@ dependencies = [
[[package]]
name = "instant"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
@ -1074,9 +1074,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.103"
version = "0.2.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce"
[[package]]
name = "lock_api"

View File

@ -17,12 +17,11 @@
mod apply_to_arguments;
mod utils;
use super::call::call_result_setter::set_scalar_result;
use super::call::call_result_setter::set_stream_result;
use super::ExecutionCtx;
use super::ExecutionResult;
use super::TraceHandler;
use crate::execution_step::air::ResolvedCallResult;
use crate::execution_step::air::ValueAggregate;
use crate::execution_step::boxed_value::Variable;
use crate::execution_step::utils::apply_lambda;
use crate::trace_to_exec_err;
@ -69,11 +68,11 @@ impl<'i> super::ExecutableInstruction<'i> for Ap<'i> {
fn save_result<'ctx>(
ap_result_type: &AstVariable<'ctx>,
merger_ap_result: &MergerApResult,
result: ResolvedCallResult,
result: ValueAggregate,
exec_ctx: &mut ExecutionCtx<'ctx>,
) -> ExecutionResult<()> {
match ap_result_type {
AstVariable::Scalar(name) => set_scalar_result(result, name, exec_ctx),
AstVariable::Scalar(name) => exec_ctx.scalars.set_value(*name, result).map(|_| ()),
AstVariable::Stream(name) => {
let generation = ap_result_to_generation(merger_ap_result);
set_stream_result(result, generation, name.to_string(), exec_ctx).map(|_| ())

View File

@ -21,7 +21,7 @@ pub(super) fn apply_to_arg(
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
should_touch_trace: bool,
) -> ExecutionResult<ResolvedCallResult> {
) -> ExecutionResult<ValueAggregate> {
let result = match argument {
ApArgument::ScalarVariable(scalar_name) => apply_scalar(scalar_name, exec_ctx, trace_ctx, should_touch_trace)?,
ApArgument::VariableWithLambda(vl) => apply_json_argument(vl, exec_ctx, trace_ctx)?,
@ -40,18 +40,14 @@ fn apply_scalar(
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
should_touch_trace: bool,
) -> ExecutionResult<ResolvedCallResult> {
use crate::execution_step::ExecutionError::VariableNotFound;
use crate::execution_step::Scalar;
) -> ExecutionResult<ValueAggregate> {
use crate::execution_step::ScalarRef;
let scalar = exec_ctx
.scalars
.get(scalar_name)
.ok_or_else(|| VariableNotFound(scalar_name.to_string()))?;
let scalar = exec_ctx.scalars.get(scalar_name)?;
let mut result = match scalar {
Scalar::JValueRef(result) => result.clone(),
Scalar::JValueFoldCursor(iterator) => {
ScalarRef::Value(result) => result.clone(),
ScalarRef::IterableValue(iterator) => {
let result = iterator.iterable.peek().expect(
"peek always return elements inside fold,\
this guaranteed by implementation of next and avoiding empty folds",
@ -67,24 +63,24 @@ fn apply_scalar(
Ok(result)
}
fn apply_const(value: impl Into<JValue>, exec_ctx: &ExecutionCtx<'_>, trace_ctx: &TraceHandler) -> ResolvedCallResult {
fn apply_const(value: impl Into<JValue>, exec_ctx: &ExecutionCtx<'_>, trace_ctx: &TraceHandler) -> ValueAggregate {
let value = Rc::new(value.into());
let tetraplet = SecurityTetraplet::literal_tetraplet(exec_ctx.init_peer_id.clone());
let tetraplet = Rc::new(RefCell::new(tetraplet));
ResolvedCallResult::new(value, tetraplet, trace_ctx.trace_pos())
ValueAggregate::new(value, tetraplet, trace_ctx.trace_pos())
}
fn apply_last_error(
error_path: &LastErrorPath,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
) -> ExecutionResult<ResolvedCallResult> {
) -> ExecutionResult<ValueAggregate> {
let (value, mut tetraplets) = crate::execution_step::utils::prepare_last_error(error_path, exec_ctx)?;
let value = Rc::new(value);
let tetraplet = tetraplets.remove(0);
let result = ResolvedCallResult::new(value, tetraplet, trace_ctx.trace_pos());
let result = ValueAggregate::new(value, tetraplet, trace_ctx.trace_pos());
Ok(result)
}
@ -92,14 +88,14 @@ fn apply_json_argument(
vl: &VariableWithLambda<'_>,
exec_ctx: &ExecutionCtx<'_>,
trace_ctx: &TraceHandler,
) -> ExecutionResult<ResolvedCallResult> {
) -> ExecutionResult<ValueAggregate> {
let variable = Variable::from_ast(&vl.variable);
let (jvalue, mut tetraplets) = apply_lambda(variable, &vl.lambda, exec_ctx)?;
let tetraplet = tetraplets
.pop()
.unwrap_or_else(|| Rc::new(RefCell::new(SecurityTetraplet::default())));
let result = ResolvedCallResult::new(Rc::new(jvalue), tetraplet, trace_ctx.trace_pos());
let result = ValueAggregate::new(Rc::new(jvalue), tetraplet, trace_ctx.trace_pos());
Ok(result)
}

View File

@ -15,13 +15,11 @@
*/
use super::*;
use crate::exec_err;
use crate::execution_step::execution_context::*;
use crate::execution_step::AstVariable;
use crate::execution_step::Generation;
use crate::execution_step::ResolvedCallResult;
use crate::execution_step::Scalar;
use crate::execution_step::Stream;
use crate::execution_step::ValueAggregate;
use air_interpreter_data::CallResult;
use air_interpreter_data::Value;
@ -34,14 +32,14 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
/// Writes result of a local `Call` instruction to `ExecutionCtx` at `output`.
/// Returns call result.
pub(crate) fn set_local_result<'i>(
executed_result: ResolvedCallResult,
executed_result: ValueAggregate,
output: &CallOutputValue<'i>,
exec_ctx: &mut ExecutionCtx<'i>,
) -> ExecutionResult<CallResult> {
let result_value = executed_result.result.clone();
match output {
CallOutputValue::Variable(AstVariable::Scalar(name)) => {
set_scalar_result(executed_result, name, exec_ctx)?;
exec_ctx.scalars.set_value(*name, executed_result)?;
Ok(CallResult::executed_scalar(result_value))
}
CallOutputValue::Variable(AstVariable::Stream(name)) => {
@ -67,11 +65,11 @@ pub(crate) fn set_result_from_value<'i>(
) -> ExecutionResult<()> {
match (output, value) {
(CallOutputValue::Variable(AstVariable::Scalar(name)), Value::Scalar(value)) => {
let result = ResolvedCallResult::new(value, tetraplet, trace_pos);
set_scalar_result(result, name, exec_ctx)?;
let result = ValueAggregate::new(value, tetraplet, trace_pos);
exec_ctx.scalars.set_value(*name, result)?;
}
(CallOutputValue::Variable(AstVariable::Stream(name)), Value::Stream { value, generation }) => {
let result = ResolvedCallResult::new(value, tetraplet, trace_pos);
let result = ValueAggregate::new(value, tetraplet, trace_pos);
let generation = Generation::Nth(generation);
let _ = set_stream_result(result, generation, name.to_string(), exec_ctx)?;
}
@ -83,68 +81,9 @@ pub(crate) fn set_result_from_value<'i>(
Ok(())
}
#[macro_export]
macro_rules! shadowing_allowed(
($exec_ctx:ident, $entry:ident) => { {
// check that current execution_step flow is inside a fold block
if $exec_ctx.met_folds.is_empty() {
// shadowing is allowed only inside fold blocks
return exec_err!(ExecutionError::MultipleVariablesFound($entry.key().clone()));
}
match $entry.get() {
Scalar::JValueRef(_) => {}
// shadowing is allowed only for JValue not iterable
_ => return exec_err!(ExecutionError::IterableShadowing($entry.key().clone())),
};
ExecutionResult::Ok(())
}}
);
// TODO: decouple this function to a separate module
pub(crate) fn set_scalar_result<'i>(
executed_result: ResolvedCallResult,
scalar_name: &'i str,
exec_ctx: &mut ExecutionCtx<'i>,
) -> ExecutionResult<()> {
meet_scalar(scalar_name, executed_result.clone(), exec_ctx)?;
match exec_ctx.scalars.entry(scalar_name.to_string()) {
Vacant(entry) => {
entry.insert(Scalar::JValueRef(executed_result));
}
Occupied(mut entry) => {
// the macro instead of a function because of borrowing
shadowing_allowed!(exec_ctx, entry)?;
entry.insert(Scalar::JValueRef(executed_result));
}
};
Ok(())
}
/// Inserts meet variable name into met calls in fold to allow shadowing.
fn meet_scalar<'i>(
scalar_name: &'i str,
executed_result: ResolvedCallResult,
exec_ctx: &mut ExecutionCtx<'i>,
) -> ExecutionResult<()> {
if let Some(fold_block_name) = exec_ctx.met_folds.back() {
let fold_state = match exec_ctx.scalars.get_mut(*fold_block_name) {
Some(Scalar::JValueFoldCursor(fold_state)) => fold_state,
_ => unreachable!("fold block data must be represented as fold cursor"),
};
fold_state.met_variables.insert(scalar_name, executed_result);
}
Ok(())
}
// TODO: decouple this function to a separate module
pub(crate) fn set_stream_result(
executed_result: ResolvedCallResult,
executed_result: ValueAggregate,
generation: Generation,
stream_name: String,
exec_ctx: &mut ExecutionCtx<'_>,

View File

@ -85,7 +85,7 @@ pub(super) fn handle_prev_state<'i>(
}
use super::call_result_setter::*;
use crate::execution_step::ResolvedCallResult;
use crate::execution_step::ValueAggregate;
use crate::JValue;
fn update_state_with_service_result<'i>(
@ -102,7 +102,7 @@ fn update_state_with_service_result<'i>(
let trace_pos = trace_ctx.trace_pos();
let executed_result = ResolvedCallResult::new(result, tetraplet.clone(), trace_pos);
let executed_result = ValueAggregate::new(result, tetraplet.clone(), trace_pos);
let new_call_result = set_local_result(executed_result, output, exec_ctx)?;
trace_ctx.meet_call_end(new_call_result);

View File

@ -169,7 +169,7 @@ impl<'i> ResolvedCall<'i> {
/// Check output type name for being already in execution context.
// TODO: this check should be moved on a parsing stage
fn check_output_name(output: &CallOutputValue<'_>, exec_ctx: &ExecutionCtx<'_>) -> ExecutionResult<()> {
use crate::execution_step::boxed_value::Scalar;
use crate::execution_step::boxed_value::ScalarRef;
let scalar_name = match output {
CallOutputValue::Variable(AstVariable::Scalar(name)) => *name,
@ -177,15 +177,14 @@ fn check_output_name(output: &CallOutputValue<'_>, exec_ctx: &ExecutionCtx<'_>)
};
match exec_ctx.scalars.get(scalar_name) {
Some(Scalar::JValueRef(_)) => {
if exec_ctx.met_folds.is_empty() {
// shadowing is allowed only inside fold blocks
crate::exec_err!(ExecutionError::MultipleVariablesFound(scalar_name.to_string()))
} else {
Ok(ScalarRef::Value(_)) => {
if exec_ctx.scalars.shadowing_allowed() {
Ok(())
} else {
crate::exec_err!(ExecutionError::MultipleVariablesFound(scalar_name.to_string()))
}
}
Some(_) => crate::exec_err!(ExecutionError::IterableShadowing(scalar_name.to_string())),
None => Ok(()),
Ok(ScalarRef::IterableValue(_)) => crate::exec_err!(ExecutionError::IterableShadowing(scalar_name.to_string())),
Err(_) => Ok(()),
}
}

View File

@ -16,17 +16,13 @@
use super::Instruction;
use super::IterableValue;
use super::ResolvedCallResult;
use std::collections::HashMap;
use std::rc::Rc;
pub(crate) struct FoldState<'i> {
pub(crate) iterable: IterableValue,
pub(crate) iterable_type: IterableType,
pub(crate) instr_head: Rc<Instruction<'i>>,
// map of met variables inside this (not any inner) fold block with their initial values
pub(crate) met_variables: HashMap<&'i str, ResolvedCallResult>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -45,7 +41,6 @@ impl<'i> FoldState<'i> {
iterable,
iterable_type,
instr_head,
met_variables: HashMap::new(),
}
}
}

View File

@ -16,17 +16,15 @@
mod fold_state;
mod utils;
mod variable_handler;
pub(crate) use fold_state::FoldState;
pub(crate) use fold_state::IterableType;
pub(super) use utils::*;
pub(super) use variable_handler::VariableHandler;
use super::ExecutionCtx;
use super::ExecutionError;
use super::ExecutionResult;
use super::Instruction;
use super::ResolvedCallResult;
use super::Scalar;
use super::ScalarRef;
use super::ValueAggregate;
use crate::execution_step::boxed_value::*;

View File

@ -88,19 +88,18 @@ fn create_scalar_iterable<'ctx>(
exec_ctx: &ExecutionCtx<'ctx>,
variable_name: &str,
) -> ExecutionResult<FoldIterableScalar> {
match exec_ctx.scalars.get(variable_name) {
Some(Scalar::JValueRef(call_result)) => from_call_result(call_result.clone()),
Some(Scalar::JValueFoldCursor(fold_state)) => {
match exec_ctx.scalars.get(variable_name)? {
ScalarRef::Value(call_result) => from_call_result(call_result.clone()),
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().unwrap();
let call_result = iterable_value.into_resolved_result();
from_call_result(call_result)
}
_ => return exec_err!(ExecutionError::VariableNotFound(variable_name.to_string())),
}
}
/// Constructs iterable value from resolved call result.
fn from_call_result(call_result: ResolvedCallResult) -> ExecutionResult<FoldIterableScalar> {
fn from_call_result(call_result: ValueAggregate) -> ExecutionResult<FoldIterableScalar> {
use ExecutionError::IncompatibleJValueType;
let len = match &call_result.result.deref() {
@ -128,19 +127,18 @@ fn create_scalar_lambda_iterable<'ctx>(
) -> ExecutionResult<FoldIterableScalar> {
use crate::execution_step::lambda_applier::select;
match exec_ctx.scalars.get(scalar_name) {
Some(Scalar::JValueRef(variable)) => {
match exec_ctx.scalars.get(scalar_name)? {
ScalarRef::Value(variable) => {
let jvalues = select(&variable.result, lambda.iter())?;
from_jvalue(jvalues, variable.tetraplet.clone(), lambda)
}
Some(Scalar::JValueFoldCursor(fold_state)) => {
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().unwrap();
let jvalues = iterable_value.apply_lambda(lambda)?;
let tetraplet = as_tetraplet(&iterable_value);
from_jvalue(jvalues[0], tetraplet, lambda)
}
_ => return exec_err!(ExecutionError::VariableNotFound(scalar_name.to_string())),
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::ExecutionCtx;
use super::ExecutionResult;
use super::FoldState;
use super::Scalar;
use std::collections::HashMap;
pub(crate) struct VariableHandler<'i> {
iterator: &'i str,
}
impl<'i> VariableHandler<'i> {
pub(crate) fn init<'ctx: 'i>(
exec_ctx: &mut ExecutionCtx<'ctx>,
iterator: &'ctx str,
fold_state: FoldState<'ctx>,
) -> ExecutionResult<Self> {
Self::try_insert_fold_state(exec_ctx, iterator, fold_state)?;
Self::meet_iterator(exec_ctx, iterator);
let handler = Self { iterator };
Ok(handler)
}
pub(crate) fn cleanup(self, exec_ctx: &mut ExecutionCtx<'_>) {
let fold_state = match exec_ctx.scalars.remove(self.iterator) {
Some(Scalar::JValueFoldCursor(fold_state)) => fold_state,
_ => unreachable!("fold cursor is changed only inside fold block"),
};
for (variable_name, _) in fold_state.met_variables {
exec_ctx.scalars.remove(variable_name);
}
exec_ctx.met_folds.pop_back();
// TODO: fix 3 or more inner folds behaviour
if let Some(fold_block_name) = exec_ctx.met_folds.back() {
let fold_state = match exec_ctx.scalars.get(*fold_block_name) {
Some(Scalar::JValueFoldCursor(fold_state)) => fold_state,
_ => unreachable!("fold block data must be represented as fold cursor"),
};
let mut upper_fold_values = HashMap::new();
for (variable_name, variable) in fold_state.met_variables.iter() {
upper_fold_values.insert(variable_name.to_string(), Scalar::JValueRef(variable.clone()));
}
exec_ctx.scalars.extend(upper_fold_values);
}
}
fn try_insert_fold_state<'ctx>(
exec_ctx: &mut ExecutionCtx<'ctx>,
iterator: &'ctx str,
fold_state: FoldState<'ctx>,
) -> ExecutionResult<()> {
use super::ExecutionError::MultipleFoldStates;
let previous_value = exec_ctx
.scalars
.insert(iterator.to_string(), Scalar::JValueFoldCursor(fold_state));
if previous_value.is_some() {
return crate::exec_err!(MultipleFoldStates(iterator.to_string()));
}
Ok(())
}
fn meet_iterator<'ctx>(exec_ctx: &mut ExecutionCtx<'ctx>, iterator: &'ctx str) {
exec_ctx.met_folds.push_back(iterator);
}
}

View File

@ -29,7 +29,9 @@ impl<'i> ExecutableInstruction<'i> for FoldScalar<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> {
log_instruction!(fold, exec_ctx, trace_ctx);
match construct_scalar_iterable_value(&self.iterable, exec_ctx)? {
exec_ctx.scalars.meet_fold_begin();
let fold_result = match construct_scalar_iterable_value(&self.iterable, exec_ctx)? {
FoldIterableScalar::Empty => Ok(()),
FoldIterableScalar::Scalar(iterable) => fold(
iterable,
@ -39,7 +41,11 @@ impl<'i> ExecutableInstruction<'i> for FoldScalar<'i> {
exec_ctx,
trace_ctx,
),
}
};
exec_ctx.scalars.meet_fold_end();
fold_result
}
}
@ -52,11 +58,11 @@ pub(super) fn fold<'i>(
trace_ctx: &mut TraceHandler,
) -> ExecutionResult<()> {
let fold_state = FoldState::from_iterable(iterable, iterable_type, instruction.clone());
let variable_handler = VariableHandler::init(exec_ctx, iterator, fold_state)?;
exec_ctx.scalars.set_iterable_value(iterator, fold_state)?;
instruction.execute(exec_ctx, trace_ctx)?;
variable_handler.cleanup(exec_ctx);
exec_ctx.scalars.remove_iterable_value(iterator);
Ok(())
}

View File

@ -36,6 +36,7 @@ impl<'i> ExecutableInstruction<'i> for FoldStream<'i> {
let fold_id = exec_ctx.tracker.fold.seen_stream_count;
trace_to_exec_err!(trace_ctx.meet_fold_start(fold_id))?;
exec_ctx.scalars.meet_fold_begin();
for iterable in iterables {
let value = match iterable.peek() {
@ -63,6 +64,7 @@ impl<'i> ExecutableInstruction<'i> for FoldStream<'i> {
}
trace_to_exec_err!(trace_ctx.meet_fold_end(fold_id))?;
exec_ctx.scalars.meet_fold_end();
Ok(())
}

View File

@ -30,8 +30,8 @@ mod xor;
pub(crate) use fold::FoldState;
use super::boxed_value::ResolvedCallResult;
use super::boxed_value::Scalar;
use super::boxed_value::ScalarRef;
use super::boxed_value::ValueAggregate;
use super::execution_context::*;
use super::Catchable;
use super::ExecutionCtx;
@ -147,12 +147,8 @@ macro_rules! log_instruction {
log::debug!(target: air_log_targets::INSTRUCTION, "> {}", stringify!($instr_name));
let mut variables = String::from(" scalars:");
if $exec_ctx.scalars.is_empty() {
variables.push_str(" empty");
}
for (key, value) in $exec_ctx.scalars.iter() {
variables.push_str(&format!("\n {} => {}", key, value));
}
variables.push_str(&format!("\n {}", $exec_ctx.scalars));
variables.push_str(" streams:");
if $exec_ctx.streams.is_empty() {

View File

@ -16,12 +16,9 @@
use super::fold::IterableType;
use super::ExecutionCtx;
use super::ExecutionError;
use super::ExecutionResult;
use super::FoldState;
use super::Scalar;
use super::TraceHandler;
use crate::exec_err;
use crate::log_instruction;
use crate::trace_to_exec_err;
@ -32,7 +29,7 @@ impl<'i> super::ExecutableInstruction<'i> for Next<'i> {
log_instruction!(next, exec_ctx, trace_ctx);
let iterator_name = self.0;
let fold_state = try_get_fold_state(exec_ctx, iterator_name)?;
let fold_state = exec_ctx.scalars.get_iterable_mut(iterator_name)?;
maybe_meet_iteration_end(fold_state, trace_ctx)?;
if !fold_state.iterable.next() {
@ -48,46 +45,14 @@ impl<'i> super::ExecutableInstruction<'i> for Next<'i> {
next_instr.execute(exec_ctx, trace_ctx)?;
// get the same fold state again because of borrow checker
match exec_ctx.scalars.get_mut(iterator_name) {
// move iterator back to provide correct value for possible subtree after next
// (for example for cases such as right fold)
Some(Scalar::JValueFoldCursor(fold_state)) => fold_state.iterable.prev(),
_ => unreachable!("iterator value shouldn't changed inside fold"),
};
// get this fold state the second time to bypass borrow checker
let fold_state = try_get_fold_state(exec_ctx, iterator_name)?;
let fold_state = exec_ctx.scalars.get_iterable_mut(iterator_name)?;
fold_state.iterable.prev();
maybe_meet_back_iterator(fold_state, trace_ctx)?;
Ok(())
}
}
fn try_get_fold_state<'i, 'ctx>(
exec_ctx: &'ctx mut ExecutionCtx<'i>,
iterator_name: &str,
) -> ExecutionResult<&'ctx mut FoldState<'i>> {
use ExecutionError::FoldStateNotFound;
use ExecutionError::IncompatibleAValueType;
let avalue = exec_ctx
.scalars
.get_mut(iterator_name)
.ok_or_else(|| FoldStateNotFound(iterator_name.to_string()))?;
match avalue {
Scalar::JValueFoldCursor(state) => Ok(state),
v => {
// it's not possible to use unreachable here
// because at now next syntactically could be used without fold
exec_err!(IncompatibleAValueType(
format!("{}", v),
String::from("JValueFoldCursor"),
))
}
}
}
fn maybe_meet_iteration_start(fold_state: &FoldState<'_>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> {
if let IterableType::Stream(fold_id) = &fold_state.iterable_type {
trace_to_exec_err!(trace_ctx.meet_iteration_start(*fold_id, fold_state.iterable.peek().unwrap().pos()))?;

View File

@ -23,7 +23,7 @@ pub(crate) use json_path_result::IterableLambdaResult;
pub(crate) use resolved_call::IterableResolvedCall;
pub(crate) use vec_resolved_call::IterableVecResolvedCall;
use super::ResolvedCallResult;
use super::ValueAggregate;
use crate::execution_step::RSecurityTetraplet;
use crate::JValue;
@ -74,7 +74,7 @@ impl IterableItem<'_> {
*pos
}
pub(crate) fn into_resolved_result(self) -> ResolvedCallResult {
pub(crate) fn into_resolved_result(self) -> ValueAggregate {
use IterableItem::*;
let (value, tetraplet, pos) = match self {
@ -83,7 +83,7 @@ impl IterableItem<'_> {
RcValue(ingredients) => ingredients,
};
ResolvedCallResult::new(value, tetraplet, pos)
ValueAggregate::new(value, tetraplet, pos)
}
}

View File

@ -16,7 +16,7 @@
use super::Iterable;
use super::IterableItem;
use super::ResolvedCallResult;
use super::ValueAggregate;
use crate::foldable_next;
use crate::foldable_prev;
use crate::JValue;
@ -26,13 +26,13 @@ use std::ops::Deref;
/// Used for iterating over JValue of array type.
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct IterableResolvedCall {
pub(crate) call_result: ResolvedCallResult,
pub(crate) call_result: ValueAggregate,
pub(crate) cursor: usize,
pub(crate) len: usize,
}
impl IterableResolvedCall {
pub(crate) fn init(call_result: ResolvedCallResult, len: usize) -> Self {
pub(crate) fn init(call_result: ValueAggregate, len: usize) -> Self {
Self {
call_result,
cursor: 0,
@ -57,7 +57,7 @@ impl<'ctx> Iterable<'ctx> for IterableResolvedCall {
return None;
}
let ResolvedCallResult {
let ValueAggregate {
result,
tetraplet,
trace_pos,

View File

@ -16,19 +16,19 @@
use super::Iterable;
use super::IterableItem;
use super::ResolvedCallResult;
use super::ValueAggregate;
use crate::foldable_next;
use crate::foldable_prev;
/// Used for iterating over stream with JValues.
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct IterableVecResolvedCall {
pub(crate) call_results: Vec<ResolvedCallResult>,
pub(crate) call_results: Vec<ValueAggregate>,
pub(crate) cursor: usize,
}
impl IterableVecResolvedCall {
pub(crate) fn init(call_results: Vec<ResolvedCallResult>) -> Self {
pub(crate) fn init(call_results: Vec<ValueAggregate>) -> Self {
Self {
call_results,
cursor: 0,
@ -52,7 +52,7 @@ impl<'ctx> Iterable<'ctx> for IterableVecResolvedCall {
return None;
}
let ResolvedCallResult {
let ValueAggregate {
result,
tetraplet,
trace_pos,

View File

@ -23,7 +23,7 @@ mod stream;
use super::iterable::IterableItem;
use super::ExecutionError;
use super::ExecutionResult;
use super::ResolvedCallResult;
use super::ValueAggregate;
use crate::execution_step::lambda_applier::*;
use crate::execution_step::SecurityTetraplets;
use crate::JValue;

View File

@ -17,7 +17,7 @@
use super::select_from_stream;
use super::ExecutionResult;
use super::JValuable;
use super::ResolvedCallResult;
use super::ValueAggregate;
use crate::execution_step::SecurityTetraplets;
use crate::JValue;
use crate::LambdaAST;
@ -27,7 +27,7 @@ use air_lambda_ast::format_ast;
use std::borrow::Cow;
use std::ops::Deref;
impl JValuable for std::cell::Ref<'_, Vec<ResolvedCallResult>> {
impl JValuable for std::cell::Ref<'_, Vec<ValueAggregate>> {
fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<Vec<&JValue>> {
let stream_iter = self.iter().map(|r| r.result.deref());
let select_result = select_from_stream(stream_iter, lambda)?;

View File

@ -18,7 +18,7 @@ use super::select;
use super::ExecutionResult;
use super::JValuable;
use super::LambdaAST;
use super::ResolvedCallResult;
use super::ValueAggregate;
use crate::execution_step::SecurityTetraplets;
use crate::JValue;
@ -27,7 +27,7 @@ use air_lambda_ast::format_ast;
use std::borrow::Cow;
use std::ops::Deref;
impl JValuable for ResolvedCallResult {
impl JValuable for ValueAggregate {
fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<Vec<&JValue>> {
let selected_value = select(&self.result, lambda.iter())?;
Ok(vec![selected_value])

View File

@ -23,8 +23,8 @@ mod variable;
pub(crate) use super::ExecutionError;
pub(crate) use iterable::*;
pub(crate) use jvaluable::*;
pub(crate) use scalar::ResolvedCallResult;
pub(crate) use scalar::Scalar;
pub(crate) use scalar::ScalarRef;
pub(crate) use scalar::ValueAggregate;
pub(crate) use stream::Generation;
pub(crate) use stream::Stream;
pub(crate) use stream::StreamIter;

View File

@ -27,22 +27,22 @@ use std::fmt::Formatter;
use std::rc::Rc;
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct ResolvedCallResult {
pub struct ValueAggregate {
pub result: Rc<JValue>,
pub tetraplet: RSecurityTetraplet,
pub trace_pos: usize,
}
pub(crate) enum Scalar<'i> {
JValueRef(ResolvedCallResult),
JValueFoldCursor(FoldState<'i>),
pub(crate) enum ScalarRef<'i> {
Value(&'i ValueAggregate),
IterableValue(&'i FoldState<'i>),
}
impl<'i> Scalar<'i> {
pub(crate) fn to_jvaluable<'ctx>(&'ctx self) -> Box<dyn JValuable + 'ctx> {
impl<'i> ScalarRef<'i> {
pub(crate) fn into_jvaluable(self) -> Box<dyn JValuable + 'i> {
match self {
Scalar::JValueRef(value) => Box::new(value.clone()),
Scalar::JValueFoldCursor(fold_state) => {
ScalarRef::Value(value) => Box::new(value.clone()),
ScalarRef::IterableValue(fold_state) => {
let peeked_value = fold_state.iterable.peek().unwrap();
Box::new(peeked_value)
}
@ -50,7 +50,7 @@ impl<'i> Scalar<'i> {
}
}
impl ResolvedCallResult {
impl ValueAggregate {
pub(crate) fn new(result: Rc<JValue>, tetraplet: RSecurityTetraplet, trace_pos: usize) -> Self {
Self {
result,
@ -60,11 +60,11 @@ impl ResolvedCallResult {
}
}
impl<'i> Display for Scalar<'i> {
impl<'i> Display for ScalarRef<'i> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Scalar::JValueRef(value) => write!(f, "{:?}", value)?,
Scalar::JValueFoldCursor(cursor) => {
ScalarRef::Value(value) => write!(f, "{:?}", value)?,
ScalarRef::IterableValue(cursor) => {
let iterable = &cursor.iterable;
write!(f, "cursor, current value: {:?}", iterable.peek())?;
}

View File

@ -16,7 +16,7 @@
use super::ExecutionError;
use super::ExecutionResult;
use super::ResolvedCallResult;
use super::ValueAggregate;
use crate::exec_err;
use crate::JValue;
@ -31,20 +31,20 @@ use std::fmt::Formatter;
/// obtained values from a current_data that were not present in prev_data becomes a new generation.
// TODO: make it non-pub after boxed value refactoring.
#[derive(Debug, Default, Clone)]
pub(crate) struct Stream(Vec<Vec<ResolvedCallResult>>);
pub(crate) struct Stream(Vec<Vec<ValueAggregate>>);
impl Stream {
pub(crate) fn from_generations_count(count: usize) -> Self {
Self(vec![vec![]; count + 1])
}
pub(crate) fn from_value(value: ResolvedCallResult) -> Self {
pub(crate) fn from_value(value: ValueAggregate) -> Self {
Self(vec![vec![value]])
}
// if generation is None, value would be added to the last generation, otherwise it would
// be added to given generation
pub(crate) fn add_value(&mut self, value: ResolvedCallResult, generation: Generation) -> ExecutionResult<u32> {
pub(crate) fn add_value(&mut self, value: ValueAggregate, generation: Generation) -> ExecutionResult<u32> {
let generation = match generation {
Generation::Last => self.0.len() - 1,
Generation::Nth(id) => id as usize,
@ -95,7 +95,7 @@ impl Stream {
}
pub(crate) fn iter(&self, generation: Generation) -> Option<StreamIter<'_>> {
let iter: Box<dyn Iterator<Item = &ResolvedCallResult>> = match generation {
let iter: Box<dyn Iterator<Item = &ValueAggregate>> = match generation {
Generation::Nth(generation) if generation as usize >= self.generations_count() => return None,
Generation::Nth(generation) => Box::new(self.0.iter().take(generation as usize + 1).flat_map(|v| v.iter())),
Generation::Last => Box::new(self.0.iter().flat_map(|v| v.iter())),
@ -109,7 +109,7 @@ impl Stream {
}
pub(crate) fn slice_iter(&self, generation: Generation) -> Option<StreamSliceIter<'_>> {
let iter: Box<dyn Iterator<Item = &[ResolvedCallResult]>> = match generation {
let iter: Box<dyn Iterator<Item = &[ValueAggregate]>> = match generation {
Generation::Nth(generation) if generation as usize >= self.generations_count() => return None,
Generation::Nth(generation) => Box::new(self.0.iter().take(generation as usize + 1).map(|v| v.as_slice())),
Generation::Last => Box::new(self.0.iter().map(|v| v.as_slice())),
@ -142,12 +142,12 @@ impl Generation {
}
pub(crate) struct StreamIter<'result> {
iter: Box<dyn Iterator<Item = &'result ResolvedCallResult> + 'result>,
iter: Box<dyn Iterator<Item = &'result ValueAggregate> + 'result>,
len: usize,
}
impl<'result> Iterator for StreamIter<'result> {
type Item = &'result ResolvedCallResult;
type Item = &'result ValueAggregate;
fn next(&mut self) -> Option<Self::Item> {
if self.len > 0 {
@ -164,12 +164,12 @@ impl<'result> Iterator for StreamIter<'result> {
impl<'result> ExactSizeIterator for StreamIter<'result> {}
pub(crate) struct StreamSliceIter<'slice> {
iter: Box<dyn Iterator<Item = &'slice [ResolvedCallResult]> + 'slice>,
iter: Box<dyn Iterator<Item = &'slice [ValueAggregate]> + 'slice>,
len: usize,
}
impl<'slice> Iterator for StreamSliceIter<'slice> {
type Item = &'slice [ResolvedCallResult];
type Item = &'slice [ValueAggregate];
fn next(&mut self) -> Option<Self::Item> {
if self.len > 0 {

View File

@ -62,21 +62,17 @@ pub(crate) enum ExecutionError {
#[error("lambda is applied to an empty stream")]
EmptyStreamLambdaError,
/// Provided JValue has incompatible with target type.
/// Provided JValue has incompatible type with a requested one.
#[error("expected JValue type '{1}', but got '{0}' JValue")]
IncompatibleJValueType(JValue, &'static str),
/// Provided AValue has incompatible with target type.
#[error("expected AValue type '{1}', but got '{0}' AValue")]
IncompatibleAValueType(String, String),
/// Fold state wasn't found for such iterator name.
#[error("fold state not found for this iterable '{0}'")]
FoldStateNotFound(String),
/// Multiple fold states found for such iterator name.
#[error("multiple fold states found for iterable '{0}'")]
MultipleFoldStates(String),
#[error("multiple iterable values found for iterable name '{0}'")]
MultipleIterableValues(String),
/// A fold instruction must iterate over array value.
#[error("lambda '{1}' returned non-array value '{0}' for fold instruction")]

View File

@ -16,7 +16,7 @@
use super::LastErrorDescriptor;
use super::LastErrorWithTetraplet;
use crate::execution_step::boxed_value::Scalar;
use super::Scalars;
use crate::execution_step::boxed_value::Stream;
use air_execution_info_collector::InstructionTracker;
@ -24,36 +24,34 @@ use air_interpreter_interface::*;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::rc::Rc;
/// Contains all necessary state needed to execute AIR script.
#[derive(Default)]
pub(crate) struct ExecutionCtx<'i> {
/// Contains all scalars.
// TODO: use shared string (Rc<String>) to avoid copying.
pub scalars: HashMap<String, Scalar<'i>>,
pub(crate) scalars: Scalars<'i>,
/// Contains all streams.
// TODO: use shared string (Rc<String>) to avoid copying.
pub streams: HashMap<String, RefCell<Stream>>,
pub(crate) streams: HashMap<String, RefCell<Stream>>,
/// Set of peer public keys that should receive resulted data.
pub next_peer_pks: Vec<String>,
pub(crate) next_peer_pks: Vec<String>,
/// PeerId of a peer executing this AIR script at the moment.
pub current_peer_id: Rc<String>,
pub(crate) current_peer_id: Rc<String>,
/// PeerId of a peer send this AIR script.
pub init_peer_id: String,
pub(crate) init_peer_id: String,
/// Last error produced by local service.
/// None means that there weren't any error.
pub last_error: Option<LastErrorDescriptor>,
pub(crate) last_error: Option<LastErrorDescriptor>,
/// True, if last error could be set. This flag is used to distinguish
/// whether an error is being bubbled up from the bottom or just encountered.
pub last_error_could_be_set: bool,
pub(crate) last_error_could_be_set: bool,
/// Indicates that previous executed subtree is complete.
/// A subtree treats as a complete if all subtree elements satisfy the following rules:
@ -61,22 +59,19 @@ pub(crate) struct ExecutionCtx<'i> {
/// - at least one of xor subtrees is completed without an error
/// - all of seq subtrees are completed
/// - call executed successfully (executed state is Executed)
pub subtree_complete: bool,
/// List of met folds used to determine whether a variable can be shadowed.
pub met_folds: VecDeque<&'i str>,
pub(crate) subtree_complete: bool,
/// Tracker of all met instructions.
pub tracker: InstructionTracker,
pub(crate) tracker: InstructionTracker,
/// Last call request id that was used as an id for call request in outcome.
pub last_call_request_id: u32,
pub(crate) last_call_request_id: u32,
/// Contains all executed results from a host side.
pub call_results: CallResults,
pub(crate) call_results: CallResults,
/// Tracks all functions that should be called from services.
pub call_requests: CallRequests,
pub(crate) call_requests: CallRequests,
}
impl<'i> ExecutionCtx<'i> {
@ -117,10 +112,14 @@ use std::fmt::Formatter;
impl<'i> Display for ExecutionCtx<'i> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "data cache:")?;
for (key, value) in self.scalars.iter() {
writeln!(f, " {} => {}", key, value)?;
writeln!(f, "scalars:")?;
writeln!(f, " {}", self.scalars)?;
writeln!(f, "streams:")?;
for (name, stream) in self.streams.iter() {
writeln!(f, " {} => {}", name, stream.borrow())?;
}
writeln!(f, "current peer id: {}", self.current_peer_id)?;
writeln!(f, "subtree complete: {}", self.subtree_complete)?;
writeln!(f, "next peer public keys: {:?}", self.next_peer_pks)?;

View File

@ -16,8 +16,10 @@
mod context;
mod error_descriptor;
mod scalar_variables;
pub(crate) use context::*;
pub use error_descriptor::LastError;
pub(crate) use error_descriptor::LastErrorDescriptor;
pub(crate) use error_descriptor::LastErrorWithTetraplet;
pub(crate) use scalar_variables::*;

View File

@ -0,0 +1,229 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::exec_err;
use crate::execution_step::boxed_value::ScalarRef;
use crate::execution_step::ExecutionError;
use crate::execution_step::ExecutionResult;
use crate::execution_step::FoldState;
use crate::execution_step::ValueAggregate;
use std::collections::HashMap;
use std::rc::Rc;
/// There are two scopes for variable scalars in AIR: global and local. A local scope
/// is a scope inside every fold block, other scope is a global. It means that scalar
/// in an upper fold block could be shadowed by a scalar with the same name in a lower
/// fold block, it works "as expected". Let's consider the following example:
/// (seq
/// (seq
/// (call ... local) ;; (1)
/// (fold iterable_1 iterator_1
/// (seq
/// (seq
/// (seq
/// (call ... local) ;; (2)
/// (fold iterable_2 iterator_2
/// (seq
/// (seq
/// (call ... local) ;; (3)
/// (call ... [local]) ;; local set by (3) will be used
/// )
/// (next iterator_2)
/// )
/// )
/// )
/// (call ... [local]) ;; local set by (2) will be used
/// )
/// (next iterator_1)
/// )
/// )
/// )
/// (seq
/// (call ... [local]) ;; local set by (1) will be used
/// (call ... local) ;; error will be occurred because, it's impossible to set variable twice
/// ;; in a global scope
/// )
/// )
///
/// Although there could be only one iterable value for a fold block, because of CRDT rules.
/// This struct is intended to provide abilities to work with scalars as it was described.
#[derive(Default)]
pub(crate) struct Scalars<'i> {
// this one is optimized for speed (not for memory), because it's unexpected
// that a script could have a lot of inner folds.
pub values: HashMap<String, Vec<Option<ValueAggregate>>>,
pub iterable_values: HashMap<String, FoldState<'i>>,
pub fold_block_id: usize,
}
#[allow(dead_code)]
impl<'i> Scalars<'i> {
/// Returns true if there was a previous value for the provided key on the same
/// fold block.
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.values.entry(name.into()) {
Vacant(entry) => {
let mut values = vec![None; self.fold_block_id];
values.push(Some(value));
entry.insert(values);
Ok(false)
}
Occupied(entry) => {
if !shadowing_allowed {
return exec_err!(ExecutionError::MultipleVariablesFound(entry.key().clone()));
}
let values = entry.into_mut();
let contains_prev_value = values
.get(self.fold_block_id)
.map_or_else(|| false, |value| value.is_none());
// could be considered as lazy erasing
values.resize(self.fold_block_id + 1, None);
values[self.fold_block_id] = Some(value);
Ok(contains_prev_value)
}
}
}
pub(crate) fn set_iterable_value(
&mut self,
name: impl Into<String>,
fold_state: FoldState<'i>,
) -> ExecutionResult<()> {
use std::collections::hash_map::Entry::{Occupied, Vacant};
match self.iterable_values.entry(name.into()) {
Vacant(entry) => {
entry.insert(fold_state);
Ok(())
}
Occupied(entry) => {
exec_err!(ExecutionError::MultipleIterableValues(entry.key().clone()))
}
}
}
pub(crate) fn remove_value(&mut self, name: &str) {
self.values.remove(name);
}
pub(crate) fn remove_iterable_value(&mut self, name: &str) {
self.iterable_values.remove(name);
}
pub(crate) fn get_value(&'i self, name: &str) -> ExecutionResult<&'i ValueAggregate> {
self.values
.get(name)
.and_then(|scalars| {
scalars
.iter()
.take(self.fold_block_id + 1)
.rev()
.find_map(|scalar| scalar.as_ref())
})
.ok_or_else(|| Rc::new(ExecutionError::VariableNotFound(name.to_string())))
}
pub(crate) fn get_value_mut(&'i mut self, name: &str) -> ExecutionResult<&'i mut ValueAggregate> {
let fold_block_id = self.fold_block_id;
self.values
.get_mut(name)
.and_then(|scalars| {
scalars
.iter_mut()
.take(fold_block_id)
.rev()
.find_map(|scalar| scalar.as_mut())
})
.ok_or_else(|| Rc::new(ExecutionError::VariableNotFound(name.to_string())))
}
pub(crate) fn get_iterable(&self, name: &str) -> ExecutionResult<&FoldState<'i>> {
self.iterable_values
.get(name)
.ok_or_else(|| Rc::new(ExecutionError::FoldStateNotFound(name.to_string())))
}
pub(crate) fn get_iterable_mut(&mut self, name: &str) -> ExecutionResult<&mut FoldState<'i>> {
self.iterable_values
.get_mut(name)
.ok_or_else(|| Rc::new(ExecutionError::FoldStateNotFound(name.to_string())))
}
pub(crate) fn get(&'i self, name: &str) -> ExecutionResult<ScalarRef<'i>> {
let value = self.get_value(name);
let iterable_value = self.iterable_values.get(name);
match (value, iterable_value) {
(Err(_), None) => exec_err!(ExecutionError::VariableNotFound(name.to_string())),
(Ok(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"),
}
}
pub(crate) fn meet_fold_begin(&mut self) {
self.fold_block_id += 1;
}
pub(crate) fn meet_fold_end(&mut self) {
self.fold_block_id -= 1;
if self.fold_block_id == 0 {
// lazy cleanup after exiting from a top fold block to the global scope
self.cleanup()
}
}
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
self.fold_block_id != 0
}
fn cleanup(&mut self) {
for (_, scalars) in self.values.iter_mut() {
scalars.truncate(self.fold_block_id + 1)
}
}
}
use std::fmt;
impl<'i> fmt::Display for Scalars<'i> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "fold_block_id: {}", self.fold_block_id)?;
for (name, _) in self.values.iter() {
let value = self.get_value(name);
if let Ok(last_value) = value {
writeln!(f, "{} => {}", name, last_value.result)?;
}
}
for (name, _) in self.iterable_values.iter() {
// it's impossible to print an iterable value for now
writeln!(f, "{} => iterable", name)?;
}
Ok(())
}
}

View File

@ -24,9 +24,9 @@ mod utils;
pub(super) use self::air::ExecutableInstruction;
pub(super) use self::air::FoldState;
pub(super) use boxed_value::Generation;
pub(super) use boxed_value::ResolvedCallResult;
pub(super) use boxed_value::Scalar;
pub(super) use boxed_value::ScalarRef;
pub(super) use boxed_value::Stream;
pub(super) use boxed_value::ValueAggregate;
pub(crate) use errors::Catchable;
pub(super) use errors::ExecutionError;
pub(crate) use errors::Joinable;

View File

@ -19,7 +19,6 @@ use crate::execution_step::boxed_value::JValuable;
use crate::execution_step::boxed_value::Variable;
use crate::execution_step::execution_context::ExecutionCtx;
use crate::execution_step::execution_context::LastErrorWithTetraplet;
use crate::execution_step::ExecutionError;
use crate::execution_step::ExecutionResult;
use crate::JValue;
use crate::LambdaAST;
@ -105,7 +104,7 @@ pub(crate) fn resolve_variable<'ctx, 'i>(
use crate::execution_step::boxed_value::StreamJvaluableIngredients;
match variable {
Variable::Scalar(name) => scalar_to_jvaluable(name, ctx),
Variable::Scalar(name) => Ok(ctx.scalars.get(name)?.into_jvaluable()),
Variable::Stream { name, generation } => {
match ctx.streams.get(name) {
Some(stream) => {
@ -139,18 +138,3 @@ pub(crate) fn apply_lambda<'i>(
// it's known that apply_lambda_with_tetraplets returns vec of one value
Ok((jvalue[0].clone(), tetraplets))
}
/// Constructs jvaluable result from scalars by name.
fn scalar_to_jvaluable<'name, 'i, 'ctx>(
name: &'name str,
ctx: &'ctx ExecutionCtx<'i>,
) -> ExecutionResult<Box<dyn JValuable + 'ctx>> {
use ExecutionError::VariableNotFound;
let value = ctx
.scalars
.get(name)
.ok_or_else(|| VariableNotFound(name.to_string()))?;
Ok(value.to_jvaluable())
}

View File

@ -157,7 +157,7 @@ fn inner_fold_with_same_iterator() {
let result = call_vm!(vm, "", script, "", "");
assert_eq!(result.ret_code, 1009);
assert_eq!(result.ret_code, 1008);
}
#[test]

View File

@ -192,11 +192,11 @@ fn match_without_xor() {
let result = call_vm!(set_variable_vm, "", &script, "", "");
let result = call_vm!(vm, "", &script, "", result.data);
assert_eq!(result.ret_code, 1012);
assert_eq!(result.ret_code, 1011);
let result = call_vm!(vm, "", script, "", result.data);
assert_eq!(result.ret_code, 1012);
assert_eq!(result.ret_code, 1011);
}
#[test]

View File

@ -143,11 +143,11 @@ fn mismatch_without_xor() {
let result = call_vm!(set_variable_vm, "asd", &script, "", "");
let result = call_vm!(vm, "asd", &script, "", result.data);
assert_eq!(result.ret_code, 1013);
assert_eq!(result.ret_code, 1012);
let result = call_vm!(vm, "asd", script, "", result.data);
assert_eq!(result.ret_code, 1013);
assert_eq!(result.ret_code, 1012);
}
#[test]

View File

@ -140,7 +140,7 @@ fn par_early_exit() {
];
let setter_3_malicious_data = raw_data_from_trace(setter_3_malicious_trace);
let init_result_3 = call_vm!(init, "", &script, init_result_2.data.clone(), setter_3_malicious_data);
assert_eq!(init_result_3.ret_code, 1014);
assert_eq!(init_result_3.ret_code, 1013);
let actual_trace = trace_from_result(&init_result_3);
let expected_trace = trace_from_result(&init_result_2);