diff --git a/CHANGELOG.md b/CHANGELOG.md index d37c2973..338c21c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## Version 0.18.0 (2021-12-14) + +[PR 192](https://github.com/fluencelabs/aquavm/pull/172): +Added a possibility to use scalars in lambdas. + +[PR 190](https://github.com/fluencelabs/aquavm/pull/190), [PR 186](https://github.com/fluencelabs/aquavm/pull/186), [PR 185](https://github.com/fluencelabs/aquavm/pull/185), [PR 182](https://github.com/fluencelabs/aquavm/pull/182), [PR 181](https://github.com/fluencelabs/aquavm/pull/181): +Bug fixing. + ## Version 0.17.0 (2021-11-24) [PR 172](https://github.com/fluencelabs/aquavm/pull/172): diff --git a/Cargo.lock b/Cargo.lock index 809e480f..e6d48f67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ [[package]] name = "air" -version = "0.17.0" +version = "0.18.0" dependencies = [ "air-execution-info-collector", "air-interpreter-data", @@ -50,7 +50,7 @@ version = "0.1.0" [[package]] name = "air-interpreter" -version = "0.17.0" +version = "0.18.0" dependencies = [ "air", "air-log-targets", diff --git a/air-interpreter/Cargo.toml b/air-interpreter/Cargo.toml index fd0f6e6b..5ac3d1b3 100644 --- a/air-interpreter/Cargo.toml +++ b/air-interpreter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "air-interpreter" -version = "0.17.0" +version = "0.18.0" description = "Crate-wrapper for air" authors = ["Fluence Labs"] edition = "2018" diff --git a/air/Cargo.toml b/air/Cargo.toml index 70b2bdda..7170644c 100644 --- a/air/Cargo.toml +++ b/air/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "air" -version = "0.17.0" +version = "0.18.0" description = "Interpreter of AIR scripts intended to coordinate request flow in the Fluence network" authors = ["Fluence Labs"] edition = "2018" diff --git a/air/src/execution_step/air/fail.rs b/air/src/execution_step/air/fail.rs new file mode 100644 index 00000000..8d65b51f --- /dev/null +++ b/air/src/execution_step/air/fail.rs @@ -0,0 +1,33 @@ +/* + * 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::ExecutionCtx; +use super::ExecutionResult; +use super::ExecutionError; +use super::TraceHandler; +use crate::log_instruction; + +use air_parser::ast::Null; + +impl<'i> super::ExecutableInstruction<'i> for Fail { + fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> { + log_instruction!(null, exec_ctx, trace_ctx); + + Err(ExecutionError::FailMet { + message: self.message.to_string() + }) + } +} diff --git a/air/src/execution_step/air/fold/utils.rs b/air/src/execution_step/air/fold/utils.rs index d6a67709..fd3a1083 100644 --- a/air/src/execution_step/air/fold/utils.rs +++ b/air/src/execution_step/air/fold/utils.rs @@ -127,12 +127,12 @@ fn create_scalar_lambda_iterable<'ctx>( match exec_ctx.scalars.get(scalar_name)? { ScalarRef::Value(variable) => { - let jvalues = select(&variable.result, lambda.iter())?; + let jvalues = select(&variable.result, lambda.iter(), exec_ctx)?; from_jvalue(jvalues, variable.tetraplet.clone(), lambda) } ScalarRef::IterableValue(fold_state) => { let iterable_value = fold_state.iterable.peek().unwrap(); - let jvalue = iterable_value.apply_lambda(lambda)?; + let jvalue = iterable_value.apply_lambda(lambda, exec_ctx)?; let tetraplet = as_tetraplet(&iterable_value); from_jvalue(jvalue, tetraplet, lambda) diff --git a/air/src/execution_step/boxed_value/jvaluable.rs b/air/src/execution_step/boxed_value/jvaluable.rs index eceb197f..0b113c26 100644 --- a/air/src/execution_step/boxed_value/jvaluable.rs +++ b/air/src/execution_step/boxed_value/jvaluable.rs @@ -25,6 +25,7 @@ use super::ExecutionError; use super::ExecutionResult; use super::ValueAggregate; use crate::execution_step::lambda_applier::*; +use crate::execution_step::ExecutionCtx; use crate::execution_step::RSecurityTetraplet; use crate::execution_step::SecurityTetraplets; use crate::JValue; @@ -37,10 +38,14 @@ use std::borrow::Cow; /// Represent a value that could be transform to a JValue with or without tetraplets. pub(crate) trait JValuable { /// Applies lambda to the internal value, produces JValue. - fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<&JValue>; + fn apply_lambda<'i>(&self, lambda: &LambdaAST<'_>, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue>; /// Applies lambda to the internal value, produces JValue with tetraplet. - fn apply_lambda_with_tetraplets(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<(&JValue, RSecurityTetraplet)>; + fn apply_lambda_with_tetraplets<'i>( + &self, + lambda: &LambdaAST<'_>, + exec_ctx: &ExecutionCtx<'i>, + ) -> ExecutionResult<(&JValue, RSecurityTetraplet)>; /// Return internal value as borrowed if it's possible, owned otherwise. fn as_jvalue(&self) -> Cow<'_, JValue>; diff --git a/air/src/execution_step/boxed_value/jvaluable/cell_vec_resolved_call_result.rs b/air/src/execution_step/boxed_value/jvaluable/cell_vec_resolved_call_result.rs index 917e8002..d3d73738 100644 --- a/air/src/execution_step/boxed_value/jvaluable/cell_vec_resolved_call_result.rs +++ b/air/src/execution_step/boxed_value/jvaluable/cell_vec_resolved_call_result.rs @@ -18,6 +18,7 @@ use super::select_from_stream; use super::ExecutionResult; use super::JValuable; use super::ValueAggregate; +use crate::execution_step::ExecutionCtx; use crate::execution_step::RSecurityTetraplet; use crate::execution_step::SecurityTetraplets; use crate::JValue; @@ -29,15 +30,19 @@ use std::borrow::Cow; use std::ops::Deref; impl JValuable for std::cell::Ref<'_, Vec> { - fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<&JValue> { + fn apply_lambda<'i>(&self, lambda: &LambdaAST<'_>, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> { 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, exec_ctx)?; Ok(select_result.result) } - fn apply_lambda_with_tetraplets(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { + fn apply_lambda_with_tetraplets<'i>( + &self, + lambda: &LambdaAST<'_>, + exec_ctx: &ExecutionCtx<'i>, + ) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { 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, exec_ctx)?; let tetraplet = self[select_result.tetraplet_idx].tetraplet.clone(); tetraplet.borrow_mut().add_lambda(&format_ast(lambda)); diff --git a/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs b/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs index baacfb3a..c2f82a26 100644 --- a/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs +++ b/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs @@ -19,6 +19,7 @@ use super::ExecutionResult; use super::JValuable; use super::LambdaAST; use crate::exec_err; +use crate::execution_step::ExecutionCtx; use crate::execution_step::RSecurityTetraplet; use crate::execution_step::SecurityTetraplets; use crate::JValue; @@ -26,12 +27,16 @@ use crate::JValue; use std::borrow::Cow; impl JValuable for () { - fn apply_lambda(&self, _lambda: &LambdaAST<'_>) -> ExecutionResult<&JValue> { + fn apply_lambda<'i>(&self, _lambda: &LambdaAST<'_>, _exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> { // applying lambda to an empty stream will produce a join behaviour exec_err!(ExecutionError::EmptyStreamLambdaError) } - fn apply_lambda_with_tetraplets(&self, _lambda: &LambdaAST<'_>) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { + fn apply_lambda_with_tetraplets<'i>( + &self, + _lambda: &LambdaAST<'_>, + _exec_ctx: &ExecutionCtx<'i>, + ) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { // applying lambda to an empty stream will produce a join behaviour exec_err!(ExecutionError::EmptyStreamLambdaError) } diff --git a/air/src/execution_step/boxed_value/jvaluable/iterable_item.rs b/air/src/execution_step/boxed_value/jvaluable/iterable_item.rs index a5bf7cb5..b0202ef5 100644 --- a/air/src/execution_step/boxed_value/jvaluable/iterable_item.rs +++ b/air/src/execution_step/boxed_value/jvaluable/iterable_item.rs @@ -19,6 +19,7 @@ use super::ExecutionResult; use super::IterableItem; use super::JValuable; use super::LambdaAST; +use crate::execution_step::ExecutionCtx; use crate::execution_step::RSecurityTetraplet; use crate::execution_step::SecurityTetraplets; use crate::JValue; @@ -27,7 +28,7 @@ use std::borrow::Cow; use std::ops::Deref; impl<'ctx> JValuable for IterableItem<'ctx> { - fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<&JValue> { + fn apply_lambda<'i>(&self, lambda: &LambdaAST<'_>, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> { use super::IterableItem::*; let jvalue = match self { @@ -36,11 +37,15 @@ impl<'ctx> JValuable for IterableItem<'ctx> { RcValue((jvalue, ..)) => jvalue.deref(), }; - let selected_value = select(jvalue, lambda.iter())?; + let selected_value = select(jvalue, lambda.iter(), exec_ctx)?; Ok(selected_value) } - fn apply_lambda_with_tetraplets(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { + fn apply_lambda_with_tetraplets<'i>( + &self, + lambda: &LambdaAST<'_>, + exec_ctx: &ExecutionCtx<'i>, + ) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { use super::IterableItem::*; let (jvalue, tetraplet) = match self { @@ -49,7 +54,7 @@ impl<'ctx> JValuable for IterableItem<'ctx> { RcValue((jvalue, tetraplet, _)) => (jvalue.deref(), tetraplet), }; - let selected_value = select(jvalue, lambda.iter())?; + let selected_value = select(jvalue, lambda.iter(), exec_ctx)?; Ok((selected_value, tetraplet.clone())) } diff --git a/air/src/execution_step/boxed_value/jvaluable/resolved_call_result.rs b/air/src/execution_step/boxed_value/jvaluable/resolved_call_result.rs index a05a1df8..5104833f 100644 --- a/air/src/execution_step/boxed_value/jvaluable/resolved_call_result.rs +++ b/air/src/execution_step/boxed_value/jvaluable/resolved_call_result.rs @@ -19,6 +19,7 @@ use super::ExecutionResult; use super::JValuable; use super::LambdaAST; use super::ValueAggregate; +use crate::execution_step::ExecutionCtx; use crate::execution_step::RSecurityTetraplet; use crate::execution_step::SecurityTetraplets; use crate::JValue; @@ -29,13 +30,17 @@ use std::borrow::Cow; use std::ops::Deref; impl JValuable for ValueAggregate { - fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<&JValue> { - let selected_value = select(&self.result, lambda.iter())?; + fn apply_lambda<'i>(&self, lambda: &LambdaAST<'_>, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> { + let selected_value = select(&self.result, lambda.iter(), exec_ctx)?; Ok(selected_value) } - fn apply_lambda_with_tetraplets(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { - let selected_value = select(&self.result, lambda.iter())?; + fn apply_lambda_with_tetraplets<'i>( + &self, + lambda: &LambdaAST<'_>, + exec_ctx: &ExecutionCtx<'i>, + ) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { + let selected_value = select(&self.result, lambda.iter(), exec_ctx)?; let tetraplet = self.tetraplet.clone(); tetraplet.borrow_mut().add_lambda(&format_ast(lambda)); diff --git a/air/src/execution_step/boxed_value/jvaluable/stream.rs b/air/src/execution_step/boxed_value/jvaluable/stream.rs index f45762b3..57bb3233 100644 --- a/air/src/execution_step/boxed_value/jvaluable/stream.rs +++ b/air/src/execution_step/boxed_value/jvaluable/stream.rs @@ -20,6 +20,7 @@ use super::JValuable; use crate::exec_err; use crate::execution_step::boxed_value::Generation; use crate::execution_step::boxed_value::Stream; +use crate::execution_step::ExecutionCtx; use crate::execution_step::RSecurityTetraplet; use crate::execution_step::SecurityTetraplets; use crate::JValue; @@ -39,16 +40,20 @@ pub(crate) struct StreamJvaluableIngredients<'stream> { // TODO: this will be deleted soon, because it would be impossible to use streams without // canonicalization as an arg of a call impl JValuable for StreamJvaluableIngredients<'_> { - fn apply_lambda(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<&JValue> { + fn apply_lambda<'i>(&self, lambda: &LambdaAST<'_>, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> { let iter = self.iter()?.map(|v| v.result.deref()); - let select_result = select_from_stream(iter, lambda)?; + let select_result = select_from_stream(iter, lambda, exec_ctx)?; Ok(select_result.result) } - fn apply_lambda_with_tetraplets(&self, lambda: &LambdaAST<'_>) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { + fn apply_lambda_with_tetraplets<'i>( + &self, + lambda: &LambdaAST<'_>, + exec_ctx: &ExecutionCtx<'i>, + ) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { let iter = self.iter()?.map(|v| v.result.deref()); - let select_result = select_from_stream(iter, lambda)?; + let select_result = select_from_stream(iter, lambda, exec_ctx)?; // unwrap is safe here because each value has a tetraplet and a lambda always returns a valid index let resolved_call = self.iter()?.nth(select_result.tetraplet_idx).unwrap(); diff --git a/air/src/execution_step/lambda_applier/applier.rs b/air/src/execution_step/lambda_applier/applier.rs index 01a59b42..4adb7c0a 100644 --- a/air/src/execution_step/lambda_applier/applier.rs +++ b/air/src/execution_step/lambda_applier/applier.rs @@ -16,7 +16,8 @@ use super::utils::*; use super::LambdaError; -use super::LambdaResult; +use crate::execution_step::ExecutionCtx; +use crate::execution_step::ExecutionResult; use crate::JValue; use crate::LambdaAST; @@ -27,19 +28,21 @@ pub(crate) struct StreamSelectResult<'value> { pub(crate) tetraplet_idx: usize, } -pub(crate) fn select_from_stream<'value>( +pub(crate) fn select_from_stream<'value, 'i>( stream: impl ExactSizeIterator + 'value, lambda: &LambdaAST<'_>, -) -> LambdaResult> { + exec_ctx: &ExecutionCtx<'i>, +) -> ExecutionResult> { use ValueAccessor::*; let (prefix, body) = lambda.split_first(); let idx = match prefix { ArrayAccess { idx } => *idx, - FieldAccess { field_name } => { + FieldAccessByName { field_name } => { return Err(LambdaError::FieldAccessorAppliedToStream { field_name: field_name.to_string(), - }) + } + .into()); } _ => unreachable!("should not execute if parsing succeeded. QED."), }; @@ -50,23 +53,28 @@ pub(crate) fn select_from_stream<'value>( .nth(idx as usize) .ok_or(LambdaError::StreamNotHaveEnoughValues { stream_size, idx })?; - let result = select(value, body.iter())?; + let result = select(value, body.iter(), exec_ctx)?; let select_result = StreamSelectResult::new(result, idx); Ok(select_result) } -pub(crate) fn select<'value, 'algebra>( +pub(crate) fn select<'value, 'accessor, 'i>( mut value: &'value JValue, - lambda: impl Iterator>, -) -> LambdaResult<&'value JValue> { - for value_algebra in lambda { - match value_algebra { + lambda: impl Iterator>, + exec_ctx: &ExecutionCtx<'i>, +) -> ExecutionResult<&'value JValue> { + for accessor in lambda { + match accessor { ValueAccessor::ArrayAccess { idx } => { value = try_jvalue_with_idx(value, *idx)?; } - ValueAccessor::FieldAccess { field_name } => { + ValueAccessor::FieldAccessByName { field_name } => { value = try_jvalue_with_field_name(value, *field_name)?; } + ValueAccessor::FieldAccessByScalar { scalar_name } => { + let scalar = exec_ctx.scalars.get(scalar_name)?; + value = select_by_scalar(value, scalar)?; + } ValueAccessor::Error => unreachable!("should not execute if parsing succeeded. QED."), } } diff --git a/air/src/execution_step/lambda_applier/errors.rs b/air/src/execution_step/lambda_applier/errors.rs index 0f08696f..ab54de2f 100644 --- a/air/src/execution_step/lambda_applier/errors.rs +++ b/air/src/execution_step/lambda_applier/errors.rs @@ -23,18 +23,24 @@ pub(crate) enum LambdaError { #[error("lambda is applied to a stream that have only '{stream_size}' elements, but '{idx}' requested")] StreamNotHaveEnoughValues { stream_size: usize, idx: u32 }, - #[error("field algebra (with field name = '{field_name}') can't be applied to a stream")] + #[error("field accessor (with field name = '{field_name}') can't be applied to a stream")] FieldAccessorAppliedToStream { field_name: String }, - #[error("value '{value}' is not an array-type to match array algebra with idx = '{idx}'")] + #[error("value '{value}' is not an array-type to match array accessor with idx = '{idx}'")] ArrayAccessorNotMatchValue { value: JValue, idx: u32 }, #[error("value '{value}' does not contain element for idx = '{idx}'")] ValueNotContainSuchArrayIdx { value: JValue, idx: u32 }, - #[error("value '{value}' is not an map-type to match field algebra with field_name = '{field_name}'")] + #[error("value '{value}' is not an map-type to match field accessor with field_name = '{field_name}'")] FieldAccessorNotMatchValue { value: JValue, field_name: String }, #[error("value '{value}' does not contain element with field name = '{field_name}'")] JValueNotContainSuchField { value: JValue, field_name: String }, + + #[error("index accessor `{accessor} can't be converted to u32`")] + IndexAccessNotU32 { accessor: serde_json::Number }, + + #[error("scalar accessor `{scalar_accessor}` should has number or string type")] + ScalarAccessorHasInvalidType { scalar_accessor: JValue }, } diff --git a/air/src/execution_step/lambda_applier/utils.rs b/air/src/execution_step/lambda_applier/utils.rs index be1b2c61..8a3d6333 100644 --- a/air/src/execution_step/lambda_applier/utils.rs +++ b/air/src/execution_step/lambda_applier/utils.rs @@ -16,6 +16,7 @@ use super::LambdaError; use super::LambdaResult; +use crate::execution_step::ScalarRef; use crate::JValue; pub(super) fn try_jvalue_with_idx(jvalue: &JValue, idx: u32) -> LambdaResult<&JValue> { @@ -52,3 +53,43 @@ pub(super) fn try_jvalue_with_field_name<'value>( }), } } + +pub(super) fn select_by_scalar<'value, 'i>( + value: &'value JValue, + scalar_ref: ScalarRef<'i>, +) -> LambdaResult<&'value JValue> { + use ScalarRef::*; + + match scalar_ref { + Value(lambda_value) => select_by_jvalue(value, &lambda_value.result), + IterableValue(fold_state) => { + // it's safe because iterable always point to valid value + let accessor = fold_state.iterable.peek().unwrap().into_resolved_result(); + select_by_jvalue(value, &accessor.result) + } + } +} + +fn select_by_jvalue<'value>(value: &'value JValue, accessor: &JValue) -> LambdaResult<&'value JValue> { + match accessor { + JValue::String(string_accessor) => try_jvalue_with_field_name(value, string_accessor), + JValue::Number(number_accessor) => { + let idx = try_number_to_u32(number_accessor)?; + try_jvalue_with_idx(value, idx) + } + scalar_accessor => Err(LambdaError::ScalarAccessorHasInvalidType { + scalar_accessor: scalar_accessor.clone(), + }), + } +} + +fn try_number_to_u32(accessor: &serde_json::Number) -> LambdaResult { + use std::convert::TryFrom; + + accessor + .as_u64() + .and_then(|v| u32::try_from(v).ok()) + .ok_or(LambdaError::IndexAccessNotU32 { + accessor: accessor.clone(), + }) +} diff --git a/air/src/execution_step/utils/resolve.rs b/air/src/execution_step/utils/resolve.rs index 0bc92b87..03ab4a30 100644 --- a/air/src/execution_step/utils/resolve.rs +++ b/air/src/execution_step/utils/resolve.rs @@ -128,7 +128,7 @@ pub(crate) fn apply_lambda<'i>( exec_ctx: &ExecutionCtx<'i>, ) -> ExecutionResult<(JValue, RSecurityTetraplet)> { let resolved = resolve_variable(variable, exec_ctx)?; - let (jvalue, tetraplet) = resolved.apply_lambda_with_tetraplets(lambda)?; + let (jvalue, tetraplet) = resolved.apply_lambda_with_tetraplets(lambda, exec_ctx)?; // it's known that apply_lambda_with_tetraplets returns vec of one value Ok((jvalue.clone(), tetraplet)) diff --git a/air/tests/test_module/integration/json_path.rs b/air/tests/test_module/integration/json_path.rs deleted file mode 100644 index f6d469e0..00000000 --- a/air/tests/test_module/integration/json_path.rs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 air_test_utils::prelude::*; - -#[test] -fn json_path_not_allowed_for_non_objects_and_arrays() { - let set_variable_peer_id = "set_variable"; - let mut set_variable_vm = create_avm(echo_call_service(), set_variable_peer_id); - - let local_peer_id = "local_peer_id"; - let mut local_vm = create_avm(echo_call_service(), local_peer_id); - - let script = format!( - r#" - (seq - (call "{0}" ("" "") ["some_string"] string_variable) - (call "{1}" ("" "") [string_variable.$.some_json_path]) - ) - "#, - set_variable_peer_id, local_peer_id - ); - - let result = checked_call_vm!(set_variable_vm, "asd", &script, "", ""); - let result = call_vm!(local_vm, "asd", script, "", result.data); - - assert_eq!(result.ret_code, 1003); -} diff --git a/air/tests/test_module/integration/lambda.rs b/air/tests/test_module/integration/lambda.rs new file mode 100644 index 00000000..824dc7ea --- /dev/null +++ b/air/tests/test_module/integration/lambda.rs @@ -0,0 +1,140 @@ +/* + * 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 air_test_utils::prelude::*; + +use fstrings::f; +use fstrings::format_args_f; + +#[test] +fn lambda_not_allowed_for_non_objects_and_arrays() { + let set_variable_peer_id = "set_variable"; + let mut set_variable_vm = create_avm(echo_call_service(), set_variable_peer_id); + + let local_peer_id = "local_peer_id"; + let mut local_vm = create_avm(echo_call_service(), local_peer_id); + + let script = format!( + r#" + (seq + (call "{0}" ("" "") ["some_string"] string_variable) + (call "{1}" ("" "") [string_variable.$.some_lambda]) + ) + "#, + set_variable_peer_id, local_peer_id + ); + + let result = checked_call_vm!(set_variable_vm, "asd", &script, "", ""); + let result = call_vm!(local_vm, "asd", script, "", result.data); + + assert_eq!(result.ret_code, 1003); +} + +#[test] +fn lambda_with_string_scalar() { + let set_variable_peer_id = "set_variable"; + let variables = maplit::hashmap! { + "string_accessor".to_string() => json!("some_field_name"), + "value".to_string() => json!({"other_name_1": 0, "some_field_name": 1, "other_name_2": 0}) + }; + let mut set_variable_vm = create_avm( + set_variables_call_service(variables, VariableOptionSource::FunctionName), + set_variable_peer_id, + ); + + let local_peer_id = "local_peer_id"; + let mut local_vm = create_avm(echo_call_service(), local_peer_id); + + let script = f!(r#" + (seq + (seq + (call "{set_variable_peer_id}" ("" "string_accessor") [] string_accessor) + (call "{set_variable_peer_id}" ("" "value") [] value) + ) + (call "{local_peer_id}" ("" "") [value.$.[string_accessor]]) + ) + "#); + + let result = checked_call_vm!(set_variable_vm, "asd", &script, "", ""); + let result = checked_call_vm!(local_vm, "asd", script, "", result.data); + let trace = trace_from_result(&result); + + assert_eq!(&trace[2], &executed_state::scalar_number(1u32)); +} + +#[test] +fn lambda_with_number_scalar() { + let set_variable_peer_id = "set_variable"; + let variables = maplit::hashmap! { + "string_accessor".to_string() => json!(1u32), + "value".to_string() => json!([0, 1, 2]) + }; + let mut set_variable_vm = create_avm( + set_variables_call_service(variables, VariableOptionSource::FunctionName), + set_variable_peer_id, + ); + + let local_peer_id = "local_peer_id"; + let mut local_vm = create_avm(echo_call_service(), local_peer_id); + + let script = f!(r#" + (seq + (seq + (call "{set_variable_peer_id}" ("" "string_accessor") [] string_accessor) + (call "{set_variable_peer_id}" ("" "value") [] value) + ) + (call "{local_peer_id}" ("" "") [value.$.[string_accessor]]) + ) + "#); + + let result = checked_call_vm!(set_variable_vm, "asd", &script, "", ""); + let result = checked_call_vm!(local_vm, "asd", script, "", result.data); + let trace = trace_from_result(&result); + + assert_eq!(&trace[2], &executed_state::scalar_number(1u32)); +} + +#[test] +fn lambda_with_scalar_join() { + let set_variable_peer_id = "set_variable"; + let variables = maplit::hashmap! { + "string_accessor".to_string() => json!("some_field_name"), + "value".to_string() => json!({"other_name_1": 0, "some_field_name": 1, "other_name_2": 0}) + }; + let mut set_variable_vm = create_avm( + set_variables_call_service(variables, VariableOptionSource::FunctionName), + set_variable_peer_id, + ); + + let local_peer_id = "local_peer_id"; + let mut local_vm = create_avm(echo_call_service(), local_peer_id); + + let script = f!(r#" + (seq + (par + (call "non_exist_peer_id" ("" "string_accessor") [] string_accessor) + (call "{set_variable_peer_id}" ("" "value") [] value) + ) + (call "{local_peer_id}" ("" "") [value.$.[string_accessor]]) + ) + "#); + + let result = checked_call_vm!(set_variable_vm, "asd", &script, "", ""); + let result = checked_call_vm!(local_vm, "asd", script, "", result.data); + let trace = trace_from_result(&result); + + assert_eq!(&trace[3], &executed_state::request_sent_by("set_variable")); +} diff --git a/air/tests/test_module/integration/mod.rs b/air/tests/test_module/integration/mod.rs index e683f896..f7f01366 100644 --- a/air/tests/test_module/integration/mod.rs +++ b/air/tests/test_module/integration/mod.rs @@ -23,7 +23,7 @@ mod empty_array; mod flattening; mod join; mod join_behaviour; -mod json_path; +mod lambda; mod last_error; mod network_explore; mod security_tetraplets; diff --git a/crates/air-lib/air-parser/src/parser/lexer/tests.rs b/crates/air-lib/air-parser/src/parser/lexer/tests.rs index 06530e20..c1ff07d4 100644 --- a/crates/air-lib/air-parser/src/parser/lexer/tests.rs +++ b/crates/air-lib/air-parser/src/parser/lexer/tests.rs @@ -285,7 +285,7 @@ fn lambda() { name: "value", lambda: unsafe { LambdaAST::new_unchecked(vec![ - ValueAccessor::FieldAccess { + ValueAccessor::FieldAccessByName { field_name: "field", }, ValueAccessor::ArrayAccess { idx: 1 }, diff --git a/crates/air-lib/air-parser/src/parser/tests/call.rs b/crates/air-lib/air-parser/src/parser/tests/call.rs index 0119cfc8..e403e08b 100644 --- a/crates/air-lib/air-parser/src/parser/tests/call.rs +++ b/crates/air-lib/air-parser/src/parser/tests/call.rs @@ -34,7 +34,7 @@ fn parse_json_path() { let expected = call( CallInstrValue::Variable(VariableWithLambda::from_raw_lambda_scalar( "peer_id", - vec![ValueAccessor::FieldAccess { field_name: "a" }], + vec![ValueAccessor::FieldAccessByName { field_name: "a" }], 15, )), CallInstrValue::Literal("service_id"), @@ -194,7 +194,7 @@ fn parse_call_with_invalid_triplet() { } #[test] -fn parse_json_path_complex() { +fn parse_lambda_complex() { let source_code = r#" (seq (call m.$.[1]! ("service_id" "function_name") [] void) @@ -218,12 +218,12 @@ fn parse_json_path_complex() { CallInstrValue::Variable(VariableWithLambda::from_raw_lambda_scalar( "m", vec![ - ValueAccessor::FieldAccess { field_name: "abc" }, + ValueAccessor::FieldAccessByName { field_name: "abc" }, ValueAccessor::ArrayAccess { idx: 0 }, - ValueAccessor::FieldAccess { field_name: "cde" }, + ValueAccessor::FieldAccessByName { field_name: "cde" }, ValueAccessor::ArrayAccess { idx: 1 }, ValueAccessor::ArrayAccess { idx: 0 }, - ValueAccessor::FieldAccess { field_name: "cde" }, + ValueAccessor::FieldAccessByName { field_name: "cde" }, ValueAccessor::ArrayAccess { idx: 1 }, ], 99, @@ -237,6 +237,64 @@ fn parse_json_path_complex() { assert_eq!(instruction, expected); } +#[test] +fn parse_lambda_with_scalars_complex() { + let source_code = r#" + (seq + (call m.$.[1].[scalar_1].[scalar_2]! ("service_id" "function_name") [] void) + (call m.$.abc[0].[scalar_2].cde[1][0][scalar_3].cde[1]! ("service_id" "function_name") [] void) + ) + "#; + let instruction = parse(source_code); + let expected = seq( + call( + CallInstrValue::Variable(VariableWithLambda::from_raw_lambda_scalar( + "m", + vec![ + ValueAccessor::ArrayAccess { idx: 1 }, + ValueAccessor::FieldAccessByScalar { + scalar_name: "scalar_1", + }, + ValueAccessor::FieldAccessByScalar { + scalar_name: "scalar_2", + }, + ], + 32, + )), + CallInstrValue::Literal("service_id"), + CallInstrValue::Literal("function_name"), + Rc::new(vec![]), + CallOutputValue::Variable(Variable::scalar("void", 97)), + ), + call( + CallInstrValue::Variable(VariableWithLambda::from_raw_lambda_scalar( + "m", + vec![ + ValueAccessor::FieldAccessByName { field_name: "abc" }, + ValueAccessor::ArrayAccess { idx: 0 }, + ValueAccessor::FieldAccessByScalar { + scalar_name: "scalar_2", + }, + ValueAccessor::FieldAccessByName { field_name: "cde" }, + ValueAccessor::ArrayAccess { idx: 1 }, + ValueAccessor::ArrayAccess { idx: 0 }, + ValueAccessor::FieldAccessByScalar { + scalar_name: "scalar_3", + }, + ValueAccessor::FieldAccessByName { field_name: "cde" }, + ValueAccessor::ArrayAccess { idx: 1 }, + ], + 121, + )), + CallInstrValue::Literal("service_id"), + CallInstrValue::Literal("function_name"), + Rc::new(vec![]), + CallOutputValue::Variable(Variable::scalar("void", 205)), + ), + ); + assert_eq!(instruction, expected); +} + #[test] fn json_path_square_braces() { let source_code = r#" @@ -246,7 +304,7 @@ fn json_path_square_braces() { let expected = call( CallInstrValue::Variable(VariableWithLambda::from_raw_lambda_scalar( "u", - vec![ValueAccessor::FieldAccess { + vec![ValueAccessor::FieldAccessByName { field_name: "peer_id", }], 15, @@ -258,16 +316,16 @@ fn json_path_square_braces() { "u", vec![ ValueAccessor::ArrayAccess { idx: 1 }, - ValueAccessor::FieldAccess { field_name: "cde" }, + ValueAccessor::FieldAccessByName { field_name: "cde" }, ValueAccessor::ArrayAccess { idx: 0 }, ValueAccessor::ArrayAccess { idx: 0 }, - ValueAccessor::FieldAccess { field_name: "abc" }, + ValueAccessor::FieldAccessByName { field_name: "abc" }, ], 43, )), Value::Variable(VariableWithLambda::from_raw_lambda_scalar( "u", - vec![ValueAccessor::FieldAccess { field_name: "name" }], + vec![ValueAccessor::FieldAccessByName { field_name: "name" }], 64, )), ]), diff --git a/crates/air-lib/air-parser/src/parser/tests/fold.rs b/crates/air-lib/air-parser/src/parser/tests/fold.rs index 8f04d980..58f531a3 100644 --- a/crates/air-lib/air-parser/src/parser/tests/fold.rs +++ b/crates/air-lib/air-parser/src/parser/tests/fold.rs @@ -126,7 +126,7 @@ fn comments() { ScalarWithLambda::from_raw_lambda( "members", vec![ - ValueAccessor::FieldAccess { + ValueAccessor::FieldAccessByName { field_name: "field", }, ValueAccessor::ArrayAccess { idx: 1 }, diff --git a/crates/air-lib/lambda/ast/src/ast.rs b/crates/air-lib/lambda/ast/src/ast.rs index cce658c8..96d75c7a 100644 --- a/crates/air-lib/lambda/ast/src/ast.rs +++ b/crates/air-lib/lambda/ast/src/ast.rs @@ -28,7 +28,10 @@ pub enum ValueAccessor<'input> { ArrayAccess { idx: u32 }, // .field - FieldAccess { field_name: &'input str }, + FieldAccessByName { field_name: &'input str }, + + // (.)?[field] + FieldAccessByScalar { scalar_name: &'input str }, // needed to allow parser catch all errors from a lambda expression without stopping // on the very first one. Although, this variant is guaranteed not to be present in a lambda. diff --git a/crates/air-lib/lambda/ast/src/ast/traits.rs b/crates/air-lib/lambda/ast/src/ast/traits.rs index 12517a9b..b31f1570 100644 --- a/crates/air-lib/lambda/ast/src/ast/traits.rs +++ b/crates/air-lib/lambda/ast/src/ast/traits.rs @@ -24,7 +24,8 @@ impl fmt::Display for ValueAccessor<'_> { match self { ArrayAccess { idx } => write!(f, ".[{}]", idx), - FieldAccess { field_name } => write!(f, ".{}", field_name), + FieldAccessByName { field_name } => write!(f, ".{}", field_name), + FieldAccessByScalar { scalar_name } => write!(f, ".[{}]", scalar_name), Error => write!(f, "a parser error occurred while parsing lambda expression"), } } diff --git a/crates/air-lib/lambda/ast/src/lib.rs b/crates/air-lib/lambda/ast/src/lib.rs index 43c0c766..17315bab 100644 --- a/crates/air-lib/lambda/ast/src/lib.rs +++ b/crates/air-lib/lambda/ast/src/lib.rs @@ -30,8 +30,8 @@ pub use ast::*; pub fn format_ast(lambda_ast: &LambdaAST<'_>) -> String { let mut formatted_ast = String::new(); - for algebra in lambda_ast.iter() { - formatted_ast.push_str(&algebra.to_string()); + for accessor in lambda_ast.iter() { + formatted_ast.push_str(&accessor.to_string()); } formatted_ast diff --git a/crates/air-lib/lambda/parser/src/lib.rs b/crates/air-lib/lambda/parser/src/lib.rs index 08a54369..342bd065 100644 --- a/crates/air-lib/lambda/parser/src/lib.rs +++ b/crates/air-lib/lambda/parser/src/lib.rs @@ -27,7 +27,7 @@ mod parser; pub use parser::parse; -pub use parser::AlgebraLexer; +pub use parser::AccessorsLexer; pub use parser::LambdaParser; pub use parser::LambdaParserError; pub use parser::LexerError; diff --git a/crates/air-lib/lambda/parser/src/parser/errors.rs b/crates/air-lib/lambda/parser/src/parser/errors.rs index 0e0e1c01..95891e72 100644 --- a/crates/air-lib/lambda/parser/src/parser/errors.rs +++ b/crates/air-lib/lambda/parser/src/parser/errors.rs @@ -26,7 +26,7 @@ pub enum LambdaParserError<'input> { #[error(transparent)] LexerError(#[from] LexerError), - #[error("provided lambda expression doesn't contain any algebras")] + #[error("provided lambda expression doesn't contain any accessor")] EmptyLambda, #[error("{0:?}")] diff --git a/crates/air-lib/lambda/parser/src/parser/lambda_parser.rs b/crates/air-lib/lambda/parser/src/parser/lambda_parser.rs index 11f712f6..412d990b 100644 --- a/crates/air-lib/lambda/parser/src/parser/lambda_parser.rs +++ b/crates/air-lib/lambda/parser/src/parser/lambda_parser.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use super::lexer::AlgebraLexer; +use super::lexer::AccessorsLexer; use super::va_lambda; use super::LambdaParserError; use super::LambdaParserResult; @@ -31,22 +31,22 @@ thread_local!(static PARSER: LambdaParser = LambdaParser::new()); pub fn parse(lambda: &str) -> LambdaParserResult<'_, LambdaAST> { PARSER.with(|parser| { let mut errors = Vec::new(); - let lexer = AlgebraLexer::new(lambda); + let lexer = AccessorsLexer::new(lambda); let result = parser.parse(lambda, &mut errors, lexer); match result { - Ok(algebras) if errors.is_empty() => try_to_lambda(algebras), + Ok(accessors) if errors.is_empty() => try_to_lambda(accessors), Ok(_) => Err(errors.into()), Err(e) => Err(e.into()), } }) } -fn try_to_lambda(algebras: Vec) -> LambdaParserResult<'_, LambdaAST> { - if algebras.is_empty() { +fn try_to_lambda(accessors: Vec) -> LambdaParserResult<'_, LambdaAST> { + if accessors.is_empty() { return Err(LambdaParserError::EmptyLambda); } - let ast = unsafe { LambdaAST::new_unchecked(algebras) }; + let ast = unsafe { LambdaAST::new_unchecked(accessors) }; Ok(ast) } diff --git a/crates/air-lib/lambda/parser/src/parser/lexer/algebra_lexer.rs b/crates/air-lib/lambda/parser/src/parser/lexer/accessors_lexer.rs similarity index 90% rename from crates/air-lib/lambda/parser/src/parser/lexer/algebra_lexer.rs rename to crates/air-lib/lambda/parser/src/parser/lexer/accessors_lexer.rs index d7e033ac..ab5311d6 100644 --- a/crates/air-lib/lambda/parser/src/parser/lexer/algebra_lexer.rs +++ b/crates/air-lib/lambda/parser/src/parser/lexer/accessors_lexer.rs @@ -25,12 +25,12 @@ const ARRAY_IDX_BASE: u32 = 10; pub type Spanned = Result<(Loc, Token, Loc), Error>; -pub struct AlgebraLexer<'input> { +pub struct AccessorsLexer<'input> { input: &'input str, chars: Peekable>, } -impl<'input> Iterator for AlgebraLexer<'input> { +impl<'input> Iterator for AccessorsLexer<'input> { type Item = Spanned, usize, LexerError>; fn next(&mut self) -> Option { @@ -38,7 +38,7 @@ impl<'input> Iterator for AlgebraLexer<'input> { } } -impl<'input> AlgebraLexer<'input> { +impl<'input> AccessorsLexer<'input> { pub fn new(input: &'input str) -> Self { Self { input, @@ -71,7 +71,11 @@ impl<'input> AlgebraLexer<'input> { .parse::() .map_err(|e| LexerError::ParseIntError(start_pos, start_pos + array_idx.len(), e)) { - Ok(idx) => Ok((start_pos, Token::ArrayIdx(idx), start_pos + array_idx.len())), + Ok(idx) => Ok(( + start_pos, + Token::NumberAccessor(idx), + start_pos + array_idx.len(), + )), Err(e) => Err(e), } } @@ -84,7 +88,7 @@ impl<'input> AlgebraLexer<'input> { Ok(( start_pos, - Token::FieldName(field_name), + Token::StringAccessor(field_name), start_pos + field_name.len(), )) } diff --git a/crates/air-lib/lambda/parser/src/parser/lexer/errors.rs b/crates/air-lib/lambda/parser/src/parser/lexer/errors.rs index 7ca1bdde..7d639ba6 100644 --- a/crates/air-lib/lambda/parser/src/parser/lexer/errors.rs +++ b/crates/air-lib/lambda/parser/src/parser/lexer/errors.rs @@ -20,7 +20,7 @@ use std::num::ParseIntError; #[derive(ThisError, Debug, Clone, PartialEq, Eq)] pub enum LexerError { - #[error("unexpected symbol for value algebra")] + #[error("unexpected symbol for value accessor")] UnexpectedSymbol(usize, usize), #[error("{2}")] diff --git a/crates/air-lib/lambda/parser/src/parser/lexer/mod.rs b/crates/air-lib/lambda/parser/src/parser/lexer/mod.rs index 2eb95cf2..a3efd597 100644 --- a/crates/air-lib/lambda/parser/src/parser/lexer/mod.rs +++ b/crates/air-lib/lambda/parser/src/parser/lexer/mod.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -mod algebra_lexer; +mod accessors_lexer; mod errors; mod token; mod utils; @@ -22,7 +22,7 @@ mod utils; #[cfg(test)] mod tests; -pub use algebra_lexer::AlgebraLexer; +pub use accessors_lexer::AccessorsLexer; pub use errors::LexerError; pub use token::Token; diff --git a/crates/air-lib/lambda/parser/src/parser/lexer/tests.rs b/crates/air-lib/lambda/parser/src/parser/lexer/tests.rs index df64f21d..0b7bd955 100644 --- a/crates/air-lib/lambda/parser/src/parser/lexer/tests.rs +++ b/crates/air-lib/lambda/parser/src/parser/lexer/tests.rs @@ -14,13 +14,13 @@ * limitations under the License. */ -use super::algebra_lexer::Spanned; -use super::AlgebraLexer; +use super::accessors_lexer::Spanned; +use super::AccessorsLexer; use super::LexerError; use super::Token; fn run_lexer(input: &str) -> Vec, usize, LexerError>> { - let lexer = AlgebraLexer::new(input); + let lexer = AccessorsLexer::new(input); lexer.collect() } @@ -32,7 +32,7 @@ fn array_access() { let expected = vec![ Spanned::Ok((0, Token::Selector, 1)), Spanned::Ok((1, Token::OpenSquareBracket, 2)), - Spanned::Ok((2, Token::ArrayIdx(0), 3)), + Spanned::Ok((2, Token::NumberAccessor(0), 3)), Spanned::Ok((3, Token::CloseSquareBracket, 4)), ]; assert_eq!(actual, expected); @@ -46,7 +46,7 @@ fn field_access() { let actual = run_lexer(&field_access); let expected = vec![ Spanned::Ok((0, Token::Selector, 1)), - Spanned::Ok((1, Token::FieldName(field_name), 1 + field_name.len())), + Spanned::Ok((1, Token::StringAccessor(field_name), 1 + field_name.len())), ]; assert_eq!(actual, expected); } diff --git a/crates/air-lib/lambda/parser/src/parser/lexer/token.rs b/crates/air-lib/lambda/parser/src/parser/lexer/token.rs index 750c860e..bcdfad3f 100644 --- a/crates/air-lib/lambda/parser/src/parser/lexer/token.rs +++ b/crates/air-lib/lambda/parser/src/parser/lexer/token.rs @@ -25,8 +25,8 @@ pub enum Token<'input> { OpenSquareBracket, CloseSquareBracket, - ArrayIdx(u32), - FieldName(&'input str), + NumberAccessor(u32), + StringAccessor(&'input str), // ! FlatteningSign, diff --git a/crates/air-lib/lambda/parser/src/parser/mod.rs b/crates/air-lib/lambda/parser/src/parser/mod.rs index 2bc24999..a2abd959 100644 --- a/crates/air-lib/lambda/parser/src/parser/mod.rs +++ b/crates/air-lib/lambda/parser/src/parser/mod.rs @@ -31,7 +31,7 @@ pub type LambdaParserResult<'input, T> = std::result::Result Vec> { TEST_PARSER.with(|parser| { let mut errors = Vec::new(); - let lexer = crate::parser::AlgebraLexer::new(source_code); + let lexer = crate::parser::AccessorsLexer::new(source_code); parser .parse(source_code, &mut errors, lexer) .expect("parsing should be successful") @@ -35,7 +35,7 @@ fn field_access() { let lambda = format!(".{}", field_name); let actual = parse(&lambda); - let expected = vec![ValueAccessor::FieldAccess { field_name }]; + let expected = vec![ValueAccessor::FieldAccessByName { field_name }]; assert_eq!(actual, expected); } @@ -45,7 +45,7 @@ fn field_access_with_flattening() { let lambda = format!(".{}!", field_name); let actual = parse(&lambda); - let expected = vec![ValueAccessor::FieldAccess { field_name }]; + let expected = vec![ValueAccessor::FieldAccessByName { field_name }]; assert_eq!(actual, expected); } @@ -69,6 +69,26 @@ fn array_access_with_flattening() { assert_eq!(actual, expected); } +#[test] +fn scalar_access() { + let scalar_name = "some_field_name"; + let lambda = format!(".[{}]", scalar_name); + + let actual = parse(&lambda); + let expected = vec![ValueAccessor::FieldAccessByScalar { scalar_name }]; + assert_eq!(actual, expected); +} + +#[test] +fn scalar_access_with_flattening() { + let scalar_name = "some_scalar_name"; + let lambda = format!(".[{}]!", scalar_name); + + let actual = parse(&lambda); + let expected = vec![ValueAccessor::FieldAccessByScalar { scalar_name }]; + assert_eq!(actual, expected); +} + #[test] fn field_array_access() { let field_name = "some_field_name"; @@ -77,7 +97,35 @@ fn field_array_access() { let actual = parse(&lambda); let expected = vec![ - ValueAccessor::FieldAccess { field_name }, + ValueAccessor::FieldAccessByName { field_name }, + ValueAccessor::ArrayAccess { idx }, + ]; + assert_eq!(actual, expected); +} + +#[test] +fn field_scalar_access() { + let field_name = "some_field_name"; + let scalar_name = "some_scalar_name"; + let lambda = format!(".{}.[{}]", field_name, scalar_name); + + let actual = parse(&lambda); + let expected = vec![ + ValueAccessor::FieldAccessByName { field_name }, + ValueAccessor::FieldAccessByScalar { scalar_name }, + ]; + assert_eq!(actual, expected); +} + +#[test] +fn scalar_array_access() { + let scalar_name = "some_scalar_name"; + let idx = 1; + let lambda = format!(".[{}].[{}]", scalar_name, idx); + + let actual = parse(&lambda); + let expected = vec![ + ValueAccessor::FieldAccessByScalar { scalar_name }, ValueAccessor::ArrayAccess { idx }, ]; assert_eq!(actual, expected); @@ -91,7 +139,7 @@ fn field_array_access_without_dot() { let actual = parse(&lambda); let expected = vec![ - ValueAccessor::FieldAccess { field_name }, + ValueAccessor::FieldAccessByName { field_name }, ValueAccessor::ArrayAccess { idx }, ]; assert_eq!(actual, expected); @@ -106,7 +154,21 @@ fn array_field_access() { let actual = parse(&lambda); let expected = vec![ ValueAccessor::ArrayAccess { idx }, - ValueAccessor::FieldAccess { field_name }, + ValueAccessor::FieldAccessByName { field_name }, + ]; + assert_eq!(actual, expected); +} + +#[test] +fn array_scalar_access() { + let scalar_name = "some_scalar_name"; + let idx = 1; + let lambda = format!(".[{}].[{}]", idx, scalar_name); + + let actual = parse(&lambda); + let expected = vec![ + ValueAccessor::ArrayAccess { idx }, + ValueAccessor::FieldAccessByScalar { scalar_name }, ]; assert_eq!(actual, expected); } @@ -122,11 +184,44 @@ fn many_array_field_access() { let actual = parse(&lambda); let expected = vec![ ValueAccessor::ArrayAccess { idx: idx_1 }, - ValueAccessor::FieldAccess { + ValueAccessor::FieldAccessByName { field_name: field_name_1, }, ValueAccessor::ArrayAccess { idx: idx_2 }, - ValueAccessor::FieldAccess { + ValueAccessor::FieldAccessByName { + field_name: field_name_2, + }, + ]; + assert_eq!(actual, expected); +} + +#[test] +fn many_array_field_scalar_access() { + let field_name_1 = "some_field_name_1"; + let field_name_2 = "some_field_name_2"; + let idx_1 = 1; + let idx_2 = u32::MAX; + let scalar_name_1 = "some_scalar_name_1"; + let scalar_name_2 = "some_scalar_name_2"; + let lambda = format!( + ".[{}].[{}].{}.[{}].[{}].{}", + idx_1, scalar_name_1, field_name_1, idx_2, scalar_name_2, field_name_2 + ); + + let actual = parse(&lambda); + let expected = vec![ + ValueAccessor::ArrayAccess { idx: idx_1 }, + ValueAccessor::FieldAccessByScalar { + scalar_name: scalar_name_1, + }, + ValueAccessor::FieldAccessByName { + field_name: field_name_1, + }, + ValueAccessor::ArrayAccess { idx: idx_2 }, + ValueAccessor::FieldAccessByScalar { + scalar_name: scalar_name_2, + }, + ValueAccessor::FieldAccessByName { field_name: field_name_2, }, ]; diff --git a/crates/air-lib/lambda/parser/src/parser/va_lambda.lalrpop b/crates/air-lib/lambda/parser/src/parser/va_lambda.lalrpop index 69c1b4c5..e30f97be 100644 --- a/crates/air-lib/lambda/parser/src/parser/va_lambda.lalrpop +++ b/crates/air-lib/lambda/parser/src/parser/va_lambda.lalrpop @@ -1,4 +1,4 @@ -use crate::ValueAlgebra; +use crate::ValueAccessor; use crate::parser::lexer::LexerError; use crate::parser::lexer::Token; @@ -7,18 +7,22 @@ use lalrpop_util::ErrorRecovery; // the only thing why input matters here is just introducing lifetime for Token grammar<'err, 'input>(input: &'input str, errors: &'err mut Vec, LexerError>>); -pub Lambda: Vec> = => <>; +pub Lambda: Vec> = => <>; -ValueAlgebra: ValueAlgebra<'input> = { - "[" "]" => { - ValueAlgebra::ArrayAccess { idx } +ValueAccessor: ValueAccessor<'input> = { + "[" "]" => { + ValueAccessor::ArrayAccess { idx } }, - "." => { - ValueAlgebra::FieldAccess { field_name } + "[" "]" => { + ValueAccessor::FieldAccessByScalar { scalar_name } }, - ! => { errors.push(<>); ValueAlgebra::Error }, + "." => { + ValueAccessor::FieldAccessByName { field_name } + }, + + ! => { errors.push(<>); ValueAccessor::Error }, } extern { @@ -31,8 +35,8 @@ extern { "[" => Token::OpenSquareBracket, "]" => Token::CloseSquareBracket, - array_idx => Token::ArrayIdx(), - field_name => Token::FieldName(<&'input str>), + number_accessor => Token::NumberAccessor(), + string_accessor => Token::StringAccessor(<&'input str>), "!" => Token::FlatteningSign, } diff --git a/crates/air-lib/lambda/parser/src/parser/va_lambda.rs b/crates/air-lib/lambda/parser/src/parser/va_lambda.rs index c6cb5b7f..d964d7b4 100644 --- a/crates/air-lib/lambda/parser/src/parser/va_lambda.rs +++ b/crates/air-lib/lambda/parser/src/parser/va_lambda.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.19.6" -// sha3: db7b23bede3d6914e4bbadd2b1df6f44d50b164a9c2ed557274f415fc6b1d5 +// sha3: 517c7e1bd341e1434f9ffcbf3c72151e4b928e7befd38c6ee2e3e734565b use crate::ValueAccessor; use crate::parser::lexer::LexerError; use crate::parser::lexer::Token; @@ -46,33 +46,45 @@ mod __parse__Lambda { // State 2 0, 0, 0, 0, 0, 0, 0, // State 3 - 0, -16, -16, 0, 0, 0, -16, + 0, -20, -20, 0, 0, 0, -20, // State 4 0, 0, 9, 0, 0, 10, 0, // State 5 - 0, 0, 0, 0, 11, 0, 0, + 0, 0, 0, 0, 11, 12, 0, // State 6 - 0, -13, -13, 0, 0, 0, -13, - // State 7 0, -17, -17, 0, 0, 0, -17, + // State 7 + 0, -21, -21, 0, 0, 0, -21, // State 8 - 0, 0, 0, 0, 12, 0, 0, + 0, 0, 0, 0, 13, 14, 0, // State 9 - 13, -12, -12, 0, 0, 0, -12, + 15, -16, -16, 0, 0, 0, -16, // State 10 - 0, 0, 0, 14, 0, 0, 0, + 0, 0, 0, 16, 0, 0, 0, // State 11 - 0, 0, 0, 15, 0, 0, 0, + 0, 0, 0, 17, 0, 0, 0, // State 12 - 0, -11, -11, 0, 0, 0, -11, + 0, 0, 0, 18, 0, 0, 0, // State 13 - 16, -10, -10, 0, 0, 0, -10, + 0, 0, 0, 19, 0, 0, 0, // State 14 - 17, -9, -9, 0, 0, 0, -9, + 0, -15, -15, 0, 0, 0, -15, // State 15 - 0, -8, -8, 0, 0, 0, -8, + 20, -10, -10, 0, 0, 0, -10, // State 16 + 21, -14, -14, 0, 0, 0, -14, + // State 17 + 22, -9, -9, 0, 0, 0, -9, + // State 18 + 23, -13, -13, 0, 0, 0, -13, + // State 19 + 0, -8, -8, 0, 0, 0, -8, + // State 20 + 0, -12, -12, 0, 0, 0, -12, + // State 21 0, -7, -7, 0, 0, 0, -7, + // State 22 + 0, -11, -11, 0, 0, 0, -11, ]; fn __action(state: i8, integer: usize) -> i8 { __ACTION[(state as usize) * 7 + integer] @@ -83,35 +95,47 @@ mod __parse__Lambda { // State 1 -6, // State 2 - -18, + -22, // State 3 - -16, + -20, // State 4 0, // State 5 0, // State 6 - -13, - // State 7 -17, + // State 7 + -21, // State 8 0, // State 9 - -12, + -16, // State 10 0, // State 11 0, // State 12 - -11, + 0, // State 13 - -10, + 0, // State 14 - -9, + -15, // State 15 - -8, + -10, // State 16 + -14, + // State 17 + -9, + // State 18 + -13, + // State 19 + -8, + // State 20 + -12, + // State 21 -7, + // State 22 + -11, ]; fn __goto(state: i8, nt: usize) -> i8 { match nt { @@ -130,8 +154,8 @@ mod __parse__Lambda { r###"".""###, r###""[""###, r###""]""###, - r###"array_idx"###, - r###"field_name"###, + r###"number_accessor"###, + r###"string_accessor"###, ]; __TERMINAL.iter().enumerate().filter_map(|(index, terminal)| { let next_state = __action(__state, index); @@ -254,8 +278,8 @@ mod __parse__Lambda { Token::Selector if true => Some(1), Token::OpenSquareBracket if true => Some(2), Token::CloseSquareBracket if true => Some(3), - Token::ArrayIdx(_) if true => Some(4), - Token::FieldName(_) if true => Some(5), + Token::NumberAccessor(_) if true => Some(4), + Token::StringAccessor(_) if true => Some(5), _ => None, } } @@ -271,11 +295,11 @@ mod __parse__Lambda { match __token_index { 0 | 1 | 2 | 3 => __Symbol::Variant0(__token), 4 => match __token { - Token::ArrayIdx(__tok0) if true => __Symbol::Variant1(__tok0), + Token::NumberAccessor(__tok0) if true => __Symbol::Variant1(__tok0), _ => unreachable!(), }, 5 => match __token { - Token::FieldName(__tok0) if true => __Symbol::Variant2(__tok0), + Token::StringAccessor(__tok0) if true => __Symbol::Variant2(__tok0), _ => unreachable!(), }, _ => unreachable!(), @@ -354,47 +378,71 @@ mod __parse__Lambda { } 10 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, + states_to_pop: 5, nonterminal_produced: 3, } } 11 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, + states_to_pop: 4, nonterminal_produced: 3, } } 12 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 4, nonterminal_produced: 3, } } 13 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 3, + nonterminal_produced: 3, + } + } + 14 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 3, + nonterminal_produced: 3, + } + } + 15 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 2, + nonterminal_produced: 3, + } + } + 16 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 1, + nonterminal_produced: 3, + } + } + 17 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 4, } } - 14 => { + 18 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 4, } } - 15 => { + 19 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 5, } } - 16 => { + 20 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 5, } } - 17 => __state_machine::SimulatedReduce::Accept, + 21 => __state_machine::SimulatedReduce::Accept, _ => panic!("invalid reduction index {}", __reduce_index) } } @@ -536,6 +584,18 @@ mod __parse__Lambda { __reduce16(input, errors, __lookahead_start, __symbols, core::marker::PhantomData::<(&(), &())>) } 17 => { + __reduce17(input, errors, __lookahead_start, __symbols, core::marker::PhantomData::<(&(), &())>) + } + 18 => { + __reduce18(input, errors, __lookahead_start, __symbols, core::marker::PhantomData::<(&(), &())>) + } + 19 => { + __reduce19(input, errors, __lookahead_start, __symbols, core::marker::PhantomData::<(&(), &())>) + } + 20 => { + __reduce20(input, errors, __lookahead_start, __symbols, core::marker::PhantomData::<(&(), &())>) + } + 21 => { // __Lambda = Lambda => ActionFn(0); let __sym0 = __pop_Variant5(__symbols); let __start = __sym0.0.clone(); @@ -655,11 +715,11 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // "!"? = "!" => ActionFn(5); + // "!"? = "!" => ActionFn(6); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); - let __nt = super::__action5::<>(input, errors, __sym0); + let __nt = super::__action6::<>(input, errors, __sym0); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (1, 0) } @@ -674,10 +734,10 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // "!"? = => ActionFn(6); + // "!"? = => ActionFn(7); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action6::<>(input, errors, &__start, &__end); + let __nt = super::__action7::<>(input, errors, &__start, &__end); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (0, 0) } @@ -692,11 +752,11 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // "."? = "." => ActionFn(7); + // "."? = "." => ActionFn(8); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); - let __nt = super::__action7::<>(input, errors, __sym0); + let __nt = super::__action8::<>(input, errors, __sym0); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (1, 1) } @@ -711,10 +771,10 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // "."? = => ActionFn(8); + // "."? = => ActionFn(9); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action8::<>(input, errors, &__start, &__end); + let __nt = super::__action9::<>(input, errors, &__start, &__end); __symbols.push((__start, __Symbol::Variant4(__nt), __end)); (0, 1) } @@ -729,10 +789,10 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // Lambda = => ActionFn(21); + // Lambda = => ActionFn(28); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action21::<>(input, errors, &__start, &__end); + let __nt = super::__action28::<>(input, errors, &__start, &__end); __symbols.push((__start, __Symbol::Variant5(__nt), __end)); (0, 2) } @@ -747,11 +807,11 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // Lambda = ValueAccessor+ => ActionFn(22); + // Lambda = ValueAccessor+ => ActionFn(29); let __sym0 = __pop_Variant7(__symbols); let __start = __sym0.0.clone(); let __end = __sym0.2.clone(); - let __nt = super::__action22::<>(input, errors, __sym0); + let __nt = super::__action29::<>(input, errors, __sym0); __symbols.push((__start, __Symbol::Variant5(__nt), __end)); (1, 2) } @@ -766,7 +826,7 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor = ".", "[", array_idx, "]", "!" => ActionFn(17); + // ValueAccessor = ".", "[", number_accessor, "]", "!" => ActionFn(20); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -775,7 +835,7 @@ mod __parse__Lambda { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym4.2.clone(); - let __nt = super::__action17::<>(input, errors, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action20::<>(input, errors, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (5, 3) } @@ -790,7 +850,7 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor = "[", array_idx, "]", "!" => ActionFn(18); + // ValueAccessor = "[", number_accessor, "]", "!" => ActionFn(21); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -798,7 +858,7 @@ mod __parse__Lambda { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); - let __nt = super::__action18::<>(input, errors, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action21::<>(input, errors, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (4, 3) } @@ -813,7 +873,7 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor = ".", "[", array_idx, "]" => ActionFn(19); + // ValueAccessor = ".", "[", number_accessor, "]" => ActionFn(22); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant1(__symbols); @@ -821,7 +881,7 @@ mod __parse__Lambda { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym3.2.clone(); - let __nt = super::__action19::<>(input, errors, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action22::<>(input, errors, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (4, 3) } @@ -836,14 +896,14 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor = "[", array_idx, "]" => ActionFn(20); + // ValueAccessor = "[", number_accessor, "]" => ActionFn(23); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant1(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); let __end = __sym2.2.clone(); - let __nt = super::__action20::<>(input, errors, __sym0, __sym1, __sym2); + let __nt = super::__action23::<>(input, errors, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); (3, 3) } @@ -858,16 +918,18 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor = ".", field_name, "!" => ActionFn(15); - assert!(__symbols.len() >= 3); - let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant2(__symbols); + // ValueAccessor = ".", "[", string_accessor, "]", "!" => ActionFn(24); + assert!(__symbols.len() >= 5); + let __sym4 = __pop_Variant0(__symbols); + let __sym3 = __pop_Variant0(__symbols); + let __sym2 = __pop_Variant2(__symbols); + let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); - let __end = __sym2.2.clone(); - let __nt = super::__action15::<>(input, errors, __sym0, __sym1, __sym2); + let __end = __sym4.2.clone(); + let __nt = super::__action24::<>(input, errors, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); - (3, 3) + (5, 3) } pub(crate) fn __reduce11< 'err, @@ -880,15 +942,17 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor = ".", field_name => ActionFn(16); - assert!(__symbols.len() >= 2); + // ValueAccessor = "[", string_accessor, "]", "!" => ActionFn(25); + assert!(__symbols.len() >= 4); + let __sym3 = __pop_Variant0(__symbols); + let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant2(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); - let __end = __sym1.2.clone(); - let __nt = super::__action16::<>(input, errors, __sym0, __sym1); + let __end = __sym3.2.clone(); + let __nt = super::__action25::<>(input, errors, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); - (2, 3) + (4, 3) } pub(crate) fn __reduce12< 'err, @@ -901,13 +965,17 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor = error => ActionFn(4); - let __sym0 = __pop_Variant3(__symbols); + // ValueAccessor = ".", "[", string_accessor, "]" => ActionFn(26); + assert!(__symbols.len() >= 4); + let __sym3 = __pop_Variant0(__symbols); + let __sym2 = __pop_Variant2(__symbols); + let __sym1 = __pop_Variant0(__symbols); + let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); - let __end = __sym0.2.clone(); - let __nt = super::__action4::<>(input, errors, __sym0); + let __end = __sym3.2.clone(); + let __nt = super::__action26::<>(input, errors, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant6(__nt), __end)); - (1, 3) + (4, 3) } pub(crate) fn __reduce13< 'err, @@ -920,12 +988,16 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor* = => ActionFn(9); - let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); - let __end = __start.clone(); - let __nt = super::__action9::<>(input, errors, &__start, &__end); - __symbols.push((__start, __Symbol::Variant7(__nt), __end)); - (0, 4) + // ValueAccessor = "[", string_accessor, "]" => ActionFn(27); + assert!(__symbols.len() >= 3); + let __sym2 = __pop_Variant0(__symbols); + let __sym1 = __pop_Variant2(__symbols); + let __sym0 = __pop_Variant0(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym2.2.clone(); + let __nt = super::__action27::<>(input, errors, __sym0, __sym1, __sym2); + __symbols.push((__start, __Symbol::Variant6(__nt), __end)); + (3, 3) } pub(crate) fn __reduce14< 'err, @@ -938,13 +1010,16 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor* = ValueAccessor+ => ActionFn(10); - let __sym0 = __pop_Variant7(__symbols); + // ValueAccessor = ".", string_accessor, "!" => ActionFn(18); + assert!(__symbols.len() >= 3); + let __sym2 = __pop_Variant0(__symbols); + let __sym1 = __pop_Variant2(__symbols); + let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); - let __end = __sym0.2.clone(); - let __nt = super::__action10::<>(input, errors, __sym0); - __symbols.push((__start, __Symbol::Variant7(__nt), __end)); - (1, 4) + let __end = __sym2.2.clone(); + let __nt = super::__action18::<>(input, errors, __sym0, __sym1, __sym2); + __symbols.push((__start, __Symbol::Variant6(__nt), __end)); + (3, 3) } pub(crate) fn __reduce15< 'err, @@ -957,13 +1032,15 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor+ = ValueAccessor => ActionFn(11); - let __sym0 = __pop_Variant6(__symbols); + // ValueAccessor = ".", string_accessor => ActionFn(19); + assert!(__symbols.len() >= 2); + let __sym1 = __pop_Variant2(__symbols); + let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0.clone(); - let __end = __sym0.2.clone(); - let __nt = super::__action11::<>(input, errors, __sym0); - __symbols.push((__start, __Symbol::Variant7(__nt), __end)); - (1, 5) + let __end = __sym1.2.clone(); + let __nt = super::__action19::<>(input, errors, __sym0, __sym1); + __symbols.push((__start, __Symbol::Variant6(__nt), __end)); + (2, 3) } pub(crate) fn __reduce16< 'err, @@ -976,13 +1053,88 @@ mod __parse__Lambda { _: core::marker::PhantomData<(&'err (), &'input ())>, ) -> (usize, usize) { - // ValueAccessor+ = ValueAccessor+, ValueAccessor => ActionFn(12); + // ValueAccessor = error => ActionFn(5); + let __sym0 = __pop_Variant3(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action5::<>(input, errors, __sym0); + __symbols.push((__start, __Symbol::Variant6(__nt), __end)); + (1, 3) + } + pub(crate) fn __reduce17< + 'err, + 'input, + >( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __lookahead_start: Option<&usize>, + __symbols: &mut alloc::vec::Vec<(usize,__Symbol<'input>,usize)>, + _: core::marker::PhantomData<(&'err (), &'input ())>, + ) -> (usize, usize) + { + // ValueAccessor* = => ActionFn(10); + let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); + let __end = __start.clone(); + let __nt = super::__action10::<>(input, errors, &__start, &__end); + __symbols.push((__start, __Symbol::Variant7(__nt), __end)); + (0, 4) + } + pub(crate) fn __reduce18< + 'err, + 'input, + >( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __lookahead_start: Option<&usize>, + __symbols: &mut alloc::vec::Vec<(usize,__Symbol<'input>,usize)>, + _: core::marker::PhantomData<(&'err (), &'input ())>, + ) -> (usize, usize) + { + // ValueAccessor* = ValueAccessor+ => ActionFn(11); + let __sym0 = __pop_Variant7(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action11::<>(input, errors, __sym0); + __symbols.push((__start, __Symbol::Variant7(__nt), __end)); + (1, 4) + } + pub(crate) fn __reduce19< + 'err, + 'input, + >( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __lookahead_start: Option<&usize>, + __symbols: &mut alloc::vec::Vec<(usize,__Symbol<'input>,usize)>, + _: core::marker::PhantomData<(&'err (), &'input ())>, + ) -> (usize, usize) + { + // ValueAccessor+ = ValueAccessor => ActionFn(12); + let __sym0 = __pop_Variant6(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action12::<>(input, errors, __sym0); + __symbols.push((__start, __Symbol::Variant7(__nt), __end)); + (1, 5) + } + pub(crate) fn __reduce20< + 'err, + 'input, + >( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __lookahead_start: Option<&usize>, + __symbols: &mut alloc::vec::Vec<(usize,__Symbol<'input>,usize)>, + _: core::marker::PhantomData<(&'err (), &'input ())>, + ) -> (usize, usize) + { + // ValueAccessor+ = ValueAccessor+, ValueAccessor => ActionFn(13); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant7(__symbols); let __start = __sym0.0.clone(); let __end = __sym1.2.clone(); - let __nt = super::__action12::<>(input, errors, __sym0, __sym1); + let __nt = super::__action13::<>(input, errors, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant7(__nt), __end)); (2, 5) } @@ -1038,6 +1190,25 @@ fn __action2< fn __action3< 'err, 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + (_, maybe_dot_selector, _): (usize, core::option::Option>, usize), + (_, _, _): (usize, Token<'input>, usize), + (_, scalar_name, _): (usize, &'input str, usize), + (_, _, _): (usize, Token<'input>, usize), + (_, maybe_flatten_sign, _): (usize, core::option::Option>, usize), +) -> ValueAccessor<'input> +{ + { + ValueAccessor::FieldAccessByScalar { scalar_name } + } +} + +#[allow(unused_variables)] +fn __action4< + 'err, + 'input, >( input: &'input str, errors: &'err mut Vec, LexerError>>, @@ -1047,12 +1218,12 @@ fn __action3< ) -> ValueAccessor<'input> { { - ValueAccessor::FieldAccess { field_name } + ValueAccessor::FieldAccessByName { field_name } } } #[allow(unused_variables)] -fn __action4< +fn __action5< 'err, 'input, >( @@ -1065,7 +1236,7 @@ fn __action4< } #[allow(unused_variables)] -fn __action5< +fn __action6< 'err, 'input, >( @@ -1077,24 +1248,24 @@ fn __action5< Some(__0) } -#[allow(unused_variables)] -fn __action6< - 'err, - 'input, ->( - input: &'input str, - errors: &'err mut Vec, LexerError>>, - __lookbehind: &usize, - __lookahead: &usize, -) -> core::option::Option> -{ - None -} - #[allow(unused_variables)] fn __action7< 'err, 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __lookbehind: &usize, + __lookahead: &usize, +) -> core::option::Option> +{ + None +} + +#[allow(unused_variables)] +fn __action8< + 'err, + 'input, >( input: &'input str, errors: &'err mut Vec, LexerError>>, @@ -1105,7 +1276,7 @@ fn __action7< } #[allow(unused_variables)] -fn __action8< +fn __action9< 'err, 'input, >( @@ -1119,7 +1290,7 @@ fn __action8< } #[allow(unused_variables)] -fn __action9< +fn __action10< 'err, 'input, >( @@ -1133,7 +1304,7 @@ fn __action9< } #[allow(unused_variables)] -fn __action10< +fn __action11< 'err, 'input, >( @@ -1146,7 +1317,7 @@ fn __action10< } #[allow(unused_variables)] -fn __action11< +fn __action12< 'err, 'input, >( @@ -1159,7 +1330,7 @@ fn __action11< } #[allow(unused_variables)] -fn __action12< +fn __action13< 'err, 'input, >( @@ -1173,7 +1344,7 @@ fn __action12< } #[allow(unused_variables)] -fn __action13< +fn __action14< 'err, 'input, >( @@ -1188,43 +1359,10 @@ fn __action13< { let __start0 = __4.0.clone(); let __end0 = __4.2.clone(); - let __temp0 = __action5( - input, - errors, - __4, - ); - let __temp0 = (__start0, __temp0, __end0); - __action2( - input, - errors, - __0, - __1, - __2, - __3, - __temp0, - ) -} - -#[allow(unused_variables)] -fn __action14< - 'err, - 'input, ->( - input: &'input str, - errors: &'err mut Vec, LexerError>>, - __0: (usize, core::option::Option>, usize), - __1: (usize, Token<'input>, usize), - __2: (usize, u32, usize), - __3: (usize, Token<'input>, usize), -) -> ValueAccessor<'input> -{ - let __start0 = __3.2.clone(); - let __end0 = __3.2.clone(); let __temp0 = __action6( input, errors, - &__start0, - &__end0, + __4, ); let __temp0 = (__start0, __temp0, __end0); __action2( @@ -1245,24 +1383,28 @@ fn __action15< >( input: &'input str, errors: &'err mut Vec, LexerError>>, - __0: (usize, Token<'input>, usize), - __1: (usize, &'input str, usize), - __2: (usize, Token<'input>, usize), + __0: (usize, core::option::Option>, usize), + __1: (usize, Token<'input>, usize), + __2: (usize, u32, usize), + __3: (usize, Token<'input>, usize), ) -> ValueAccessor<'input> { - let __start0 = __2.0.clone(); - let __end0 = __2.2.clone(); - let __temp0 = __action5( + let __start0 = __3.2.clone(); + let __end0 = __3.2.clone(); + let __temp0 = __action7( input, errors, - __2, + &__start0, + &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action3( + __action2( input, errors, __0, __1, + __2, + __3, __temp0, ) } @@ -1274,13 +1416,48 @@ fn __action16< >( input: &'input str, errors: &'err mut Vec, LexerError>>, - __0: (usize, Token<'input>, usize), - __1: (usize, &'input str, usize), + __0: (usize, core::option::Option>, usize), + __1: (usize, Token<'input>, usize), + __2: (usize, &'input str, usize), + __3: (usize, Token<'input>, usize), + __4: (usize, Token<'input>, usize), ) -> ValueAccessor<'input> { - let __start0 = __1.2.clone(); - let __end0 = __1.2.clone(); + let __start0 = __4.0.clone(); + let __end0 = __4.2.clone(); let __temp0 = __action6( + input, + errors, + __4, + ); + let __temp0 = (__start0, __temp0, __end0); + __action3( + input, + errors, + __0, + __1, + __2, + __3, + __temp0, + ) +} + +#[allow(unused_variables)] +fn __action17< + 'err, + 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __0: (usize, core::option::Option>, usize), + __1: (usize, Token<'input>, usize), + __2: (usize, &'input str, usize), + __3: (usize, Token<'input>, usize), +) -> ValueAccessor<'input> +{ + let __start0 = __3.2.clone(); + let __end0 = __3.2.clone(); + let __temp0 = __action7( input, errors, &__start0, @@ -1292,12 +1469,72 @@ fn __action16< errors, __0, __1, + __2, + __3, __temp0, ) } #[allow(unused_variables)] -fn __action17< +fn __action18< + 'err, + 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __0: (usize, Token<'input>, usize), + __1: (usize, &'input str, usize), + __2: (usize, Token<'input>, usize), +) -> ValueAccessor<'input> +{ + let __start0 = __2.0.clone(); + let __end0 = __2.2.clone(); + let __temp0 = __action6( + input, + errors, + __2, + ); + let __temp0 = (__start0, __temp0, __end0); + __action4( + input, + errors, + __0, + __1, + __temp0, + ) +} + +#[allow(unused_variables)] +fn __action19< + 'err, + 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __0: (usize, Token<'input>, usize), + __1: (usize, &'input str, usize), +) -> ValueAccessor<'input> +{ + let __start0 = __1.2.clone(); + let __end0 = __1.2.clone(); + let __temp0 = __action7( + input, + errors, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action4( + input, + errors, + __0, + __1, + __temp0, + ) +} + +#[allow(unused_variables)] +fn __action20< 'err, 'input, >( @@ -1312,13 +1549,13 @@ fn __action17< { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); - let __temp0 = __action7( + let __temp0 = __action8( input, errors, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action13( + __action14( input, errors, __temp0, @@ -1330,7 +1567,7 @@ fn __action17< } #[allow(unused_variables)] -fn __action18< +fn __action21< 'err, 'input, >( @@ -1344,14 +1581,14 @@ fn __action18< { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); - let __temp0 = __action8( + let __temp0 = __action9( input, errors, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action13( + __action14( input, errors, __temp0, @@ -1363,7 +1600,7 @@ fn __action18< } #[allow(unused_variables)] -fn __action19< +fn __action22< 'err, 'input, >( @@ -1377,13 +1614,13 @@ fn __action19< { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); - let __temp0 = __action7( + let __temp0 = __action8( input, errors, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action14( + __action15( input, errors, __temp0, @@ -1394,7 +1631,7 @@ fn __action19< } #[allow(unused_variables)] -fn __action20< +fn __action23< 'err, 'input, >( @@ -1407,14 +1644,14 @@ fn __action20< { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); - let __temp0 = __action8( + let __temp0 = __action9( input, errors, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action14( + __action15( input, errors, __temp0, @@ -1425,7 +1662,135 @@ fn __action20< } #[allow(unused_variables)] -fn __action21< +fn __action24< + 'err, + 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __0: (usize, Token<'input>, usize), + __1: (usize, Token<'input>, usize), + __2: (usize, &'input str, usize), + __3: (usize, Token<'input>, usize), + __4: (usize, Token<'input>, usize), +) -> ValueAccessor<'input> +{ + let __start0 = __0.0.clone(); + let __end0 = __0.2.clone(); + let __temp0 = __action8( + input, + errors, + __0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action16( + input, + errors, + __temp0, + __1, + __2, + __3, + __4, + ) +} + +#[allow(unused_variables)] +fn __action25< + 'err, + 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __0: (usize, Token<'input>, usize), + __1: (usize, &'input str, usize), + __2: (usize, Token<'input>, usize), + __3: (usize, Token<'input>, usize), +) -> ValueAccessor<'input> +{ + let __start0 = __0.0.clone(); + let __end0 = __0.0.clone(); + let __temp0 = __action9( + input, + errors, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action16( + input, + errors, + __temp0, + __0, + __1, + __2, + __3, + ) +} + +#[allow(unused_variables)] +fn __action26< + 'err, + 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __0: (usize, Token<'input>, usize), + __1: (usize, Token<'input>, usize), + __2: (usize, &'input str, usize), + __3: (usize, Token<'input>, usize), +) -> ValueAccessor<'input> +{ + let __start0 = __0.0.clone(); + let __end0 = __0.2.clone(); + let __temp0 = __action8( + input, + errors, + __0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action17( + input, + errors, + __temp0, + __1, + __2, + __3, + ) +} + +#[allow(unused_variables)] +fn __action27< + 'err, + 'input, +>( + input: &'input str, + errors: &'err mut Vec, LexerError>>, + __0: (usize, Token<'input>, usize), + __1: (usize, &'input str, usize), + __2: (usize, Token<'input>, usize), +) -> ValueAccessor<'input> +{ + let __start0 = __0.0.clone(); + let __end0 = __0.0.clone(); + let __temp0 = __action9( + input, + errors, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action17( + input, + errors, + __temp0, + __0, + __1, + __2, + ) +} + +#[allow(unused_variables)] +fn __action28< 'err, 'input, >( @@ -1437,7 +1802,7 @@ fn __action21< { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); - let __temp0 = __action9( + let __temp0 = __action10( input, errors, &__start0, @@ -1452,7 +1817,7 @@ fn __action21< } #[allow(unused_variables)] -fn __action22< +fn __action29< 'err, 'input, >( @@ -1463,7 +1828,7 @@ fn __action22< { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); - let __temp0 = __action10( + let __temp0 = __action11( input, errors, __0,