mirror of
https://github.com/fluencelabs/aquavm
synced 2025-03-15 12:30:50 +00:00
support empty array literal in fold (#230)
This commit is contained in:
parent
c00b453a48
commit
a64a4fc0a6
@ -24,14 +24,21 @@ use crate::joinable;
|
||||
use crate::log_instruction;
|
||||
|
||||
use air_parser::ast::FoldScalar;
|
||||
use air_parser::ast::FoldScalarIterable;
|
||||
use air_parser::ast::Instruction;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
impl<'i> ExecutableInstruction<'i> for FoldScalar<'i> {
|
||||
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> {
|
||||
log_instruction!(fold, exec_ctx, trace_ctx);
|
||||
|
||||
let scalar_iterable = joinable!(construct_scalar_iterable_value(&self.iterable, exec_ctx), exec_ctx)?;
|
||||
let scalar = match &self.iterable {
|
||||
FoldScalarIterable::Scalar(scalar) => scalar,
|
||||
// just do nothing on an empty array
|
||||
FoldScalarIterable::EmptyArray => return Ok(()),
|
||||
};
|
||||
let scalar_iterable = joinable!(construct_scalar_iterable_value(scalar, exec_ctx), exec_ctx)?;
|
||||
|
||||
match scalar_iterable {
|
||||
// just exit on empty iterable
|
||||
|
@ -163,7 +163,7 @@ fn inner_fold_with_same_iterator() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_fold() {
|
||||
fn empty_iterable_fold() {
|
||||
let mut vm = create_avm(echo_call_service(), "A");
|
||||
let mut set_variable_vm = create_avm(set_variable_call_service(json!([])), "set_variable");
|
||||
|
||||
@ -188,6 +188,24 @@ fn empty_fold() {
|
||||
assert_eq!(actual_trace[0], expected_state);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_literal_array_fold() {
|
||||
let mut vm = create_avm(echo_call_service(), "A");
|
||||
|
||||
let empty_fold = r#"
|
||||
(fold [] i
|
||||
(seq
|
||||
(call "A" ("" "") [i] $acc)
|
||||
(next i)
|
||||
)
|
||||
)"#;
|
||||
|
||||
let result = checked_call_vm!(vm, "", empty_fold, "", "");
|
||||
let actual_trace = trace_from_result(&result);
|
||||
|
||||
assert!(actual_trace.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_fold_json_path() {
|
||||
let mut vm = create_avm(echo_call_service(), "A");
|
||||
|
@ -92,3 +92,10 @@ pub enum Number {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub enum FoldScalarIterable<'i> {
|
||||
#[serde(borrow)]
|
||||
Scalar(ScalarWithLambda<'i>),
|
||||
EmptyArray,
|
||||
}
|
||||
|
@ -117,6 +117,17 @@ impl fmt::Display for Number {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FoldScalarIterable<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use FoldScalarIterable::*;
|
||||
|
||||
match self {
|
||||
Scalar(variable) => write!(f, "{}", variable),
|
||||
EmptyArray => write!(f, "[]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Number> for serde_json::Value {
|
||||
fn from(number: Number) -> Self {
|
||||
(&number).into()
|
||||
|
@ -99,7 +99,8 @@ pub enum Fail<'i> {
|
||||
/// (fold scalar_iterable iterator instruction)
|
||||
#[derive(Serialize, Debug, PartialEq)]
|
||||
pub struct FoldScalar<'i> {
|
||||
pub iterable: ScalarWithLambda<'i>,
|
||||
#[serde(borrow)]
|
||||
pub iterable: FoldScalarIterable<'i>,
|
||||
#[serde(borrow)]
|
||||
pub iterator: Scalar<'i>,
|
||||
pub instruction: Rc<Instruction<'i>>,
|
||||
|
@ -93,7 +93,7 @@ impl<'i> MisMatch<'i> {
|
||||
|
||||
impl<'i> FoldScalar<'i> {
|
||||
pub fn new(
|
||||
iterable: ScalarWithLambda<'i>,
|
||||
iterable: FoldScalarIterable<'i>,
|
||||
iterator: Scalar<'i>,
|
||||
instruction: Instruction<'i>,
|
||||
span: Span,
|
||||
|
@ -147,9 +147,10 @@ FailBody: Fail<'input> = {
|
||||
}
|
||||
}
|
||||
|
||||
FoldScalarIterable: ScalarWithLambda<'input> = {
|
||||
<scalar:Scalar> => ScalarWithLambda::new(scalar.0, None, scalar.1),
|
||||
<scalar:ScalarWithLambda> => ScalarWithLambda::new(scalar.0, Some(scalar.1), scalar.2),
|
||||
FoldScalarIterable: FoldScalarIterable<'input> = {
|
||||
<scalar:Scalar> => FoldScalarIterable::Scalar(ScalarWithLambda::new(scalar.0, None, scalar.1)),
|
||||
<scalar:ScalarWithLambda> => FoldScalarIterable::Scalar(ScalarWithLambda::new(scalar.0, Some(scalar.1), scalar.2)),
|
||||
"[" "]" => FoldScalarIterable::EmptyArray,
|
||||
};
|
||||
|
||||
Function = CallInstrValue;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -84,16 +84,29 @@ pub(super) fn fail_last_error() -> Instruction<'static> {
|
||||
Instruction::Fail(Fail::LastError)
|
||||
}
|
||||
|
||||
pub(super) fn fold_scalar<'i>(
|
||||
iterable: ScalarWithLambda<'i>,
|
||||
pub(super) fn fold_scalar_variable<'i>(
|
||||
scalar: ScalarWithLambda<'i>,
|
||||
iterator: Scalar<'i>,
|
||||
instruction: Instruction<'i>,
|
||||
span: Span,
|
||||
) -> Instruction<'i> {
|
||||
Instruction::FoldScalar(FoldScalar {
|
||||
iterable,
|
||||
iterable: FoldScalarIterable::Scalar(scalar),
|
||||
iterator,
|
||||
instruction: std::rc::Rc::new(instruction),
|
||||
instruction: Rc::new(instruction),
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn fold_scalar_empty_array<'i>(
|
||||
iterator: Scalar<'i>,
|
||||
instruction: Instruction<'i>,
|
||||
span: Span,
|
||||
) -> Instruction<'i> {
|
||||
Instruction::FoldScalar(FoldScalar {
|
||||
iterable: FoldScalarIterable::EmptyArray,
|
||||
iterator,
|
||||
instruction: Rc::new(instruction),
|
||||
span,
|
||||
})
|
||||
}
|
||||
@ -107,7 +120,7 @@ pub(super) fn fold_stream<'i>(
|
||||
Instruction::FoldStream(FoldStream {
|
||||
iterable,
|
||||
iterator,
|
||||
instruction: std::rc::Rc::new(instruction),
|
||||
instruction: Rc::new(instruction),
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ fn parse_fold() {
|
||||
)
|
||||
"#;
|
||||
let instruction = parse(&source_code);
|
||||
let expected = fold_scalar(
|
||||
let expected = fold_scalar_variable(
|
||||
ScalarWithLambda::new("iterable", None, 15),
|
||||
Scalar::new("i", 24),
|
||||
null(),
|
||||
@ -168,7 +168,7 @@ fn fold_json_path() {
|
||||
"#;
|
||||
|
||||
let instruction = parse(source_code);
|
||||
let expected = fold_scalar(
|
||||
let expected = fold_scalar_variable(
|
||||
ScalarWithLambda::from_raw_lambda(
|
||||
"members",
|
||||
vec![ValueAccessor::ArrayAccess { idx: 123321 }],
|
||||
@ -181,6 +181,19 @@ fn fold_json_path() {
|
||||
assert_eq!(instruction, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fold_empty_array_iterable() {
|
||||
let source_code = r#"
|
||||
(fold [] m
|
||||
(null)
|
||||
)
|
||||
"#;
|
||||
|
||||
let instruction = parse(source_code);
|
||||
let expected = fold_scalar_empty_array(Scalar::new("m", 18), null(), Span::new(9, 48));
|
||||
assert_eq!(instruction, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fold_on_stream() {
|
||||
let source_code = r#"
|
||||
@ -205,7 +218,7 @@ fn comments() {
|
||||
;;; comme;?!.$. nt[][][][()()()null;$::!
|
||||
"#;
|
||||
let instruction = parse(source_code);
|
||||
let expected = fold_scalar(
|
||||
let expected = fold_scalar_variable(
|
||||
ScalarWithLambda::from_raw_lambda(
|
||||
"members",
|
||||
vec![
|
||||
@ -234,7 +247,7 @@ fn parse_fold_with_xor_par_seq() {
|
||||
let source_code = source_fold_with(name);
|
||||
let instruction = parse(&source_code);
|
||||
let instr = binary_instruction(*name);
|
||||
let expected = fold_scalar(
|
||||
let expected = fold_scalar_variable(
|
||||
ScalarWithLambda::new("iterable", None, 6),
|
||||
Scalar::new("i", 15),
|
||||
instr(null(), null()),
|
||||
|
@ -83,7 +83,12 @@ impl<'i> VariableValidator<'i> {
|
||||
}
|
||||
|
||||
pub(super) fn met_fold_scalar(&mut self, fold: &FoldScalar<'i>, span: Span) {
|
||||
self.met_variable_name(fold.iterable.name, span);
|
||||
use FoldScalarIterable::*;
|
||||
|
||||
match &fold.iterable {
|
||||
Scalar(variable) => self.met_variable_name(variable.name, span),
|
||||
EmptyArray => {}
|
||||
};
|
||||
self.met_iterator_definition(&fold.iterator, span);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user