2021-08-24 16:14:15 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2020 Fluence Labs Limited
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
use super::*;
|
2023-08-07 20:00:02 +03:00
|
|
|
use crate::execution_step::value_types::populate_tetraplet_with_lambda;
|
|
|
|
use crate::execution_step::value_types::IterableValue;
|
2021-12-21 11:37:35 +03:00
|
|
|
use crate::execution_step::CatchableError;
|
2022-09-06 10:53:33 +03:00
|
|
|
use crate::execution_step::PEEK_ALLOWED_ON_NON_EMPTY;
|
2021-08-24 16:14:15 +03:00
|
|
|
use crate::JValue;
|
2021-10-18 23:23:30 +03:00
|
|
|
use crate::LambdaAST;
|
2022-02-18 18:00:42 +03:00
|
|
|
use crate::SecurityTetraplet;
|
2021-08-24 16:14:15 +03:00
|
|
|
|
2023-05-08 19:42:41 +07:00
|
|
|
use air_interpreter_data::Provenance;
|
2021-08-24 16:14:15 +03:00
|
|
|
use air_parser::ast;
|
|
|
|
|
|
|
|
use std::ops::Deref;
|
2022-02-18 18:00:42 +03:00
|
|
|
use std::rc::Rc;
|
2021-08-24 16:14:15 +03:00
|
|
|
|
|
|
|
// TODO: refactor this file after switching to boxed value
|
|
|
|
|
|
|
|
pub(crate) enum FoldIterableScalar {
|
|
|
|
Empty,
|
2022-08-26 00:43:43 +03:00
|
|
|
ScalarBased(IterableValue),
|
2021-08-24 16:14:15 +03:00
|
|
|
}
|
|
|
|
|
2022-11-30 17:38:32 +03:00
|
|
|
/// Creates iterable value for given scalar iterable.
|
|
|
|
pub(crate) fn create_scalar_iterable(
|
|
|
|
exec_ctx: &ExecutionCtx<'_>,
|
|
|
|
variable_name: &str,
|
|
|
|
) -> ExecutionResult<FoldIterableScalar> {
|
|
|
|
match exec_ctx.scalars.get_value(variable_name)? {
|
|
|
|
ScalarRef::Value(call_result) => from_value(call_result.clone(), variable_name),
|
|
|
|
ScalarRef::IterableValue(fold_state) => {
|
|
|
|
let iterable_value = fold_state.iterable.peek().expect(PEEK_ALLOWED_ON_NON_EMPTY);
|
|
|
|
let call_result = iterable_value.into_resolved_result();
|
|
|
|
from_value(call_result, variable_name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates iterable value for given scalar with lambda iterable.
|
|
|
|
pub(crate) fn create_scalar_wl_iterable<'ctx>(
|
|
|
|
scalar_iterable: &ast::ScalarWithLambda<'ctx>,
|
2021-08-24 16:14:15 +03:00
|
|
|
exec_ctx: &ExecutionCtx<'ctx>,
|
|
|
|
) -> ExecutionResult<FoldIterableScalar> {
|
2022-11-30 17:38:32 +03:00
|
|
|
use crate::execution_step::lambda_applier::select_by_lambda_from_scalar;
|
|
|
|
let scalar_name = scalar_iterable.name;
|
|
|
|
let lambda = &scalar_iterable.lambda;
|
|
|
|
|
|
|
|
match exec_ctx.scalars.get_value(scalar_name)? {
|
|
|
|
ScalarRef::Value(variable) => {
|
2023-05-08 19:42:41 +07:00
|
|
|
let jvalues = select_by_lambda_from_scalar(variable.get_result(), lambda, exec_ctx)?;
|
|
|
|
let tetraplet = variable.get_tetraplet().deref().clone();
|
2024-02-13 16:11:21 +04:00
|
|
|
from_jvalue(&jvalues, tetraplet, variable.get_provenance(), lambda)
|
2022-11-30 17:38:32 +03:00
|
|
|
}
|
|
|
|
ScalarRef::IterableValue(fold_state) => {
|
|
|
|
let iterable_value = fold_state.iterable.peek().unwrap();
|
|
|
|
let jvalue = iterable_value.apply_lambda(lambda, exec_ctx)?;
|
|
|
|
let tetraplet = to_tetraplet(&iterable_value);
|
2023-05-08 19:42:41 +07:00
|
|
|
let provenance = to_provenance(&iterable_value);
|
2022-11-30 17:38:32 +03:00
|
|
|
|
2024-02-13 16:11:21 +04:00
|
|
|
from_jvalue(&jvalue, tetraplet, provenance, lambda)
|
2022-11-30 17:38:32 +03:00
|
|
|
}
|
2021-08-24 16:14:15 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-30 17:38:32 +03:00
|
|
|
/// Creates iterable value for given canon stream.
|
|
|
|
pub(crate) fn create_canon_stream_iterable_value<'ctx>(
|
2022-08-26 00:43:43 +03:00
|
|
|
ast_canon_stream: &ast::CanonStream<'ctx>,
|
|
|
|
exec_ctx: &ExecutionCtx<'ctx>,
|
|
|
|
) -> ExecutionResult<FoldIterableScalar> {
|
|
|
|
let canon_stream = exec_ctx.scalars.get_canon_stream(ast_canon_stream.name)?;
|
2022-09-06 10:53:33 +03:00
|
|
|
if canon_stream.is_empty() {
|
|
|
|
return Ok(FoldIterableScalar::Empty);
|
|
|
|
}
|
|
|
|
|
2022-08-26 00:43:43 +03:00
|
|
|
// TODO: this one is a relatively long operation and will be refactored in Boxed Value
|
2023-05-08 19:42:41 +07:00
|
|
|
let iterable_ingredients = CanonStreamIterableIngredients::init((**canon_stream).clone());
|
2022-08-26 00:43:43 +03:00
|
|
|
let iterable = Box::new(iterable_ingredients);
|
|
|
|
Ok(FoldIterableScalar::ScalarBased(iterable))
|
|
|
|
}
|
|
|
|
|
2023-09-07 11:30:24 +03:00
|
|
|
/// Creates iterable value for a canon stream map.
|
|
|
|
pub(crate) fn create_canon_stream_map_iterable_value(
|
|
|
|
ast_canon_stream_map: &ast::CanonStreamMap<'_>,
|
|
|
|
exec_ctx: &ExecutionCtx<'_>,
|
|
|
|
) -> ExecutionResult<FoldIterableScalar> {
|
|
|
|
let canon_stream_map = exec_ctx.scalars.get_canon_map(ast_canon_stream_map.name)?;
|
|
|
|
|
|
|
|
if canon_stream_map.is_empty() {
|
|
|
|
return Ok(FoldIterableScalar::Empty);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: this one is a relatively long operation and will be refactored in Boxed Value
|
|
|
|
// Can not create iterable from existing CanonStreamMap b/c CSM contains a map with
|
|
|
|
// a limited lifetime but the boxed value needs static lifetime.
|
|
|
|
let values = canon_stream_map.iter().cloned().collect::<Vec<_>>();
|
|
|
|
let iterable_ingredients = CanonStreamMapIterableIngredients::init(values);
|
|
|
|
let iterable = Box::new(iterable_ingredients);
|
|
|
|
Ok(FoldIterableScalar::ScalarBased(iterable))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates iterable value for a canon stream map with a lens applied.
|
|
|
|
pub(crate) fn create_canon_stream_map_wl_iterable_value(
|
|
|
|
ast_canon_stream_map: &ast::CanonStreamMapWithLambda<'_>,
|
|
|
|
exec_ctx: &ExecutionCtx<'_>,
|
|
|
|
) -> ExecutionResult<FoldIterableScalar> {
|
|
|
|
let canon_stream_map = exec_ctx.scalars.get_canon_map(ast_canon_stream_map.name)?;
|
|
|
|
// Source canon map provenance is used here to mimic the semantics used for scalar.
|
|
|
|
let provenance = Provenance::canon(canon_stream_map.cid.clone());
|
|
|
|
if canon_stream_map.is_empty() {
|
|
|
|
return Ok(FoldIterableScalar::Empty);
|
|
|
|
}
|
|
|
|
|
|
|
|
let canon_stream_map = &canon_stream_map.canon_stream_map;
|
|
|
|
let tetraplet = canon_stream_map.tetraplet().deref().clone();
|
|
|
|
let lambda = &ast_canon_stream_map.lambda;
|
|
|
|
// Source canon map tetraplet is used here similar with a scalar with lens processing path.
|
|
|
|
let jvalues = JValuable::apply_lambda(&canon_stream_map, lambda, exec_ctx)?;
|
|
|
|
|
2024-02-13 16:11:21 +04:00
|
|
|
from_jvalue(&jvalues, tetraplet, provenance, lambda)
|
2023-09-07 11:30:24 +03:00
|
|
|
}
|
|
|
|
|
2021-08-24 16:14:15 +03:00
|
|
|
/// Constructs iterable value from resolved call result.
|
2022-08-26 00:43:43 +03:00
|
|
|
fn from_value(call_result: ValueAggregate, variable_name: &str) -> ExecutionResult<FoldIterableScalar> {
|
2024-02-13 16:11:21 +04:00
|
|
|
let len = match call_result.get_result() {
|
2021-08-24 16:14:15 +03:00
|
|
|
JValue::Array(array) => {
|
|
|
|
if array.is_empty() {
|
|
|
|
// skip fold if array is empty
|
|
|
|
return Ok(FoldIterableScalar::Empty);
|
|
|
|
}
|
|
|
|
array.len()
|
|
|
|
}
|
2021-12-15 17:39:26 +03:00
|
|
|
v => {
|
2023-03-09 14:37:39 +03:00
|
|
|
return Err(CatchableError::FoldIteratesOverNonArray((*v).clone(), variable_name.to_string()).into());
|
2021-12-15 17:39:26 +03:00
|
|
|
}
|
2021-08-24 16:14:15 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
let foldable = IterableResolvedCall::init(call_result, len);
|
|
|
|
let foldable = Box::new(foldable);
|
2022-08-26 00:43:43 +03:00
|
|
|
let iterable = FoldIterableScalar::ScalarBased(foldable);
|
2021-08-24 16:14:15 +03:00
|
|
|
|
|
|
|
Ok(iterable)
|
|
|
|
}
|
|
|
|
|
2021-10-18 23:23:30 +03:00
|
|
|
/// Construct IterableValue from the result and given triplet.
|
|
|
|
fn from_jvalue(
|
2024-02-13 16:11:21 +04:00
|
|
|
jvalue: &JValue,
|
2022-09-08 16:58:04 +03:00
|
|
|
tetraplet: SecurityTetraplet,
|
2023-05-08 19:42:41 +07:00
|
|
|
provenance: Provenance,
|
2021-10-18 23:23:30 +03:00
|
|
|
lambda: &LambdaAST<'_>,
|
2021-08-24 16:14:15 +03:00
|
|
|
) -> ExecutionResult<FoldIterableScalar> {
|
2022-09-08 16:58:04 +03:00
|
|
|
let tetraplet = populate_tetraplet_with_lambda(tetraplet, lambda);
|
2022-02-18 18:00:42 +03:00
|
|
|
let tetraplet = Rc::new(tetraplet);
|
2021-08-24 16:14:15 +03:00
|
|
|
|
2024-02-13 16:11:21 +04:00
|
|
|
let iterable = match jvalue {
|
2021-10-18 23:23:30 +03:00
|
|
|
JValue::Array(array) => array,
|
|
|
|
_ => {
|
2024-02-13 16:11:21 +04:00
|
|
|
return Err(CatchableError::FoldIteratesOverNonArray(jvalue.clone(), lambda.to_string()).into());
|
2021-10-18 23:23:30 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if iterable.is_empty() {
|
2021-08-24 16:14:15 +03:00
|
|
|
return Ok(FoldIterableScalar::Empty);
|
|
|
|
}
|
|
|
|
|
2021-10-18 23:23:30 +03:00
|
|
|
let iterable = iterable.to_vec();
|
2023-05-08 19:42:41 +07:00
|
|
|
let foldable = IterableLambdaResult::init(iterable, tetraplet, provenance);
|
2022-08-26 00:43:43 +03:00
|
|
|
let iterable = FoldIterableScalar::ScalarBased(Box::new(foldable));
|
2021-08-24 16:14:15 +03:00
|
|
|
Ok(iterable)
|
|
|
|
}
|
|
|
|
|
2022-02-18 18:00:42 +03:00
|
|
|
fn to_tetraplet(iterable: &IterableItem<'_>) -> SecurityTetraplet {
|
2021-08-24 16:14:15 +03:00
|
|
|
use IterableItem::*;
|
|
|
|
|
|
|
|
let tetraplet = match iterable {
|
2023-05-08 19:42:41 +07:00
|
|
|
RefValue((_, tetraplet, _, _)) => tetraplet,
|
|
|
|
RcValue((_, tetraplet, _, _)) => tetraplet,
|
2021-08-24 16:14:15 +03:00
|
|
|
};
|
|
|
|
|
2022-02-18 18:00:42 +03:00
|
|
|
(*tetraplet).deref().clone()
|
2021-08-24 16:14:15 +03:00
|
|
|
}
|
2023-05-08 19:42:41 +07:00
|
|
|
|
|
|
|
fn to_provenance(iterable: &IterableItem<'_>) -> Provenance {
|
|
|
|
use IterableItem::*;
|
|
|
|
|
|
|
|
let provenance = match iterable {
|
|
|
|
RefValue((_, _, _, provenance)) => provenance,
|
|
|
|
RcValue((_, _, _, provenance)) => provenance,
|
|
|
|
};
|
|
|
|
|
|
|
|
provenance.clone()
|
|
|
|
}
|