mirror of
https://github.com/fluencelabs/aquavm
synced 2024-12-04 23:20:18 +00:00
Improve the scalars storing scheme (#162)
This commit is contained in:
parent
1c55d34981
commit
18f4c0036f
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -291,9 +291,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.7.1"
|
version = "3.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
|
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
@ -935,9 +935,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.11"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
@ -1074,9 +1074,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.103"
|
version = "0.2.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
|
@ -17,12 +17,11 @@
|
|||||||
mod apply_to_arguments;
|
mod apply_to_arguments;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use super::call::call_result_setter::set_scalar_result;
|
|
||||||
use super::call::call_result_setter::set_stream_result;
|
use super::call::call_result_setter::set_stream_result;
|
||||||
use super::ExecutionCtx;
|
use super::ExecutionCtx;
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::TraceHandler;
|
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::boxed_value::Variable;
|
||||||
use crate::execution_step::utils::apply_lambda;
|
use crate::execution_step::utils::apply_lambda;
|
||||||
use crate::trace_to_exec_err;
|
use crate::trace_to_exec_err;
|
||||||
@ -69,11 +68,11 @@ impl<'i> super::ExecutableInstruction<'i> for Ap<'i> {
|
|||||||
fn save_result<'ctx>(
|
fn save_result<'ctx>(
|
||||||
ap_result_type: &AstVariable<'ctx>,
|
ap_result_type: &AstVariable<'ctx>,
|
||||||
merger_ap_result: &MergerApResult,
|
merger_ap_result: &MergerApResult,
|
||||||
result: ResolvedCallResult,
|
result: ValueAggregate,
|
||||||
exec_ctx: &mut ExecutionCtx<'ctx>,
|
exec_ctx: &mut ExecutionCtx<'ctx>,
|
||||||
) -> ExecutionResult<()> {
|
) -> ExecutionResult<()> {
|
||||||
match ap_result_type {
|
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) => {
|
AstVariable::Stream(name) => {
|
||||||
let generation = ap_result_to_generation(merger_ap_result);
|
let generation = ap_result_to_generation(merger_ap_result);
|
||||||
set_stream_result(result, generation, name.to_string(), exec_ctx).map(|_| ())
|
set_stream_result(result, generation, name.to_string(), exec_ctx).map(|_| ())
|
||||||
|
@ -21,7 +21,7 @@ pub(super) fn apply_to_arg(
|
|||||||
exec_ctx: &ExecutionCtx<'_>,
|
exec_ctx: &ExecutionCtx<'_>,
|
||||||
trace_ctx: &TraceHandler,
|
trace_ctx: &TraceHandler,
|
||||||
should_touch_trace: bool,
|
should_touch_trace: bool,
|
||||||
) -> ExecutionResult<ResolvedCallResult> {
|
) -> ExecutionResult<ValueAggregate> {
|
||||||
let result = match argument {
|
let result = match argument {
|
||||||
ApArgument::ScalarVariable(scalar_name) => apply_scalar(scalar_name, exec_ctx, trace_ctx, should_touch_trace)?,
|
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)?,
|
ApArgument::VariableWithLambda(vl) => apply_json_argument(vl, exec_ctx, trace_ctx)?,
|
||||||
@ -40,18 +40,14 @@ fn apply_scalar(
|
|||||||
exec_ctx: &ExecutionCtx<'_>,
|
exec_ctx: &ExecutionCtx<'_>,
|
||||||
trace_ctx: &TraceHandler,
|
trace_ctx: &TraceHandler,
|
||||||
should_touch_trace: bool,
|
should_touch_trace: bool,
|
||||||
) -> ExecutionResult<ResolvedCallResult> {
|
) -> ExecutionResult<ValueAggregate> {
|
||||||
use crate::execution_step::ExecutionError::VariableNotFound;
|
use crate::execution_step::ScalarRef;
|
||||||
use crate::execution_step::Scalar;
|
|
||||||
|
|
||||||
let scalar = exec_ctx
|
let scalar = exec_ctx.scalars.get(scalar_name)?;
|
||||||
.scalars
|
|
||||||
.get(scalar_name)
|
|
||||||
.ok_or_else(|| VariableNotFound(scalar_name.to_string()))?;
|
|
||||||
|
|
||||||
let mut result = match scalar {
|
let mut result = match scalar {
|
||||||
Scalar::JValueRef(result) => result.clone(),
|
ScalarRef::Value(result) => result.clone(),
|
||||||
Scalar::JValueFoldCursor(iterator) => {
|
ScalarRef::IterableValue(iterator) => {
|
||||||
let result = iterator.iterable.peek().expect(
|
let result = iterator.iterable.peek().expect(
|
||||||
"peek always return elements inside fold,\
|
"peek always return elements inside fold,\
|
||||||
this guaranteed by implementation of next and avoiding empty folds",
|
this guaranteed by implementation of next and avoiding empty folds",
|
||||||
@ -67,24 +63,24 @@ fn apply_scalar(
|
|||||||
Ok(result)
|
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 value = Rc::new(value.into());
|
||||||
let tetraplet = SecurityTetraplet::literal_tetraplet(exec_ctx.init_peer_id.clone());
|
let tetraplet = SecurityTetraplet::literal_tetraplet(exec_ctx.init_peer_id.clone());
|
||||||
let tetraplet = Rc::new(RefCell::new(tetraplet));
|
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(
|
fn apply_last_error(
|
||||||
error_path: &LastErrorPath,
|
error_path: &LastErrorPath,
|
||||||
exec_ctx: &ExecutionCtx<'_>,
|
exec_ctx: &ExecutionCtx<'_>,
|
||||||
trace_ctx: &TraceHandler,
|
trace_ctx: &TraceHandler,
|
||||||
) -> ExecutionResult<ResolvedCallResult> {
|
) -> ExecutionResult<ValueAggregate> {
|
||||||
let (value, mut tetraplets) = crate::execution_step::utils::prepare_last_error(error_path, exec_ctx)?;
|
let (value, mut tetraplets) = crate::execution_step::utils::prepare_last_error(error_path, exec_ctx)?;
|
||||||
let value = Rc::new(value);
|
let value = Rc::new(value);
|
||||||
let tetraplet = tetraplets.remove(0);
|
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)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +88,14 @@ fn apply_json_argument(
|
|||||||
vl: &VariableWithLambda<'_>,
|
vl: &VariableWithLambda<'_>,
|
||||||
exec_ctx: &ExecutionCtx<'_>,
|
exec_ctx: &ExecutionCtx<'_>,
|
||||||
trace_ctx: &TraceHandler,
|
trace_ctx: &TraceHandler,
|
||||||
) -> ExecutionResult<ResolvedCallResult> {
|
) -> ExecutionResult<ValueAggregate> {
|
||||||
let variable = Variable::from_ast(&vl.variable);
|
let variable = Variable::from_ast(&vl.variable);
|
||||||
let (jvalue, mut tetraplets) = apply_lambda(variable, &vl.lambda, exec_ctx)?;
|
let (jvalue, mut tetraplets) = apply_lambda(variable, &vl.lambda, exec_ctx)?;
|
||||||
|
|
||||||
let tetraplet = tetraplets
|
let tetraplet = tetraplets
|
||||||
.pop()
|
.pop()
|
||||||
.unwrap_or_else(|| Rc::new(RefCell::new(SecurityTetraplet::default())));
|
.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)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::exec_err;
|
|
||||||
use crate::execution_step::execution_context::*;
|
use crate::execution_step::execution_context::*;
|
||||||
use crate::execution_step::AstVariable;
|
use crate::execution_step::AstVariable;
|
||||||
use crate::execution_step::Generation;
|
use crate::execution_step::Generation;
|
||||||
use crate::execution_step::ResolvedCallResult;
|
|
||||||
use crate::execution_step::Scalar;
|
|
||||||
use crate::execution_step::Stream;
|
use crate::execution_step::Stream;
|
||||||
|
use crate::execution_step::ValueAggregate;
|
||||||
|
|
||||||
use air_interpreter_data::CallResult;
|
use air_interpreter_data::CallResult;
|
||||||
use air_interpreter_data::Value;
|
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`.
|
/// Writes result of a local `Call` instruction to `ExecutionCtx` at `output`.
|
||||||
/// Returns call result.
|
/// Returns call result.
|
||||||
pub(crate) fn set_local_result<'i>(
|
pub(crate) fn set_local_result<'i>(
|
||||||
executed_result: ResolvedCallResult,
|
executed_result: ValueAggregate,
|
||||||
output: &CallOutputValue<'i>,
|
output: &CallOutputValue<'i>,
|
||||||
exec_ctx: &mut ExecutionCtx<'i>,
|
exec_ctx: &mut ExecutionCtx<'i>,
|
||||||
) -> ExecutionResult<CallResult> {
|
) -> ExecutionResult<CallResult> {
|
||||||
let result_value = executed_result.result.clone();
|
let result_value = executed_result.result.clone();
|
||||||
match output {
|
match output {
|
||||||
CallOutputValue::Variable(AstVariable::Scalar(name)) => {
|
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))
|
Ok(CallResult::executed_scalar(result_value))
|
||||||
}
|
}
|
||||||
CallOutputValue::Variable(AstVariable::Stream(name)) => {
|
CallOutputValue::Variable(AstVariable::Stream(name)) => {
|
||||||
@ -67,11 +65,11 @@ pub(crate) fn set_result_from_value<'i>(
|
|||||||
) -> ExecutionResult<()> {
|
) -> ExecutionResult<()> {
|
||||||
match (output, value) {
|
match (output, value) {
|
||||||
(CallOutputValue::Variable(AstVariable::Scalar(name)), Value::Scalar(value)) => {
|
(CallOutputValue::Variable(AstVariable::Scalar(name)), Value::Scalar(value)) => {
|
||||||
let result = ResolvedCallResult::new(value, tetraplet, trace_pos);
|
let result = ValueAggregate::new(value, tetraplet, trace_pos);
|
||||||
set_scalar_result(result, name, exec_ctx)?;
|
exec_ctx.scalars.set_value(*name, result)?;
|
||||||
}
|
}
|
||||||
(CallOutputValue::Variable(AstVariable::Stream(name)), Value::Stream { value, generation }) => {
|
(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 generation = Generation::Nth(generation);
|
||||||
let _ = set_stream_result(result, generation, name.to_string(), exec_ctx)?;
|
let _ = set_stream_result(result, generation, name.to_string(), exec_ctx)?;
|
||||||
}
|
}
|
||||||
@ -83,68 +81,9 @@ pub(crate) fn set_result_from_value<'i>(
|
|||||||
Ok(())
|
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
|
// TODO: decouple this function to a separate module
|
||||||
pub(crate) fn set_stream_result(
|
pub(crate) fn set_stream_result(
|
||||||
executed_result: ResolvedCallResult,
|
executed_result: ValueAggregate,
|
||||||
generation: Generation,
|
generation: Generation,
|
||||||
stream_name: String,
|
stream_name: String,
|
||||||
exec_ctx: &mut ExecutionCtx<'_>,
|
exec_ctx: &mut ExecutionCtx<'_>,
|
||||||
|
@ -85,7 +85,7 @@ pub(super) fn handle_prev_state<'i>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
use super::call_result_setter::*;
|
use super::call_result_setter::*;
|
||||||
use crate::execution_step::ResolvedCallResult;
|
use crate::execution_step::ValueAggregate;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
|
|
||||||
fn update_state_with_service_result<'i>(
|
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 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)?;
|
let new_call_result = set_local_result(executed_result, output, exec_ctx)?;
|
||||||
trace_ctx.meet_call_end(new_call_result);
|
trace_ctx.meet_call_end(new_call_result);
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ impl<'i> ResolvedCall<'i> {
|
|||||||
/// Check output type name for being already in execution context.
|
/// Check output type name for being already in execution context.
|
||||||
// TODO: this check should be moved on a parsing stage
|
// TODO: this check should be moved on a parsing stage
|
||||||
fn check_output_name(output: &CallOutputValue<'_>, exec_ctx: &ExecutionCtx<'_>) -> ExecutionResult<()> {
|
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 {
|
let scalar_name = match output {
|
||||||
CallOutputValue::Variable(AstVariable::Scalar(name)) => *name,
|
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) {
|
match exec_ctx.scalars.get(scalar_name) {
|
||||||
Some(Scalar::JValueRef(_)) => {
|
Ok(ScalarRef::Value(_)) => {
|
||||||
if exec_ctx.met_folds.is_empty() {
|
if exec_ctx.scalars.shadowing_allowed() {
|
||||||
// shadowing is allowed only inside fold blocks
|
|
||||||
crate::exec_err!(ExecutionError::MultipleVariablesFound(scalar_name.to_string()))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
crate::exec_err!(ExecutionError::MultipleVariablesFound(scalar_name.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(_) => crate::exec_err!(ExecutionError::IterableShadowing(scalar_name.to_string())),
|
Ok(ScalarRef::IterableValue(_)) => crate::exec_err!(ExecutionError::IterableShadowing(scalar_name.to_string())),
|
||||||
None => Ok(()),
|
Err(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,17 +16,13 @@
|
|||||||
|
|
||||||
use super::Instruction;
|
use super::Instruction;
|
||||||
use super::IterableValue;
|
use super::IterableValue;
|
||||||
use super::ResolvedCallResult;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub(crate) struct FoldState<'i> {
|
pub(crate) struct FoldState<'i> {
|
||||||
pub(crate) iterable: IterableValue,
|
pub(crate) iterable: IterableValue,
|
||||||
pub(crate) iterable_type: IterableType,
|
pub(crate) iterable_type: IterableType,
|
||||||
pub(crate) instr_head: Rc<Instruction<'i>>,
|
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)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -45,7 +41,6 @@ impl<'i> FoldState<'i> {
|
|||||||
iterable,
|
iterable,
|
||||||
iterable_type,
|
iterable_type,
|
||||||
instr_head,
|
instr_head,
|
||||||
met_variables: HashMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,17 +16,15 @@
|
|||||||
|
|
||||||
mod fold_state;
|
mod fold_state;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod variable_handler;
|
|
||||||
|
|
||||||
pub(crate) use fold_state::FoldState;
|
pub(crate) use fold_state::FoldState;
|
||||||
pub(crate) use fold_state::IterableType;
|
pub(crate) use fold_state::IterableType;
|
||||||
pub(super) use utils::*;
|
pub(super) use utils::*;
|
||||||
pub(super) use variable_handler::VariableHandler;
|
|
||||||
|
|
||||||
use super::ExecutionCtx;
|
use super::ExecutionCtx;
|
||||||
use super::ExecutionError;
|
use super::ExecutionError;
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::Instruction;
|
use super::Instruction;
|
||||||
use super::ResolvedCallResult;
|
use super::ScalarRef;
|
||||||
use super::Scalar;
|
use super::ValueAggregate;
|
||||||
use crate::execution_step::boxed_value::*;
|
use crate::execution_step::boxed_value::*;
|
||||||
|
@ -88,19 +88,18 @@ fn create_scalar_iterable<'ctx>(
|
|||||||
exec_ctx: &ExecutionCtx<'ctx>,
|
exec_ctx: &ExecutionCtx<'ctx>,
|
||||||
variable_name: &str,
|
variable_name: &str,
|
||||||
) -> ExecutionResult<FoldIterableScalar> {
|
) -> ExecutionResult<FoldIterableScalar> {
|
||||||
match exec_ctx.scalars.get(variable_name) {
|
match exec_ctx.scalars.get(variable_name)? {
|
||||||
Some(Scalar::JValueRef(call_result)) => from_call_result(call_result.clone()),
|
ScalarRef::Value(call_result) => from_call_result(call_result.clone()),
|
||||||
Some(Scalar::JValueFoldCursor(fold_state)) => {
|
ScalarRef::IterableValue(fold_state) => {
|
||||||
let iterable_value = fold_state.iterable.peek().unwrap();
|
let iterable_value = fold_state.iterable.peek().unwrap();
|
||||||
let call_result = iterable_value.into_resolved_result();
|
let call_result = iterable_value.into_resolved_result();
|
||||||
from_call_result(call_result)
|
from_call_result(call_result)
|
||||||
}
|
}
|
||||||
_ => return exec_err!(ExecutionError::VariableNotFound(variable_name.to_string())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs iterable value from resolved call result.
|
/// 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;
|
use ExecutionError::IncompatibleJValueType;
|
||||||
|
|
||||||
let len = match &call_result.result.deref() {
|
let len = match &call_result.result.deref() {
|
||||||
@ -128,19 +127,18 @@ fn create_scalar_lambda_iterable<'ctx>(
|
|||||||
) -> ExecutionResult<FoldIterableScalar> {
|
) -> ExecutionResult<FoldIterableScalar> {
|
||||||
use crate::execution_step::lambda_applier::select;
|
use crate::execution_step::lambda_applier::select;
|
||||||
|
|
||||||
match exec_ctx.scalars.get(scalar_name) {
|
match exec_ctx.scalars.get(scalar_name)? {
|
||||||
Some(Scalar::JValueRef(variable)) => {
|
ScalarRef::Value(variable) => {
|
||||||
let jvalues = select(&variable.result, lambda.iter())?;
|
let jvalues = select(&variable.result, lambda.iter())?;
|
||||||
from_jvalue(jvalues, variable.tetraplet.clone(), lambda)
|
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 iterable_value = fold_state.iterable.peek().unwrap();
|
||||||
let jvalues = iterable_value.apply_lambda(lambda)?;
|
let jvalues = iterable_value.apply_lambda(lambda)?;
|
||||||
let tetraplet = as_tetraplet(&iterable_value);
|
let tetraplet = as_tetraplet(&iterable_value);
|
||||||
|
|
||||||
from_jvalue(jvalues[0], tetraplet, lambda)
|
from_jvalue(jvalues[0], tetraplet, lambda)
|
||||||
}
|
}
|
||||||
_ => return exec_err!(ExecutionError::VariableNotFound(scalar_name.to_string())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,7 +29,9 @@ impl<'i> ExecutableInstruction<'i> for FoldScalar<'i> {
|
|||||||
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> {
|
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> {
|
||||||
log_instruction!(fold, exec_ctx, trace_ctx);
|
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::Empty => Ok(()),
|
||||||
FoldIterableScalar::Scalar(iterable) => fold(
|
FoldIterableScalar::Scalar(iterable) => fold(
|
||||||
iterable,
|
iterable,
|
||||||
@ -39,7 +41,11 @@ impl<'i> ExecutableInstruction<'i> for FoldScalar<'i> {
|
|||||||
exec_ctx,
|
exec_ctx,
|
||||||
trace_ctx,
|
trace_ctx,
|
||||||
),
|
),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
exec_ctx.scalars.meet_fold_end();
|
||||||
|
|
||||||
|
fold_result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,11 +58,11 @@ pub(super) fn fold<'i>(
|
|||||||
trace_ctx: &mut TraceHandler,
|
trace_ctx: &mut TraceHandler,
|
||||||
) -> ExecutionResult<()> {
|
) -> ExecutionResult<()> {
|
||||||
let fold_state = FoldState::from_iterable(iterable, iterable_type, instruction.clone());
|
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)?;
|
instruction.execute(exec_ctx, trace_ctx)?;
|
||||||
|
|
||||||
variable_handler.cleanup(exec_ctx);
|
exec_ctx.scalars.remove_iterable_value(iterator);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ impl<'i> ExecutableInstruction<'i> for FoldStream<'i> {
|
|||||||
|
|
||||||
let fold_id = exec_ctx.tracker.fold.seen_stream_count;
|
let fold_id = exec_ctx.tracker.fold.seen_stream_count;
|
||||||
trace_to_exec_err!(trace_ctx.meet_fold_start(fold_id))?;
|
trace_to_exec_err!(trace_ctx.meet_fold_start(fold_id))?;
|
||||||
|
exec_ctx.scalars.meet_fold_begin();
|
||||||
|
|
||||||
for iterable in iterables {
|
for iterable in iterables {
|
||||||
let value = match iterable.peek() {
|
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))?;
|
trace_to_exec_err!(trace_ctx.meet_fold_end(fold_id))?;
|
||||||
|
exec_ctx.scalars.meet_fold_end();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ mod xor;
|
|||||||
|
|
||||||
pub(crate) use fold::FoldState;
|
pub(crate) use fold::FoldState;
|
||||||
|
|
||||||
use super::boxed_value::ResolvedCallResult;
|
use super::boxed_value::ScalarRef;
|
||||||
use super::boxed_value::Scalar;
|
use super::boxed_value::ValueAggregate;
|
||||||
use super::execution_context::*;
|
use super::execution_context::*;
|
||||||
use super::Catchable;
|
use super::Catchable;
|
||||||
use super::ExecutionCtx;
|
use super::ExecutionCtx;
|
||||||
@ -147,12 +147,8 @@ macro_rules! log_instruction {
|
|||||||
log::debug!(target: air_log_targets::INSTRUCTION, "> {}", stringify!($instr_name));
|
log::debug!(target: air_log_targets::INSTRUCTION, "> {}", stringify!($instr_name));
|
||||||
|
|
||||||
let mut variables = String::from(" scalars:");
|
let mut variables = String::from(" scalars:");
|
||||||
if $exec_ctx.scalars.is_empty() {
|
|
||||||
variables.push_str(" empty");
|
variables.push_str(&format!("\n {}", $exec_ctx.scalars));
|
||||||
}
|
|
||||||
for (key, value) in $exec_ctx.scalars.iter() {
|
|
||||||
variables.push_str(&format!("\n {} => {}", key, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
variables.push_str(" streams:");
|
variables.push_str(" streams:");
|
||||||
if $exec_ctx.streams.is_empty() {
|
if $exec_ctx.streams.is_empty() {
|
||||||
|
@ -16,12 +16,9 @@
|
|||||||
|
|
||||||
use super::fold::IterableType;
|
use super::fold::IterableType;
|
||||||
use super::ExecutionCtx;
|
use super::ExecutionCtx;
|
||||||
use super::ExecutionError;
|
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::FoldState;
|
use super::FoldState;
|
||||||
use super::Scalar;
|
|
||||||
use super::TraceHandler;
|
use super::TraceHandler;
|
||||||
use crate::exec_err;
|
|
||||||
use crate::log_instruction;
|
use crate::log_instruction;
|
||||||
use crate::trace_to_exec_err;
|
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);
|
log_instruction!(next, exec_ctx, trace_ctx);
|
||||||
|
|
||||||
let iterator_name = self.0;
|
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)?;
|
maybe_meet_iteration_end(fold_state, trace_ctx)?;
|
||||||
|
|
||||||
if !fold_state.iterable.next() {
|
if !fold_state.iterable.next() {
|
||||||
@ -48,46 +45,14 @@ impl<'i> super::ExecutableInstruction<'i> for Next<'i> {
|
|||||||
next_instr.execute(exec_ctx, trace_ctx)?;
|
next_instr.execute(exec_ctx, trace_ctx)?;
|
||||||
|
|
||||||
// get the same fold state again because of borrow checker
|
// get the same fold state again because of borrow checker
|
||||||
match exec_ctx.scalars.get_mut(iterator_name) {
|
let fold_state = exec_ctx.scalars.get_iterable_mut(iterator_name)?;
|
||||||
// move iterator back to provide correct value for possible subtree after next
|
fold_state.iterable.prev();
|
||||||
// (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)?;
|
|
||||||
maybe_meet_back_iterator(fold_state, trace_ctx)?;
|
maybe_meet_back_iterator(fold_state, trace_ctx)?;
|
||||||
|
|
||||||
Ok(())
|
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<()> {
|
fn maybe_meet_iteration_start(fold_state: &FoldState<'_>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> {
|
||||||
if let IterableType::Stream(fold_id) = &fold_state.iterable_type {
|
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()))?;
|
trace_to_exec_err!(trace_ctx.meet_iteration_start(*fold_id, fold_state.iterable.peek().unwrap().pos()))?;
|
||||||
|
@ -23,7 +23,7 @@ pub(crate) use json_path_result::IterableLambdaResult;
|
|||||||
pub(crate) use resolved_call::IterableResolvedCall;
|
pub(crate) use resolved_call::IterableResolvedCall;
|
||||||
pub(crate) use vec_resolved_call::IterableVecResolvedCall;
|
pub(crate) use vec_resolved_call::IterableVecResolvedCall;
|
||||||
|
|
||||||
use super::ResolvedCallResult;
|
use super::ValueAggregate;
|
||||||
use crate::execution_step::RSecurityTetraplet;
|
use crate::execution_step::RSecurityTetraplet;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ impl IterableItem<'_> {
|
|||||||
*pos
|
*pos
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn into_resolved_result(self) -> ResolvedCallResult {
|
pub(crate) fn into_resolved_result(self) -> ValueAggregate {
|
||||||
use IterableItem::*;
|
use IterableItem::*;
|
||||||
|
|
||||||
let (value, tetraplet, pos) = match self {
|
let (value, tetraplet, pos) = match self {
|
||||||
@ -83,7 +83,7 @@ impl IterableItem<'_> {
|
|||||||
RcValue(ingredients) => ingredients,
|
RcValue(ingredients) => ingredients,
|
||||||
};
|
};
|
||||||
|
|
||||||
ResolvedCallResult::new(value, tetraplet, pos)
|
ValueAggregate::new(value, tetraplet, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use super::Iterable;
|
use super::Iterable;
|
||||||
use super::IterableItem;
|
use super::IterableItem;
|
||||||
use super::ResolvedCallResult;
|
use super::ValueAggregate;
|
||||||
use crate::foldable_next;
|
use crate::foldable_next;
|
||||||
use crate::foldable_prev;
|
use crate::foldable_prev;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
@ -26,13 +26,13 @@ use std::ops::Deref;
|
|||||||
/// Used for iterating over JValue of array type.
|
/// Used for iterating over JValue of array type.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) struct IterableResolvedCall {
|
pub(crate) struct IterableResolvedCall {
|
||||||
pub(crate) call_result: ResolvedCallResult,
|
pub(crate) call_result: ValueAggregate,
|
||||||
pub(crate) cursor: usize,
|
pub(crate) cursor: usize,
|
||||||
pub(crate) len: usize,
|
pub(crate) len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IterableResolvedCall {
|
impl IterableResolvedCall {
|
||||||
pub(crate) fn init(call_result: ResolvedCallResult, len: usize) -> Self {
|
pub(crate) fn init(call_result: ValueAggregate, len: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
call_result,
|
call_result,
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
@ -57,7 +57,7 @@ impl<'ctx> Iterable<'ctx> for IterableResolvedCall {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ResolvedCallResult {
|
let ValueAggregate {
|
||||||
result,
|
result,
|
||||||
tetraplet,
|
tetraplet,
|
||||||
trace_pos,
|
trace_pos,
|
||||||
|
@ -16,19 +16,19 @@
|
|||||||
|
|
||||||
use super::Iterable;
|
use super::Iterable;
|
||||||
use super::IterableItem;
|
use super::IterableItem;
|
||||||
use super::ResolvedCallResult;
|
use super::ValueAggregate;
|
||||||
use crate::foldable_next;
|
use crate::foldable_next;
|
||||||
use crate::foldable_prev;
|
use crate::foldable_prev;
|
||||||
|
|
||||||
/// Used for iterating over stream with JValues.
|
/// Used for iterating over stream with JValues.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) struct IterableVecResolvedCall {
|
pub(crate) struct IterableVecResolvedCall {
|
||||||
pub(crate) call_results: Vec<ResolvedCallResult>,
|
pub(crate) call_results: Vec<ValueAggregate>,
|
||||||
pub(crate) cursor: usize,
|
pub(crate) cursor: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IterableVecResolvedCall {
|
impl IterableVecResolvedCall {
|
||||||
pub(crate) fn init(call_results: Vec<ResolvedCallResult>) -> Self {
|
pub(crate) fn init(call_results: Vec<ValueAggregate>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
call_results,
|
call_results,
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
@ -52,7 +52,7 @@ impl<'ctx> Iterable<'ctx> for IterableVecResolvedCall {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ResolvedCallResult {
|
let ValueAggregate {
|
||||||
result,
|
result,
|
||||||
tetraplet,
|
tetraplet,
|
||||||
trace_pos,
|
trace_pos,
|
||||||
|
@ -23,7 +23,7 @@ mod stream;
|
|||||||
use super::iterable::IterableItem;
|
use super::iterable::IterableItem;
|
||||||
use super::ExecutionError;
|
use super::ExecutionError;
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::ResolvedCallResult;
|
use super::ValueAggregate;
|
||||||
use crate::execution_step::lambda_applier::*;
|
use crate::execution_step::lambda_applier::*;
|
||||||
use crate::execution_step::SecurityTetraplets;
|
use crate::execution_step::SecurityTetraplets;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
use super::select_from_stream;
|
use super::select_from_stream;
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::JValuable;
|
use super::JValuable;
|
||||||
use super::ResolvedCallResult;
|
use super::ValueAggregate;
|
||||||
use crate::execution_step::SecurityTetraplets;
|
use crate::execution_step::SecurityTetraplets;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
use crate::LambdaAST;
|
use crate::LambdaAST;
|
||||||
@ -27,7 +27,7 @@ use air_lambda_ast::format_ast;
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Deref;
|
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>> {
|
fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<Vec<&JValue>> {
|
||||||
let stream_iter = self.iter().map(|r| r.result.deref());
|
let stream_iter = self.iter().map(|r| r.result.deref());
|
||||||
let select_result = select_from_stream(stream_iter, lambda)?;
|
let select_result = select_from_stream(stream_iter, lambda)?;
|
||||||
|
@ -18,7 +18,7 @@ use super::select;
|
|||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::JValuable;
|
use super::JValuable;
|
||||||
use super::LambdaAST;
|
use super::LambdaAST;
|
||||||
use super::ResolvedCallResult;
|
use super::ValueAggregate;
|
||||||
use crate::execution_step::SecurityTetraplets;
|
use crate::execution_step::SecurityTetraplets;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ use air_lambda_ast::format_ast;
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
impl JValuable for ResolvedCallResult {
|
impl JValuable for ValueAggregate {
|
||||||
fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<Vec<&JValue>> {
|
fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<Vec<&JValue>> {
|
||||||
let selected_value = select(&self.result, lambda.iter())?;
|
let selected_value = select(&self.result, lambda.iter())?;
|
||||||
Ok(vec![selected_value])
|
Ok(vec![selected_value])
|
||||||
|
@ -23,8 +23,8 @@ mod variable;
|
|||||||
pub(crate) use super::ExecutionError;
|
pub(crate) use super::ExecutionError;
|
||||||
pub(crate) use iterable::*;
|
pub(crate) use iterable::*;
|
||||||
pub(crate) use jvaluable::*;
|
pub(crate) use jvaluable::*;
|
||||||
pub(crate) use scalar::ResolvedCallResult;
|
pub(crate) use scalar::ScalarRef;
|
||||||
pub(crate) use scalar::Scalar;
|
pub(crate) use scalar::ValueAggregate;
|
||||||
pub(crate) use stream::Generation;
|
pub(crate) use stream::Generation;
|
||||||
pub(crate) use stream::Stream;
|
pub(crate) use stream::Stream;
|
||||||
pub(crate) use stream::StreamIter;
|
pub(crate) use stream::StreamIter;
|
||||||
|
@ -27,22 +27,22 @@ use std::fmt::Formatter;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ResolvedCallResult {
|
pub struct ValueAggregate {
|
||||||
pub result: Rc<JValue>,
|
pub result: Rc<JValue>,
|
||||||
pub tetraplet: RSecurityTetraplet,
|
pub tetraplet: RSecurityTetraplet,
|
||||||
pub trace_pos: usize,
|
pub trace_pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum Scalar<'i> {
|
pub(crate) enum ScalarRef<'i> {
|
||||||
JValueRef(ResolvedCallResult),
|
Value(&'i ValueAggregate),
|
||||||
JValueFoldCursor(FoldState<'i>),
|
IterableValue(&'i FoldState<'i>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'i> Scalar<'i> {
|
impl<'i> ScalarRef<'i> {
|
||||||
pub(crate) fn to_jvaluable<'ctx>(&'ctx self) -> Box<dyn JValuable + 'ctx> {
|
pub(crate) fn into_jvaluable(self) -> Box<dyn JValuable + 'i> {
|
||||||
match self {
|
match self {
|
||||||
Scalar::JValueRef(value) => Box::new(value.clone()),
|
ScalarRef::Value(value) => Box::new(value.clone()),
|
||||||
Scalar::JValueFoldCursor(fold_state) => {
|
ScalarRef::IterableValue(fold_state) => {
|
||||||
let peeked_value = fold_state.iterable.peek().unwrap();
|
let peeked_value = fold_state.iterable.peek().unwrap();
|
||||||
Box::new(peeked_value)
|
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 {
|
pub(crate) fn new(result: Rc<JValue>, tetraplet: RSecurityTetraplet, trace_pos: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
result,
|
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 {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Scalar::JValueRef(value) => write!(f, "{:?}", value)?,
|
ScalarRef::Value(value) => write!(f, "{:?}", value)?,
|
||||||
Scalar::JValueFoldCursor(cursor) => {
|
ScalarRef::IterableValue(cursor) => {
|
||||||
let iterable = &cursor.iterable;
|
let iterable = &cursor.iterable;
|
||||||
write!(f, "cursor, current value: {:?}", iterable.peek())?;
|
write!(f, "cursor, current value: {:?}", iterable.peek())?;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use super::ExecutionError;
|
use super::ExecutionError;
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::ResolvedCallResult;
|
use super::ValueAggregate;
|
||||||
use crate::exec_err;
|
use crate::exec_err;
|
||||||
use crate::JValue;
|
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.
|
/// 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.
|
// TODO: make it non-pub after boxed value refactoring.
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub(crate) struct Stream(Vec<Vec<ResolvedCallResult>>);
|
pub(crate) struct Stream(Vec<Vec<ValueAggregate>>);
|
||||||
|
|
||||||
impl Stream {
|
impl Stream {
|
||||||
pub(crate) fn from_generations_count(count: usize) -> Self {
|
pub(crate) fn from_generations_count(count: usize) -> Self {
|
||||||
Self(vec![vec![]; count + 1])
|
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]])
|
Self(vec![vec![value]])
|
||||||
}
|
}
|
||||||
|
|
||||||
// if generation is None, value would be added to the last generation, otherwise it would
|
// if generation is None, value would be added to the last generation, otherwise it would
|
||||||
// be added to given generation
|
// 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 {
|
let generation = match generation {
|
||||||
Generation::Last => self.0.len() - 1,
|
Generation::Last => self.0.len() - 1,
|
||||||
Generation::Nth(id) => id as usize,
|
Generation::Nth(id) => id as usize,
|
||||||
@ -95,7 +95,7 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn iter(&self, generation: Generation) -> Option<StreamIter<'_>> {
|
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) 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::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())),
|
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<'_>> {
|
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) 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::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())),
|
Generation::Last => Box::new(self.0.iter().map(|v| v.as_slice())),
|
||||||
@ -142,12 +142,12 @@ impl Generation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StreamIter<'result> {
|
pub(crate) struct StreamIter<'result> {
|
||||||
iter: Box<dyn Iterator<Item = &'result ResolvedCallResult> + 'result>,
|
iter: Box<dyn Iterator<Item = &'result ValueAggregate> + 'result>,
|
||||||
len: usize,
|
len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'result> Iterator for StreamIter<'result> {
|
impl<'result> Iterator for StreamIter<'result> {
|
||||||
type Item = &'result ResolvedCallResult;
|
type Item = &'result ValueAggregate;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.len > 0 {
|
if self.len > 0 {
|
||||||
@ -164,12 +164,12 @@ impl<'result> Iterator for StreamIter<'result> {
|
|||||||
impl<'result> ExactSizeIterator for StreamIter<'result> {}
|
impl<'result> ExactSizeIterator for StreamIter<'result> {}
|
||||||
|
|
||||||
pub(crate) struct StreamSliceIter<'slice> {
|
pub(crate) struct StreamSliceIter<'slice> {
|
||||||
iter: Box<dyn Iterator<Item = &'slice [ResolvedCallResult]> + 'slice>,
|
iter: Box<dyn Iterator<Item = &'slice [ValueAggregate]> + 'slice>,
|
||||||
len: usize,
|
len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'slice> Iterator for StreamSliceIter<'slice> {
|
impl<'slice> Iterator for StreamSliceIter<'slice> {
|
||||||
type Item = &'slice [ResolvedCallResult];
|
type Item = &'slice [ValueAggregate];
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.len > 0 {
|
if self.len > 0 {
|
||||||
|
@ -62,21 +62,17 @@ pub(crate) enum ExecutionError {
|
|||||||
#[error("lambda is applied to an empty stream")]
|
#[error("lambda is applied to an empty stream")]
|
||||||
EmptyStreamLambdaError,
|
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")]
|
#[error("expected JValue type '{1}', but got '{0}' JValue")]
|
||||||
IncompatibleJValueType(JValue, &'static str),
|
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.
|
/// Fold state wasn't found for such iterator name.
|
||||||
#[error("fold state not found for this iterable '{0}'")]
|
#[error("fold state not found for this iterable '{0}'")]
|
||||||
FoldStateNotFound(String),
|
FoldStateNotFound(String),
|
||||||
|
|
||||||
/// Multiple fold states found for such iterator name.
|
/// Multiple fold states found for such iterator name.
|
||||||
#[error("multiple fold states found for iterable '{0}'")]
|
#[error("multiple iterable values found for iterable name '{0}'")]
|
||||||
MultipleFoldStates(String),
|
MultipleIterableValues(String),
|
||||||
|
|
||||||
/// A fold instruction must iterate over array value.
|
/// A fold instruction must iterate over array value.
|
||||||
#[error("lambda '{1}' returned non-array value '{0}' for fold instruction")]
|
#[error("lambda '{1}' returned non-array value '{0}' for fold instruction")]
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use super::LastErrorDescriptor;
|
use super::LastErrorDescriptor;
|
||||||
use super::LastErrorWithTetraplet;
|
use super::LastErrorWithTetraplet;
|
||||||
use crate::execution_step::boxed_value::Scalar;
|
use super::Scalars;
|
||||||
use crate::execution_step::boxed_value::Stream;
|
use crate::execution_step::boxed_value::Stream;
|
||||||
|
|
||||||
use air_execution_info_collector::InstructionTracker;
|
use air_execution_info_collector::InstructionTracker;
|
||||||
@ -24,36 +24,34 @@ use air_interpreter_interface::*;
|
|||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Contains all necessary state needed to execute AIR script.
|
/// Contains all necessary state needed to execute AIR script.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct ExecutionCtx<'i> {
|
pub(crate) struct ExecutionCtx<'i> {
|
||||||
/// Contains all scalars.
|
/// Contains all scalars.
|
||||||
// TODO: use shared string (Rc<String>) to avoid copying.
|
pub(crate) scalars: Scalars<'i>,
|
||||||
pub scalars: HashMap<String, Scalar<'i>>,
|
|
||||||
|
|
||||||
/// Contains all streams.
|
/// Contains all streams.
|
||||||
// TODO: use shared string (Rc<String>) to avoid copying.
|
// 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.
|
/// 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.
|
/// 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.
|
/// 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.
|
/// Last error produced by local service.
|
||||||
/// None means that there weren't any error.
|
/// 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
|
/// 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.
|
/// 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.
|
/// Indicates that previous executed subtree is complete.
|
||||||
/// A subtree treats as a complete if all subtree elements satisfy the following rules:
|
/// 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
|
/// - at least one of xor subtrees is completed without an error
|
||||||
/// - all of seq subtrees are completed
|
/// - all of seq subtrees are completed
|
||||||
/// - call executed successfully (executed state is Executed)
|
/// - call executed successfully (executed state is Executed)
|
||||||
pub subtree_complete: bool,
|
pub(crate) subtree_complete: bool,
|
||||||
|
|
||||||
/// List of met folds used to determine whether a variable can be shadowed.
|
|
||||||
pub met_folds: VecDeque<&'i str>,
|
|
||||||
|
|
||||||
/// Tracker of all met instructions.
|
/// 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.
|
/// 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.
|
/// 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.
|
/// Tracks all functions that should be called from services.
|
||||||
pub call_requests: CallRequests,
|
pub(crate) call_requests: CallRequests,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'i> ExecutionCtx<'i> {
|
impl<'i> ExecutionCtx<'i> {
|
||||||
@ -117,10 +112,14 @@ use std::fmt::Formatter;
|
|||||||
|
|
||||||
impl<'i> Display for ExecutionCtx<'i> {
|
impl<'i> Display for ExecutionCtx<'i> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "data cache:")?;
|
writeln!(f, "scalars:")?;
|
||||||
for (key, value) in self.scalars.iter() {
|
writeln!(f, " {}", self.scalars)?;
|
||||||
writeln!(f, " {} => {}", key, value)?;
|
|
||||||
|
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, "current peer id: {}", self.current_peer_id)?;
|
||||||
writeln!(f, "subtree complete: {}", self.subtree_complete)?;
|
writeln!(f, "subtree complete: {}", self.subtree_complete)?;
|
||||||
writeln!(f, "next peer public keys: {:?}", self.next_peer_pks)?;
|
writeln!(f, "next peer public keys: {:?}", self.next_peer_pks)?;
|
||||||
|
@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
mod error_descriptor;
|
mod error_descriptor;
|
||||||
|
mod scalar_variables;
|
||||||
|
|
||||||
pub(crate) use context::*;
|
pub(crate) use context::*;
|
||||||
pub use error_descriptor::LastError;
|
pub use error_descriptor::LastError;
|
||||||
pub(crate) use error_descriptor::LastErrorDescriptor;
|
pub(crate) use error_descriptor::LastErrorDescriptor;
|
||||||
pub(crate) use error_descriptor::LastErrorWithTetraplet;
|
pub(crate) use error_descriptor::LastErrorWithTetraplet;
|
||||||
|
pub(crate) use scalar_variables::*;
|
||||||
|
229
air/src/execution_step/execution_context/scalar_variables.rs
Normal file
229
air/src/execution_step/execution_context/scalar_variables.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
@ -24,9 +24,9 @@ mod utils;
|
|||||||
pub(super) use self::air::ExecutableInstruction;
|
pub(super) use self::air::ExecutableInstruction;
|
||||||
pub(super) use self::air::FoldState;
|
pub(super) use self::air::FoldState;
|
||||||
pub(super) use boxed_value::Generation;
|
pub(super) use boxed_value::Generation;
|
||||||
pub(super) use boxed_value::ResolvedCallResult;
|
pub(super) use boxed_value::ScalarRef;
|
||||||
pub(super) use boxed_value::Scalar;
|
|
||||||
pub(super) use boxed_value::Stream;
|
pub(super) use boxed_value::Stream;
|
||||||
|
pub(super) use boxed_value::ValueAggregate;
|
||||||
pub(crate) use errors::Catchable;
|
pub(crate) use errors::Catchable;
|
||||||
pub(super) use errors::ExecutionError;
|
pub(super) use errors::ExecutionError;
|
||||||
pub(crate) use errors::Joinable;
|
pub(crate) use errors::Joinable;
|
||||||
|
@ -19,7 +19,6 @@ use crate::execution_step::boxed_value::JValuable;
|
|||||||
use crate::execution_step::boxed_value::Variable;
|
use crate::execution_step::boxed_value::Variable;
|
||||||
use crate::execution_step::execution_context::ExecutionCtx;
|
use crate::execution_step::execution_context::ExecutionCtx;
|
||||||
use crate::execution_step::execution_context::LastErrorWithTetraplet;
|
use crate::execution_step::execution_context::LastErrorWithTetraplet;
|
||||||
use crate::execution_step::ExecutionError;
|
|
||||||
use crate::execution_step::ExecutionResult;
|
use crate::execution_step::ExecutionResult;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
use crate::LambdaAST;
|
use crate::LambdaAST;
|
||||||
@ -105,7 +104,7 @@ pub(crate) fn resolve_variable<'ctx, 'i>(
|
|||||||
use crate::execution_step::boxed_value::StreamJvaluableIngredients;
|
use crate::execution_step::boxed_value::StreamJvaluableIngredients;
|
||||||
|
|
||||||
match variable {
|
match variable {
|
||||||
Variable::Scalar(name) => scalar_to_jvaluable(name, ctx),
|
Variable::Scalar(name) => Ok(ctx.scalars.get(name)?.into_jvaluable()),
|
||||||
Variable::Stream { name, generation } => {
|
Variable::Stream { name, generation } => {
|
||||||
match ctx.streams.get(name) {
|
match ctx.streams.get(name) {
|
||||||
Some(stream) => {
|
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
|
// it's known that apply_lambda_with_tetraplets returns vec of one value
|
||||||
Ok((jvalue[0].clone(), tetraplets))
|
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())
|
|
||||||
}
|
|
||||||
|
@ -157,7 +157,7 @@ fn inner_fold_with_same_iterator() {
|
|||||||
|
|
||||||
let result = call_vm!(vm, "", script, "", "");
|
let result = call_vm!(vm, "", script, "", "");
|
||||||
|
|
||||||
assert_eq!(result.ret_code, 1009);
|
assert_eq!(result.ret_code, 1008);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -192,11 +192,11 @@ fn match_without_xor() {
|
|||||||
let result = call_vm!(set_variable_vm, "", &script, "", "");
|
let result = call_vm!(set_variable_vm, "", &script, "", "");
|
||||||
let result = call_vm!(vm, "", &script, "", result.data);
|
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);
|
let result = call_vm!(vm, "", script, "", result.data);
|
||||||
|
|
||||||
assert_eq!(result.ret_code, 1012);
|
assert_eq!(result.ret_code, 1011);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -143,11 +143,11 @@ fn mismatch_without_xor() {
|
|||||||
let result = call_vm!(set_variable_vm, "asd", &script, "", "");
|
let result = call_vm!(set_variable_vm, "asd", &script, "", "");
|
||||||
let result = call_vm!(vm, "asd", &script, "", result.data);
|
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);
|
let result = call_vm!(vm, "asd", script, "", result.data);
|
||||||
|
|
||||||
assert_eq!(result.ret_code, 1013);
|
assert_eq!(result.ret_code, 1012);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -140,7 +140,7 @@ fn par_early_exit() {
|
|||||||
];
|
];
|
||||||
let setter_3_malicious_data = raw_data_from_trace(setter_3_malicious_trace);
|
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);
|
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 actual_trace = trace_from_result(&init_result_3);
|
||||||
let expected_trace = trace_from_result(&init_result_2);
|
let expected_trace = trace_from_result(&init_result_2);
|
||||||
|
Loading…
Reference in New Issue
Block a user