pub mod name;
pub mod verbatim;
use std::collections::BTreeSet;
use inkwell::values::BasicValue;
use serde::Deserialize;
use serde::Serialize;
use crate::error::Error;
use crate::lexer::token::lexeme::literal::Literal as LexicalLiteral;
use crate::lexer::token::lexeme::symbol::Symbol;
use crate::lexer::token::lexeme::Lexeme;
use crate::lexer::token::location::Location;
use crate::lexer::token::Token;
use crate::lexer::Lexer;
use crate::parser::error::Error as ParserError;
use crate::parser::statement::expression::literal::Literal;
use crate::parser::statement::expression::Expression;
use crate::visitor::AstNode;
use crate::visitor::AstVisitor;
use self::name::Name;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct FunctionCall {
pub location: Location,
pub name: Name,
pub arguments: Vec<Expression>,
}
impl FunctionCall {
pub fn parse(lexer: &mut Lexer, initial: Option<Token>) -> Result<Self, Error> {
let token = crate::parser::take_or_next(initial, lexer)?;
let (location, name) = match token {
Token {
lexeme: Lexeme::Identifier(identifier),
location,
..
} => (location, Name::from(identifier.inner.as_str())),
token => {
return Err(ParserError::InvalidToken {
location: token.location,
expected: vec!["{identifier}"],
found: token.lexeme.to_string(),
}
.into());
}
};
let mut arguments = Vec::new();
loop {
let argument = match lexer.next()? {
Token {
lexeme: Lexeme::Symbol(Symbol::ParenthesisRight),
..
} => break,
token => Expression::parse(lexer, Some(token))?,
};
arguments.push(argument);
match lexer.peek()? {
Token {
lexeme: Lexeme::Symbol(Symbol::Comma),
..
} => {
lexer.next()?;
continue;
}
Token {
lexeme: Lexeme::Symbol(Symbol::ParenthesisRight),
..
} => {
lexer.next()?;
break;
}
_ => break,
}
}
Ok(Self {
location,
name,
arguments,
})
}
pub fn get_missing_libraries(&self) -> BTreeSet<String> {
let mut libraries = BTreeSet::new();
if let Name::LinkerSymbol = self.name {
let _argument = self.arguments.first().expect("Always exists");
if let Expression::Literal(Literal {
inner: LexicalLiteral::String(library_path),
..
}) = self.arguments.first().expect("Always exists")
{
libraries.insert(library_path.to_string());
}
return libraries;
}
for argument in self.arguments.iter() {
libraries.extend(argument.get_missing_libraries());
}
libraries
}
pub fn into_llvm<'ctx>(
mut self,
context: &mut revive_llvm_context::PolkaVMContext<'ctx>,
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>> {
let location = self.location;
context.set_debug_location(location.line, location.column, None)?;
match self.name {
Name::UserDefined(name) => {
let mut values = Vec::with_capacity(self.arguments.len());
for argument in self.arguments.into_iter().rev() {
let value = argument
.into_llvm(context)?
.expect("Always exists")
.access(context)?;
values.push(value);
}
values.reverse();
let function = context.get_function(name.as_str(), true).ok_or_else(|| {
anyhow::anyhow!("{} Undeclared function `{}`", location, name)
})?;
let expected_arguments_count =
function.borrow().declaration().value.count_params() as usize;
if expected_arguments_count != values.len() {
anyhow::bail!(
"{} Function `{}` expected {} arguments, found {}",
location,
name,
expected_arguments_count,
values.len()
);
}
let return_value = context.build_call(
function.borrow().declaration(),
values.as_slice(),
format!("{name}_call").as_str(),
);
Ok(return_value)
}
Name::Add => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::addition(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Sub => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::subtraction(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Mul => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::multiplication(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Div => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::division(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Mod => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::remainder(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Sdiv => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::division_signed(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Smod => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::remainder_signed(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Lt => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_comparison::compare(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
inkwell::IntPredicate::ULT,
)
.map(Some)
}
Name::Gt => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_comparison::compare(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
inkwell::IntPredicate::UGT,
)
.map(Some)
}
Name::Eq => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_comparison::compare(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
inkwell::IntPredicate::EQ,
)
.map(Some)
}
Name::IsZero => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_comparison::compare(
context,
arguments[0].into_int_value(),
context.word_const(0),
inkwell::IntPredicate::EQ,
)
.map(Some)
}
Name::Slt => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_comparison::compare(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
inkwell::IntPredicate::SLT,
)
.map(Some)
}
Name::Sgt => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_comparison::compare(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
inkwell::IntPredicate::SGT,
)
.map(Some)
}
Name::Or => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::or(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Xor => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::xor(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Not => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_bitwise::xor(
context,
arguments[0].into_int_value(),
context.word_type().const_all_ones(),
)
.map(Some)
}
Name::And => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::and(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Shl => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::shift_left(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Shr => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::shift_right(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Sar => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::shift_right_arithmetic(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Clz => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_bitwise::count_leading_zeros(
context,
arguments[0].into_int_value(),
)
.map(Some)
}
Name::Byte => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::byte(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Pop => {
let _arguments = self.pop_arguments_llvm::<1>(context)?;
Ok(None)
}
Name::AddMod => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
revive_llvm_context::polkavm_evm_math::add_mod(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
arguments[2].into_int_value(),
)
.map(Some)
}
Name::MulMod => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
revive_llvm_context::polkavm_evm_math::mul_mod(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
arguments[2].into_int_value(),
)
.map(Some)
}
Name::Exp => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_math::exponent(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::SignExtend => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_math::sign_extend(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::Keccak256 => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_crypto::sha3(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
}
Name::MLoad => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_memory::load(
context,
arguments[0].into_int_value(),
)
.map(Some)
}
Name::MStore => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_memory::store(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(|_| None)
}
Name::MStore8 => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_memory::store_byte(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(|_| None)
}
Name::MCopy => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
let destination = revive_llvm_context::PolkaVMPointer::new_with_offset(
context,
revive_llvm_context::PolkaVMAddressSpace::Heap,
context.byte_type(),
arguments[0].into_int_value(),
"mcopy_destination",
);
let source = revive_llvm_context::PolkaVMPointer::new_with_offset(
context,
revive_llvm_context::PolkaVMAddressSpace::Heap,
context.byte_type(),
arguments[1].into_int_value(),
"mcopy_source",
);
context.build_memcpy(
destination,
source,
arguments[2].into_int_value(),
"mcopy_size",
)?;
Ok(None)
}
Name::SLoad => {
let arguments = self.pop_arguments::<1>(context)?;
revive_llvm_context::polkavm_evm_storage::load(context, &arguments[0]).map(Some)
}
Name::SStore => {
let arguments = self.pop_arguments::<2>(context)?;
revive_llvm_context::polkavm_evm_storage::store(
context,
&arguments[0],
&arguments[1],
)
.map(|_| None)
}
Name::TLoad => {
let arguments = self.pop_arguments::<1>(context)?;
revive_llvm_context::polkavm_evm_storage::transient_load(context, &arguments[0])
.map(Some)
}
Name::TStore => {
let arguments = self.pop_arguments::<2>(context)?;
revive_llvm_context::polkavm_evm_storage::transient_store(
context,
&arguments[0],
&arguments[1],
)
.map(|_| None)
}
Name::LoadImmutable => {
let mut arguments = self.pop_arguments::<1>(context)?;
let key = arguments[0].original.take().ok_or_else(|| {
anyhow::anyhow!("{} `load_immutable` literal is missing", location)
})?;
let offset = context
.solidity_mut()
.get_or_allocate_immutable(key.as_str())
/ revive_common::BYTE_LENGTH_WORD;
let index = context.xlen_type().const_int(offset as u64, false);
revive_llvm_context::polkavm_evm_immutable::load(context, index).map(Some)
}
Name::SetImmutable => {
let mut arguments = self.pop_arguments::<3>(context)?;
let key = arguments[1].original.take().ok_or_else(|| {
anyhow::anyhow!("{} `load_immutable` literal is missing", location)
})?;
let offset = context.solidity_mut().allocate_immutable(key.as_str())
/ revive_common::BYTE_LENGTH_WORD;
let index = context.xlen_type().const_int(offset as u64, false);
let value = arguments[2].access(context)?.into_int_value();
revive_llvm_context::polkavm_evm_immutable::store(context, index, value)
.map(|_| None)
}
Name::CallDataLoad => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
match context
.code_type()
.ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))?
{
revive_llvm_context::PolkaVMCodeType::Deploy => {
Ok(Some(context.word_const(0).as_basic_value_enum()))
}
revive_llvm_context::PolkaVMCodeType::Runtime => {
revive_llvm_context::polkavm_evm_calldata::load(
context,
arguments[0].into_int_value(),
)
.map(Some)
}
}
}
Name::CallDataSize => {
match context
.code_type()
.ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))?
{
revive_llvm_context::PolkaVMCodeType::Deploy => {
Ok(Some(context.word_const(0).as_basic_value_enum()))
}
revive_llvm_context::PolkaVMCodeType::Runtime => {
revive_llvm_context::polkavm_evm_calldata::size(context).map(Some)
}
}
}
Name::CallDataCopy => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
match context
.code_type()
.ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))?
{
revive_llvm_context::PolkaVMCodeType::Deploy => {
let calldata_size =
revive_llvm_context::polkavm_evm_calldata::size(context)?;
revive_llvm_context::polkavm_evm_calldata::copy(
context,
arguments[0].into_int_value(),
calldata_size.into_int_value(),
arguments[2].into_int_value(),
)
.map(|_| None)
}
revive_llvm_context::PolkaVMCodeType::Runtime => {
revive_llvm_context::polkavm_evm_calldata::copy(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
arguments[2].into_int_value(),
)
.map(|_| None)
}
}
}
Name::CodeSize => {
match context
.code_type()
.ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))?
{
revive_llvm_context::PolkaVMCodeType::Deploy => {
revive_llvm_context::polkavm_evm_calldata::size(context).map(Some)
}
revive_llvm_context::PolkaVMCodeType::Runtime => {
revive_llvm_context::polkavm_evm_ext_code::size(context, None).map(Some)
}
}
}
Name::CodeCopy => {
if let revive_llvm_context::PolkaVMCodeType::Runtime = context
.code_type()
.ok_or_else(|| anyhow::anyhow!("The contract code part type is undefined"))?
{
anyhow::bail!(
"{} The `CODECOPY` instruction is not supported in the runtime code",
location,
);
}
let arguments = self.pop_arguments_llvm::<3>(context)?;
revive_llvm_context::polkavm_evm_calldata::copy(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
arguments[2].into_int_value(),
)
.map(|_| None)
}
Name::ReturnDataSize => {
revive_llvm_context::polkavm_evm_return_data::size(context).map(Some)
}
Name::ReturnDataCopy => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
revive_llvm_context::polkavm_evm_return_data::copy(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
arguments[2].into_int_value(),
)
.map(|_| None)
}
Name::ExtCodeSize => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_ext_code::size(
context,
Some(arguments[0].into_int_value()),
)
.map(Some)
}
Name::ExtCodeHash => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_ext_code::hash(
context,
arguments[0].into_int_value(),
)
.map(Some)
}
Name::Return => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_return::r#return(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(|_| None)
}
Name::Revert => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_return::revert(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(|_| None)
}
Name::Stop => revive_llvm_context::polkavm_evm_return::stop(context).map(|_| None),
Name::Invalid => {
revive_llvm_context::polkavm_evm_return::invalid(context).map(|_| None)
}
Name::SelfDestruct => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_return::selfdestruct(
context,
arguments[0].into_int_value(),
)
.map(|_| None)
}
Name::Log0 => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_event::log(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
[],
)
.map(|_| None)
}
Name::Log1 => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
revive_llvm_context::polkavm_evm_event::log(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
[arguments[2]],
)
.map(|_| None)
}
Name::Log2 => {
let arguments = self.pop_arguments_llvm::<4>(context)?;
revive_llvm_context::polkavm_evm_event::log(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
[arguments[2], arguments[3]],
)
.map(|_| None)
}
Name::Log3 => {
let arguments = self.pop_arguments_llvm::<5>(context)?;
revive_llvm_context::polkavm_evm_event::log(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
[arguments[2], arguments[3], arguments[4]],
)
.map(|_| None)
}
Name::Log4 => {
let arguments = self.pop_arguments_llvm::<6>(context)?;
revive_llvm_context::polkavm_evm_event::log(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
[arguments[2], arguments[3], arguments[4], arguments[5]],
)
.map(|_| None)
}
Name::Call => {
let arguments = self.pop_arguments::<7>(context)?;
let gas = arguments[0].access(context)?.into_int_value();
let address = arguments[1].access(context)?.into_int_value();
let value = arguments[2].access(context)?.into_int_value();
let input_offset = arguments[3].access(context)?.into_int_value();
let input_size = arguments[4].access(context)?.into_int_value();
let output_offset = arguments[5].access(context)?.into_int_value();
let output_size = arguments[6].access(context)?.into_int_value();
let simulation_address: Vec<Option<num::BigUint>> = arguments
.into_iter()
.map(|mut argument| argument.constant.take())
.collect();
revive_llvm_context::polkavm_evm_call::call(
context,
gas,
address,
Some(value),
input_offset,
input_size,
output_offset,
output_size,
simulation_address,
false,
)
.map(Some)
}
Name::StaticCall => {
let arguments = self.pop_arguments::<6>(context)?;
let gas = arguments[0].access(context)?.into_int_value();
let address = arguments[1].access(context)?.into_int_value();
let input_offset = arguments[2].access(context)?.into_int_value();
let input_size = arguments[3].access(context)?.into_int_value();
let output_offset = arguments[4].access(context)?.into_int_value();
let output_size = arguments[5].access(context)?.into_int_value();
let simulation_address: Vec<Option<num::BigUint>> = arguments
.into_iter()
.map(|mut argument| argument.constant.take())
.collect();
revive_llvm_context::polkavm_evm_call::call(
context,
gas,
address,
None,
input_offset,
input_size,
output_offset,
output_size,
simulation_address,
true,
)
.map(Some)
}
Name::DelegateCall => {
let arguments = self.pop_arguments::<6>(context)?;
let gas = arguments[0].access(context)?.into_int_value();
let address = arguments[1].access(context)?.into_int_value();
let input_offset = arguments[2].access(context)?.into_int_value();
let input_size = arguments[3].access(context)?.into_int_value();
let output_offset = arguments[4].access(context)?.into_int_value();
let output_size = arguments[5].access(context)?.into_int_value();
let simulation_address: Vec<Option<num::BigUint>> = arguments
.into_iter()
.map(|mut argument| argument.constant.take())
.collect();
revive_llvm_context::polkavm_evm_call::delegate_call(
context,
gas,
address,
input_offset,
input_size,
output_offset,
output_size,
simulation_address,
)
.map(Some)
}
Name::Create => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
let value = arguments[0].into_int_value();
let input_offset = arguments[1].into_int_value();
let input_length = arguments[2].into_int_value();
revive_llvm_context::polkavm_evm_create::create(
context,
value,
input_offset,
input_length,
None,
)
.map(Some)
}
Name::Create2 => {
let arguments = self.pop_arguments_llvm::<4>(context)?;
let value = arguments[0].into_int_value();
let input_offset = arguments[1].into_int_value();
let input_length = arguments[2].into_int_value();
let salt = arguments[3].into_int_value();
revive_llvm_context::polkavm_evm_create::create(
context,
value,
input_offset,
input_length,
Some(salt),
)
.map(Some)
}
Name::DataOffset => {
let mut arguments = self.pop_arguments::<1>(context)?;
let identifier = arguments[0].original.take().ok_or_else(|| {
anyhow::anyhow!("{} `dataoffset` object identifier is missing", location)
})?;
revive_llvm_context::polkavm_evm_create::contract_hash(context, identifier)
.and_then(|argument| argument.access(context))
.map(Some)
}
Name::DataSize => {
let mut arguments = self.pop_arguments::<1>(context)?;
let identifier = arguments[0].original.take().ok_or_else(|| {
anyhow::anyhow!("{} `dataoffset` object identifier is missing", location)
})?;
revive_llvm_context::polkavm_evm_create::header_size(context, identifier)
.and_then(|argument| argument.access(context))
.map(Some)
}
Name::DataCopy => {
let arguments = self.pop_arguments_llvm::<3>(context)?;
revive_llvm_context::polkavm_evm_memory::store(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(|_| None)
}
Name::LinkerSymbol => {
let mut arguments = self.pop_arguments::<1>(context)?;
let path = arguments[0].original.take().ok_or_else(|| {
anyhow::anyhow!("{} Linker symbol literal is missing", location)
})?;
revive_llvm_context::polkavm_evm_call::linker_symbol(context, &path).map(Some)
}
Name::MemoryGuard => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
Ok(Some(arguments[0]))
}
Name::Address => {
revive_llvm_context::polkavm_evm_contract_context::address(context).map(Some)
}
Name::Caller => {
revive_llvm_context::polkavm_evm_contract_context::caller(context).map(Some)
}
Name::CallValue => revive_llvm_context::polkavm_evm_ether_gas::value(context).map(Some),
Name::Gas => revive_llvm_context::polkavm_evm_ether_gas::gas(context).map(Some),
Name::Balance => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
let address = arguments[0].into_int_value();
revive_llvm_context::polkavm_evm_ether_gas::balance(context, address).map(Some)
}
Name::SelfBalance => {
revive_llvm_context::polkavm_evm_ether_gas::self_balance(context).map(Some)
}
Name::GasLimit => {
revive_llvm_context::polkavm_evm_contract_context::gas_limit(context).map(Some)
}
Name::GasPrice => {
revive_llvm_context::polkavm_evm_contract_context::gas_price(context).map(Some)
}
Name::Origin => {
revive_llvm_context::polkavm_evm_contract_context::origin(context).map(Some)
}
Name::ChainId => {
revive_llvm_context::polkavm_evm_contract_context::chain_id(context).map(Some)
}
Name::Timestamp => {
revive_llvm_context::polkavm_evm_contract_context::block_timestamp(context)
.map(Some)
}
Name::Number => {
revive_llvm_context::polkavm_evm_contract_context::block_number(context).map(Some)
}
Name::BlockHash => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
let index = arguments[0].into_int_value();
revive_llvm_context::polkavm_evm_contract_context::block_hash(context, index)
.map(Some)
}
Name::BlobHash => {
let _arguments = self.pop_arguments_llvm::<1>(context)?;
anyhow::bail!(
"{} The `BLOBHASH` instruction is not supported in revive",
location
);
}
Name::Difficulty | Name::Prevrandao => {
revive_llvm_context::polkavm_evm_contract_context::difficulty(context).map(Some)
}
Name::CoinBase => {
revive_llvm_context::polkavm_evm_contract_context::coinbase(context).map(Some)
}
Name::BaseFee => {
revive_llvm_context::polkavm_evm_contract_context::basefee(context).map(Some)
}
Name::BlobBaseFee => {
anyhow::bail!(
"{} The `BLOBBASEFEE` instruction is not supported in revive",
location
);
}
Name::MSize => revive_llvm_context::polkavm_evm_memory::msize(context).map(Some),
Name::Verbatim {
input_size,
output_size,
} => verbatim::verbatim(context, &mut self, input_size, output_size),
Name::CallCode => {
let _arguments = self.pop_arguments_llvm::<7>(context)?;
anyhow::bail!("{} The `CALLCODE` instruction is not supported", location)
}
Name::Pc => anyhow::bail!("{} The `PC` instruction is not supported", location),
Name::ExtCodeCopy => {
let _arguments = self.pop_arguments_llvm::<4>(context)?;
anyhow::bail!(
"{} The `EXTCODECOPY` instruction is not supported",
location
)
}
}
}
fn pop_arguments_llvm<'ctx, const N: usize>(
&mut self,
context: &mut revive_llvm_context::PolkaVMContext<'ctx>,
) -> anyhow::Result<[inkwell::values::BasicValueEnum<'ctx>; N]> {
let mut arguments = Vec::with_capacity(N);
for expression in self.arguments.drain(0..N).rev() {
arguments.push(
expression
.into_llvm(context)?
.expect("Always exists")
.access(context)?,
);
}
arguments.reverse();
context.set_debug_location(self.location.line, self.location.column, None)?;
Ok(arguments.try_into().expect("Always successful"))
}
fn pop_arguments<'ctx, const N: usize>(
&mut self,
context: &mut revive_llvm_context::PolkaVMContext<'ctx>,
) -> anyhow::Result<[revive_llvm_context::PolkaVMArgument<'ctx>; N]> {
let mut arguments = Vec::with_capacity(N);
for expression in self.arguments.drain(0..N).rev() {
arguments.push(expression.into_llvm(context)?.expect("Always exists"));
}
arguments.reverse();
context.set_debug_location(self.location.line, self.location.column, None)?;
Ok(arguments.try_into().expect("Always successful"))
}
}
impl AstNode for FunctionCall {
fn accept(&self, ast_visitor: &mut impl AstVisitor) {
ast_visitor.visit_function_call(self);
}
fn visit_children(&self, ast_visitor: &mut impl AstVisitor) {
for argument in &self.arguments {
argument.accept(ast_visitor);
}
}
fn location(&self) -> Location {
self.location
}
}