use crate::{
location::*,
spec_language_ast::{Condition, Invariant, SyntheticDefinition},
};
use move_core_types::{
account_address::AccountAddress, identifier::Identifier, language_storage::ModuleId,
value::MoveValue,
};
use move_symbol_pool::Symbol;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::{
collections::{BTreeSet, HashSet, VecDeque},
fmt,
};
#[derive(Debug, Clone)]
pub struct Program {
pub modules: Vec<ModuleDefinition>,
pub script: Script,
}
#[derive(Debug, Clone)]
pub enum ScriptOrModule {
Script(Script),
Module(ModuleDefinition),
}
#[derive(Debug, Clone)]
pub struct Script {
pub loc: Loc,
pub imports: Vec<ImportDefinition>,
pub explicit_dependency_declarations: Vec<ModuleDependency>,
pub constants: Vec<Constant>,
pub main: Function,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ModuleName(pub Symbol);
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ModuleIdent {
pub name: ModuleName,
pub address: AccountAddress,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleDefinition {
pub loc: Loc,
pub identifier: ModuleIdent,
pub friends: Vec<ModuleIdent>,
pub imports: Vec<ImportDefinition>,
pub explicit_dependency_declarations: Vec<ModuleDependency>,
pub structs: Vec<StructDefinition>,
pub constants: Vec<Constant>,
pub functions: Vec<(FunctionName, Function)>,
pub synthetics: Vec<SyntheticDefinition>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleDependency {
pub name: ModuleName,
pub structs: Vec<StructDependency>,
pub functions: Vec<FunctionDependency>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ImportDefinition {
pub ident: ModuleIdent,
pub alias: ModuleName,
}
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
pub struct Var_(pub Symbol);
pub type Var = Spanned<Var_>;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct TypeVar_(pub Symbol);
pub type TypeVar = Spanned<TypeVar_>;
#[derive(Debug, Clone, Eq, Copy, Hash, Ord, PartialEq, PartialOrd)]
pub enum Ability {
Copy,
Drop,
Store,
Key,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Type {
Address,
Signer,
U8,
U64,
U128,
Bool,
Vector(Box<Type>),
Struct(QualifiedStructIdent, Vec<Type>),
Reference(bool, Box<Type>),
TypeParameter(TypeVar_),
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct QualifiedStructIdent {
pub module: ModuleName,
pub name: StructName,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct Field_(pub Symbol);
pub type Field = Spanned<Field_>;
#[derive(Clone, Debug, PartialEq)]
pub struct FieldIdent_ {
pub struct_name: StructName,
pub type_actuals: Vec<Type>,
pub field: Field,
}
pub type FieldIdent = Spanned<FieldIdent_>;
pub type Fields<T> = Vec<(Field, T)>;
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct StructName(pub Symbol);
pub type StructTypeParameter = (bool, TypeVar, BTreeSet<Ability>);
#[derive(Clone, Debug, PartialEq)]
pub struct StructDefinition_ {
pub abilities: BTreeSet<Ability>,
pub name: StructName,
pub type_formals: Vec<StructTypeParameter>,
pub fields: StructDefinitionFields,
pub invariants: Vec<Invariant>,
}
pub type StructDefinition = Spanned<StructDefinition_>;
#[derive(Clone, Debug, PartialEq)]
pub struct StructDependency {
pub abilities: BTreeSet<Ability>,
pub name: StructName,
pub type_formals: Vec<StructTypeParameter>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum StructDefinitionFields {
Move { fields: Fields<Type> },
Native,
}
#[derive(Debug, Serialize, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Clone)]
pub struct ConstantName(pub Symbol);
#[derive(Clone, Debug, PartialEq)]
pub struct Constant {
pub name: ConstantName,
pub signature: Type,
pub value: MoveValue,
}
#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Clone)]
pub struct FunctionName(pub Symbol);
#[derive(PartialEq, Debug, Clone)]
pub struct FunctionSignature {
pub formals: Vec<(Var, Type)>,
pub return_type: Vec<Type>,
pub type_formals: Vec<(TypeVar, BTreeSet<Ability>)>,
}
#[derive(PartialEq, Debug, Clone)]
pub struct FunctionDependency {
pub name: FunctionName,
pub signature: FunctionSignature,
}
#[derive(PartialEq, Debug, Clone)]
pub enum FunctionVisibility {
Public,
Friend,
Internal,
}
#[derive(PartialEq, Debug, Clone)]
pub enum FunctionBody {
Move {
locals: Vec<(Var, Type)>,
code: Vec<Block>,
},
Bytecode {
locals: Vec<(Var, Type)>,
code: BytecodeBlocks,
},
Native,
}
#[derive(PartialEq, Debug, Clone)]
pub struct Function_ {
pub visibility: FunctionVisibility,
pub is_entry: bool,
pub signature: FunctionSignature,
pub acquires: Vec<StructName>,
pub specifications: Vec<Condition>,
pub body: FunctionBody,
}
pub type Function = Spanned<Function_>;
#[derive(Debug, PartialEq, Clone)]
pub enum Builtin {
Exists(StructName, Vec<Type>),
BorrowGlobal(bool, StructName, Vec<Type>),
MoveFrom(StructName, Vec<Type>),
MoveTo(StructName, Vec<Type>),
VecPack(Vec<Type>, u64),
VecLen(Vec<Type>),
VecImmBorrow(Vec<Type>),
VecMutBorrow(Vec<Type>),
VecPushBack(Vec<Type>),
VecPopBack(Vec<Type>),
VecUnpack(Vec<Type>, u64),
VecSwap(Vec<Type>),
Freeze,
ToU8,
ToU64,
ToU128,
}
#[derive(Debug, PartialEq, Clone)]
pub enum FunctionCall_ {
Builtin(Builtin),
ModuleFunctionCall {
module: ModuleName,
name: FunctionName,
type_actuals: Vec<Type>,
},
}
pub type FunctionCall = Spanned<FunctionCall_>;
#[derive(Debug, Clone, PartialEq)]
pub enum LValue_ {
Var(Var),
Mutate(Exp),
Pop,
}
pub type LValue = Spanned<LValue_>;
#[derive(Debug, Clone, PartialEq)]
pub enum Statement_ {
Abort(Option<Box<Exp>>),
Assert(Box<Exp>, Box<Exp>),
Return(Box<Exp>),
Assign(Vec<LValue>, Exp),
Exp(Box<Exp>),
Jump(BlockLabel),
JumpIf(Box<Exp>, BlockLabel),
JumpIfFalse(Box<Exp>, BlockLabel),
Unpack(StructName, Vec<Type>, Fields<Var>, Box<Exp>),
}
pub type Statement = Spanned<Statement_>;
#[derive(Debug, PartialEq, Clone)]
pub struct Block_ {
pub label: BlockLabel,
pub statements: VecDeque<Statement>,
}
pub type Block = Spanned<Block_>;
#[derive(Debug, PartialEq, Clone)]
pub enum CopyableVal_ {
Address(AccountAddress),
U8(u8),
U64(u64),
U128(u128),
Bool(bool),
ByteArray(Vec<u8>),
}
pub type CopyableVal = Spanned<CopyableVal_>;
pub type ExpFields = Fields<Exp>;
#[derive(Debug, Clone, PartialEq)]
pub enum UnaryOp {
Not,
}
#[derive(Debug, Clone, PartialEq)]
pub enum BinOp {
Add,
Sub,
Mul,
Mod,
Div,
BitOr,
BitAnd,
Xor,
Shl,
Shr,
And,
Or,
Eq,
Neq,
Lt,
Gt,
Le,
Ge,
Subrange,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Exp_ {
Dereference(Box<Exp>),
UnaryExp(UnaryOp, Box<Exp>),
BinopExp(Box<Exp>, BinOp, Box<Exp>),
Value(CopyableVal),
Pack(StructName, Vec<Type>, ExpFields),
Borrow {
is_mutable: bool,
exp: Box<Exp>,
field: FieldIdent,
},
Move(Var),
Copy(Var),
BorrowLocal(bool, Var),
FunctionCall(FunctionCall, Box<Exp>),
ExprList(Vec<Exp>),
}
pub type Exp = Spanned<Exp_>;
pub type BytecodeBlocks = Vec<(BlockLabel_, BytecodeBlock)>;
pub type BytecodeBlock = Vec<Bytecode>;
#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct BlockLabel_(pub Symbol);
pub type BlockLabel = Spanned<BlockLabel_>;
#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct NopLabel(pub Symbol);
#[derive(Debug, Clone, PartialEq)]
pub enum Bytecode_ {
Pop,
Ret,
Nop(Option<NopLabel>),
BrTrue(BlockLabel_),
BrFalse(BlockLabel_),
Branch(BlockLabel_),
LdU8(u8),
LdU64(u64),
LdU128(u128),
CastU8,
CastU64,
CastU128,
LdTrue,
LdFalse,
LdConst(Type, MoveValue),
LdNamedConst(ConstantName),
CopyLoc(Var),
MoveLoc(Var),
StLoc(Var),
Call(ModuleName, FunctionName, Vec<Type>),
Pack(StructName, Vec<Type>),
Unpack(StructName, Vec<Type>),
ReadRef,
WriteRef,
FreezeRef,
MutBorrowLoc(Var),
ImmBorrowLoc(Var),
MutBorrowField(StructName, Vec<Type>, Field),
ImmBorrowField(StructName, Vec<Type>, Field),
MutBorrowGlobal(StructName, Vec<Type>),
ImmBorrowGlobal(StructName, Vec<Type>),
Add,
Sub,
Mul,
Mod,
Div,
BitOr,
BitAnd,
Xor,
Or,
And,
Not,
Eq,
Neq,
Lt,
Gt,
Le,
Ge,
Abort,
Exists(StructName, Vec<Type>),
MoveFrom(StructName, Vec<Type>),
MoveTo(StructName, Vec<Type>),
Shl,
Shr,
VecPack(Type, u64),
VecLen(Type),
VecImmBorrow(Type),
VecMutBorrow(Type),
VecPushBack(Type),
VecPopBack(Type),
VecUnpack(Type, u64),
VecSwap(Type),
}
pub type Bytecode = Spanned<Bytecode_>;
fn get_external_deps(imports: &[ImportDefinition]) -> Vec<ModuleId> {
let mut deps = HashSet::new();
for dep in imports.iter() {
let identifier = Identifier::new(dep.ident.name.0.as_str().to_owned()).unwrap();
deps.insert(ModuleId::new(dep.ident.address, identifier));
}
deps.into_iter().collect()
}
impl Program {
pub fn new(modules: Vec<ModuleDefinition>, script: Script) -> Self {
Program { modules, script }
}
}
impl Script {
pub fn new(
loc: Loc,
imports: Vec<ImportDefinition>,
explicit_dependency_declarations: Vec<ModuleDependency>,
constants: Vec<Constant>,
main: Function,
) -> Self {
Script {
loc,
imports,
explicit_dependency_declarations,
constants,
main,
}
}
pub fn body(&self) -> &[Block] {
match self.main.value.body {
FunctionBody::Move { ref code, .. } => code,
FunctionBody::Bytecode { .. } => panic!("Invalid body access on bytecode main()"),
FunctionBody::Native => panic!("main() cannot be native"),
}
}
pub fn get_external_deps(&self) -> Vec<ModuleId> {
get_external_deps(self.imports.as_slice())
}
}
static SELF_MODULE_NAME: Lazy<Symbol> = Lazy::new(|| Symbol::from("Self"));
impl ModuleName {
pub fn self_name() -> &'static str {
SELF_MODULE_NAME.as_str()
}
pub fn module_self() -> Self {
ModuleName(*SELF_MODULE_NAME)
}
}
impl ModuleIdent {
pub fn new(name: ModuleName, address: AccountAddress) -> Self {
ModuleIdent { name, address }
}
pub fn name(&self) -> &ModuleName {
&self.name
}
pub fn address(&self) -> &AccountAddress {
&self.address
}
}
impl ModuleDefinition {
pub fn new(
loc: Loc,
identifier: ModuleIdent,
friends: Vec<ModuleIdent>,
imports: Vec<ImportDefinition>,
explicit_dependency_declarations: Vec<ModuleDependency>,
structs: Vec<StructDefinition>,
constants: Vec<Constant>,
functions: Vec<(FunctionName, Function)>,
synthetics: Vec<SyntheticDefinition>,
) -> Self {
ModuleDefinition {
loc,
identifier,
friends,
imports,
explicit_dependency_declarations,
structs,
constants,
functions,
synthetics,
}
}
pub fn get_external_deps(&self) -> Vec<ModuleId> {
get_external_deps(self.imports.as_slice())
}
}
impl Ability {
pub const COPY: &'static str = "copy";
pub const DROP: &'static str = "drop";
pub const STORE: &'static str = "store";
pub const KEY: &'static str = "key";
}
impl Type {
pub fn r#struct(ident: QualifiedStructIdent, type_actuals: Vec<Type>) -> Type {
Type::Struct(ident, type_actuals)
}
pub fn reference(is_mutable: bool, t: Type) -> Type {
Type::Reference(is_mutable, Box::new(t))
}
pub fn address() -> Type {
Type::Address
}
pub fn u64() -> Type {
Type::U64
}
pub fn bool() -> Type {
Type::Bool
}
}
impl QualifiedStructIdent {
pub fn new(module: ModuleName, name: StructName) -> Self {
QualifiedStructIdent { module, name }
}
pub fn module(&self) -> &ModuleName {
&self.module
}
pub fn name(&self) -> &StructName {
&self.name
}
}
impl ImportDefinition {
pub fn new(ident: ModuleIdent, alias_opt: Option<ModuleName>) -> Self {
let alias = match alias_opt {
Some(alias) => alias,
None => *ident.name(),
};
ImportDefinition { ident, alias }
}
}
impl StructDefinition_ {
pub fn move_declared(
abilities: BTreeSet<Ability>,
name: Symbol,
type_formals: Vec<StructTypeParameter>,
fields: Fields<Type>,
invariants: Vec<Invariant>,
) -> Self {
StructDefinition_ {
abilities,
name: StructName(name),
type_formals,
fields: StructDefinitionFields::Move { fields },
invariants,
}
}
pub fn native(
abilities: BTreeSet<Ability>,
name: Symbol,
type_formals: Vec<StructTypeParameter>,
) -> Self {
StructDefinition_ {
abilities,
name: StructName(name),
type_formals,
fields: StructDefinitionFields::Native,
invariants: vec![],
}
}
}
impl FunctionSignature {
pub fn new(
formals: Vec<(Var, Type)>,
return_type: Vec<Type>,
type_parameters: Vec<(TypeVar, BTreeSet<Ability>)>,
) -> Self {
FunctionSignature {
formals,
return_type,
type_formals: type_parameters,
}
}
}
impl Function_ {
pub fn new(
visibility: FunctionVisibility,
is_entry: bool,
formals: Vec<(Var, Type)>,
return_type: Vec<Type>,
type_parameters: Vec<(TypeVar, BTreeSet<Ability>)>,
acquires: Vec<StructName>,
specifications: Vec<Condition>,
body: FunctionBody,
) -> Self {
let signature = FunctionSignature::new(formals, return_type, type_parameters);
Function_ {
visibility,
is_entry,
signature,
acquires,
specifications,
body,
}
}
}
impl FunctionCall_ {
pub fn module_call(module: ModuleName, name: FunctionName, type_actuals: Vec<Type>) -> Self {
FunctionCall_::ModuleFunctionCall {
module,
name,
type_actuals,
}
}
pub fn builtin(bif: Builtin) -> FunctionCall {
Spanned::unsafe_no_loc(FunctionCall_::Builtin(bif))
}
}
impl Statement_ {
pub fn return_empty() -> Self {
Statement_::Return(Box::new(Spanned::unsafe_no_loc(Exp_::ExprList(vec![]))))
}
pub fn return_(op: Exp) -> Self {
Statement_::Return(Box::new(op))
}
}
impl Block_ {
pub fn new(label: BlockLabel, statements: Vec<Statement>) -> Self {
Self {
label,
statements: VecDeque::from(statements),
}
}
}
impl Exp_ {
pub fn address(addr: AccountAddress) -> Exp {
Spanned::unsafe_no_loc(Exp_::Value(Spanned::unsafe_no_loc(CopyableVal_::Address(
addr,
))))
}
pub fn value(b: CopyableVal_) -> Exp {
Spanned::unsafe_no_loc(Exp_::Value(Spanned::unsafe_no_loc(b)))
}
pub fn u64(i: u64) -> Exp {
Exp_::value(CopyableVal_::U64(i))
}
pub fn bool(b: bool) -> Exp {
Exp_::value(CopyableVal_::Bool(b))
}
pub fn byte_array(buf: Vec<u8>) -> Exp {
Exp_::value(CopyableVal_::ByteArray(buf))
}
pub fn instantiate(n: StructName, tys: Vec<Type>, s: ExpFields) -> Exp {
Spanned::unsafe_no_loc(Exp_::Pack(n, tys, s))
}
pub fn binop(lhs: Exp, op: BinOp, rhs: Exp) -> Exp {
Spanned::unsafe_no_loc(Exp_::BinopExp(Box::new(lhs), op, Box::new(rhs)))
}
pub fn add(lhs: Exp, rhs: Exp) -> Exp {
Exp_::binop(lhs, BinOp::Add, rhs)
}
pub fn sub(lhs: Exp, rhs: Exp) -> Exp {
Exp_::binop(lhs, BinOp::Sub, rhs)
}
pub fn dereference(e: Exp) -> Exp {
Spanned::unsafe_no_loc(Exp_::Dereference(Box::new(e)))
}
pub fn borrow(is_mutable: bool, exp: Box<Exp>, field: FieldIdent) -> Exp {
Spanned::unsafe_no_loc(Exp_::Borrow {
is_mutable,
exp,
field,
})
}
pub fn copy(v: Var) -> Exp {
Spanned::unsafe_no_loc(Exp_::Copy(v))
}
pub fn move_(v: Var) -> Exp {
Spanned::unsafe_no_loc(Exp_::Move(v))
}
pub fn function_call(f: FunctionCall, e: Exp) -> Exp {
Spanned::unsafe_no_loc(Exp_::FunctionCall(f, Box::new(e)))
}
pub fn expr_list(exps: Vec<Exp>) -> Exp {
Spanned::unsafe_no_loc(Exp_::ExprList(exps))
}
}
impl PartialEq for Script {
fn eq(&self, other: &Script) -> bool {
self.imports == other.imports && self.main.value.body == other.main.value.body
}
}
impl Iterator for Block_ {
type Item = Statement;
fn next(&mut self) -> Option<Statement> {
self.statements.pop_front()
}
}
impl fmt::Display for TypeVar_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for Ability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Ability::Copy => Ability::COPY,
Ability::Drop => Ability::DROP,
Ability::Store => Ability::STORE,
Ability::Key => Ability::KEY,
}
)
}
}
fn format_constraints(set: &BTreeSet<Ability>) -> String {
set.iter()
.map(|a| format!("{}", a))
.collect::<Vec<_>>()
.join(" + ")
}
impl fmt::Display for ScriptOrModule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ScriptOrModule::*;
match self {
Module(module_def) => write!(f, "{}", module_def),
Script(script) => write!(f, "{}", script),
}
}
}
impl fmt::Display for Script {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Script(")?;
write!(f, "Imports(")?;
write!(f, "{}", intersperse(&self.imports, ", "))?;
writeln!(f, ")")?;
writeln!(f, "Dependency(")?;
for dependency in &self.explicit_dependency_declarations {
writeln!(f, "{},", dependency)?;
}
writeln!(f, ")")?;
writeln!(f, "Constants(")?;
for constant in &self.constants {
writeln!(f, "{};", constant)?;
}
writeln!(f, ")")?;
write!(f, "Main(")?;
write!(f, "{}", self.main)?;
write!(f, ")")?;
write!(f, ")")
}
}
impl fmt::Display for ModuleName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for ModuleIdent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}.{}", self.address, self.name)
}
}
impl fmt::Display for ModuleDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Module({}, ", self.identifier)?;
writeln!(f, "Imports(")?;
for import in &self.imports {
writeln!(f, "{};", import)?;
}
writeln!(f, ")")?;
writeln!(f, "Dependency(")?;
for dependency in &self.explicit_dependency_declarations {
writeln!(f, "{},", dependency)?;
}
writeln!(f, ")")?;
writeln!(f, "Structs(")?;
for struct_def in &self.structs {
writeln!(f, "{}, ", struct_def)?;
}
writeln!(f, ")")?;
writeln!(f, "Constants(")?;
for constant in &self.constants {
writeln!(f, "{};", constant)?;
}
writeln!(f, ")")?;
writeln!(f, "Functions(")?;
for (fun_name, fun) in &self.functions {
writeln!(f, "({}, {}), ", fun_name, fun)?;
}
writeln!(f, ")")?;
writeln!(f, ")")
}
}
impl fmt::Display for ImportDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "import {} as {}", &self.ident, &self.alias)
}
}
impl fmt::Display for ModuleDependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Dependency({}, ", &self.name)?;
for sdep in &self.structs {
writeln!(f, "{}, ", sdep)?
}
for fdep in &self.functions {
writeln!(f, "{}, ", fdep)?
}
writeln!(f, ")")
}
}
impl fmt::Display for StructDependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"StructDep({} {}{}",
self.abilities
.iter()
.map(|a| format!("{}", a))
.collect::<Vec<_>>()
.join(" "),
&self.name,
format_struct_type_formals(&self.type_formals)
)
}
}
impl fmt::Display for FunctionDependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FunctionDep({}{}", &self.name, &self.signature)
}
}
impl fmt::Display for StructDefinition_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
"Struct({}{}, ",
self.name,
format_struct_type_formals(&self.type_formals)
)?;
match &self.fields {
StructDefinitionFields::Move { fields } => writeln!(f, "{}", format_fields(fields))?,
StructDefinitionFields::Native => writeln!(f, "{{native}}")?,
}
write!(f, ")")
}
}
impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"const {}: {} = {}",
&self.name.0,
self.signature,
format_move_value(&self.value)
)
}
}
impl fmt::Display for Function_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} ({})", self.signature, self.body)
}
}
impl fmt::Display for Field_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for FieldIdent_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}::{}", self.struct_name, self.field)
}
}
impl fmt::Display for StructName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for FunctionName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for BlockLabel_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for ConstantName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for FunctionBody {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FunctionBody::Move {
ref locals,
ref code,
} => {
for (local, ty) in locals {
write!(f, "let {}: {};", local, ty)?;
}
for block in code {
writeln!(f, "{}", block.value)?;
}
Ok(())
}
FunctionBody::Bytecode { locals, code } => {
write!(f, "locals: [")?;
for (local, ty) in locals {
write!(f, "{}: {},", local, ty)?;
}
writeln!(f, "]")?;
for (label, block) in code {
writeln!(f, "{}:", &label)?;
for instr in block {
writeln!(f, " {}", instr)?;
}
}
Ok(())
}
FunctionBody::Native => write!(f, "native"),
}
}
}
fn intersperse<T: fmt::Display>(items: &[T], join: &str) -> String {
items.iter().fold(String::new(), |acc, v| {
format!("{acc}{join}{v}", acc = acc, join = join, v = v)
})
}
fn format_fields<T: fmt::Display>(fields: &[(Field, T)]) -> String {
fields.iter().fold(String::new(), |acc, (field, val)| {
format!("{} {}: {},", acc, field.value, val)
})
}
impl fmt::Display for FunctionSignature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", format_fun_type_formals(&self.type_formals))?;
write!(f, "(")?;
for (v, ty) in self.formals.iter() {
write!(f, "{}: {}, ", v, ty)?;
}
write!(f, ")")?;
Ok(())
}
}
impl fmt::Display for QualifiedStructIdent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.module, self.name)
}
}
fn format_type_actuals(tys: &[Type]) -> String {
if tys.is_empty() {
"".to_string()
} else {
format!("<{}>", intersperse(tys, ", "))
}
}
fn format_fun_type_formals(formals: &[(TypeVar, BTreeSet<Ability>)]) -> String {
if formals.is_empty() {
"".to_string()
} else {
let formatted = formals
.iter()
.map(|(tv, abilities)| format!("{}: {}", tv.value, format_constraints(abilities)))
.collect::<Vec<_>>();
format!("<{}>", intersperse(&formatted, ", "))
}
}
fn format_struct_type_formals(formals: &[StructTypeParameter]) -> String {
if formals.is_empty() {
"".to_string()
} else {
let formatted = formals
.iter()
.map(|(is_phantom, tv, abilities)| {
format!(
"{}{}: {}",
if *is_phantom { "phantom " } else { "" },
tv.value,
format_constraints(abilities)
)
})
.collect::<Vec<_>>();
format!("<{}>", intersperse(&formatted, ", "))
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::U8 => write!(f, "u8"),
Type::U64 => write!(f, "u64"),
Type::U128 => write!(f, "u128"),
Type::Bool => write!(f, "bool"),
Type::Address => write!(f, "address"),
Type::Signer => write!(f, "signer"),
Type::Vector(ty) => write!(f, "vector<{}>", ty),
Type::Struct(ident, tys) => write!(f, "{}{}", ident, format_type_actuals(tys)),
Type::Reference(is_mutable, t) => {
write!(f, "&{}{}", if *is_mutable { "mut " } else { "" }, t)
}
Type::TypeParameter(s) => write!(f, "{}", s),
}
}
}
impl fmt::Display for Var_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for Builtin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Builtin::Exists(t, tys) => write!(f, "exists<{}{}>", t, format_type_actuals(tys)),
Builtin::BorrowGlobal(mut_, t, tys) => {
let mut_flag = if *mut_ { "_mut" } else { "" };
write!(
f,
"borrow_global{}<{}{}>",
mut_flag,
t,
format_type_actuals(tys)
)
}
Builtin::MoveFrom(t, tys) => write!(f, "move_from<{}{}>", t, format_type_actuals(tys)),
Builtin::MoveTo(t, tys) => write!(f, "move_to<{}{}>", t, format_type_actuals(tys)),
Builtin::VecPack(tys, num) => write!(f, "vec_pack_{}{}", num, format_type_actuals(tys)),
Builtin::VecLen(tys) => write!(f, "vec_len{}", format_type_actuals(tys)),
Builtin::VecImmBorrow(tys) => write!(f, "vec_imm_borrow{}", format_type_actuals(tys)),
Builtin::VecMutBorrow(tys) => write!(f, "vec_mut_borrow{}", format_type_actuals(tys)),
Builtin::VecPushBack(tys) => write!(f, "vec_push_back{}", format_type_actuals(tys)),
Builtin::VecPopBack(tys) => write!(f, "vec_pop_back{}", format_type_actuals(tys)),
Builtin::VecUnpack(tys, num) => {
write!(f, "vec_unpack_{}{}", num, format_type_actuals(tys))
}
Builtin::VecSwap(tys) => write!(f, "vec_swap{}", format_type_actuals(tys)),
Builtin::Freeze => write!(f, "freeze"),
Builtin::ToU8 => write!(f, "to_u8"),
Builtin::ToU64 => write!(f, "to_u64"),
Builtin::ToU128 => write!(f, "to_u128"),
}
}
}
impl fmt::Display for FunctionCall_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FunctionCall_::Builtin(fun) => write!(f, "{}", fun),
FunctionCall_::ModuleFunctionCall {
module,
name,
type_actuals,
} => write!(
f,
"{}.{}{}",
module,
name,
format_type_actuals(type_actuals)
),
}
}
}
impl fmt::Display for LValue_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LValue_::Var(x) => write!(f, "{}", x),
LValue_::Mutate(e) => write!(f, "*{}", e),
LValue_::Pop => write!(f, "_"),
}
}
}
impl fmt::Display for Statement_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Statement_::Abort(None) => write!(f, "abort;"),
Statement_::Abort(Some(err)) => write!(f, "abort {};", err),
Statement_::Assert(cond, err) => write!(f, "assert({}, {});", cond, err),
Statement_::Assign(var_list, e) => {
if var_list.is_empty() {
write!(f, "{};", e)
} else {
write!(f, "{} = ({});", intersperse(var_list, ", "), e)
}
}
Statement_::Exp(e) => write!(f, "({});", e),
Statement_::Jump(label) => write!(f, "jump {}", label),
Statement_::JumpIf(e, label) => write!(f, "jump_if ({}) {}", e, label),
Statement_::JumpIfFalse(e, label) => write!(f, "jump_if_false ({}) {}", e, label),
Statement_::Return(exps) => write!(f, "return {};", exps),
Statement_::Unpack(n, tys, bindings, e) => write!(
f,
"{}{} {{ {} }} = {}",
n,
format_type_actuals(tys),
bindings
.iter()
.fold(String::new(), |acc, (field, var)| format!(
"{} {} : {},",
acc, field, var
)),
e
),
}
}
}
impl fmt::Display for Block_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "label {}:", self.label)?;
for statement in self.statements.iter() {
writeln!(f, " {}", statement)?;
}
Ok(())
}
}
impl fmt::Display for CopyableVal_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CopyableVal_::U8(v) => write!(f, "{}u8", v),
CopyableVal_::U64(v) => write!(f, "{}", v),
CopyableVal_::U128(v) => write!(f, "{}u128", v),
CopyableVal_::Bool(v) => write!(f, "{}", v),
CopyableVal_::ByteArray(v) => write!(f, "0b{}", hex::encode(v)),
CopyableVal_::Address(v) => write!(f, "0x{}", hex::encode(v)),
}
}
}
impl fmt::Display for UnaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
UnaryOp::Not => "!",
}
)
}
}
impl fmt::Display for BinOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
BinOp::Add => "+",
BinOp::Sub => "-",
BinOp::Mul => "*",
BinOp::Mod => "%",
BinOp::Div => "/",
BinOp::BitOr => "|",
BinOp::BitAnd => "&",
BinOp::Xor => "^",
BinOp::Shl => "<<",
BinOp::Shr => ">>",
BinOp::Or => "||",
BinOp::And => "&&",
BinOp::Eq => "==",
BinOp::Neq => "!=",
BinOp::Lt => "<",
BinOp::Gt => ">",
BinOp::Le => "<=",
BinOp::Ge => ">=",
BinOp::Subrange => "..",
}
)
}
}
impl fmt::Display for Exp_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Exp_::Dereference(e) => write!(f, "*({})", e),
Exp_::UnaryExp(o, e) => write!(f, "({}{})", o, e),
Exp_::BinopExp(e1, o, e2) => write!(f, "({} {} {})", o, e1, e2),
Exp_::Value(v) => write!(f, "{}", v),
Exp_::Pack(n, tys, s) => write!(
f,
"{}{}{{{}}}",
n,
format_type_actuals(tys),
s.iter().fold(String::new(), |acc, (field, op)| format!(
"{} {} : {},",
acc, field, op,
))
),
Exp_::Borrow {
is_mutable,
exp,
field,
} => write!(
f,
"&{}{}.{}",
if *is_mutable { "mut " } else { "" },
exp,
field
),
Exp_::Move(v) => write!(f, "move({})", v),
Exp_::Copy(v) => write!(f, "copy({})", v),
Exp_::BorrowLocal(is_mutable, v) => {
write!(f, "&{}{}", if *is_mutable { "mut " } else { "" }, v)
}
Exp_::FunctionCall(func, e) => write!(f, "{}({})", func, e),
Exp_::ExprList(exps) => {
if exps.is_empty() {
write!(f, "()")
} else {
write!(f, "({})", intersperse(exps, ", "))
}
}
}
}
}
impl fmt::Display for Bytecode_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Bytecode_::Pop => write!(f, "Pop"),
Bytecode_::Ret => write!(f, "Ret"),
Bytecode_::Nop(None) => write!(f, "Nop"),
Bytecode_::Nop(Some(s)) => write!(f, "Nop {}", &s.0),
Bytecode_::BrTrue(lbl) => write!(f, "BrTrue {}", &lbl.0),
Bytecode_::BrFalse(lbl) => write!(f, "BrFalse {}", &lbl.0),
Bytecode_::Branch(lbl) => write!(f, "Branch {}", &lbl.0),
Bytecode_::LdU8(u) => write!(f, "LdU8 {}", u),
Bytecode_::LdU64(u) => write!(f, "LdU64 {}", u),
Bytecode_::LdU128(u) => write!(f, "LdU128 {}", u),
Bytecode_::CastU8 => write!(f, "CastU8"),
Bytecode_::CastU64 => write!(f, "CastU64"),
Bytecode_::CastU128 => write!(f, "CastU128"),
Bytecode_::LdTrue => write!(f, "LdTrue"),
Bytecode_::LdFalse => write!(f, "LdFalse"),
Bytecode_::LdConst(ty, v) => write!(f, "LdConst<{}> {}", ty, format_move_value(v)),
Bytecode_::LdNamedConst(n) => write!(f, "LdNamedConst {}", &n.0),
Bytecode_::CopyLoc(v) => write!(f, "CopyLoc {}", v),
Bytecode_::MoveLoc(v) => write!(f, "MoveLoc {}", v),
Bytecode_::StLoc(v) => write!(f, "StLoc {}", v),
Bytecode_::Call(m, n, tys) => write!(f, "Call {}.{}{}", m, n, format_type_actuals(tys)),
Bytecode_::Pack(n, tys) => write!(f, "Pack {}{}", n, format_type_actuals(tys)),
Bytecode_::Unpack(n, tys) => write!(f, "Unpack {}{}", n, format_type_actuals(tys)),
Bytecode_::ReadRef => write!(f, "ReadRef"),
Bytecode_::WriteRef => write!(f, "WriteRef"),
Bytecode_::FreezeRef => write!(f, "FreezeRef"),
Bytecode_::MutBorrowLoc(v) => write!(f, "MutBorrowLoc {}", v),
Bytecode_::ImmBorrowLoc(v) => write!(f, "ImmBorrowLoc {}", v),
Bytecode_::MutBorrowField(n, tys, field) => write!(
f,
"MutBorrowField {}{}.{}",
n,
format_type_actuals(tys),
field
),
Bytecode_::ImmBorrowField(n, tys, field) => write!(
f,
"ImmBorrowField {}{}.{}",
n,
format_type_actuals(tys),
field
),
Bytecode_::MutBorrowGlobal(n, tys) => {
write!(f, "MutBorrowGlobal {}{}", n, format_type_actuals(tys))
}
Bytecode_::ImmBorrowGlobal(n, tys) => {
write!(f, "ImmBorrowGlobal {}{}", n, format_type_actuals(tys))
}
Bytecode_::Add => write!(f, "Add"),
Bytecode_::Sub => write!(f, "Sub"),
Bytecode_::Mul => write!(f, "Mul"),
Bytecode_::Mod => write!(f, "Mod"),
Bytecode_::Div => write!(f, "Div"),
Bytecode_::BitOr => write!(f, "BitOr"),
Bytecode_::BitAnd => write!(f, "BitAnd"),
Bytecode_::Xor => write!(f, "Xor"),
Bytecode_::Or => write!(f, "Or"),
Bytecode_::And => write!(f, "And"),
Bytecode_::Not => write!(f, "Not"),
Bytecode_::Eq => write!(f, "Eq"),
Bytecode_::Neq => write!(f, "Neq"),
Bytecode_::Lt => write!(f, "Lt"),
Bytecode_::Gt => write!(f, "Gt"),
Bytecode_::Le => write!(f, "Le"),
Bytecode_::Ge => write!(f, "Ge"),
Bytecode_::Abort => write!(f, "Abort"),
Bytecode_::Exists(n, tys) => write!(f, "Exists {}{}", n, format_type_actuals(tys)),
Bytecode_::MoveFrom(n, tys) => write!(f, "MoveFrom {}{}", n, format_type_actuals(tys)),
Bytecode_::MoveTo(n, tys) => write!(f, "MoveTo {}{}", n, format_type_actuals(tys)),
Bytecode_::Shl => write!(f, "Shl"),
Bytecode_::Shr => write!(f, "Shr"),
Bytecode_::VecPack(ty, n) => write!(f, "VecPack {} {}", ty, n),
Bytecode_::VecLen(ty) => write!(f, "VecLen {}", ty),
Bytecode_::VecImmBorrow(ty) => write!(f, "VecImmBorrow {}", ty),
Bytecode_::VecMutBorrow(ty) => write!(f, "VecMutBorrow {}", ty),
Bytecode_::VecPushBack(ty) => write!(f, "VecPushBack {}", ty),
Bytecode_::VecPopBack(ty) => write!(f, "VecPopBack {}", ty),
Bytecode_::VecUnpack(ty, n) => write!(f, "VecUnpack {} {}", ty, n),
Bytecode_::VecSwap(ty) => write!(f, "VecSwap {}", ty),
}
}
}
fn format_move_value(v: &MoveValue) -> String {
match v {
MoveValue::U8(u) => format!("{}u8", u),
MoveValue::U64(u) => format!("{}u64", u),
MoveValue::U128(u) => format!("{}u128", u),
MoveValue::Bool(true) => "true".to_owned(),
MoveValue::Bool(false) => "false".to_owned(),
MoveValue::Address(a) => format!("0x{}", a.short_str_lossless()),
MoveValue::Vector(v) => {
let items = v
.iter()
.map(format_move_value)
.collect::<Vec<_>>()
.join(", ");
format!("vector[{}]", items)
}
MoveValue::Struct(_) | MoveValue::Signer(_) => {
panic!("Should be inexpressible as a constant")
}
}
}