#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(unsafe_code)]
#![allow(unknown_lints)]
#![allow(clippy::inline_always)]
#![allow(clippy::redundant_field_names)]
#![cfg_attr(all(not(feature = "std"), feature = "alloc"), no_std)]
#![cfg_attr(all(not(feature = "std"), feature = "alloc"), feature(alloc))]
#[macro_use]
extern crate cfg_if;
cfg_if! {
if #[cfg(all(not(feature = "std"), feature = "alloc"))] {
extern crate core as std;
#[macro_use]
extern crate alloc;
mod imports {
pub use alloc::boxed;
pub use alloc::vec;
pub use alloc::string;
pub use alloc::borrow;
pub use alloc::collections::btree_map;
}
} else {
mod imports {
pub use std::boxed;
pub use std::vec;
pub use std::string;
pub use std::borrow;
pub use std::collections::btree_map;
}
}
}
use imports::*;
use string::String;
use vec::Vec;
#[macro_use]
mod logging;
pub mod ast;
pub mod error;
mod index_str;
mod subs;
use ast::{Demangle, Parse, ParseContext};
use error::{Error, Result};
use index_str::IndexStr;
use std::fmt;
#[derive(Clone, Copy, Debug, Default)]
pub struct DemangleOptions {
pub no_params: bool,
}
pub type OwnedSymbol = Symbol<Vec<u8>>;
pub type BorrowedSymbol<'a> = Symbol<&'a [u8]>;
#[derive(Clone, Debug, PartialEq)]
pub struct Symbol<T> {
raw: T,
substitutions: subs::SubstitutionTable,
parsed: ast::MangledName,
}
impl<T> Symbol<T>
where
T: AsRef<[u8]>,
{
pub fn new(raw: T) -> Result<Symbol<T>> {
let mut substitutions = subs::SubstitutionTable::new();
let parsed = {
let ctx = ParseContext::default();
let input = IndexStr::new(raw.as_ref());
let (parsed, tail) = ast::MangledName::parse(&ctx, &mut substitutions, input)?;
debug_assert!(ctx.recursion_level() == 0);
if tail.is_empty() {
parsed
} else {
return Err(Error::UnexpectedText);
}
};
let symbol = Symbol {
raw: raw,
substitutions: substitutions,
parsed: parsed,
};
log!(
"Successfully parsed '{}' as
AST = {:#?}
substitutions = {:#?}",
String::from_utf8_lossy(symbol.raw.as_ref()),
symbol.parsed,
symbol.substitutions
);
Ok(symbol)
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn demangle(&self, options: &DemangleOptions) -> ::std::result::Result<String, fmt::Error> {
let mut out = String::new();
{
let mut ctx = ast::DemangleContext::new(
&self.substitutions,
self.raw.as_ref(),
*options,
&mut out,
);
self.parsed.demangle(&mut ctx, None)?;
}
Ok(out)
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn structured_demangle<W: DemangleWrite>(&self, out: &mut W, options: &DemangleOptions) -> fmt::Result {
let mut ctx = ast::DemangleContext::new(
&self.substitutions,
self.raw.as_ref(),
*options,
out,
);
self.parsed.demangle(&mut ctx, None)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum DemangleNodeType {
Prefix,
TemplatePrefix,
TemplateArgs,
UnqualifiedName,
TemplateParam,
Decltype,
DataMemberPrefix,
NestedName,
}
pub trait DemangleWrite {
fn push_demangle_node(&mut self, _: DemangleNodeType) {}
fn write_string(&mut self, s: &str) -> fmt::Result;
fn pop_demangle_node(&mut self) {}
}
impl<W: fmt::Write> DemangleWrite for W {
fn write_string(&mut self, s: &str) -> fmt::Result {
fmt::Write::write_str(self, s)
}
}
impl<'a, T> Symbol<&'a T>
where T: AsRef<[u8]> + ?Sized,
{
pub fn with_tail(input: &'a T) -> Result<(BorrowedSymbol<'a>, &'a [u8])> {
let mut substitutions = subs::SubstitutionTable::new();
let ctx = ParseContext::default();
let idx_str = IndexStr::new(input.as_ref());
let (parsed, tail) = ast::MangledName::parse(&ctx, &mut substitutions, idx_str)?;
debug_assert!(ctx.recursion_level() == 0);
let symbol = Symbol {
raw: input.as_ref(),
substitutions: substitutions,
parsed: parsed,
};
log!(
"Successfully parsed '{}' as
AST = {:#?}
substitutions = {:#?}",
String::from_utf8_lossy(symbol.raw),
symbol.parsed,
symbol.substitutions
);
Ok((symbol, tail.into()))
}
}
impl<T> fmt::Display for Symbol<T>
where
T: AsRef<[u8]>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut out = String::new();
{
let options = DemangleOptions::default();
let mut ctx = ast::DemangleContext::new(
&self.substitutions,
self.raw.as_ref(),
options,
&mut out,
);
self.parsed.demangle(&mut ctx, None).map_err(|err| {
log!("Demangling error: {:#?}", err);
fmt::Error
})?;
}
write!(f, "{}", &out)
}
}