diff --git a/Cargo.lock b/Cargo.lock
index 32ab2279..a2d3b514 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+version = 3
+
[[package]]
name = "abigen"
version = "0.1.0"
@@ -831,6 +833,7 @@ dependencies = [
"log",
"maplit",
"move-executor",
+ "move-resource-viewer",
"once_cell",
"rand",
"regex",
@@ -1625,7 +1628,7 @@ dependencies = [
"log",
"lsp-types",
"move-compat",
- "move-core-types 0.1.0 (git+https://github.com/dfinance/libra.git)",
+ "move-core-types 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
"rand",
"regex",
"rust-base58",
@@ -1666,7 +1669,7 @@ name = "libra-canonical-serialization"
version = "0.1.0"
source = "git+https://github.com/dfinance/libra.git?branch=master#c46b32d73087ed2afc6c1ac3e78535cac37e3fa9"
dependencies = [
- "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git)",
+ "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
"serde",
"thiserror",
]
@@ -1719,10 +1722,10 @@ dependencies = [
"ed25519-dalek 1.0.0-pre.4",
"hex",
"hkdf",
- "libra-canonical-serialization 0.1.0 (git+https://github.com/dfinance/libra.git)",
- "libra-crypto-derive 0.1.0 (git+https://github.com/dfinance/libra.git)",
- "libra-nibble 0.1.0 (git+https://github.com/dfinance/libra.git)",
- "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git)",
+ "libra-canonical-serialization 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
+ "libra-crypto-derive 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
+ "libra-nibble 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
+ "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
"mirai-annotations",
"once_cell",
"rand",
@@ -1774,7 +1777,7 @@ name = "libra-crypto-derive"
version = "0.1.0"
source = "git+https://github.com/dfinance/libra.git?branch=master#c46b32d73087ed2afc6c1ac3e78535cac37e3fa9"
dependencies = [
- "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git)",
+ "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
"proc-macro2",
"quote",
"syn",
@@ -1911,7 +1914,7 @@ name = "libra-nibble"
version = "0.1.0"
source = "git+https://github.com/dfinance/libra.git?branch=master#c46b32d73087ed2afc6c1ac3e78535cac37e3fa9"
dependencies = [
- "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git)",
+ "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
"serde",
]
@@ -2349,10 +2352,10 @@ source = "git+https://github.com/dfinance/libra.git?branch=master#c46b32d73087ed
dependencies = [
"anyhow",
"hex",
- "libra-canonical-serialization 0.1.0 (git+https://github.com/dfinance/libra.git)",
- "libra-crypto 0.1.0 (git+https://github.com/dfinance/libra.git)",
- "libra-crypto-derive 0.1.0 (git+https://github.com/dfinance/libra.git)",
- "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git)",
+ "libra-canonical-serialization 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
+ "libra-crypto 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
+ "libra-crypto-derive 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
+ "libra-workspace-hack 0.1.0 (git+https://github.com/dfinance/libra.git?branch=master)",
"mirai-annotations",
"once_cell",
"rand",
diff --git a/README.md b/README.md
index d4b519a2..77810afc 100644
--- a/README.md
+++ b/README.md
@@ -53,9 +53,98 @@ Build project:
```shell script
dove build
```
-
See `./target/` folder to get scripts/modules binaries.
+
+Create transactions:
+
+Command `ct` allows you to create transactions for `polkadot` chain with move vm palette.
+
+`ct` takes script identifier, type parameters, and arguments and creates a transaction file as an artifact of work.
+
+Example:
+```shell script
+dove ct 'store_u64(60)'
+```
+This command searches for the script by name 'store_u64' in the script directory. Then it compiles it and creates a transaction file.
+
+This command will fail if:
+
+- There is no script with the name given name 'store_u64'.
+- There is more than one script with the name 'store_64'.
+- The passed parameters or type parameters do not match the script parameters.
+- There are syntax errors in the script.
+
+Type parameters:
+
+You can use type parameters like in the move language.
+Example:
+```shell script
+dove ct 'create_account<0x01::Dfinance::USD, 0x01::Dfinance::BTC>()'
+```
+You allow can use ss58 address format:
+```shell script
+dove ct 'create_account<1exaAg2VJRQbyUBAeXcktChCAqjVP9TUxF3zo23R2T6EGdE::Dfinance::USD>()'
+```
+
+Types:
+
+numbers (u8, u64, u128): 10, 1024.
+
+bool: true, false.
+
+address: 1exaAg2VJRQbyUBAeXcktChCAqjVP9TUxF3zo23R2T6EGdE, 0x1CF326C5AAA5AF9F0E2791E66310FE8F044FAADAF12567EAA0976959D1F7731F
+
+vector
: [1exaAg2VJRQbyUBAeXcktChCAqjVP9TUxF3zo23R2T6EGdE, 0x1CF326C5AAA5AF9F0E2791E66310FE8F044FAADAF12567EAA0976959D1F7731F, 0x01]
+
+vector: [10, 30, 1024]
+
+vector: [true, false]
+
+You can define or override script names by using '--name' or '-n' parameter.
+
+Example:
+Override script name:
+```shell script
+dove ct 'store_u64(60)' -n store_u126
+```
+Define script name:
+```shell script
+dove ct -n store_u126
+```
+
+File name:
+You can define the file name by using '--file' or '-f' parameter.
+With this option 'ct' searches in a specified file. It may be useful when there is more than one script with the same name in different files.
+Or the specified file has one script.
+```shell script
+dove ct 'store_u64(60)' -n store_u126 -f script.move
+```
+```shell script
+dove ct -n store_u126 -f script
+```
+
+Type parameters:
+
+You can define or override script type parameters by using '--type' or '-t' parameter.
+```shell script
+dove ct 'store_u64()' -t 0x01::Dfinance::USD u8
+```
+```shell script
+dove ct -n store_u64 -t 0x01::Dfinance::USD u8
+```
+
+
+arguments:
+
+You can define or override script arguments by using '--args' or '-a' parameter.
+```shell script
+dove ct 'store_u64()' -a [10, 1024] 10 0x01
+```
+```shell script
+dove ct -n store_u64 -a [10, 1024] 10 0x01
+```
+
## Resource Viewer
See [documentation](/resource-viewer/README.md).
diff --git a/dove/Cargo.toml b/dove/Cargo.toml
index 07d29e6c..bc1f86a8 100644
--- a/dove/Cargo.toml
+++ b/dove/Cargo.toml
@@ -31,6 +31,7 @@ reqwest = { version = "0.10.4", features = ["blocking", "json"] }
itertools = "0.9.0"
lang = { path = "../lang" }
move-executor = { path = "../executor" }
+move-resource-viewer = { path = "../resource-viewer", default-features = false }
git-hash = { path = "../common/git-hash" }
maplit = "1.0.2"
serde_json = "1.0.52"
@@ -44,14 +45,17 @@ libra_address = [
"libra/libra_address",
"lang/libra_address",
"move-executor/libra_address",
+ "move-resource-viewer/libra_address",
]
dfinance_address = [
"libra/dfinance_address",
"lang/dfinance_address",
"move-executor/dfinance_address",
+ "move-resource-viewer/dfinance_address",
]
ps_address = [
"libra/ps_address",
"lang/ps_address",
"move-executor/ps_address",
+ "move-resource-viewer/ps_address"
]
\ No newline at end of file
diff --git a/dove/src/bin/dove.rs b/dove/src/bin/dove.rs
index 0cbb5c03..2c825c64 100644
--- a/dove/src/bin/dove.rs
+++ b/dove/src/bin/dove.rs
@@ -14,6 +14,7 @@ use dove::cmd::fetch::Fetch;
use dove::cmd::build::Build;
use dove::cmd::test::Test;
use dove::cmd::run::Run;
+use dove::cmd::ct::CreateTransactionCmd;
#[derive(StructOpt, Debug)]
#[structopt(name = "Move compiler.", version = git_hash::crate_version_with_git_hash_short!())]
@@ -58,6 +59,11 @@ enum Opt {
#[structopt(flatten)]
cmd: Run,
},
+ #[structopt(about = "Create transaction")]
+ Ct {
+ #[structopt(flatten)]
+ cmd: CreateTransactionCmd,
+ },
}
fn main() {
@@ -73,6 +79,7 @@ fn main() {
Opt::Build { cmd } => cmd.execute(),
Opt::Test { cmd } => cmd.execute(),
Opt::Run { cmd } => cmd.execute(),
+ Opt::Ct { cmd } => cmd.execute(),
});
}
diff --git a/dove/src/cmd/build.rs b/dove/src/cmd/build.rs
index 7b69fd75..5a036283 100644
--- a/dove/src/cmd/build.rs
+++ b/dove/src/cmd/build.rs
@@ -2,11 +2,10 @@ use crate::cmd::{Cmd, load_dependencies};
use crate::context::Context;
use anyhow::Error;
use structopt::StructOpt;
-use crate::index::Index;
use lang::compiler::file::load_move_files;
use lang::builder::{Artifacts, MoveBuilder};
use termcolor::{StandardStream, ColorChoice};
-use std::path::PathBuf;
+use std::path::Path;
use std::fs::File;
use std::io::Write;
use std::fs;
@@ -24,17 +23,12 @@ pub struct Build {}
impl Cmd for Build {
fn apply(self, ctx: Context) -> Result<(), Error> {
- let dirs: Vec<_> = [
+ let dirs = ctx.paths_for(&[
&ctx.manifest.layout.script_dir,
&ctx.manifest.layout.module_dir,
- ]
- .iter()
- .map(|d| ctx.path_for(&d))
- .filter(|p| p.exists())
- .collect();
+ ]);
- let mut index = Index::load(&ctx)?;
- index.build()?;
+ let mut index = ctx.build_index()?;
let dep_set = index.make_dependency_set(&dirs)?;
let dep_list = load_dependencies(dep_set)?;
@@ -68,7 +62,7 @@ pub fn verify_and_store(
.into_iter()
.partition(|u| matches!(u, CompiledUnit::Module { .. }));
- fn store(units: Vec, base_dir: &PathBuf) -> Result<(), Error> {
+ fn store(units: Vec, base_dir: &Path) -> Result<(), Error> {
for (idx, unit) in units.into_iter().enumerate() {
let mut path = base_dir.join(format!("{}_{}", idx, unit.name()));
path.set_extension("mv");
diff --git a/dove/src/cmd/ct.rs b/dove/src/cmd/ct.rs
new file mode 100644
index 00000000..a4636971
--- /dev/null
+++ b/dove/src/cmd/ct.rs
@@ -0,0 +1,708 @@
+use crate::cmd::{Cmd, load_dependencies};
+use crate::context::Context;
+use anyhow::Error;
+use structopt::StructOpt;
+use lang::compiler::file::{MoveFile, find_move_files, load_move_files};
+use lang::meta_extractor::{ScriptMetadata, Meta};
+use lang::builder::{Artifacts, MoveBuilder};
+use termcolor::{StandardStream, ColorChoice};
+use libra::move_core_types::language_storage::TypeTag;
+use serde::{Serialize, Deserialize};
+use libra::account::AccountAddress;
+use libra::move_lang::parser::lexer::{Lexer, Tok};
+use libra::move_lang::parser::syntax::parse_type;
+use libra::{
+ prelude::CompiledUnit,
+ move_lang::{compiled_unit, errors::output_errors},
+};
+use move_resource_viewer::tte::unwrap_spanned_ty;
+use std::fmt::Debug;
+use std::str::FromStr;
+use lang::compiler::ss58::{ss58_to_libra, replace_ss58_addresses};
+use std::fs;
+
+/// Create transaction.
+#[derive(StructOpt, Debug)]
+pub struct CreateTransactionCmd {
+ #[structopt(help = "Script call declaration.\
+ Example: 'create_balance<0x01::Dfinance::USD>([10,10], true, 68656c6c6f776f726c64, 100)'")]
+ call: Option,
+ #[structopt(help = "Script name.", long = "name", short = "n")]
+ script_name: Option,
+ #[structopt(help = "Script file name.", long = "file", short = "f")]
+ file_name: Option,
+ #[structopt(
+ help = r#"Script type parametrs, e.g. 0x1::Dfinance::USD"#,
+ name = "Script type parameters.",
+ long = "type",
+ short = "t"
+ )]
+ type_parameters: Option>,
+ #[structopt(
+ help = r#"Script arguments, e.g. 10 20 30"#,
+ name = "Script arguments.",
+ long = "args",
+ short = "a"
+ )]
+ args: Option>,
+}
+
+impl Cmd for CreateTransactionCmd {
+ fn apply(self, ctx: Context) -> Result<(), Error> {
+ let builder = TransactionBuilder::new(self, &ctx)?;
+ let (script_name, transaction) = builder.build()?;
+ store_transaction(&ctx, &script_name, transaction)
+ }
+}
+
+struct TransactionBuilder<'a> {
+ script_file_name: Option,
+ script_name: Option,
+ type_parameters: Vec,
+ args: Vec,
+ dove_ctx: &'a Context,
+}
+
+impl<'a> TransactionBuilder<'a> {
+ pub fn new(cmd: CreateTransactionCmd, ctx: &'a Context) -> Result {
+ let (mut script_name, mut type_parameters, mut args) = if let Some(call) = cmd.call {
+ let (script_name, type_parameters, args) = Self::parse_call(&call)?;
+ (Some(script_name), type_parameters, args)
+ } else {
+ (None, vec![], vec![])
+ };
+
+ if let Some(cmd_script_name) = cmd.script_name {
+ script_name = Some(cmd_script_name);
+ }
+
+ if let Some(cmd_type_parameters) = cmd.type_parameters {
+ type_parameters = cmd_type_parameters
+ .iter()
+ .map(|tp| replace_ss58_addresses(tp, &mut Default::default()))
+ .map(|tp| parse_type_params(&mut Lexer::new(&tp, "tp", Default::default())))
+ .collect::>()?;
+ }
+
+ if let Some(cmd_args) = cmd.args {
+ args = cmd_args
+ .iter()
+ .map(|arg| replace_ss58_addresses(arg, &mut Default::default()))
+ .collect();
+ }
+
+ Ok(TransactionBuilder {
+ script_file_name: cmd.file_name,
+ script_name,
+ type_parameters,
+ args,
+ dove_ctx: ctx,
+ })
+ }
+
+ pub fn parse_call(call: &str) -> Result<(String, Vec, Vec), Error> {
+ let call = replace_ss58_addresses(call, &mut Default::default());
+
+ let map_err = |err| Error::msg(format!("{:?}", err));
+ let mut lexer = Lexer::new(&call, "call", Default::default());
+ lexer.advance().map_err(map_err)?;
+ if lexer.peek() != Tok::IdentifierValue {
+ return Err(anyhow!("Invalid call script format.\
+ Expected function identifier. Use pattern \
+ 'script_name(comma separated parameters WITHOUT signers)'"));
+ }
+
+ let script_name = lexer.content().to_owned();
+
+ lexer.advance().map_err(map_err)?;
+
+ let type_parameters = if lexer.peek() == Tok::Less {
+ let mut type_parameter = vec![];
+
+ lexer.advance().map_err(map_err)?;
+ while lexer.peek() != Tok::Greater {
+ if lexer.peek() == Tok::EOF {
+ return Err(anyhow!("Invalid call script format.\
+ Invalid type parameters format.. Use pattern \
+ 'script_name(comma separated parameters WITHOUT signers)'"));
+ }
+
+ if lexer.peek() == Tok::Comma {
+ lexer.advance().map_err(map_err)?;
+ continue;
+ }
+
+ type_parameter.push(parse_type_params(&mut lexer)?);
+ }
+ lexer.advance().map_err(map_err)?;
+ type_parameter
+ } else {
+ vec![]
+ };
+
+ if lexer.peek() != Tok::LParen {
+ return Err(anyhow!("Invalid call script format.\
+ Invalid script arguments format.. Left paren '(' is expected. Use pattern \
+ 'script_name(comma separated parameters WITHOUT signers)'"));
+ }
+
+ let mut arguments = vec![];
+
+ lexer.advance().map_err(map_err)?;
+ while lexer.peek() != Tok::RParen {
+ if lexer.peek() == Tok::EOF {
+ return Err(anyhow!("Invalid call script format.\
+ Invalid arguments format.. Use pattern \
+ 'script_name(comma separated parameters WITHOUT signers)'"));
+ }
+
+ if lexer.peek() == Tok::Comma {
+ lexer.advance().map_err(map_err)?;
+ continue;
+ }
+
+ if lexer.peek() == Tok::LBracket {
+ let mut token = String::new();
+ token.push_str(lexer.content());
+ lexer.advance().map_err(map_err)?;
+ while lexer.peek() != Tok::RBracket {
+ token.push_str(lexer.content());
+ lexer.advance().map_err(map_err)?;
+ }
+ token.push_str(lexer.content());
+ arguments.push(token);
+ } else {
+ let mut token = String::new();
+ token.push_str(lexer.content());
+ lexer.advance().map_err(map_err)?;
+ while lexer.peek() != Tok::Comma && lexer.peek() != Tok::RParen {
+ token.push_str(lexer.content());
+ lexer.advance().map_err(map_err)?;
+ }
+ arguments.push(token);
+ if lexer.peek() == Tok::RParen {
+ break;
+ }
+ }
+ lexer.advance().map_err(map_err)?;
+ }
+
+ Ok((script_name, type_parameters, arguments))
+ }
+
+ fn lookup_script_by_file_name(&self, fname: &str) -> Result<(MoveFile, Meta), Error> {
+ let script_path = self
+ .dove_ctx
+ .path_for(&self.dove_ctx.manifest.layout.script_dir);
+ let file_path = if !fname.ends_with("move") {
+ let mut path = script_path.join(fname);
+ path.set_extension("move");
+ path
+ } else {
+ script_path.join(fname)
+ };
+ if !file_path.exists() {
+ return Err(anyhow!("File [{}] not found", fname));
+ }
+
+ let script = MoveFile::load(&file_path)?;
+ let mut scripts = ScriptMetadata::extract(self.dove_ctx.dialect.as_ref(), &script)?;
+ if scripts.is_empty() {
+ return Err(anyhow!("Script not found in file '{}'", fname));
+ }
+
+ let meta = if scripts.len() > 1 {
+ let mut scripts = scripts
+ .into_iter()
+ .filter(|sc| {
+ if let Some(script_name) = &self.script_name {
+ &sc.name == script_name
+ } else {
+ false
+ }
+ })
+ .collect::>();
+ if scripts.len() > 1 {
+ return Err(anyhow!(
+ "There are several scripts with the name '{:?}' in file '{}'",
+ self.script_name,
+ fname
+ ));
+ } else {
+ scripts.remove(0)
+ }
+ } else {
+ scripts.remove(0)
+ };
+
+ Ok((script, meta))
+ }
+
+ fn lookup_script_by_name(&self, name: &str) -> Result<(MoveFile, Meta), Error> {
+ let script_path = self
+ .dove_ctx
+ .path_for(&self.dove_ctx.manifest.layout.script_dir);
+ let mut files = find_move_files(&script_path)?
+ .iter()
+ .map(MoveFile::load)
+ .filter_map(|mf| match mf {
+ Ok(mf) => {
+ if mf.content().contains(name) {
+ Some(mf)
+ } else {
+ None
+ }
+ }
+ Err(err) => {
+ warn!("{:?}", err);
+ None
+ }
+ })
+ .map(|mf| {
+ ScriptMetadata::extract(self.dove_ctx.dialect.as_ref(), &mf)
+ .map(|meta| (mf, meta))
+ })
+ .filter_map(|script| match script {
+ Ok((mf, meta)) => Some((mf, meta)),
+ Err(err) => {
+ warn!("{:?}", err);
+ None
+ }
+ })
+ .filter(|(_, meta)| meta.iter().any(|meta| *name == meta.name))
+ .collect::>();
+
+ if files.is_empty() {
+ return Err(anyhow!("Script not found."));
+ }
+
+ if files.len() > 1 {
+ let name_list = files
+ .iter()
+ .map(|(mf, _)| mf.name())
+ .collect::>()
+ .join(", ");
+ return Err(anyhow!(
+ "There are several scripts with the name '{:?}' in files ['{}'].",
+ name,
+ name_list
+ ));
+ }
+
+ let (file, mut meta) = files.remove(0);
+ if meta.is_empty() {
+ return Err(anyhow!("Script not found."));
+ }
+
+ if meta.len() > 1 {
+ return Err(anyhow!(
+ "There are several scripts with the name '{:?}' in file '{}'.",
+ name,
+ file.name()
+ ));
+ }
+ Ok((file, meta.remove(0)))
+ }
+
+ fn lookup_script(&self) -> Result<(MoveFile, Meta), Error> {
+ if let Some(file_name) = &self.script_file_name {
+ return self.lookup_script_by_file_name(file_name);
+ }
+
+ if let Some(name) = &self.script_name {
+ return self.lookup_script_by_name(name);
+ }
+
+ let script_path = self
+ .dove_ctx
+ .path_for(&self.dove_ctx.manifest.layout.script_dir);
+ let files = find_move_files(&script_path)?;
+ if files.len() == 1 {
+ let mf = MoveFile::load(&files[0])?;
+ let mut meta = ScriptMetadata::extract(self.dove_ctx.dialect.as_ref(), &mf)?;
+ if meta.is_empty() {
+ return Err(anyhow!("Script not found."));
+ }
+ if meta.len() > 1 {
+ return Err(anyhow!("Failed to determine script. There are several scripts. Use '--name' to determine the script."));
+ }
+ Ok((mf, meta.remove(0)))
+ } else {
+ Err(anyhow!("Failed to determine script. There are several scripts. Use '--name' or '--file' to determine the script."))
+ }
+ }
+
+ fn build_script(&self, script: MoveFile) -> Result, Error> {
+ let mut index = self.dove_ctx.build_index()?;
+
+ let module_dir = self
+ .dove_ctx
+ .path_for(&self.dove_ctx.manifest.layout.module_dir)
+ .to_str()
+ .map(|path| path.to_owned())
+ .ok_or_else(|| anyhow!("Failed to convert module dir path"))?;
+
+ let dep_set = index.make_dependency_set(&[module_dir.as_str(), script.name()])?;
+ let mut dep_list = load_dependencies(dep_set)?;
+ dep_list.extend(load_move_files(&[module_dir])?);
+
+ let sender = self.dove_ctx.account_address()?;
+ let Artifacts { files, prog } =
+ MoveBuilder::new(self.dove_ctx.dialect.as_ref(), Some(sender).as_ref())
+ .build(&[script], &dep_list);
+
+ match prog {
+ Err(errors) => {
+ let mut writer = StandardStream::stderr(ColorChoice::Auto);
+ output_errors(&mut writer, files, errors);
+ Err(anyhow!(
+ "could not compile:{}",
+ self.dove_ctx.project_name()
+ ))
+ }
+ Ok(compiled_units) => {
+ let (compiled_units, ice_errors) = compiled_unit::verify_units(compiled_units);
+
+ if !ice_errors.is_empty() {
+ let mut writer = StandardStream::stderr(ColorChoice::Auto);
+ output_errors(&mut writer, files, ice_errors);
+ Err(anyhow!("could not verify:{}", self.dove_ctx.project_name()))
+ } else {
+ Ok(compiled_units)
+ }
+ }
+ }
+ }
+
+ fn prepare_arguments(
+ &self,
+ args_type: &[(String, String)],
+ ) -> Result<(usize, usize, Vec), Error> {
+ let total_args = args_type.len();
+
+ fn parse_err(name: &str, tp: &str, index: usize, value: &str, err: D) -> Error {
+ anyhow!(
+ "Parameter '{}' has {} type. Failed to parse {} [{}]. Error:'{:?}'",
+ name,
+ tp,
+ value,
+ index,
+ err
+ )
+ }
+
+ args_type.iter().try_fold(
+ (0, 0, Vec::new()),
+ |(signers, args_index, mut values), (name, tp)| match tp.as_str() {
+ "&signer" => Ok((signers + 1, args_index, values)),
+ "bool" => {
+ let arg = self.argument(args_index, total_args)?;
+ values.push(ScriptArg::Bool(
+ arg.parse()
+ .map_err(|err| parse_err(name, tp, args_index, arg, err))?,
+ ));
+ Ok((signers, args_index + 1, values))
+ }
+ "u8" => {
+ let arg = self.argument(args_index, total_args)?;
+ values.push(ScriptArg::U8(
+ arg.parse()
+ .map_err(|err| parse_err(name, tp, args_index, arg, err))?,
+ ));
+ Ok((signers, args_index + 1, values))
+ }
+ "u64" => {
+ let arg = self.argument(args_index, total_args)?;
+ values.push(ScriptArg::U64(
+ arg.parse()
+ .map_err(|err| parse_err(name, tp, args_index, arg, err))?,
+ ));
+ Ok((signers, args_index + 1, values))
+ }
+ "u128" => {
+ let arg = self.argument(args_index, total_args)?;
+ values.push(ScriptArg::U128(
+ arg.parse()
+ .map_err(|err| parse_err(name, tp, args_index, arg, err))?,
+ ));
+ Ok((signers, args_index + 1, values))
+ }
+ "address" => {
+ let arg = self.argument(args_index, total_args)?;
+ values.push(ScriptArg::Address(Address::from_str(arg)?.addr));
+ Ok((signers, args_index + 1, values))
+ }
+ "vector" => {
+ let arg = self.argument(args_index, total_args)?;
+ let buffer = if arg.contains('[') {
+ parse_vec(arg, "u8")?
+ } else {
+ hex::decode(arg)?
+ };
+ values.push(ScriptArg::VectorU8(buffer));
+ Ok((signers, args_index + 1, values))
+ }
+ "vector" => {
+ let arg = self.argument(args_index, total_args)?;
+ values.push(ScriptArg::VectorU64(parse_vec(arg, "u64")?));
+ Ok((signers, args_index + 1, values))
+ }
+ "vector" => {
+ let arg = self.argument(args_index, total_args)?;
+ values.push(ScriptArg::VectorU128(parse_vec(arg, "u128")?));
+ Ok((signers, args_index + 1, values))
+ }
+ "vector" => {
+ let arg = self.argument(args_index, total_args)?;
+ let address = parse_vec::(arg, "vector")?
+ .iter()
+ .map(|addr| addr.addr)
+ .collect();
+ values.push(ScriptArg::VectorAddress(address));
+ Ok((signers, args_index + 1, values))
+ }
+ &_ => Err(anyhow!("Unexpected script parameter: {}", tp)),
+ },
+ )
+ }
+
+ fn argument(&self, index: usize, total_expected: usize) -> Result<&String, Error> {
+ self.args
+ .get(index)
+ .ok_or_else(|| anyhow!("{} arguments are expected.", total_expected))
+ }
+
+ pub fn build(self) -> Result<(String, Transaction), Error> {
+ let (script, meta) = self.lookup_script()?;
+ let units = self.build_script(script)?;
+
+ let unit = units
+ .into_iter()
+ .find(|unit| {
+ let is_module = match &unit {
+ CompiledUnit::Module { .. } => false,
+ CompiledUnit::Script { .. } => true,
+ };
+ is_module && unit.name() == meta.name
+ })
+ .map(|unit| unit.serialize())
+ .ok_or_else(|| anyhow!("Script '{}' not found", meta.name))?;
+
+ if meta.type_parameters.len() != self.type_parameters.len() {
+ return Err(anyhow!(
+ "Script '{}' takes {} type parameters, {} passed",
+ meta.name,
+ meta.type_parameters.len(),
+ self.type_parameters.len()
+ ));
+ }
+
+ let (signers, args_count, args) = self.prepare_arguments(&meta.parameters)?;
+
+ if self.args.len() != args_count {
+ return Err(anyhow!(
+ "Script '{}' takes {} parameters, {} passed",
+ meta.name,
+ args_count,
+ self.args.len()
+ ));
+ }
+
+ Ok((
+ meta.name,
+ Transaction::new(signers as u8, unit, args, self.type_parameters),
+ ))
+ }
+}
+
+/// Script argument type.
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, PartialOrd)]
+pub enum ScriptArg {
+ /// u8
+ U8(u8),
+ /// u64
+ U64(u64),
+ /// u128
+ U128(u128),
+ /// bool
+ Bool(bool),
+ /// address
+ Address(AccountAddress),
+ /// vector
+ VectorU8(Vec),
+ /// vector
+ VectorU64(Vec),
+ /// vector
+ VectorU128(Vec),
+ /// vector
+ VectorBool(Vec),
+ /// vector
+ VectorAddress(Vec),
+}
+
+/// Transaction model.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Transaction {
+ signers_count: u8,
+ code: Vec,
+ args: Vec,
+ type_args: Vec,
+}
+
+impl Transaction {
+ /// Create a new transaction.
+ pub fn new(
+ signers_count: u8,
+ code: Vec,
+ args: Vec,
+ type_args: Vec,
+ ) -> Transaction {
+ Transaction {
+ signers_count,
+ code,
+ args,
+ type_args,
+ }
+ }
+}
+
+fn parse_type_params(lexer: &mut Lexer) -> Result {
+ let ty = parse_type(lexer).map_err(|err| Error::msg(format!("{:?}", err)))?;
+ unwrap_spanned_ty(ty)
+}
+
+fn parse_vec(tkn: &str, tp_name: &str) -> Result, Error>
+where
+ E: FromStr,
+{
+ let map_err = |err| Error::msg(format!("{:?}", err));
+
+ let mut lexer = Lexer::new(tkn, "vec", Default::default());
+ lexer.advance().map_err(map_err)?;
+
+ if lexer.peek() != Tok::LBracket {
+ return Err(anyhow!("Vector in format [n1, n2, ..., nn] is expected."));
+ }
+ lexer.advance().map_err(map_err)?;
+
+ let mut elements = vec![];
+ while lexer.peek() != Tok::RBracket {
+ match lexer.peek() {
+ Tok::Comma => {
+ lexer.advance().map_err(map_err)?;
+ continue;
+ }
+ Tok::EOF => {
+ return Err(anyhow!("unexpected end of vector."));
+ }
+ _ => {
+ elements.push(E::from_str(lexer.content()).map_err(|_| {
+ anyhow!(
+ "Failed to parse vector element. {} type is expected. Actual:'{}'",
+ tp_name,
+ lexer.content()
+ )
+ })?);
+ lexer.advance().map_err(map_err)?;
+ }
+ }
+ }
+ Ok(elements)
+}
+
+fn store_transaction(ctx: &Context, name: &str, tx: Transaction) -> Result<(), Error> {
+ let tx_dir = ctx.path_for(&ctx.manifest.layout.transaction_output);
+ if !tx_dir.exists() {
+ fs::create_dir_all(&tx_dir)?;
+ }
+
+ let mut tx_file = tx_dir.join(name);
+ tx_file.set_extension("mvt");
+
+ if tx_file.exists() {
+ fs::remove_file(&tx_file)?;
+ }
+ println!("Store transaction:{:?}", tx_file);
+ Ok(fs::write(&tx_file, libra::lcs::to_bytes(&tx)?)?)
+}
+
+struct Address {
+ addr: AccountAddress,
+}
+
+impl FromStr for Address {
+ type Err = Error;
+
+ fn from_str(addr: &str) -> Result {
+ let addr = match ss58_to_libra(addr) {
+ Ok(addr) => AccountAddress::from_hex_literal(&addr)?,
+ Err(_) => AccountAddress::from_hex_literal(&addr)?,
+ };
+ Ok(Address { addr })
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use crate::cmd::ct::TransactionBuilder;
+ use libra::move_core_types::language_storage::{TypeTag, StructTag};
+ use libra::move_core_types::language_storage::CORE_CODE_ADDRESS;
+ use libra::move_core_types::identifier::Identifier;
+
+ #[test]
+ fn test_parse_call() {
+ let (name, tp, args) = TransactionBuilder::parse_call("create_account>(10, 68656c6c6f, [10, 23], true, 1exaAg2VJRQbyUBAeXcktChCAqjVP9TUxF3zo23R2T6EGdE)").unwrap();
+ assert_eq!(name, "create_account");
+ assert_eq!(
+ tp,
+ vec![
+ TypeTag::U8,
+ TypeTag::Struct(StructTag {
+ address: CORE_CODE_ADDRESS,
+ module: Identifier::new("Dfinance").unwrap(),
+ name: Identifier::new("USD").unwrap(),
+ type_params: vec![TypeTag::U8],
+ })
+ ]
+ );
+ assert_eq!(
+ args,
+ vec![
+ "10".to_owned(),
+ "68656c6c6f".to_owned(),
+ "[10,23]".to_owned(),
+ "true".to_owned(),
+ "0x1CF326C5AAA5AF9F0E2791E66310FE8F044FAADAF12567EAA0976959D1F7731F".to_owned()
+ ]
+ );
+
+ let (name, tp, args) = TransactionBuilder::parse_call(
+ "create_account<0x01::Dfinance::USD>([true, false], [0x01, 0x02])",
+ )
+ .unwrap();
+ assert_eq!(name, "create_account");
+ assert_eq!(
+ tp,
+ vec![TypeTag::Struct(StructTag {
+ address: CORE_CODE_ADDRESS,
+ module: Identifier::new("Dfinance").unwrap(),
+ name: Identifier::new("USD").unwrap(),
+ type_params: vec![],
+ })]
+ );
+ assert_eq!(
+ args,
+ vec!["[true,false]".to_owned(), "[0x01,0x02]".to_owned()]
+ );
+
+ let (name, tp, args) = TransactionBuilder::parse_call("create_account()").unwrap();
+ assert_eq!(name, "create_account");
+ assert_eq!(tp, Vec::::new());
+ assert_eq!(args, Vec::::new());
+
+ let (name, tp, args) = TransactionBuilder::parse_call("create_account<>()").unwrap();
+ assert_eq!(name, "create_account");
+ assert_eq!(tp, Vec::::new());
+ assert_eq!(args, Vec::::new());
+ }
+}
diff --git a/dove/src/cmd/fetch.rs b/dove/src/cmd/fetch.rs
index ccc2aaf3..43ca4448 100644
--- a/dove/src/cmd/fetch.rs
+++ b/dove/src/cmd/fetch.rs
@@ -2,7 +2,6 @@ use crate::cmd::Cmd;
use crate::context::Context;
use anyhow::Error;
use structopt::StructOpt;
-use crate::index::Index;
/// Fetch dependencies.
#[derive(StructOpt, Debug)]
@@ -10,8 +9,7 @@ pub struct Fetch {}
impl Cmd for Fetch {
fn apply(self, ctx: Context) -> Result<(), Error> {
- let mut index = Index::load(&ctx)?;
- index.build()?;
+ ctx.build_index()?;
Ok(())
}
}
diff --git a/dove/src/cmd/metadata.rs b/dove/src/cmd/metadata.rs
index 04463db9..06e8321c 100644
--- a/dove/src/cmd/metadata.rs
+++ b/dove/src/cmd/metadata.rs
@@ -57,18 +57,18 @@ pub struct PackageJson {
pub local_dependencies: Vec,
}
-impl Into for DoveToml {
- fn into(self) -> DoveJson {
+impl From for DoveJson {
+ fn from(toml: DoveToml) -> Self {
DoveJson {
- package: self.package.into(),
- layout: self.layout,
+ package: toml.package.into(),
+ layout: toml.layout,
}
}
}
-impl Into for Package {
- fn into(self) -> PackageJson {
- let (locals, git) = if let Some(dependencies) = self.dependencies {
+impl From for PackageJson {
+ fn from(pac: Package) -> Self {
+ let (locals, git) = if let Some(dependencies) = pac.dependencies {
dependencies.deps.into_iter().fold(
(Vec::new(), Vec::new()),
|(mut locals, mut gits), elt| {
@@ -84,10 +84,10 @@ impl Into for Package {
};
PackageJson {
- name: self.name.unwrap_or_default(),
- account_address: self.account_address,
- authors: self.authors,
- blockchain_api: self.blockchain_api,
+ name: pac.name.unwrap_or_default(),
+ account_address: pac.account_address,
+ authors: pac.authors,
+ blockchain_api: pac.blockchain_api,
git_dependencies: git,
local_dependencies: locals,
}
diff --git a/dove/src/cmd/mod.rs b/dove/src/cmd/mod.rs
index d4a4f27f..daba4110 100644
--- a/dove/src/cmd/mod.rs
+++ b/dove/src/cmd/mod.rs
@@ -8,6 +8,8 @@ use std::rc::Rc;
pub mod build;
/// Project dependencies loader.
pub mod clean;
+/// Create transaction.
+pub mod ct;
/// Dependencies fetcher.
pub mod fetch;
/// Project initializer.
diff --git a/dove/src/cmd/run.rs b/dove/src/cmd/run.rs
index 0a00547e..08b0663d 100644
--- a/dove/src/cmd/run.rs
+++ b/dove/src/cmd/run.rs
@@ -3,7 +3,6 @@ use crate::context::Context;
use anyhow::Error;
use structopt::StructOpt;
use lang::compiler::file::{MoveFile, load_move_files};
-use crate::index::Index;
use move_executor::executor::{Executor, render_execution_result};
/// Run script.
@@ -29,8 +28,7 @@ impl Cmd for Run {
}
let module_dir = ctx.path_for(&ctx.manifest.layout.module_dir);
- let mut index = Index::load(&ctx)?;
- index.build()?;
+ let mut index = ctx.build_index()?;
let dep_set = index.make_dependency_set(&[&script, &module_dir])?;
let mut dep_list = load_dependencies(dep_set)?;
diff --git a/dove/src/cmd/test.rs b/dove/src/cmd/test.rs
index d15b91a5..8f295741 100644
--- a/dove/src/cmd/test.rs
+++ b/dove/src/cmd/test.rs
@@ -2,7 +2,6 @@ use crate::cmd::{Cmd, load_dependencies};
use crate::context::Context;
use anyhow::Error;
use structopt::StructOpt;
-use crate::index::Index;
use lang::compiler::file::load_move_files;
use move_executor::executor::{Executor, render_test_result};
@@ -24,19 +23,14 @@ impl Cmd for Test {
return Ok(());
}
- let mut dirs: Vec<_> = [
+ let mut dirs = ctx.paths_for(&[
&ctx.manifest.layout.script_dir,
&ctx.manifest.layout.module_dir,
- ]
- .iter()
- .map(|d| ctx.path_for(&d))
- .filter(|p| p.exists())
- .collect();
+ ]);
dirs.push(tests_dir.clone());
- let mut index = Index::load(&ctx)?;
- index.build()?;
+ let mut index = ctx.build_index()?;
let dep_set = index.make_dependency_set(&dirs)?;
let mut dep_list = load_dependencies(dep_set)?;
diff --git a/dove/src/context.rs b/dove/src/context.rs
index 9c6f89db..87988e3e 100644
--- a/dove/src/context.rs
+++ b/dove/src/context.rs
@@ -1,10 +1,11 @@
use std::path::{PathBuf, Path};
use crate::manifest::{DoveToml, MANIFEST, read_manifest, default_dialect};
use std::str::FromStr;
-use anyhow::{Result, anyhow};
+use anyhow::{Result, anyhow, Error};
use std::env;
use lang::compiler::dialects::{Dialect, DialectName};
use lang::compiler::address::ProvidedAccountAddress;
+use crate::index::Index;
/// Project context.
pub struct Context {
@@ -22,6 +23,22 @@ impl Context {
self.project_dir.join(path)
}
+ /// Create absolute paths in project.
+ pub fn paths_for>(&self, paths: &[P]) -> Vec {
+ paths
+ .iter()
+ .map(|d| self.path_for(&d))
+ .filter(|p| p.exists())
+ .collect()
+ }
+
+ /// Build project index.
+ pub fn build_index(&self) -> Result {
+ let mut index = Index::load(self)?;
+ index.build()?;
+ Ok(index)
+ }
+
/// Returns project name or default name `project` if the name is not defined.
pub fn project_name(&self) -> String {
self.manifest.package.name.clone().unwrap_or_else(|| {
diff --git a/dove/src/index/mod.rs b/dove/src/index/mod.rs
index 3f71632c..7ffe0095 100644
--- a/dove/src/index/mod.rs
+++ b/dove/src/index/mod.rs
@@ -63,10 +63,10 @@ impl<'a> Index<'a> {
if !self.dep_names.contains(&name) {
if name.starts_with(git::PREFIX) {
let git = GitIndex::new(self.ctx, &path);
- self.store_meta(git.meta()?, SourceType::Git, name.clone())?;
+ self.store_meta(git.meta()?, SourceType::Git, name.clone());
} else if name.starts_with(chain::PREFIX) {
let chain = ChainIndex::new(self.ctx, &path);
- self.store_meta(chain.meta()?, SourceType::Chain, name.clone())?;
+ self.store_meta(chain.meta()?, SourceType::Chain, name.clone());
chain.meta()?;
}
new_deps.insert(name.clone());
@@ -184,7 +184,7 @@ impl<'a> Index<'a> {
}
}
- self.store_meta(files_meta, SourceType::Chain, name)?;
+ self.store_meta(files_meta, SourceType::Chain, name);
if !resolve(self, import, deps)? {
return Err(anyhow!("Failed to resolve dependency:{:?}", import));
@@ -220,7 +220,7 @@ impl<'a> Index<'a> {
self.ctx.dialect.as_ref(),
)?;
- self.store_meta(vec![meta], SourceType::Local, dep_name.clone())?;
+ self.store_meta(vec![meta], SourceType::Local, dep_name.clone());
}
Ok(())
}
@@ -257,12 +257,7 @@ impl<'a> Index<'a> {
Ok(())
}
- fn store_meta(
- &mut self,
- f_meta: Vec,
- src_type: SourceType,
- dep_name: Rc,
- ) -> Result<(), Error> {
+ fn store_meta(&mut self, f_meta: Vec, src_type: SourceType, dep_name: Rc) {
for file in f_meta {
for unit in file.meta {
let name = Rc::new(unit.module_id);
@@ -283,7 +278,6 @@ impl<'a> Index<'a> {
);
}
}
- Ok(())
}
}
diff --git a/dove/src/index/resolver/chain/loader.rs b/dove/src/index/resolver/chain/loader.rs
index 4647a204..e1b76950 100644
--- a/dove/src/index/resolver/chain/loader.rs
+++ b/dove/src/index/resolver/chain/loader.rs
@@ -105,7 +105,7 @@ where
/// Tries to load the module from the local cache.
/// Then tries to load the module from the external module source if the module doesn't exist in cache.
pub fn get(&self, module_id: &ModuleId) -> Result> {
- let name = self.make_local_name(&module_id)?;
+ let name = self.make_local_name(&module_id);
if let Some(cache_path) = &self.cache_path {
let local_path = cache_path.join(name);
@@ -128,12 +128,12 @@ where
}
}
- fn make_local_name(&self, module_id: &ModuleId) -> Result {
+ fn make_local_name(&self, module_id: &ModuleId) -> String {
let mut digest = Sha3::v256();
digest.update(module_id.name().as_bytes());
digest.update(module_id.address().as_ref());
let mut output = [0; 32];
digest.finalize(&mut output);
- Ok(hex::encode(&output))
+ hex::encode(&output)
}
}
diff --git a/dove/src/lib.rs b/dove/src/lib.rs
index 4c0128ff..66116090 100644
--- a/dove/src/lib.rs
+++ b/dove/src/lib.rs
@@ -4,6 +4,7 @@
#[macro_use]
extern crate anyhow;
+#[macro_use]
extern crate log;
/// Dove commands handler.
diff --git a/dove/src/manifest.rs b/dove/src/manifest.rs
index b4abd676..1ccfcc53 100644
--- a/dove/src/manifest.rs
+++ b/dove/src/manifest.rs
@@ -55,6 +55,7 @@ impl Default for Package {
}
}
+#[allow(clippy::unnecessary_wraps)]
fn dialect() -> Option {
Some(default_dialect())
}
@@ -79,6 +80,10 @@ fn script_output() -> String {
"target/scripts".to_owned()
}
+fn transaction_output() -> String {
+ "target/transactions".to_owned()
+}
+
fn target_deps() -> String {
"target/.external".to_owned()
}
@@ -91,6 +96,7 @@ fn index() -> String {
".Dove.man".to_owned()
}
+#[allow(clippy::unnecessary_wraps)]
fn code_code_address() -> Option {
Some(format!("0x{}", CORE_CODE_ADDRESS))
}
@@ -118,6 +124,10 @@ pub struct Layout {
#[serde(default = "script_output")]
pub script_output: String,
+ /// Directory with transactions.
+ #[serde(default = "transaction_output")]
+ pub transaction_output: String,
+
/// Directory with external dependencies.
#[serde(default = "target_deps")]
pub target_deps: String,
@@ -138,6 +148,7 @@ impl Default for Layout {
tests_dir: tests_dir(),
module_output: module_output(),
script_output: script_output(),
+ transaction_output: transaction_output(),
target_deps: target_deps(),
target: target(),
index: index(),
diff --git a/lang/disassembler/src/code/exp/mod.rs b/lang/disassembler/src/code/exp/mod.rs
index 6240fb55..bd7c0a0d 100644
--- a/lang/disassembler/src/code/exp/mod.rs
+++ b/lang/disassembler/src/code/exp/mod.rs
@@ -298,7 +298,7 @@ where
let sorted_index_list = range_list
.into_iter()
.map(|p| p.source_range())
- .filter_map(|p| p)
+ .flatten()
.flat_map(|p| vec![p.0, p.1])
.sorted()
.collect::>();
diff --git a/lang/src/lib.rs b/lang/src/lib.rs
index a35cdf67..785ea38d 100644
--- a/lang/src/lib.rs
+++ b/lang/src/lib.rs
@@ -8,3 +8,4 @@ pub extern crate disassembler;
pub mod builder;
pub mod checker;
pub mod compiler;
+pub mod meta_extractor;
diff --git a/lang/src/meta_extractor.rs b/lang/src/meta_extractor.rs
new file mode 100644
index 00000000..a7476091
--- /dev/null
+++ b/lang/src/meta_extractor.rs
@@ -0,0 +1,144 @@
+use crate::compiler::{CompileFlow, Step, compile};
+use anyhow::Error;
+use crate::compiler::parser::{ParserArtifact, ParsingMeta};
+use libra::module::{CompiledUnit, Definition};
+use libra::move_lang::errors::Errors;
+use crate::compiler::error::CompilerError;
+use crate::compiler::dialects::Dialect;
+use crate::compiler::file::MoveFile;
+use libra::move_lang::parser::ast::{Script, Type, Type_, ModuleAccess_};
+
+pub struct ScriptMetadata;
+
+impl ScriptMetadata {
+ pub fn extract(dialect: &dyn Dialect, script: &MoveFile) -> Result, Error> {
+ compile(dialect, &[script.to_owned()], &[], None, ScriptMetadata)
+ }
+}
+
+impl CompileFlow, Error>> for ScriptMetadata {
+ fn after_parsing(
+ &mut self,
+ parser_artifact: ParserArtifact,
+ ) -> Step, Error>, ParserArtifact> {
+ let result = parser_artifact.result;
+ let source_map = parser_artifact.meta.source_map;
+ let offsets_map = parser_artifact.meta.offsets_map;
+ Step::Stop(
+ result
+ .map_err(|err| {
+ CompilerError {
+ source_map,
+ errors: offsets_map.transform(err),
+ }
+ .into()
+ })
+ .map(|prog| {
+ prog.source_definitions
+ .into_iter()
+ .filter_map(|def| {
+ if let Definition::Script(script) = def {
+ Some(make_script_meta(script))
+ } else {
+ None
+ }
+ })
+ .collect::>()
+ }),
+ )
+ }
+
+ fn after_translate(
+ &mut self,
+ _: ParsingMeta,
+ _: Result, Errors>,
+ ) -> Result, Error> {
+ Ok(vec![])
+ }
+}
+
+fn make_script_meta(script: Script) -> Meta {
+ let func = script.function;
+ let type_parameters = func
+ .signature
+ .type_parameters
+ .into_iter()
+ .map(|tp| tp.0.value)
+ .collect();
+ let parameters = func
+ .signature
+ .parameters
+ .into_iter()
+ .map(|(var, tp)| (var.0.value, extract_type_name(tp)))
+ .collect();
+ Meta {
+ name: func.name.0.value,
+ type_parameters,
+ parameters,
+ }
+}
+
+fn extract_type_name(tp: Type) -> String {
+ match tp.value {
+ Type_::Apply(name, types) => {
+ let mut tp = match name.value {
+ ModuleAccess_::Name(name) => name.value,
+ ModuleAccess_::ModuleAccess(module, name) => {
+ format!("{}::{}", module.0.value, name.value)
+ }
+ ModuleAccess_::QualifiedModuleAccess(module, name) => {
+ let module = module.0.value;
+ format!("{}::{}::{}", module.address, module.name.0, name.value)
+ }
+ };
+ if !types.is_empty() {
+ tp.push('<');
+ tp.push_str(
+ &types
+ .into_iter()
+ .map(extract_type_name)
+ .collect::>()
+ .join(", "),
+ );
+ tp.push('>');
+ }
+ tp
+ }
+ Type_::Ref(is_mut, tp) => {
+ if is_mut {
+ format!("&mut {}", extract_type_name(*tp))
+ } else {
+ format!("&{}", extract_type_name(*tp))
+ }
+ }
+ Type_::Fun(types, tp) => {
+ format!(
+ "({}):{}",
+ types
+ .into_iter()
+ .map(extract_type_name)
+ .collect::>()
+ .join(", "),
+ extract_type_name(*tp)
+ )
+ }
+ Type_::Unit => "()".to_owned(),
+ Type_::Multiple(types) => {
+ format!(
+ "({})",
+ types
+ .into_iter()
+ .map(extract_type_name)
+ .collect::>()
+ .join(", ")
+ )
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct Meta {
+ pub name: String,
+ pub type_parameters: Vec,
+ pub parameters: Vec<(String, String)>,
+}
diff --git a/language_server/src/main_loop.rs b/language_server/src/main_loop.rs
index 07151df7..c19196ba 100644
--- a/language_server/src/main_loop.rs
+++ b/language_server/src/main_loop.rs
@@ -178,15 +178,7 @@ pub fn loop_turn(
}
Event::Lsp(message) => {
match message {
- Message::Request(req) => {
- on_request(
- global_state,
- pool,
- resp_events_sender,
- &connection.sender,
- req,
- )?;
- }
+ Message::Request(_) => {}
Message::Notification(not) => {
on_notification(&connection.sender, fs_events_sender, loop_state, not)?;
}
@@ -235,22 +227,6 @@ pub fn loop_turn(
Ok(())
}
-#[allow(unused)]
-fn on_request(
- global_state: &mut GlobalState,
- pool: &ThreadPool,
- task_sender: &Sender,
- msg_sender: &Sender,
- req: Request,
-) -> Result<()> {
- // let mut pool_dispatcher =
- // PoolDispatcher::new(req, pool, global_state, msg_sender, task_sender);
- // pool_dispatcher
- // .on::(handlers::handle_completion)?
- // .finish();
- Ok(())
-}
-
fn diagnostic_as_string(d: &Diagnostic) -> String {
format!(
"({}, {}), ({}, {}): {}",
diff --git a/resource-viewer/src/lib.rs b/resource-viewer/src/lib.rs
new file mode 100644
index 00000000..4b15559d
--- /dev/null
+++ b/resource-viewer/src/lib.rs
@@ -0,0 +1,5 @@
+#[macro_use]
+extern crate anyhow;
+
+pub mod ser;
+pub mod tte;
diff --git a/resource-viewer/src/main.rs b/resource-viewer/src/main.rs
index 199931d4..1b27a6ae 100644
--- a/resource-viewer/src/main.rs
+++ b/resource-viewer/src/main.rs
@@ -7,8 +7,6 @@
#[macro_use]
extern crate log;
-#[macro_use]
-extern crate anyhow;
use std::path::{Path, PathBuf};
use anyhow::{Result, Error, anyhow};
@@ -18,9 +16,7 @@ use libra::prelude::*;
use lang::compiler::bech32::{bech32_into_libra, HRP};
use dnclient::blocking as net;
use libra::rv;
-
-mod ser;
-mod tte;
+use move_resource_viewer::{tte, ser};
const VERSION: &str = git_hash::crate_version_with_git_hash_short!();
const JSON_SCHEMA_STDOUT: &str = "-";
diff --git a/resource-viewer/src/ser.rs b/resource-viewer/src/ser.rs
index 088e3383..d1fc8c87 100644
--- a/resource-viewer/src/ser.rs
+++ b/resource-viewer/src/ser.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::field_reassign_with_default)]
+
use libra::rv;
use libra::prelude::*;
use libra::move_core_types::language_storage::StructTag;
diff --git a/resource-viewer/src/tte.rs b/resource-viewer/src/tte.rs
index 79b8b192..af698c93 100644
--- a/resource-viewer/src/tte.rs
+++ b/resource-viewer/src/tte.rs
@@ -28,9 +28,9 @@ impl FromStr for TypeTagQuery {
}
}
-impl Into<(TypeTag, Option)> for TypeTagQuery {
- fn into(self) -> (TypeTag, Option) {
- (self.tt, self.i)
+impl From for (TypeTag, Option) {
+ fn from(query: TypeTagQuery) -> Self {
+ (query.tt, query.i)
}
}
@@ -40,7 +40,7 @@ impl TypeTagQuery {
}
}
-fn unwrap_spanned_ty(ty: Type) -> Result {
+pub fn unwrap_spanned_ty(ty: Type) -> Result {
fn unwrap_spanned_ty_(ty: Type, this: Option) -> Result {
let st = match ty.value {
Type_::Apply(ma, mut ty_params) => {