use codespan::{ByteIndex, Span};
use std::{
collections::{BTreeMap, VecDeque},
fmt,
ops::Deref,
};
use types::{account_address::AccountAddress, byte_array::ByteArray};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
pub struct Spanned<T> {
pub span: Loc,
pub value: T,
}
pub type Loc = Span<ByteIndex>;
#[derive(Debug, Clone)]
pub struct Program {
pub modules: Vec<ModuleDefinition>,
pub script: Script,
}
#[derive(Debug, Clone)]
pub struct Script {
pub imports: Vec<ImportDefinition>,
pub main: Function,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ModuleName(String);
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct QualifiedModuleIdent {
pub name: ModuleName,
pub address: AccountAddress,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleDefinition {
pub name: ModuleName,
pub imports: Vec<ImportDefinition>,
pub structs: Vec<StructDefinition>,
pub functions: Vec<(FunctionName, Function)>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum ModuleIdent {
Transaction(ModuleName),
Qualified(QualifiedModuleIdent),
}
#[derive(Clone, Debug, PartialEq)]
pub struct ImportDefinition {
pub ident: ModuleIdent,
pub alias: ModuleName,
}
pub type Field = types::access_path::Field;
pub type Fields<T> = BTreeMap<Field, T>;
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct StructName(String);
#[derive(Clone, Debug, PartialEq)]
pub struct StructDefinition {
pub resource_kind: bool,
pub name: StructName,
pub fields: Fields<Type>,
}
#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Clone)]
pub struct FunctionName(String);
#[derive(PartialEq, Debug, Clone)]
pub struct FunctionSignature {
pub formals: Vec<(Var, Type)>,
pub return_type: Vec<Type>,
}
#[derive(PartialEq, Debug, Clone)]
pub enum FunctionVisibility {
Public,
Internal,
}
#[derive(PartialEq, Debug, Clone)]
pub enum FunctionAnnotation {
Requires(String),
Ensures(String),
}
#[derive(PartialEq, Debug, Clone)]
pub enum FunctionBody {
Move {
locals: Vec<(Var_, Type)>,
code: Block,
},
Native,
}
#[derive(PartialEq, Debug, Clone)]
pub struct Function {
pub visibility: FunctionVisibility,
pub signature: FunctionSignature,
pub annotations: Vec<FunctionAnnotation>,
pub body: FunctionBody,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Kind {
Resource,
Value,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct StructType {
pub module: ModuleName,
pub name: StructName,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Tag {
Address,
U64,
Bool,
ByteArray,
String,
Struct(StructType),
}
#[derive(Debug, PartialEq, Clone)]
pub enum Type {
Normal(Kind, Tag),
Reference {
is_mutable: bool,
kind: Kind,
tag: Tag,
},
}
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
pub struct Var(String);
pub type Var_ = Spanned<Var>;
#[derive(Debug, PartialEq, Clone)]
pub enum Builtin {
Release,
Exists(StructName),
BorrowGlobal(StructName),
GetHeight,
GetTxnGasUnitPrice,
GetTxnMaxGasUnits,
GetTxnPublicKey,
GetTxnSender,
GetTxnSequenceNumber,
GetGasRemaining,
EmitEvent,
CreateAccount,
MoveFrom(StructName),
MoveToSender(StructName),
Freeze,
}
#[derive(Debug, PartialEq, Clone)]
pub enum FunctionCall {
Builtin(Builtin),
ModuleFunctionCall {
module: ModuleName,
name: FunctionName,
},
}
pub type FunctionCall_ = Spanned<FunctionCall>;
#[derive(Debug, Clone, PartialEq)]
pub enum Cmd {
Assign(Vec<Var_>, Exp_),
Unpack(StructName, Fields<Var_>, Exp_),
Mutate(Exp_, Exp_),
Abort(Option<Exp_>),
Return(Exp_),
Break,
Continue,
Exp(Exp_),
}
pub type Cmd_ = Spanned<Cmd>;
#[derive(Debug, PartialEq, Clone)]
pub struct IfElse {
pub cond: Exp_,
pub if_block: Block,
pub else_block: Option<Block>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct While {
pub cond: Exp_,
pub block: Block,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Loop {
pub block: Block,
}
#[derive(Debug, PartialEq, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum Statement {
CommandStatement(Cmd_),
IfElseStatement(IfElse),
WhileStatement(While),
LoopStatement(Loop),
VerifyStatement(String),
AssumeStatement(String),
EmptyStatement,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Block {
pub stmts: VecDeque<Statement>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum CopyableVal {
Address(AccountAddress),
U64(u64),
Bool(bool),
ByteArray(ByteArray),
String(String),
}
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,
And,
Or,
Eq,
Neq,
Lt,
Gt,
Le,
Ge,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Exp {
Dereference(Box<Exp_>),
UnaryExp(UnaryOp, Box<Exp_>),
BinopExp(Box<Exp_>, BinOp, Box<Exp_>),
Value(CopyableVal_),
Pack(StructName, ExpFields),
Borrow {
is_mutable: bool,
exp: Box<Exp_>,
field: Field,
},
Move(Var_),
Copy(Var_),
BorrowLocal(bool, Var_),
FunctionCall(FunctionCall, Box<Exp_>),
ExprList(Vec<Exp_>),
}
pub type Exp_ = Spanned<Exp>;
impl Program {
pub fn new(modules: Vec<ModuleDefinition>, script: Script) -> Self {
Program { modules, script }
}
}
impl Script {
pub fn new(imports: Vec<ImportDefinition>, main: Function) -> Self {
Script { imports, main }
}
pub fn body(&self) -> &Block {
match self.main.body {
FunctionBody::Move { ref code, .. } => &code,
FunctionBody::Native => panic!("main() can't be native"),
}
}
}
impl ModuleName {
pub fn new(name: String) -> Self {
assert!(name != "");
ModuleName(name)
}
pub const SELF: &'static str = "Self";
pub fn module_self() -> Self {
ModuleName::new(ModuleName::SELF.to_string())
}
pub fn as_bytes(&self) -> Vec<u8> {
self.0.as_bytes().to_vec()
}
pub fn name(&self) -> String {
self.0.clone()
}
pub fn name_ref(&self) -> &String {
&self.0
}
}
impl QualifiedModuleIdent {
pub fn new(name: ModuleName, address: AccountAddress) -> Self {
QualifiedModuleIdent { address, name }
}
pub fn get_name(&self) -> &ModuleName {
&self.name
}
pub fn get_address(&self) -> &AccountAddress {
&self.address
}
}
impl ModuleIdent {
pub fn get_name(&self) -> &ModuleName {
match self {
ModuleIdent::Transaction(name) => &name,
ModuleIdent::Qualified(id) => &id.name,
}
}
}
impl ModuleDefinition {
pub fn new(
name: String,
imports: Vec<ImportDefinition>,
structs: Vec<StructDefinition>,
functions: Vec<(FunctionName, Function)>,
) -> Self {
ModuleDefinition {
name: ModuleName::new(name),
imports,
structs,
functions,
}
}
}
impl Type {
pub fn nonreference(kind: Kind, tag: Tag) -> Type {
Type::Normal(kind, tag)
}
pub fn reference(is_mutable: bool, annot: Type) -> Type {
match annot {
Type::Normal(kind, tag) => Type::Reference {
is_mutable,
kind,
tag,
},
_ => panic!("ICE expected Normal annotation"),
}
}
pub fn address() -> Type {
Type::Normal(Kind::Value, Tag::Address)
}
pub fn u64() -> Type {
Type::Normal(Kind::Value, Tag::U64)
}
pub fn bool() -> Type {
Type::Normal(Kind::Value, Tag::Bool)
}
pub fn bytearray() -> Type {
Type::Normal(Kind::Value, Tag::ByteArray)
}
}
impl StructType {
pub fn new(module: ModuleName, name: StructName) -> Self {
StructType { 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.get_name().clone(),
};
ImportDefinition { ident, alias }
}
}
impl StructName {
pub fn new(name: String) -> Self {
StructName(name)
}
pub fn as_bytes(&self) -> Vec<u8> {
self.0.as_bytes().to_vec()
}
pub fn name(&self) -> String {
self.0.clone()
}
pub fn name_ref(&self) -> &String {
&self.0
}
}
impl StructDefinition {
pub fn new(resource_kind: bool, name: String, fields: Fields<Type>) -> Self {
StructDefinition {
resource_kind,
name: StructName::new(name),
fields,
}
}
}
impl FunctionName {
pub fn new(name: String) -> Self {
FunctionName(name)
}
pub fn name(&self) -> String {
self.0.clone()
}
pub fn name_ref(&self) -> &String {
&self.0
}
}
impl FunctionSignature {
pub fn new(formals: Vec<(Var, Type)>, return_type: Vec<Type>) -> Self {
FunctionSignature {
formals,
return_type,
}
}
}
impl Function {
pub fn new(
visibility: FunctionVisibility,
formals: Vec<(Var, Type)>,
return_type: Vec<Type>,
annotations: Vec<FunctionAnnotation>,
body: FunctionBody,
) -> Self {
let signature = FunctionSignature::new(formals, return_type);
Function {
visibility,
signature,
annotations,
body,
}
}
}
impl Var {
pub fn new(s: &str) -> Self {
Var(s.to_string())
}
pub fn new_(s: &str) -> Var_ {
Spanned::no_loc(Var::new(s))
}
pub fn name(&self) -> &str {
&self.0
}
}
impl FunctionCall {
pub fn module_call(module: ModuleName, name: FunctionName) -> Self {
FunctionCall::ModuleFunctionCall { module, name }
}
pub fn builtin(bif: Builtin) -> FunctionCall_ {
Spanned::no_loc(FunctionCall::Builtin(bif))
}
}
impl Cmd {
pub fn return_empty() -> Self {
Cmd::Return(Spanned::no_loc(Exp::ExprList(vec![])))
}
pub fn return_(op: Exp_) -> Self {
Cmd::Return(op)
}
}
impl IfElse {
pub fn if_block(cond: Exp_, if_block: Block) -> Self {
IfElse {
cond,
if_block,
else_block: None,
}
}
pub fn if_else(cond: Exp_, if_block: Block, else_block: Block) -> Self {
IfElse {
cond,
if_block,
else_block: Some(else_block),
}
}
}
impl Statement {
pub fn cmd(c: Cmd_) -> Self {
Statement::CommandStatement(c)
}
pub fn if_block(cond: Exp_, if_block: Block) -> Self {
Statement::IfElseStatement(IfElse::if_block(cond, if_block))
}
pub fn if_else(cond: Exp_, if_block: Block, else_block: Block) -> Self {
Statement::IfElseStatement(IfElse::if_else(cond, if_block, else_block))
}
}
impl Block {
pub fn new(stmts: Vec<Statement>) -> Self {
Block {
stmts: VecDeque::from(stmts),
}
}
pub fn empty() -> Self {
Block {
stmts: VecDeque::new(),
}
}
}
impl Exp {
pub fn address(addr: AccountAddress) -> Exp_ {
Spanned::no_loc(Exp::Value(Spanned::no_loc(CopyableVal::Address(addr))))
}
pub fn value(b: CopyableVal) -> Exp_ {
Spanned::no_loc(Exp::Value(Spanned::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: ByteArray) -> Exp_ {
Exp::value(CopyableVal::ByteArray(buf))
}
pub fn instantiate(n: StructName, s: ExpFields) -> Exp_ {
Spanned::no_loc(Exp::Pack(n, s))
}
pub fn binop(lhs: Exp_, op: BinOp, rhs: Exp_) -> Exp_ {
Spanned::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::no_loc(Exp::Dereference(Box::new(e)))
}
pub fn borrow(is_mutable: bool, exp: Box<Exp_>, field: Field) -> Exp_ {
Spanned::no_loc(Exp::Borrow {
is_mutable,
exp,
field,
})
}
pub fn copy(v: Var_) -> Exp_ {
Spanned::no_loc(Exp::Copy(v))
}
pub fn move_(v: Var_) -> Exp_ {
Spanned::no_loc(Exp::Move(v))
}
pub fn function_call(f: FunctionCall, e: Exp_) -> Exp_ {
Spanned::no_loc(Exp::FunctionCall(f, Box::new(e)))
}
pub fn expr_list(exps: Vec<Exp_>) -> Exp_ {
Spanned::no_loc(Exp::ExprList(exps))
}
}
impl Iterator for Script {
type Item = Statement;
fn next(&mut self) -> Option<Statement> {
match self.main.body {
FunctionBody::Move { ref mut code, .. } => code.stmts.pop_front(),
FunctionBody::Native => panic!("main() cannot be native code"),
}
}
}
impl PartialEq for Script {
fn eq(&self, other: &Script) -> bool {
self.imports == other.imports && self.main.body == other.main.body
}
}
impl<T> Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
impl<T> AsRef<T> for Spanned<T> {
fn as_ref(&self) -> &T {
&self.value
}
}
impl<T> Spanned<T> {
pub fn no_loc(value: T) -> Spanned<T> {
Spanned {
value,
span: Span::default(),
}
}
}
impl Iterator for Block {
type Item = Statement;
fn next(&mut self) -> Option<Statement> {
self.stmts.pop_front()
}
}
impl Into<Field> for CopyableVal {
fn into(self) -> Field {
Field::new(self.to_string().as_ref())
}
}
impl<T> fmt::Display for Spanned<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value)
}
}
impl fmt::Display for ModuleName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for QualifiedModuleIdent {
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.name.name())?;
write!(f, "Structs(")?;
for struct_def in &self.structs {
write!(f, "{}, ", struct_def)?;
}
write!(f, "Functions(")?;
for (fun_name, fun) in &self.functions {
write!(f, "({}, {}), ", fun_name, fun)?;
}
write!(f, ")")
}
}
impl fmt::Display for StructDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Struct({}, ", self.name)?;
writeln!(f, "{}", format_fields(&self.fields))?;
write!(f, ")")
}
}
impl fmt::Display for Function {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} ({})", self.signature, self.body)
}
}
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 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)?;
}
writeln!(f, "{}", code)
}
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: &Fields<T>) -> String {
fields.iter().fold(String::new(), |acc, (field, val)| {
format!("{} {}: {},", acc, field, val)
})
}
impl fmt::Display for FunctionSignature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(")?;
for (v, ty) in self.formals.iter() {
write!(f, "{}: {}, ", v, ty)?;
}
write!(f, ")")?;
Ok(())
}
}
impl fmt::Display for Kind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Kind::Resource => write!(f, "R"),
Kind::Value => write!(f, "V"),
}
}
}
impl fmt::Display for StructType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.module, self.name.name())
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Tag::U64 => write!(f, "u64"),
Tag::Bool => write!(f, "bool"),
Tag::Address => write!(f, "address"),
Tag::ByteArray => write!(f, "bytearray"),
Tag::String => write!(f, "string"),
Tag::Struct(ty) => write!(f, "{}", ty),
}
}
}
fn write_kind_tag(f: &mut fmt::Formatter<'_>, k: &Kind, t: &Tag) -> fmt::Result {
match t {
Tag::Struct(_) => write!(f, "{}#{}", k, t),
_ => write!(f, "{}", t),
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::Normal(k, t) => write_kind_tag(f, k, t),
Type::Reference {
kind,
tag,
is_mutable,
} => {
write!(f, "&{}", if *is_mutable { "mut " } else { "" })?;
write_kind_tag(f, kind, tag)
}
}
}
}
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::CreateAccount => write!(f, "create_account"),
Builtin::Release => write!(f, "release"),
Builtin::EmitEvent => write!(f, "log"),
Builtin::Exists(t) => write!(f, "exists<{}>", t),
Builtin::BorrowGlobal(t) => write!(f, "borrow_global<{}>", t),
Builtin::GetHeight => write!(f, "get_height"),
Builtin::GetTxnMaxGasUnits => write!(f, "get_txn_max_gas_units"),
Builtin::GetTxnGasUnitPrice => write!(f, "get_txn_gas_unit_price"),
Builtin::GetTxnPublicKey => write!(f, "get_txn_public_key"),
Builtin::GetTxnSender => write!(f, "get_txn_sender"),
Builtin::GetTxnSequenceNumber => write!(f, "get_txn_sequence_number"),
Builtin::GetGasRemaining => write!(f, "get_gas_remaining"),
Builtin::MoveFrom(t) => write!(f, "move_from<{}>", t),
Builtin::MoveToSender(t) => write!(f, "move_to_sender<{}>", t),
Builtin::Freeze => write!(f, "freeze"),
}
}
}
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 } => write!(f, "{}.{}", module, name),
}
}
}
impl fmt::Display for Cmd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Cmd::Assign(var_list, e) => {
if var_list.is_empty() {
write!(f, "{};", e)
} else {
write!(f, "{} = ({});", intersperse(var_list, ", "), e)
}
}
Cmd::Unpack(n, bindings, e) => write!(
f,
"{} {{ {} }} = {}",
n,
bindings
.iter()
.fold(String::new(), |acc, (field, var)| format!(
"{} {} : {},",
acc, field, var
)),
e
),
Cmd::Mutate(e, o) => write!(f, "*({}) = {};", e, o),
Cmd::Abort(None) => write!(f, "abort;"),
Cmd::Abort(Some(err)) => write!(f, "abort {};", err),
Cmd::Return(exps) => write!(f, "return {};", exps),
Cmd::Break => write!(f, "break;"),
Cmd::Continue => write!(f, "continue;"),
Cmd::Exp(e) => write!(f, "({});", e),
}
}
}
impl fmt::Display for IfElse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"if ({}) {{\n{:indent$}\n}}",
self.cond,
self.if_block,
indent = 4
)?;
match self.else_block {
None => Ok(()),
Some(ref block) => write!(f, " else {{\n{:indent$}\n}}", block, indent = 4),
}
}
}
impl fmt::Display for While {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"while ({}) {{\n{:indent$}\n}}",
self.cond,
self.block,
indent = 4
)?;
Ok(())
}
}
impl fmt::Display for Loop {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "loop {{\n{:indent$}\n}}", self.block, indent = 4)?;
Ok(())
}
}
impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Statement::CommandStatement(cmd) => write!(f, "{}", cmd),
Statement::IfElseStatement(if_else) => write!(f, "{}", if_else),
Statement::WhileStatement(while_) => write!(f, "{}", while_),
Statement::LoopStatement(loop_) => write!(f, "{}", loop_),
Statement::VerifyStatement(cond) => write!(f, "verify<{}>)", cond),
Statement::AssumeStatement(cond) => write!(f, "assume<{}>", cond),
Statement::EmptyStatement => write!(f, "<empty statement>"),
}
}
}
impl fmt::Display for Block {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for stmt in self.stmts.iter() {
writeln!(f, "{}", stmt)?;
}
Ok(())
}
}
impl fmt::Display for CopyableVal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CopyableVal::U64(v) => write!(f, "{}", v),
CopyableVal::Bool(v) => write!(f, "{}", v),
CopyableVal::ByteArray(v) => write!(f, "{}", v),
CopyableVal::Address(v) => write!(f, "0x{}", hex::encode(&v)),
CopyableVal::String(v) => write!(f, "{}", 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::Or => "||",
BinOp::And => "&&",
BinOp::Eq => "==",
BinOp::Neq => "!=",
BinOp::Lt => "<",
BinOp::Gt => ">",
BinOp::Le => "<=",
BinOp::Ge => ">=",
}
)
}
}
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, s) => write!(
f,
"{}{{{}}}",
n,
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, ", "))
}
}
}
}
}