mirror of
https://github.com/fluencelabs/aquavm
synced 2024-12-04 23:20:18 +00:00
Introduce mismatch (#62)
This commit is contained in:
parent
611bee0836
commit
709b5e0a52
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -57,7 +57,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aquamarine"
|
name = "aquamarine"
|
||||||
version = "0.3.0"
|
version = "0.4.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fluence",
|
"fluence",
|
||||||
"log",
|
"log",
|
||||||
@ -1693,7 +1693,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stepper-lib"
|
name = "stepper-lib"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"air-parser",
|
"air-parser",
|
||||||
"aqua-test-utils",
|
"aqua-test-utils",
|
||||||
|
@ -31,7 +31,15 @@ Instr: Box<Instruction<'input>> = {
|
|||||||
|
|
||||||
"(" xor <l:Instr> <r:Instr> ")" => Box::new(Instruction::Xor(Xor(l, r))),
|
"(" xor <l:Instr> <r:Instr> ")" => Box::new(Instruction::Xor(Xor(l, r))),
|
||||||
|
|
||||||
"(" match_ <l:Matchable> <r:Matchable> <i:Instr> ")" => Box::new(Instruction::Match(Match(l, r, i))),
|
"(" match_ <l:Matchable> <r:Matchable> <i:Instr> ")" => {
|
||||||
|
let match_ = Match { left_value: l, right_value: r, instruction: i};
|
||||||
|
Box::new(Instruction::Match(match_))
|
||||||
|
},
|
||||||
|
|
||||||
|
"(" mismatch <l:Matchable> <r:Matchable> <i:Instr> ")" => {
|
||||||
|
let mismatch = MisMatch { left_value: l, right_value: r, instruction: i};
|
||||||
|
Box::new(Instruction::MisMatch(mismatch))
|
||||||
|
},
|
||||||
|
|
||||||
! => { errors.push(<>); Box::new(Instruction::Error) },
|
! => { errors.push(<>); Box::new(Instruction::Error) },
|
||||||
}
|
}
|
||||||
@ -112,5 +120,6 @@ extern {
|
|||||||
xor => Token::Xor,
|
xor => Token::Xor,
|
||||||
next => Token::Next,
|
next => Token::Next,
|
||||||
match_ => Token::Match,
|
match_ => Token::Match,
|
||||||
|
mismatch => Token::MisMatch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,7 @@ pub enum Instruction<'i> {
|
|||||||
Par(Par<'i>),
|
Par(Par<'i>),
|
||||||
Xor(Xor<'i>),
|
Xor(Xor<'i>),
|
||||||
Match(Match<'i>),
|
Match(Match<'i>),
|
||||||
|
MisMatch(MisMatch<'i>),
|
||||||
Fold(Fold<'i>),
|
Fold(Fold<'i>),
|
||||||
Next(Next<'i>),
|
Next(Next<'i>),
|
||||||
Error,
|
Error,
|
||||||
@ -91,11 +92,18 @@ pub struct Par<'i>(pub Box<Instruction<'i>>, pub Box<Instruction<'i>>);
|
|||||||
pub struct Xor<'i>(pub Box<Instruction<'i>>, pub Box<Instruction<'i>>);
|
pub struct Xor<'i>(pub Box<Instruction<'i>>, pub Box<Instruction<'i>>);
|
||||||
|
|
||||||
#[derive(Serialize, Debug, PartialEq, Eq)]
|
#[derive(Serialize, Debug, PartialEq, Eq)]
|
||||||
pub struct Match<'i>(
|
pub struct Match<'i> {
|
||||||
pub MatchableValue<'i>,
|
pub left_value: MatchableValue<'i>,
|
||||||
pub MatchableValue<'i>,
|
pub right_value: MatchableValue<'i>,
|
||||||
pub Box<Instruction<'i>>,
|
pub instruction: Box<Instruction<'i>>,
|
||||||
);
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug, PartialEq, Eq)]
|
||||||
|
pub struct MisMatch<'i> {
|
||||||
|
pub left_value: MatchableValue<'i>,
|
||||||
|
pub right_value: MatchableValue<'i>,
|
||||||
|
pub instruction: Box<Instruction<'i>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug, PartialEq, Eq)]
|
#[derive(Serialize, Debug, PartialEq, Eq)]
|
||||||
pub struct Fold<'i> {
|
pub struct Fold<'i> {
|
||||||
|
@ -181,6 +181,7 @@ fn string_to_token(input: &str, start_pos: usize) -> Result<Token, LexerError> {
|
|||||||
XOR_INSTR => Ok(Token::Xor),
|
XOR_INSTR => Ok(Token::Xor),
|
||||||
NEXT_INSTR => Ok(Token::Next),
|
NEXT_INSTR => Ok(Token::Next),
|
||||||
MATCH_INSTR => Ok(Token::Match),
|
MATCH_INSTR => Ok(Token::Match),
|
||||||
|
MISMATCH_INSTR => Ok(Token::MisMatch),
|
||||||
|
|
||||||
INIT_PEER_ID => Ok(Token::InitPeerId),
|
INIT_PEER_ID => Ok(Token::InitPeerId),
|
||||||
|
|
||||||
@ -236,6 +237,7 @@ const FOLD_INSTR: &str = "fold";
|
|||||||
const XOR_INSTR: &str = "xor";
|
const XOR_INSTR: &str = "xor";
|
||||||
const NEXT_INSTR: &str = "next";
|
const NEXT_INSTR: &str = "next";
|
||||||
const MATCH_INSTR: &str = "match";
|
const MATCH_INSTR: &str = "match";
|
||||||
|
const MISMATCH_INSTR: &str = "mismatch";
|
||||||
|
|
||||||
const INIT_PEER_ID: &str = "%init_peer_id%";
|
const INIT_PEER_ID: &str = "%init_peer_id%";
|
||||||
|
|
||||||
|
@ -103,6 +103,32 @@ fn air_instructions() {
|
|||||||
Ok((5, Token::CloseRoundBracket, 6))
|
Ok((5, Token::CloseRoundBracket, 6))
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let match_tokens = run_lexer("match");
|
||||||
|
assert_eq!(match_tokens, vec![Ok((0, Token::Match, 5))]);
|
||||||
|
|
||||||
|
let match_tokens = run_lexer("(match)");
|
||||||
|
assert_eq!(
|
||||||
|
match_tokens,
|
||||||
|
vec![
|
||||||
|
Ok((0, Token::OpenRoundBracket, 1)),
|
||||||
|
Ok((1, Token::Match, 6)),
|
||||||
|
Ok((6, Token::CloseRoundBracket, 7))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mismatch_tokens = run_lexer("mismatch");
|
||||||
|
assert_eq!(mismatch_tokens, vec![Ok((0, Token::MisMatch, 8))]);
|
||||||
|
|
||||||
|
let mismatch_tokens = run_lexer("(mismatch)");
|
||||||
|
assert_eq!(
|
||||||
|
mismatch_tokens,
|
||||||
|
vec![
|
||||||
|
Ok((0, Token::OpenRoundBracket, 1)),
|
||||||
|
Ok((1, Token::MisMatch, 9)),
|
||||||
|
Ok((9, Token::CloseRoundBracket, 10))
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -36,4 +36,5 @@ pub enum Token<'input> {
|
|||||||
Xor,
|
Xor,
|
||||||
Next,
|
Next,
|
||||||
Match,
|
Match,
|
||||||
|
MisMatch,
|
||||||
}
|
}
|
||||||
|
@ -244,6 +244,34 @@ fn parse_fold() {
|
|||||||
assert_eq!(instruction, expected);
|
assert_eq!(instruction, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_match() {
|
||||||
|
use ast::MatchableValue::Variable;
|
||||||
|
|
||||||
|
let source_code = r#"
|
||||||
|
(match v1 v2
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
let instruction = parse(&source_code.as_ref());
|
||||||
|
let expected = match_(Variable("v1"), Variable("v2"), null());
|
||||||
|
assert_eq!(instruction, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_mismatch() {
|
||||||
|
use ast::MatchableValue::Variable;
|
||||||
|
|
||||||
|
let source_code = r#"
|
||||||
|
(mismatch v1 v2
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
let instruction = parse(&source_code.as_ref());
|
||||||
|
let expected = mismatch(Variable("v1"), Variable("v2"), null());
|
||||||
|
assert_eq!(instruction, expected);
|
||||||
|
}
|
||||||
|
|
||||||
fn source_fold_with(name: &str) -> String {
|
fn source_fold_with(name: &str) -> String {
|
||||||
f!(r#"(fold iterable i
|
f!(r#"(fold iterable i
|
||||||
({name} (null) (null))
|
({name} (null) (null))
|
||||||
@ -516,18 +544,23 @@ fn comments() {
|
|||||||
fn seq<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
fn seq<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
||||||
Instruction::Seq(ast::Seq(Box::new(l), Box::new(r)))
|
Instruction::Seq(ast::Seq(Box::new(l), Box::new(r)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn par<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
fn par<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
||||||
Instruction::Par(ast::Par(Box::new(l), Box::new(r)))
|
Instruction::Par(ast::Par(Box::new(l), Box::new(r)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xor<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
fn xor<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
|
||||||
Instruction::Xor(ast::Xor(Box::new(l), Box::new(r)))
|
Instruction::Xor(ast::Xor(Box::new(l), Box::new(r)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seqnn() -> Instruction<'static> {
|
fn seqnn() -> Instruction<'static> {
|
||||||
seq(null(), null())
|
seq(null(), null())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn null() -> Instruction<'static> {
|
fn null() -> Instruction<'static> {
|
||||||
Instruction::Null(ast::Null)
|
Instruction::Null(ast::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold<'a>(
|
fn fold<'a>(
|
||||||
iterable: ast::IterableValue<'a>,
|
iterable: ast::IterableValue<'a>,
|
||||||
iterator: &'a str,
|
iterator: &'a str,
|
||||||
@ -539,6 +572,31 @@ fn fold<'a>(
|
|||||||
instruction: std::rc::Rc::new(instruction),
|
instruction: std::rc::Rc::new(instruction),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_<'a>(
|
||||||
|
left_value: ast::MatchableValue<'a>,
|
||||||
|
right_value: ast::MatchableValue<'a>,
|
||||||
|
instruction: Instruction<'a>,
|
||||||
|
) -> Instruction<'a> {
|
||||||
|
Instruction::Match(ast::Match {
|
||||||
|
left_value,
|
||||||
|
right_value,
|
||||||
|
instruction: Box::new(instruction),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mismatch<'a>(
|
||||||
|
left_value: ast::MatchableValue<'a>,
|
||||||
|
right_value: ast::MatchableValue<'a>,
|
||||||
|
instruction: Instruction<'a>,
|
||||||
|
) -> Instruction<'a> {
|
||||||
|
Instruction::MisMatch(ast::MisMatch {
|
||||||
|
left_value,
|
||||||
|
right_value,
|
||||||
|
instruction: Box::new(instruction),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn binary_instruction<'a, 'b>(
|
fn binary_instruction<'a, 'b>(
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
) -> impl Fn(Instruction<'b>, Instruction<'b>) -> Instruction<'b> {
|
) -> impl Fn(Instruction<'b>, Instruction<'b>) -> Instruction<'b> {
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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 crate::contexts::execution::ExecutionCtx;
|
||||||
|
use crate::execution::air::ExecutionResult;
|
||||||
|
use crate::execution::utils::resolve_to_jvaluable;
|
||||||
|
use crate::JValue;
|
||||||
|
|
||||||
|
use air_parser::ast::MatchableValue;
|
||||||
|
|
||||||
|
pub(crate) fn are_matchable_eq<'ctx>(
|
||||||
|
left: &MatchableValue<'_>,
|
||||||
|
right: &MatchableValue<'_>,
|
||||||
|
exec_ctx: &'ctx ExecutionCtx<'_>,
|
||||||
|
) -> ExecutionResult<bool> {
|
||||||
|
use MatchableValue::*;
|
||||||
|
|
||||||
|
match (left, right) {
|
||||||
|
(Literal(name), matchable) => compare_matchable_and_literal(matchable, name, exec_ctx),
|
||||||
|
(matchable, Literal(name)) => compare_matchable_and_literal(matchable, name, exec_ctx),
|
||||||
|
(Variable(left_name), Variable(right_name)) => {
|
||||||
|
let left_jvaluable = resolve_to_jvaluable(left_name, exec_ctx)?;
|
||||||
|
let left_value = left_jvaluable.as_jvalue();
|
||||||
|
|
||||||
|
let right_jvaluable = resolve_to_jvaluable(right_name, exec_ctx)?;
|
||||||
|
let right_value = right_jvaluable.as_jvalue();
|
||||||
|
|
||||||
|
Ok(left_value == right_value)
|
||||||
|
}
|
||||||
|
(JsonPath { variable: lv, path: lp }, JsonPath { variable: rv, path: rp }) => {
|
||||||
|
let left_jvaluable = resolve_to_jvaluable(lv, exec_ctx)?;
|
||||||
|
let left_value = left_jvaluable.apply_json_path(lp)?;
|
||||||
|
|
||||||
|
let right_jvaluable = resolve_to_jvaluable(rv, exec_ctx)?;
|
||||||
|
let right_value = right_jvaluable.apply_json_path(rp)?;
|
||||||
|
|
||||||
|
Ok(left_value == right_value)
|
||||||
|
}
|
||||||
|
_ => Ok(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare_matchable_and_literal<'ctx>(
|
||||||
|
matchable: &MatchableValue<'_>,
|
||||||
|
string_literal: &str,
|
||||||
|
exec_ctx: &'ctx ExecutionCtx<'_>,
|
||||||
|
) -> ExecutionResult<bool> {
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use MatchableValue::*;
|
||||||
|
|
||||||
|
fn compare_jvalue_and_literal(jvalue: Cow<'_, JValue>, string_literal: &str) -> bool {
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
match jvalue.deref() {
|
||||||
|
JValue::String(value) => value == string_literal,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match matchable {
|
||||||
|
Literal(name) => Ok(name == &string_literal),
|
||||||
|
Variable(name) => {
|
||||||
|
let jvaluable = resolve_to_jvaluable(name, exec_ctx)?;
|
||||||
|
let jvalue = jvaluable.as_jvalue();
|
||||||
|
Ok(compare_jvalue_and_literal(jvalue, string_literal))
|
||||||
|
}
|
||||||
|
JsonPath { variable, path } => {
|
||||||
|
let jvaluable = resolve_to_jvaluable(variable, exec_ctx)?;
|
||||||
|
let jvalues = jvaluable.apply_json_path(path)?;
|
||||||
|
if jvalues.len() != 1 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(compare_jvalue_and_literal(Cow::Borrowed(jvalues[0]), string_literal))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
stepper-lib/src/execution/air/compare_matchable/mod.rs
Normal file
19
stepper-lib/src/execution/air/compare_matchable/mod.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mod compare_matchable;
|
||||||
|
|
||||||
|
pub(super) use compare_matchable::are_matchable_eq;
|
@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use super::compare_matchable::are_matchable_eq;
|
||||||
use super::ExecutionCtx;
|
use super::ExecutionCtx;
|
||||||
use super::ExecutionError;
|
use super::ExecutionError;
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
@ -21,92 +22,18 @@ use super::ExecutionTraceCtx;
|
|||||||
use crate::log_instruction;
|
use crate::log_instruction;
|
||||||
|
|
||||||
use air_parser::ast::Match;
|
use air_parser::ast::Match;
|
||||||
use air_parser::ast::MatchableValue;
|
|
||||||
|
|
||||||
impl<'i> super::ExecutableInstruction<'i> for Match<'i> {
|
impl<'i> super::ExecutableInstruction<'i> for Match<'i> {
|
||||||
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut ExecutionTraceCtx) -> ExecutionResult<()> {
|
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut ExecutionTraceCtx) -> ExecutionResult<()> {
|
||||||
log_instruction!(match_, exec_ctx, trace_ctx);
|
log_instruction!(match_, exec_ctx, trace_ctx);
|
||||||
|
|
||||||
let left_value = &self.0;
|
let are_values_equal = are_matchable_eq(&self.left_value, &self.right_value, exec_ctx)?;
|
||||||
let right_value = &self.1;
|
|
||||||
let is_equal_values = compare_matchable(left_value, right_value, exec_ctx)?;
|
|
||||||
|
|
||||||
if !is_equal_values {
|
if !are_values_equal {
|
||||||
return Err(ExecutionError::MatchWithoutXorError);
|
return Err(ExecutionError::MatchWithoutXorError);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.2.execute(exec_ctx, trace_ctx)
|
self.instruction.execute(exec_ctx, trace_ctx)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::execution::utils::resolve_to_jvaluable;
|
|
||||||
use crate::JValue;
|
|
||||||
|
|
||||||
fn compare_matchable<'ctx>(
|
|
||||||
left: &MatchableValue<'_>,
|
|
||||||
right: &MatchableValue<'_>,
|
|
||||||
exec_ctx: &'ctx ExecutionCtx<'_>,
|
|
||||||
) -> ExecutionResult<bool> {
|
|
||||||
use MatchableValue::*;
|
|
||||||
|
|
||||||
match (left, right) {
|
|
||||||
(Literal(name), matchable) => compare_matchable_and_literal(matchable, name, exec_ctx),
|
|
||||||
(matchable, Literal(name)) => compare_matchable_and_literal(matchable, name, exec_ctx),
|
|
||||||
(Variable(left_name), Variable(right_name)) => {
|
|
||||||
let left_jvaluable = resolve_to_jvaluable(left_name, exec_ctx)?;
|
|
||||||
let left_value = left_jvaluable.as_jvalue();
|
|
||||||
|
|
||||||
let right_jvaluable = resolve_to_jvaluable(right_name, exec_ctx)?;
|
|
||||||
let right_value = right_jvaluable.as_jvalue();
|
|
||||||
|
|
||||||
Ok(left_value == right_value)
|
|
||||||
}
|
|
||||||
(JsonPath { variable: lv, path: lp }, JsonPath { variable: rv, path: rp }) => {
|
|
||||||
let left_jvaluable = resolve_to_jvaluable(lv, exec_ctx)?;
|
|
||||||
let left_value = left_jvaluable.apply_json_path(lp)?;
|
|
||||||
|
|
||||||
let right_jvaluable = resolve_to_jvaluable(rv, exec_ctx)?;
|
|
||||||
let right_value = right_jvaluable.apply_json_path(rp)?;
|
|
||||||
|
|
||||||
Ok(left_value == right_value)
|
|
||||||
}
|
|
||||||
_ => Ok(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compare_matchable_and_literal<'ctx>(
|
|
||||||
matchable: &MatchableValue<'_>,
|
|
||||||
string_literal: &str,
|
|
||||||
exec_ctx: &'ctx ExecutionCtx<'_>,
|
|
||||||
) -> ExecutionResult<bool> {
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use MatchableValue::*;
|
|
||||||
|
|
||||||
fn compare_jvalue_and_literal(jvalue: Cow<'_, JValue>, string_literal: &str) -> bool {
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
match jvalue.deref() {
|
|
||||||
JValue::String(value) => value == string_literal,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match matchable {
|
|
||||||
Literal(name) => Ok(name == &string_literal),
|
|
||||||
Variable(name) => {
|
|
||||||
let jvaluable = resolve_to_jvaluable(name, exec_ctx)?;
|
|
||||||
let jvalue = jvaluable.as_jvalue();
|
|
||||||
Ok(compare_jvalue_and_literal(jvalue, string_literal))
|
|
||||||
}
|
|
||||||
JsonPath { variable, path } => {
|
|
||||||
let jvaluable = resolve_to_jvaluable(variable, exec_ctx)?;
|
|
||||||
let jvalues = jvaluable.apply_json_path(path)?;
|
|
||||||
if jvalues.len() != 1 {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(compare_jvalue_and_literal(Cow::Borrowed(jvalues[0]), string_literal))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
193
stepper-lib/src/execution/air/mismatch.rs
Normal file
193
stepper-lib/src/execution/air/mismatch.rs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* 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::compare_matchable::are_matchable_eq;
|
||||||
|
use super::ExecutionCtx;
|
||||||
|
use super::ExecutionError;
|
||||||
|
use super::ExecutionResult;
|
||||||
|
use super::ExecutionTraceCtx;
|
||||||
|
use crate::log_instruction;
|
||||||
|
|
||||||
|
use air_parser::ast::MisMatch;
|
||||||
|
|
||||||
|
impl<'i> super::ExecutableInstruction<'i> for MisMatch<'i> {
|
||||||
|
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut ExecutionTraceCtx) -> ExecutionResult<()> {
|
||||||
|
log_instruction!(match_, exec_ctx, trace_ctx);
|
||||||
|
|
||||||
|
let are_values_equal = are_matchable_eq(&self.left_value, &self.right_value, exec_ctx)?;
|
||||||
|
|
||||||
|
if are_values_equal {
|
||||||
|
return Err(ExecutionError::MatchWithoutXorError);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.instruction.execute(exec_ctx, trace_ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::contexts::execution_trace::ExecutionTrace;
|
||||||
|
use crate::JValue;
|
||||||
|
|
||||||
|
use aqua_test_utils::call_vm;
|
||||||
|
use aqua_test_utils::create_aqua_vm;
|
||||||
|
use aqua_test_utils::echo_string_call_service;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mismatch_equal() {
|
||||||
|
use crate::contexts::execution_trace::CallResult::*;
|
||||||
|
use crate::contexts::execution_trace::ExecutedState::*;
|
||||||
|
|
||||||
|
let set_variable_peer_id = "set_variable_peer_id";
|
||||||
|
let mut set_variable_vm = create_aqua_vm(echo_string_call_service(), set_variable_peer_id);
|
||||||
|
|
||||||
|
let local_peer_id = "local_peer_id";
|
||||||
|
let mut vm = create_aqua_vm(echo_string_call_service(), local_peer_id);
|
||||||
|
|
||||||
|
let script = format!(
|
||||||
|
r#"
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call "{0}" ("" "") ["value_1"] value_1)
|
||||||
|
(call "{0}" ("" "") ["value_1"] value_2)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(mismatch value_1 value_2
|
||||||
|
(call "{1}" ("service_id_2" "local_fn_name") ["result_1"] result_1)
|
||||||
|
)
|
||||||
|
(call "{1}" ("service_id_2" "local_fn_name") ["result_2"] result_2)
|
||||||
|
)
|
||||||
|
)"#,
|
||||||
|
set_variable_peer_id, local_peer_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = call_vm!(set_variable_vm, "asd", script.clone(), "", "");
|
||||||
|
let res = call_vm!(vm, "asd", script, "", res.data);
|
||||||
|
|
||||||
|
let actual_trace: ExecutionTrace = serde_json::from_slice(&res.data).expect("should be valid json");
|
||||||
|
let expected_executed_call_result = Call(Executed(Rc::new(JValue::String(String::from("result_2")))));
|
||||||
|
|
||||||
|
assert_eq!(actual_trace.len(), 3);
|
||||||
|
assert_eq!(actual_trace[2], expected_executed_call_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mismatch_not_equal() {
|
||||||
|
use crate::contexts::execution_trace::CallResult::*;
|
||||||
|
use crate::contexts::execution_trace::ExecutedState::*;
|
||||||
|
|
||||||
|
let set_variable_peer_id = "set_variable_peer_id";
|
||||||
|
let mut set_variable_vm = create_aqua_vm(echo_string_call_service(), set_variable_peer_id);
|
||||||
|
|
||||||
|
let local_peer_id = "local_peer_id";
|
||||||
|
let mut vm = create_aqua_vm(echo_string_call_service(), local_peer_id);
|
||||||
|
|
||||||
|
let script = format!(
|
||||||
|
r#"
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call "{0}" ("" "") ["value_1"] value_1)
|
||||||
|
(call "{0}" ("" "") ["value_2"] value_2)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(mismatch value_1 value_2
|
||||||
|
(call "{1}" ("service_id_2" "local_fn_name") ["result_1"] result_1)
|
||||||
|
)
|
||||||
|
(call "{1}" ("service_id_2" "local_fn_name") ["result_2"] result_2)
|
||||||
|
)
|
||||||
|
)"#,
|
||||||
|
set_variable_peer_id, local_peer_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = call_vm!(set_variable_vm, "asd", script.clone(), "", "");
|
||||||
|
let res = call_vm!(vm, "asd", script, "", res.data);
|
||||||
|
|
||||||
|
let actual_trace: ExecutionTrace = serde_json::from_slice(&res.data).expect("should be valid json");
|
||||||
|
let expected_executed_call_result = Call(Executed(Rc::new(JValue::String(String::from("result_1")))));
|
||||||
|
|
||||||
|
assert_eq!(actual_trace.len(), 3);
|
||||||
|
assert_eq!(actual_trace[2], expected_executed_call_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mismatch_with_string() {
|
||||||
|
use crate::contexts::execution_trace::CallResult::*;
|
||||||
|
use crate::contexts::execution_trace::ExecutedState::*;
|
||||||
|
|
||||||
|
let set_variable_peer_id = "set_variable_peer_id";
|
||||||
|
let mut set_variable_vm = create_aqua_vm(echo_string_call_service(), set_variable_peer_id);
|
||||||
|
|
||||||
|
let local_peer_id = "local_peer_id";
|
||||||
|
let mut vm = create_aqua_vm(echo_string_call_service(), local_peer_id);
|
||||||
|
|
||||||
|
let script = format!(
|
||||||
|
r#"
|
||||||
|
(seq
|
||||||
|
(call "{0}" ("" "") ["value_1"] value_1)
|
||||||
|
(xor
|
||||||
|
(mismatch value_1 "value_1"
|
||||||
|
(call "{1}" ("service_id_2" "local_fn_name") ["result_1"] result_1)
|
||||||
|
)
|
||||||
|
(call "{1}" ("service_id_2" "local_fn_name") ["result_2"] result_2)
|
||||||
|
)
|
||||||
|
)"#,
|
||||||
|
set_variable_peer_id, local_peer_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = call_vm!(set_variable_vm, "asd", script.clone(), "", "");
|
||||||
|
let res = call_vm!(vm, "asd", script, "", res.data);
|
||||||
|
|
||||||
|
let actual_trace: ExecutionTrace = serde_json::from_slice(&res.data).expect("should be valid json");
|
||||||
|
let expected_executed_call_result = Call(Executed(Rc::new(JValue::String(String::from("result_2")))));
|
||||||
|
|
||||||
|
assert_eq!(actual_trace.len(), 2);
|
||||||
|
assert_eq!(actual_trace[1], expected_executed_call_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mismatch_without_xor() {
|
||||||
|
let set_variable_peer_id = "set_variable_peer_id";
|
||||||
|
let mut set_variable_vm = create_aqua_vm(echo_string_call_service(), set_variable_peer_id);
|
||||||
|
|
||||||
|
let local_peer_id = "local_peer_id";
|
||||||
|
let mut vm = create_aqua_vm(echo_string_call_service(), local_peer_id);
|
||||||
|
|
||||||
|
let script = format!(
|
||||||
|
r#"
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call "{0}" ("" "") ["value_1"] value_1)
|
||||||
|
(call "{0}" ("" "") ["value_1"] value_2)
|
||||||
|
)
|
||||||
|
(mismatch value_1 value_2
|
||||||
|
(call "{1}" ("service_id_2" "local_fn_name") ["result_1"] result_1)
|
||||||
|
)
|
||||||
|
)"#,
|
||||||
|
set_variable_peer_id, local_peer_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = call_vm!(set_variable_vm, "asd", script.clone(), "", "");
|
||||||
|
let res = call_vm!(vm, "asd", script.clone(), "", res.data);
|
||||||
|
|
||||||
|
assert_eq!(res.ret_code, 1015);
|
||||||
|
|
||||||
|
let res = call_vm!(vm, "asd", script, "", res.data);
|
||||||
|
|
||||||
|
assert_eq!(res.ret_code, 1015);
|
||||||
|
}
|
||||||
|
}
|
@ -15,8 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
mod call;
|
mod call;
|
||||||
|
mod compare_matchable;
|
||||||
mod fold;
|
mod fold;
|
||||||
mod match_;
|
mod match_;
|
||||||
|
mod mismatch;
|
||||||
mod null;
|
mod null;
|
||||||
mod par;
|
mod par;
|
||||||
mod seq;
|
mod seq;
|
||||||
@ -46,6 +48,7 @@ impl<'i> ExecutableInstruction<'i> for Instruction<'i> {
|
|||||||
Instruction::Seq(seq) => seq.execute(exec_ctx, trace_ctx),
|
Instruction::Seq(seq) => seq.execute(exec_ctx, trace_ctx),
|
||||||
Instruction::Xor(xor) => xor.execute(exec_ctx, trace_ctx),
|
Instruction::Xor(xor) => xor.execute(exec_ctx, trace_ctx),
|
||||||
Instruction::Match(match_) => match_.execute(exec_ctx, trace_ctx),
|
Instruction::Match(match_) => match_.execute(exec_ctx, trace_ctx),
|
||||||
|
Instruction::MisMatch(mismatch) => mismatch.execute(exec_ctx, trace_ctx),
|
||||||
Instruction::Error => unreachable!("should not execute if parsing succeeded. QED."),
|
Instruction::Error => unreachable!("should not execute if parsing succeeded. QED."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user