diff --git a/Cargo.lock b/Cargo.lock index a815117bd8fc4..a2aebd353d6e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7416,7 +7416,6 @@ dependencies = [ "hex", "move-binary-format", "move-core-types", - "num-bigint 0.4.4", "once_cell", "serde", "sha2 0.9.9", diff --git a/crates/sui-core/src/unit_tests/authority_tests.rs b/crates/sui-core/src/unit_tests/authority_tests.rs index f3e4d4646bf42..ba3f06d167689 100644 --- a/crates/sui-core/src/unit_tests/authority_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_tests.rs @@ -11,7 +11,6 @@ use move_binary_format::{ }; use move_core_types::identifier::IdentStr; use move_core_types::language_storage::StructTag; -use move_core_types::parser::parse_type_tag; use move_core_types::{ account_address::AccountAddress, ident_str, identifier::Identifier, language_storage::TypeTag, }; @@ -24,6 +23,7 @@ use rand::{ use serde_json::json; use std::collections::HashSet; use std::fs; +use std::str::FromStr; use std::{convert::TryInto, env}; use sui_json_rpc_types::{ @@ -3674,7 +3674,7 @@ async fn test_dynamic_field_struct_name_parsing() { assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); assert_eq!(json!({"name_str": "Test Name"}), fields[0].name.value); assert_eq!( - parse_type_tag("0x0::object_basics::Name").unwrap(), + TypeTag::from_str("0x0::object_basics::Name").unwrap(), fields[0].name.type_ ) } @@ -3686,7 +3686,10 @@ async fn test_dynamic_field_bytearray_name_parsing() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); - assert_eq!(parse_type_tag("vector").unwrap(), fields[0].name.type_); + assert_eq!( + TypeTag::from_str("vector").unwrap(), + fields[0].name.type_ + ); assert_eq!(json!("Test Name".as_bytes()), fields[0].name.value); } @@ -3697,7 +3700,7 @@ async fn test_dynamic_field_address_name_parsing() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicField)); - assert_eq!(parse_type_tag("address").unwrap(), fields[0].name.type_); + assert_eq!(TypeTag::from_str("address").unwrap(), fields[0].name.type_); assert_eq!(json!(sender), fields[0].name.value); } @@ -3709,7 +3712,7 @@ async fn test_dynamic_object_field_struct_name_parsing() { assert!(matches!(fields[0].type_, DynamicFieldType::DynamicObject)); assert_eq!(json!({"name_str": "Test Name"}), fields[0].name.value); assert_eq!( - parse_type_tag("0x0::object_basics::Name").unwrap(), + TypeTag::from_str("0x0::object_basics::Name").unwrap(), fields[0].name.type_ ) } @@ -3721,7 +3724,10 @@ async fn test_dynamic_object_field_bytearray_name_parsing() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicObject)); - assert_eq!(parse_type_tag("vector").unwrap(), fields[0].name.type_); + assert_eq!( + TypeTag::from_str("vector").unwrap(), + fields[0].name.type_ + ); assert_eq!(json!("Test Name".as_bytes()), fields[0].name.value); } @@ -3732,7 +3738,7 @@ async fn test_dynamic_object_field_address_name_parsing() { assert_eq!(fields.len(), 1); assert!(matches!(fields[0].type_, DynamicFieldType::DynamicObject)); - assert_eq!(parse_type_tag("address").unwrap(), fields[0].name.type_); + assert_eq!(TypeTag::from_str("address").unwrap(), fields[0].name.type_); assert_eq!(json!(sender), fields[0].name.value); } diff --git a/crates/sui-graphql-e2e-tests/tests/stable/packages/types.exp b/crates/sui-graphql-e2e-tests/tests/stable/packages/types.exp index 078ee9b351126..452e3b571a172 100644 --- a/crates/sui-graphql-e2e-tests/tests/stable/packages/types.exp +++ b/crates/sui-graphql-e2e-tests/tests/stable/packages/types.exp @@ -141,7 +141,7 @@ Response: { "data": null, "errors": [ { - "message": "Bad type: unexpected token Name(\"not_a_type\"), expected type tag", + "message": "Bad type: unexpected end of tokens", "locations": [ { "line": 3, diff --git a/crates/sui-replay/src/data_fetcher.rs b/crates/sui-replay/src/data_fetcher.rs index 897e9cb511a6f..f7d5fcfcb0cc5 100644 --- a/crates/sui-replay/src/data_fetcher.rs +++ b/crates/sui-replay/src/data_fetcher.rs @@ -6,7 +6,7 @@ use crate::types::EPOCH_CHANGE_STRUCT_TAG; use async_trait::async_trait; use futures::future::join_all; use lru::LruCache; -use move_core_types::parser::parse_struct_tag; +use move_core_types::language_storage::StructTag; use parking_lot::RwLock; use rand::Rng; use std::collections::BTreeMap; @@ -568,7 +568,7 @@ impl DataFetcher for RemoteFetcher { reverse: bool, ) -> Result, ReplayEngineError> { let struct_tag_str = EPOCH_CHANGE_STRUCT_TAG.to_string(); - let struct_tag = parse_struct_tag(&struct_tag_str)?; + let struct_tag = StructTag::from_str(&struct_tag_str)?; let mut epoch_change_events: Vec = vec![]; let mut has_next_page = true; diff --git a/crates/sui-transactional-test-runner/src/args.rs b/crates/sui-transactional-test-runner/src/args.rs index 2d73a54ea99d9..5e0e12299942d 100644 --- a/crates/sui-transactional-test-runner/src/args.rs +++ b/crates/sui-transactional-test-runner/src/args.rs @@ -5,10 +5,13 @@ use crate::test_adapter::{FakeID, SuiTestAdapter}; use anyhow::{bail, ensure}; use clap; use clap::{Args, Parser}; -use move_command_line_common::parser::{parse_u256, parse_u64}; -use move_command_line_common::values::{ParsableValue, ParsedValue}; -use move_command_line_common::{parser::Parser as MoveCLParser, values::ValueToken}; use move_compiler::editions::Flavor; +use move_core_types::parsing::{ + parser::Parser as MoveCLParser, + parser::{parse_u256, parse_u64}, + values::ValueToken, + values::{ParsableValue, ParsedValue}, +}; use move_core_types::runtime_value::{MoveStruct, MoveValue}; use move_core_types::u256::U256; use move_symbol_pool::Symbol; diff --git a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs b/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs index 3dfd6ec45ce6e..eb9397e40e5ea 100644 --- a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs +++ b/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/parser.rs @@ -3,7 +3,7 @@ use std::{borrow::BorrowMut, marker::PhantomData, str::FromStr}; -use move_command_line_common::{ +use move_core_types::parsing::{ parser::{Parser, Token}, types::{ParsedType, TypeToken}, }; diff --git a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/token.rs b/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/token.rs index 145bc5347c499..d4d03475881ad 100644 --- a/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/token.rs +++ b/crates/sui-transactional-test-runner/src/programmable_transaction_test_parser/token.rs @@ -4,8 +4,8 @@ use std::fmt::{self, Display}; use anyhow::bail; -use move_command_line_common::parser::Token; use move_core_types::identifier; +use move_core_types::parsing::parser::Token; #[derive(Eq, PartialEq, Debug, Clone, Copy)] pub enum CommandToken { diff --git a/crates/sui-transactional-test-runner/src/test_adapter.rs b/crates/sui-transactional-test-runner/src/test_adapter.rs index 6ee27e331e740..f9113bb41b8da 100644 --- a/crates/sui-transactional-test-runner/src/test_adapter.rs +++ b/crates/sui-transactional-test-runner/src/test_adapter.rs @@ -15,15 +15,14 @@ use fastcrypto::encoding::{Base64, Encoding}; use fastcrypto::traits::ToFromBytes; use move_binary_format::CompiledModule; use move_bytecode_utils::module_cache::GetModule; -use move_command_line_common::{ - address::ParsedAddress, files::verify_and_create_named_address_mapping, -}; +use move_command_line_common::files::verify_and_create_named_address_mapping; use move_compiler::{ editions::{Edition, Flavor}, shared::{NumberFormat, NumericalAddress, PackageConfig, PackagePaths}, Flags, FullyCompiledProgram, }; use move_core_types::ident_str; +use move_core_types::parsing::address::ParsedAddress; use move_core_types::{ account_address::AccountAddress, identifier::IdentStr, diff --git a/crates/sui-types/src/lib.rs b/crates/sui-types/src/lib.rs index 4823253ab985f..b956b6a38de6c 100644 --- a/crates/sui-types/src/lib.rs +++ b/crates/sui-types/src/lib.rs @@ -153,7 +153,7 @@ pub fn sui_framework_address_concat_string(suffix: &str) -> String { /// Parsing succeeds if and only if `s` matches one of these formats exactly, with no remaining /// suffix. This function is intended for use within the authority codebases. pub fn parse_sui_address(s: &str) -> anyhow::Result { - use move_command_line_common::address::ParsedAddress; + use move_core_types::parsing::address::ParsedAddress; Ok(ParsedAddress::parse(s)? .into_account_address(&resolve_address)? .into()) @@ -163,7 +163,7 @@ pub fn parse_sui_address(s: &str) -> anyhow::Result { /// module name (an identifier). Parsing succeeds if and only if `s` matches this format exactly, /// with no remaining input. This function is intended for use within the authority codebases. pub fn parse_sui_module_id(s: &str) -> anyhow::Result { - use move_command_line_common::types::ParsedModuleId; + use move_core_types::parsing::types::ParsedModuleId; ParsedModuleId::parse(s)?.into_module_id(&resolve_address) } @@ -172,7 +172,7 @@ pub fn parse_sui_module_id(s: &str) -> anyhow::Result { /// format exactly, with no remaining input. This function is intended for use within the authority /// codebases. pub fn parse_sui_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> { - use move_command_line_common::types::ParsedFqName; + use move_core_types::parsing::types::ParsedFqName; ParsedFqName::parse(s)?.into_fq_name(&resolve_address) } @@ -181,7 +181,7 @@ pub fn parse_sui_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> { /// brackets). Parsing succeeds if and only if `s` matches this format exactly, with no remaining /// input. This function is intended for use within the authority codebase. pub fn parse_sui_struct_tag(s: &str) -> anyhow::Result { - use move_command_line_common::types::ParsedStructType; + use move_core_types::parsing::types::ParsedStructType; ParsedStructType::parse(s)?.into_struct_tag(&resolve_address) } @@ -189,7 +189,7 @@ pub fn parse_sui_struct_tag(s: &str) -> anyhow::Result { /// vector with a type parameter. Parsing succeeds if and only if `s` matches this format exactly, /// with no remaining input. This function is intended for use within the authority codebase. pub fn parse_sui_type_tag(s: &str) -> anyhow::Result { - use move_command_line_common::types::ParsedType; + use move_core_types::parsing::types::ParsedType; ParsedType::parse(s)?.into_type_tag(&resolve_address) } diff --git a/crates/sui/src/client_ptb/ast.rs b/crates/sui/src/client_ptb/ast.rs index 762c34fd64b49..94eb9c23a5dc9 100644 --- a/crates/sui/src/client_ptb/ast.rs +++ b/crates/sui/src/client_ptb/ast.rs @@ -3,7 +3,7 @@ use std::fmt; -use move_command_line_common::{ +use move_core_types::parsing::{ address::{NumericalAddress, ParsedAddress}, types::{ParsedFqName, ParsedModuleId, ParsedStructType, ParsedType}, }; diff --git a/crates/sui/src/client_ptb/builder.rs b/crates/sui/src/client_ptb/builder.rs index 3737437b24a48..8df2dbf90dd7e 100644 --- a/crates/sui/src/client_ptb/builder.rs +++ b/crates/sui/src/client_ptb/builder.rs @@ -16,7 +16,7 @@ use miette::Severity; use move_binary_format::{ binary_config::BinaryConfig, file_format::SignatureToken, CompiledModule, }; -use move_command_line_common::{ +use move_core_types::parsing::{ address::{NumericalAddress, ParsedAddress}, parser::NumberFormat, }; diff --git a/crates/sui/src/client_ptb/parser.rs b/crates/sui/src/client_ptb/parser.rs index 7f442e0c96614..e9e769a39cfa3 100644 --- a/crates/sui/src/client_ptb/parser.rs +++ b/crates/sui/src/client_ptb/parser.rs @@ -3,7 +3,7 @@ use std::iter::Peekable; -use move_command_line_common::{ +use move_core_types::parsing::{ address::{NumericalAddress, ParsedAddress}, parser::{parse_u128, parse_u16, parse_u256, parse_u32, parse_u64, parse_u8}, types::{ParsedFqName, ParsedModuleId, ParsedStructType, ParsedType}, diff --git a/external-crates/move/Cargo.lock b/external-crates/move/Cargo.lock index acf99f3683cb6..375412d050dda 100644 --- a/external-crates/move/Cargo.lock +++ b/external-crates/move/Cargo.lock @@ -1804,7 +1804,6 @@ dependencies = [ "hex", "move-binary-format", "move-core-types", - "num-bigint", "once_cell", "proptest", "serde", diff --git a/external-crates/move/crates/move-cli/src/sandbox/cli.rs b/external-crates/move/crates/move-cli/src/sandbox/cli.rs index 30a4053bfdfb0..e8aee6887e169 100644 --- a/external-crates/move/crates/move-cli/src/sandbox/cli.rs +++ b/external-crates/move/crates/move-cli/src/sandbox/cli.rs @@ -11,15 +11,19 @@ use crate::{ }; use anyhow::Result; use clap::Parser; -use move_core_types::{ - language_storage::TypeTag, parser, transaction_argument::TransactionArgument, -}; +use move_core_types::parsing::values::ParsedValue; +use move_core_types::{language_storage::TypeTag, transaction_argument::TransactionArgument}; use move_package::compilation::package_layout::CompiledPackageLayout; use move_vm_test_utils::gas_schedule::CostTable; use std::{ fs, path::{Path, PathBuf}, }; +fn parse_transaction_argument(s: &str) -> Result { + let x: ParsedValue<()> = ParsedValue::parse(s)?; + let move_value = x.into_concrete_value(&|_| None)?; + TransactionArgument::try_from(move_value) +} #[derive(Parser)] pub enum SandboxCommand { @@ -75,7 +79,7 @@ pub enum SandboxCommand { /// ASCII strings (e.g., 'b"hi" will parse as the vector value [68, 69]). #[clap( long = "args", - value_parser = parser::parse_transaction_argument, + value_parser = parse_transaction_argument, num_args(1..), action = clap::ArgAction::Append, )] @@ -84,7 +88,6 @@ pub enum SandboxCommand { /// `main()`). Must match the type arguments kinds expected by `script_file`. #[clap( long = "type-args", - value_parser = parser::parse_type_tag, num_args(1..), action = clap::ArgAction::Append, )] @@ -155,7 +158,6 @@ pub struct StructLayoutOptions { /// Generate layout bindings for `struct` bound to these type arguments. #[clap( long = "type-args", - value_parser = parser::parse_type_tag, requires="struct", action = clap::ArgAction::Append, num_args(1..), diff --git a/external-crates/move/crates/move-command-line-common/Cargo.toml b/external-crates/move/crates/move-command-line-common/Cargo.toml index 08679ba8a6e31..83aa969a204af 100644 --- a/external-crates/move/crates/move-command-line-common/Cargo.toml +++ b/external-crates/move/crates/move-command-line-common/Cargo.toml @@ -15,7 +15,6 @@ difference.workspace = true walkdir.workspace = true sha2.workspace = true hex.workspace = true -num-bigint.workspace = true once_cell.workspace = true serde.workspace = true dirs-next.workspace = true @@ -27,9 +26,3 @@ move-binary-format.workspace = true [dev-dependencies] proptest.workspace = true -# Ok to do this since: -# edition = 2021 ==> resolver = 2 -# * https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html#summary -# resolver = 2 ==> feature-resolver-version-2 which allows dev-dependencies to set features -# * https://doc.rust-lang.org/cargo/reference/resolver.html#feature-resolver-version-2 -move-core-types = { workspace = true, features = ["fuzzing"] } diff --git a/external-crates/move/crates/move-command-line-common/src/lib.rs b/external-crates/move/crates/move-command-line-common/src/lib.rs index 2b087266cf27f..6014194ab13ef 100644 --- a/external-crates/move/crates/move-command-line-common/src/lib.rs +++ b/external-crates/move/crates/move-command-line-common/src/lib.rs @@ -4,14 +4,10 @@ #![forbid(unsafe_code)] -pub mod address; pub mod character_sets; pub mod display; pub mod env; pub mod error_bitset; pub mod files; pub mod interactive; -pub mod parser; pub mod testing; -pub mod types; -pub mod values; diff --git a/external-crates/move/crates/move-compiler/src/expansion/translate.rs b/external-crates/move/crates/move-compiler/src/expansion/translate.rs index 13c5aa0530fba..4e70132871e6e 100644 --- a/external-crates/move/crates/move-compiler/src/expansion/translate.rs +++ b/external-crates/move/crates/move-compiler/src/expansion/translate.rs @@ -40,8 +40,8 @@ use crate::{ }, FullyCompiledProgram, }; -use move_command_line_common::parser::{parse_u16, parse_u256, parse_u32}; use move_core_types::account_address::AccountAddress; +use move_core_types::parsing::parser::{parse_u16, parse_u256, parse_u32}; use move_ir_types::location::*; use move_proc_macros::growing_stack; use move_symbol_pool::Symbol; diff --git a/external-crates/move/crates/move-compiler/src/shared/ide.rs b/external-crates/move/crates/move-compiler/src/shared/ide.rs index 6816278d34ed8..895f57da06985 100644 --- a/external-crates/move/crates/move-compiler/src/shared/ide.rs +++ b/external-crates/move/crates/move-compiler/src/shared/ide.rs @@ -16,7 +16,7 @@ use crate::{ unit_test::filter_test_members::UNIT_TEST_POISON_FUN_NAME, }; -use move_command_line_common::address::NumericalAddress; +use move_core_types::parsing::address::NumericalAddress; use move_ir_types::location::Loc; use move_symbol_pool::Symbol; diff --git a/external-crates/move/crates/move-compiler/src/shared/mod.rs b/external-crates/move/crates/move-compiler/src/shared/mod.rs index a242bcb7565ef..b0609c6f4fd93 100644 --- a/external-crates/move/crates/move-compiler/src/shared/mod.rs +++ b/external-crates/move/crates/move-compiler/src/shared/mod.rs @@ -62,7 +62,7 @@ pub use ast_debug::AstDebug; // Numbers //************************************************************************************************** -pub use move_command_line_common::parser::{ +pub use move_core_types::parsing::parser::{ parse_address_number as parse_address, parse_u128, parse_u16, parse_u256, parse_u32, parse_u64, parse_u8, NumberFormat, }; @@ -71,7 +71,7 @@ pub use move_command_line_common::parser::{ // Address //************************************************************************************************** -pub use move_command_line_common::address::NumericalAddress; +pub use move_core_types::parsing::address::NumericalAddress; pub fn parse_named_address(s: &str) -> anyhow::Result<(String, NumericalAddress)> { let before_after = s.split('=').collect::>(); diff --git a/external-crates/move/crates/move-core-types/src/language_storage.rs b/external-crates/move/crates/move-core-types/src/language_storage.rs index 64f314cfe49ef..bbf597fc5d326 100644 --- a/external-crates/move/crates/move-core-types/src/language_storage.rs +++ b/external-crates/move/crates/move-core-types/src/language_storage.rs @@ -6,7 +6,7 @@ use crate::{ account_address::AccountAddress, gas_algebra::{AbstractMemorySize, BOX_ABSTRACT_SIZE, ENUM_BASE_ABSTRACT_SIZE}, identifier::{IdentStr, Identifier}, - parser::{parse_struct_tag, parse_type_tag}, + parsing::types::{ParsedModuleId, ParsedStructType, ParsedType}, }; use move_proc_macros::test_variant_order; use once_cell::sync::Lazy; @@ -137,7 +137,7 @@ impl FromStr for TypeTag { type Err = anyhow::Error; fn from_str(s: &str) -> Result { - parse_type_tag(s) + ParsedType::parse(s)?.into_type_tag(&|_| None) } } @@ -252,7 +252,7 @@ impl FromStr for StructTag { type Err = anyhow::Error; fn from_str(s: &str) -> Result { - parse_struct_tag(s) + ParsedStructType::parse(s)?.into_struct_tag(&|_| None) } } @@ -327,6 +327,13 @@ impl Display for ModuleId { } } +impl FromStr for ModuleId { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result { + ParsedModuleId::parse(s)?.into_module_id(&|_| None) + } +} + impl ModuleId { pub fn short_str_lossless(&self) -> String { format!("0x{}::{}", self.address.short_str_lossless(), self.name) diff --git a/external-crates/move/crates/move-core-types/src/lib.rs b/external-crates/move/crates/move-core-types/src/lib.rs index fa471e38808e4..d90bd5a8246bc 100644 --- a/external-crates/move/crates/move-core-types/src/lib.rs +++ b/external-crates/move/crates/move-core-types/src/lib.rs @@ -18,7 +18,7 @@ pub mod identifier; pub mod language_storage; pub mod metadata; pub mod move_resource; -pub mod parser; +pub mod parsing; #[cfg(any(test, feature = "fuzzing"))] pub mod proptest_types; pub mod resolver; diff --git a/external-crates/move/crates/move-core-types/src/parser.rs b/external-crates/move/crates/move-core-types/src/parser.rs deleted file mode 100644 index 99af0f2dce1b5..0000000000000 --- a/external-crates/move/crates/move-core-types/src/parser.rs +++ /dev/null @@ -1,632 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use crate::{ - account_address::AccountAddress, - identifier::{self, Identifier}, - language_storage::{StructTag, TypeTag}, - transaction_argument::TransactionArgument, -}; -use anyhow::{bail, format_err, Result}; -use std::iter::Peekable; - -#[derive(Eq, PartialEq, Debug)] -enum Token { - U8Type, - U16Type, - U32Type, - U64Type, - U128Type, - U256Type, - BoolType, - AddressType, - VectorType, - SignerType, - Whitespace(String), - Name(String), - Address(String), - U8(String), - U16(String), - U32(String), - U64(String), - U128(String), - U256(String), - - Bytes(String), - True, - False, - ColonColon, - Lt, - Gt, - Comma, - EOF, -} - -impl Token { - fn is_whitespace(&self) -> bool { - matches!(self, Self::Whitespace(_)) - } -} - -fn token_as_name(tok: Token) -> Result { - use Token::*; - Ok(match tok { - U8Type => "u8".to_string(), - U16Type => "u16".to_string(), - U32Type => "u32".to_string(), - U64Type => "u64".to_string(), - U128Type => "u128".to_string(), - U256Type => "u256".to_string(), - BoolType => "bool".to_string(), - AddressType => "address".to_string(), - VectorType => "vector".to_string(), - True => "true".to_string(), - False => "false".to_string(), - SignerType => "signer".to_string(), - Name(s) => s, - Whitespace(_) | Address(_) | U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | U256(_) - | Bytes(_) | ColonColon | Lt | Gt | Comma | EOF => { - bail!("Invalid token. Expected a name but got {:?}", tok) - } - }) -} - -fn name_token(s: String) -> Token { - match s.as_str() { - "u8" => Token::U8Type, - "u16" => Token::U16Type, - "u32" => Token::U32Type, - "u64" => Token::U64Type, - "u128" => Token::U128Type, - "u256" => Token::U256Type, - "bool" => Token::BoolType, - "address" => Token::AddressType, - "vector" => Token::VectorType, - "true" => Token::True, - "false" => Token::False, - "signer" => Token::SignerType, - _ => Token::Name(s), - } -} - -fn next_number(initial: char, mut it: impl Iterator) -> Result<(Token, usize)> { - let mut num = String::new(); - num.push(initial); - loop { - match it.next() { - Some(c) if c.is_ascii_digit() || c == '_' => num.push(c), - Some(c) if c.is_alphanumeric() => { - let mut suffix = String::new(); - suffix.push(c); - loop { - match it.next() { - Some(c) if c.is_ascii_alphanumeric() => suffix.push(c), - _ => { - let len = num.len() + suffix.len(); - let tok = match suffix.as_str() { - "u8" => Token::U8(num), - "u16" => Token::U16(num), - "u32" => Token::U32(num), - "u64" => Token::U64(num), - "u128" => Token::U128(num), - "u256" => Token::U256(num), - _ => bail!("invalid suffix"), - }; - return Ok((tok, len)); - } - } - } - } - _ => { - let len = num.len(); - return Ok((Token::U64(num), len)); - } - } - } -} - -#[allow(clippy::many_single_char_names)] -fn next_token(s: &str) -> Result> { - let mut it = s.chars().peekable(); - 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"), - }, - '0' if it.peek() == Some(&'x') || it.peek() == Some(&'X') => { - it.next().unwrap(); - match it.next() { - Some(c) if c.is_ascii_hexdigit() => { - 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); - } else { - break; - } - } - let len = r.len(); - (Token::Address(r), len) - } - _ => bail!("unrecognized token"), - } - } - c if c.is_ascii_digit() => next_number(c, it)?, - 'b' if it.peek() == Some(&'"') => { - it.next().unwrap(); - let mut r = String::new(); - loop { - match it.next() { - Some('"') => break, - Some(c) if c.is_ascii() => r.push(c), - _ => bail!("unrecognized token"), - } - } - let len = r.len() + 3; - (Token::Bytes(hex::encode(r)), len) - } - 'x' if it.peek() == Some(&'"') => { - it.next().unwrap(); - let mut r = String::new(); - loop { - match it.next() { - Some('"') => break, - Some(c) if c.is_ascii_hexdigit() => r.push(c), - _ => bail!("unrecognized token"), - } - } - let len = r.len() + 3; - (Token::Bytes(r), len) - } - c if c.is_ascii_whitespace() => { - let mut r = String::new(); - r.push(c); - for c in it { - if c.is_ascii_whitespace() { - r.push(c); - } else { - break; - } - } - let len = r.len(); - (Token::Whitespace(r), len) - } - c if c.is_ascii_alphabetic() => { - let mut r = String::new(); - r.push(c); - for c in it { - if identifier::is_valid_identifier_char(c) { - r.push(c); - } else { - break; - } - } - let len = r.len(); - (name_token(r), len) - } - _ => 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::U8Type => TypeTag::U8, - Token::U16Type => TypeTag::U16, - Token::U32Type => TypeTag::U32, - Token::U64Type => TypeTag::U64, - Token::U128Type => TypeTag::U128, - Token::U256Type => TypeTag::U256, - Token::BoolType => TypeTag::Bool, - Token::AddressType => TypeTag::Address, - Token::SignerType => TypeTag::Signer, - Token::VectorType => { - 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)?; - let module = self.next().and_then(token_as_name)?; - self.consume(Token::ColonColon)?; - let name = self.next().and_then(token_as_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(Box::new(StructTag { - address: AccountAddress::from_hex_literal(&addr)?, - module: Identifier::new(module)?, - name: Identifier::new(name)?, - type_params: ty_args, - })) - } - tok => bail!("unexpected token {:?}, expected type tag", tok), - }) - } - - fn parse_transaction_argument(&mut self) -> Result { - Ok(match self.next()? { - Token::U8(s) => TransactionArgument::U8(s.replace('_', "").parse()?), - Token::U16(s) => TransactionArgument::U16(s.replace('_', "").parse()?), - Token::U32(s) => TransactionArgument::U32(s.replace('_', "").parse()?), - Token::U64(s) => TransactionArgument::U64(s.replace('_', "").parse()?), - Token::U128(s) => TransactionArgument::U128(s.replace('_', "").parse()?), - Token::U256(s) => TransactionArgument::U256(s.replace('_', "").parse()?), - Token::True => TransactionArgument::Bool(true), - Token::False => TransactionArgument::Bool(false), - Token::Address(addr) => { - TransactionArgument::Address(AccountAddress::from_hex_literal(&addr)?) - } - Token::Bytes(s) => TransactionArgument::U8Vector(hex::decode(s)?), - tok => bail!("unexpected token {:?}, expected transaction argument", tok), - }) - } -} - -fn parse(s: &str, f: F) -> Result -where - F: Fn(&mut Parser>) -> 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 res = f(&mut parser)?; - parser.consume(Token::EOF)?; - Ok(res) -} - -pub fn parse_type_tag(s: &str) -> Result { - parse(s, |parser| parser.parse_type_tag()) -} - -pub fn parse_transaction_argument(s: &str) -> Result { - parse(s, |parser| parser.parse_transaction_argument()) -} - -pub fn parse_struct_tag(s: &str) -> Result { - let type_tag = parse(s, |parser| parser.parse_type_tag()) - .map_err(|e| format_err!("invalid struct tag: {}, {}", s, e))?; - if let TypeTag::Struct(struct_tag) = type_tag { - Ok(*struct_tag) - } else { - bail!("invalid struct tag: {}", s) - } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use crate::{ - account_address::AccountAddress, - parser::{parse_struct_tag, parse_transaction_argument, parse_type_tag}, - transaction_argument::TransactionArgument, - u256, - }; - - #[allow(clippy::unreadable_literal)] - #[test] - fn tests_parse_transaction_argument_positive() { - use TransactionArgument as T; - - for (s, expected) in &[ - (" 0u8", T::U8(0)), - ("0u8", T::U8(0)), - ("255u8", T::U8(255)), - ("0", T::U64(0)), - ("0123", T::U64(123)), - ("0u64", T::U64(0)), - ("18446744073709551615", T::U64(18446744073709551615)), - ("18446744073709551615u64", T::U64(18446744073709551615)), - ("0u128", T::U128(0)), - ("1_0u8", T::U8(1_0)), - ("10_u8", T::U8(10)), - ("10___u8", T::U8(10)), - ("1_000u64", T::U64(1_000)), - ("1_000", T::U64(1_000)), - ("1_0_0_0u64", T::U64(1_000)), - ("1_000_000u128", T::U128(1_000_000)), - ( - "340282366920938463463374607431768211455u128", - T::U128(340282366920938463463374607431768211455), - ), - (" 0u16", T::U16(0)), - ("0u16", T::U16(0)), - ("532u16", T::U16(532)), - ("65535u16", T::U16(65535)), - ("0u32", T::U32(0)), - ("01239498u32", T::U32(1239498)), - ("35366u32", T::U32(35366)), - ("4294967295u32", T::U32(4294967295)), - ("0u256", T::U256(u256::U256::from(0u8))), - ("1_0u16", T::U16(1_0)), - ("10_u16", T::U16(10)), - ("10___u16", T::U16(10)), - ("1_000u32", T::U32(1_000)), - ("1_0_00u32", T::U32(1_000)), - ("1_0_0_0u32", T::U32(1_000)), - ("1_000_000u256", T::U256(u256::U256::from(1_000_000u64))), - ( - "1_000_000_000u256", - T::U256(u256::U256::from(1_000_000_000u128)), - ), - ( - "3402823669209384634633746074317682114551234u256", - T::U256( - u256::U256::from_str("3402823669209384634633746074317682114551234").unwrap(), - ), - ), - ("true", T::Bool(true)), - ("false", T::Bool(false)), - ( - "0x0", - T::Address(AccountAddress::from_hex_literal("0x0").unwrap()), - ), - ( - "0x54afa3526", - T::Address(AccountAddress::from_hex_literal("0x54afa3526").unwrap()), - ), - ( - "0X54afa3526", - T::Address(AccountAddress::from_hex_literal("0x54afa3526").unwrap()), - ), - ("x\"7fff\"", T::U8Vector(vec![0x7f, 0xff])), - ("x\"\"", T::U8Vector(vec![])), - ("x\"00\"", T::U8Vector(vec![0x00])), - ("x\"deadbeef\"", T::U8Vector(vec![0xde, 0xad, 0xbe, 0xef])), - ] { - assert_eq!(&parse_transaction_argument(s).unwrap(), expected) - } - } - - #[test] - fn tests_parse_transaction_argument_negative() { - /// Test cases for the parser that should always fail. - const PARSE_VALUE_NEGATIVE_TEST_CASES: &[&str] = &[ - "-3", - "0u42", - "0u645", - "0u64x", - "0u6 4", - "0u", - "_10", - "_10_u8", - "_10__u8", - "_1014__u32", - "10_u8__", - "_", - "__", - "__4", - "_u8", - "5_bool", - "256u8", - "18446744073709551616u64", - "340282366920938463463374607431768211456u128", - "340282366920938463463374607431768211456340282366920938463463374607431768211456340282366920938463463374607431768211456u256", - "0xg", - "0x00g0", - "0x", - "0x_", - "", - "@@", - "()", - "x\"ffff", - "x\"a \"", - "x\" \"", - "x\"0g\"", - "x\"0\"", - "garbage", - "true3", - "3false", - "3 false", - "", - ]; - - for s in PARSE_VALUE_NEGATIVE_TEST_CASES { - assert!( - parse_transaction_argument(s).is_err(), - "test case unexpectedly succeeded: {}", - s - ) - } - } - - #[test] - fn test_type_tag() { - for s in &[ - "u64", - "bool", - "vector", - "vector>", - "vector", - "vector>", - "vector", - "vector>", - "vector", - "vector>", - "vector", - "vector>", - "signer", - "0x1::M::S", - "0x2::M::S_", - "0x3::M_::S", - "0x4::M_::S_", - "0x00000000004::M::S", - "0x1::M::S", - "0x1::M::S", - "0x1::M::S", - "0x1::M::S", - "0x1::M::S<0x2::P::Q>", - "vector<0x1::M::S>", - "vector<0x1::M_::S_>", - "vector>", - "0x1::M::S>", - "0x1::M::S>", - "0x1::M::S>", - "0x1::M::S>", - "0x1::M::S>", - "0x1::M::S>", - ] { - assert!(parse_type_tag(s).is_ok(), "Failed to parse tag {}", s); - } - } - - #[test] - fn test_parse_valid_struct_tag() { - let valid = vec![ - "0x1::Diem::Diem", - "0x1::Diem_Type::Diem", - "0x1::Diem_::Diem", - "0x1::X_123::X32_", - "0x1::Diem::Diem_Type", - "0x1::Diem::Diem<0x1::XDX::XDX>", - "0x1::Diem::Diem<0x1::XDX::XDX_Type>", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem
", - "0x1::Diem::Diem", - "0x1::Diem::Diem>", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem", - "0x1::Diem::Diem,address,signer>", - "0x1::Diem::Diem>>", - "0x1::Diem::Diem<0x1::Diem::Struct, 0x1::Diem::Diem>>>>", - ]; - for text in valid { - let st = parse_struct_tag(text).expect("valid StructTag"); - assert_eq!( - st.to_string().replace(' ', ""), - text.replace(' ', ""), - "text: {:?}, StructTag: {:?}", - text, - st - ); - } - } - - #[test] - fn test_parse_struct_tag_with_type_names() { - let names = vec![ - "address", "vector", "u128", "u256", "u64", "u32", "u16", "u8", "bool", "signer", - ]; - - let mut tests = vec![]; - for name in &names { - for name_type in &names { - tests.push(format!("0x1::{name}::{name_type}")) - } - } - - let mut instantiations = vec![]; - for ty in &tests { - for other_ty in &tests { - instantiations.push(format!("{ty}<{other_ty}>")) - } - } - - for text in tests.iter().chain(instantiations.iter()) { - let st = parse_struct_tag(text).expect("valid StructTag"); - assert_eq!( - st.to_string().replace(' ', ""), - text.replace(' ', ""), - "text: {:?}, StructTag: {:?}", - text, - st - ); - } - } -} diff --git a/external-crates/move/crates/move-command-line-common/src/address.rs b/external-crates/move/crates/move-core-types/src/parsing/address.rs similarity index 97% rename from external-crates/move/crates/move-command-line-common/src/address.rs rename to external-crates/move/crates/move-core-types/src/parsing/address.rs index 0e63a23b8d85d..b479e76dcf23c 100644 --- a/external-crates/move/crates/move-command-line-common/src/address.rs +++ b/external-crates/move/crates/move-core-types/src/parsing/address.rs @@ -1,10 +1,10 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::parser::{parse_address_number, NumberFormat}; +use crate::account_address::AccountAddress; +use crate::parsing::parser::{parse_address_number, NumberFormat}; use anyhow::anyhow; -use move_core_types::account_address::AccountAddress; -use num_bigint::BigUint; +use num::BigUint; use std::{fmt, hash::Hash}; // Parsed Address, either a name or a numerical address diff --git a/external-crates/move/crates/move-core-types/src/parsing/mod.rs b/external-crates/move/crates/move-core-types/src/parsing/mod.rs new file mode 100644 index 0000000000000..46c51e639f0a6 --- /dev/null +++ b/external-crates/move/crates/move-core-types/src/parsing/mod.rs @@ -0,0 +1,10 @@ +// Copyright (c) The Diem Core Contributors +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] + +pub mod address; +pub mod parser; +pub mod types; +pub mod values; diff --git a/external-crates/move/crates/move-command-line-common/src/parser.rs b/external-crates/move/crates/move-core-types/src/parsing/parser.rs similarity index 62% rename from external-crates/move/crates/move-command-line-common/src/parser.rs rename to external-crates/move/crates/move-core-types/src/parsing/parser.rs index accd1d1a94653..1245c34239d54 100644 --- a/external-crates/move/crates/move-command-line-common/src/parser.rs +++ b/external-crates/move/crates/move-core-types/src/parsing/parser.rs @@ -1,17 +1,17 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::{ +use crate::parsing::{ address::{NumericalAddress, ParsedAddress}, types::{ParsedFqName, ParsedModuleId, ParsedStructType, ParsedType, TypeToken}, values::{ParsableValue, ParsedValue, ValueToken}, }; -use anyhow::{anyhow, bail, Result}; -use move_core_types::{ +use crate::{ account_address::AccountAddress, u256::{U256FromStrError, U256}, }; -use num_bigint::BigUint; +use anyhow::{anyhow, bail, Result}; +use num::BigUint; use std::{fmt::Display, iter::Peekable, num::ParseIntError}; const MAX_TYPE_DEPTH: u64 = 128; @@ -76,7 +76,7 @@ impl ParsedValue { } } -fn parse<'a, Tok: Token, R>( +pub(crate) fn parse<'a, Tok: Token, R>( s: &'a str, f: impl FnOnce(&mut Parser<'a, Tok, std::vec::IntoIter<(Tok, &'a str)>>) -> Result, ) -> Result { @@ -139,8 +139,12 @@ impl<'a, Tok: Token, I: Iterator> Parser<'a, Tok, I> { break; } self.advance(delim)?; - if is_end(self.peek_tok()) && allow_trailing_delim { - break; + if is_end(self.peek_tok()) { + if allow_trailing_delim { + break; + } else { + bail!("Invalid type list: trailing delimiter '{}'", delim) + } } } Ok(v) @@ -225,6 +229,9 @@ impl<'a, I: Iterator> Parser<'a, TypeToken, I> { true, )?; self.advance(TypeToken::Gt)?; + if type_args.is_empty() { + bail!("expected at least one type argument") + } type_args } _ => vec![], @@ -457,289 +464,3 @@ pub fn parse_address_number(s: &str) -> Option<([u8; AccountAddress::LENGTH], Nu result[(AccountAddress::LENGTH - bytes.len())..].clone_from_slice(&bytes); Some((result, base)) } - -#[cfg(test)] -mod tests { - use crate::{ - address::{NumericalAddress, ParsedAddress}, - types::{ParsedStructType, ParsedType}, - values::ParsedValue, - }; - use move_core_types::{account_address::AccountAddress, identifier::Identifier, u256::U256}; - use proptest::prelude::*; - use proptest::proptest; - - #[allow(clippy::unreadable_literal)] - #[test] - fn tests_parse_value_positive() { - use ParsedValue as V; - let cases: &[(&str, V)] = &[ - (" 0u8", V::U8(0)), - ("0u8", V::U8(0)), - ("0xF_Fu8", V::U8(255)), - ("0xF__FF__Eu16", V::U16(u16::MAX - 1)), - ("0xFFF_FF__FF_Cu32", V::U32(u32::MAX - 3)), - ("255u8", V::U8(255)), - ("255u256", V::U256(U256::from(255u64))), - ("0", V::InferredNum(U256::from(0u64))), - ("0123", V::InferredNum(U256::from(123u64))), - ("0xFF", V::InferredNum(U256::from(0xFFu64))), - ("0xF_F", V::InferredNum(U256::from(0xFFu64))), - ("0xFF__", V::InferredNum(U256::from(0xFFu64))), - ( - "0x12_34__ABCD_FF", - V::InferredNum(U256::from(0x1234ABCDFFu64)), - ), - ("0u64", V::U64(0)), - ("0x0u64", V::U64(0)), - ( - "18446744073709551615", - V::InferredNum(U256::from(18446744073709551615u128)), - ), - ("18446744073709551615u64", V::U64(18446744073709551615)), - ("0u128", V::U128(0)), - ("1_0u8", V::U8(1_0)), - ("10_u8", V::U8(10)), - ("1_000u64", V::U64(1_000)), - ("1_000", V::InferredNum(U256::from(1_000u32))), - ("1_0_0_0u64", V::U64(1_000)), - ("1_000_000u128", V::U128(1_000_000)), - ( - "340282366920938463463374607431768211455u128", - V::U128(340282366920938463463374607431768211455), - ), - ("true", V::Bool(true)), - ("false", V::Bool(false)), - ( - "@0x0", - V::Address(ParsedAddress::Numerical(NumericalAddress::new( - AccountAddress::from_hex_literal("0x0") - .unwrap() - .into_bytes(), - crate::parser::NumberFormat::Hex, - ))), - ), - ( - "@0", - V::Address(ParsedAddress::Numerical(NumericalAddress::new( - AccountAddress::from_hex_literal("0x0") - .unwrap() - .into_bytes(), - crate::parser::NumberFormat::Hex, - ))), - ), - ( - "@0x54afa3526", - V::Address(ParsedAddress::Numerical(NumericalAddress::new( - AccountAddress::from_hex_literal("0x54afa3526") - .unwrap() - .into_bytes(), - crate::parser::NumberFormat::Hex, - ))), - ), - ( - "b\"hello\"", - V::Vector("hello".as_bytes().iter().copied().map(V::U8).collect()), - ), - ("x\"7fff\"", V::Vector(vec![V::U8(0x7f), V::U8(0xff)])), - ("x\"\"", V::Vector(vec![])), - ("x\"00\"", V::Vector(vec![V::U8(0x00)])), - ( - "x\"deadbeef\"", - V::Vector(vec![V::U8(0xde), V::U8(0xad), V::U8(0xbe), V::U8(0xef)]), - ), - ]; - - for (s, expected) in cases { - assert_eq!(&ParsedValue::parse(s).unwrap(), expected) - } - } - - #[test] - fn tests_parse_value_negative() { - /// Test cases for the parser that should always fail. - const PARSE_VALUE_NEGATIVE_TEST_CASES: &[&str] = &[ - "-3", - "0u42", - "0u645", - "0u64x", - "0u6 4", - "0u", - "_10", - "_10_u8", - "_10__u8", - "10_u8__", - "0xFF_u8_", - "0xF_u8__", - "0x_F_u8__", - "_", - "__", - "__4", - "_u8", - "5_bool", - "256u8", - "4294967296u32", - "65536u16", - "18446744073709551616u64", - "340282366920938463463374607431768211456u128", - "340282366920938463463374607431768211456340282366920938463463374607431768211456340282366920938463463374607431768211456340282366920938463463374607431768211456u256", - "0xg", - "0x00g0", - "0x", - "0x_", - "", - "@@", - "()", - "x\"ffff", - "x\"a \"", - "x\" \"", - "x\"0g\"", - "x\"0\"", - "garbage", - "true3", - "3false", - "3 false", - "", - "0XFF", - "0X0", - ]; - - for s in PARSE_VALUE_NEGATIVE_TEST_CASES { - assert!( - ParsedValue::<()>::parse(s).is_err(), - "Unexpectedly succeeded in parsing: {}", - s - ) - } - } - - #[test] - fn test_parse_type_negative() { - for s in &[ - "_", - "_::_::_", - "0x1::_", - "0x1::__::_", - "0x1::_::__", - "0x1::_::foo", - "0x1::foo::_", - "0x1::_::_", - "0x1::bar::foo<0x1::_::foo>", - ] { - assert!( - ParsedType::parse(s).is_err(), - "Parsed type {s} but should have failed" - ); - } - } - - #[test] - fn test_parse_struct_negative() { - for s in &[ - "_", - "_::_::_", - "0x1::_", - "0x1::__::_", - "0x1::_::__", - "0x1::_::foo", - "0x1::foo::_", - "0x1::_::_", - "0x1::bar::foo<0x1::_::foo>", - ] { - assert!( - ParsedStructType::parse(s).is_err(), - "Parsed type {s} but should have failed" - ); - } - } - - #[test] - fn test_type_type() { - for s in &[ - "u64", - "bool", - "vector", - "vector>", - "address", - "signer", - "0x1::M::S", - "0x2::M::S_", - "0x3::M_::S", - "0x4::M_::S_", - "0x00000000004::M::S", - "0x1::M::S", - "0x1::M::S<0x2::P::Q>", - "vector<0x1::M::S>", - "vector<0x1::M_::S_>", - "vector>", - "0x1::M::S>", - "0x1::_bar::_BAR", - "0x1::__::__", - "0x1::_bar::_BAR<0x2::_____::______fooo______>", - "0x1::__::__<0x2::_____::______fooo______, 0xff::Bar____::_______foo>", - ] { - assert!(ParsedType::parse(s).is_ok(), "Failed to parse type {}", s); - } - } - - #[test] - fn test_parse_valid_struct_type() { - let valid = vec![ - "0x1::Foo::Foo", - "0x1::Foo_Type::Foo", - "0x1::Foo_::Foo", - "0x1::X_123::X32_", - "0x1::Foo::Foo_Type", - "0x1::Foo::Foo<0x1::ABC::ABC>", - "0x1::Foo::Foo<0x1::ABC::ABC_Type>", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo
", - "0x1::Foo::Foo", - "0x1::Foo::Foo>", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo", - "0x1::Foo::Foo,address,signer>", - "0x1::Foo::Foo>>", - "0x1::Foo::Foo<0x1::Foo::Struct, 0x1::Foo::Foo>>>>", - "0x1::_bar::_BAR", - "0x1::__::__", - "0x1::_bar::_BAR<0x2::_____::______fooo______>", - "0x1::__::__<0x2::_____::______fooo______, 0xff::Bar____::_______foo>", - ]; - for s in valid { - assert!( - ParsedStructType::parse(s).is_ok(), - "Failed to parse struct {}", - s - ); - } - } - - fn struct_type_gen() -> impl Strategy { - ( - any::(), - any::(), - any::(), - ) - .prop_map(|(address, module, name)| format!("0x{}::{}::{}", address, module, name)) - } - - proptest! { - #[test] - fn test_parse_valid_struct_type_proptest(s in struct_type_gen()) { - prop_assert!(ParsedStructType::parse(&s).is_ok()); - } - - #[test] - fn test_parse_valid_type_struct_only_proptest(s in struct_type_gen()) { - prop_assert!(ParsedStructType::parse(&s).is_ok()); - } - } -} diff --git a/external-crates/move/crates/move-command-line-common/src/types.rs b/external-crates/move/crates/move-core-types/src/parsing/types.rs similarity index 98% rename from external-crates/move/crates/move-command-line-common/src/types.rs rename to external-crates/move/crates/move-core-types/src/parsing/types.rs index 442e0ed691629..f011d4fc62cb9 100644 --- a/external-crates/move/crates/move-command-line-common/src/types.rs +++ b/external-crates/move/crates/move-core-types/src/parsing/types.rs @@ -3,14 +3,14 @@ use std::fmt::{self, Display}; -use anyhow::bail; -use move_core_types::{ +use crate::{ account_address::AccountAddress, identifier::{self, Identifier}, language_storage::{ModuleId, StructTag, TypeTag}, }; +use anyhow::bail; -use crate::{address::ParsedAddress, parser::Token}; +use crate::parsing::{address::ParsedAddress, parser::Token}; #[derive(Eq, PartialEq, Debug, Clone, Copy)] pub enum TypeToken { diff --git a/external-crates/move/crates/move-command-line-common/src/values.rs b/external-crates/move/crates/move-core-types/src/parsing/values.rs similarity index 99% rename from external-crates/move/crates/move-command-line-common/src/values.rs rename to external-crates/move/crates/move-core-types/src/parsing/values.rs index 03bf0a80ad9f4..951dafe04c11a 100644 --- a/external-crates/move/crates/move-command-line-common/src/values.rs +++ b/external-crates/move/crates/move-core-types/src/parsing/values.rs @@ -1,16 +1,16 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::{ +use crate::parsing::{ address::ParsedAddress, parser::{Parser, Token}, }; -use anyhow::bail; -use move_core_types::{ +use crate::{ account_address::AccountAddress, identifier, runtime_value::{MoveStruct, MoveValue}, }; +use anyhow::bail; use std::fmt::{self, Display}; #[derive(Eq, PartialEq, Debug, Clone, Copy)] @@ -39,13 +39,13 @@ pub enum ValueToken { #[derive(Eq, PartialEq, Debug, Clone)] pub enum ParsedValue { Address(ParsedAddress), - InferredNum(move_core_types::u256::U256), + InferredNum(crate::u256::U256), U8(u8), U16(u16), U32(u32), U64(u64), U128(u128), - U256(move_core_types::u256::U256), + U256(crate::u256::U256), Bool(bool), Vector(Vec>), Struct(Vec>), diff --git a/external-crates/move/crates/move-core-types/src/unit_tests/mod.rs b/external-crates/move/crates/move-core-types/src/unit_tests/mod.rs index 237660ea9a80a..64e54f71b241d 100644 --- a/external-crates/move/crates/move-core-types/src/unit_tests/mod.rs +++ b/external-crates/move/crates/move-core-types/src/unit_tests/mod.rs @@ -5,5 +5,6 @@ mod extractor_test; mod identifier_test; mod language_storage_test; +mod parsing_test; mod value_test; mod visitor_test; diff --git a/external-crates/move/crates/move-core-types/src/unit_tests/parsing_test.rs b/external-crates/move/crates/move-core-types/src/unit_tests/parsing_test.rs new file mode 100644 index 0000000000000..426d03abc92a4 --- /dev/null +++ b/external-crates/move/crates/move-core-types/src/unit_tests/parsing_test.rs @@ -0,0 +1,590 @@ +use crate::{ + account_address::AccountAddress, + identifier::Identifier, + language_storage::{ModuleId, StructTag, TypeTag}, + parsing::{ + address::{NumericalAddress, ParsedAddress}, + parser::parse, + types::{ParsedFqName, ParsedType, TypeToken}, + values::ParsedValue, + }, + u256::U256, +}; +use anyhow::bail; +use proptest::{prelude::*, proptest}; +use std::str::FromStr; + +#[allow(clippy::unreadable_literal)] +#[test] +fn tests_parse_value_positive() { + use ParsedValue as V; + let cases: &[(&str, V)] = &[ + (" 0u8", V::U8(0)), + ("0u8", V::U8(0)), + ("0xF_Fu8", V::U8(255)), + ("0xF__FF__Eu16", V::U16(u16::MAX - 1)), + ("0xFFF_FF__FF_Cu32", V::U32(u32::MAX - 3)), + ("255u8", V::U8(255)), + ("255u256", V::U256(U256::from(255u64))), + ("0", V::InferredNum(U256::from(0u64))), + ("0123", V::InferredNum(U256::from(123u64))), + ("0xFF", V::InferredNum(U256::from(0xFFu64))), + ("0xF_F", V::InferredNum(U256::from(0xFFu64))), + ("0xFF__", V::InferredNum(U256::from(0xFFu64))), + ( + "0x12_34__ABCD_FF", + V::InferredNum(U256::from(0x1234ABCDFFu64)), + ), + ("0u64", V::U64(0)), + ("0x0u64", V::U64(0)), + ( + "18446744073709551615", + V::InferredNum(U256::from(18446744073709551615u128)), + ), + ("18446744073709551615u64", V::U64(18446744073709551615)), + ("0u128", V::U128(0)), + ("1_0u8", V::U8(1_0)), + ("10_u8", V::U8(10)), + ("1_000u64", V::U64(1_000)), + ("1_000", V::InferredNum(U256::from(1_000u32))), + ("1_0_0_0u64", V::U64(1_000)), + ("1_000_000u128", V::U128(1_000_000)), + ( + "340282366920938463463374607431768211455u128", + V::U128(340282366920938463463374607431768211455), + ), + ("true", V::Bool(true)), + ("false", V::Bool(false)), + ( + "@0x0", + V::Address(ParsedAddress::Numerical(NumericalAddress::new( + AccountAddress::from_hex_literal("0x0") + .unwrap() + .into_bytes(), + crate::parsing::parser::NumberFormat::Hex, + ))), + ), + ( + "@0", + V::Address(ParsedAddress::Numerical(NumericalAddress::new( + AccountAddress::from_hex_literal("0x0") + .unwrap() + .into_bytes(), + crate::parsing::parser::NumberFormat::Hex, + ))), + ), + ( + "@0x54afa3526", + V::Address(ParsedAddress::Numerical(NumericalAddress::new( + AccountAddress::from_hex_literal("0x54afa3526") + .unwrap() + .into_bytes(), + crate::parsing::parser::NumberFormat::Hex, + ))), + ), + ( + "b\"hello\"", + V::Vector("hello".as_bytes().iter().copied().map(V::U8).collect()), + ), + ("x\"7fff\"", V::Vector(vec![V::U8(0x7f), V::U8(0xff)])), + ("x\"\"", V::Vector(vec![])), + ("x\"00\"", V::Vector(vec![V::U8(0x00)])), + ( + "x\"deadbeef\"", + V::Vector(vec![V::U8(0xde), V::U8(0xad), V::U8(0xbe), V::U8(0xef)]), + ), + ]; + + for (s, expected) in cases { + assert_eq!(&ParsedValue::parse(s).unwrap(), expected) + } +} + +#[test] +fn tests_parse_value_negative() { + /// Test cases for the parser that should always fail. + const PARSE_VALUE_NEGATIVE_TEST_CASES: &[&str] = &[ + "-3", + "0u42", + "0u645", + "0u64x", + "0u6 4", + "0u", + "_10", + "_10_u8", + "_10__u8", + "10_u8__", + "0xFF_u8_", + "0xF_u8__", + "0x_F_u8__", + "_", + "__", + "__4", + "_u8", + "5_bool", + "256u8", + "4294967296u32", + "65536u16", + "18446744073709551616u64", + "340282366920938463463374607431768211456u128", + "340282366920938463463374607431768211456340282366920938463463374607431768211456340282366920938463463374607431768211456340282366920938463463374607431768211456u256", + "0xg", + "0x00g0", + "0x", + "0x_", + "", + "@@", + "()", + "x\"ffff", + "x\"a \"", + "x\" \"", + "x\"0g\"", + "x\"0\"", + "garbage", + "true3", + "3false", + "3 false", + "", + "0XFF", + "0X0", + ]; + + for s in PARSE_VALUE_NEGATIVE_TEST_CASES { + assert!( + ParsedValue::<()>::parse(s).is_err(), + "Unexpectedly succeeded in parsing: {}", + s + ) + } +} + +#[test] +fn test_parse_type_negative() { + for s in &[ + "_", + "_::_::_", + "0x1::_", + "0x1::__::_", + "0x1::_::__", + "0x1::_::foo", + "0x1::foo::_", + "0x1::_::_", + "0x1::bar::foo<0x1::_::foo>", + "0X1::bar::bar", + ] { + assert!( + TypeTag::from_str(s).is_err(), + "Parsed type {s} but should have failed" + ); + } +} + +#[test] +fn test_parse_struct_negative() { + for s in &[ + "_", + "_::_::_", + "0x1::_", + "0x1::__::_", + "0x1::_::__", + "0x1::_::foo", + "0x1::foo::_", + "0x1::_::_", + "0x1::bar::foo<0x1::_::foo>", + "0x1::bar::bar::foo", + "0x1::Foo::Foo<", + "0x1::Foo::Foo<0x1::ABC::ABC", + "0x1::Foo::Foo<0x1::ABC::ABC::>", + "0x1::Foo::Foo<0x1::ABC::ABC::A>", + "0x1::Foo::Foo<>", + "0x1::Foo::Foo<,>", + "0x1::Foo::Foo<,", + "0x1::Foo::Foo,>", + "0x1::Foo::Foo>", + "0x1::Foo::Foo,", + ] { + assert!( + TypeTag::from_str(s).is_err(), + "Parsed type {s} but should have failed" + ); + } +} + +#[test] +fn test_type_type() { + for s in &[ + "u64", + "bool", + "vector", + "vector>", + "address", + "signer", + "0x1::M::S", + "0x2::M::S_", + "0x3::M_::S", + "0x4::M_::S_", + "0x00000000004::M::S", + "0x1::M::S", + "0x1::M::S<0x2::P::Q>", + "vector<0x1::M::S>", + "vector<0x1::M_::S_>", + "vector>", + "0x1::M::S>", + "0x1::_bar::_BAR", + "0x1::__::__", + "0x1::_bar::_BAR<0x2::_____::______fooo______>", + "0x1::__::__<0x2::_____::______fooo______, 0xff::Bar____::_______foo>", + ] { + assert!(TypeTag::from_str(s).is_ok(), "Failed to parse type {}", s); + } +} + +#[test] +fn test_parse_valid_struct_type() { + let valid = vec![ + "0x1::Foo::Foo", + "0x1::Foo_Type::Foo", + "0x1::Foo_::Foo", + "0x1::X_123::X32_", + "0x1::Foo::Foo_Type", + "0x1::Foo::Foo<0x1::ABC::ABC>", + "0x1::Foo::Foo<0x1::ABC::ABC_Type>", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo
", + "0x1::Foo::Foo", + "0x1::Foo::Foo>", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo", + "0x1::Foo::Foo,address,signer>", + "0x1::Foo::Foo>>", + "0x1::Foo::Foo<0x1::Foo::Struct, 0x1::Foo::Foo>>>>", + "0x1::_bar::_BAR", + "0x1::__::__", + "0x1::_bar::_BAR<0x2::_____::______fooo______>", + "0x1::__::__<0x2::_____::______fooo______, 0xff::Bar____::_______foo>", + ]; + for s in valid { + assert!( + StructTag::from_str(s).is_ok(), + "Failed to parse struct {}", + s + ); + } +} + +#[test] +fn test_parse_type_list() { + let valid_with_trails = vec![ + "", + "", + ",>", + ]; + let valid_no_trails = vec![ + "", + "", + ">", + ]; + let invalid = vec![ + "<>", + "<,>", + "", + "<,u64>", + "<,u64,>", + ",", + "", + "<", + "<<", + "><", + ">,<", + ">,", + ",>", + ",,", + ">>", + "", + "u64,>", + "u64, u64,>", + "u64, u64,", + "u64, u64", + "u64 u64", + "", + "", + "u64 u64,", + "", + ",", + ",,>", + ]; + + for t in valid_no_trails.iter().chain(valid_with_trails.iter()) { + assert!(parse_type_tags(t, true).is_ok()); + } + + for t in &valid_no_trails { + assert!(parse_type_tags(t, false).is_ok()); + } + + for t in &valid_with_trails { + assert!(parse_type_tags(t, false).is_err()); + } + + for t in &invalid { + assert!(parse_type_tags(t, true).is_err(), "parsed type {}", t); + assert!(parse_type_tags(t, false).is_err(), "parsed type {}", t); + } +} + +fn struct_type_gen0() -> impl Strategy { + ( + any::(), + any::(), + any::(), + ) + .prop_map(|(address, module, name)| format!("0x{}::{}::{}", address, module, name)) +} + +fn struct_type_gen1() -> impl Strategy { + (any::(), any::(), any::()) + .prop_map(|(address, module, name)| format!("{}::{}::{}", address, module, name)) +} + +fn module_id_gen0() -> impl Strategy { + (any::(), any::()) + .prop_map(|(address, module)| format!("0x{address}::{module}")) +} + +fn module_id_gen1() -> impl Strategy { + (any::(), any::()) + .prop_map(|(address, module)| format!("{address}::{module}")) +} + +fn fq_id_gen0() -> impl Strategy { + ( + any::(), + any::(), + any::(), + ) + .prop_map(|(address, module, name)| format!("0x{address}::{module}::{name}")) +} + +fn fq_id_gen1() -> impl Strategy { + (any::(), any::(), any::()) + .prop_map(|(address, module, name)| format!("{address}::{module}::{name}")) +} + +fn parse_type_tags(s: &str, allow_trailing_delim: bool) -> anyhow::Result> { + parse(s, |parser| { + parser.advance(TypeToken::Lt)?; + let parsed = parser.parse_list( + |parser| parser.parse_type(), + TypeToken::Comma, + TypeToken::Gt, + allow_trailing_delim, + )?; + parser.advance(TypeToken::Gt)?; + if parsed.is_empty() { + bail!("expected at least one type argument") + } + Ok(parsed) + }) +} + +proptest! { + #[test] + fn parse_type_tag_list(t in struct_type_gen0(), args in proptest::collection::vec(struct_type_gen0(), 1..=100)) { + let s_no_trail = format!("<{}>", args.join(",")); + let s_with_trail = format!("<{},>", args.join(",")); + let s_no_trail_no_trail = parse_type_tags(&s_no_trail, false); + let s_no_trail_allow_trail = parse_type_tags(&s_no_trail, true); + let s_with_trail_no_trail = parse_type_tags(&s_with_trail, false); + let s_with_trail_allow_trail = parse_type_tags(&s_with_trail, true); + prop_assert!(s_no_trail_no_trail.is_ok()); + prop_assert!(s_no_trail_allow_trail.is_ok()); + prop_assert!(s_with_trail_no_trail.is_err()); + prop_assert!(s_with_trail_allow_trail.is_ok()); + let t_with_trail = format!("{t}{s_no_trail}"); + let t_no_trail = format!("{t}{s_with_trail}"); + let t_with_trail = TypeTag::from_str(&t_with_trail); + let t_no_trail = TypeTag::from_str(&t_no_trail); + prop_assert!(t_with_trail.is_ok()); + prop_assert!(t_no_trail.is_ok()); + prop_assert_eq!(t_with_trail.unwrap(), t_no_trail.unwrap()); + } + + #[test] + fn test_parse_valid_struct_type_proptest0(s in struct_type_gen0(), x in r#"(::foo)[^a-zA-Z0-9_\s]+"#) { + prop_assert!(StructTag::from_str(&s).is_ok()); + prop_assert!(TypeTag::from_str(&s).is_ok()); + prop_assert!(ParsedFqName::parse(&s).is_ok()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + + // Add remainder string + let s = s + &x; + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + + } + + #[test] + fn test_parse_valid_struct_type_proptest1(s in struct_type_gen1(), x in r#"(::foo)[^a-zA-Z0-9_\s]+"#) { + prop_assert!(StructTag::from_str(&s).is_ok()); + prop_assert!(TypeTag::from_str(&s).is_ok()); + prop_assert!(ParsedFqName::parse(&s).is_ok()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + // add remainder string + let s = s + &x; + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + } + + #[test] + fn test_parse_valid_module_id_proptest0(s in module_id_gen0(), x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(ModuleId::from_str(&s).is_ok()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + // add remainder string + let s = s + &x; + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + } + + #[test] + fn test_parse_valid_module_id_proptest1(s in module_id_gen1(), x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(ModuleId::from_str(&s).is_ok()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + // add remainder String + let s = s + &x; + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + + } + + #[test] + fn test_parse_valid_fq_id_proptest0(s in fq_id_gen0(), x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(ParsedFqName::parse(&s).is_ok()); + prop_assert!(StructTag::from_str(&s).is_ok()); + prop_assert!(TypeTag::from_str(&s).is_ok()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + // add remainder string + let s = s + &x; + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + } + + #[test] + fn test_parse_valid_fq_id_proptest1(s in fq_id_gen1(), x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(ParsedFqName::parse(&s).is_ok()); + prop_assert!(StructTag::from_str(&s).is_ok()); + prop_assert!(TypeTag::from_str(&s).is_ok()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + let s = s + &x; + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + } + + #[test] + fn test_parse_valid_numeric_address(s in "[0-9]{64}", x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(AccountAddress::from_str(&s).is_ok()); + prop_assert!(ParsedAddress::parse(&s).is_ok()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + // add remainder string + let s = s + &x; + prop_assert!(AccountAddress::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + } + + #[test] + fn test_parse_different_length_numeric_addresses(s in "[0-9]{1,63}", x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(AccountAddress::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_ok()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + // add remainder string + let s = s + &x; + prop_assert!(AccountAddress::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + } + + #[test] + fn test_parse_valid_hex_address(s in "0x[0-9a-fA-F]{64}", x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(AccountAddress::from_str(&s).is_ok()); + prop_assert!(ParsedAddress::parse(&s).is_ok()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + // add remainder string + let s = s + &x; + prop_assert!(AccountAddress::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + } + + #[test] + fn test_parse_invalid_hex_address(s in "[0-9]{63}[a-fA-F]{1}", x in r#"[^a-zA-Z0-9_\s]+"#) { + prop_assert!(AccountAddress::from_str(&s).is_ok()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + // add remainder string + let s = s + &x; + prop_assert!(AccountAddress::from_str(&s).is_err()); + prop_assert!(ParsedAddress::parse(&s).is_err()); + prop_assert!(ParsedFqName::parse(&s).is_err()); + prop_assert!(ModuleId::from_str(&s).is_err()); + prop_assert!(StructTag::from_str(&s).is_err()); + prop_assert!(TypeTag::from_str(&s).is_err()); + } +} diff --git a/external-crates/move/crates/move-model/src/model.rs b/external-crates/move/crates/move-model/src/model.rs index f80c4c15b9ba1..40d0391f2a456 100644 --- a/external-crates/move/crates/move-model/src/model.rs +++ b/external-crates/move/crates/move-model/src/model.rs @@ -47,7 +47,8 @@ use move_binary_format::{ CompiledModule, }; use move_bytecode_source_map::{mapping::SourceMapping, source_map::SourceMap}; -use move_command_line_common::{address::NumericalAddress, files::FileHash}; +use move_command_line_common::files::FileHash; +use move_core_types::parsing::address::NumericalAddress; use move_core_types::{ account_address::AccountAddress, identifier::{IdentStr, Identifier}, diff --git a/external-crates/move/crates/move-stdlib/src/lib.rs b/external-crates/move/crates/move-stdlib/src/lib.rs index 5d714e3d3acd1..a823dca9fefe4 100644 --- a/external-crates/move/crates/move-stdlib/src/lib.rs +++ b/external-crates/move/crates/move-stdlib/src/lib.rs @@ -3,10 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 use log::LevelFilter; -use move_command_line_common::{ - address::NumericalAddress, - files::{extension_equals, find_filenames, MOVE_EXTENSION}, -}; +use move_command_line_common::files::{extension_equals, find_filenames, MOVE_EXTENSION}; +use move_core_types::parsing::address::NumericalAddress; use std::{collections::BTreeMap, path::PathBuf}; #[cfg(test)] diff --git a/external-crates/move/crates/move-transactional-test-runner/src/framework.rs b/external-crates/move/crates/move-transactional-test-runner/src/framework.rs index 54f935d88d65c..ac38bdfbe78cd 100644 --- a/external-crates/move/crates/move-transactional-test-runner/src/framework.rs +++ b/external-crates/move/crates/move-transactional-test-runner/src/framework.rs @@ -14,12 +14,9 @@ use clap::Parser; use move_binary_format::file_format::CompiledModule; use move_bytecode_source_map::{mapping::SourceMapping, source_map::SourceMap}; use move_command_line_common::{ - address::ParsedAddress, env::read_bool_env_var, files::{MOVE_EXTENSION, MOVE_IR_EXTENSION}, testing::{add_update_baseline_fix, format_diff, read_env_update_baseline, EXP_EXT}, - types::ParsedType, - values::{ParsableValue, ParsedValue}, }; use move_compiler::{ compiled_unit::AnnotatedCompiledUnit, @@ -28,6 +25,11 @@ use move_compiler::{ shared::{files::MappedFiles, NumericalAddress, PackageConfig}, FullyCompiledProgram, }; +use move_core_types::parsing::{ + address::ParsedAddress, + types::ParsedType, + values::{ParsableValue, ParsedValue}, +}; use move_core_types::{ account_address::AccountAddress, identifier::{IdentStr, Identifier}, diff --git a/external-crates/move/crates/move-transactional-test-runner/src/tasks.rs b/external-crates/move/crates/move-transactional-test-runner/src/tasks.rs index c1e62c544f60b..f5247de2c86a7 100644 --- a/external-crates/move/crates/move-transactional-test-runner/src/tasks.rs +++ b/external-crates/move/crates/move-transactional-test-runner/src/tasks.rs @@ -6,14 +6,14 @@ use anyhow::{anyhow, bail, Result}; use clap::*; -use move_command_line_common::{ +use move_command_line_common::files::{MOVE_EXTENSION, MOVE_IR_EXTENSION}; +use move_compiler::shared::NumericalAddress; +use move_core_types::identifier::Identifier; +use move_core_types::parsing::{ address::ParsedAddress, - files::{MOVE_EXTENSION, MOVE_IR_EXTENSION}, types::ParsedType, values::{ParsableValue, ParsedValue}, }; -use move_compiler::shared::NumericalAddress; -use move_core_types::identifier::Identifier; use std::{convert::TryInto, fmt::Debug, path::Path, str::FromStr}; use tempfile::NamedTempFile; diff --git a/external-crates/move/crates/move-transactional-test-runner/src/vm_test_harness.rs b/external-crates/move/crates/move-transactional-test-runner/src/vm_test_harness.rs index f04769afce091..05b3b5d281926 100644 --- a/external-crates/move/crates/move-transactional-test-runner/src/vm_test_harness.rs +++ b/external-crates/move/crates/move-transactional-test-runner/src/vm_test_harness.rs @@ -15,10 +15,9 @@ use move_binary_format::{ errors::{Location, VMError, VMResult}, CompiledModule, }; -use move_command_line_common::{ - address::ParsedAddress, files::verify_and_create_named_address_mapping, -}; +use move_command_line_common::files::verify_and_create_named_address_mapping; use move_compiler::{editions::Edition, shared::PackagePaths, FullyCompiledProgram}; +use move_core_types::parsing::address::ParsedAddress; use move_core_types::{ account_address::AccountAddress, identifier::IdentStr,