From b69a4301284bcce3c45674df171559ff80dc3dea Mon Sep 17 00:00:00 2001 From: liangping <18786721@qq.com> Date: Wed, 13 May 2020 12:08:21 +0800 Subject: [PATCH] Release 0.0.8 add type arguments for run.rs. `$ move run abc.mvir -t u64 -t address` --- Cargo.toml | 2 +- src/commands/mod.rs | 22 ++- src/commands/run.rs | 15 ++- src/commands/test.rs | 36 +++-- src/commands/type_parser.rs | 258 ++++++++++++++++++++++++++++++++++++ src/config.rs | 13 +- src/main.rs | 3 + 7 files changed, 306 insertions(+), 43 deletions(-) create mode 100644 src/commands/type_parser.rs diff --git a/Cargo.toml b/Cargo.toml index 699c95d..75745ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "move-runner" -version = "0.0.7" +version = "0.0.8" authors = ["Ping <18786721@qq.com>"] edition = "2018" description = "A Move VM simulator which allows developers to compile and run Move script/module on local computer. " diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 075b830..925f6f8 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -13,6 +13,7 @@ pub mod compile; pub mod new; pub mod run; pub mod test; +pub mod type_parser; pub trait Command { fn execute(&self, params: Parameter); @@ -38,13 +39,14 @@ pub fn test_command() -> Box { Box::new(test::TestCommand {}) } - fn load_genesis(cfg: &Config, runner: &mut MoveRunner) { println_color("Loading"); print!("'genesis.blob' from {:?}\n", &cfg.home); let mut exec_cfg = ExecutionConfig::default(); exec_cfg.genesis_file_location = PathBuf::from("genesis.blob"); - exec_cfg.load(&RootPath::new(&cfg.home)).expect("'genesis.blob' is invalid:"); + exec_cfg + .load(&RootPath::new(&cfg.home)) + .expect("'genesis.blob' is invalid:"); let tx = exec_cfg.genesis.unwrap(); let gen_payload = tx.as_signed_user_txn().unwrap().payload(); @@ -52,16 +54,10 @@ fn load_genesis(cfg: &Config, runner: &mut MoveRunner) { TransactionPayload::WriteSet(cs) => { runner.datastore.add_write_set(cs.write_set()); //print_all(cs); - }, - TransactionPayload::Module(m) => { - println!("module:{:?}", m) - }, - TransactionPayload::Script(s) => { - println!("script:{:?}", s) - }, - TransactionPayload::Program => { - println!("unimplemented") - }, + } + TransactionPayload::Module(m) => println!("module:{:?}", m), + TransactionPayload::Script(s) => println!("script:{:?}", s), + TransactionPayload::Program => println!("unimplemented"), } } @@ -75,4 +71,4 @@ fn convert_txn_args(args: &[TransactionArgument]) -> Vec { TransactionArgument::U8Vector(v) => Value::vector_u8(v.clone()), }) .collect() -} \ No newline at end of file +} diff --git a/src/commands/run.rs b/src/commands/run.rs index 5119ca5..eb209b1 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -1,6 +1,7 @@ use bytecode_verifier::verifier::VerifiedModule; use libra_types::transaction::{parse_as_transaction_argument, TransactionArgument}; use move_core_types::gas_schedule::{GasAlgebra, GasUnits}; +use move_core_types::language_storage::TypeTag; use move_vm_runtime::MoveVM; use move_vm_state::execution_context::{ExecutionContext, TransactionExecutionContext}; use move_vm_types::gas_schedule::zero_cost_schedule; @@ -11,6 +12,7 @@ use glob::glob; use crate::{commands::Command, config::Config, Parameter, println_color, runner::MoveRunner}; use crate::commands::{convert_txn_args, load_genesis}; +use crate::commands::type_parser::parse_type_tags; pub struct RunCommand {} @@ -19,9 +21,12 @@ impl Command for RunCommand { if let Parameter::Run { home, mut source_path, + type_args, args, } = params { + let ty_args: Vec = parse_type_tags(&type_args.join(",")).unwrap(); + // check if arguments are valid. let ta_args: Vec = args .iter() @@ -60,11 +65,11 @@ impl Command for RunCommand { load_genesis(&cfg, &mut m_runner); - println_color("Running"); print!( - "Script: {:?} Args: {:?}\n", + "Script: {:?} Type Args:{:?}, Args: {:?}\n", &source_path.file_name().unwrap(), + &ty_args, args ); @@ -77,15 +82,14 @@ impl Command for RunCommand { // Execute script. // create a Move VM and populate it with generated modules let move_vm = MoveVM::new(); - let mut ctx = - TransactionExecutionContext::new(GasUnits::new(600), &m_runner.datastore); + let mut ctx = TransactionExecutionContext::new(GasUnits::new(600), &m_runner.datastore); let gas_schedule = zero_cost_schedule(); let mut txn_data = TransactionMetadata::default(); txn_data.sender = cfg.address(); let result: VMResult<()> = - move_vm.execute_script(script, &gas_schedule, &mut ctx, &txn_data, vec![], va_args); + move_vm.execute_script(script, &gas_schedule, &mut ctx, &txn_data, ty_args, va_args); match result { Ok(_) => { @@ -103,4 +107,3 @@ impl Command for RunCommand { } } } - diff --git a/src/commands/test.rs b/src/commands/test.rs index 6e5ca3d..03b1065 100644 --- a/src/commands/test.rs +++ b/src/commands/test.rs @@ -1,17 +1,13 @@ use std::io::Write; use bytecode_verifier::verifier::VerifiedModule; -use move_core_types::{ - gas_schedule::{GasAlgebra, GasUnits}, -}; +use move_core_types::gas_schedule::{GasAlgebra, GasUnits}; use move_vm_runtime::MoveVM; use move_vm_state::execution_context::TransactionExecutionContext; use move_vm_types::gas_schedule::zero_cost_schedule; use move_vm_types::transaction_metadata::TransactionMetadata; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; -use vm::{ - errors::VMResult, -}; +use vm::errors::VMResult; use glob::glob; @@ -22,10 +18,7 @@ pub struct TestCommand {} impl Command for TestCommand { fn execute(&self, params: Parameter) { - if let Parameter::Test { - home, - } = params - { + if let Parameter::Test { home } = params { // initialize let cfg = Config::load_config(home); let mut m_runner = MoveRunner::new(cfg.clone()); @@ -64,10 +57,7 @@ impl Command for TestCommand { let compiled_script = m_runner.complie_script(&path).into_inner(); println_color("Running"); - print!( - "Script: {:?} Args: []", - &path.file_name().unwrap() - ); + print!("Script: {:?} Args: []", &path.file_name().unwrap()); let mut script: Vec = vec![]; compiled_script @@ -78,21 +68,29 @@ impl Command for TestCommand { // Execute script. // create a Move VM and populate it with generated modules let move_vm = MoveVM::new(); - let mut ctx = - TransactionExecutionContext::new(GasUnits::new(600), &m_runner.datastore); + let mut ctx = TransactionExecutionContext::new( + GasUnits::new(600), + &m_runner.datastore, + ); let gas_schedule = zero_cost_schedule(); let mut txn_data = TransactionMetadata::default(); txn_data.sender = cfg.address(); - let result: VMResult<()> = - move_vm.execute_script(script, &gas_schedule, &mut ctx, &txn_data, vec![], vec![]); + let result: VMResult<()> = move_vm.execute_script( + script, + &gas_schedule, + &mut ctx, + &txn_data, + vec![], + vec![], + ); match result { Ok(_) => status_print("OK\n", Color::Green), Err(_e) => status_print("Failed\n", Color::Red), } - }, + } Err(_) => { panic!("Failed to load source file of test cases."); } diff --git a/src/commands/type_parser.rs b/src/commands/type_parser.rs new file mode 100644 index 0000000..909508c --- /dev/null +++ b/src/commands/type_parser.rs @@ -0,0 +1,258 @@ +// Copyright (c) The Libra Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +// replace with the official when it becomes public. + +use std::iter::Peekable; + +use functional_tests::errors::*; +use libra_types::account_address::AccountAddress; +use move_core_types::{ + identifier::Identifier, + language_storage::{StructTag, TypeTag}, +}; + +#[derive(Eq, PartialEq, Debug)] +enum Token { + U8, + U64, + U128, + Bool, + AddressType, + Vector, + Whitespace(String), + Name(String), + Address(String), + ColonColon, + Lt, + Gt, + Comma, + EOF, + LBraceBrace, + RBraceBrace, +} + +impl Token { + fn is_whitespace(&self) -> bool { + match self { + Self::Whitespace(_) => true, + _ => false, + } + } +} + +fn name_token(s: String) -> Token { + match s.as_str() { + "u8" => Token::U8, + "u64" => Token::U64, + "u128" => Token::U128, + "bool" => Token::Bool, + "address" => Token::AddressType, + "vector" => Token::Vector, + _ => Token::Name(s), + } +} + +#[allow(clippy::many_single_char_names)] +fn next_token(s: &str) -> Result> { + let mut it = s.chars(); + match it.next() { + None => Ok(None), + Some(c) => Ok(Some(match c { + '<' => (Token::Lt, 1), + '>' => (Token::Gt, 1), + ',' => (Token::Comma, 1), + ':' => match it.next() { + Some(':') => (Token::ColonColon, 2), + _ => bail!("unrecognized token"), + }, + '{' => match it.next() { + Some('{') => (Token::LBraceBrace, 2), + _ => bail!("unrecognized token"), + }, + '}' => match it.next() { + Some('}') => (Token::RBraceBrace, 2), + _ => bail!("unrecognized token"), + }, + '0' => match it.next() { + Some(x @ 'x') | Some(x @ 'X') => match it.next() { + Some(c) if c.is_ascii_hexdigit() => { + let mut n: usize = 3; + let mut r = String::new(); + r.push('0'); + r.push(x); + r.push(c); + for c in it { + if c.is_ascii_hexdigit() { + r.push(c); + n += 1; + } else { + break; + } + } + (Token::Address(r), n) + } + _ => bail!("unrecognized token"), + }, + _ => bail!("unrecognized token"), + }, + c if c.is_ascii_whitespace() => { + let mut n = 1; + let mut r = String::new(); + r.push(c); + for c in it { + if c.is_ascii_whitespace() { + r.push(c); + n += 1; + } else { + break; + } + } + (Token::Whitespace(r), n) + } + c if c.is_ascii_alphabetic() => { + let mut n = 1; + let mut r = String::new(); + r.push(c); + for c in it { + if c.is_ascii_alphanumeric() { + r.push(c); + n += 1; + } else { + break; + } + } + (name_token(r), n) + } + _ => bail!("unrecognized token"), + })), + } +} + +fn tokenize(mut s: &str) -> Result> { + let mut v = vec![]; + while let Some((tok, n)) = next_token(s)? { + v.push(tok); + s = &s[n..]; + } + Ok(v) +} + +struct Parser> { + it: Peekable, +} + +impl> Parser { + fn new>(v: T) -> Self { + Self { + it: v.into_iter().peekable(), + } + } + + fn next(&mut self) -> Result { + match self.it.next() { + Some(tok) => Ok(tok), + None => bail!("out of tokens, this should not happen"), + } + } + + fn peek(&mut self) -> Option<&Token> { + self.it.peek() + } + + fn consume(&mut self, tok: Token) -> Result<()> { + let t = self.next()?; + if t != tok { + bail!("expected token {:?}, got {:?}", tok, t) + } + Ok(()) + } + + fn parse_comma_list( + &mut self, + parse_list_item: F, + end_token: Token, + allow_trailing_comma: bool, + ) -> Result> + where + F: Fn(&mut Self) -> Result, + R: std::fmt::Debug, + { + let mut v = vec![]; + if !(self.peek() == Some(&end_token)) { + loop { + v.push(parse_list_item(self)?); + if self.peek() == Some(&end_token) { + break; + } + self.consume(Token::Comma)?; + if self.peek() == Some(&end_token) && allow_trailing_comma { + break; + } + } + } + Ok(v) + } + + fn parse_type_tag(&mut self) -> Result { + Ok(match self.next()? { + Token::U8 => TypeTag::U8, + Token::U64 => TypeTag::U64, + Token::U128 => TypeTag::U128, + Token::Bool => TypeTag::Bool, + Token::AddressType => TypeTag::Address, + Token::Vector => { + self.consume(Token::Lt)?; + let ty = self.parse_type_tag()?; + self.consume(Token::Gt)?; + TypeTag::Vector(Box::new(ty)) + } + Token::Address(addr) => { + self.consume(Token::ColonColon)?; + match self.next()? { + Token::Name(module) => { + self.consume(Token::ColonColon)?; + match self.next()? { + Token::Name(name) => { + let ty_args = if self.peek() == Some(&Token::Lt) { + self.next()?; + let ty_args = self.parse_comma_list( + |parser| parser.parse_type_tag(), + Token::Gt, + true, + )?; + self.consume(Token::Gt)?; + ty_args + } else { + vec![] + }; + TypeTag::Struct(StructTag { + address: AccountAddress::from_hex_literal(&addr)?, + module: Identifier::new(module)?, + name: Identifier::new(name)?, + type_params: ty_args, + }) + } + t => bail!("expected name, got {:?}", t), + } + } + t => bail!("expected name, got {:?}", t), + } + } + tok => bail!("unexpected token {:?}, expected type tag", tok), + }) + } +} + +pub fn parse_type_tags(s: &str) -> Result> { + let mut tokens: Vec<_> = tokenize(s)? + .into_iter() + .filter(|tok| !tok.is_whitespace()) + .collect(); + tokens.push(Token::EOF); + let mut parser = Parser::new(tokens); + let tags = parser.parse_comma_list(|parser| parser.parse_type_tag(), Token::EOF, true); + let tags = tags?; + parser.consume(Token::EOF)?; + Ok(tags) +} diff --git a/src/config.rs b/src/config.rs index 7dd93eb..a6db6a3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,7 +6,9 @@ use libra_crypto::{ traits::*, }; use libra_crypto::hash::CryptoHash; -use libra_types::{account_address::AccountAddress, account_address::from_public_key, transaction::Transaction}; +use libra_types::{ + account_address::AccountAddress, account_address::from_public_key, transaction::Transaction, +}; use libra_types::transaction::{RawTransaction, SignedTransaction}; use serde::{Deserialize, Serialize}; use stdlib::StdLibOptions; @@ -61,10 +63,13 @@ impl Config { let change_set = vm_genesis::generate_genesis_change_set_for_testing(StdLibOptions::Staged); let mut cfg = ExecutionConfig::default(); - let priv_key = &Ed25519PrivateKey::from_encoded_string(&self.tx.keypair_private_key).unwrap(); - let raw_txs = RawTransaction::new_change_set(self.address(), self.tx.sequence_number, change_set); + let priv_key = + &Ed25519PrivateKey::from_encoded_string(&self.tx.keypair_private_key).unwrap(); + let raw_txs = + RawTransaction::new_change_set(self.address(), self.tx.sequence_number, change_set); let signature = priv_key.sign_message(&raw_txs.hash()); - let signed_tx = SignedTransaction::new(raw_txs, self.tx.keypair_public_key.clone(), signature); + let signed_tx = + SignedTransaction::new(raw_txs, self.tx.keypair_public_key.clone(), signature); cfg.genesis = Some(Transaction::UserTransaction(signed_tx)); cfg.save(&RootPath::new(&self.home)) diff --git a/src/main.rs b/src/main.rs index 7106305..b98b762 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,9 @@ pub enum Parameter { /// Compile source file. #[structopt(parse(from_os_str))] source_path: PathBuf, + /// Type_arguments to run script, ie: U64, Address + #[structopt(short, long)] + type_args: Vec, /// Args assigned to move script. #[structopt(name = "args")] args: Vec,