Introduce never instruction (#335)

This commit is contained in:
Mike Voronov 2022-09-19 14:36:46 +03:00 committed by GitHub
parent 250b316682
commit 20bb230a3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 955 additions and 756 deletions

View File

@ -1,3 +1,11 @@
## Version 0.29.0 (2022-09-19)
[PR 335](https://github.com/fluencelabs/aquavm/pull/335):
Introduce `never` instruction
[PR 332](https://github.com/fluencelabs/aquavm/pull/332):
Fix bug with incorrect positions in `canon` instruction
## Version 0.28.0 (2022-09-07) ## Version 0.28.0 (2022-09-07)
[PR 314](https://github.com/fluencelabs/aquavm/pull/314): [PR 314](https://github.com/fluencelabs/aquavm/pull/314):

View File

@ -28,7 +28,7 @@ AIR scripts control the Fluence peer-to-peer network, its peers and, through Mar
### What is AIR? ### What is AIR?
- S-expression-based low-level language with binary form to come - S-expression-based low-level language with binary form to come
- Consists of twelve (12) instructions with more instructions to come - Consists of fourteen (14) instructions with more instructions to come
- Semantics are inspired by [π-calculus](https://en.wikipedia.org/wiki/%CE%A0-calculus), [λ-calculus](https://en.wikipedia.org/wiki/Lambda_calculus) and [category theory](https://en.wikipedia.org/wiki/Category_theory) - Semantics are inspired by [π-calculus](https://en.wikipedia.org/wiki/%CE%A0-calculus), [λ-calculus](https://en.wikipedia.org/wiki/Lambda_calculus) and [category theory](https://en.wikipedia.org/wiki/Category_theory)
- Syntax is inspired by [Wasm Text Format](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format) (WAT) and [Lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)) - Syntax is inspired by [Wasm Text Format](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format) (WAT) and [Lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language))
@ -175,6 +175,14 @@ Example
(fail 1337 "error message") (fail 1337 "error message")
``` ```
#### never
```wasm
(never)
```
- marks a subgraph as incomplete, useful for code generation
#### null #### null
```wasm ```wasm

View File

@ -1,6 +1,6 @@
[package] [package]
name = "air-interpreter" name = "air-interpreter"
version = "0.28.0" version = "0.29.0"
description = "Crate-wrapper for air" description = "Crate-wrapper for air"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
edition = "2018" edition = "2018"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "air" name = "air"
version = "0.28.0" version = "0.29.0"
description = "Interpreter of AIR scripts intended to coordinate request flow in the Fluence network" description = "Interpreter of AIR scripts intended to coordinate request flow in the Fluence network"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
edition = "2018" edition = "2018"

View File

@ -24,6 +24,7 @@ mod fold_scalar;
mod fold_stream; mod fold_stream;
mod match_; mod match_;
mod mismatch; mod mismatch;
mod never;
mod new; mod new;
mod next; mod next;
mod null; mod null;
@ -80,6 +81,7 @@ impl<'i> ExecutableInstruction<'i> for Instruction<'i> {
Instruction::Fail(fail) => execute!(self, fail, exec_ctx, trace_ctx), Instruction::Fail(fail) => execute!(self, fail, exec_ctx, trace_ctx),
Instruction::FoldScalar(fold) => execute!(self, fold, exec_ctx, trace_ctx), Instruction::FoldScalar(fold) => execute!(self, fold, exec_ctx, trace_ctx),
Instruction::FoldStream(fold) => execute!(self, fold, exec_ctx, trace_ctx), Instruction::FoldStream(fold) => execute!(self, fold, exec_ctx, trace_ctx),
Instruction::Never(never) => execute!(self, never, exec_ctx, trace_ctx),
Instruction::New(new) => execute!(self, new, exec_ctx, trace_ctx), Instruction::New(new) => execute!(self, new, exec_ctx, trace_ctx),
Instruction::Next(next) => execute!(self, next, exec_ctx, trace_ctx), Instruction::Next(next) => execute!(self, next, exec_ctx, trace_ctx),
Instruction::Null(null) => execute!(self, null, exec_ctx, trace_ctx), Instruction::Null(null) => execute!(self, null, exec_ctx, trace_ctx),

View File

@ -0,0 +1,31 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::ExecutionCtx;
use super::ExecutionResult;
use super::TraceHandler;
use crate::log_instruction;
use air_parser::ast::Never;
impl<'i> super::ExecutableInstruction<'i> for Never {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, trace_ctx: &mut TraceHandler) -> ExecutionResult<()> {
log_instruction!(null, exec_ctx, trace_ctx);
exec_ctx.subgraph_complete = false;
Ok(())
}
}

View File

@ -21,6 +21,7 @@ mod fail;
mod fold; mod fold;
mod match_; mod match_;
mod mismatch; mod mismatch;
mod never;
mod new; mod new;
mod par; mod par;
mod seq; mod seq;

View File

@ -0,0 +1,34 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use air_test_utils::prelude::*;
#[test]
fn never_not_complete_subgraph() {
let vm_peer_id = "test_peer_id";
let mut vm = create_avm(unit_call_service(), vm_peer_id);
let script = f!(r#"
(seq
(never)
(call "{vm_peer_id}" ("" "") [])
)
"#);
let result = checked_call_vm!(vm, <_>::default(), script, "", "");
let actual_trace = trace_from_result(&result);
assert!(actual_trace.is_empty());
}

View File

@ -37,6 +37,7 @@ pub enum Instruction<'i> {
Fail(Fail<'i>), Fail(Fail<'i>),
FoldScalar(FoldScalar<'i>), FoldScalar(FoldScalar<'i>),
FoldStream(FoldStream<'i>), FoldStream(FoldStream<'i>),
Never(Never),
New(New<'i>), New(New<'i>),
Next(Next<'i>), Next(Next<'i>),
Null(Null), Null(Null),
@ -137,6 +138,10 @@ pub struct Next<'i> {
pub iterator: Scalar<'i>, pub iterator: Scalar<'i>,
} }
/// (never)
#[derive(Serialize, Debug, PartialEq, Eq)]
pub struct Never;
/// (new variable instruction) /// (new variable instruction)
#[derive(Serialize, Debug, PartialEq)] #[derive(Serialize, Debug, PartialEq)]
pub struct New<'i> { pub struct New<'i> {

View File

@ -34,6 +34,7 @@ impl fmt::Display for Instruction<'_> {
Fail(fail) => write!(f, "{}", fail), Fail(fail) => write!(f, "{}", fail),
FoldScalar(fold) => write!(f, "{}", fold), FoldScalar(fold) => write!(f, "{}", fold),
FoldStream(fold) => write!(f, "{}", fold), FoldStream(fold) => write!(f, "{}", fold),
Never(never) => write!(f, "{}", never),
Next(next) => write!(f, "{}", next), Next(next) => write!(f, "{}", next),
New(new) => write!(f, "{}", new), New(new) => write!(f, "{}", new),
Null(null) => write!(f, "{}", null), Null(null) => write!(f, "{}", null),
@ -131,6 +132,12 @@ impl fmt::Display for MisMatch<'_> {
} }
} }
impl fmt::Display for Never {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "never")
}
}
impl fmt::Display for Next<'_> { impl fmt::Display for Next<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "next {}", self.iterator) write!(f, "next {}", self.iterator)

