From 9c786181f65cdca63bc0a1c34f593a34c53a7e70 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Wed, 1 Nov 2023 22:15:50 +0300 Subject: [PATCH 1/2] MIR: tzt runner: compare against typed output stack Comparing against untyped output stack is simply impossible in general, a lot of stacks we may be interested in don't have a unique untyped representation, or don't have an untyped representation at all. Case in point: big_map, address, contract, operation &c --- contrib/mir/src/tzt.rs | 12 +++--------- contrib/mir/src/tzt/expectation.rs | 14 ++++---------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/contrib/mir/src/tzt.rs b/contrib/mir/src/tzt.rs index 698c18f2ae3c..34404158b5cb 100644 --- a/contrib/mir/src/tzt.rs +++ b/contrib/mir/src/tzt.rs @@ -23,10 +23,7 @@ pub type TestStack = Vec<(Type, TypedValue)>; #[derive(PartialEq, Eq, Clone, Debug)] pub enum TztTestError { - StackMismatch( - (FailingTypeStack, Stack), - (FailingTypeStack, Stack), - ), + StackMismatch((FailingTypeStack, IStack), (FailingTypeStack, IStack)), UnexpectedError(TestError), UnexpectedSuccess(ErrorExpectation, IStack), ExpectedDifferentError(ErrorExpectation, TestError), @@ -118,10 +115,7 @@ impl TryFrom> for TztTest { "output", &mut m_output, match tzt_output { - TztSuccess(stk) => { - typecheck_stack(stk.clone())?; - ExpectSuccess(stk) - } + TztSuccess(stk) => ExpectSuccess(typecheck_stack(stk)?), TztError(error_exp) => ExpectError(error_exp), }, )?, @@ -161,7 +155,7 @@ pub enum TestError { /// the code in a test. #[derive(Debug, PartialEq, Eq, Clone)] pub enum TestExpectation { - ExpectSuccess(Vec<(Type, Value)>), + ExpectSuccess(Vec<(Type, TypedValue)>), ExpectError(ErrorExpectation), } diff --git a/contrib/mir/src/tzt/expectation.rs b/contrib/mir/src/tzt/expectation.rs index 7cb9b494e715..f76928a5e963 100644 --- a/contrib/mir/src/tzt/expectation.rs +++ b/contrib/mir/src/tzt/expectation.rs @@ -70,18 +70,12 @@ pub fn check_expectation( use TestExpectation::*; use TztTestError::*; match (expected, real) { - (ExpectSuccess(stk_exp), Ok((res_type_stack, i_stack))) => { - let (exp_stk_types, exp_stk_values): (Vec, Vec) = + (ExpectSuccess(stk_exp), Ok((res_type_stack, result_stack))) => { + let (exp_stk_types, exp_stk_values): (Vec, Vec) = stk_exp.into_iter().unzip(); - let expected_type_stack = FailingTypeStack::Ok(TopIsFirst::from_iter(exp_stk_types).0); - let expected_stack = TopIsFirst::from_iter(exp_stk_values).0; - let result_stack: Stack = TopIsFirst::from_iter( - i_stack - .iter() - .map(|x| typed_value_to_value_optimized(x.clone())), - ) - .0; + let expected_type_stack = FailingTypeStack::Ok(TopIsFirst::from(exp_stk_types).0); + let expected_stack = TopIsFirst::from(exp_stk_values).0; // If the run was success, and the expectation is also of success check the expected // stack. Stack types and values should match. if res_type_stack == expected_type_stack && result_stack == expected_stack { -- GitLab From 0e1e4c436e1471719d5e53ea785dcfb69f43b76b Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Wed, 1 Nov 2023 21:37:21 +0300 Subject: [PATCH 2/2] MIR: tzt runner: add self and parameter options --- contrib/mir/src/ast.rs | 2 +- contrib/mir/src/lexer.rs | 22 +++++++++++++++++++--- contrib/mir/src/syntax.lalrpop | 3 +++ contrib/mir/src/tzt.rs | 34 ++++++++++++++++++++++++++++++---- contrib/mir/tzt_runner/main.rs | 17 +++++++++++++++++ 5 files changed, 70 insertions(+), 8 deletions(-) diff --git a/contrib/mir/src/ast.rs b/contrib/mir/src/ast.rs index 78474427a4f5..633d6b65d90c 100644 --- a/contrib/mir/src/ast.rs +++ b/contrib/mir/src/ast.rs @@ -204,7 +204,7 @@ pub fn typed_value_to_value_optimized(tv: TypedValue) -> Value { // Note that there are more than one way to do this conversion. Here we use the optimized untyped // representation as the target, since that is what the typed to untyped conversion during a -// FAILWITH call does in the reference implementation, and this logic is primarly used in the +// FAILWITH call does in the reference implementation, and this logic is primarily used in the // corresponding section of MIR now. // // TODO: This implementation will be moved to interpreter in the context of issue, diff --git a/contrib/mir/src/lexer.rs b/contrib/mir/src/lexer.rs index 2dedc04138ce..6ad7ddfc9eed 100644 --- a/contrib/mir/src/lexer.rs +++ b/contrib/mir/src/lexer.rs @@ -7,11 +7,21 @@ use logos::Logos; +/// Expand to the first argument if not empty; otherwise, the second argument. +macro_rules! coalesce { + (, $r:expr) => { + $r + }; + ($l:expr, $r:expr) => { + $l + }; +} + /// Takes a list of primitive names, creates a simple `enum` with the names /// provided, and defines `FromStr` implementation using stringified /// representation of the identifiers. macro_rules! defprim { - ($ty:ident; $($prim:ident),* $(,)*) => { + ($ty:ident; $($(#[token($str:expr)])? $prim:ident),* $(,)*) => { #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[allow(non_camel_case_types, clippy::upper_case_acronyms)] pub enum $ty { @@ -20,7 +30,11 @@ macro_rules! defprim { impl std::fmt::Display for $ty { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", &self) + match self { + $( + $ty::$prim => write!(f, "{}", coalesce!($($str)?, stringify!($prim))), + )* + } } } @@ -28,7 +42,7 @@ macro_rules! defprim { type Err = PrimError; fn from_str(s: &str) -> Result { match s { - $(stringify!($prim) => Ok($ty::$prim),)* + $(coalesce!($($str)?, stringify!($prim)) => Ok($ty::$prim),)* _ => Err(PrimError(s.to_owned())) } } @@ -111,6 +125,8 @@ defprim! { MutezOverflow, GeneralOverflow, StaticError, + #[token("self")] + self_, } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/contrib/mir/src/syntax.lalrpop b/contrib/mir/src/syntax.lalrpop index 730f68571bc3..dcaadbb00d23 100644 --- a/contrib/mir/src/syntax.lalrpop +++ b/contrib/mir/src/syntax.lalrpop @@ -32,6 +32,7 @@ extern { "generalOverflow" => Tok::Prim(TztPrim(TzP::GeneralOverflow)), "StaticError" => Tok::Prim(TztPrim(TzP::StaticError)), "amount" => Tok::Prim(TztPrim(TzP::amount)), + "self" => Tok::Prim(TztPrim(TzP::self_)), number => Tok::Number(), string => Tok::String(), bytes => Tok::Bytes(>), @@ -300,6 +301,8 @@ tztEntity : TztEntity = { "output" "(" "StaticError" "_" ")" => Output(TztError(TypecheckerError(None))), "amount" => TztEntity::Amount(m), "chain_id" => TztEntity::ChainId(<>), + "parameter" => TztEntity::Parameter(<>), + "self" => TztEntity::SelfAddr(<>), } pub tztTestEntities : Vec = semicolonSepSeq; diff --git a/contrib/mir/src/tzt.rs b/contrib/mir/src/tzt.rs index 34404158b5cb..1ae8c6d6eff2 100644 --- a/contrib/mir/src/tzt.rs +++ b/contrib/mir/src/tzt.rs @@ -9,6 +9,7 @@ mod expectation; use std::fmt; +use crate::ast::michelson_address::AddressHash; use crate::ast::*; use crate::context::*; use crate::interpreter::*; @@ -65,6 +66,8 @@ pub struct TztTest { pub output: TestExpectation, pub amount: Option, pub chain_id: Option, + pub parameter: Option, + pub self_addr: Option, } fn typecheck_stack(stk: Vec<(Type, Value)>) -> Result, TcError> { @@ -106,6 +109,8 @@ impl TryFrom> for TztTest { let mut m_output: Option = None; let mut m_amount: Option = None; let mut m_chain_id: Option = None; + let mut m_parameter: Option = None; + let mut m_self: Option = None; for e in tzt { match e { @@ -121,6 +126,8 @@ impl TryFrom> for TztTest { )?, Amount(m) => set_tzt_field("amount", &mut m_amount, m)?, ChainId(id) => set_tzt_field("chain_id", &mut m_chain_id, id)?, + Parameter(ty) => set_tzt_field("parameter", &mut m_parameter, ty)?, + SelfAddr(v) => set_tzt_field("self", &mut m_self, v)?, } } @@ -137,6 +144,18 @@ impl TryFrom> for TztTest { )) }) .transpose()?, + parameter: m_parameter, + self_addr: m_self + .map(|v| { + Ok::<_, TcError>( + irrefutable_match!( + v.typecheck(&mut Ctx::default(), &Type::Address)?; + TypedValue::Address + ) + .hash, + ) + }) + .transpose()?, }) } } @@ -202,6 +221,8 @@ pub enum TztEntity { Output(TztOutput), Amount(i64), ChainId(Value), + Parameter(Type), + SelfAddr(Value), } /// Possible values for the "output" expectation field in a Tzt test @@ -213,7 +234,7 @@ pub enum TztOutput { fn execute_tzt_test_code( code: ParsedInstruction, ctx: &mut Ctx, - parameter: Option<&Type>, + parameter: &Type, input: Vec<(Type, TypedValue)>, ) -> Result<(FailingTypeStack, IStack), TestError> { // Build initial stacks (type and value) for running the test from the test input @@ -228,7 +249,7 @@ fn execute_tzt_test_code( // This value along with the test expectation // from the test file will be used to decide if // the test was a success or a fail. - let typechecked_code = code.typecheck(ctx, parameter, &mut t_stack)?; + let typechecked_code = code.typecheck(ctx, Some(parameter), &mut t_stack)?; let mut i_stack: IStack = TopIsFirst::from(vals).0; typechecked_code.interpret(ctx, &mut i_stack)?; Ok((t_stack, i_stack)) @@ -242,8 +263,13 @@ pub fn run_tzt_test(test: TztTest) -> Result<(), TztTestError> { gas: crate::gas::Gas::default(), amount: test.amount.unwrap_or_default(), chain_id: test.chain_id.unwrap_or(Ctx::default().chain_id), - self_address: Ctx::default().self_address, + self_address: test.self_addr.unwrap_or(Ctx::default().self_address), }; - let execution_result = execute_tzt_test_code(test.code, &mut ctx, None, test.input); + let execution_result = execute_tzt_test_code( + test.code, + &mut ctx, + &test.parameter.unwrap_or(Type::Unit), + test.input, + ); check_expectation(&mut ctx, test.output, execution_result) } diff --git a/contrib/mir/tzt_runner/main.rs b/contrib/mir/tzt_runner/main.rs index 8d795c2eda0a..acb215e8c988 100644 --- a/contrib/mir/tzt_runner/main.rs +++ b/contrib/mir/tzt_runner/main.rs @@ -164,6 +164,23 @@ mod tztrunner_tests { ); } + #[test] + fn test_runner_self_parameter() { + assert_eq!( + run_tzt_test( + parse_tzt_test( + r#"code { SELF }; + input {}; + parameter int; + self "KT1Wr7sqVqpbuELSD5xpTBPSCjyNRFj9Xpba"; + output { Stack_elt (contract int) "KT1Wr7sqVqpbuELSD5xpTBPSCjyNRFj9Xpba" }"#, + ) + .unwrap() + ), + Ok(()) + ); + } + const TZT_SAMPLE_ADD: &str = "code { ADD } ; input { Stack_elt int 5 ; Stack_elt int 5 } ; output { Stack_elt int 10 }"; -- GitLab