use crate::codegen::Expression;
use crate::sema::ast::{CallTy, Contract, Function, Namespace, Parameter, Type};
use std::collections::HashMap;
use std::fmt;
use std::str;
use crate::Target;
use inkwell::targets::TargetTriple;
use inkwell::types::IntType;
use inkwell::values::{
ArrayValue, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, PointerValue,
};
pub mod binary;
mod cfg;
mod expression;
mod functions;
mod instructions;
mod loop_builder;
mod math;
pub mod solana;
mod storage;
mod strings;
pub mod substrate;
use crate::codegen::{cfg::HashTy, Options};
use crate::emit::binary::Binary;
use crate::sema::ast;
#[derive(Clone)]
pub struct Variable<'a> {
value: BasicValueEnum<'a>,
}
#[derive(Clone, Copy)]
pub enum BinaryOp {
Add,
Subtract,
Multiply,
}
impl fmt::Display for BinaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Add => "add",
Self::Subtract => "sub",
Self::Multiply => "mul",
}
)
}
}
pub trait TargetRuntime<'a> {
fn abi_decode<'b>(
&self,
bin: &Binary<'b>,
function: FunctionValue<'b>,
args: &mut Vec<BasicValueEnum<'b>>,
data: PointerValue<'b>,
length: IntValue<'b>,
spec: &[Parameter],
ns: &Namespace,
);
fn abi_encode(
&self,
bin: &Binary<'a>,
selector: Option<IntValue<'a>>,
load: bool,
function: FunctionValue<'a>,
args: &[BasicValueEnum<'a>],
tys: &[Type],
ns: &Namespace,
) -> (PointerValue<'a>, IntValue<'a>);
fn abi_encode_to_vector<'b>(
&self,
binary: &Binary<'b>,
function: FunctionValue<'b>,
packed: &[BasicValueEnum<'b>],
args: &[BasicValueEnum<'b>],
tys: &[Type],
ns: &Namespace,
) -> PointerValue<'b>;
fn get_storage_int(
&self,
bin: &Binary<'a>,
function: FunctionValue,
slot: PointerValue<'a>,
ty: IntType<'a>,
) -> IntValue<'a>;
fn storage_load(
&self,
binary: &Binary<'a>,
ty: &ast::Type,
slot: &mut IntValue<'a>,
function: FunctionValue<'a>,
ns: &ast::Namespace,
) -> BasicValueEnum<'a>;
fn storage_store(
&self,
binary: &Binary<'a>,
ty: &ast::Type,
existing: bool,
slot: &mut IntValue<'a>,
dest: BasicValueEnum<'a>,
function: FunctionValue<'a>,
ns: &ast::Namespace,
);
fn storage_delete(
&self,
bin: &Binary<'a>,
ty: &Type,
slot: &mut IntValue<'a>,
function: FunctionValue<'a>,
ns: &Namespace,
);
fn set_storage_string(
&self,
bin: &Binary<'a>,
function: FunctionValue<'a>,
slot: PointerValue<'a>,
dest: BasicValueEnum<'a>,
);
fn get_storage_string(
&self,
bin: &Binary<'a>,
function: FunctionValue,
slot: PointerValue<'a>,
) -> PointerValue<'a>;
fn set_storage_extfunc(
&self,
bin: &Binary<'a>,
function: FunctionValue,
slot: PointerValue,
dest: PointerValue,
);
fn get_storage_extfunc(
&self,
bin: &Binary<'a>,
function: FunctionValue,
slot: PointerValue<'a>,
ns: &Namespace,
) -> PointerValue<'a>;
fn get_storage_bytes_subscript(
&self,
bin: &Binary<'a>,
function: FunctionValue,
slot: IntValue<'a>,
index: IntValue<'a>,
) -> IntValue<'a>;
fn set_storage_bytes_subscript(
&self,
bin: &Binary<'a>,
function: FunctionValue,
slot: IntValue<'a>,
index: IntValue<'a>,
value: IntValue<'a>,
);
fn storage_subscript(
&self,
bin: &Binary<'a>,
function: FunctionValue<'a>,
ty: &Type,
slot: IntValue<'a>,
index: BasicValueEnum<'a>,
ns: &Namespace,
) -> IntValue<'a>;
fn storage_push(
&self,
bin: &Binary<'a>,
function: FunctionValue<'a>,
ty: &Type,
slot: IntValue<'a>,
val: Option<BasicValueEnum<'a>>,
ns: &Namespace,
) -> BasicValueEnum<'a>;
fn storage_pop(
&self,
bin: &Binary<'a>,
function: FunctionValue<'a>,
ty: &Type,
slot: IntValue<'a>,
load: bool,
ns: &Namespace,
) -> Option<BasicValueEnum<'a>>;
fn storage_array_length(
&self,
_bin: &Binary<'a>,
_function: FunctionValue,
_slot: IntValue<'a>,
_elem_ty: &Type,
_ns: &Namespace,
) -> IntValue<'a>;
fn keccak256_hash(
&self,
bin: &Binary<'a>,
src: PointerValue,
length: IntValue,
dest: PointerValue,
ns: &Namespace,
);
fn print(&self, bin: &Binary, string: PointerValue, length: IntValue);
fn return_empty_abi(&self, bin: &Binary);
fn return_code<'b>(&self, bin: &'b Binary, ret: IntValue<'b>);
fn return_abi<'b>(&self, bin: &'b Binary, data: PointerValue<'b>, length: IntValue);
fn assert_failure<'b>(&self, bin: &'b Binary, data: PointerValue, length: IntValue);
fn builtin_function(
&self,
binary: &Binary<'a>,
function: FunctionValue<'a>,
builtin_func: &Function,
args: &[BasicMetadataValueEnum<'a>],
ns: &Namespace,
) -> BasicValueEnum<'a>;
fn create_contract<'b>(
&mut self,
bin: &Binary<'b>,
function: FunctionValue<'b>,
success: Option<&mut BasicValueEnum<'b>>,
contract_no: usize,
address: PointerValue<'b>,
encoded_args: BasicValueEnum<'b>,
encoded_args_len: BasicValueEnum<'b>,
gas: IntValue<'b>,
value: Option<IntValue<'b>>,
salt: Option<IntValue<'b>>,
seeds: Option<(PointerValue<'b>, IntValue<'b>)>,
ns: &Namespace,
);
fn external_call<'b>(
&self,
bin: &Binary<'b>,
function: FunctionValue<'b>,
success: Option<&mut BasicValueEnum<'b>>,
payload: PointerValue<'b>,
payload_len: IntValue<'b>,
address: Option<PointerValue<'b>>,
gas: IntValue<'b>,
value: IntValue<'b>,
accounts: Option<(PointerValue<'b>, IntValue<'b>)>,
seeds: Option<(PointerValue<'b>, IntValue<'b>)>,
ty: CallTy,
ns: &Namespace,
);
fn value_transfer<'b>(
&self,
_bin: &Binary<'b>,
_function: FunctionValue,
_success: Option<&mut BasicValueEnum<'b>>,
_address: PointerValue<'b>,
_value: IntValue<'b>,
_ns: &Namespace,
);
fn builtin<'b>(
&self,
bin: &Binary<'b>,
expr: &Expression,
vartab: &HashMap<usize, Variable<'b>>,
function: FunctionValue<'b>,
ns: &Namespace,
) -> BasicValueEnum<'b>;
fn return_data<'b>(&self, bin: &Binary<'b>, function: FunctionValue<'b>) -> PointerValue<'b>;
fn value_transferred<'b>(&self, binary: &Binary<'b>, ns: &Namespace) -> IntValue<'b>;
fn selfdestruct<'b>(&self, binary: &Binary<'b>, addr: ArrayValue<'b>, ns: &Namespace);
fn hash<'b>(
&self,
bin: &Binary<'b>,
function: FunctionValue<'b>,
hash: HashTy,
string: PointerValue<'b>,
length: IntValue<'b>,
ns: &Namespace,
) -> IntValue<'b>;
fn emit_event<'b>(
&self,
bin: &Binary<'b>,
contract: &Contract,
function: FunctionValue<'b>,
event_no: usize,
data: &[BasicValueEnum<'b>],
data_tys: &[Type],
topics: &[BasicValueEnum<'b>],
topic_tys: &[Type],
ns: &Namespace,
);
fn return_abi_data<'b>(
&self,
binary: &Binary<'b>,
data: PointerValue<'b>,
data_len: BasicValueEnum<'b>,
);
}
#[derive(PartialEq, Eq)]
pub enum Generate {
Object,
Assembly,
Linked,
}
impl Target {
fn llvm_target_name(&self) -> &'static str {
if *self == Target::Solana {
"bpfel"
} else {
"wasm32"
}
}
fn llvm_target_triple(&self) -> TargetTriple {
TargetTriple::create(if *self == Target::Solana {
"bpfel-unknown-unknown"
} else {
"wasm32-unknown-unknown-wasm"
})
}
fn llvm_features(&self) -> &'static str {
if *self == Target::Solana {
"+solana"
} else {
""
}
}
}
impl ast::Contract {
pub fn binary<'a>(
&'a self,
ns: &'a ast::Namespace,
context: &'a inkwell::context::Context,
filename: &'a str,
opt: &'a Options,
) -> binary::Binary {
binary::Binary::build(context, self, ns, filename, opt)
}
pub fn emit(&self, ns: &ast::Namespace, opt: &Options) -> Vec<u8> {
if ns.target == Target::EVM {
return vec![];
}
self.code
.get_or_init(move || {
let context = inkwell::context::Context::create();
let filename = ns.files[self.loc.file_no()].path.to_string_lossy();
let binary = self.binary(ns, &context, &filename, opt);
binary.code(Generate::Linked).expect("llvm build")
})
.to_vec()
}
}