View File

@ -46,6 +46,7 @@ Instr: Box<Instruction<'input>> = {
"(" seq <l:Instr> <r:Instr> ")" => Box::new(Instruction::Seq(Seq::new(l, r))), "(" seq <l:Instr> <r:Instr> ")" => Box::new(Instruction::Seq(Seq::new(l, r))),
"(" par <l:Instr> <r:Instr> ")" => Box::new(Instruction::Par(Par::new(l, r))), "(" par <l:Instr> <r:Instr> ")" => Box::new(Instruction::Par(Par::new(l, r))),
"(" never ")" => Box::new(Instruction::Never(Never)),
"(" null ")" => Box::new(Instruction::Null(Null)), "(" null ")" => Box::new(Instruction::Null(Null)),
<left: @L> "(" new <argument: NewArgument> <instruction:Instr> ")" <right: @R> => { <left: @L> "(" new <argument: NewArgument> <instruction:Instr> ")" <right: @R> => {
@ -264,6 +265,7 @@ extern {
fail => Token::Fail, fail => Token::Fail,
fold => Token::Fold, fold => Token::Fold,
xor => Token::Xor, xor => Token::Xor,
never => Token::Never,
new => Token::New, new => Token::New,
next => Token::Next, next => Token::Next,
null => Token::Null, null => Token::Null,

File diff suppressed because it is too large Load Diff

View File

@ -183,6 +183,7 @@ fn string_to_token(input: &str, start_pos: usize) -> LexerResult<Token> {
FAIL_INSTR => Ok(Token::Fail), FAIL_INSTR => Ok(Token::Fail),
FOLD_INSTR => Ok(Token::Fold), FOLD_INSTR => Ok(Token::Fold),
XOR_INSTR => Ok(Token::Xor), XOR_INSTR => Ok(Token::Xor),
NEVER_INSTR => Ok(Token::Never),
NEW_INSTR => Ok(Token::New), NEW_INSTR => Ok(Token::New),
NEXT_INSTR => Ok(Token::Next), NEXT_INSTR => Ok(Token::Next),
NULL_INSTR => Ok(Token::Null), NULL_INSTR => Ok(Token::Null),
@ -233,6 +234,7 @@ const PAR_INSTR: &str = "par";
const FAIL_INSTR: &str = "fail"; const FAIL_INSTR: &str = "fail";
const FOLD_INSTR: &str = "fold"; const FOLD_INSTR: &str = "fold";
const XOR_INSTR: &str = "xor"; const XOR_INSTR: &str = "xor";
const NEVER_INSTR: &str = "never";
const NEW_INSTR: &str = "new"; const NEW_INSTR: &str = "new";
const NEXT_INSTR: &str = "next"; const NEXT_INSTR: &str = "next";
const NULL_INSTR: &str = "null"; const NULL_INSTR: &str = "null";

View File

@ -74,6 +74,7 @@ pub enum Token<'input> {
Fail, Fail,
Fold, Fold,
Xor, Xor,
Never,
New, New,
Next, Next,
Null, Null,

View File

@ -65,6 +65,10 @@ pub(super) fn new<'i>(
}) })
} }
pub(super) fn never() -> Instruction<'static> {
Instruction::Never(Never)
}
pub(super) fn null() -> Instruction<'static> { pub(super) fn null() -> Instruction<'static> {
Instruction::Null(Null) Instruction::Null(Null)
} }

