mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 21:31:05 +00:00
11f82c8488
- Support for solc v0.8.31. - Support for the `clz` Yul builtin. --------- Signed-off-by: xermicus <cyrill@parity.io>
493 lines
15 KiB
Rust
493 lines
15 KiB
Rust
//! The function name.
|
||
|
||
use std::fmt;
|
||
|
||
use serde::Deserialize;
|
||
use serde::Serialize;
|
||
|
||
/// The function name.
|
||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||
#[serde(rename_all = "lowercase")]
|
||
pub enum Name {
|
||
/// The user-defined function.
|
||
UserDefined(String),
|
||
|
||
/// `x + y`
|
||
Add,
|
||
/// `x - y`
|
||
Sub,
|
||
/// `x * y`
|
||
Mul,
|
||
/// `x / y` or `0` if `y == 0`
|
||
Div,
|
||
/// `x % y` or `0` if `y == 0`
|
||
Mod,
|
||
/// `x / y`, for signed numbers in two’s complement, `0` if `y == 0`
|
||
Sdiv,
|
||
/// `x % y`, for signed numbers in two’s complement, `0` if `y == 0`
|
||
Smod,
|
||
|
||
/// `1` if `x < y`, `0` otherwise
|
||
Lt,
|
||
/// `1` if `x > y`, `0` otherwise
|
||
Gt,
|
||
/// `1` if `x == y`, `0` otherwise
|
||
Eq,
|
||
/// `1` if `x == 0`, `0` otherwise
|
||
IsZero,
|
||
/// `1` if `x < y`, `0` otherwise, for signed numbers in two’s complement
|
||
Slt,
|
||
/// `1` if `x > y`, `0` otherwise, for signed numbers in two’s complement
|
||
Sgt,
|
||
|
||
/// bitwise "or" of `x` and `y`
|
||
Or,
|
||
/// bitwise "xor" of `x` and `y`
|
||
Xor,
|
||
/// bitwise "not" of `x` (every bit of `x` is negated)
|
||
Not,
|
||
/// bitwise "and" of `x` and `y`
|
||
And,
|
||
/// logical shift left `y` by `x` bits
|
||
Shl,
|
||
/// logical shift right `y` by `x` bits
|
||
Shr,
|
||
/// signed arithmetic shift right `y` by `x` bits
|
||
Sar,
|
||
/// number of leading zero bits of x, 256 if x == 0
|
||
Clz,
|
||
/// `n`th byte of `x`, where the most significant byte is the `0`th byte
|
||
Byte,
|
||
/// discard value x
|
||
Pop,
|
||
|
||
/// `(x + y) % m` with arbitrary precision arithmetic, `0` if `m == 0`
|
||
AddMod,
|
||
/// `(x * y) % m` with arbitrary precision arithmetic, `0` if `m == 0`
|
||
MulMod,
|
||
/// `x` to the power of `y`
|
||
Exp,
|
||
/// sign extend from `(i*8+7)`th bit counting from least significant
|
||
SignExtend,
|
||
|
||
/// `keccak(mem[p…(p+n)))`
|
||
Keccak256,
|
||
|
||
/// `mem[p…(p+32))`
|
||
MLoad,
|
||
/// `mem[p…(p+32)) := v`
|
||
MStore,
|
||
/// `mem[p] := v & 0xff` (only modifies a single byte)
|
||
MStore8,
|
||
/// heap memory copy
|
||
MCopy,
|
||
|
||
/// `storage[p]`
|
||
SLoad,
|
||
/// `storage[p] := v`
|
||
SStore,
|
||
/// transient `storage[p]`
|
||
TLoad,
|
||
/// transient `storage[p] := v`
|
||
TStore,
|
||
/// `loadimmutable` storage read
|
||
LoadImmutable,
|
||
/// `setimmutable` storage write
|
||
SetImmutable,
|
||
|
||
/// call data starting from position `p` (32 bytes)
|
||
CallDataLoad,
|
||
/// size of call data in bytes
|
||
CallDataSize,
|
||
/// copy `s` bytes from calldata at position `f` to memory at position `t`
|
||
CallDataCopy,
|
||
/// size of the code of the current contract / execution context
|
||
CodeSize,
|
||
/// copy `s` bytes from code at position `f` to mem at position `t`
|
||
CodeCopy,
|
||
/// size of the code at address `a`
|
||
ExtCodeSize,
|
||
/// code hash of address `a`
|
||
ExtCodeHash,
|
||
/// size of the last returndata
|
||
ReturnDataSize,
|
||
/// copy `s` bytes from returndata at position `f` to mem at position `t`
|
||
ReturnDataCopy,
|
||
|
||
/// end execution, return data `mem[p…(p+s))`
|
||
Return,
|
||
/// end execution, revert state changes, return data `mem[p…(p+s))`
|
||
Revert,
|
||
/// stop execution, identical to `return(0, 0)`
|
||
Stop,
|
||
/// end execution with invalid instruction
|
||
Invalid,
|
||
|
||
/// log without topics and data `mem[p…(p+s))`
|
||
Log0,
|
||
/// log with topic t1 and data `mem[p…(p+s))`
|
||
Log1,
|
||
/// log with topics t1, t2 and data `mem[p…(p+s))`
|
||
Log2,
|
||
/// log with topics t1, t2, t3 and data `mem[p…(p+s))`
|
||
Log3,
|
||
/// log with topics t1, t2, t3, t4 and data `mem[p…(p+s))`
|
||
Log4,
|
||
|
||
/// call contract at address a with input `mem[in…(in+insize))` providing `g` gas and `v` wei
|
||
/// and output area `mem[out…(out+outsize))` returning 0 on error (e.g. out of gas)
|
||
/// and 1 on success
|
||
/// [See more](https://docs.soliditylang.org/en/v0.8.2/yul.html#yul-call-return-area)
|
||
Call,
|
||
/// identical to call but only use the code from a and stay in the context of the current
|
||
/// contract otherwise
|
||
CallCode,
|
||
/// identical to `callcode` but also keeps `caller` and `callvalue`
|
||
DelegateCall,
|
||
/// identical to `call(g, a, 0, in, insize, out, outsize)` but do not allows state modifications
|
||
StaticCall,
|
||
|
||
/// create new contract with code `mem[p…(p+n))` and send `v` wei and return the new address
|
||
/// Passes bytecode to the system contracts.
|
||
Create,
|
||
/// create new contract with code `mem[p…(p+n))` at address
|
||
/// `keccak256(0xff . this . s . keccak256(mem[p…(p+n)))` and send `v` wei and return the
|
||
/// new address, where `0xff` is a 1-byte value, this is the current contract’s address as a
|
||
/// 20-byte value and `s` is a big-endian 256-bit value
|
||
/// Passes bytecode to the system contracts.
|
||
Create2,
|
||
/// returns the size in the data area
|
||
DataSize,
|
||
/// is equivalent to `CodeCopy`
|
||
DataCopy,
|
||
/// returns the offset in the data area
|
||
DataOffset,
|
||
|
||
/// `linkersymbol` is a stub call
|
||
LinkerSymbol,
|
||
/// `memoryguard` is a stub call
|
||
MemoryGuard,
|
||
|
||
/// address of the current contract / execution context
|
||
Address,
|
||
/// call sender (excluding `delegatecall`)
|
||
Caller,
|
||
|
||
/// wei sent together with the current call
|
||
CallValue,
|
||
/// gas still available to execution
|
||
Gas,
|
||
/// wei balance at address `a`
|
||
Balance,
|
||
/// equivalent to `balance(address())`, but cheaper
|
||
SelfBalance,
|
||
|
||
/// block gas limit of the current block
|
||
GasLimit,
|
||
/// gas price of the transaction
|
||
GasPrice,
|
||
/// transaction sender
|
||
Origin,
|
||
/// ID of the executing chain (EIP 1344)
|
||
ChainId,
|
||
/// current block number
|
||
Number,
|
||
/// timestamp of the current block in seconds since the epoch
|
||
Timestamp,
|
||
/// hash of block nr b - only for last 256 blocks excluding current
|
||
BlockHash,
|
||
/// versioned hash of transaction’s i-th blob
|
||
BlobHash,
|
||
/// difficulty of the current block
|
||
Difficulty,
|
||
/// <https://eips.ethereum.org/EIPS/eip-4399>
|
||
Prevrandao,
|
||
/// current mining beneficiary
|
||
CoinBase,
|
||
/// size of memory, i.e. largest accessed memory index
|
||
MSize,
|
||
|
||
/// verbatim instruction with 0 inputs and 0 outputs only works in the Yul mode,
|
||
/// so it is mostly used as a tool for extending Yul for PolkaVM
|
||
Verbatim {
|
||
/// the number of input arguments
|
||
input_size: usize,
|
||
/// the number of output arguments
|
||
output_size: usize,
|
||
},
|
||
|
||
/// current block’s base fee (EIP-3198 and EIP-1559)
|
||
BaseFee,
|
||
/// current block’s blob base fee (EIP-7516 and EIP-4844)
|
||
BlobBaseFee,
|
||
/// current position in code
|
||
Pc,
|
||
/// like `codecopy(t, f, s)` but take code at address `a`
|
||
ExtCodeCopy,
|
||
/// end execution, destroy current contract and send funds to `a`
|
||
SelfDestruct,
|
||
}
|
||
|
||
impl Name {
|
||
/// Tries parsing the verbatim instruction.
|
||
fn parse_verbatim(input: &str) -> Option<Self> {
|
||
let verbatim = input.strip_prefix("verbatim")?;
|
||
let regex = regex::Regex::new(r"_(\d+)i_(\d+)o").expect("Always valid");
|
||
let captures = regex.captures(verbatim)?;
|
||
let input_size: usize = captures.get(1)?.as_str().parse().ok()?;
|
||
let output_size: usize = captures.get(2)?.as_str().parse().ok()?;
|
||
Some(Self::Verbatim {
|
||
input_size,
|
||
output_size,
|
||
})
|
||
}
|
||
}
|
||
|
||
impl From<&str> for Name {
|
||
fn from(input: &str) -> Self {
|
||
if let Some(verbatim) = Self::parse_verbatim(input) {
|
||
return verbatim;
|
||
}
|
||
|
||
match input {
|
||
"add" => Self::Add,
|
||
"sub" => Self::Sub,
|
||
"mul" => Self::Mul,
|
||
"div" => Self::Div,
|
||
"mod" => Self::Mod,
|
||
"sdiv" => Self::Sdiv,
|
||
"smod" => Self::Smod,
|
||
|
||
"lt" => Self::Lt,
|
||
"gt" => Self::Gt,
|
||
"eq" => Self::Eq,
|
||
"iszero" => Self::IsZero,
|
||
"slt" => Self::Slt,
|
||
"sgt" => Self::Sgt,
|
||
|
||
"or" => Self::Or,
|
||
"xor" => Self::Xor,
|
||
"not" => Self::Not,
|
||
"and" => Self::And,
|
||
"shl" => Self::Shl,
|
||
"shr" => Self::Shr,
|
||
"sar" => Self::Sar,
|
||
"clz" => Self::Clz,
|
||
"byte" => Self::Byte,
|
||
"pop" => Self::Pop,
|
||
|
||
"addmod" => Self::AddMod,
|
||
"mulmod" => Self::MulMod,
|
||
"exp" => Self::Exp,
|
||
"signextend" => Self::SignExtend,
|
||
|
||
"keccak256" => Self::Keccak256,
|
||
|
||
"mload" => Self::MLoad,
|
||
"mstore" => Self::MStore,
|
||
"mstore8" => Self::MStore8,
|
||
"mcopy" => Self::MCopy,
|
||
|
||
"sload" => Self::SLoad,
|
||
"sstore" => Self::SStore,
|
||
"tload" => Self::TLoad,
|
||
"tstore" => Self::TStore,
|
||
"loadimmutable" => Self::LoadImmutable,
|
||
"setimmutable" => Self::SetImmutable,
|
||
|
||
"calldataload" => Self::CallDataLoad,
|
||
"calldatasize" => Self::CallDataSize,
|
||
"calldatacopy" => Self::CallDataCopy,
|
||
"codesize" => Self::CodeSize,
|
||
"codecopy" => Self::CodeCopy,
|
||
"returndatasize" => Self::ReturnDataSize,
|
||
"returndatacopy" => Self::ReturnDataCopy,
|
||
"extcodesize" => Self::ExtCodeSize,
|
||
"extcodehash" => Self::ExtCodeHash,
|
||
|
||
"return" => Self::Return,
|
||
"revert" => Self::Revert,
|
||
|
||
"log0" => Self::Log0,
|
||
"log1" => Self::Log1,
|
||
"log2" => Self::Log2,
|
||
"log3" => Self::Log3,
|
||
"log4" => Self::Log4,
|
||
|
||
"call" => Self::Call,
|
||
"delegatecall" => Self::DelegateCall,
|
||
"staticcall" => Self::StaticCall,
|
||
|
||
"create" => Self::Create,
|
||
"create2" => Self::Create2,
|
||
"datasize" => Self::DataSize,
|
||
"dataoffset" => Self::DataOffset,
|
||
"datacopy" => Self::DataCopy,
|
||
|
||
"stop" => Self::Stop,
|
||
"invalid" => Self::Invalid,
|
||
|
||
"linkersymbol" => Self::LinkerSymbol,
|
||
"memoryguard" => Self::MemoryGuard,
|
||
|
||
"address" => Self::Address,
|
||
"caller" => Self::Caller,
|
||
|
||
"callvalue" => Self::CallValue,
|
||
"gas" => Self::Gas,
|
||
"balance" => Self::Balance,
|
||
"selfbalance" => Self::SelfBalance,
|
||
|
||
"gaslimit" => Self::GasLimit,
|
||
"gasprice" => Self::GasPrice,
|
||
"origin" => Self::Origin,
|
||
"chainid" => Self::ChainId,
|
||
"timestamp" => Self::Timestamp,
|
||
"number" => Self::Number,
|
||
"blockhash" => Self::BlockHash,
|
||
"blobhash" => Self::BlobHash,
|
||
"difficulty" => Self::Difficulty,
|
||
"prevrandao" => Self::Prevrandao,
|
||
"coinbase" => Self::CoinBase,
|
||
"basefee" => Self::BaseFee,
|
||
"blobbasefee" => Self::BlobBaseFee,
|
||
"msize" => Self::MSize,
|
||
|
||
"callcode" => Self::CallCode,
|
||
"pc" => Self::Pc,
|
||
"extcodecopy" => Self::ExtCodeCopy,
|
||
"selfdestruct" => Self::SelfDestruct,
|
||
|
||
input => Self::UserDefined(input.to_owned()),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl fmt::Display for Name {
|
||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
if let Self::Verbatim {
|
||
input_size,
|
||
output_size,
|
||
} = self
|
||
{
|
||
return write!(f, "verbatim_{input_size}i_{output_size}o");
|
||
}
|
||
|
||
let token = match self {
|
||
Self::Add => "add",
|
||
Self::Sub => "sub",
|
||
Self::Mul => "mul",
|
||
Self::Div => "div",
|
||
Self::Mod => "mod",
|
||
Self::Sdiv => "sdiv",
|
||
Self::Smod => "smod",
|
||
|
||
Self::Lt => "lt",
|
||
Self::Gt => "gt",
|
||
Self::Eq => "eq",
|
||
Self::IsZero => "iszero",
|
||
Self::Slt => "slt",
|
||
Self::Sgt => "sgt",
|
||
|
||
Self::Or => "or",
|
||
Self::Xor => "xor",
|
||
Self::Not => "not",
|
||
Self::And => "and",
|
||
Self::Shl => "shl",
|
||
Self::Shr => "shr",
|
||
Self::Sar => "sar",
|
||
Self::Clz => "clz",
|
||
Self::Byte => "byte",
|
||
Self::Pop => "pop",
|
||
|
||
Self::AddMod => "addmod",
|
||
Self::MulMod => "mulmod",
|
||
Self::Exp => "exp",
|
||
Self::SignExtend => "signextend",
|
||
|
||
Self::Keccak256 => "keccak256",
|
||
|
||
Self::MLoad => "mload",
|
||
Self::MStore => "mstore",
|
||
Self::MStore8 => "mstore8",
|
||
Self::MCopy => "mcopy",
|
||
|
||
Self::SLoad => "sload",
|
||
Self::SStore => "sstore",
|
||
Self::TLoad => "tload",
|
||
Self::TStore => "tstore",
|
||
Self::LoadImmutable => "loadimmutable",
|
||
Self::SetImmutable => "setimmutable",
|
||
|
||
Self::CallDataLoad => "calldataload",
|
||
Self::CallDataSize => "calldatasize",
|
||
Self::CallDataCopy => "calldatacopy",
|
||
Self::CodeSize => "codesize",
|
||
Self::CodeCopy => "codecopy",
|
||
Self::ReturnDataSize => "returndatasize",
|
||
Self::ReturnDataCopy => "returndatacopy",
|
||
Self::ExtCodeSize => "extcodesize",
|
||
Self::ExtCodeHash => "extcodehash",
|
||
|
||
Self::Return => "return",
|
||
Self::Revert => "revert",
|
||
|
||
Self::Log0 => "log0",
|
||
Self::Log1 => "log1",
|
||
Self::Log2 => "log2",
|
||
Self::Log3 => "log3",
|
||
Self::Log4 => "log4",
|
||
|
||
Self::Call => "call",
|
||
Self::DelegateCall => "delegatecall",
|
||
Self::StaticCall => "staticcall",
|
||
Self::Create => "create",
|
||
Self::Create2 => "create2",
|
||
|
||
Self::DataSize => "datasize",
|
||
Self::DataOffset => "dataoffset",
|
||
Self::DataCopy => "datacopy",
|
||
|
||
Self::Stop => "stop",
|
||
Self::Invalid => "invalid",
|
||
|
||
Self::LinkerSymbol => "linkersymbol",
|
||
Self::MemoryGuard => "memoryguard",
|
||
|
||
Self::Address => "address",
|
||
Self::Caller => "caller",
|
||
|
||
Self::CallValue => "callvalue",
|
||
Self::Gas => "gas",
|
||
Self::Balance => "balance",
|
||
Self::SelfBalance => "selfbalance",
|
||
|
||
Self::GasLimit => "gaslimit",
|
||
Self::GasPrice => "gasprice",
|
||
Self::Origin => "origin",
|
||
Self::ChainId => "chainid",
|
||
Self::Timestamp => "timestamp",
|
||
Self::Number => "number",
|
||
Self::BlockHash => "blockhash",
|
||
Self::BlobHash => "blobhash",
|
||
Self::Difficulty => "difficulty",
|
||
Self::Prevrandao => "prevrandao",
|
||
Self::CoinBase => "coinbase",
|
||
Self::BaseFee => "basefee",
|
||
Self::BlobBaseFee => "blobbasefee",
|
||
Self::MSize => "msize",
|
||
|
||
Self::CallCode => "callcode",
|
||
Self::Pc => "pc",
|
||
Self::ExtCodeCopy => "extcodecopy",
|
||
Self::SelfDestruct => "selfdestruct",
|
||
|
||
Self::UserDefined(s) => s.as_str(),
|
||
|
||
Self::Verbatim { .. } => unreachable!(),
|
||
};
|
||
|
||
write!(f, "{token}")
|
||
}
|
||
}
|