Refactor call triplets (#269)

Older grammar allowed some variabilty in triple format.  Now, the only
format allowed is:

  `peer_id (service_id function_name)`

As less errors can happen during parsing of the triplet, the code was
simplified further .

Closes #267.
This commit is contained in:
Ivan Boldyrev 2022-05-19 15:59:08 +03:00 committed by GitHub
parent 99d7aa0d93
commit 3c23ab735c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1107 additions and 1447 deletions

View File

@ -32,20 +32,6 @@ pub enum CallInstrValue<'i> {
Variable(VariableWithLambda<'i>),
}
/// The peer part of a call instruction triplet
#[derive(Serialize, Debug, PartialEq)]
pub enum PeerPart<'i> {
PeerPk(CallInstrValue<'i>),
PeerPkWithServiceId(CallInstrValue<'i>, CallInstrValue<'i>),
}
/// The function part of a call instruction triplet
#[derive(Serialize, Debug, PartialEq)]
pub enum FunctionPart<'i> {
FuncName(CallInstrValue<'i>),
ServiceIdWithFuncName(CallInstrValue<'i>, CallInstrValue<'i>),
}
/// Triplet represents a location of the executable code in the network.
/// It is build from `PeerPart` and `FunctionPart` of a `Call` instruction.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]

View File

@ -76,30 +76,6 @@ impl fmt::Display for ApArgument<'_> {
}
}
impl fmt::Display for PeerPart<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use PeerPart::*;
match self {
PeerPk(peer_pk) => write!(f, "{}", peer_pk),
PeerPkWithServiceId(peer_pk, service_id) => write!(f, "({} {})", peer_pk, service_id),
}
}
}
impl fmt::Display for FunctionPart<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use FunctionPart::*;
match self {
FuncName(func_name) => write!(f, "{}", func_name),
ServiceIdWithFuncName(service_id, func_name) => {
write!(f, "({} {})", service_id, func_name)
}
}
}
}
impl fmt::Display for Triplet<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(

View File

@ -3,8 +3,6 @@ use crate::parser::ParserError;
use crate::parser::VariableValidator;
use crate::parser::Span;
use crate::parser::lexer::Token;
use crate::parser::air_utils::*;
use crate::make_user_error;
use air_lambda_parser::LambdaAST;
use lalrpop_util::ErrorRecovery;
@ -16,16 +14,7 @@ grammar<'err, 'input, 'v>(input: &'input str, errors: &'err mut Vec<ErrorRecover
pub AIR = Instr;
Instr: Box<Instruction<'input>> = {
<left: @L> "(" call <peer_part:PeerPart> <function_part:FPart> <args:Args> <output:CallOutput?> ")" <right: @R> => {
let triplet = match try_to_raw_triplet(peer_part, function_part) {
Some(raw_triplet) => raw_triplet,
None => {
// none means error
errors.push(make_user_error!(InvalidCallTriplet, left, Token::Call, right));
return Box::new(Instruction::Error);
}
};
<left: @L> "(" call <triplet:Triplet> <args:Args> <output:CallOutput?> ")" <right: @R> => {
let args = Rc::new(args);
let output = output.map(CallOutputValue::Variable).unwrap_or(CallOutputValue::None);
let call = Call::new(triplet, args, output);
@ -117,14 +106,12 @@ Args: Vec<Value<'input>> = {
"[" <args:(<Arg>)*> "]" => args
}
FPart: FunctionPart<'input> = {
<f:Function> => FunctionPart::FuncName(f),
"(" <sid:ServiceId> <f:Function> ")" => FunctionPart::ServiceIdWithFuncName(sid, f),
}
PeerPart: PeerPart<'input> = {
<pid:PeerId> => PeerPart::PeerPk(pid),
"(" <pid:PeerId> <sid:ServiceId> ")" => PeerPart::PeerPkWithServiceId(pid, sid),
Triplet: Triplet<'input> = {
<peer_pk:PeerId> "(" <service_id:ServiceId> <function_name:Function> ")" => Triplet {
peer_pk,
service_id,
function_name
}
}
ApResult = ScriptVariable;

File diff suppressed because it is too large Load Diff

View File

