extern crate core;
pub mod abi;
pub mod codegen;
#[cfg(feature = "llvm")]
pub mod emit;
pub mod file_resolver;
#[cfg(feature = "llvm")]
mod linker;
pub mod standard_json;
#[allow(clippy::result_unit_err)]
pub mod sema;
use file_resolver::FileResolver;
use sema::diagnostics;
use solang_parser::pt;
use std::{ffi::OsStr, fmt};
#[derive(Clone, Copy)]
pub enum Target {
Solana,
Substrate {
address_length: usize,
value_length: usize,
},
EVM,
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Target::Solana => write!(f, "solana"),
Target::Substrate { .. } => write!(f, "substrate"),
Target::EVM => write!(f, "evm"),
}
}
}
impl PartialEq for Target {
fn eq(&self, other: &Self) -> bool {
match self {
Target::Solana => matches!(other, Target::Solana),
Target::Substrate { .. } => matches!(other, Target::Substrate { .. }),
Target::EVM => matches!(other, Target::EVM),
}
}
}
impl Target {
pub fn is_substrate(&self) -> bool {
matches!(self, Target::Substrate { .. })
}
pub const fn default_substrate() -> Self {
Target::Substrate {
address_length: 32,
value_length: 16,
}
}
pub fn from(name: &str) -> Option<Self> {
match name {
"solana" => Some(Target::Solana),
"substrate" => Some(Target::default_substrate()),
"evm" => Some(Target::EVM),
_ => None,
}
}
pub fn file_extension(&self) -> &'static str {
match self {
Target::Solana => "so",
_ => "wasm",
}
}
pub fn ptr_size(&self) -> u16 {
if *self == Target::Solana {
64
} else {
32
}
}
pub fn selector_length(&self) -> u8 {
match self {
Target::Solana => 8,
_ => 4,
}
}
}
#[cfg(feature = "llvm")]
pub fn compile(
filename: &OsStr,
resolver: &mut FileResolver,
opt_level: inkwell::OptimizationLevel,
target: Target,
math_overflow_check: bool,
log_api_return_codes: bool,
) -> (Vec<(Vec<u8>, String)>, sema::ast::Namespace) {
let mut ns = parse_and_resolve(filename, resolver, target);
let opts = codegen::Options {
math_overflow_check,
log_api_return_codes,
opt_level: opt_level.into(),
..Default::default()
};
if ns.diagnostics.any_errors() {
return (Vec::new(), ns);
}
codegen::codegen(&mut ns, &opts);
if ns.diagnostics.any_errors() {
return (Vec::new(), ns);
}
let mut results = Vec::new();
for contract_no in 0..ns.contracts.len() {
let contract = &ns.contracts[contract_no];
if contract.instantiable {
let code = contract.emit(&ns, &opts);
let (abistr, _) = abi::generate_abi(contract_no, &ns, &code, false);
results.push((code, abistr));
};
}
(results, ns)
}
pub fn parse_and_resolve(
filename: &OsStr,
resolver: &mut FileResolver,
target: Target,
) -> sema::ast::Namespace {
let mut ns = sema::ast::Namespace::new(target);
match resolver.resolve_file(None, filename) {
Err(message) => {
ns.diagnostics.push(sema::ast::Diagnostic {
ty: sema::ast::ErrorType::ParserError,
level: sema::ast::Level::Error,
message,
loc: pt::Loc::CommandLine,
notes: Vec::new(),
});
}
Ok(file) => {
sema::sema(&file, resolver, &mut ns);
}
}
ns.diagnostics.sort_and_dedup();
ns
}