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;
pub mod lir;
pub mod sema;
use file_resolver::FileResolver;
use sema::diagnostics;
use solang_parser::pt;
use std::{ffi::OsStr, fmt};
#[derive(Debug, Clone, Copy)]
pub enum Target {
Solana,
Polkadot {
address_length: usize,
value_length: usize,
},
EVM,
Soroban,
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Target::Solana => write!(f, "Solana"),
Target::Polkadot { .. } => write!(f, "Polkadot"),
Target::EVM => write!(f, "EVM"),
Target::Soroban => write!(f, "Soroban"),
}
}
}
impl PartialEq for Target {
fn eq(&self, other: &Self) -> bool {
match self {
Target::Solana => matches!(other, Target::Solana),
Target::Polkadot { .. } => matches!(other, Target::Polkadot { .. }),
Target::EVM => matches!(other, Target::EVM),
Target::Soroban => matches!(other, Target::Soroban),
}
}
}
impl Target {
pub fn is_polkadot(&self) -> bool {
matches!(self, Target::Polkadot { .. })
}
pub const fn default_polkadot() -> Self {
Target::Polkadot {
address_length: 32,
value_length: 16,
}
}
pub fn from(name: &str) -> Option<Self> {
match name {
"solana" => Some(Target::Solana),
"polkadot" => Some(Target::default_polkadot()),
"evm" => Some(Target::EVM),
_ => None,
}
}
pub fn file_extension(&self) -> &'static str {
match self {
Target::Solana => "so",
_ => "wasm",
}
}
pub fn ptr_size(&self) -> u16 {
match *self {
Target::Solana => 64,
_ => 32,
}
}
pub fn selector_length(&self) -> u8 {
match self {
Target::Solana => 8,
_ => 4,
}
}
}
#[cfg(feature = "llvm")]
pub fn compile(
filename: &OsStr,
resolver: &mut FileResolver,
target: Target,
opts: &codegen::Options,
authors: Vec<String>,
version: &str,
) -> (Vec<(Vec<u8>, String)>, sema::ast::Namespace) {
let mut ns = parse_and_resolve(filename, resolver, target);
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, contract_no);
let (abistr, _) = abi::generate_abi(contract_no, &ns, &code, false, &authors, version);
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
}