@ -14,10 +14,6 @@
* limitations under the License.
*/
mod triplet;
pub(crate) use triplet::try_to_raw_triplet;
#[macro_export]
macro_rules! make_user_error(
($error_type:ident, $start_pos: ident, $token:expr, $end_pos: ident) => { {

View File

@ -1,49 +0,0 @@
/*
* Copyright 2021 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::ast::FunctionPart;
use crate::ast::PeerPart;
use crate::ast::Triplet;
/// Build a `Triplet` from `Call`'s `PeerPart` and `FunctionPart`
pub(crate) fn try_to_raw_triplet<'i>(
peer: PeerPart<'i>,
f: FunctionPart<'i>,
) -> Option<Triplet<'i>> {
use FunctionPart::*;
use PeerPart::*;
let (peer_pk, service_id, function_name) = match (peer, f) {
(PeerPkWithServiceId(peer_pk, _), ServiceIdWithFuncName(service_id, func_name)) => {
(peer_pk, service_id, func_name)
}
(PeerPkWithServiceId(peer_pk, peer_service_id), FuncName(func_name)) => {
(peer_pk, peer_service_id, func_name)
}
(PeerPk(peer_pk), ServiceIdWithFuncName(service_id, func_name)) => {
(peer_pk, service_id, func_name)
}
(PeerPk(_), FuncName(_)) => return None,
};
let raw_triplet = Triplet {
peer_pk,
service_id,
function_name,
};
Some(raw_triplet)
}

View File

@ -36,10 +36,6 @@ pub enum ParserError {
#[error("last error with non-empty path is ambiguous, please use just %last_error%")]
AmbiguousFailLastError(Span),
/// Semantic errors in a call instructions.
#[error("call should have service id specified by peer part or function part")]
InvalidCallTriplet(Span),
#[error("new can't be applied to a '{iterator_name}' because it's an iterator")]
IteratorRestrictionNotAllowed { span: Span, iterator_name: String },
@ -60,7 +56,6 @@ impl ParserError {
Self::UndefinedVariable { span, .. } => *span,
Self::UndefinedIterable { span, .. } => *span,
Self::AmbiguousFailLastError(span) => *span,
Self::InvalidCallTriplet(span) => *span,
Self::IteratorRestrictionNotAllowed { span, .. } => *span,
Self::MultipleIterableValuesForOneIterator { span, .. } => *span,
Self::MultipleNextInFold { span, .. } => *span,

View File

@ -174,31 +174,6 @@ fn parse_undefined_stream_with_lambda() {
));
}
#[test]
fn parse_call_with_invalid_triplet() {
let source_code = r#"
(call "" "" [$stream.$.json_path])
"#;
let lexer = crate::AIRLexer::new(source_code);
let parser = crate::AIRParser::new();
let mut errors = Vec::new();
let mut validator = crate::parser::VariableValidator::new();
parser
.parse(source_code, &mut errors, &mut validator, lexer)
.expect("parser shouldn't fail");
assert_eq!(errors.len(), 1);
let error = &errors[0].error;
let parser_error = match error {
ParseError::User { error } => error,
_ => panic!("unexpected error type"),
};
assert!(matches!(parser_error, ParserError::InvalidCallTriplet(..)));
}
#[test]
fn parse_lambda_complex() {
let source_code = r#"

View File

@ -55,7 +55,7 @@ fn parse_par_par() {
(par
(par
(call "" ("" "") [])
(call ("" "") ("" "") [])
(call "" ("" "") [])
)
(call "" ("" "") [])
)

View File

@ -59,7 +59,7 @@ fn parse_seq_seq() {
(seq
(seq
(call peer_id (service_id function_name) [])
(call (peer_id service_A) ("service_B" function_name) [])
(call peer_id ("service_B" function_name) [])
)
(call "peer_id" ("service_id" "function_name") ["hello" name] $output)
)
@ -70,14 +70,14 @@ fn parse_seq_seq() {
call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 53)),
CallInstrValue::Variable(VariableWithLambda::scalar("service_id", 62)),
CallInstrValue::Variable(VariableWithLambda::scalar("function_name", 073)),
CallInstrValue::Variable(VariableWithLambda::scalar("function_name", 73)),
Rc::new(vec![]),
CallOutputValue::None,
),
call(
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 115)),
CallInstrValue::Variable(VariableWithLambda::scalar("peer_id", 114)),
CallInstrValue::Literal("service_B"),
CallInstrValue::Variable(VariableWithLambda::scalar("function_name", 147)),
CallInstrValue::Variable(VariableWithLambda::scalar("function_name", 135)),
Rc::new(vec![]),
CallOutputValue::None,
),
@ -88,9 +88,9 @@ fn parse_seq_seq() {
CallInstrValue::Literal("function_name"),
Rc::new(vec![
Value::Literal("hello"),
Value::Variable(VariableWithLambda::scalar("name", 248)),
Value::Variable(VariableWithLambda::scalar("name", 236)),
]),
CallOutputValue::Variable(Variable::stream("$output", 254)),
CallOutputValue::Variable(Variable::stream("$output", 242)),
),
);
assert_eq!(instruction, expected);