Use $ to identify streams instead of [] (#79)

This commit is contained in:
vms 2021-03-26 17:13:28 +03:00 committed by GitHub
parent 9bdd2e3501
commit 45fc92ae3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1257 additions and 1017 deletions

72
Cargo.lock generated
View File

@ -13,7 +13,7 @@ dependencies = [
[[package]]
name = "air-parser"
version = "0.6.0"
version = "0.7.0"
dependencies = [
"codespan",
"codespan-reporting",
@ -40,9 +40,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.38"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767"
[[package]]
name = "aqua-interpreter-interface"
@ -82,7 +82,7 @@ dependencies = [
[[package]]
name = "aquamarine"
version = "0.7.0"
version = "0.8.0"
dependencies = [
"fluence 0.4.2",
"interpreter-lib",
@ -240,9 +240,9 @@ checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
[[package]]
name = "byteorder"
version = "1.4.2"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cast"
@ -481,9 +481,9 @@ dependencies = [
[[package]]
name = "csv"
version = "1.1.5"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97"
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
@ -503,9 +503,9 @@ dependencies = [
[[package]]
name = "ctor"
version = "0.1.19"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19"
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
dependencies = [
"quote",
"syn",
@ -980,9 +980,9 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "indexmap"
version = "1.6.1"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
"autocfg",
"hashbrown",
@ -1000,7 +1000,7 @@ dependencies = [
[[package]]
name = "interpreter-lib"
version = "0.7.0"
version = "0.8.0"
dependencies = [
"air-parser",
"aqua-interpreter-interface 0.3.1",
@ -1156,9 +1156,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.87"
version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
[[package]]
name = "lock_api"
@ -1211,9 +1211,9 @@ dependencies = [
[[package]]
name = "memoffset"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
checksum = "cc14fc54a812b4472b4113facc3e44d099fbc0ea2ce0551fa5c703f8edfbfd38"
dependencies = [
"autocfg",
]
@ -1552,14 +1552,13 @@ dependencies = [
[[package]]
name = "regex"
version = "1.4.3"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
@ -1573,9 +1572,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.22"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "rust-argon2"
@ -1703,9 +1702,9 @@ dependencies = [
[[package]]
name = "siphasher"
version = "0.3.3"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7"
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
[[package]]
name = "smallvec"
@ -1739,9 +1738,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
[[package]]
name = "syn"
version = "1.0.61"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5"
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
dependencies = [
"proc-macro2",
"quote",
@ -1803,15 +1802,6 @@ dependencies = [
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.43"
@ -1852,9 +1842,9 @@ dependencies = [
[[package]]
name = "typenum"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "typetag"
@ -1909,9 +1899,9 @@ dependencies = [
[[package]]
name = "version_check"
version = "0.9.2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "void"
@ -1921,9 +1911,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "walkdir"
version = "2.3.1"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",

View File

@ -1,6 +1,6 @@
[package]
name = "air-parser"
version = "0.6.0"
version = "0.7.0"
authors = ["Fluence Labs"]
edition = "2018"
license = "Apache-2.0"

View File

@ -28,24 +28,24 @@ use air_parser::AIRParser;
const SOURCE_CODE_BAD: &'static str = r#"(seq
(seq
(call node ("identity" "") [] void[])
(call node ("identity" "") [] $void)
(call provider (service_id "{fname}") {arg_list} result)
)
(seq
(call node ("identity" "") [] void[])
(call "{LOCAL_VM}" ("return" "result") [result] void[])
(call node ("identity" "") [] $void)
(call "{LOCAL_VM}" ("return" "result") [result] $void)
)
)"#;
const SOURCE_CODE_GOOD: &'static str = r#"
(seq
(seq
(call node ("identity" "") [] void[])
(call node ("identity" "") [] $void)
(call provider (service_id "fname") [arg list] result)
)
(seq
(call node ("identity" "") [] void[])
(call "local_vm" ("return" "result") [result] void[])
(call node ("identity" "") [] $void)
(call "local_vm" ("return" "result") [result] $void)
)
)"#;

View File

@ -1,11 +1,11 @@
use crate::parser::ast::*;
use crate::parser::air_parser::into_variable_and_path;
use crate::parser::air_parser::make_flattened_error;
use crate::parser::ParserError;
use crate::parser::VariableValidator;
use crate::parser::Span;
use crate::parser::lexer::Token;
use crate::parser::lexer::Number;
use crate::parser::lexer::Variable;
use lalrpop_util::ErrorRecovery;
use std::rc::Rc;
@ -16,10 +16,10 @@ grammar<'err, 'input, 'v>(input: &'input str, errors: &'err mut Vec<ErrorRecover
pub AIR = Instr;
Instr: Box<Instruction<'input>> = {
<left: @L> "(" call <p:PeerPart> <f:FPart> <args:Args> <output:Output?> ")" <right: @R> => {
<left: @L> "(" call <peer_part:PeerPart> <function_part:FPart> <args:Args> <output:Output?> ")" <right: @R> => {
let output = output.unwrap_or(CallOutputValue::None);
let args = Rc::new(args);
let call = Call { peer_part: p, function_part: f, args, output };
let call = Call { peer_part, function_part, args, output };
let span = Span { left, right };
validator.met_call(&call, span);
@ -82,8 +82,8 @@ PeerPart: PeerPart<'input> = {
}
Output: CallOutputValue<'input> = {
<s:Alphanumeric> => CallOutputValue::Scalar(s),
<a:Accumulator> => CallOutputValue::Accumulator(a),
<a:Alphanumeric> => CallOutputValue::Variable(Variable::Scalar(a)),
<s:Stream> => CallOutputValue::Variable(Variable::Stream(s)),
};
Function = CallInstrValue;
@ -91,13 +91,16 @@ PeerId = CallInstrValue;
ServiceId = CallInstrValue;
CallInstrValue: CallInstrValue<'input> = {
<s:Literal> => CallInstrValue::Literal(s),
<s:Alphanumeric> => CallInstrValue::Variable(s),
<l: @L> <v:JsonPath> <r: @R> => {
let (variable, path) = into_variable_and_path(v.0, v.1, v.2);
let should_flatten = v.2;
<l:Literal> => CallInstrValue::Literal(l),
<a:Alphanumeric> => CallInstrValue::Variable(Variable::Scalar(a)),
<s:Stream> => CallInstrValue::Variable(Variable::Stream(s)),
<l: @L> <j:JsonPath> <r: @R> => {
let variable = j.0;
let path = j.1;
let should_flatten = j.2;
// Due the json path constraints json path should be flattened in a call triplet.
if !should_flatten {
let token = Token::JsonPath(v.0, v.1, v.2);
let token = Token::VariableWithJsonPath(variable.clone(), path, should_flatten);
errors.push(make_flattened_error(l, token, r));
}
CallInstrValue::JsonPath { variable, path, should_flatten }
@ -109,12 +112,9 @@ Arg = CallInstrArgValue;
CallInstrArgValue: CallInstrArgValue<'input> = {
<s:Literal> => CallInstrArgValue::Literal(s),
<s:Alphanumeric> => CallInstrArgValue::Variable(s),
<v:JsonPath> => {
let (variable, path) = into_variable_and_path(v.0, v.1, v.2);
let should_flatten = v.2;
CallInstrArgValue::JsonPath { variable, path, should_flatten }
},
<v:Alphanumeric> => CallInstrArgValue::Variable(Variable::Scalar(v)),
<v:Stream> => CallInstrArgValue::Variable(Variable::Stream(v)),
<j:JsonPath> => CallInstrArgValue::JsonPath { variable: j.0, path: j.1, should_flatten: j.2 },
<n:Number> => CallInstrArgValue::Number(n),
<b:Boolean> => CallInstrArgValue::Boolean(b),
InitPeerId => CallInstrArgValue::InitPeerId,
@ -122,25 +122,18 @@ CallInstrArgValue: CallInstrArgValue<'input> = {
}
Iterable: IterableValue<'input> = {
<s:Alphanumeric> => IterableValue::Variable(s),
<v:JsonPath> => {
let (variable, path) = into_variable_and_path(v.0, v.1, v.2);
let should_flatten = v.2;
IterableValue::JsonPath { variable, path, should_flatten }
},
<v:Alphanumeric> => IterableValue::Variable(Variable::Scalar(v)),
<v:Stream> => IterableValue::Variable(Variable::Stream(v)),
<j:JsonPath> => IterableValue::JsonPath { variable: j.0, path: j.1, should_flatten: j.2 },
}
Matchable: MatchableValue<'input> = {
<s:Alphanumeric> => MatchableValue::Variable(s),
<v:Alphanumeric> => MatchableValue::Variable(Variable::Scalar(v)),
<v:Stream> => MatchableValue::Variable(Variable::Stream(v)),
<s:Literal> => MatchableValue::Literal(s),
<b:Boolean> => MatchableValue::Boolean(b),
<n:Number> => MatchableValue::Number(n),
<v:JsonPath> => {
let (variable, path) = into_variable_and_path(v.0, v.1, v.2);
let should_flatten = v.2;
MatchableValue::JsonPath { variable, path, should_flatten }
},
<j:JsonPath> => MatchableValue::JsonPath { variable: j.0, path: j.1, should_flatten: j.2 },
}
extern {
@ -153,10 +146,10 @@ extern {
"[" => Token::OpenSquareBracket,
"]" => Token::CloseSquareBracket,
Alphanumeric => Token::Alphanumeric(<&'input str>),
Literal => Token::StringLiteral(<&'input str>),
JsonPath => Token::JsonPath(<&'input str>, <usize>, <bool>),
Accumulator => Token::Accumulator(<&'input str>),
Alphanumeric => Token::Alphanumeric(<&'input str>),
Stream => Token::Stream(<&'input str>),
JsonPath => Token::VariableWithJsonPath(<Variable<'input>>, <&'input str>, <bool>),
Number => Token::Number(<Number>),
Boolean => Token::Boolean(<bool>),

File diff suppressed because it is too large Load Diff

View File

@ -148,7 +148,7 @@ fn lexical_error_to_label(file_id: usize, error: LexerError) -> Label<usize> {
IsNotAlphanumeric(start, end) => {
Label::primary(file_id, start..end).with_message(error.to_string())
}
EmptyAccName(start, end) => {
EmptyStreamName(start, end) => {
Label::primary(file_id, start..end).with_message(error.to_string())
}
EmptyVariableOrConst(start, end) => {
@ -175,16 +175,6 @@ fn lexical_error_to_label(file_id: usize, error: LexerError) -> Label<usize> {
}
}
pub(super) fn into_variable_and_path(str: &str, pos: usize, should_flatten: bool) -> (&str, &str) {
let json_path = if should_flatten {
&str[pos + 1..str.len() - 1]
} else {
&str[pos + 1..]
};
(&str[0..pos], json_path)
}
pub(super) fn make_flattened_error(
start_pos: usize,
token: Token<'_>,

View File

@ -17,6 +17,7 @@
mod traits;
pub use crate::parser::lexer::Number;
pub use crate::parser::lexer::Variable;
use serde::Deserialize;
use serde::Serialize;
@ -62,9 +63,9 @@ pub struct Call<'i> {
pub enum CallInstrValue<'i> {
InitPeerId,
Literal(&'i str),
Variable(&'i str),
Variable(Variable<'i>),
JsonPath {
variable: &'i str,
variable: Variable<'i>,
path: &'i str,
should_flatten: bool,
},
@ -77,9 +78,9 @@ pub enum CallInstrArgValue<'i> {
Literal(&'i str),
Number(Number),
Boolean(bool),
Variable(&'i str),
Variable(Variable<'i>),
JsonPath {
variable: &'i str,
variable: Variable<'i>,
path: &'i str,
should_flatten: bool,
},
@ -87,9 +88,9 @@ pub enum CallInstrArgValue<'i> {
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum IterableValue<'i> {
Variable(&'i str),
Variable(Variable<'i>),
JsonPath {
variable: &'i str,
variable: Variable<'i>,
path: &'i str,
should_flatten: bool,
},
@ -100,9 +101,9 @@ pub enum MatchableValue<'i> {
Literal(&'i str),
Number(Number),
Boolean(bool),
Variable(&'i str),
Variable(Variable<'i>),
JsonPath {
variable: &'i str,
variable: Variable<'i>,
path: &'i str,
should_flatten: bool,
},
@ -110,8 +111,7 @@ pub enum MatchableValue<'i> {
#[derive(Serialize, Debug, PartialEq, Clone)]
pub enum CallOutputValue<'i> {
Scalar(&'i str),
Accumulator(&'i str),
Variable(Variable<'i>),
None,
}

View File

@ -38,8 +38,8 @@ impl fmt::Display for CallInstrArgValue<'_> {
}
}
fn print_json_path(
variable: &str,
fn print_json_path<'a>(
variable: &Variable<'a>,
path: &str,
should_flatten: &bool,
f: &mut fmt::Formatter,
@ -104,8 +104,7 @@ impl fmt::Display for CallOutputValue<'_> {
use CallOutputValue::*;
match self {
Scalar(str) => write!(f, "{}", str),
Accumulator(str) => write!(f, "{}[]", str),
Variable(variable) => write!(f, "{}", variable),
None => Ok(()),
}
}

View File

@ -15,7 +15,6 @@
*/
use super::errors::LexerError;
use super::is_aqua_alphanumeric;
use super::token::Token;
use super::LexerResult;
@ -191,31 +190,10 @@ fn string_to_token(input: &str, start_pos: usize) -> LexerResult<Token> {
TRUE_VALUE => Ok(Token::Boolean(true)),
FALSE_VALUE => Ok(Token::Boolean(false)),
str if str.ends_with(ACC_END_TAG) => try_parse_accumulator(str, start_pos),
str => super::call_variable_parser::try_parse_call_variable(str, start_pos),
}
}
fn try_parse_accumulator(maybe_acc: &str, start: usize) -> LexerResult<Token> {
const ACC_END_TAG_SIZE: usize = 2;
let str_len = maybe_acc.len();
if str_len == ACC_END_TAG_SIZE {
return Err(LexerError::EmptyAccName(start, start));
}
// this slice is safe here because str's been checked for ending with "[]"
let maybe_acc = &maybe_acc[0..str_len - ACC_END_TAG_SIZE];
for (pos, ch) in maybe_acc.chars().enumerate() {
if !is_aqua_alphanumeric(ch) {
return Err(LexerError::IsNotAlphanumeric(start + pos, start + pos));
}
}
Ok(Token::Accumulator(maybe_acc))
}
const CALL_INSTR: &str = "call";
const SEQ_INSTR: &str = "seq";
const PAR_INSTR: &str = "par";
@ -231,5 +209,3 @@ const LAST_ERROR: &str = "%last_error%";
const TRUE_VALUE: &str = "true";
const FALSE_VALUE: &str = "false";
const ACC_END_TAG: &str = "[]";

View File

@ -17,6 +17,7 @@
use super::LexerError;
use super::LexerResult;
use super::Token;
use super::Variable;
use std::convert::TryInto;
use std::iter::Peekable;
@ -36,6 +37,7 @@ struct ParserState {
pub(self) digit_met: bool,
pub(self) flattening_met: bool,
pub(self) is_first_char: bool,
pub(self) is_first_stream_tag: bool,
pub(self) current_char: char,
pub(self) current_pos: usize,
}
@ -61,6 +63,7 @@ impl<'input> CallVariableParser<'input> {
digit_met: false,
flattening_met: false,
is_first_char: true,
is_first_stream_tag: false,
current_char,
current_pos,
};
@ -164,7 +167,7 @@ impl<'input> CallVariableParser<'input> {
}
fn try_parse_as_variable(&mut self) -> LexerResult<()> {
if self.try_parse_as_json_path_start()? {
if self.try_parse_as_stream_start()? || self.try_parse_as_json_path_start()? {
return Ok(());
} else if self.is_json_path_started() {
self.try_parse_as_json_path()?;
@ -175,6 +178,20 @@ impl<'input> CallVariableParser<'input> {
Ok(())
}
fn try_parse_as_stream_start(&mut self) -> LexerResult<bool> {
if self.current_pos() == 0 && self.current_char() == STREAM_START_TAG {
if self.string_to_parse.len() == 1 {
let error_pos = self.pos_in_string_to_parse();
return Err(LexerError::EmptyStreamName(error_pos, error_pos));
}
self.state.is_first_stream_tag = true;
return Ok(true);
}
Ok(false)
}
fn try_parse_as_json_path_start(&mut self) -> LexerResult<bool> {
self.try_parse_first_met_dot()
}
@ -253,6 +270,15 @@ impl<'input> CallVariableParser<'input> {
self.current_pos() == self.string_to_parse.len() - 1
}
fn to_variable<'v>(&self, variable_name: &'v str) -> Variable<'v> {
if self.state.is_first_stream_tag {
// TODO: cut the stream tag after the refactoring.
Variable::Stream(variable_name)
} else {
Variable::Scalar(variable_name)
}
}
fn to_token(&self) -> LexerResult<Token<'input>> {
use super::token::UnparsedNumber;
@ -267,12 +293,42 @@ impl<'input> CallVariableParser<'input> {
let number: super::Number = number.try_into()?;
Ok(number.into())
}
(false, false) => Ok(Token::Alphanumeric(self.string_to_parse)),
(false, true) => Ok(Token::JsonPath(
self.string_to_parse,
self.state.first_dot_met_pos.unwrap(),
self.state.flattening_met,
)),
(false, false) => {
if self.state.is_first_stream_tag {
Ok(Token::Stream(&self.string_to_parse))
} else {
Ok(Token::Alphanumeric(&self.string_to_parse))
}
}
(false, true) => {
let json_path_start_pos = self.state.first_dot_met_pos.unwrap();
let should_flatten = self.state.flattening_met;
let (variable, json_path) = to_variable_and_path(
&self.string_to_parse,
json_path_start_pos,
should_flatten,
);
let variable = self.to_variable(variable);
Ok(Token::VariableWithJsonPath(
variable,
json_path,
should_flatten,
))
}
}
}
}
const STREAM_START_TAG: char = '$';
fn to_variable_and_path(str: &str, pos: usize, should_flatten: bool) -> (&str, &str) {
let json_path = if should_flatten {
// -1 to not include the flattening symbol ! to the resulted json path
&str[pos + 1..str.len() - 1]
} else {
&str[pos + 1..]
};
(&str[0..pos], json_path)
}

View File

@ -30,8 +30,8 @@ pub enum LexerError {
#[error("only alphanumeric, '_', and '-' characters are allowed in this position")]
IsNotAlphanumeric(usize, usize),
#[error("an accumulator name should be non empty")]
EmptyAccName(usize, usize),
#[error("a stream name should be non empty")]
EmptyStreamName(usize, usize),
#[error("this variable or constant shouldn't have empty name")]
EmptyVariableOrConst(usize, usize),

View File

@ -27,6 +27,7 @@ pub use air_lexer::AIRLexer;
pub use errors::LexerError;
pub use token::Number;
pub use token::Token;
pub use token::Variable;
pub(super) type LexerResult<T> = std::result::Result<T, LexerError>;

View File

@ -19,6 +19,7 @@ use super::AIRLexer;
use super::LexerError;
use super::Number;
use super::Token;
use super::Variable;
fn run_lexer(input: &str) -> Vec<Spanned<Token<'_>, usize, LexerError>> {
let lexer = AIRLexer::new(input);
@ -152,17 +153,10 @@ fn init_peer_id() {
}
#[test]
fn accumulator() {
const ACC: &str = "accumulator____asdasd[]";
fn stream() {
const STREAM: &str = "$stream____asdasd";
lexer_test(
ACC,
Single(Ok((
0,
Token::Accumulator(&ACC[0..ACC.len() - 2]),
ACC.len(),
))),
);
lexer_test(STREAM, Single(Ok((0, Token::Stream(STREAM), STREAM.len()))));
}
#[test]
@ -268,14 +262,15 @@ fn too_big_float_number() {
#[test]
fn json_path() {
// this json path contains all allowed in json path charactes
// this json path contains all allowed in json path characters
const JSON_PATH: &str = r#"value.$[$@[]():?.*,"]"#;
let variable = Variable::Scalar("value");
lexer_test(
JSON_PATH,
Single(Ok((
0,
Token::JsonPath(JSON_PATH, 5, false),
Token::VariableWithJsonPath(variable, r#"$[$@[]():?.*,"]"#, false),
JSON_PATH.len(),
))),
);

View File

@ -17,7 +17,7 @@
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Token<'input> {
OpenRoundBracket,
CloseRoundBracket,
@ -26,8 +26,8 @@ pub enum Token<'input> {
StringLiteral(&'input str),
Alphanumeric(&'input str),
JsonPath(&'input str, usize, bool),
Accumulator(&'input str),
Stream(&'input str),
VariableWithJsonPath(Variable<'input>, &'input str, bool),
Number(Number),
Boolean(bool),
@ -45,6 +45,12 @@ pub enum Token<'input> {
MisMatch,
}
#[derive(Debug, Clone, PartialEq, Hash, Serialize, Deserialize)]
pub enum Variable<'input> {
Scalar(&'input str),
Stream(&'input str),
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Number {
Int(i64),
@ -64,6 +70,17 @@ impl fmt::Display for Number {
}
}
impl fmt::Display for Variable<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Variable::*;
match self {
Scalar(name) => write!(f, "{}", name),
Stream(name) => write!(f, "&{}", name),
}
}
}
impl From<Number> for Token<'_> {
fn from(value: Number) -> Self {
Token::Number(value)

View File

@ -17,7 +17,12 @@
use crate::ast;
use crate::parser::AIRParser;
use crate::parser::ParserError;
use ast::Call;
use ast::CallInstrArgValue;
use ast::CallInstrValue;
use ast::Instruction;
use ast::Variable::Scalar;
use ast::Variable::Stream;
use fstrings::f;
use lalrpop_util::ParseError;
@ -32,15 +37,12 @@ fn parse(source_code: &str) -> Instruction {
let mut validator = crate::parser::VariableValidator::new();
parser
.parse(source_code, &mut errors, &mut validator, lexer)
.expect("parsing should be successfull")
.expect("parsing should be successful")
})
}
#[test]
fn parse_seq() {
use ast::Call;
use ast::CallInstrArgValue;
use ast::CallInstrValue;
use ast::CallOutputValue::*;
use ast::FunctionPart::*;
use ast::PeerPart::*;
@ -54,17 +56,17 @@ fn parse_seq() {
let instruction = parse(source_code);
let expected = seq(
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::Variable("peerid")),
function_part: FuncName(CallInstrValue::Variable("function")),
peer_part: PeerPk(CallInstrValue::Variable(Scalar("peerid"))),
function_part: FuncName(CallInstrValue::Variable(Scalar("function"))),
args: Rc::new(vec![]),
output: Scalar("output"),
output: Variable(Scalar("output")),
}),
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::Literal("id")),
function_part: FuncName(CallInstrValue::Literal("f")),
args: Rc::new(vec![
CallInstrArgValue::Literal("hello"),
CallInstrArgValue::Variable("name"),
CallInstrArgValue::Variable(Scalar("name")),
]),
output: None,
}),
@ -74,9 +76,6 @@ fn parse_seq() {
#[test]
fn parse_seq_seq() {
use ast::Call;
use ast::CallInstrArgValue;
use ast::CallInstrValue;
use ast::CallOutputValue::*;
use ast::FunctionPart::*;
use ast::PeerPart::*;
@ -87,26 +86,26 @@ fn parse_seq_seq() {
(call peerid function [])
(call (peerid serviceA) ("serviceB" function) [])
)
(call "id" "f" ["hello" name] output[])
(call "id" "f" ["hello" name] $output)
)
"#;
let instruction = parse(source_code);
let expected = seq(
seq(
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::Variable("peerid")),
function_part: FuncName(CallInstrValue::Variable("function")),
peer_part: PeerPk(CallInstrValue::Variable(Scalar("peerid"))),
function_part: FuncName(CallInstrValue::Variable(Scalar("function"))),
args: Rc::new(vec![]),
output: None,
}),
Instruction::Call(Call {
peer_part: PeerPkWithServiceId(
CallInstrValue::Variable("peerid"),
CallInstrValue::Variable("serviceA"),
CallInstrValue::Variable(Scalar("peerid")),
CallInstrValue::Variable(Scalar("serviceA")),
),
function_part: ServiceIdWithFuncName(
CallInstrValue::Literal("serviceB"),
CallInstrValue::Variable("function"),
CallInstrValue::Variable(Scalar("function")),
),
args: Rc::new(vec![]),
output: None,
@ -117,9 +116,9 @@ fn parse_seq_seq() {
function_part: FuncName(CallInstrValue::Literal("f")),
args: Rc::new(vec![
CallInstrArgValue::Literal("hello"),
CallInstrArgValue::Variable("name"),
CallInstrArgValue::Variable(Scalar("name")),
]),
output: Accumulator("output"),
output: Variable(Stream("$output")),
}),
);
assert_eq!(instruction, expected);
@ -127,29 +126,26 @@ fn parse_seq_seq() {
#[test]
fn parse_json_path() {
use ast::Call;
use ast::CallInstrArgValue;
use ast::CallInstrValue;
use ast::CallOutputValue::*;
use ast::FunctionPart::*;
use ast::PeerPart::*;
let source_code = r#"
(call id.$.a! "f" ["hello" name] void[])
(call id.$.a! "f" ["hello" name] $void)
"#;
let instruction = parse(source_code);
let expected = Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::JsonPath {
variable: "id",
variable: Scalar("id"),
path: "$.a",
should_flatten: true,
}),
function_part: FuncName(CallInstrValue::Literal("f")),
args: Rc::new(vec![
CallInstrArgValue::Literal("hello"),
CallInstrArgValue::Variable("name"),
CallInstrArgValue::Variable(Scalar("name")),
]),
output: Accumulator("void"),
output: Variable(Stream("$void")),
});
assert_eq!(instruction, expected);
}
@ -157,7 +153,7 @@ fn parse_json_path() {
#[test]
fn parse_undefined_variable() {
let source_code = r#"
(call id.$.a "f" ["hello" name] void[])
(call id.$.a "f" ["hello" name] $void)
"#;
let lexer = crate::AIRLexer::new(source_code);
@ -190,7 +186,7 @@ fn parse_undefined_iterable() {
(call "" ("" "") [] iterable)
(fold iterable i
(seq
(call "" ("" "") ["hello" ""] void[])
(call "" ("" "") ["hello" ""] $void)
(next j)
)
)
@ -221,8 +217,6 @@ fn parse_undefined_iterable() {
#[test]
fn parse_json_path_complex() {
use ast::Call;
use ast::CallInstrValue;
use ast::CallOutputValue::*;
use ast::FunctionPart::*;
use ast::PeerPart::*;
@ -237,23 +231,23 @@ fn parse_json_path_complex() {
let expected = seq(
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::JsonPath {
variable: "m",
variable: Scalar("m"),
path: "$.[1]",
should_flatten: true,
}),
function_part: FuncName(CallInstrValue::Literal("f")),
args: Rc::new(vec![]),
output: Scalar("void"),
output: Variable(Scalar("void")),
}),
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::JsonPath {
variable: "m",
variable: Scalar("m"),
path: r#"$.abc["c"].cde[a][0].cde["bcd"]"#,
should_flatten: true,
}),
function_part: FuncName(CallInstrValue::Literal("f")),
args: Rc::new(vec![]),
output: Scalar("void"),
output: Variable(Scalar("void")),
}),
);
assert_eq!(instruction, expected);
@ -261,20 +255,17 @@ fn parse_json_path_complex() {
#[test]
fn json_path_square_braces() {
use ast::Call;
use ast::CallInstrArgValue;
use ast::CallInstrValue;
use ast::CallOutputValue::*;
use ast::FunctionPart::*;
use ast::PeerPart::*;
let source_code = r#"
(call u.$["peer_id"]! ("return" "") [u.$["peer_id"].cde[0]["abc"].abc u.$["name"]] void[])
(call u.$["peer_id"]! ("return" "") [u.$["peer_id"].cde[0]["abc"].abc u.$["name"]] $void)
"#;
let instruction = parse(source_code);
let expected = Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::JsonPath {
variable: "u",
variable: Scalar("u"),
path: r#"$["peer_id"]"#,
should_flatten: true,
}),
@ -284,17 +275,17 @@ fn json_path_square_braces() {
),
args: Rc::new(vec![
CallInstrArgValue::JsonPath {
variable: "u",
variable: Scalar("u"),
path: r#"$["peer_id"].cde[0]["abc"].abc"#,
should_flatten: false,
},
CallInstrArgValue::JsonPath {
variable: "u",
variable: Scalar("u"),
path: r#"$["name"]"#,
should_flatten: false,
},
]),
output: Accumulator("void"),
output: Variable(Stream("$void")),
});
assert_eq!(instruction, expected);
@ -344,8 +335,12 @@ fn parse_fold() {
(null)
)
"#;
let instruction = parse(source_code);
let expected = fold(ast::IterableValue::Variable("iterable"), "i", null());
let instruction = parse(&source_code);
let expected = fold(
ast::IterableValue::Variable(Scalar("iterable")),
"i",
null(),
);
assert_eq!(instruction, expected);
}
@ -358,8 +353,8 @@ fn parse_match() {
(null)
)
"#;
let instruction = parse(source_code);
let expected = match_(Variable("v1"), Variable("v2"), null());
let instruction = parse(&source_code);
let expected = match_(Variable(Scalar("v1")), Variable(Scalar("v2")), null());
assert_eq!(instruction, expected);
}
@ -372,8 +367,8 @@ fn parse_mismatch() {
(null)
)
"#;
let instruction = parse(source_code);
let expected = mismatch(Variable("v1"), Variable("v2"), null());
let instruction = parse(&source_code);
let expected = mismatch(Variable(Scalar("v1")), Variable(Scalar("v2")), null());
assert_eq!(instruction, expected);
}
@ -389,7 +384,7 @@ fn parse_fold_with_xor_par_seq() {
let instruction = parse(&source_code);
let instr = binary_instruction(*name);
let expected = fold(
ast::IterableValue::Variable("iterable"),
ast::IterableValue::Variable(Scalar("iterable")),
"i",
instr(null(), null()),
);
@ -505,7 +500,7 @@ fn seq_par_call() {
CallInstrValue::Literal("local_fn_name"),
),
args: Rc::new(vec![]),
output: Scalar("result_1"),
output: Variable(Scalar("result_1")),
}),
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::Literal(&peer_id)),
@ -514,7 +509,7 @@ fn seq_par_call() {
CallInstrValue::Literal("fn_name"),
),
args: Rc::new(vec![]),
output: Scalar("g"),
output: Variable(Scalar("g")),
}),
),
Instruction::Call(Call {
@ -524,7 +519,7 @@ fn seq_par_call() {
CallInstrValue::Literal("local_fn_name"),
),
args: Rc::new(vec![]),
output: Scalar("result_2"),
output: Variable(Scalar("result_2")),
}),
);
@ -572,7 +567,7 @@ fn seq_with_empty_and_dash() {
CallInstrValue::Literal(""),
),
args: Rc::new(vec![CallInstrArgValue::Literal("module-bytes")]),
output: Scalar("module-bytes"),
output: Variable(Scalar("module-bytes")),
}),
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::Literal("set_variables")),
@ -581,7 +576,7 @@ fn seq_with_empty_and_dash() {
CallInstrValue::Literal(""),
),
args: Rc::new(vec![CallInstrArgValue::Literal("module_config")]),
output: Scalar("module_config"),
output: Variable(Scalar("module_config")),
}),
),
Instruction::Call(Call {
@ -591,7 +586,7 @@ fn seq_with_empty_and_dash() {
CallInstrValue::Literal(""),
),
args: Rc::new(vec![CallInstrArgValue::Literal("blueprint")]),
output: Scalar("blueprint"),
output: Variable(Scalar("blueprint")),
}),
),
seq(
@ -602,10 +597,10 @@ fn seq_with_empty_and_dash() {
CallInstrValue::Literal(""),
),
args: Rc::new(vec![
CallInstrArgValue::Variable("module-bytes"),
CallInstrArgValue::Variable("module_config"),
CallInstrArgValue::Variable(Scalar("module-bytes")),
CallInstrArgValue::Variable(Scalar("module_config")),
]),
output: Scalar("module"),
output: Variable(Scalar("module")),
}),
seq(
Instruction::Call(Call {
@ -614,8 +609,8 @@ fn seq_with_empty_and_dash() {
CallInstrValue::Literal("add_blueprint"),
CallInstrValue::Literal(""),
),
args: Rc::new(vec![CallInstrArgValue::Variable("blueprint")]),
output: Scalar("blueprint_id"),
args: Rc::new(vec![CallInstrArgValue::Variable(Scalar("blueprint"))]),
output: Variable(Scalar("blueprint_id")),
}),
seq(
Instruction::Call(Call {
@ -624,8 +619,8 @@ fn seq_with_empty_and_dash() {
CallInstrValue::Literal("create"),
CallInstrValue::Literal(""),
),
args: Rc::new(vec![CallInstrArgValue::Variable("blueprint_id")]),
output: Scalar("service_id"),
args: Rc::new(vec![CallInstrArgValue::Variable(Scalar("blueprint_id"))]),
output: Variable(Scalar("service_id")),
}),
Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::Literal("remote_peer_id")),
@ -633,8 +628,8 @@ fn seq_with_empty_and_dash() {
CallInstrValue::Literal(""),
CallInstrValue::Literal(""),
),
args: Rc::new(vec![CallInstrArgValue::Variable("service_id")]),
output: Scalar("client_result"),
args: Rc::new(vec![CallInstrArgValue::Variable(Scalar("service_id"))]),
output: Variable(Scalar("client_result")),
}),
),
),
@ -654,7 +649,7 @@ fn match_with_bool() {
)
"#;
let left_value = Variable("isOnline");
let left_value = Variable(Scalar("isOnline"));
let right_value = Boolean(true);
let null = null();
let expected = match_(left_value, right_value, null);
@ -674,7 +669,7 @@ fn mismatch_with_bool() {
"#;
let left_value = Boolean(true);
let right_value = Variable("isOnline");
let right_value = Variable(Scalar("isOnline"));
let null = null();
let expected = mismatch(left_value, right_value, null);
@ -695,10 +690,10 @@ fn no_output() {
"#;
let instruction = parse(source_code);
let expected = Instruction::Call(Call {
peer_part: PeerPk(CallInstrValue::Variable("peer")),
peer_part: PeerPk(CallInstrValue::Variable(Scalar("peer"))),
function_part: ServiceIdWithFuncName(
CallInstrValue::Variable("service"),
CallInstrValue::Variable("fname"),
CallInstrValue::Variable(Scalar("service")),
CallInstrValue::Variable(Scalar("fname")),
),
args: Rc::new(vec![]),
output: None,
@ -719,7 +714,7 @@ fn fold_json_path() {
let instruction = parse(source_code);
let expected = Instruction::Fold(Fold {
iterable: JsonPath {
variable: "members",
variable: Scalar("members"),
path: "$.[\"users\"]",
should_flatten: false,
},
@ -742,7 +737,7 @@ fn comments() {
let instruction = parse(source_code);
let expected = Instruction::Fold(Fold {
iterable: JsonPath {
variable: "members",
variable: Scalar("members"),
path: "$.[\"users\"]",
should_flatten: false,
},

View File

@ -143,7 +143,12 @@ impl<'i> VariableValidator<'i> {
}
}
fn met_variable(&mut self, name: &'i str, span: Span) {
fn met_variable(&mut self, variable: &Variable<'i>, span: Span) {
let name = match variable {
Variable::Scalar(name) => name,
Variable::Stream(name) => name,
};
if !self.contains_variable(name, span) {
self.unresolved_variables.insert(name, span);
}
@ -168,8 +173,8 @@ impl<'i> VariableValidator<'i> {
use std::collections::hash_map::Entry;
let variable_name = match call_output {
CallOutputValue::Scalar(variable) => variable,
CallOutputValue::Accumulator(accumulator) => accumulator,
CallOutputValue::Variable(Variable::Scalar(name)) => name,
CallOutputValue::Variable(Variable::Stream(name)) => name,
CallOutputValue::None => return,
};

View File

@ -1,6 +1,6 @@
[package]
name = "interpreter-lib"
version = "0.7.0"
version = "0.8.0"
authors = ["Fluence Labs"]
edition = "2018"

View File

@ -35,16 +35,16 @@ fn chat_sent_message_benchmark() -> Result<InterpreterOutcome, AquamarineVMError
let script = String::from(
r#"
(seq
(call "Relay1" ("identity" "") [] void1[])
(call "Relay1" ("identity" "") [] $void1)
(seq
(call "Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") [] void2[])
(call "Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") [] $void2)
(seq
(call "Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") [] members)
(fold members m
(par
(seq
(call m.$.[1] ("identity" "") [] void[])
(call m.$.[0] ("fgemb3" "add") [] void3[])
(call m.$.[1] ("identity" "") [] $void)
(call m.$.[0] ("fgemb3" "add") [] $void3)
)
(next m)
)

View File

@ -34,7 +34,7 @@ pub struct ResolvedCallResult {
pub(crate) enum AValue<'i> {
JValueRef(ResolvedCallResult),
JValueAccumulatorRef(RefCell<Vec<ResolvedCallResult>>),
JValueStreamRef(RefCell<Vec<ResolvedCallResult>>),
JValueFoldCursor(FoldState<'i>),
}
@ -42,9 +42,9 @@ impl<'i> Display for AValue<'i> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AValue::JValueRef(value) => write!(f, "{:?}", value)?,
AValue::JValueAccumulatorRef(acc) => {
AValue::JValueStreamRef(stream) => {
write!(f, "[ ")?;
for value in acc.borrow().iter() {
for value in stream.borrow().iter() {
write!(f, "{:?} ", value)?;
}
write!(f, "]")?;

View File

@ -26,18 +26,18 @@ use std::fmt::Formatter;
pub type ExecutionTrace = std::collections::VecDeque<ExecutedState>;
/// Encapsulates all necessary state regarding to the call pathes1.
/// Encapsulates all necessary state regarding to the call paths.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub(crate) struct ExecutionTraceCtx {
/// Contains trace (serialized tree of states) after merging current and previous data,
/// interpreter used it to realize which instructions've been already executed.
/// interpreter used it to realize which instructions have been already executed.
pub(crate) current_trace: ExecutionTrace,
/// Size of a current considered subtree inside current path.
pub(crate) current_subtree_size: usize,
// TODO: consider change it to Vec for optimization
/// Accumulator for resulted path produced by the interpreter after execution.
/// Stream for resulted path produced by the interpreter after execution.
pub(crate) new_trace: ExecutionTrace,
}

View File

@ -79,12 +79,14 @@ impl<'a, 'i> Triplet<'a, 'i> {
/// Resolve value to string by either resolving variable from `ExecutionCtx`, taking literal value, or etc.
// TODO: return Rc<String> to avoid excess cloning
fn resolve_to_string<'i>(value: &CallInstrValue<'i>, ctx: &ExecutionCtx<'i>) -> ExecutionResult<String> {
use crate::execution::utils::get_variable_name;
use crate::execution::utils::resolve_to_jvaluable;
let resolved = match value {
CallInstrValue::InitPeerId => ctx.init_peer_id.clone(),
CallInstrValue::Literal(value) => value.to_string(),
CallInstrValue::Variable(name) => {
CallInstrValue::Variable(variable) => {
let name = get_variable_name(variable);
let resolved = resolve_to_jvaluable(name, ctx)?;
let jvalue = resolved.into_jvalue();
jvalue_to_string(jvalue)?
@ -97,7 +99,9 @@ fn resolve_to_string<'i>(value: &CallInstrValue<'i>, ctx: &ExecutionCtx<'i>) ->
// this is checked on the parsing stage
debug_assert!(*should_flatten);
let resolved = resolve_to_jvaluable(variable, ctx)?;
let name = get_variable_name(variable);
let resolved = resolve_to_jvaluable(name, ctx)?;
let resolved = resolved.apply_json_path(path)?;
vec_to_string(resolved, path)?
}

View File

@ -20,6 +20,7 @@ use super::ExecutionResult;
use crate::contexts::execution::ResolvedCallResult;
use crate::contexts::execution_trace::*;
use crate::exec_err;
use crate::execution::Variable;
use crate::log_targets::EXECUTED_STATE_CHANGING;
use crate::JValue;
@ -43,7 +44,7 @@ pub(super) fn set_local_call_result<'i>(
let executed_result = ResolvedCallResult { result, triplet };
match output {
CallOutputValue::Scalar(name) => {
CallOutputValue::Variable(Variable::Scalar(name)) => {
if let Some(fold_block_name) = exec_ctx.met_folds.back() {
let fold_state = match exec_ctx.data_cache.get_mut(*fold_block_name) {
Some(AValue::JValueFoldCursor(fold_state)) => fold_state,
@ -74,15 +75,15 @@ pub(super) fn set_local_call_result<'i>(
}
};
}
CallOutputValue::Accumulator(name) => {
CallOutputValue::Variable(Variable::Stream(name)) => {
match exec_ctx.data_cache.entry(name.to_string()) {
Occupied(mut entry) => match entry.get_mut() {
// if result is an array, insert result to the end of the array
AValue::JValueAccumulatorRef(values) => values.borrow_mut().push(executed_result),
AValue::JValueStreamRef(values) => values.borrow_mut().push(executed_result),
v => return exec_err!(IncompatibleAValueType(format!("{}", v), String::from("Array"))),
},
Vacant(entry) => {
entry.insert(AValue::JValueAccumulatorRef(RefCell::new(vec![executed_result])));
entry.insert(AValue::JValueStreamRef(RefCell::new(vec![executed_result])));
}
};
}

View File

@ -16,6 +16,7 @@
use crate::contexts::execution::ExecutionCtx;
use crate::execution::air::ExecutionResult;
use crate::execution::utils::get_variable_name;
use crate::execution::utils::resolve_to_jvaluable;
use crate::JValue;
@ -41,10 +42,12 @@ pub(crate) fn are_matchable_eq<'ctx>(
(Number(value), matchable) => compare_matchable(matchable, exec_ctx, make_number_comparator(value)),
(matchable, Number(value)) => compare_matchable(matchable, exec_ctx, make_number_comparator(value)),
(Variable(left_name), Variable(right_name)) => {
(Variable(left_variable), Variable(right_variable)) => {
let left_name = get_variable_name(left_variable);
let left_jvaluable = resolve_to_jvaluable(left_name, exec_ctx)?;
let left_value = left_jvaluable.as_jvalue();
let right_name = get_variable_name(right_variable);
let right_jvaluable = resolve_to_jvaluable(right_name, exec_ctx)?;
let right_value = right_jvaluable.as_jvalue();
@ -67,10 +70,12 @@ pub(crate) fn are_matchable_eq<'ctx>(
return Ok(false);
}
let left_jvaluable = resolve_to_jvaluable(lv, exec_ctx)?;
let left_name = get_variable_name(lv);
let left_jvaluable = resolve_to_jvaluable(left_name, exec_ctx)?;
let left_value = left_jvaluable.apply_json_path(lp)?;
let right_jvaluable = resolve_to_jvaluable(rv, exec_ctx)?;
let right_name = get_variable_name(rv);
let right_jvaluable = resolve_to_jvaluable(right_name, exec_ctx)?;
let right_value = right_jvaluable.apply_json_path(rp)?;
Ok(left_value == right_value)
@ -102,7 +107,8 @@ fn compare_matchable<'ctx>(
let jvalue = (*bool).into();
Ok(comparator(Cow::Owned(jvalue)))
}
Variable(name) => {
Variable(variable) => {
let name = get_variable_name(variable);
let jvaluable = resolve_to_jvaluable(name, exec_ctx)?;
let jvalue = jvaluable.as_jvalue();
Ok(comparator(jvalue))
@ -112,7 +118,8 @@ fn compare_matchable<'ctx>(
path,
should_flatten,
} => {
let jvaluable = resolve_to_jvaluable(variable, exec_ctx)?;
let var_name = get_variable_name(variable);
let jvaluable = resolve_to_jvaluable(var_name, exec_ctx)?;
let jvalues = jvaluable.apply_json_path(path)?;
let jvalue = if *should_flatten {

View File

@ -186,7 +186,7 @@ mod tests {
(call "set_variable" ("" "") [] Iterable)
(fold Iterable i
(seq
(call "A" ("" "") [i] acc[])
(call "A" ("" "") [i] $acc)
(next i)
)
)
@ -220,7 +220,7 @@ mod tests {
(fold Iterable i
(seq
(next i)
(call "A" ("" "") [i] acc[])
(call "A" ("" "") [i] $acc)
)
)
)"#,
@ -257,7 +257,7 @@ mod tests {
(seq
(fold Iterable2 j
(seq
(call "A" ("" "") [i] acc[])
(call "A" ("" "") [i] $acc)
(next j)
)
)
@ -300,7 +300,7 @@ mod tests {
(seq
(fold Iterable2 i
(seq
(call "A" ("" "") [i] acc[])
(call "A" ("" "") [i] $acc)
(next i)
)
)
@ -329,7 +329,7 @@ mod tests {
(call "set_variable" ("" "") [] Iterable)
(fold Iterable i
(seq
(call "A" ("" "") [i] acc[])
(call "A" ("" "") [i] $acc)
(next i)
)
)
@ -358,7 +358,7 @@ mod tests {
(call "unknown_peer" ("" "") [] lazy_def_variable)
(fold iterable i
(seq
(call "A" ("" "") [lazy_def_variable.$.hash!] acc[])
(call "A" ("" "") [lazy_def_variable.$.hash!] $acc)
(next i)
)
)
@ -390,7 +390,7 @@ mod tests {
(call "set_variable" ("" "") [] iterable)
(fold iterable.$.array! i
(seq
(call "A" ("" "") [i] acc[])
(call "A" ("" "") [i] $acc)
(next i)
)
)

View File

@ -16,6 +16,7 @@
use super::*;
use crate::exec_err;
use crate::execution::utils::get_variable_name;
use crate::JValue;
use crate::ResolvedTriplet;
use crate::SecurityTetraplet;
@ -36,12 +37,18 @@ pub(super) fn construct_iterable_value<'ctx>(
exec_ctx: &ExecutionCtx<'ctx>,
) -> ExecutionResult<Option<IterableValue>> {
match ast_iterable {
ast::IterableValue::Variable(name) => handle_instruction_variable(exec_ctx, name),
ast::IterableValue::Variable(variable) => {
let name = get_variable_name(variable);
handle_instruction_variable(exec_ctx, name)
}
ast::IterableValue::JsonPath {
variable,
path,
should_flatten,
} => handle_instruction_json_path(exec_ctx, variable, path, *should_flatten),
} => {
let name = get_variable_name(variable);
handle_instruction_json_path(exec_ctx, name, path, *should_flatten)
}
}
}
@ -51,13 +58,13 @@ fn handle_instruction_variable<'ctx>(
) -> ExecutionResult<Option<IterableValue>> {
let iterable: Option<IterableValue> = match exec_ctx.data_cache.get(variable_name) {
Some(AValue::JValueRef(call_result)) => from_call_result(call_result.clone())?,
Some(AValue::JValueAccumulatorRef(acc)) => {
let acc = acc.borrow();
if acc.is_empty() {
Some(AValue::JValueStreamRef(stream)) => {
let stream = stream.borrow();
if stream.is_empty() {
return Ok(None);
}
let call_results = acc.iter().cloned().collect::<Vec<_>>();
let call_results = stream.iter().cloned().collect::<Vec<_>>();
let foldable = IterableVecResolvedCall::init(call_results);
Some(Box::new(foldable))
}
@ -103,28 +110,28 @@ fn handle_instruction_json_path<'ctx>(
json_path: &str,
should_flatten: bool,
) -> ExecutionResult<Option<IterableValue>> {
use ExecutionError::JValueAccJsonPathError;
use ExecutionError::JValueStreamJsonPathError;
match exec_ctx.data_cache.get(variable_name) {
Some(AValue::JValueRef(variable)) => {
let jvalues = apply_json_path(&variable.result, json_path)?;
from_jvalues(jvalues, variable.triplet.clone(), json_path, should_flatten)
}
Some(AValue::JValueAccumulatorRef(acc)) => {
let acc = acc.borrow();
if acc.is_empty() {
Some(AValue::JValueStreamRef(stream)) => {
let stream = stream.borrow();
if stream.is_empty() {
return Ok(None);
}
let acc_iter = acc.iter().map(|v| v.result.deref());
let acc_iter = stream.iter().map(|v| v.result.deref());
let (jvalues, tetraplet_indices) = select_with_iter(acc_iter, &json_path)
.map_err(|e| JValueAccJsonPathError(acc.clone(), json_path.to_string(), e))?;
.map_err(|e| JValueStreamJsonPathError(stream.clone(), json_path.to_string(), e))?;
let jvalues = construct_iterable_jvalues(jvalues, should_flatten)?;
let tetraplets = tetraplet_indices
.into_iter()
.map(|id| SecurityTetraplet {
triplet: acc[id].triplet.clone(),
triplet: stream[id].triplet.clone(),
json_path: json_path.to_string(),
})
.collect::<Vec<_>>();

View File

@ -196,8 +196,8 @@ fn is_joinable_error_type(exec_error: &ExecutionError) -> bool {
log_join!(" waiting for an argument with path '{}' on jvalue '{:?}'", json_path, value);
true
}
JValueAccJsonPathError(acc, json_path, _) => {
log_join!(" waiting for an argument with path '{}' on accumulator '{:?}'", json_path, acc);
JValueStreamJsonPathError(stream, json_path, _) => {
log_join!(" waiting for an argument with path '{}' on stream '{:?}'", json_path, stream);
true
}
_ => false,

View File

@ -21,7 +21,7 @@ use crate::foldable_prev;
use crate::JValue;
use crate::SecurityTetraplet;
/// Used for iterating over a result of applied to an accumulator json path.
/// Used for iterating over a result of applied to an stream json path.
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct IterableVecJsonPathResult {
pub(crate) jvalues: Vec<JValue>,

View File

@ -21,7 +21,7 @@ use crate::foldable_next;
use crate::foldable_prev;
use crate::SecurityTetraplet;
/// Used for iterating over accumulator with JValues.
/// Used for iterating over stream with JValues.
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct IterableVecResolvedCall {
pub(crate) call_results: Vec<ResolvedCallResult>,

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
use super::ExecutionError::JValueAccJsonPathError;
use super::ExecutionError::JValueStreamJsonPathError;
use super::ExecutionResult;
use super::JValuable;
use crate::contexts::execution::ResolvedCallResult;
@ -29,8 +29,9 @@ use std::ops::Deref;
impl JValuable for std::cell::Ref<'_, Vec<ResolvedCallResult>> {
fn apply_json_path(&self, json_path: &str) -> ExecutionResult<Vec<&JValue>> {
let acc_iter = self.iter().map(|r| r.result.deref());
let (selected_values, _) = select_with_iter(acc_iter, json_path)
.map_err(|e| JValueAccJsonPathError(self.iter().cloned().collect::<Vec<_>>(), json_path.to_string(), e))?;
let (selected_values, _) = select_with_iter(acc_iter, json_path).map_err(|e| {
JValueStreamJsonPathError(self.iter().cloned().collect::<Vec<_>>(), json_path.to_string(), e)
})?;
Ok(selected_values)
}
@ -41,8 +42,9 @@ impl JValuable for std::cell::Ref<'_, Vec<ResolvedCallResult>> {
) -> ExecutionResult<(Vec<&JValue>, Vec<SecurityTetraplet>)> {
let acc_iter = self.iter().map(|r| r.result.deref());
let (selected_values, tetraplet_indices) = select_with_iter(acc_iter, json_path)
.map_err(|e| JValueAccJsonPathError(self.iter().cloned().collect::<Vec<_>>(), json_path.to_string(), e))?;
let (selected_values, tetraplet_indices) = select_with_iter(acc_iter, json_path).map_err(|e| {
JValueStreamJsonPathError(self.iter().cloned().collect::<Vec<_>>(), json_path.to_string(), e)
})?;
let tetraplets = tetraplet_indices
.into_iter()

View File

@ -52,9 +52,9 @@ pub(crate) enum ExecutionError {
#[error("variable with path '{1}' not found in '{0}' with an error: '{2}'")]
JValueJsonPathError(JValue, String, JsonPathError),
/// An error occurred while trying to apply json path to this accumulator with JValue's.
/// An error occurred while trying to apply json path to this stream with JValue's.
#[error("variable with path '{1}' not found in '{0:?}' with error: '{2}'")]
JValueAccJsonPathError(Vec<ResolvedCallResult>, String, JsonPathError),
JValueStreamJsonPathError(Vec<ResolvedCallResult>, String, JsonPathError),
/// Provided JValue has incompatible with target type.
#[error("expected JValue type '{1}', but got '{0}' JValue")]
@ -108,7 +108,7 @@ impl ExecutionError {
VariableNotFound(_) => 4,
MultipleVariablesFound(_) => 5,
JValueJsonPathError(..) => 6,
JValueAccJsonPathError(..) => 7,
JValueStreamJsonPathError(..) => 7,
IncompatibleJValueType(..) => 8,
IncompatibleAValueType(..) => 9,
MultipleValuesInJsonPath(_) => 10,

View File

@ -26,6 +26,7 @@ pub(super) use errors::ExecutionError;
use std::rc::Rc;
pub(self) type ExecutionResult<T> = std::result::Result<T, Rc<ExecutionError>>;
pub(self) use air_parser::ast::Variable;
#[macro_export]
macro_rules! exec_err {

View File

@ -16,5 +16,6 @@
mod resolve;
pub(crate) use resolve::get_variable_name;
pub(crate) use resolve::resolve_to_args;
pub(crate) use resolve::resolve_to_jvaluable;

View File

@ -35,12 +35,18 @@ pub(crate) fn resolve_to_args<'i>(
CallInstrArgValue::Literal(value) => prepare_consts(value.to_string(), ctx),
CallInstrArgValue::Boolean(value) => prepare_consts(*value, ctx),
CallInstrArgValue::Number(value) => prepare_consts(value, ctx),
CallInstrArgValue::Variable(name) => prepare_variable(name, ctx),
CallInstrArgValue::Variable(variable) => {
let name = get_variable_name(variable);
prepare_variable(name, ctx)
}
CallInstrArgValue::JsonPath {
variable,
path,
should_flatten,
} => prepare_json_path(variable, path, *should_flatten, ctx),
} => {
let name = get_variable_name(variable);
prepare_json_path(name, path, *should_flatten, ctx)
}
}
}
@ -121,10 +127,19 @@ pub(crate) fn resolve_to_jvaluable<'name, 'i, 'ctx>(
match value {
AValue::JValueRef(value) => Ok(Box::new(value.clone())),
AValue::JValueAccumulatorRef(acc) => Ok(Box::new(acc.borrow())),
AValue::JValueStreamRef(stream) => Ok(Box::new(stream.borrow())),
AValue::JValueFoldCursor(fold_state) => {
let peeked_value = fold_state.iterable.peek().unwrap();
Ok(Box::new(peeked_value))
}
}
}
use air_parser::ast::Variable;
pub(crate) fn get_variable_name<'a>(variable: &'a Variable<'_>) -> &'a str {
match variable {
Variable::Scalar(name) => name,
Variable::Stream(name) => name,
}
}

View File

@ -254,7 +254,7 @@ fn executed_trace_par_seq_fold_call() {
(call "some_peer_id_1" ("local_service_id" "local_fn_name") [] IterableResultPeer1)
(fold IterableResultPeer1 i
(par
(call "some_peer_id_2" ("local_service_id" "local_fn_name") [i] acc[])
(call "some_peer_id_2" ("local_service_id" "local_fn_name") [i] $acc)
(next i)
)
)
@ -330,7 +330,7 @@ fn executed_trace_par_seq_fold_in_cycle_call() {
(call "some_peer_id_1" ("local_service_id" "local_fn_name") [] IterableResultPeer1)
(fold IterableResultPeer1 i
(par
(call "some_peer_id_2" ("local_service_id" "local_fn_name") [i] acc[])
(call "some_peer_id_2" ("local_service_id" "local_fn_name") [i] $acc)
(next i)
)
)

View File

@ -51,19 +51,19 @@ fn data_merge() {
(seq
(fold neighborhood i
(par
(call i ("add_provider" "") [] void[])
(call i ("add_provider" "") [] $void)
(next i)
)
)
(fold neighborhood i
(par
(call i ("get_providers" "") [] providers[])
(call i ("get_providers" "") [] $providers)
(next i)
)
)
)
(seq
(call "A" ("identity" "") [] void[])
(call "A" ("identity" "") [] $void)
(call "B" ("" "") [] none)
)
)
@ -189,16 +189,16 @@ fn acc_merge() {
let script = String::from(
r#"
(seq
(call "A" ("add_provider" "") [] void[])
(call "A" ("add_provider" "") [] $void)
(seq
(call "A" ("add_provider" "") [] void[])
(call "A" ("add_provider" "") [] $void)
(seq
(call "A" ("get_providers" "") [] providers[])
(call "A" ("get_providers" "") [] $providers)
(seq
(call "A" ("get_providers" "") [] providers[])
(call "A" ("get_providers" "") [] $providers)
(seq
(call "B" ("" "2") [providers] void[])
(call "B" ("" "3") [void] void[])
(call "B" ("" "2") [$providers] $void)
(call "B" ("" "3") [$void] $void)
)
)
)

View File

@ -130,12 +130,12 @@ fn flattening_streams() {
(seq
(seq
(seq
(call "{0}" ("" "") [] stream[])
(call "{0}" ("" "") [] stream[])
(call "{0}" ("" "") [] $stream)
(call "{0}" ("" "") [] $stream)
)
(call "{0}" ("" "") [] stream[])
(call "{0}" ("" "") [] $stream)
)
(fold stream.$.[0,1,2] v
(fold $stream.$.[0,1,2] v
(seq
(call v.$.peer_id! (v.$.service_id! v.$.function_name!) [v.$.args[0]! v.$.args[1]!])
(next v)
@ -180,12 +180,12 @@ fn test_handling_non_flattening_values() {
(seq
(seq
(seq
(call "{0}" ("" "") [] stream[])
(call "{0}" ("" "") [] stream[])
(call "{0}" ("" "") [] $stream)
(call "{0}" ("" "") [] $stream)
)
(call "{0}" ("" "") [] stream[])
(call "{0}" ("" "") [] $stream)
)
(fold stream.$.[0,1,2]! v
(fold $stream.$.[0,1,2]! v
(seq
(call v.$.peer_id! (v.$.service_id! v.$.function_name!) [v.$.args[0]! v.$.args[1]!])
(next v)

View File

@ -49,16 +49,16 @@ fn join_chat() {
let script = String::from(
r#"
(seq
(call "Relay1" ("identity" "") [] void1[])
(call "Relay1" ("identity" "") [] $void1)
(seq
(call "Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") [] void2[])
(call "Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") [] $void2)
(seq
(call "Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") [] members)
(fold members m
(par
(seq
(call m.$.[1]! ("identity" "") [] void[])
(call m.$.[0]! ("fgemb3" "add") [] void3[])
(call m.$.[1]! ("identity" "") [] $void)
(call m.$.[0]! ("fgemb3" "add") [] $void3)
)
(next m)
)
@ -210,14 +210,14 @@ fn join() {
let script = String::from(
r#"
(seq
(call "Relay1" ("identity" "") [] void1[])
(call "Relay1" ("identity" "") [] $void1)
(seq
(call "Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") [] members)
(fold members m
(par
(seq
(call "Relay1" ("identity" "") [] void[])
(call "A" ("fgemb3" "add") [m] void3[])
(call "Relay1" ("identity" "") [] $void)
(call "A" ("fgemb3" "add") [m] $void3)
)
(next m)
)

View File

@ -18,7 +18,7 @@
)
)
(seq
(call "{1}" ("op" "identity") ["XOR: create_greeting_service failed"] fail[])
(call "{1}" ("op" "identity") ["XOR: create_greeting_service failed"] $fail)
(call "{2}" ("return" "") [%last_error%])
)
)

View File

@ -8,15 +8,15 @@
(seq
(fold neighs_top n
(seq
(call n ("dht" "neighborhood") [n] neighs_inner[])
(call n ("dht" "neighborhood") [n] $neighs_inner)
(next n)
)
)
(fold neighs_inner ns
(fold $neighs_inner ns
(seq
(fold ns n
(seq
(call n ("op" "identify") [] services[])
(call n ("op" "identify") [] $services)
(next n)
)
)

View File

@ -81,7 +81,7 @@ fn simple_fold() {
(call "{}" ("{}" "{}") [] IterableResultPeer1)
(fold IterableResultPeer1 i
(par
(call i ("local_service_id" "local_fn_name") [i "some_text_literal"] acc[])
(call i ("local_service_id" "local_fn_name") [i "some_text_literal"] $acc)
(next i)
)
)
@ -155,7 +155,7 @@ fn fold_json_path() {
(call "{}" ("{}" "{}") [] IterableResultPeer1)
(fold IterableResultPeer1.$.arg i
(par
(call "{}" ("local_service_id" "local_fn_name") [i "some_text_literal"] acc[])
(call "{}" ("local_service_id" "local_fn_name") [i "some_text_literal"] $acc)
(next i)
)
)

View File

@ -1,6 +1,6 @@
[package]
name = "aquamarine"
version = "0.7.0"
version = "0.8.0"
authors = ["Fluence Labs"]
edition = "2018"