View File

@ -21,6 +21,7 @@ mod dsl;
mod fail; mod fail;
mod fold; mod fold;
mod match_; mod match_;
mod never;
mod new; mod new;
mod null; mod null;
mod par; mod par;

View File

@ -0,0 +1,32 @@
/*
* Copyright 2022 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::dsl::*;
use super::parse;
#[test]
fn parse_null() {
let source_code = r#"
(seq
(never)
( never )
)
"#;
let instruction = parse(source_code);
let expected = seq(never(), never());
assert_eq!(instruction, expected)
}

View File

@ -138,6 +138,7 @@ impl<W: io::Write> Beautifier<W> {
ast::Instruction::FoldStream(fold_stream) => { ast::Instruction::FoldStream(fold_stream) => {
self.beautify_fold_stream(fold_stream, indent) self.beautify_fold_stream(fold_stream, indent)
} }
ast::Instruction::Never(never) => self.beautify_simple(never, indent),
ast::Instruction::New(new) => self.beautify_new(new, indent), ast::Instruction::New(new) => self.beautify_new(new, indent),
ast::Instruction::Next(next) => self.beautify_simple(next, indent), ast::Instruction::Next(next) => self.beautify_simple(next, indent),
ast::Instruction::Null(null) => self.beautify_simple(null, indent), ast::Instruction::Null(null) => self.beautify_simple(null, indent),