Skip to content

Commit

Permalink
[Move] Sui Parser for fully-qualified names (MystenLabs#15660)
Browse files Browse the repository at this point in the history
## Description

Extract implementation for fully-qualified name parsing, and expose it
as a parsing entrypoint, to be used to create a cascading filter for
functions (where the most precise filter format is the function's
fully-qualified name).

## Test Plan

New unit tests:

```
sui-types$ cargo nextest run
```

##  Stack

- MystenLabs#15625 
- MystenLabs#15528
- MystenLabs#15529
- MystenLabs#15628
  • Loading branch information
amnn committed Jan 12, 2024
1 parent f4b18af commit f09f738
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 18 deletions.
21 changes: 21 additions & 0 deletions crates/sui-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ pub fn parse_sui_module_id(s: &str) -> anyhow::Result<ModuleId> {
ParsedModuleId::parse(s)?.into_module_id(&resolve_address)
}

/// Parse `s` as a fully-qualified name: A Module ID (see `parse_sui_module_id`), followed by `::`,
/// and then an identifier (for the module member). 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_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> {
use move_command_line_common::types::ParsedFqName;
ParsedFqName::parse(s)?.into_fq_name(&resolve_address)
}

/// Parse `s` as a struct type: A fully-qualified name, optionally followed by a list of type
/// parameters (types -- see `parse_sui_type_tag`, separated by commas, surrounded by angle
/// brackets). Parsing succeeds if and only if `s` matches this format exactly, with no remaining
Expand Down Expand Up @@ -339,6 +348,18 @@ mod tests {
expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
}

#[test]
fn test_parse_sui_fq_name() {
let (module, name) = parse_sui_fq_name("0x2::object::new").expect("should not error");
let expected = expect![
"0x0000000000000000000000000000000000000000000000000000000000000002::object::new"
];
expected.assert_eq(&format!(
"{}::{name}",
module.to_canonical_display(/* with_prefix */ true)
));
}

#[test]
fn test_parse_sui_struct_tag_short_account_addr() {
let result = parse_sui_struct_tag("0x2::sui::SUI").expect("should not error");
Expand Down
34 changes: 25 additions & 9 deletions external-crates/move/crates/move-command-line-common/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::{
address::{NumericalAddress, ParsedAddress},
types::{ParsedModuleId, ParsedStructType, ParsedType, TypeToken},
types::{ParsedFqName, ParsedModuleId, ParsedStructType, ParsedType, TypeToken},
values::{ParsableValue, ParsedValue, ValueToken},
};
use anyhow::{anyhow, bail, Result};
Expand Down Expand Up @@ -47,6 +47,12 @@ impl ParsedModuleId {
}
}

impl ParsedFqName {
pub fn parse(s: &str) -> Result<ParsedFqName> {
parse(s, |parser| parser.parse_fq_name())
}
}

impl ParsedStructType {
pub fn parse(s: &str) -> Result<ParsedStructType> {
let ty = parse(s, |parser| parser.parse_type())
Expand Down Expand Up @@ -147,6 +153,11 @@ impl<'a, I: Iterator<Item = (TypeToken, &'a str)>> Parser<'a, TypeToken, I> {
self.parse_module_id_impl(tok, contents)
}

pub fn parse_fq_name(&mut self) -> Result<ParsedFqName> {
let (tok, contents) = self.advance_any()?;
self.parse_fq_name_impl(tok, contents)
}

pub fn parse_type(&mut self) -> Result<ParsedType> {
self.parse_type_impl(0)
}
Expand All @@ -167,6 +178,17 @@ impl<'a, I: Iterator<Item = (TypeToken, &'a str)>> Parser<'a, TypeToken, I> {
Ok(ParsedModuleId { address, name })
}

pub fn parse_fq_name_impl(
&mut self,
tok: TypeToken,
contents: &'a str,
) -> Result<ParsedFqName> {
let module = self.parse_module_id_impl(tok, contents)?;
self.advance(TypeToken::ColonColon)?;
let name = self.advance(TypeToken::Ident)?.to_owned();
Ok(ParsedFqName { module, name })
}

fn parse_type_impl(&mut self, depth: u64) -> Result<ParsedType> {
self.count += 1;

Expand All @@ -192,9 +214,7 @@ impl<'a, I: Iterator<Item = (TypeToken, &'a str)>> Parser<'a, TypeToken, I> {
}

(tok @ (TypeToken::Ident | TypeToken::AddressIdent), contents) => {
let module = self.parse_module_id_impl(tok, contents)?;
self.advance(TypeToken::ColonColon)?;
let name = self.advance(TypeToken::Ident)?.to_owned();
let fq_name = self.parse_fq_name_impl(tok, contents)?;
let type_args = match self.peek_tok() {
Some(TypeToken::Lt) => {
self.advance(TypeToken::Lt)?;
Expand All @@ -209,11 +229,7 @@ impl<'a, I: Iterator<Item = (TypeToken, &'a str)>> Parser<'a, TypeToken, I> {
}
_ => vec![],
};
ParsedType::Struct(ParsedStructType {
module,
name,
type_args,
})
ParsedType::Struct(ParsedStructType { fq_name, type_args })
}
(tok, _) => bail!("unexpected token {tok}, expected type"),
})
Expand Down
28 changes: 19 additions & 9 deletions external-crates/move/crates/move-command-line-common/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,14 @@ pub struct ParsedModuleId {
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub struct ParsedStructType {
pub struct ParsedFqName {
pub module: ParsedModuleId,
pub name: String,
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub struct ParsedStructType {
pub fq_name: ParsedFqName,
pub type_args: Vec<ParsedType>,
}

Expand Down Expand Up @@ -133,20 +138,25 @@ impl ParsedModuleId {
}
}

impl ParsedFqName {
pub fn into_fq_name(
self,
mapping: &impl Fn(&str) -> Option<AccountAddress>,
) -> anyhow::Result<(ModuleId, String)> {
Ok((self.module.into_module_id(mapping)?, self.name))
}
}

impl ParsedStructType {
pub fn into_struct_tag(
self,
mapping: &impl Fn(&str) -> Option<AccountAddress>,
) -> anyhow::Result<StructTag> {
let Self {
module,
name,
type_args,
} = self;
let Self { fq_name, type_args } = self;
Ok(StructTag {
address: module.address.into_account_address(mapping)?,
module: Identifier::new(module.name)?,
name: Identifier::new(name)?,
address: fq_name.module.address.into_account_address(mapping)?,
module: Identifier::new(fq_name.module.name)?,
name: Identifier::new(fq_name.name)?,
type_params: type_args
.into_iter()
.map(|t| t.into_type_tag(mapping))
Expand Down

0 comments on commit f09f738

Please sign in to comment.