use super::{DemangleWrite, DemangleNodeType, DemangleOptions};
use error::{self, Result};
use index_str::IndexStr;
use std::cell::Cell;
#[cfg(feature = "logging")]
use std::cell::RefCell;
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops;
use std::ptr;
use subs::{Substitutable, SubstitutionTable};
use string::String;
use vec::Vec;
use boxed::Box;
struct AutoLogParse;
#[cfg(feature = "logging")]
thread_local! {
static LOG_DEPTH: RefCell<usize> = RefCell::new(0);
}
impl AutoLogParse {
#[cfg(feature = "logging")]
fn new(production: &'static str, input: IndexStr<'_>) -> AutoLogParse {
LOG_DEPTH.with(|depth| {
if *depth.borrow() == 0 {
println!();
}
let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect();
log!(
"{}({} \"{}\"",
indent,
production,
String::from_utf8_lossy(input.as_ref())
);
*depth.borrow_mut() += 1;
});
AutoLogParse
}
#[cfg(not(feature = "logging"))]
#[inline(always)]
fn new(_: &'static str, _: IndexStr) -> AutoLogParse {
AutoLogParse
}
}
#[cfg(feature = "logging")]
impl Drop for AutoLogParse {
fn drop(&mut self) {
LOG_DEPTH.with(|depth| {
*depth.borrow_mut() -= 1;
let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect();
log!("{})", indent);
});
}
}
macro_rules! try_begin_parse {
( $production:expr , $ctx:expr , $input:expr ) => {
let _log = AutoLogParse::new($production, $input);
let _auto_check_recursion = AutoParseRecursion::new($ctx)?;
}
}
struct AutoLogDemangle;
impl AutoLogDemangle {
#[cfg(feature = "logging")]
fn new<P, W>(
production: &P,
ctx: &DemangleContext<W>,
scope: Option<ArgScopeStack>,
is_inner: bool,
) -> AutoLogDemangle
where
P: ?Sized + fmt::Debug,
W: DemangleWrite,
{
LOG_DEPTH.with(|depth| {
if *depth.borrow() == 0 {
println!();
}
let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect();
log!("{}(", indent);
log!(
"{} {}{:?}",
indent,
if is_inner { "as_inner: " } else { "" },
production
);
log!("{} inner = {:?}", indent, ctx.inner);
log!("{} scope = {:?}", indent, scope);
*depth.borrow_mut() += 1;
});
AutoLogDemangle
}
#[cfg(not(feature = "logging"))]
#[inline(always)]
fn new<P, W>(
_: &P,
_: &DemangleContext<W>,
_: Option<ArgScopeStack>,
_: bool,
) -> AutoLogDemangle
where
P: ?Sized + fmt::Debug,
W: DemangleWrite,
{
AutoLogDemangle
}
}
#[cfg(feature = "logging")]
impl Drop for AutoLogDemangle {
fn drop(&mut self) {
LOG_DEPTH.with(|depth| {
*depth.borrow_mut() -= 1;
let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect();
log!("{})", indent);
});
}
}
macro_rules! try_begin_demangle {
( $production:expr, $ctx:expr, $scope:expr ) => {{
let _log = AutoLogDemangle::new($production, $ctx, $scope, false);
&mut AutoParseDemangle::new($ctx)?
}}
}
macro_rules! try_begin_demangle_as_inner {
( $production:expr, $ctx:expr, $scope:expr ) => {{
let _log = AutoLogDemangle::new($production, $ctx, $scope, true);
&mut AutoParseDemangle::new($ctx)?
}}
}
#[derive(Debug, Default, Clone, Copy)]
struct ParseContextState {
recursion_level: u32,
in_conversion: bool,
}
#[derive(Debug, Clone)]
pub struct ParseContext {
max_recursion: u32,
state: Cell<ParseContextState>,
}
impl Default for ParseContext {
fn default() -> ParseContext {
ParseContext {
max_recursion: 64,
state: Cell::new(ParseContextState::default()),
}
}
}
impl ParseContext {
pub fn recursion_level(&self) -> u32 {
self.state.get().recursion_level
}
#[inline]
fn enter_recursion(&self) -> error::Result<()> {
let mut state = self.state.get();
let new_recursion_level = state.recursion_level + 1;
if new_recursion_level >= self.max_recursion {
log!("Hit too much recursion at level {}", self.max_recursion);
Err(error::Error::TooMuchRecursion)
} else {
state.recursion_level = new_recursion_level;
self.state.set(state);
Ok(())
}
}
#[inline]
fn exit_recursion(&self) {
let mut state = self.state.get();
debug_assert!(state.recursion_level >= 1);
state.recursion_level -= 1;
self.state.set(state);
}
#[inline]
fn in_conversion(&self) -> bool {
self.state.get().in_conversion
}
fn set_in_conversion(&self, in_conversion: bool) -> bool {
let mut state = self.state.get();
let previously_in_conversion = state.in_conversion;
state.in_conversion = in_conversion;
self.state.set(state);
previously_in_conversion
}
}
struct AutoParseRecursion<'a>(&'a ParseContext);
impl<'a> AutoParseRecursion<'a> {
#[inline]
fn new(ctx: &'a ParseContext) -> error::Result<AutoParseRecursion<'a>> {
ctx.enter_recursion()?;
Ok(AutoParseRecursion(ctx))
}
}
impl<'a> Drop for AutoParseRecursion<'a> {
#[inline]
fn drop(&mut self) {
self.0.exit_recursion();
}
}
#[doc(hidden)]
pub trait Parse: Sized {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Self, IndexStr<'b>)>;
}
trait GetTemplateArgs {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs>;
}
#[derive(Debug)]
pub(crate) enum LeafName<'a> {
SourceName(&'a SourceName),
WellKnownComponent(&'a WellKnownComponent),
Closure(&'a ClosureTypeName),
UnnamedType(&'a UnnamedTypeName),
}
impl<'subs, W> DemangleAsLeaf<'subs, W> for LeafName<'subs>
where
W: 'subs + DemangleWrite,
{
fn demangle_as_leaf<'me, 'ctx>(
&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
) -> fmt::Result {
match *self {
LeafName::SourceName(sn) => sn.demangle(ctx, None),
LeafName::Closure(c) => c.demangle(ctx, None),
LeafName::WellKnownComponent(wkc) => wkc.demangle_as_leaf(ctx),
LeafName::UnnamedType(utn) => utn.demangle_as_leaf(ctx),
}
}
}
pub(crate) trait GetLeafName<'a> {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>>;
}
pub(crate) trait IsCtorDtorConversion {
fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool;
}
trait ArgScope<'me, 'ctx>: fmt::Debug {
fn leaf_name(&'me self) -> Result<LeafName<'ctx>>;
fn get_template_arg(&'me self, index: usize) -> Result<(&'ctx TemplateArg, &'ctx TemplateArgs)>;
fn get_function_arg(&'me self, index: usize) -> Result<&'ctx Type>;
}
#[derive(Copy, Clone, Debug)]
pub struct ArgScopeStack<'prev, 'subs>
where
'subs: 'prev,
{
item: &'subs dyn ArgScope<'subs, 'subs>,
in_arg: Option<(usize, &'subs TemplateArgs)>,
prev: Option<&'prev ArgScopeStack<'prev, 'subs>>,
}
trait ArgScopeStackExt<'prev, 'subs>: Copy {
fn push(
&'prev self,
item: &'subs dyn ArgScope<'subs, 'subs>,
) -> Option<ArgScopeStack<'prev, 'subs>>;
}
impl<'prev, 'subs> ArgScopeStackExt<'prev, 'subs> for Option<ArgScopeStack<'prev, 'subs>> {
fn push(
&'prev self,
item: &'subs dyn ArgScope<'subs, 'subs>,
) -> Option<ArgScopeStack<'prev, 'subs>> {
log!("ArgScopeStack::push: {:?}", item);
Some(ArgScopeStack {
prev: self.as_ref(),
in_arg: None,
item: item,
})
}
}
impl<'prev, 'subs> ArgScope<'prev, 'subs> for Option<ArgScopeStack<'prev, 'subs>> {
fn leaf_name(&'prev self) -> Result<LeafName<'subs>> {
let mut scope = self.as_ref();
while let Some(s) = scope {
if let Ok(c) = s.item.leaf_name() {
return Ok(c);
}
scope = s.prev;
}
Err(error::Error::BadLeafNameReference)
}
fn get_template_arg(&'prev self, idx: usize) -> Result<(&'subs TemplateArg, &'subs TemplateArgs)> {
let mut scope = self.as_ref();
while let Some(s) = scope {
if let Ok((arg, args)) = s.item.get_template_arg(idx) {
if let Some((in_idx, in_args)) = s.in_arg {
if args as *const TemplateArgs == in_args as *const TemplateArgs &&
in_idx <= idx {
return Err(error::Error::ForwardTemplateArgReference);
}
}
return Ok((arg, args));
}
scope = s.prev;
}
Err(error::Error::BadTemplateArgReference)
}
fn get_function_arg(&'prev self, idx: usize) -> Result<&'subs Type> {
let mut scope = self.as_ref();
while let Some(s) = scope {
if let Ok(arg) = s.item.get_function_arg(idx) {
return Ok(arg);
}
scope = s.prev;
}
Err(error::Error::BadFunctionArgReference)
}
}
#[derive(Debug, Copy, Clone)]
struct DemangleState {
pub recursion_level: u32,
}
struct AutoParseDemangle<'a, 'b, W: 'a + DemangleWrite>(&'b mut DemangleContext<'a, W>);
impl<'a, 'b, W: 'a + DemangleWrite> AutoParseDemangle<'a, 'b, W> {
#[inline]
fn new(ctx: &'b mut DemangleContext<'a, W>) -> std::result::Result<Self, fmt::Error> {
ctx.enter_recursion()?;
Ok(AutoParseDemangle(ctx))
}
}
impl<'a, 'b, W: 'a + DemangleWrite> std::ops::Deref for AutoParseDemangle<'a, 'b, W> {
type Target = DemangleContext<'a, W>;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a, 'b, W: 'a + DemangleWrite> std::ops::DerefMut for AutoParseDemangle<'a, 'b, W> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<'a, 'b, W: 'a + DemangleWrite> Drop for AutoParseDemangle<'a, 'b, W> {
#[inline]
fn drop(&mut self) {
self.0.exit_recursion();
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct DemangleContext<'a, W>
where
W: 'a + DemangleWrite,
{
subs: &'a SubstitutionTable,
max_recursion: u32,
inner: Vec<&'a dyn DemangleAsInner<'a, W>>,
input: &'a [u8],
source_name: Option<&'a str>,
out: &'a mut W,
bytes_written: usize,
last_char_written: Option<char>,
is_lambda_arg: bool,
is_template_prefix: bool,
is_template_prefix_in_nested_name: bool,
is_template_argument_pack: bool,
show_params: bool,
state: Cell<DemangleState>,
}
impl<'a, W> fmt::Write for DemangleContext<'a, W>
where
W: 'a + DemangleWrite,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
if s.is_empty() {
return Ok(());
}
log!("DemangleContext::write: '{}'", s);
self.out.write_string(s).map(|_| {
self.last_char_written = s.chars().last();
self.bytes_written += s.len();
})
}
}
impl<'a, W> DemangleContext<'a, W>
where
W: 'a + DemangleWrite,
{
pub fn new(
subs: &'a SubstitutionTable,
input: &'a [u8],
options: DemangleOptions,
out: &'a mut W,
) -> DemangleContext<'a, W> {
DemangleContext {
subs: subs,
max_recursion: 128,
inner: vec![],
input: input,
source_name: None,
out: out,
bytes_written: 0,
last_char_written: None,
is_lambda_arg: false,
is_template_prefix: false,
is_template_prefix_in_nested_name: false,
is_template_argument_pack: false,
show_params: !options.no_params,
state: Cell::new(DemangleState {
recursion_level: 0,
}),
}
}
pub fn recursion_level(&self) -> u32 {
self.state.get().recursion_level
}
#[inline]
fn enter_recursion(&self) -> fmt::Result {
let mut state = self.state.get();
let new_recursion_level = state.recursion_level + 1;
if new_recursion_level >= self.max_recursion {
log!("Hit too much recursion at level {}", self.max_recursion);
Err(Default::default())
} else {
state.recursion_level = new_recursion_level;
self.state.set(state);
Ok(())
}
}
#[inline]
fn exit_recursion(&self) {
let mut state = self.state.get();
debug_assert!(state.recursion_level >= 1);
state.recursion_level -= 1;
self.state.set(state);
}
#[inline]
fn ensure(&mut self, ch: char) -> fmt::Result {
if self.last_char_written == Some(ch) {
Ok(())
} else {
write!(self, "{}", ch)?;
Ok(())
}
}
#[inline]
fn ensure_space(&mut self) -> fmt::Result {
self.ensure(' ')
}
#[inline]
fn push_inner(&mut self, item: &'a dyn DemangleAsInner<'a, W>) {
log!("DemangleContext::push_inner: {:?}", item);
self.inner.push(item);
}
#[inline]
fn pop_inner(&mut self) -> Option<&'a dyn DemangleAsInner<'a, W>> {
let popped = self.inner.pop();
log!("DemangleContext::pop_inner: {:?}", popped);
popped
}
#[inline]
fn pop_inner_if(&mut self, inner: &'a dyn DemangleAsInner<'a, W>) -> bool {
let last = match self.inner.last() {
None => return false,
Some(last) => *last,
};
if ptr::eq(last, inner) {
self.inner.pop();
true
} else {
false
}
}
fn demangle_inner_prefixes<'prev>(
&mut self,
scope: Option<ArgScopeStack<'prev, 'a>>,
) -> fmt::Result {
log!("DemangleContext::demangle_inner_prefixes");
let mut new_inner = vec![];
while let Some(inner) = self.pop_inner() {
if inner
.downcast_to_function_type()
.map_or(false, |f| !f.cv_qualifiers.is_empty())
{
log!(
"DemangleContext::demangle_inner_prefixes: not a prefix, saving: {:?}",
inner
);
new_inner.push(inner);
} else {
log!(
"DemangleContext::demangle_inner_prefixes: demangling prefix: {:?}",
inner
);
inner.demangle_as_inner(self, scope)?;
}
}
new_inner.reverse();
self.inner = new_inner;
Ok(())
}
fn demangle_inners<'prev>(
&mut self,
scope: Option<ArgScopeStack<'prev, 'a>>,
) -> fmt::Result {
while let Some(inner) = self.pop_inner() {
inner.demangle_as_inner(self, scope)?;
}
Ok(())
}
fn set_source_name(&mut self, start: usize, end: usize) {
let ident = &self.input[start..end];
self.source_name = std::str::from_utf8(ident).ok();
}
fn push_demangle_node(&mut self, t: DemangleNodeType) {
self.out.push_demangle_node(t);
}
fn pop_demangle_node(&mut self) {
self.out.pop_demangle_node();
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct AutoDemangleContextInnerBarrier<'ctx, 'a, W>
where
W: 'a + DemangleWrite,
'a: 'ctx,
{
ctx: &'ctx mut DemangleContext<'a, W>,
saved_inner: Vec<&'a dyn DemangleAsInner<'a, W>>,
}
impl<'ctx, 'a, W> AutoDemangleContextInnerBarrier<'ctx, 'a, W>
where
W: 'a + DemangleWrite,
'a: 'ctx,
{
pub fn new(ctx: &'ctx mut DemangleContext<'a, W>) -> Self {
let mut saved_inner = vec![];
mem::swap(&mut saved_inner, &mut ctx.inner);
AutoDemangleContextInnerBarrier {
ctx: ctx,
saved_inner: saved_inner,
}
}
}
impl<'ctx, 'a, W> ops::Deref for AutoDemangleContextInnerBarrier<'ctx, 'a, W>
where
W: 'a + DemangleWrite,
'a: 'ctx,
{
type Target = DemangleContext<'a, W>;
fn deref(&self) -> &Self::Target {
self.ctx
}
}
impl<'ctx, 'a, W> ops::DerefMut for AutoDemangleContextInnerBarrier<'ctx, 'a, W>
where
W: 'a + DemangleWrite,
'a: 'ctx,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.ctx
}
}
impl<'ctx, 'a, W> Drop for AutoDemangleContextInnerBarrier<'ctx, 'a, W>
where
W: 'a + DemangleWrite,
'a: 'ctx,
{
fn drop(&mut self) {
if !self.ctx.inner.is_empty() {
log!("Context inner was not emptied, did demangling fail?");
}
mem::swap(&mut self.saved_inner, &mut self.ctx.inner);
}
}
macro_rules! inner_barrier {
( $ctx:ident ) => {
let mut _ctx = AutoDemangleContextInnerBarrier::new($ctx);
let $ctx = &mut _ctx;
}
}
#[doc(hidden)]
pub trait Demangle<'subs, W>: fmt::Debug
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result;
}
#[doc(hidden)]
pub trait DemangleAsInner<'subs, W>: Demangle<'subs, W>
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
self.demangle(ctx, scope)
}
fn downcast_to_type(&self) -> Option<&Type> {
None
}
fn downcast_to_function_type(&self) -> Option<&FunctionType> {
None
}
fn downcast_to_array_type(&self) -> Option<&ArrayType> {
None
}
fn downcast_to_pointer_to_member(&self) -> Option<&PointerToMemberType> {
None
}
fn is_qualified(&self) -> bool {
false
}
}
pub(crate) trait DemangleAsLeaf<'subs, W>
where
W: 'subs + DemangleWrite,
{
fn demangle_as_leaf<'me, 'ctx>(
&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
) -> fmt::Result;
}
macro_rules! reference_newtype {
( $newtype_name:ident , $oldtype:ty ) => {
#[derive(Debug)]
struct $newtype_name($oldtype);
impl $newtype_name {
#[allow(clippy::ptr_arg)]
#[allow(unsafe_code)]
fn new(types: &$oldtype) -> &$newtype_name {
unsafe {
&*(types as *const $oldtype as *const $newtype_name)
}
}
}
impl Drop for $newtype_name {
fn drop(&mut self) {
unreachable!("Dropping implies we dereferenced and took ownership, which \
is not safe for this newtype");
}
}
impl ops::Deref for $newtype_name {
type Target = $oldtype;
fn deref(&self) -> &Self::Target {
&self.0
}
}
}
}
reference_newtype!(FunctionArgList, Vec<TypeHandle>);
reference_newtype!(FunctionArgListAndReturnType, Vec<TypeHandle>);
reference_newtype!(FunctionArgSlice, [TypeHandle]);
impl<'subs, W> Demangle<'subs, W> for FunctionArgSlice
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
let mut saw_needs_paren = false;
let (needs_space, needs_paren) = ctx.inner
.iter()
.rev()
.map(|inner| {
if inner.downcast_to_pointer_to_member().is_some() {
(true, true)
} else {
match inner.downcast_to_type() {
Some(&Type::Qualified(..))
| Some(&Type::Complex(_))
| Some(&Type::Imaginary(_))
| Some(&Type::PointerToMember(_)) => (true, true),
Some(&Type::PointerTo(_))
| Some(&Type::LvalueRef(_))
| Some(&Type::RvalueRef(_)) => (false, true),
_ => (false, false),
}
}
})
.take_while(|&(_, needs_paren)| {
if saw_needs_paren {
false
} else {
saw_needs_paren |= needs_paren;
true
}
})
.fold((false, false), |(space, paren), (next_space, next_paren)| {
(space || next_space, paren || next_paren)
});
if needs_paren {
let needs_space = needs_space || match ctx.last_char_written {
Some('(') | Some('*') => false,
_ => true,
};
if needs_space {
ctx.ensure_space()?;
}
write!(ctx, "(")?;
}
ctx.demangle_inner_prefixes(scope)?;
if needs_paren {
write!(ctx, ")")?;
}
write!(ctx, "(")?;
if self.len() == 1 && self[0].is_void() {
write!(ctx, ")")?;
return Ok(());
}
let mut need_comma = false;
for arg in self.iter() {
if need_comma {
write!(ctx, ", ")?;
}
arg.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ")")?;
ctx.demangle_inners(scope)
}
}
impl<'subs, W> Demangle<'subs, W> for FunctionArgList
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
FunctionArgSlice::new(&self.0[..]).demangle(ctx, scope)
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for FunctionArgList
where
W: 'subs + DemangleWrite,
{
}
impl<'subs, W> Demangle<'subs, W> for FunctionArgListAndReturnType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
FunctionArgSlice::new(&self.0[1..]).demangle(ctx, scope)
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for FunctionArgListAndReturnType
where
W: 'subs + DemangleWrite,
{
}
macro_rules! define_handle {
(
$(#[$attr:meta])*
pub enum $typename:ident
) => {
define_handle! {
$(#[$attr])*
pub enum $typename {}
}
};
(
$(#[$attr:meta])*
pub enum $typename:ident {
$(
$( #[$extra_attr:meta] )*
extra $extra_variant:ident ( $extra_variant_ty:ty ),
)*
}
) => {
$(#[$attr])*
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum $typename {
WellKnown(WellKnownComponent),
BackReference(usize),
$(
$( #[$extra_attr] )*
$extra_variant( $extra_variant_ty ),
)*
}
impl $typename {
pub fn back_reference(&self) -> Option<usize> {
match *self {
$typename::BackReference(n) => Some(n),
_ => None,
}
}
}
impl<'subs, W> Demangle<'subs, W> for $typename
where
W: 'subs + DemangleWrite
{
#[inline]
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>)
-> fmt::Result {
match *self {
$typename::WellKnown(ref comp) => comp.demangle(ctx, scope),
$typename::BackReference(idx) => ctx.subs[idx].demangle(ctx, scope),
$(
$typename::$extra_variant(ref extra) => extra.demangle(ctx, scope),
)*
}
}
}
impl<'a> GetLeafName<'a> for $typename {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
$typename::WellKnown(ref wk) => wk.get_leaf_name(subs),
$typename::BackReference(idx) => {
subs.get(idx).and_then(|s| s.get_leaf_name(subs))
}
$(
$typename::$extra_variant(ref e) => e.get_leaf_name(subs),
)*
}
}
}
};
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NonSubstitution(usize);
impl<'subs, W> Demangle<'subs, W> for NonSubstitution
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
ctx.subs.non_substitution(self.0).demangle(ctx, scope)
}
}
impl<'a> GetLeafName<'a> for NonSubstitution {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
subs.get_non_substitution(self.0)
.and_then(|ns| ns.get_leaf_name(subs))
}
}
macro_rules! define_vocabulary {
( $(#[$attr:meta])* pub enum $typename:ident {
$($variant:ident ( $mangled:expr, $printable:expr )),*
} ) => {
$(#[$attr])*
pub enum $typename {
$(
#[doc=$printable]
$variant
),*
}
impl Parse for $typename {
fn parse<'a, 'b>(ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>)
-> Result<($typename, IndexStr<'b>)> {
try_begin_parse!(stringify!($typename), ctx, input);
let mut found_prefix = false;
$(
if let Some((head, tail)) = input.try_split_at($mangled.len()) {
if head.as_ref() == $mangled {
return Ok(($typename::$variant, tail));
}
} else {
found_prefix |= 0 < input.len() &&
input.len() < $mangled.len() &&
input.as_ref() == &$mangled[..input.len()];
}
)*
if input.is_empty() || found_prefix {
Err(error::Error::UnexpectedEnd)
} else {
Err(error::Error::UnexpectedText)
}
}
}
impl<'subs, W> Demangle<'subs, W> for $typename
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
write!(ctx, "{}", match *self {
$(
$typename::$variant => $printable
),*
})
}
}
impl $typename {
#[allow(dead_code)]
#[inline]
fn starts_with(byte: u8) -> bool {
$(
if $mangled[0] == byte {
return true;
}
)*
false
}
}
};
( $(#[$attr:meta])* pub enum $typename:ident {
$($variant:ident ( $mangled:expr, $printable:expr, $userdata:expr)),*
}
impl $typename2:ident {
fn $fn_name:ident(&self) -> $userdata_ty:ty;
} ) => {
define_vocabulary! {
$(#[$attr])*
pub enum $typename {
$(
$variant ( $mangled, $printable )
),*
}
}
impl $typename2 {
fn $fn_name(&self) -> $userdata_ty {
match *self {
$(
$typename2::$variant => $userdata,
)*
}
}
}
};
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MangledName {
Encoding(Encoding, Vec<CloneSuffix>),
BlockInvoke(Encoding, Option<isize>),
Type(TypeHandle),
GlobalCtorDtor(GlobalCtorDtor),
}
impl Parse for MangledName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(MangledName, IndexStr<'b>)> {
try_begin_parse!("MangledName", ctx, input);
if let Ok(tail) = consume(b"_Z", input).or_else(|_| consume(b"__Z", input)) {
let (encoding, tail) = Encoding::parse(ctx, subs, tail)?;
let (clone_suffixes, tail) = zero_or_more(ctx, subs, tail)?;
return Ok((MangledName::Encoding(encoding, clone_suffixes), tail));
}
if let Ok(tail) = consume(b"___Z", input).or_else(|_| consume(b"____Z", input)) {
let (encoding, tail) = Encoding::parse(ctx, subs, tail)?;
let tail = consume(b"_block_invoke", tail)?;
let tail_opt = match consume(b"_", tail) {
Ok(tail) => Some(parse_number(10, false, tail)?),
Err(_) => parse_number(10, false, tail).ok(),
};
let (digits, tail) = match tail_opt {
Some((digits, tail)) => (Some(digits), tail),
None => (None, tail),
};
return Ok((MangledName::BlockInvoke(encoding, digits), tail));
}
if let Ok(tail) = consume(b"_GLOBAL_", input) {
let (global_ctor_dtor, tail) = GlobalCtorDtor::parse(ctx, subs, tail)?;
return Ok((MangledName::GlobalCtorDtor(global_ctor_dtor), tail));
}
let (ty, tail) = TypeHandle::parse(ctx, subs, input)?;
Ok((MangledName::Type(ty), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for MangledName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
MangledName::Encoding(ref enc, ref cs) => {
enc.demangle(ctx, scope)?;
if !cs.is_empty() && ctx.show_params {
for clone_suffix in cs {
clone_suffix.demangle(ctx, scope)?;
}
}
Ok(())
},
MangledName::BlockInvoke(ref enc, _) => {
write!(ctx, "invocation function for block in ")?;
enc.demangle(ctx, scope)?;
Ok(())
}
MangledName::Type(ref ty) => ty.demangle(ctx, scope),
MangledName::GlobalCtorDtor(ref gcd) => gcd.demangle(ctx, scope),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Encoding {
Function(Name, BareFunctionType),
Data(Name),
Special(SpecialName),
}
impl Parse for Encoding {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Encoding, IndexStr<'b>)> {
try_begin_parse!("Encoding", ctx, input);
if let Ok((name, tail)) = Name::parse(ctx, subs, input) {
if let Ok((ty, tail)) = BareFunctionType::parse(ctx, subs, tail) {
return Ok((Encoding::Function(name, ty), tail));
} else {
return Ok((Encoding::Data(name), tail));
}
}
let (name, tail) = SpecialName::parse(ctx, subs, input)?;
Ok((Encoding::Special(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Encoding
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
inner_barrier!(ctx);
match *self {
Encoding::Function(ref name, ref fun_ty) => {
debug_assert!(!fun_ty.0.is_empty());
let scope = if let Some(leaf) = name.get_leaf_name(ctx.subs) {
match leaf {
LeafName::SourceName(leaf) => scope.push(leaf),
LeafName::WellKnownComponent(leaf) => scope.push(leaf),
LeafName::Closure(leaf) => scope.push(leaf),
LeafName::UnnamedType(leaf) => scope.push(leaf),
}
} else {
scope
};
let scope = if let Some(template_args) = name.get_template_args(ctx.subs) {
let scope = scope.push(template_args);
if ctx.show_params && !name.is_ctor_dtor_conversion(ctx.subs) {
fun_ty.0[0].demangle(ctx, scope)?;
write!(ctx, " ")?;
}
scope
} else {
scope
};
if ctx.show_params {
ctx.push_inner(self);
name.demangle(ctx, scope)?;
if ctx.pop_inner_if(self) {
self.demangle_as_inner(ctx, scope)?;
}
} else {
name.demangle(ctx, scope)?;
}
Ok(())
}
Encoding::Data(ref name) => name.demangle(ctx, scope),
Encoding::Special(ref name) => name.demangle(ctx, scope),
}
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for Encoding
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
if let Encoding::Function(ref name, ref fun_ty) = *self {
let (scope, function_args) =
if let Some(template_args) = name.get_template_args(ctx.subs) {
let scope = scope.push(template_args);
let function_args = FunctionArgListAndReturnType::new(&fun_ty.0);
(scope, function_args as &dyn DemangleAsInner<W>)
} else {
let function_args = FunctionArgList::new(&fun_ty.0);
(scope, function_args as &dyn DemangleAsInner<W>)
};
function_args.demangle_as_inner(ctx, scope)
} else {
unreachable!("we only push Encoding::Function onto the inner stack");
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CloneSuffix(CloneTypeIdentifier, Vec<isize>);
impl Parse for CloneSuffix {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(CloneSuffix, IndexStr<'b>)> {
try_begin_parse!("CloneSuffix", ctx, input);
let tail = consume(b".", input)?;
let (identifier, mut tail) = CloneTypeIdentifier::parse(ctx, subs, tail)?;
let mut numbers = Vec::with_capacity(1);
while let Ok((n, t)) = consume(b".", tail).and_then(|t| parse_number(10, false, t)) {
numbers.push(n);
tail = t;
}
let clone_suffix = CloneSuffix(identifier, numbers);
Ok((clone_suffix, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for CloneSuffix
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
write!(ctx, " [clone")?;
self.0.demangle(ctx, scope)?;
for nonnegative in &self.1 {
write!(ctx, ".{}", nonnegative)?;
}
write!(ctx, "]")?;
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum GlobalCtorDtor {
Ctor(Box<MangledName>),
Dtor(Box<MangledName>),
}
impl Parse for GlobalCtorDtor {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(GlobalCtorDtor, IndexStr<'b>)> {
try_begin_parse!("GlobalCtorDtor", ctx, input);
let tail = match input.next_or(error::Error::UnexpectedEnd)? {
(b'_', t) | (b'.', t) | (b'$', t) => t,
_ => return Err(error::Error::UnexpectedText),
};
match tail.next_or(error::Error::UnexpectedEnd)? {
(b'I', tail) => {
let tail = consume(b"_", tail)?;
let (name, tail) = MangledName::parse(ctx, subs, tail)?;
Ok((GlobalCtorDtor::Ctor(Box::new(name)), tail))
}
(b'D', tail) => {
let tail = consume(b"_", tail)?;
let (name, tail) = MangledName::parse(ctx, subs, tail)?;
Ok((GlobalCtorDtor::Dtor(Box::new(name)), tail))
}
_ => Err(error::Error::UnexpectedText),
}
}
}
impl<'subs, W> Demangle<'subs, W> for GlobalCtorDtor
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
inner_barrier!(ctx);
let saved_show_params = ctx.show_params;
ctx.show_params = true;
let ret = match *self {
GlobalCtorDtor::Ctor(ref name) => {
write!(ctx, "global constructors keyed to ")?;
name.demangle(ctx, scope)
}
GlobalCtorDtor::Dtor(ref name) => {
write!(ctx, "global destructors keyed to ")?;
name.demangle(ctx, scope)
}
};
ctx.show_params = saved_show_params;
ret
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Name {
Nested(NestedName),
Unscoped(UnscopedName),
UnscopedTemplate(UnscopedTemplateNameHandle, TemplateArgs),
Local(LocalName),
}
impl Parse for Name {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Name, IndexStr<'b>)> {
try_begin_parse!("Name", ctx, input);
if let Ok((name, tail)) = NestedName::parse(ctx, subs, input) {
return Ok((Name::Nested(name), tail));
}
if let Ok((name, tail)) = UnscopedName::parse(ctx, subs, input) {
if tail.peek() == Some(b'I') {
let name = UnscopedTemplateName(name);
let idx = subs.insert(Substitutable::UnscopedTemplateName(name));
let handle = UnscopedTemplateNameHandle::BackReference(idx);
let (args, tail) = TemplateArgs::parse(ctx, subs, tail)?;
return Ok((Name::UnscopedTemplate(handle, args), tail));
} else {
return Ok((Name::Unscoped(name), tail));
}
}
if let Ok((name, tail)) = UnscopedTemplateNameHandle::parse(ctx, subs, input) {
let (args, tail) = TemplateArgs::parse(ctx, subs, tail)?;
return Ok((Name::UnscopedTemplate(name, args), tail));
}
let (name, tail) = LocalName::parse(ctx, subs, input)?;
Ok((Name::Local(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Name
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
Name::Nested(ref nested) => nested.demangle(ctx, scope),
Name::Unscoped(ref unscoped) => unscoped.demangle(ctx, scope),
Name::UnscopedTemplate(ref template, ref args) => {
template.demangle(ctx, scope.push(args))?;
args.demangle(ctx, scope)
}
Name::Local(ref local) => local.demangle(ctx, scope),
}
}
}
impl GetTemplateArgs for Name {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
match *self {
Name::UnscopedTemplate(_, ref args) => Some(args),
Name::Nested(ref nested) => nested.get_template_args(subs),
Name::Local(ref local) => local.get_template_args(subs),
Name::Unscoped(_) => None,
}
}
}
impl<'a> GetLeafName<'a> for Name {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
Name::UnscopedTemplate(ref templ, _) => templ.get_leaf_name(subs),
Name::Nested(ref nested) => nested.get_leaf_name(subs),
Name::Unscoped(ref unscoped) => unscoped.get_leaf_name(subs),
Name::Local(ref local) => local.get_leaf_name(subs),
}
}
}
impl IsCtorDtorConversion for Name {
fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool {
match *self {
Name::Unscoped(ref unscoped) => unscoped.is_ctor_dtor_conversion(subs),
Name::Nested(ref nested) => nested.is_ctor_dtor_conversion(subs),
Name::Local(_) |
Name::UnscopedTemplate(..) => false,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnscopedName {
Unqualified(UnqualifiedName),
Std(UnqualifiedName),
}
impl Parse for UnscopedName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(UnscopedName, IndexStr<'b>)> {
try_begin_parse!("UnscopedName", ctx, input);
if let Ok(tail) = consume(b"St", input) {
let (name, tail) = UnqualifiedName::parse(ctx, subs, tail)?;
return Ok((UnscopedName::Std(name), tail));
}
let (name, tail) = UnqualifiedName::parse(ctx, subs, input)?;
Ok((UnscopedName::Unqualified(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for UnscopedName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
UnscopedName::Unqualified(ref unqualified) => unqualified.demangle(ctx, scope),
UnscopedName::Std(ref std) => {
write!(ctx, "std::")?;
std.demangle(ctx, scope)
}
}
}
}
impl<'a> GetLeafName<'a> for UnscopedName {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
UnscopedName::Unqualified(ref name) | UnscopedName::Std(ref name) => {
name.get_leaf_name(subs)
}
}
}
}
impl IsCtorDtorConversion for UnscopedName {
fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool {
match *self {
UnscopedName::Unqualified(ref name) | UnscopedName::Std(ref name) => name.is_ctor_dtor_conversion(subs),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnscopedTemplateName(UnscopedName);
define_handle! {
pub enum UnscopedTemplateNameHandle {
extra NonSubstitution(NonSubstitution),
}
}
impl Parse for UnscopedTemplateNameHandle {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(UnscopedTemplateNameHandle, IndexStr<'b>)> {
try_begin_parse!("UnscopedTemplateNameHandle", ctx, input);
if let Ok((name, tail)) = UnscopedName::parse(ctx, subs, input) {
let name = UnscopedTemplateName(name);
let idx = subs.insert(Substitutable::UnscopedTemplateName(name));
let handle = UnscopedTemplateNameHandle::BackReference(idx);
return Ok((handle, tail));
}
let (sub, tail) = Substitution::parse(ctx, subs, input)?;
match sub {
Substitution::WellKnown(component) => {
Ok((UnscopedTemplateNameHandle::WellKnown(component), tail))
}
Substitution::BackReference(idx) => {
Ok((UnscopedTemplateNameHandle::BackReference(idx), tail))
}
}
}
}
impl<'subs, W> Demangle<'subs, W> for UnscopedTemplateName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
self.0.demangle(ctx, scope)
}
}
impl<'a> GetLeafName<'a> for UnscopedTemplateName {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
self.0.get_leaf_name(subs)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NestedName {
Unqualified(
CvQualifiers,
Option<RefQualifier>,
PrefixHandle,
UnqualifiedName,
),
Template(CvQualifiers, Option<RefQualifier>, PrefixHandle),
}
impl Parse for NestedName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(NestedName, IndexStr<'b>)> {
try_begin_parse!("NestedName", ctx, input);
let tail = consume(b"N", input)?;
let (cv_qualifiers, tail) = if let Ok((q, tail)) = CvQualifiers::parse(ctx, subs, tail) {
(q, tail)
} else {
(Default::default(), tail)
};
let (ref_qualifier, tail) = if let Ok((r, tail)) = RefQualifier::parse(ctx, subs, tail) {
(Some(r), tail)
} else {
(None, tail)
};
let (prefix, tail) = PrefixHandle::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let substitutable = match prefix {
PrefixHandle::BackReference(idx) => subs.get(idx),
PrefixHandle::NonSubstitution(NonSubstitution(idx)) => subs.get_non_substitution(idx),
PrefixHandle::WellKnown(_) => None,
};
match substitutable {
Some(&Substitutable::Prefix(Prefix::Nested(ref prefix, ref name))) => Ok((
NestedName::Unqualified(cv_qualifiers, ref_qualifier, prefix.clone(), name.clone()),
tail,
)),
Some(&Substitutable::Prefix(Prefix::Template(..))) => Ok((
NestedName::Template(cv_qualifiers, ref_qualifier, prefix),
tail,
)),
_ => Err(error::Error::UnexpectedText),
}
}
}
impl NestedName {
pub fn cv_qualifiers(&self) -> &CvQualifiers {
match *self {
NestedName::Unqualified(ref q, ..) | NestedName::Template(ref q, ..) => q,
}
}
pub fn ref_qualifier(&self) -> Option<&RefQualifier> {
match *self {
NestedName::Unqualified(_, Some(ref r), ..)
| NestedName::Template(_, Some(ref r), ..) => Some(r),
_ => None,
}
}
fn prefix(&self) -> &PrefixHandle {
match *self {
NestedName::Unqualified(_, _, ref p, _) | NestedName::Template(_, _, ref p) => p,
}
}
}
impl<'subs, W> Demangle<'subs, W> for NestedName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
NestedName::Unqualified(_, _, ref p, ref name) => {
ctx.push_demangle_node(DemangleNodeType::NestedName);
p.demangle(ctx, scope)?;
if name.accepts_double_colon() {
ctx.write_str("::")?;
}
name.demangle(ctx, scope)?;
ctx.pop_demangle_node();
}
NestedName::Template(_, _, ref p) => {
ctx.is_template_prefix_in_nested_name = true;
p.demangle(ctx, scope)?;
ctx.is_template_prefix_in_nested_name = false;
}
}
if let Some(inner) = ctx.pop_inner() {
inner.demangle_as_inner(ctx, scope)?;
}
if self.cv_qualifiers() != &CvQualifiers::default() && ctx.show_params {
self.cv_qualifiers().demangle(ctx, scope)?;
}
if let Some(ref refs) = self.ref_qualifier() {
ctx.ensure_space()?;
refs.demangle(ctx, scope)?;
}
Ok(())
}
}
impl GetTemplateArgs for NestedName {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
match *self {
NestedName::Template(_, _, ref prefix) => prefix.get_template_args(subs),
_ => None,
}
}
}
impl<'a> GetLeafName<'a> for NestedName {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
NestedName::Unqualified(_, _, ref prefix, ref name) => name.get_leaf_name(subs)
.or_else(|| prefix.get_leaf_name(subs)),
NestedName::Template(_, _, ref prefix) => prefix.get_leaf_name(subs),
}
}
}
impl IsCtorDtorConversion for NestedName {
fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool {
self.prefix().is_ctor_dtor_conversion(subs)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Prefix {
Unqualified(UnqualifiedName),
Nested(PrefixHandle, UnqualifiedName),
Template(PrefixHandle, TemplateArgs),
TemplateParam(TemplateParam),
Decltype(Decltype),
DataMember(PrefixHandle, DataMemberPrefix),
}
impl GetTemplateArgs for Prefix {
fn get_template_args<'a>(&'a self, _: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
match *self {
Prefix::Template(_, ref args) => Some(args),
Prefix::Unqualified(_)
| Prefix::Nested(_, _)
| Prefix::TemplateParam(_)
| Prefix::Decltype(_)
| Prefix::DataMember(_, _) => None,
}
}
}
define_handle! {
pub enum PrefixHandle {
extra NonSubstitution(NonSubstitution),
}
}
impl Parse for PrefixHandle {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(PrefixHandle, IndexStr<'b>)> {
try_begin_parse!("PrefixHandle", ctx, input);
#[inline]
fn save(
subs: &mut SubstitutionTable,
prefix: Prefix,
tail_tail: IndexStr<'_>,
) -> PrefixHandle {
if let Some(b'E') = tail_tail.peek() {
let idx = subs.insert_non_substitution(Substitutable::Prefix(prefix));
PrefixHandle::NonSubstitution(NonSubstitution(idx))
} else {
let idx = subs.insert(Substitutable::Prefix(prefix));
PrefixHandle::BackReference(idx)
}
}
let mut tail = input;
let mut current = None;
loop {
try_begin_parse!("PrefixHandle iteration", ctx, tail);
match tail.peek() {
Some(b'E') | None => if let Some(handle) = current {
return Ok((handle, tail));
} else {
return Err(error::Error::UnexpectedEnd);
},
Some(b'S') => {
let (sub, tail_tail) = Substitution::parse(ctx, subs, tail)?;
current = Some(match sub {
Substitution::WellKnown(component) => PrefixHandle::WellKnown(component),
Substitution::BackReference(idx) => {
PrefixHandle::BackReference(idx)
}
});
tail = tail_tail;
}
Some(b'T') => {
let (param, tail_tail) = TemplateParam::parse(ctx, subs, tail)?;
current = Some(save(subs, Prefix::TemplateParam(param), tail_tail));
tail = tail_tail;
}
Some(b'D') => {
if let Ok((decltype, tail_tail)) = Decltype::parse(ctx, subs, tail) {
current = Some(save(subs, Prefix::Decltype(decltype), tail_tail));
tail = tail_tail;
} else {
let (name, tail_tail) = UnqualifiedName::parse(ctx, subs, tail)?;
let prefix = match current {
None => Prefix::Unqualified(name),
Some(handle) => Prefix::Nested(handle, name),
};
current = Some(save(subs, prefix, tail_tail));
tail = tail_tail;
}
}
Some(b'I')
if current.is_some() && current.as_ref().unwrap().is_template_prefix() =>
{
let (args, tail_tail) = TemplateArgs::parse(ctx, subs, tail)?;
let prefix = Prefix::Template(current.unwrap(), args);
current = Some(save(subs, prefix, tail_tail));
tail = tail_tail;
}
Some(c) if current.is_some() && SourceName::starts_with(c) => {
debug_assert!(SourceName::starts_with(c));
debug_assert!(DataMemberPrefix::starts_with(c));
let (name, tail_tail) = SourceName::parse(ctx, subs, tail)?;
if tail_tail.peek() == Some(b'M') {
let prefix = Prefix::DataMember(current.unwrap(), DataMemberPrefix(name));
current = Some(save(subs, prefix, tail_tail));
tail = consume(b"M", tail_tail).unwrap();
} else {
let name = UnqualifiedName::Source(name);
let prefix = match current {
None => Prefix::Unqualified(name),
Some(handle) => Prefix::Nested(handle, name),
};
current = Some(save(subs, prefix, tail_tail));
tail = tail_tail;
}
}
Some(c) if UnqualifiedName::starts_with(c, &tail) => {
let (name, tail_tail) = UnqualifiedName::parse(ctx, subs, tail)?;
let prefix = match current {
None => Prefix::Unqualified(name),
Some(handle) => Prefix::Nested(handle, name),
};
current = Some(save(subs, prefix, tail_tail));
tail = tail_tail;
}
Some(_) => if let Some(handle) = current {
return Ok((handle, tail));
} else if tail.is_empty() {
return Err(error::Error::UnexpectedEnd);
} else {
return Err(error::Error::UnexpectedText);
},
}
}
}
}
impl<'a> GetLeafName<'a> for Prefix {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
Prefix::Nested(ref prefix, ref name) => name.get_leaf_name(subs)
.or_else(|| prefix.get_leaf_name(subs)),
Prefix::Unqualified(ref name) => name.get_leaf_name(subs),
Prefix::Template(ref prefix, _) => prefix.get_leaf_name(subs),
Prefix::DataMember(_, ref name) => name.get_leaf_name(subs),
Prefix::TemplateParam(_) | Prefix::Decltype(_) => None,
}
}
}
impl GetTemplateArgs for PrefixHandle {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
match *self {
PrefixHandle::BackReference(idx) => {
if let Some(&Substitutable::Prefix(ref p)) = subs.get(idx) {
p.get_template_args(subs)
} else {
None
}
}
PrefixHandle::NonSubstitution(NonSubstitution(idx)) => {
if let Some(&Substitutable::Prefix(ref p)) = subs.get_non_substitution(idx) {
p.get_template_args(subs)
} else {
None
}
}
_ => None,
}
}
}
impl<'subs, W> Demangle<'subs, W> for Prefix
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
if ctx.is_template_prefix {
ctx.push_demangle_node(DemangleNodeType::TemplatePrefix);
ctx.is_template_prefix = false;
} else if ctx.is_template_prefix_in_nested_name {
ctx.push_demangle_node(DemangleNodeType::NestedName);
ctx.is_template_prefix_in_nested_name = false;
} else {
ctx.push_demangle_node(DemangleNodeType::Prefix);
}
let ret = match *self {
Prefix::Unqualified(ref unqualified) => unqualified.demangle(ctx, scope),
Prefix::Nested(ref prefix, ref unqualified) => {
prefix.demangle(ctx, scope)?;
if unqualified.accepts_double_colon() {
write!(ctx, "::")?;
}
unqualified.demangle(ctx, scope)
}
Prefix::Template(ref prefix, ref args) => {
ctx.is_template_prefix = true;
prefix.demangle(ctx, scope)?;
ctx.is_template_prefix = false;
args.demangle(ctx, scope)
}
Prefix::TemplateParam(ref param) => param.demangle(ctx, scope),
Prefix::Decltype(ref dt) => dt.demangle(ctx, scope),
Prefix::DataMember(ref prefix, ref member) => {
prefix.demangle(ctx, scope)?;
write!(ctx, "::")?;
member.demangle(ctx, scope)
}
};
ctx.pop_demangle_node();
ret
}
}
impl IsCtorDtorConversion for Prefix {
fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool {
match *self {
Prefix::Unqualified(ref unqualified) |
Prefix::Nested(_, ref unqualified) => unqualified.is_ctor_dtor_conversion(subs),
Prefix::Template(ref prefix, _) => prefix.is_ctor_dtor_conversion(subs),
_ => false,
}
}
}
impl IsCtorDtorConversion for PrefixHandle {
fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool {
match *self {
PrefixHandle::BackReference(idx) => {
if let Some(sub) = subs.get(idx) {
sub.is_ctor_dtor_conversion(subs)
} else {
false
}
}
PrefixHandle::NonSubstitution(NonSubstitution(idx)) => {
if let Some(sub) = subs.get_non_substitution(idx) {
sub.is_ctor_dtor_conversion(subs)
} else {
false
}
}
PrefixHandle::WellKnown(_) => false,
}
}
}
impl PrefixHandle {
fn is_template_prefix(&self) -> bool {
match *self {
PrefixHandle::BackReference(_) |
PrefixHandle::WellKnown(_) => true,
PrefixHandle::NonSubstitution(_) => false,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnqualifiedName {
Operator(OperatorName),
CtorDtor(CtorDtorName),
Source(SourceName),
LocalSourceName(SourceName, Option<Discriminator>),
UnnamedType(UnnamedTypeName),
ABITag(TaggedName),
ClosureType(ClosureTypeName),
}
impl Parse for UnqualifiedName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(UnqualifiedName, IndexStr<'b>)> {
try_begin_parse!("UnqualifiedName", ctx, input);
if let Ok((op, tail)) = OperatorName::parse(ctx, subs, input) {
return Ok((UnqualifiedName::Operator(op), tail));
}
if let Ok((ctor_dtor, tail)) = CtorDtorName::parse(ctx, subs, input) {
return Ok((UnqualifiedName::CtorDtor(ctor_dtor), tail));
}
if let Ok(tail) = consume(b"L", input) {
let (name, tail) = SourceName::parse(ctx, subs, tail)?;
let (discr, tail) = if let Ok((d, t)) = Discriminator::parse(ctx, subs, tail) {
(Some(d), t)
} else {
(None, tail)
};
return Ok((UnqualifiedName::LocalSourceName(name, discr), tail));
}
if let Ok((source, tail)) = SourceName::parse(ctx, subs, input) {
return Ok((UnqualifiedName::Source(source), tail));
}
if let Ok((tagged, tail)) = TaggedName::parse(ctx, subs, input) {
return Ok((UnqualifiedName::ABITag(tagged), tail));
}
if let Ok((closure, tail)) = ClosureTypeName::parse(ctx, subs, input) {
return Ok((UnqualifiedName::ClosureType(closure), tail));
}
UnnamedTypeName::parse(ctx, subs, input).map(|(unnamed, tail)| {
(UnqualifiedName::UnnamedType(unnamed), tail)
})
}
}
impl<'subs, W> Demangle<'subs, W> for UnqualifiedName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_demangle_node(DemangleNodeType::UnqualifiedName);
let ret = match *self {
UnqualifiedName::Operator(ref op_name) => {
write!(ctx, "operator")?;
op_name.demangle(ctx, scope)
}
UnqualifiedName::CtorDtor(ref ctor_dtor) => ctor_dtor.demangle(ctx, scope),
UnqualifiedName::Source(ref name) | UnqualifiedName::LocalSourceName(ref name, ..) => {
name.demangle(ctx, scope)
}
UnqualifiedName::UnnamedType(ref unnamed) => unnamed.demangle(ctx, scope),
UnqualifiedName::ABITag(ref tagged) => tagged.demangle(ctx, scope),
UnqualifiedName::ClosureType(ref closure) => closure.demangle(ctx, scope),
};
ctx.pop_demangle_node();
ret
}
}
impl<'a> GetLeafName<'a> for UnqualifiedName {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
UnqualifiedName::ABITag(_)
| UnqualifiedName::Operator(_)
| UnqualifiedName::CtorDtor(_) => None,
UnqualifiedName::UnnamedType(ref name) => {
Some(LeafName::UnnamedType(name))
},
UnqualifiedName::ClosureType(ref closure) => closure.get_leaf_name(subs),
UnqualifiedName::Source(ref name) | UnqualifiedName::LocalSourceName(ref name, _) => {
Some(LeafName::SourceName(name))
}
}
}
}
impl IsCtorDtorConversion for UnqualifiedName {
fn is_ctor_dtor_conversion(&self, _: &SubstitutionTable) -> bool {
match *self {
UnqualifiedName::CtorDtor(_) |
UnqualifiedName::Operator(OperatorName::Conversion(_)) => true,
UnqualifiedName::Operator(_) |
UnqualifiedName::Source(_) |
UnqualifiedName::LocalSourceName(..) |
UnqualifiedName::UnnamedType(_) |
UnqualifiedName::ClosureType(_) |
UnqualifiedName::ABITag(_) => false,
}
}
}
impl UnqualifiedName {
#[inline]
fn starts_with(byte: u8, input: &IndexStr) -> bool {
byte == b'L' || OperatorName::starts_with(byte) || CtorDtorName::starts_with(byte)
|| SourceName::starts_with(byte) || UnnamedTypeName::starts_with(byte)
|| TaggedName::starts_with(byte) || ClosureTypeName::starts_with(byte, input)
}
fn accepts_double_colon(&self) -> bool {
match *self {
UnqualifiedName::Operator(_)
| UnqualifiedName::CtorDtor(_)
| UnqualifiedName::Source(_)
| UnqualifiedName::LocalSourceName(..)
| UnqualifiedName::UnnamedType(_)
| UnqualifiedName::ClosureType(_) => true,
UnqualifiedName::ABITag(_) => false,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SourceName(Identifier);
impl Parse for SourceName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(SourceName, IndexStr<'b>)> {
try_begin_parse!("SourceName", ctx, input);
let (source_name_len, input) = parse_number(10, false, input)?;
debug_assert!(source_name_len >= 0);
if source_name_len == 0 {
return Err(error::Error::UnexpectedText);
}
let (head, tail) = match input.try_split_at(source_name_len as _) {
Some((head, tail)) => (head, tail),
None => return Err(error::Error::UnexpectedEnd),
};
let (identifier, empty) = Identifier::parse(ctx, subs, head)?;
if !empty.is_empty() {
return Err(error::Error::UnexpectedText);
}
let source_name = SourceName(identifier);
Ok((source_name, tail))
}
}
impl<'subs> ArgScope<'subs, 'subs> for SourceName {
fn leaf_name(&'subs self) -> Result<LeafName<'subs>> {
Ok(LeafName::SourceName(self))
}
fn get_template_arg(&'subs self, _: usize) -> Result<(&'subs TemplateArg, &'subs TemplateArgs)> {
Err(error::Error::BadTemplateArgReference)
}
fn get_function_arg(&'subs self, _: usize) -> Result<&'subs Type> {
Err(error::Error::BadFunctionArgReference)
}
}
impl SourceName {
#[inline]
fn starts_with(byte: u8) -> bool {
byte == b'0' || (b'0' <= byte && byte <= b'9')
}
}
impl<'subs, W> Demangle<'subs, W> for SourceName
where
W: 'subs + DemangleWrite,
{
#[inline]
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
self.0.demangle(ctx, scope)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TaggedName(SourceName);
impl Parse for TaggedName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(TaggedName, IndexStr<'b>)> {
try_begin_parse!("TaggedName", ctx, input);
let tail = consume(b"B", input)?;
let (source_name, tail) = SourceName::parse(ctx, subs, tail)?;
Ok((TaggedName(source_name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for TaggedName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
write!(ctx, "[abi:")?;
self.0.demangle(ctx, scope)?;
write!(ctx, "]")
}
}
impl TaggedName {
#[inline]
fn starts_with(byte: u8) -> bool {
byte == b'B'
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Identifier {
start: usize,
end: usize,
}
impl Parse for Identifier {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Identifier, IndexStr<'b>)> {
try_begin_parse!("Identifier", ctx, input);
if input.is_empty() {
return Err(error::Error::UnexpectedEnd);
}
let end = input
.as_ref()
.iter()
.map(|&c| c as char)
.take_while(|&c| c == '$' || c == '_' || c == '.' || c.is_digit(36))
.count();
if end == 0 {
return Err(error::Error::UnexpectedText);
}
let tail = input.range_from(end..);
let identifier = Identifier {
start: input.index(),
end: tail.index(),
};
Ok((identifier, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Identifier
where
W: 'subs + DemangleWrite,
{
#[inline]
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
let ident = &ctx.input[self.start..self.end];
let anon_namespace_prefix = b"_GLOBAL_";
if ident.starts_with(anon_namespace_prefix)
&& ident.len() >= anon_namespace_prefix.len() + 2
{
let first = ident[anon_namespace_prefix.len()];
let second = ident[anon_namespace_prefix.len() + 1];
match (first, second) {
(b'.', b'N') | (b'_', b'N') | (b'$', b'N') => {
write!(ctx, "(anonymous namespace)")?;
return Ok(());
}
_ => {
}
}
}
let source_name = String::from_utf8_lossy(ident);
ctx.set_source_name(self.start, self.end);
write!(ctx, "{}", source_name)?;
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CloneTypeIdentifier {
start: usize,
end: usize,
}
impl Parse for CloneTypeIdentifier {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(CloneTypeIdentifier, IndexStr<'b>)> {
try_begin_parse!("CloneTypeIdentifier", ctx, input);
if input.is_empty() {
return Err(error::Error::UnexpectedEnd);
}
let end = input
.as_ref()
.iter()
.map(|&c| c as char)
.take_while(|&c| c == '$' || c == '_' || c.is_digit(36))
.count();
if end == 0 {
return Err(error::Error::UnexpectedText);
}
let tail = input.range_from(end..);
let identifier = CloneTypeIdentifier {
start: input.index(),
end: tail.index(),
};
Ok((identifier, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for CloneTypeIdentifier
where
W: 'subs + DemangleWrite,
{
#[inline]
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
let ident = &ctx.input[self.start..self.end];
let source_name = String::from_utf8_lossy(ident);
ctx.set_source_name(self.start, self.end);
write!(ctx, " .{}", source_name)?;
Ok(())
}
}
type Number = isize;
impl Parse for Number {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(isize, IndexStr<'b>)> {
try_begin_parse!("Number", ctx, input);
parse_number(10, true, input)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SeqId(usize);
impl Parse for SeqId {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(SeqId, IndexStr<'b>)> {
try_begin_parse!("SeqId", ctx, input);
parse_number(36, false, input).map(|(num, tail)| (SeqId(num as _), tail))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OperatorName {
Simple(SimpleOperatorName),
Cast(TypeHandle),
Conversion(TypeHandle),
Literal(SourceName),
VendorExtension(u8, SourceName),
}
impl OperatorName {
fn starts_with(byte: u8) -> bool {
byte == b'c' || byte == b'l' || byte == b'v' || SimpleOperatorName::starts_with(byte)
}
fn arity(&self) -> u8 {
match self {
&OperatorName::Cast(_) |
&OperatorName::Conversion(_) |
&OperatorName::Literal(_) => 1,
&OperatorName::Simple(ref s) => s.arity(),
&OperatorName::VendorExtension(arity, _) => arity,
}
}
fn parse_from_expr<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>
) -> Result<(Expression, IndexStr<'b>)> {
let (operator, tail) = OperatorName::parse_internal(ctx, subs, input, true)?;
let arity = operator.arity();
if arity == 1 {
let (first, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::Unary(operator, Box::new(first));
Ok((expr, tail))
} else if arity == 2 {
let (first, tail) = Expression::parse(ctx, subs, tail)?;
let (second, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::Binary(operator, Box::new(first), Box::new(second));
Ok((expr, tail))
} else if arity == 3 {
let (first, tail) = Expression::parse(ctx, subs, tail)?;
let (second, tail) = Expression::parse(ctx, subs, tail)?;
let (third, tail) = Expression::parse(ctx, subs, tail)?;
let expr =
Expression::Ternary(operator, Box::new(first), Box::new(second), Box::new(third));
Ok((expr, tail))
} else {
Err(error::Error::UnexpectedText)
}
}
fn parse_internal<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
from_expr: bool,
) -> Result<(OperatorName, IndexStr<'b>)> {
try_begin_parse!("OperatorName", ctx, input);
if let Ok((simple, tail)) = SimpleOperatorName::parse(ctx, subs, input) {
return Ok((OperatorName::Simple(simple), tail));
}
if let Ok(tail) = consume(b"cv", input) {
let previously_in_conversion = ctx.set_in_conversion(!from_expr);
let parse_result = TypeHandle::parse(ctx, subs, tail);
ctx.set_in_conversion(previously_in_conversion);
let (ty, tail) = parse_result?;
if from_expr {
return Ok((OperatorName::Cast(ty), tail));
} else {
return Ok((OperatorName::Conversion(ty), tail));
}
}
if let Ok(tail) = consume(b"li", input) {
let (name, tail) = SourceName::parse(ctx, subs, tail)?;
return Ok((OperatorName::Literal(name), tail));
}
let tail = consume(b"v", input)?;
let (arity, tail) = match tail.peek() {
Some(c) if b'0' <= c && c <= b'9' => (c - b'0', tail.range_from(1..)),
None => return Err(error::Error::UnexpectedEnd),
_ => return Err(error::Error::UnexpectedText),
};
let (name, tail) = SourceName::parse(ctx, subs, tail)?;
Ok((OperatorName::VendorExtension(arity, name), tail))
}
}
impl Parse for OperatorName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(OperatorName, IndexStr<'b>)> {
OperatorName::parse_internal(ctx, subs, input, false)
}
}
impl<'subs, W> Demangle<'subs, W> for OperatorName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
OperatorName::Simple(ref simple) => {
match *simple {
SimpleOperatorName::New
| SimpleOperatorName::NewArray
| SimpleOperatorName::Delete
| SimpleOperatorName::DeleteArray => {
ctx.ensure_space()?;
}
_ => {}
}
simple.demangle(ctx, scope)
}
OperatorName::Cast(ref ty) |
OperatorName::Conversion(ref ty) => {
ctx.ensure_space()?;
let scope = ty.get_template_args(ctx.subs)
.map_or(scope, |args| scope.push(args));
ty.demangle(ctx, scope)?;
Ok(())
}
OperatorName::Literal(ref name) => {
name.demangle(ctx, scope)?;
write!(ctx, "::operator \"\"")?;
Ok(())
}
OperatorName::VendorExtension(arity, ref name) => {
name.demangle(ctx, scope)?;
write!(ctx, "::operator {}", arity)?;
Ok(())
}
}
}
}
define_vocabulary! {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SimpleOperatorName {
New (b"nw", "new", 3),
NewArray (b"na", "new[]", 3),
Delete (b"dl", "delete", 1),
DeleteArray (b"da", "delete[]", 1),
UnaryPlus (b"ps", "+", 1),
Neg (b"ng", "-", 1),
AddressOf (b"ad", "&", 1),
Deref (b"de", "*", 1),
BitNot (b"co", "~", 1),
Add (b"pl", "+", 2),
Sub (b"mi", "-", 2),
Mul (b"ml", "*", 2),
Div (b"dv", "/", 2),
Rem (b"rm", "%", 2),
BitAnd (b"an", "&", 2),
BitOr (b"or", "|", 2),
BitXor (b"eo", "^", 2),
Assign (b"aS", "=", 2),
AddAssign (b"pL", "+=", 2),
SubAssign (b"mI", "-=", 2),
MulAssign (b"mL", "*=", 2),
DivAssign (b"dV", "/=", 2),
RemAssign (b"rM", "%=", 2),
BitAndAssign (b"aN", "&=", 2),
BitOrAssign (b"oR", "|=", 2),
BitXorAssign (b"eO", "^=", 2),
Shl (b"ls", "<<", 2),
Shr (b"rs", ">>", 2),
ShlAssign (b"lS", "<<=", 2),
ShrAssign (b"rS", ">>=", 2),
Eq (b"eq", "==", 2),
Ne (b"ne", "!=", 2),
Less (b"lt", "<", 2),
Greater (b"gt", ">", 2),
LessEq (b"le", "<=", 2),
GreaterEq (b"ge", ">=", 2),
Not (b"nt", "!", 1),
LogicalAnd (b"aa", "&&", 2),
LogicalOr (b"oo", "||", 2),
PostInc (b"pp", "++", 1),
PostDec (b"mm", "--", 1),
Comma (b"cm", ",", 2),
DerefMemberPtr (b"pm", "->*", 2),
DerefMember (b"pt", "->", 2),
Call (b"cl", "()", 2),
Index (b"ix", "[]", 2),
Question (b"qu", "?:", 3),
Spaceship (b"ss", "<=>", 2)
}
impl SimpleOperatorName {
fn arity(&self) -> u8;
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CallOffset {
NonVirtual(NvOffset),
Virtual(VOffset),
}
impl Parse for CallOffset {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(CallOffset, IndexStr<'b>)> {
try_begin_parse!("CallOffset", ctx, input);
if input.is_empty() {
return Err(error::Error::UnexpectedEnd);
}
if let Ok(tail) = consume(b"h", input) {
let (offset, tail) = NvOffset::parse(ctx, subs, tail)?;
let tail = consume(b"_", tail)?;
return Ok((CallOffset::NonVirtual(offset), tail));
}
if let Ok(tail) = consume(b"v", input) {
let (offset, tail) = VOffset::parse(ctx, subs, tail)?;
let tail = consume(b"_", tail)?;
return Ok((CallOffset::Virtual(offset), tail));
}
Err(error::Error::UnexpectedText)
}
}
impl<'subs, W> Demangle<'subs, W> for CallOffset
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
CallOffset::NonVirtual(NvOffset(offset)) => {
write!(ctx, "{{offset({})}}", offset)?;
}
CallOffset::Virtual(VOffset(vbase, vcall)) => {
write!(ctx, "{{virtual offset({}, {})}}", vbase, vcall)?;
}
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NvOffset(isize);
impl Parse for NvOffset {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(NvOffset, IndexStr<'b>)> {
try_begin_parse!("NvOffset", ctx, input);
Number::parse(ctx, subs, input).map(|(num, tail)| (NvOffset(num), tail))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VOffset(isize, isize);
impl Parse for VOffset {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(VOffset, IndexStr<'b>)> {
try_begin_parse!("VOffset", ctx, input);
let (offset, tail) = Number::parse(ctx, subs, input)?;
let tail = consume(b"_", tail)?;
let (virtual_offset, tail) = Number::parse(ctx, subs, tail)?;
Ok((VOffset(offset, virtual_offset), tail))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CtorDtorName {
CompleteConstructor(Option<TypeHandle>),
BaseConstructor(Option<TypeHandle>),
CompleteAllocatingConstructor(Option<TypeHandle>),
MaybeInChargeConstructor(Option<TypeHandle>),
DeletingDestructor,
CompleteDestructor,
BaseDestructor,
MaybeInChargeDestructor,
}
impl CtorDtorName {
fn inheriting_mut(&mut self) -> &mut Option<TypeHandle> {
match self {
CtorDtorName::CompleteConstructor(ref mut inheriting)
| CtorDtorName::BaseConstructor(ref mut inheriting)
| CtorDtorName::CompleteAllocatingConstructor(ref mut inheriting)
| CtorDtorName::MaybeInChargeConstructor(ref mut inheriting) => inheriting,
CtorDtorName::DeletingDestructor
| CtorDtorName::CompleteDestructor
| CtorDtorName::BaseDestructor
| CtorDtorName::MaybeInChargeDestructor => unreachable!(),
}
}
}
impl Parse for CtorDtorName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(CtorDtorName, IndexStr<'b>)> {
try_begin_parse!(stringify!(CtorDtorName), ctx, input);
match input.peek() {
Some(b'C') => {
let mut tail = consume(b"C", input)?;
let inheriting = match tail.peek() {
Some(b'I') => {
tail = consume(b"I", tail)?;
true
}
_ => false,
};
let mut ctor_type: CtorDtorName = match tail
.try_split_at(1)
.as_ref()
.map(|&(ref h, t)| (h.as_ref(), t))
{
None => Err(error::Error::UnexpectedEnd),
Some((b"1", t)) => {
tail = t;
Ok(CtorDtorName::CompleteConstructor(None))
},
Some((b"2", t)) => {
tail = t;
Ok(CtorDtorName::BaseConstructor(None))
},
Some((b"3", t)) => {
tail = t;
Ok(CtorDtorName::CompleteAllocatingConstructor(None))
},
Some((b"4", t)) => {
tail = t;
Ok(CtorDtorName::MaybeInChargeConstructor(None))
},
_ => Err(error::Error::UnexpectedText),
}?;
if inheriting {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
*ctor_type.inheriting_mut() = Some(ty);
Ok((ctor_type, tail))
} else {
Ok((ctor_type, tail))
}
}
Some(b'D') => {
match input
.try_split_at(2)
.as_ref()
.map(|&(ref h, t)| (h.as_ref(), t))
{
Some((b"D0", tail)) => Ok((CtorDtorName::DeletingDestructor, tail)),
Some((b"D1", tail)) => Ok((CtorDtorName::CompleteDestructor, tail)),
Some((b"D2", tail)) => Ok((CtorDtorName::BaseDestructor, tail)),
Some((b"D4", tail)) => Ok((CtorDtorName::MaybeInChargeDestructor, tail)),
_ => Err(error::Error::UnexpectedText),
}
}
None => Err(error::Error::UnexpectedEnd),
_ => Err(error::Error::UnexpectedText),
}
}
}
impl<'subs, W> Demangle<'subs, W> for CtorDtorName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
let leaf = scope
.leaf_name()
.map_err(|e| {
log!("Error getting leaf name: {}", e);
fmt::Error
})?;
match *self {
CtorDtorName::CompleteConstructor(ref inheriting)
| CtorDtorName::BaseConstructor(ref inheriting)
| CtorDtorName::CompleteAllocatingConstructor(ref inheriting)
| CtorDtorName::MaybeInChargeConstructor(ref inheriting) => {
match inheriting {
Some(ty) => ty.get_leaf_name(ctx.subs).ok_or_else(|| {
log!("Error getting leaf name: {:?}", ty);
fmt::Error
})?.demangle_as_leaf(ctx),
None => leaf.demangle_as_leaf(ctx),
}
},
CtorDtorName::DeletingDestructor
| CtorDtorName::CompleteDestructor
| CtorDtorName::BaseDestructor
| CtorDtorName::MaybeInChargeDestructor => {
write!(ctx, "~")?;
leaf.demangle_as_leaf(ctx)
}
}
}
}
impl CtorDtorName {
#[inline]
fn starts_with(byte: u8) -> bool {
byte == b'C' || byte == b'D'
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum Type {
Function(FunctionType),
ClassEnum(ClassEnumType),
Array(ArrayType),
Vector(VectorType),
PointerToMember(PointerToMemberType),
TemplateParam(TemplateParam),
TemplateTemplate(TemplateTemplateParamHandle, TemplateArgs),
Decltype(Decltype),
Qualified(CvQualifiers, TypeHandle),
PointerTo(TypeHandle),
LvalueRef(TypeHandle),
RvalueRef(TypeHandle),
Complex(TypeHandle),
Imaginary(TypeHandle),
VendorExtension(SourceName, Option<TemplateArgs>, TypeHandle),
PackExpansion(TypeHandle),
}
define_handle! {
pub enum TypeHandle {
extra Builtin(BuiltinType),
extra QualifiedBuiltin(QualifiedBuiltin),
}
}
impl TypeHandle {
fn is_void(&self) -> bool {
match *self {
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Void)) => true,
_ => false,
}
}
}
impl Parse for TypeHandle {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(TypeHandle, IndexStr<'b>)> {
try_begin_parse!("TypeHandle", ctx, input);
fn insert_and_return_handle<'a, 'b>(
ty: Type,
subs: &'a mut SubstitutionTable,
tail: IndexStr<'b>,
) -> Result<(TypeHandle, IndexStr<'b>)> {
let ty = Substitutable::Type(ty);
let idx = subs.insert(ty);
let handle = TypeHandle::BackReference(idx);
Ok((handle, tail))
}
if let Ok((builtin, tail)) = BuiltinType::parse(ctx, subs, input) {
let handle = TypeHandle::Builtin(builtin);
return Ok((handle, tail));
}
if let Ok((ty, tail)) = ClassEnumType::parse(ctx, subs, input) {
let ty = Type::ClassEnum(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok((sub, tail)) = Substitution::parse(ctx, subs, input) {
if tail.peek() != Some(b'I') {
match sub {
Substitution::WellKnown(component) => {
return Ok((TypeHandle::WellKnown(component), tail));
}
Substitution::BackReference(idx) => {
return Ok((TypeHandle::BackReference(idx), tail));
}
}
}
}
if let Ok((funty, tail)) = FunctionType::parse(ctx, subs, input) {
let ty = Type::Function(funty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok((ty, tail)) = ArrayType::parse(ctx, subs, input) {
let ty = Type::Array(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok((ty, tail)) = VectorType::parse(ctx, subs, input) {
let ty = Type::Vector(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok((ty, tail)) = PointerToMemberType::parse(ctx, subs, input) {
let ty = Type::PointerToMember(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok((param, tail)) = TemplateParam::parse(ctx, subs, input) {
if tail.peek() != Some(b'I') {
let ty = Type::TemplateParam(param);
return insert_and_return_handle(ty, subs, tail);
} else if ctx.in_conversion() {
let mut tmp_subs = subs.clone();
if let Ok((_, new_tail)) = TemplateArgs::parse(ctx, &mut tmp_subs, tail) {
if new_tail.peek() != Some(b'I') {
let ty = Type::TemplateParam(param);
return insert_and_return_handle(ty, subs, tail);
}
}
}
}
if let Ok((ttp, tail)) = TemplateTemplateParamHandle::parse(ctx, subs, input) {
let (args, tail) = TemplateArgs::parse(ctx, subs, tail)?;
let ty = Type::TemplateTemplate(ttp, args);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok((param, tail)) = Decltype::parse(ctx, subs, input) {
let ty = Type::Decltype(param);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok((qualifiers, tail)) = CvQualifiers::parse(ctx, subs, input) {
if tail.len() < input.len() {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::Qualified(qualifiers, ty);
return insert_and_return_handle(ty, subs, tail);
}
}
if let Ok(tail) = consume(b"P", input) {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::PointerTo(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok(tail) = consume(b"R", input) {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::LvalueRef(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok(tail) = consume(b"O", input) {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::RvalueRef(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok(tail) = consume(b"C", input) {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::Complex(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok(tail) = consume(b"G", input) {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::Imaginary(ty);
return insert_and_return_handle(ty, subs, tail);
}
if let Ok(tail) = consume(b"U", input) {
let (name, tail) = SourceName::parse(ctx, subs, tail)?;
let (args, tail) = if let Ok((args, tail)) = TemplateArgs::parse(ctx, subs, tail) {
(Some(args), tail)
} else {
(None, tail)
};
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::VendorExtension(name, args, ty);
return insert_and_return_handle(ty, subs, tail);
}
let tail = consume(b"Dp", input)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let ty = Type::PackExpansion(ty);
insert_and_return_handle(ty, subs, tail)
}
}
impl GetTemplateArgs for TypeHandle {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
subs.get_type(self)
.and_then(|ty| ty.get_template_args(subs))
}
}
impl<'subs, W> Demangle<'subs, W> for Type
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
Type::Function(ref func_ty) => func_ty.demangle(ctx, scope),
Type::ClassEnum(ref cls_enum_ty) => cls_enum_ty.demangle(ctx, scope),
Type::Array(ref array_ty) => array_ty.demangle(ctx, scope),
Type::Vector(ref vector_ty) => vector_ty.demangle(ctx, scope),
Type::PointerToMember(ref ptm) => ptm.demangle(ctx, scope),
Type::TemplateParam(ref param) => param.demangle(ctx, scope),
Type::TemplateTemplate(ref tt_param, ref args) => {
tt_param.demangle(ctx, scope)?;
args.demangle(ctx, scope)
}
Type::Decltype(ref dt) => dt.demangle(ctx, scope),
Type::Qualified(_, ref ty) => {
ctx.push_inner(self);
ty.demangle(ctx, scope)?;
if ctx.pop_inner_if(self) {
self.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
Type::PointerTo(ref ty) | Type::LvalueRef(ref ty) | Type::RvalueRef(ref ty) => {
ctx.push_inner(self);
ty.demangle(ctx, scope)?;
if ctx.pop_inner_if(self) {
self.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
Type::Complex(ref ty) => {
ty.demangle(ctx, scope)?;
write!(ctx, " complex")?;
Ok(())
}
Type::Imaginary(ref ty) => {
ty.demangle(ctx, scope)?;
write!(ctx, " imaginary")?;
Ok(())
}
Type::VendorExtension(ref name, ref template_args, ref ty) => {
ty.demangle(ctx, scope)?;
write!(ctx, " ")?;
name.demangle(ctx, scope)?;
if let Some(ref args) = *template_args {
args.demangle(ctx, scope)?;
}
Ok(())
}
Type::PackExpansion(ref ty) => {
ty.demangle(ctx, scope)?;
if !ctx.is_template_argument_pack {
write!(ctx, "...")?;
}
Ok(())
}
}
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for Type
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle_as_inner!(self, ctx, scope);
match *self {
Type::Qualified(ref quals, _) => quals.demangle_as_inner(ctx, scope),
Type::PointerTo(_) => write!(ctx, "*"),
Type::LvalueRef(_) => write!(ctx, "&"),
Type::RvalueRef(_) => write!(ctx, "&&"),
ref otherwise => {
unreachable!(
"We shouldn't ever put any other types on the inner stack: {:?}",
otherwise
);
}
}
}
fn downcast_to_type(&self) -> Option<&Type> {
Some(self)
}
fn downcast_to_function_type(&self) -> Option<&FunctionType> {
if let Type::Function(ref f) = *self {
Some(f)
} else {
None
}
}
fn downcast_to_array_type(&self) -> Option<&ArrayType> {
if let Type::Array(ref arr) = *self {
Some(arr)
} else {
None
}
}
fn downcast_to_pointer_to_member(&self) -> Option<&PointerToMemberType> {
if let Type::PointerToMember(ref ptm) = *self {
Some(ptm)
} else {
None
}
}
fn is_qualified(&self) -> bool {
match *self {
Type::Qualified(..) => true,
_ => false,
}
}
}
impl GetTemplateArgs for Type {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
match *self {
Type::VendorExtension(_, Some(ref args), _) | Type::TemplateTemplate(_, ref args) => {
Some(args)
}
Type::PointerTo(ref ty) | Type::LvalueRef(ref ty) | Type::RvalueRef(ref ty) => {
ty.get_template_args(subs)
}
_ => None,
}
}
}
impl<'a> GetLeafName<'a> for Type {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
Type::ClassEnum(ref cls_enum_ty) => cls_enum_ty.get_leaf_name(subs),
_ => None,
}
}
}
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
pub struct CvQualifiers {
pub restrict: bool,
pub volatile: bool,
pub const_: bool,
}
impl CvQualifiers {
#[inline]
fn is_empty(&self) -> bool {
!self.restrict && !self.volatile && !self.const_
}
}
impl Parse for CvQualifiers {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(CvQualifiers, IndexStr<'b>)> {
try_begin_parse!("CvQualifiers", ctx, input);
let (restrict, tail) = if let Ok(tail) = consume(b"r", input) {
(true, tail)
} else {
(false, input)
};
let (volatile, tail) = if let Ok(tail) = consume(b"V", tail) {
(true, tail)
} else {
(false, tail)
};
let (const_, tail) = if let Ok(tail) = consume(b"K", tail) {
(true, tail)
} else {
(false, tail)
};
let qualifiers = CvQualifiers {
restrict: restrict,
volatile: volatile,
const_: const_,
};
Ok((qualifiers, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for CvQualifiers
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
if self.const_ {
ctx.ensure_space()?;
write!(ctx, "const")?;
}
if self.volatile {
ctx.ensure_space()?;
write!(ctx, "volatile")?;
}
if self.restrict {
ctx.ensure_space()?;
write!(ctx, "restrict")?;
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for CvQualifiers
where
W: 'subs + DemangleWrite,
{
}
define_vocabulary! {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RefQualifier {
LValueRef(b"R", "&"),
RValueRef(b"O", "&&")
}
}
define_vocabulary! {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StandardBuiltinType {
Void (b"v", "void"),
Wchar (b"w", "wchar_t"),
Bool (b"b", "bool"),
Char (b"c", "char"),
SignedChar (b"a", "signed char"),
UnsignedChar (b"h", "unsigned char"),
Short (b"s", "short"),
UnsignedShort (b"t", "unsigned short"),
Int (b"i", "int"),
UnsignedInt (b"j", "unsigned int"),
Long (b"l", "long"),
UnsignedLong (b"m", "unsigned long"),
LongLong (b"x", "long long"),
UnsignedLongLong (b"y", "unsigned long long"),
Int128 (b"n", "__int128"),
Uint128 (b"o", "unsigned __int128"),
Float (b"f", "float"),
Double (b"d", "double"),
LongDouble (b"e", "long double"),
Float128 (b"g", "__float128"),
Ellipsis (b"z", "..."),
DecimalFloat64 (b"Dd", "decimal64"),
DecimalFloat128 (b"De", "decimal128"),
DecimalFloat32 (b"Df", "decimal32"),
DecimalFloat16 (b"Dh", "half"),
Char32 (b"Di", "char32_t"),
Char16 (b"Ds", "char16_t"),
Auto (b"Da", "auto"),
Decltype (b"Dc", "decltype(auto)"),
Nullptr (b"Dn", "std::nullptr_t")
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BuiltinType {
Standard(StandardBuiltinType),
Extension(SourceName),
}
impl Parse for BuiltinType {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(BuiltinType, IndexStr<'b>)> {
try_begin_parse!("BuiltinType", ctx, input);
if let Ok((ty, tail)) = StandardBuiltinType::parse(ctx, subs, input) {
return Ok((BuiltinType::Standard(ty), tail));
}
let tail = consume(b"u", input)?;
let (name, tail) = SourceName::parse(ctx, subs, tail)?;
Ok((BuiltinType::Extension(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for BuiltinType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
BuiltinType::Standard(ref ty) => ty.demangle(ctx, scope),
BuiltinType::Extension(ref name) => name.demangle(ctx, scope),
}
}
}
impl<'a> GetLeafName<'a> for BuiltinType {
fn get_leaf_name(&'a self, _: &'a SubstitutionTable) -> Option<LeafName<'a>> {
None
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QualifiedBuiltin(CvQualifiers, BuiltinType);
impl<'subs, W> Demangle<'subs, W> for QualifiedBuiltin
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_inner(&self.0);
self.1.demangle(ctx, scope)?;
if ctx.pop_inner_if(&self.0) {
self.0.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
}
impl<'a> GetLeafName<'a> for QualifiedBuiltin {
fn get_leaf_name(&'a self, _: &'a SubstitutionTable) -> Option<LeafName<'a>> {
None
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionType {
cv_qualifiers: CvQualifiers,
transaction_safe: bool,
extern_c: bool,
bare: BareFunctionType,
ref_qualifier: Option<RefQualifier>,
}
impl Parse for FunctionType {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(FunctionType, IndexStr<'b>)> {
try_begin_parse!("FunctionType", ctx, input);
let (cv_qualifiers, tail) =
if let Ok((cv_qualifiers, tail)) = CvQualifiers::parse(ctx, subs, input) {
(cv_qualifiers, tail)
} else {
(Default::default(), input)
};
let (transaction_safe, tail) = if let Ok(tail) = consume(b"Dx", tail) {
(true, tail)
} else {
(false, tail)
};
let tail = consume(b"F", tail)?;
let (extern_c, tail) = if let Ok(tail) = consume(b"Y", tail) {
(true, tail)
} else {
(false, tail)
};
let (bare, tail) = BareFunctionType::parse(ctx, subs, tail)?;
let (ref_qualifier, tail) =
if let Ok((ref_qualifier, tail)) = RefQualifier::parse(ctx, subs, tail) {
(Some(ref_qualifier), tail)
} else {
(None, tail)
};
let tail = consume(b"E", tail)?;
let func_ty = FunctionType {
cv_qualifiers: cv_qualifiers,
transaction_safe: transaction_safe,
extern_c: extern_c,
bare: bare,
ref_qualifier: ref_qualifier,
};
Ok((func_ty, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for FunctionType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_inner(self);
self.bare.demangle(ctx, scope)?;
if ctx.pop_inner_if(self) {
self.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for FunctionType
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle_as_inner!(self, ctx, scope);
if !self.cv_qualifiers.is_empty() {
self.cv_qualifiers.demangle(ctx, scope)?;
}
if let Some(ref rq) = self.ref_qualifier {
ctx.ensure_space()?;
rq.demangle(ctx, scope)?;
}
Ok(())
}
fn downcast_to_function_type(&self) -> Option<&FunctionType> {
Some(self)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BareFunctionType(Vec<TypeHandle>);
impl BareFunctionType {
fn ret(&self) -> &TypeHandle {
&self.0[0]
}
fn args(&self) -> &FunctionArgListAndReturnType {
FunctionArgListAndReturnType::new(&self.0)
}
}
impl Parse for BareFunctionType {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(BareFunctionType, IndexStr<'b>)> {
try_begin_parse!("BareFunctionType", ctx, input);
let (types, tail) = one_or_more::<TypeHandle>(ctx, subs, input)?;
Ok((BareFunctionType(types), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for BareFunctionType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_inner(self);
self.ret().demangle(ctx, scope)?;
if ctx.pop_inner_if(self) {
ctx.ensure_space()?;
self.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for BareFunctionType
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle_as_inner!(self, ctx, scope);
self.args().demangle_as_inner(ctx, scope)?;
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Decltype {
IdExpression(Expression),
Expression(Expression),
}
impl Parse for Decltype {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Decltype, IndexStr<'b>)> {
try_begin_parse!("Decltype", ctx, input);
let tail = consume(b"D", input)?;
if let Ok(tail) = consume(b"t", tail) {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
return Ok((Decltype::IdExpression(expr), tail));
}
let tail = consume(b"T", tail)?;
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
Ok((Decltype::Expression(expr), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Decltype
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_demangle_node(DemangleNodeType::TemplateParam);
let ret = match *self {
Decltype::Expression(ref expr) | Decltype::IdExpression(ref expr) => {
write!(ctx, "decltype (")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
};
ctx.pop_demangle_node();
ret
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ClassEnumType {
Named(Name),
ElaboratedStruct(Name),
ElaboratedUnion(Name),
ElaboratedEnum(Name),
}
impl Parse for ClassEnumType {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(ClassEnumType, IndexStr<'b>)> {
try_begin_parse!("ClassEnumType", ctx, input);
if let Ok((name, tail)) = Name::parse(ctx, subs, input) {
return Ok((ClassEnumType::Named(name), tail));
}
let tail = consume(b"T", input)?;
if let Ok(tail) = consume(b"s", tail) {
let (name, tail) = Name::parse(ctx, subs, tail)?;
return Ok((ClassEnumType::ElaboratedStruct(name), tail));
}
if let Ok(tail) = consume(b"u", tail) {
let (name, tail) = Name::parse(ctx, subs, tail)?;
return Ok((ClassEnumType::ElaboratedUnion(name), tail));
}
let tail = consume(b"e", tail)?;
let (name, tail) = Name::parse(ctx, subs, tail)?;
Ok((ClassEnumType::ElaboratedEnum(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ClassEnumType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
ClassEnumType::Named(ref name) => name.demangle(ctx, scope),
ClassEnumType::ElaboratedStruct(ref name) => {
write!(ctx, "class ")?;
name.demangle(ctx, scope)
}
ClassEnumType::ElaboratedUnion(ref name) => {
write!(ctx, "union ")?;
name.demangle(ctx, scope)
}
ClassEnumType::ElaboratedEnum(ref name) => {
write!(ctx, "enum ")?;
name.demangle(ctx, scope)
}
}
}
}
impl<'a> GetLeafName<'a> for ClassEnumType {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
ClassEnumType::Named(ref name)
| ClassEnumType::ElaboratedStruct(ref name)
| ClassEnumType::ElaboratedUnion(ref name)
| ClassEnumType::ElaboratedEnum(ref name) => {
name.get_leaf_name(subs)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnnamedTypeName(Option<usize>);
impl Parse for UnnamedTypeName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(UnnamedTypeName, IndexStr<'b>)> {
try_begin_parse!("UnnamedTypeName", ctx, input);
let input = consume(b"Ut", input)?;
let (number, input) = match parse_number(10, false, input) {
Ok((number, input)) => (Some(number as _), input),
Err(_) => (None, input),
};
let input = consume(b"_", input)?;
Ok((UnnamedTypeName(number), input))
}
}
impl UnnamedTypeName {
#[inline]
fn starts_with(byte: u8) -> bool {
byte == b'U'
}
}
impl<'subs, W> Demangle<'subs, W> for UnnamedTypeName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
write!(ctx, "{{unnamed type#{}}}", self.0.map_or(1, |n| n + 1))?;
Ok(())
}
}
impl<'subs, W> DemangleAsLeaf<'subs, W> for UnnamedTypeName
where
W: 'subs + DemangleWrite,
{
fn demangle_as_leaf<'me, 'ctx>(
&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, None);
if let Some(source_name) = ctx.source_name {
write!(ctx, "{}", source_name)?;
} else {
write!(ctx, "{{unnamed type#{}}}", self.0.map_or(1, |n| n + 1))?;
}
Ok(())
}
}
impl<'subs> ArgScope<'subs, 'subs> for UnnamedTypeName {
fn leaf_name(&'subs self) -> Result<LeafName<'subs>> {
Ok(LeafName::UnnamedType(self))
}
fn get_template_arg(&'subs self, _: usize) -> Result<(&'subs TemplateArg, &'subs TemplateArgs)> {
Err(error::Error::BadTemplateArgReference)
}
fn get_function_arg(&'subs self, _: usize) -> Result<&'subs Type> {
Err(error::Error::BadFunctionArgReference)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ArrayType {
DimensionNumber(usize, TypeHandle),
DimensionExpression(Expression, TypeHandle),
NoDimension(TypeHandle),
}
impl Parse for ArrayType {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(ArrayType, IndexStr<'b>)> {
try_begin_parse!("ArrayType", ctx, input);
let tail = consume(b"A", input)?;
if let Ok((num, tail)) = parse_number(10, false, tail) {
debug_assert!(num >= 0);
let tail = consume(b"_", tail)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
return Ok((ArrayType::DimensionNumber(num as _, ty), tail));
}
if let Ok((expr, tail)) = Expression::parse(ctx, subs, tail) {
let tail = consume(b"_", tail)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
return Ok((ArrayType::DimensionExpression(expr, ty), tail));
}
let tail = consume(b"_", tail)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((ArrayType::NoDimension(ty), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ArrayType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_inner(self);
match *self {
ArrayType::DimensionNumber(_, ref ty)
| ArrayType::DimensionExpression(_, ref ty)
| ArrayType::NoDimension(ref ty) => {
ty.demangle(ctx, scope)?;
}
}
if ctx.pop_inner_if(self) {
self.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for ArrayType
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle_as_inner!(self, ctx, scope);
let mut needs_space = true;
while let Some(inner) = ctx.pop_inner() {
let inner_is_array = match inner.downcast_to_type() {
Some(&Type::Qualified(_, ref ty)) => ctx.subs.get_type(ty).map_or(false, |ty| {
DemangleAsInner::<W>::downcast_to_array_type(ty).is_some()
}),
_ => if inner.downcast_to_array_type().is_some() {
needs_space = false;
true
} else {
false
},
};
if inner_is_array {
inner.demangle_as_inner(ctx, scope)?;
} else {
ctx.ensure_space()?;
if inner.is_qualified() {
inner.demangle_as_inner(ctx, scope)?;
ctx.ensure_space()?;
write!(ctx, "(")?;
} else {
write!(ctx, "(")?;
inner.demangle_as_inner(ctx, scope)?;
}
ctx.demangle_inners(scope)?;
write!(ctx, ")")?;
}
}
if needs_space {
ctx.ensure_space()?;
}
match *self {
ArrayType::DimensionNumber(n, _) => {
write!(ctx, "[{}]", n)?;
}
ArrayType::DimensionExpression(ref expr, _) => {
write!(ctx, "[")?;
expr.demangle(ctx, scope)?;
write!(ctx, "]")?;
}
ArrayType::NoDimension(_) => {
write!(ctx, "[]")?;
}
}
Ok(())
}
fn downcast_to_array_type(&self) -> Option<&ArrayType> {
Some(self)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum VectorType {
DimensionNumber(usize, TypeHandle),
DimensionExpression(Expression, TypeHandle),
}
impl Parse for VectorType {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(VectorType, IndexStr<'b>)> {
try_begin_parse!("VectorType", ctx, input);
let tail = consume(b"Dv", input)?;
if let Ok((num, tail)) = parse_number(10, false, tail) {
debug_assert!(num >= 0);
let tail = consume(b"_", tail)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
return Ok((VectorType::DimensionNumber(num as _, ty), tail));
}
let tail = consume(b"_", tail)?;
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let tail = consume(b"_", tail)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((VectorType::DimensionExpression(expr, ty), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for VectorType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_inner(self);
match *self {
VectorType::DimensionNumber(_, ref ty) | VectorType::DimensionExpression(_, ref ty) => {
ty.demangle(ctx, scope)?;
}
}
if ctx.pop_inner_if(self) {
self.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for VectorType
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle_as_inner!(self, ctx, scope);
match *self {
VectorType::DimensionNumber(n, _) => {
write!(ctx, " __vector({})", n)?;
}
VectorType::DimensionExpression(ref expr, _) => {
write!(ctx, " __vector(")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
}
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PointerToMemberType(TypeHandle, TypeHandle);
impl Parse for PointerToMemberType {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(PointerToMemberType, IndexStr<'b>)> {
try_begin_parse!("PointerToMemberType", ctx, input);
let tail = consume(b"M", input)?;
let (ty1, tail) = TypeHandle::parse(ctx, subs, tail)?;
let (ty2, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((PointerToMemberType(ty1, ty2), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for PointerToMemberType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_inner(self);
self.1.demangle(ctx, scope)?;
if ctx.pop_inner_if(self) {
self.demangle_as_inner(ctx, scope)?;
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for PointerToMemberType
where
W: 'subs + DemangleWrite,
{
fn demangle_as_inner<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle_as_inner!(self, ctx, scope);
if ctx.last_char_written != Some('(') {
ctx.ensure_space()?;
}
self.0.demangle(ctx, scope)?;
write!(ctx, "::*")?;
Ok(())
}
fn downcast_to_pointer_to_member(&self) -> Option<&PointerToMemberType> {
Some(self)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TemplateParam(usize);
impl Parse for TemplateParam {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(TemplateParam, IndexStr<'b>)> {
try_begin_parse!("TemplateParam", ctx, input);
let input = consume(b"T", input)?;
let (number, input) = match parse_number(10, false, input) {
Ok((number, input)) => ((number + 1) as _, input),
Err(_) => (0, input),
};
let input = consume(b"_", input)?;
Ok((TemplateParam(number), input))
}
}
impl<'subs, W> Demangle<'subs, W> for TemplateParam
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_demangle_node(DemangleNodeType::TemplateParam);
let ret = if ctx.is_lambda_arg {
write!(ctx, "auto:{}", self.0 + 1)
} else {
let arg = self.resolve(scope)?;
arg.demangle(ctx, scope)
};
ctx.pop_demangle_node();
ret
}
}
impl TemplateParam {
fn resolve<'subs, 'prev>(
&'subs self,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> ::std::result::Result<&'subs TemplateArg, fmt::Error> {
scope
.get_template_arg(self.0)
.map_err(|e| {
log!("Error obtaining template argument: {}", e);
fmt::Error
})
.map(|v| v.0)
}
}
impl<'a> Hash for &'a TemplateParam {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
let self_ref: &TemplateParam = *self;
let self_ptr = self_ref as *const TemplateParam;
self_ptr.hash(state);
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TemplateTemplateParam(TemplateParam);
define_handle! {
pub enum TemplateTemplateParamHandle
}
impl Parse for TemplateTemplateParamHandle {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(TemplateTemplateParamHandle, IndexStr<'b>)> {
try_begin_parse!("TemplateTemplateParamHandle", ctx, input);
if let Ok((sub, tail)) = Substitution::parse(ctx, subs, input) {
match sub {
Substitution::WellKnown(component) => {
return Ok((TemplateTemplateParamHandle::WellKnown(component), tail));
}
Substitution::BackReference(idx) => {
return Ok((TemplateTemplateParamHandle::BackReference(idx), tail));
}
}
}
let (param, tail) = TemplateParam::parse(ctx, subs, input)?;
let ttp = TemplateTemplateParam(param);
let ttp = Substitutable::TemplateTemplateParam(ttp);
let idx = subs.insert(ttp);
let handle = TemplateTemplateParamHandle::BackReference(idx);
Ok((handle, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for TemplateTemplateParam
where
W: 'subs + DemangleWrite,
{
#[inline]
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
self.0.demangle(ctx, scope)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionParam(usize, CvQualifiers, Option<usize>);
impl Parse for FunctionParam {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(FunctionParam, IndexStr<'b>)> {
try_begin_parse!("FunctionParam", ctx, input);
let tail = consume(b"f", input)?;
if tail.is_empty() {
return Err(error::Error::UnexpectedEnd);
}
let (scope, tail) = if let Ok(tail) = consume(b"L", tail) {
parse_number(10, false, tail)?
} else {
(0, tail)
};
let tail = consume(b"p", tail)?;
let (qualifiers, tail) = CvQualifiers::parse(ctx, subs, tail)?;
let (param, tail) = if tail.peek() == Some(b'T') {
(None, consume(b"T", tail)?)
} else if let Ok((num, tail)) = parse_number(10, false, tail) {
(Some(num as usize + 1), consume(b"_", tail)?)
} else {
(Some(0), consume(b"_", tail)?)
};
Ok((FunctionParam(scope as _, qualifiers, param), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for FunctionParam
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match self.2 {
None => write!(ctx, "this"),
Some(i) => write!(ctx, "{{parm#{}}}", i + 1),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TemplateArgs(Vec<TemplateArg>);
impl Parse for TemplateArgs {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(TemplateArgs, IndexStr<'b>)> {
try_begin_parse!("TemplateArgs", ctx, input);
let tail = consume(b"I", input)?;
let (args, tail) = one_or_more::<TemplateArg>(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
Ok((TemplateArgs(args), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for TemplateArgs
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
mut scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
inner_barrier!(ctx);
if ctx.last_char_written == Some('<') {
write!(ctx, " ")?;
}
write!(ctx, "<")?;
ctx.push_demangle_node(DemangleNodeType::TemplateArgs);
let mut need_comma = false;
for arg_index in 0..self.0.len() {
if need_comma {
write!(ctx, ", ")?;
}
if let Some(ref mut scope) = scope {
scope.in_arg = Some((arg_index, self));
}
self.0[arg_index].demangle(ctx, scope)?;
need_comma = true;
}
if ctx.last_char_written == Some('>') {
write!(ctx, " ")?;
}
ctx.pop_demangle_node();
write!(ctx, ">")?;
Ok(())
}
}
impl<'subs> ArgScope<'subs, 'subs> for TemplateArgs {
fn leaf_name(&'subs self) -> Result<LeafName<'subs>> {
Err(error::Error::BadLeafNameReference)
}
fn get_template_arg(&'subs self, idx: usize) -> Result<(&'subs TemplateArg, &'subs TemplateArgs)> {
self.0.get(idx).ok_or(error::Error::BadTemplateArgReference).map(|v| (v, self))
}
fn get_function_arg(&'subs self, _: usize) -> Result<&'subs Type> {
Err(error::Error::BadFunctionArgReference)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TemplateArg {
Type(TypeHandle),
Expression(Expression),
SimpleExpression(ExprPrimary),
ArgPack(Vec<TemplateArg>),
}
impl Parse for TemplateArg {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(TemplateArg, IndexStr<'b>)> {
try_begin_parse!("TemplateArg", ctx, input);
if let Ok(tail) = consume(b"X", input) {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
return Ok((TemplateArg::Expression(expr), tail));
}
if let Ok((expr, tail)) = ExprPrimary::parse(ctx, subs, input) {
return Ok((TemplateArg::SimpleExpression(expr), tail));
}
if let Ok((ty, tail)) = TypeHandle::parse(ctx, subs, input) {
return Ok((TemplateArg::Type(ty), tail));
}
let tail = if input.peek() == Some(b'J') {
consume(b"J", input)?
} else {
consume(b"I", input)?
};
let (args, tail) = if tail.peek() == Some(b'E') {
(vec![], tail)
} else {
zero_or_more::<TemplateArg>(ctx, subs, tail)?
};
let tail = consume(b"E", tail)?;
Ok((TemplateArg::ArgPack(args), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for TemplateArg
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
TemplateArg::Type(ref ty) => ty.demangle(ctx, scope),
TemplateArg::Expression(ref expr) => expr.demangle(ctx, scope),
TemplateArg::SimpleExpression(ref expr) => expr.demangle(ctx, scope),
TemplateArg::ArgPack(ref args) => {
ctx.is_template_argument_pack = true;
let mut need_comma = false;
for arg in &args[..] {
if need_comma {
write!(ctx, ", ")?;
}
arg.demangle(ctx, scope)?;
need_comma = true;
}
Ok(())
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MemberName(Name);
impl Parse for MemberName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(MemberName, IndexStr<'b>)> {
try_begin_parse!("MemberName", ctx, input);
let (name, tail) = UnqualifiedName::parse(ctx, subs, input)?;
let name = UnscopedName::Unqualified(name);
if let Ok((template, tail)) = TemplateArgs::parse(ctx, subs, tail) {
let name = UnscopedTemplateName(name);
let idx = subs.insert_non_substitution(Substitutable::UnscopedTemplateName(name));
let handle = UnscopedTemplateNameHandle::NonSubstitution(NonSubstitution(idx));
Ok((MemberName(Name::UnscopedTemplate(handle, template)), tail))
} else {
Ok((MemberName(Name::Unscoped(name)), tail))
}
}
}
impl<'subs, W> Demangle<'subs, W> for MemberName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
let needs_parens = self.0.get_template_args(ctx.subs).is_some();
if needs_parens {
write!(ctx, "(")?;
}
self.0.demangle(ctx, scope)?;
if needs_parens {
write!(ctx, ")")?;
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expression {
Unary(OperatorName, Box<Expression>),
Binary(OperatorName, Box<Expression>, Box<Expression>),
Ternary(
OperatorName,
Box<Expression>,
Box<Expression>,
Box<Expression>,
),
PrefixInc(Box<Expression>),
PrefixDec(Box<Expression>),
Call(Box<Expression>, Vec<Expression>),
ConversionOne(TypeHandle, Box<Expression>),
ConversionMany(TypeHandle, Vec<Expression>),
ConversionBraced(TypeHandle, Vec<Expression>),
BracedInitList(Box<Expression>),
New(Vec<Expression>, TypeHandle, Option<Initializer>),
GlobalNew(Vec<Expression>, TypeHandle, Option<Initializer>),
NewArray(Vec<Expression>, TypeHandle, Option<Initializer>),
GlobalNewArray(Vec<Expression>, TypeHandle, Option<Initializer>),
Delete(Box<Expression>),
GlobalDelete(Box<Expression>),
DeleteArray(Box<Expression>),
GlobalDeleteArray(Box<Expression>),
DynamicCast(TypeHandle, Box<Expression>),
StaticCast(TypeHandle, Box<Expression>),
ConstCast(TypeHandle, Box<Expression>),
ReinterpretCast(TypeHandle, Box<Expression>),
TypeidType(TypeHandle),
TypeidExpr(Box<Expression>),
SizeofType(TypeHandle),
SizeofExpr(Box<Expression>),
AlignofType(TypeHandle),
AlignofExpr(Box<Expression>),
Noexcept(Box<Expression>),
TemplateParam(TemplateParam),
FunctionParam(FunctionParam),
Member(Box<Expression>, MemberName),
DerefMember(Box<Expression>, MemberName),
PointerToMember(Box<Expression>, Box<Expression>),
SizeofTemplatePack(TemplateParam),
SizeofFunctionPack(FunctionParam),
SizeofCapturedTemplatePack(Vec<TemplateArg>),
PackExpansion(Box<Expression>),
Throw(Box<Expression>),
Rethrow,
UnresolvedName(UnresolvedName),
Primary(ExprPrimary),
}
impl Parse for Expression {
#[allow(cyclomatic_complexity)]
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Expression, IndexStr<'b>)> {
try_begin_parse!("Expression", ctx, input);
if let Ok(tail) = consume(b"pp_", input) {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::PrefixInc(Box::new(expr));
return Ok((expr, tail));
}
if let Ok(tail) = consume(b"mm_", input) {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::PrefixDec(Box::new(expr));
return Ok((expr, tail));
}
if let Some((head, tail)) = input.try_split_at(2) {
match head.as_ref() {
b"cl" => {
let (func, tail) = Expression::parse(ctx, subs, tail)?;
let (args, tail) = zero_or_more::<Expression>(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let expr = Expression::Call(Box::new(func), args);
return Ok((expr, tail));
}
b"cv" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
if let Ok(tail) = consume(b"_", tail) {
let (exprs, tail) = zero_or_more::<Expression>(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let expr = Expression::ConversionMany(ty, exprs);
return Ok((expr, tail));
} else {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::ConversionOne(ty, Box::new(expr));
return Ok((expr, tail));
}
}
b"tl" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let (exprs, tail) = zero_or_more::<Expression>(ctx, subs, tail)?;
let expr = Expression::ConversionBraced(ty, exprs);
let tail = consume(b"E", tail)?;
return Ok((expr, tail));
}
b"il" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let expr = Expression::BracedInitList(Box::new(expr));
return Ok((expr, tail));
}
b"dc" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::DynamicCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"sc" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::StaticCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"cc" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::ConstCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"rc" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::ReinterpretCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"ti" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let expr = Expression::TypeidType(ty);
return Ok((expr, tail));
}
b"te" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::TypeidExpr(Box::new(expr));
return Ok((expr, tail));
}
b"st" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let expr = Expression::SizeofType(ty);
return Ok((expr, tail));
}
b"sz" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::SizeofExpr(Box::new(expr));
return Ok((expr, tail));
}
b"at" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
let expr = Expression::AlignofType(ty);
return Ok((expr, tail));
}
b"az" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::AlignofExpr(Box::new(expr));
return Ok((expr, tail));
}
b"nx" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::Noexcept(Box::new(expr));
return Ok((expr, tail));
}
b"dt" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let (name, tail) = MemberName::parse(ctx, subs, tail)?;
let expr = Expression::Member(Box::new(expr), name);
return Ok((expr, tail));
}
b"pt" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let (name, tail) = MemberName::parse(ctx, subs, tail)?;
let expr = Expression::DerefMember(Box::new(expr), name);
return Ok((expr, tail));
}
b"ds" => {
let (first, tail) = Expression::parse(ctx, subs, tail)?;
let (second, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::PointerToMember(Box::new(first), Box::new(second));
return Ok((expr, tail));
}
b"sZ" => {
if let Ok((param, tail)) = TemplateParam::parse(ctx, subs, tail) {
let expr = Expression::SizeofTemplatePack(param);
return Ok((expr, tail));
}
let (param, tail) = FunctionParam::parse(ctx, subs, tail)?;
let expr = Expression::SizeofFunctionPack(param);
return Ok((expr, tail));
}
b"sP" => {
let (args, tail) = zero_or_more::<TemplateArg>(ctx, subs, tail)?;
let expr = Expression::SizeofCapturedTemplatePack(args);
let tail = consume(b"E", tail)?;
return Ok((expr, tail));
}
b"sp" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::PackExpansion(Box::new(expr));
return Ok((expr, tail));
}
b"tw" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = Expression::Throw(Box::new(expr));
return Ok((expr, tail));
}
b"tr" => {
let expr = Expression::Rethrow;
return Ok((expr, tail));
}
b"gs" => {
if let Ok((expr, tail)) = can_be_global(true, ctx, subs, tail) {
return Ok((expr, tail));
}
}
_ => {}
}
}
if let Ok((expr, tail)) = can_be_global(false, ctx, subs, input) {
return Ok((expr, tail));
}
if let Ok((param, tail)) = TemplateParam::parse(ctx, subs, input) {
let expr = Expression::TemplateParam(param);
return Ok((expr, tail));
}
if let Ok((param, tail)) = FunctionParam::parse(ctx, subs, input) {
let expr = Expression::FunctionParam(param);
return Ok((expr, tail));
}
if let Ok((name, tail)) = UnresolvedName::parse(ctx, subs, input) {
let expr = Expression::UnresolvedName(name);
return Ok((expr, tail));
}
if let Ok((prim, tail)) = ExprPrimary::parse(ctx, subs, input) {
let expr = Expression::Primary(prim);
return Ok((expr, tail));
}
let (expr, tail) = OperatorName::parse_from_expr(ctx, subs, input)?;
return Ok((expr, tail));
fn can_be_global<'a, 'b>(
is_global: bool,
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Expression, IndexStr<'b>)> {
match input.try_split_at(2) {
None => Err(error::Error::UnexpectedEnd),
Some((head, tail)) => match head.as_ref() {
b"nw" => {
let (exprs, tail) = zero_or_more::<Expression>(ctx, subs, tail)?;
let tail = consume(b"_", tail)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
if let Ok(tail) = consume(b"E", tail) {
let expr = if is_global {
Expression::GlobalNew(exprs, ty, None)
} else {
Expression::New(exprs, ty, None)
};
Ok((expr, tail))
} else {
let (init, tail) = Initializer::parse(ctx, subs, tail)?;
let expr = if is_global {
Expression::GlobalNew(exprs, ty, Some(init))
} else {
Expression::New(exprs, ty, Some(init))
};
Ok((expr, tail))
}
}
b"na" => {
let (exprs, tail) = zero_or_more::<Expression>(ctx, subs, tail)?;
let tail = consume(b"_", tail)?;
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
if let Ok(tail) = consume(b"E", tail) {
let expr = if is_global {
Expression::GlobalNewArray(exprs, ty, None)
} else {
Expression::NewArray(exprs, ty, None)
};
Ok((expr, tail))
} else {
let (init, tail) = Initializer::parse(ctx, subs, tail)?;
let expr = if is_global {
Expression::GlobalNewArray(exprs, ty, Some(init))
} else {
Expression::NewArray(exprs, ty, Some(init))
};
Ok((expr, tail))
}
}
b"dl" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = if is_global {
Expression::GlobalDelete(Box::new(expr))
} else {
Expression::Delete(Box::new(expr))
};
Ok((expr, tail))
}
b"da" => {
let (expr, tail) = Expression::parse(ctx, subs, tail)?;
let expr = if is_global {
Expression::GlobalDeleteArray(Box::new(expr))
} else {
Expression::DeleteArray(Box::new(expr))
};
Ok((expr, tail))
}
_ => Err(error::Error::UnexpectedText),
},
}
}
}
}
impl<'subs, W> Demangle<'subs, W> for Expression
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
Expression::Unary(
OperatorName::Simple(ref op),
ref expr
) if *op == SimpleOperatorName::PostInc || *op == SimpleOperatorName::PostDec => {
expr.demangle_as_subexpr(ctx, scope)?;
op.demangle(ctx, scope)
}
Expression::Unary(ref op, ref expr) => {
op.demangle(ctx, scope)?;
expr.demangle_as_subexpr(ctx, scope)
}
Expression::Binary(
OperatorName::Simple(SimpleOperatorName::Greater),
ref lhs,
ref rhs,
) => {
write!(ctx, "((")?;
lhs.demangle(ctx, scope)?;
write!(ctx, ")>(")?;
rhs.demangle(ctx, scope)?;
write!(ctx, "))")
}
Expression::Binary(ref op, ref lhs, ref rhs) => {
lhs.demangle_as_subexpr(ctx, scope)?;
op.demangle(ctx, scope)?;
rhs.demangle_as_subexpr(ctx, scope)
}
Expression::Ternary(
OperatorName::Simple(SimpleOperatorName::Question),
ref condition,
ref consequent,
ref alternative,
) => {
condition.demangle_as_subexpr(ctx, scope)?;
write!(ctx, "?")?;
consequent.demangle_as_subexpr(ctx, scope)?;
write!(ctx, " : ")?;
alternative.demangle_as_subexpr(ctx, scope)
}
Expression::Ternary(ref op, ref e1, ref e2, ref e3) => {
op.demangle(ctx, scope)?;
write!(ctx, "(")?;
e1.demangle(ctx, scope)?;
write!(ctx, ", ")?;
e2.demangle(ctx, scope)?;
write!(ctx, ", ")?;
e3.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::PrefixInc(ref expr) => {
write!(ctx, "++")?;
expr.demangle(ctx, scope)
}
Expression::PrefixDec(ref expr) => {
write!(ctx, "--")?;
expr.demangle(ctx, scope)
}
Expression::Call(ref functor_expr, ref args) => {
functor_expr.demangle_as_subexpr(ctx, scope)?;
write!(ctx, "(")?;
let mut need_comma = false;
for arg in args {
if need_comma {
write!(ctx, ", ")?;
}
arg.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ")")?;
Ok(())
}
Expression::ConversionOne(ref ty, ref expr) => {
write!(ctx, "(")?;
ty.demangle(ctx, scope)?;
write!(ctx, ")(")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::ConversionMany(ref ty, ref exprs) => {
ty.demangle(ctx, scope)?;
write!(ctx, "(")?;
let mut need_comma = false;
for expr in exprs {
if need_comma {
write!(ctx, ", ")?;
}
expr.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ")")?;
Ok(())
}
Expression::ConversionBraced(ref ty, ref exprs) => {
ty.demangle(ctx, scope)?;
write!(ctx, "{{")?;
let mut need_comma = false;
for expr in exprs {
if need_comma {
write!(ctx, ", ")?;
}
expr.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, "}}")?;
Ok(())
}
Expression::BracedInitList(ref expr) => {
write!(ctx, "{{")?;
expr.demangle(ctx, scope)?;
write!(ctx, "}}")?;
Ok(())
}
Expression::New(ref exprs, ref ty, ref init) => {
write!(ctx, "new (")?;
let mut need_comma = false;
for expr in exprs {
if need_comma {
write!(ctx, ", ")?;
}
expr.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ") ")?;
ty.demangle(ctx, scope)?;
if let Some(ref init) = *init {
init.demangle(ctx, scope)?;
}
Ok(())
}
Expression::GlobalNew(ref exprs, ref ty, ref init) => {
write!(ctx, "::new (")?;
let mut need_comma = false;
for expr in exprs {
if need_comma {
write!(ctx, ", ")?;
}
expr.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ") ")?;
ty.demangle(ctx, scope)?;
if let Some(ref init) = *init {
init.demangle(ctx, scope)?;
}
Ok(())
}
Expression::NewArray(ref exprs, ref ty, ref init) => {
write!(ctx, "new[] (")?;
let mut need_comma = false;
for expr in exprs {
if need_comma {
write!(ctx, ", ")?;
}
expr.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ") ")?;
ty.demangle(ctx, scope)?;
if let Some(ref init) = *init {
init.demangle(ctx, scope)?;
}
Ok(())
}
Expression::GlobalNewArray(ref exprs, ref ty, ref init) => {
write!(ctx, "::new[] (")?;
let mut need_comma = false;
for expr in exprs {
if need_comma {
write!(ctx, ", ")?;
}
expr.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ") ")?;
ty.demangle(ctx, scope)?;
if let Some(ref init) = *init {
init.demangle(ctx, scope)?;
}
Ok(())
}
Expression::Delete(ref expr) => {
write!(ctx, "delete ")?;
expr.demangle(ctx, scope)
}
Expression::GlobalDelete(ref expr) => {
write!(ctx, "::delete ")?;
expr.demangle(ctx, scope)
}
Expression::DeleteArray(ref expr) => {
write!(ctx, "delete[] ")?;
expr.demangle(ctx, scope)
}
Expression::GlobalDeleteArray(ref expr) => {
write!(ctx, "::delete[] ")?;
expr.demangle(ctx, scope)
}
Expression::DynamicCast(ref ty, ref expr) => {
write!(ctx, "dynamic_cast<")?;
ty.demangle(ctx, scope)?;
write!(ctx, ">(")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::StaticCast(ref ty, ref expr) => {
write!(ctx, "static_cast<")?;
ty.demangle(ctx, scope)?;
write!(ctx, ">(")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::ConstCast(ref ty, ref expr) => {
write!(ctx, "const_cast<")?;
ty.demangle(ctx, scope)?;
write!(ctx, ">(")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::ReinterpretCast(ref ty, ref expr) => {
write!(ctx, "reinterpret_cast<")?;
ty.demangle(ctx, scope)?;
write!(ctx, ">(")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::TypeidType(ref ty) => {
write!(ctx, "typeid (")?;
ty.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::TypeidExpr(ref expr) => {
write!(ctx, "typeid (")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::SizeofType(ref ty) => {
write!(ctx, "sizeof (")?;
ty.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::SizeofExpr(ref expr) => {
write!(ctx, "sizeof (")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::AlignofType(ref ty) => {
write!(ctx, "alignof (")?;
ty.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::AlignofExpr(ref expr) => {
write!(ctx, "alignof (")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::Noexcept(ref expr) => {
write!(ctx, "noexcept (")?;
expr.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::TemplateParam(ref param) => param.demangle(ctx, scope),
Expression::FunctionParam(ref param) => param.demangle(ctx, scope),
Expression::Member(ref expr, ref name) => {
expr.demangle_as_subexpr(ctx, scope)?;
write!(ctx, ".")?;
name.demangle(ctx, scope)
}
Expression::DerefMember(ref expr, ref name) => {
expr.demangle(ctx, scope)?;
write!(ctx, "->")?;
name.demangle(ctx, scope)
}
Expression::PointerToMember(ref e1, ref e2) => {
e1.demangle(ctx, scope)?;
write!(ctx, ".*")?;
e2.demangle(ctx, scope)
}
Expression::SizeofTemplatePack(ref param) => {
write!(ctx, "sizeof...(")?;
param.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::SizeofFunctionPack(ref param) => {
write!(ctx, "sizeof...(")?;
param.demangle(ctx, scope)?;
write!(ctx, ")")?;
Ok(())
}
Expression::SizeofCapturedTemplatePack(ref args) => {
write!(ctx, "sizeof...(")?;
let mut need_comma = false;
for arg in args {
if need_comma {
write!(ctx, ", ")?;
}
arg.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ")")?;
Ok(())
}
Expression::PackExpansion(ref pack) => {
pack.demangle_as_subexpr(ctx, scope)?;
write!(ctx, "...")?;
Ok(())
}
Expression::Throw(ref expr) => {
write!(ctx, "throw ")?;
expr.demangle(ctx, scope)
}
Expression::Rethrow => {
write!(ctx, "throw")?;
Ok(())
}
Expression::UnresolvedName(ref name) => name.demangle(ctx, scope),
Expression::Primary(ref expr) => expr.demangle(ctx, scope),
}
}
}
impl Expression {
fn demangle_as_subexpr<'subs, 'prev, 'ctx, W>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result
where W: 'subs + DemangleWrite
{
let needs_parens = match *self {
Expression::FunctionParam(_) |
Expression::Primary(ExprPrimary::External(_)) => false,
_ => true,
};
if needs_parens {
write!(ctx, "(")?;
}
self.demangle(ctx, scope)?;
if needs_parens {
write!(ctx, ")")?;
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnresolvedName {
Name(BaseUnresolvedName),
Global(BaseUnresolvedName),
Nested1(
UnresolvedTypeHandle,
Vec<UnresolvedQualifierLevel>,
BaseUnresolvedName,
),
Nested2(Vec<UnresolvedQualifierLevel>, BaseUnresolvedName),
GlobalNested2(Vec<UnresolvedQualifierLevel>, BaseUnresolvedName),
}
impl Parse for UnresolvedName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(UnresolvedName, IndexStr<'b>)> {
try_begin_parse!("UnresolvedName", ctx, input);
if let Ok(tail) = consume(b"gs", input) {
if let Ok((name, tail)) = BaseUnresolvedName::parse(ctx, subs, tail) {
return Ok((UnresolvedName::Global(name), tail));
}
let tail = consume(b"sr", tail)?;
let (levels, tail) = one_or_more::<UnresolvedQualifierLevel>(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let (name, tail) = BaseUnresolvedName::parse(ctx, subs, tail)?;
return Ok((UnresolvedName::GlobalNested2(levels, name), tail));
}
if let Ok((name, tail)) = BaseUnresolvedName::parse(ctx, subs, input) {
return Ok((UnresolvedName::Name(name), tail));
}
let tail = consume(b"sr", input)?;
if tail.peek() == Some(b'N') {
let tail = consume(b"N", tail).unwrap();
let (ty, tail) = UnresolvedTypeHandle::parse(ctx, subs, tail)?;
let (levels, tail) = one_or_more::<UnresolvedQualifierLevel>(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let (name, tail) = BaseUnresolvedName::parse(ctx, subs, tail)?;
return Ok((UnresolvedName::Nested1(ty, levels, name), tail));
}
if let Ok((ty, tail)) = UnresolvedTypeHandle::parse(ctx, subs, tail) {
let (name, tail) = BaseUnresolvedName::parse(ctx, subs, tail)?;
return Ok((UnresolvedName::Nested1(ty, vec![], name), tail));
}
let (levels, tail) = one_or_more::<UnresolvedQualifierLevel>(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let (name, tail) = BaseUnresolvedName::parse(ctx, subs, tail)?;
Ok((UnresolvedName::Nested2(levels, name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for UnresolvedName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
UnresolvedName::Name(ref name) => name.demangle(ctx, scope),
UnresolvedName::Global(ref name) => {
write!(ctx, "::")?;
name.demangle(ctx, scope)
}
UnresolvedName::Nested1(ref ty, ref levels, ref name) => {
ty.demangle(ctx, scope)?;
write!(ctx, "::")?;
for lvl in &levels[..] {
lvl.demangle(ctx, scope)?;
write!(ctx, "::")?;
}
name.demangle(ctx, scope)
}
UnresolvedName::Nested2(ref levels, ref name) => {
for lvl in &levels[..] {
lvl.demangle(ctx, scope)?;
write!(ctx, "::")?;
}
name.demangle(ctx, scope)
}
UnresolvedName::GlobalNested2(ref levels, ref name) => {
write!(ctx, "::")?;
for lvl in &levels[..] {
lvl.demangle(ctx, scope)?;
write!(ctx, "::")?;
}
name.demangle(ctx, scope)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnresolvedType {
Template(TemplateParam, Option<TemplateArgs>),
Decltype(Decltype),
}
define_handle! {
pub enum UnresolvedTypeHandle
}
impl Parse for UnresolvedTypeHandle {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(UnresolvedTypeHandle, IndexStr<'b>)> {
try_begin_parse!("UnresolvedTypeHandle", ctx, input);
if let Ok((param, tail)) = TemplateParam::parse(ctx, subs, input) {
let (args, tail) = if let Ok((args, tail)) = TemplateArgs::parse(ctx, subs, tail) {
(Some(args), tail)
} else {
(None, tail)
};
let ty = UnresolvedType::Template(param, args);
let ty = Substitutable::UnresolvedType(ty);
let idx = subs.insert(ty);
let handle = UnresolvedTypeHandle::BackReference(idx);
return Ok((handle, tail));
}
if let Ok((decltype, tail)) = Decltype::parse(ctx, subs, input) {
let ty = UnresolvedType::Decltype(decltype);
let ty = Substitutable::UnresolvedType(ty);
let idx = subs.insert(ty);
let handle = UnresolvedTypeHandle::BackReference(idx);
return Ok((handle, tail));
}
let (sub, tail) = Substitution::parse(ctx, subs, input)?;
match sub {
Substitution::WellKnown(component) => {
Ok((UnresolvedTypeHandle::WellKnown(component), tail))
}
Substitution::BackReference(idx) => {
Ok((UnresolvedTypeHandle::BackReference(idx), tail))
}
}
}
}
impl<'subs, W> Demangle<'subs, W> for UnresolvedType
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
UnresolvedType::Decltype(ref dt) => dt.demangle(ctx, scope),
UnresolvedType::Template(ref param, ref args) => {
if let Some(ref args) = *args {
let scope = scope.push(args);
param.demangle(ctx, scope)?;
args.demangle(ctx, scope)?;
} else {
param.demangle(ctx, scope)?;
}
Ok(())
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnresolvedQualifierLevel(SimpleId);
impl Parse for UnresolvedQualifierLevel {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(UnresolvedQualifierLevel, IndexStr<'b>)> {
try_begin_parse!("UnresolvedQualifierLevel", ctx, input);
let (id, tail) = SimpleId::parse(ctx, subs, input)?;
Ok((UnresolvedQualifierLevel(id), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for UnresolvedQualifierLevel
where
W: 'subs + DemangleWrite,
{
#[inline]
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
self.0.demangle(ctx, scope)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SimpleId(SourceName, Option<TemplateArgs>);
impl Parse for SimpleId {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(SimpleId, IndexStr<'b>)> {
try_begin_parse!("SimpleId", ctx, input);
let (name, tail) = SourceName::parse(ctx, subs, input)?;
let (args, tail) = if let Ok((args, tail)) = TemplateArgs::parse(ctx, subs, tail) {
(Some(args), tail)
} else {
(None, tail)
};
Ok((SimpleId(name, args), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for SimpleId
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
self.0.demangle(ctx, scope)?;
if let Some(ref args) = self.1 {
args.demangle(ctx, scope)?;
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BaseUnresolvedName {
Name(SimpleId),
Operator(OperatorName, Option<TemplateArgs>),
Destructor(DestructorName),
}
impl Parse for BaseUnresolvedName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(BaseUnresolvedName, IndexStr<'b>)> {
try_begin_parse!("BaseUnresolvedName", ctx, input);
if let Ok((name, tail)) = SimpleId::parse(ctx, subs, input) {
return Ok((BaseUnresolvedName::Name(name), tail));
}
if let Ok(tail) = consume(b"on", input) {
let (opname, tail) = OperatorName::parse(ctx, subs, tail)?;
let (args, tail) = if let Ok((args, tail)) = TemplateArgs::parse(ctx, subs, tail) {
(Some(args), tail)
} else {
(None, tail)
};
return Ok((BaseUnresolvedName::Operator(opname, args), tail));
}
let tail = consume(b"dn", input)?;
let (name, tail) = DestructorName::parse(ctx, subs, tail)?;
Ok((BaseUnresolvedName::Destructor(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for BaseUnresolvedName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
BaseUnresolvedName::Name(ref name) => name.demangle(ctx, scope),
BaseUnresolvedName::Destructor(ref dtor) => dtor.demangle(ctx, scope),
BaseUnresolvedName::Operator(ref op, ref args) => {
op.demangle(ctx, scope)?;
if let Some(ref args) = *args {
args.demangle(ctx, scope)?;
}
Ok(())
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DestructorName {
Unresolved(UnresolvedTypeHandle),
Name(SimpleId),
}
impl Parse for DestructorName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(DestructorName, IndexStr<'b>)> {
try_begin_parse!("DestructorName", ctx, input);
if let Ok((ty, tail)) = UnresolvedTypeHandle::parse(ctx, subs, input) {
return Ok((DestructorName::Unresolved(ty), tail));
}
let (name, tail) = SimpleId::parse(ctx, subs, input)?;
Ok((DestructorName::Name(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for DestructorName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
write!(ctx, "~")?;
match *self {
DestructorName::Unresolved(ref ty) => ty.demangle(ctx, scope),
DestructorName::Name(ref name) => name.demangle(ctx, scope),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ExprPrimary {
Literal(TypeHandle, usize, usize),
External(MangledName),
}
impl Parse for ExprPrimary {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(ExprPrimary, IndexStr<'b>)> {
try_begin_parse!("ExprPrimary", ctx, input);
let tail = consume(b"L", input)?;
if let Ok((ty, tail)) = TypeHandle::parse(ctx, subs, tail) {
let start = tail.index();
let num_bytes_in_literal = tail.as_ref().iter().take_while(|&&c| c != b'E').count();
let tail = tail.range_from(num_bytes_in_literal..);
let end = tail.index();
let tail = consume(b"E", tail)?;
let expr = ExprPrimary::Literal(ty, start, end);
return Ok((expr, tail));
}
let (name, tail) = MangledName::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let expr = ExprPrimary::External(name);
Ok((expr, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ExprPrimary
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
fn write_literal<W>(
ctx: &mut DemangleContext<W>,
start: usize,
end: usize,
) -> fmt::Result
where
W: DemangleWrite,
{
debug_assert!(start <= end);
let start = if start < end && ctx.input[start] == b'n' {
write!(ctx, "-")?;
start + 1
} else {
start
};
let s = ::std::str::from_utf8(&ctx.input[start..end]).map_err(|e| {
log!("Error writing literal: {}", e);
fmt::Error
})?;
ctx.write_str(s)
}
match *self {
ExprPrimary::External(ref name) => {
let saved_show_params = ctx.show_params;
ctx.show_params = true;
let ret = name.demangle(ctx, scope);
ctx.show_params = saved_show_params;
ret
}
ExprPrimary::Literal(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Bool)),
start,
end,
) => match &ctx.input[start..end] {
b"0" => write!(ctx, "false"),
b"1" => write!(ctx, "true"),
_ => {
write!(ctx, "(bool)")?;
write_literal(ctx, start, end)
}
},
ExprPrimary::Literal(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Nullptr)),
_,
_,
) => write!(ctx, "nullptr"),
ExprPrimary::Literal(
ref ty @ TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Double)),
start,
end,
)
| ExprPrimary::Literal(
ref ty @ TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Float)),
start,
end,
) => {
write!(ctx, "(")?;
ty.demangle(ctx, scope)?;
let start = if start < end && ctx.input[start] == b'n' {
write!(ctx, ")-[")?;
start + 1
} else {
write!(ctx, ")[")?;
start
};
let s = ::std::str::from_utf8(&ctx.input[start..end]).map_err(|e| {
log!("Error writing literal: {}", e);
fmt::Error
})?;
ctx.write_str(s)?;
write!(ctx, "]")
}
ExprPrimary::Literal(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int)),
start,
end,
) => write_literal(ctx, start, end),
ExprPrimary::Literal(ref ty, start, end) => {
write!(ctx, "(")?;
ty.demangle(ctx, scope)?;
write!(ctx, ")")?;
write_literal(ctx, start, end)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Initializer(Vec<Expression>);
impl Parse for Initializer {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Initializer, IndexStr<'b>)> {
try_begin_parse!("Initializer", ctx, input);
let tail = consume(b"pi", input)?;
let (exprs, tail) = zero_or_more::<Expression>(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
Ok((Initializer(exprs), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Initializer
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
write!(ctx, "(")?;
let mut need_comma = false;
for expr in &self.0 {
if need_comma {
write!(ctx, ", ")?;
}
expr.demangle(ctx, scope)?;
need_comma = true;
}
write!(ctx, ")")?;
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LocalName {
Relative(Box<Encoding>, Option<Box<Name>>, Option<Discriminator>),
Default(Box<Encoding>, Option<usize>, Box<Name>),
}
impl Parse for LocalName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(LocalName, IndexStr<'b>)> {
try_begin_parse!("LocalName", ctx, input);
let tail = consume(b"Z", input)?;
let (encoding, tail) = Encoding::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
if let Ok(tail) = consume(b"s", tail) {
let (disc, tail) = if let Ok((disc, tail)) = Discriminator::parse(ctx, subs, tail) {
(Some(disc), tail)
} else {
(None, tail)
};
return Ok((LocalName::Relative(Box::new(encoding), None, disc), tail));
}
if let Ok(tail) = consume(b"d", tail) {
let (param, tail) = if let Ok((num, tail)) = Number::parse(ctx, subs, tail) {
(Some(num as _), tail)
} else {
(None, tail)
};
let tail = consume(b"_", tail)?;
let (name, tail) = Name::parse(ctx, subs, tail)?;
return Ok((
LocalName::Default(Box::new(encoding), param, Box::new(name)),
tail,
));
}
let (name, tail) = Name::parse(ctx, subs, tail)?;
let (disc, tail) = if let Ok((disc, tail)) = Discriminator::parse(ctx, subs, tail) {
(Some(disc), tail)
} else {
(None, tail)
};
Ok((
LocalName::Relative(Box::new(encoding), Some(Box::new(name)), disc),
tail,
))
}
}
impl<'subs, W> Demangle<'subs, W> for LocalName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
let saved_show_params = ctx.show_params;
ctx.show_params = true;
let ret = match *self {
LocalName::Relative(ref encoding, Some(ref name), _) => {
encoding.demangle(ctx, scope)?;
write!(ctx, "::")?;
name.demangle(ctx, scope)
}
LocalName::Relative(ref encoding, None, _) => {
encoding.demangle(ctx, scope)?;
write!(ctx, "::string literal")?;
Ok(())
}
LocalName::Default(ref encoding, _, _) => encoding.demangle(ctx, scope),
};
ctx.show_params = saved_show_params;
ret
}
}
impl GetTemplateArgs for LocalName {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
match *self {
LocalName::Relative(_, None, _) => None,
LocalName::Relative(_, Some(ref name), _) | LocalName::Default(_, _, ref name) => {
name.get_template_args(subs)
}
}
}
}
impl<'a> GetLeafName<'a> for LocalName {
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
LocalName::Relative(_, None, _) => None,
LocalName::Relative(_, Some(ref name), _) | LocalName::Default(_, _, ref name) => {
name.get_leaf_name(subs)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Discriminator(usize);
impl Parse for Discriminator {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
_subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Discriminator, IndexStr<'b>)> {
try_begin_parse!("Discriminator", ctx, input);
let tail = consume(b"_", input)?;
if let Ok(tail) = consume(b"_", tail) {
let (num, tail) = parse_number(10, false, tail)?;
debug_assert!(num >= 0);
if num < 10 {
return Err(error::Error::UnexpectedText);
}
let tail = consume(b"_", tail)?;
return Ok((Discriminator(num as _), tail));
}
match tail.try_split_at(1) {
None => Err(error::Error::UnexpectedEnd),
Some((head, tail)) => match head.as_ref()[0] {
b'0' => Ok((Discriminator(0), tail)),
b'1' => Ok((Discriminator(1), tail)),
b'2' => Ok((Discriminator(2), tail)),
b'3' => Ok((Discriminator(3), tail)),
b'4' => Ok((Discriminator(4), tail)),
b'5' => Ok((Discriminator(5), tail)),
b'6' => Ok((Discriminator(6), tail)),
b'7' => Ok((Discriminator(7), tail)),
b'8' => Ok((Discriminator(8), tail)),
b'9' => Ok((Discriminator(9), tail)),
_ => Err(error::Error::UnexpectedText),
},
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClosureTypeName(LambdaSig, Option<usize>);
impl Parse for ClosureTypeName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(ClosureTypeName, IndexStr<'b>)> {
try_begin_parse!("ClosureTypeName", ctx, input);
let tail = consume(b"Ul", input)?;
let (sig, tail) = LambdaSig::parse(ctx, subs, tail)?;
let tail = consume(b"E", tail)?;
let (num, tail) = if let Ok((num, tail)) = parse_number(10, false, tail) {
(Some(num as _), tail)
} else {
(None, tail)
};
let tail = consume(b"_", tail)?;
Ok((ClosureTypeName(sig, num), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ClosureTypeName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
write!(ctx, "{{lambda(")?;
self.0.demangle(ctx, scope)?;
write!(ctx, ")#{}}}", self.1.map_or(1, |n| n + 2))?;
Ok(())
}
}
impl<'subs> ArgScope<'subs, 'subs> for ClosureTypeName {
fn leaf_name(&'subs self) -> Result<LeafName<'subs>> {
Ok(LeafName::Closure(self))
}
fn get_template_arg(&'subs self, _: usize) -> Result<(&'subs TemplateArg, &'subs TemplateArgs)> {
Err(error::Error::BadTemplateArgReference)
}
fn get_function_arg(&'subs self, _: usize) -> Result<&'subs Type> {
Err(error::Error::BadFunctionArgReference)
}
}
impl<'a> GetLeafName<'a> for ClosureTypeName {
#[inline]
fn get_leaf_name(&'a self, _: &'a SubstitutionTable) -> Option<LeafName<'a>> {
Some(LeafName::Closure(self))
}
}
impl ClosureTypeName {
#[inline]
fn starts_with(byte: u8, input: &IndexStr) -> bool {
byte == b'U' && input.peek_second().map(|b| b == b'l').unwrap_or(false)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LambdaSig(Vec<TypeHandle>);
impl LambdaSig {
fn demangle_args<'subs, 'prev, 'ctx, W>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result
where W: 'subs + DemangleWrite
{
let mut need_comma = false;
for ty in &self.0 {
if need_comma {
write!(ctx, ", ")?;
}
ty.demangle(ctx, scope)?;
need_comma = true;
}
Ok(())
}
}
impl Parse for LambdaSig {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(LambdaSig, IndexStr<'b>)> {
try_begin_parse!("LambdaSig", ctx, input);
let (types, tail) = if let Ok(tail) = consume(b"v", input) {
(vec![], tail)
} else {
one_or_more::<TypeHandle>(ctx, subs, input)?
};
Ok((LambdaSig(types), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for LambdaSig
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.is_lambda_arg = true;
let r = self.demangle_args(ctx, scope);
ctx.is_lambda_arg = false;
r
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DataMemberPrefix(SourceName);
impl Parse for DataMemberPrefix {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(DataMemberPrefix, IndexStr<'b>)> {
try_begin_parse!("DataMemberPrefix", ctx, input);
let (name, tail) = SourceName::parse(ctx, subs, input)?;
let tail = consume(b"M", tail)?;
Ok((DataMemberPrefix(name), tail))
}
}
impl<'a> GetLeafName<'a> for DataMemberPrefix {
#[inline]
fn get_leaf_name(&'a self, _: &'a SubstitutionTable) -> Option<LeafName<'a>> {
Some(LeafName::SourceName(&self.0))
}
}
impl DataMemberPrefix {
fn starts_with(byte: u8) -> bool {
SourceName::starts_with(byte)
}
}
impl<'subs, W> Demangle<'subs, W> for DataMemberPrefix
where
W: 'subs + DemangleWrite,
{
#[inline]
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
ctx.push_demangle_node(DemangleNodeType::DataMemberPrefix);
let ret = self.0.demangle(ctx, scope);
ctx.pop_demangle_node();
ret
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Substitution {
BackReference(usize),
WellKnown(WellKnownComponent),
}
impl Parse for Substitution {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Substitution, IndexStr<'b>)> {
try_begin_parse!("Substitution", ctx, input);
if let Ok((well_known, tail)) = WellKnownComponent::parse(ctx, subs, input) {
return Ok((Substitution::WellKnown(well_known), tail));
}
let tail = consume(b"S", input)?;
let (idx, tail) = if let Ok((idx, tail)) = SeqId::parse(ctx, subs, tail) {
(idx.0 + 1, tail)
} else {
(0, tail)
};
if !subs.contains(idx) {
return Err(error::Error::BadBackReference);
}
let tail = consume(b"_", tail)?;
log!("Found a reference to @ {}", idx);
Ok((Substitution::BackReference(idx), tail))
}
}
define_vocabulary! {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum WellKnownComponent {
Std (b"St", "std"),
StdAllocator (b"Sa", "std::allocator"),
StdString1 (b"Sb", "std::basic_string"),
StdString2 (b"Ss", "std::string"),
StdIstream (b"Si", "std::basic_istream<char, std::char_traits<char> >"),
StdOstream (b"So", "std::ostream"),
StdIostream (b"Sd", "std::basic_iostream<char, std::char_traits<char> >")
}
}
impl<'a> GetLeafName<'a> for WellKnownComponent {
fn get_leaf_name(&'a self, _: &'a SubstitutionTable) -> Option<LeafName<'a>> {
match *self {
WellKnownComponent::Std => None,
_ => Some(LeafName::WellKnownComponent(self)),
}
}
}
impl<'a> ArgScope<'a, 'a> for WellKnownComponent {
fn leaf_name(&'a self) -> Result<LeafName<'a>> {
Ok(LeafName::WellKnownComponent(self))
}
fn get_template_arg(&'a self, _: usize) -> Result<(&'a TemplateArg, &'a TemplateArgs)> {
Err(error::Error::BadTemplateArgReference)
}
fn get_function_arg(&'a self, _: usize) -> Result<&'a Type> {
Err(error::Error::BadFunctionArgReference)
}
}
impl<'subs, W> DemangleAsLeaf<'subs, W> for WellKnownComponent
where
W: 'subs + DemangleWrite,
{
fn demangle_as_leaf<'me, 'ctx>(
&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
) -> fmt::Result {
match *self {
WellKnownComponent::Std => {
panic!("should never treat `WellKnownComponent::Std` as a leaf name")
}
WellKnownComponent::StdAllocator => write!(ctx, "allocator"),
WellKnownComponent::StdString1 => write!(ctx, "basic_string"),
WellKnownComponent::StdString2 => write!(ctx, "string"),
WellKnownComponent::StdIstream => write!(ctx, "basic_istream"),
WellKnownComponent::StdOstream => write!(ctx, "ostream"),
WellKnownComponent::StdIostream => write!(ctx, "basic_iostream"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SpecialName {
VirtualTable(TypeHandle),
Vtt(TypeHandle),
Typeinfo(TypeHandle),
TypeinfoName(TypeHandle),
VirtualOverrideThunk(CallOffset, Box<Encoding>),
VirtualOverrideThunkCovariant(CallOffset, CallOffset, Box<Encoding>),
Guard(Name),
GuardTemporary(Name, usize),
ConstructionVtable(TypeHandle, usize, TypeHandle),
TypeinfoFunction(TypeHandle),
TlsInit(Name),
TlsWrapper(Name),
}
impl Parse for SpecialName {
fn parse<'a, 'b>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(SpecialName, IndexStr<'b>)> {
try_begin_parse!("SpecialName", ctx, input);
let (head, tail) = match input.try_split_at(2) {
None => return Err(error::Error::UnexpectedEnd),
Some((head, tail)) => (head, tail),
};
match head.as_ref() {
b"TV" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((SpecialName::VirtualTable(ty), tail))
}
b"TT" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((SpecialName::Vtt(ty), tail))
}
b"TI" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((SpecialName::Typeinfo(ty), tail))
}
b"TS" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((SpecialName::TypeinfoName(ty), tail))
}
b"Tc" => {
let (first, tail) = CallOffset::parse(ctx, subs, tail)?;
let (second, tail) = CallOffset::parse(ctx, subs, tail)?;
let (base, tail) = Encoding::parse(ctx, subs, tail)?;
Ok((
SpecialName::VirtualOverrideThunkCovariant(first, second, Box::new(base)),
tail,
))
}
b"Th" | b"Tv" => {
let tail = consume(b"T", input).unwrap();
let (offset, tail) = CallOffset::parse(ctx, subs, tail)?;
let (base, tail) = Encoding::parse(ctx, subs, tail)?;
Ok((
SpecialName::VirtualOverrideThunk(offset, Box::new(base)),
tail,
))
}
b"TC" => {
let (ty1, tail) = TypeHandle::parse(ctx, subs, tail)?;
let (n, tail) = parse_number(10, false, tail)?;
let tail = consume(b"_", tail)?;
let (ty2, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((
SpecialName::ConstructionVtable(ty1, n as usize, ty2),
tail,
))
}
b"TF" => {
let (ty, tail) = TypeHandle::parse(ctx, subs, tail)?;
Ok((SpecialName::TypeinfoFunction(ty), tail))
}
b"TH" => {
let (name, tail) = Name::parse(ctx, subs, tail)?;
Ok((SpecialName::TlsInit(name), tail))
}
b"TW" => {
let (name, tail) = Name::parse(ctx, subs, tail)?;
Ok((SpecialName::TlsWrapper(name), tail))
}
b"GV" => {
let (name, tail) = Name::parse(ctx, subs, tail)?;
Ok((SpecialName::Guard(name), tail))
}
b"GR" => {
let (name, tail) = Name::parse(ctx, subs, tail)?;
let (idx, tail) = if let Ok(tail) = consume(b"_", tail) {
(0, tail)
} else {
let (idx, tail) = SeqId::parse(ctx, subs, tail)?;
let tail = consume(b"_", tail)?;
(idx.0 + 1, tail)
};
Ok((SpecialName::GuardTemporary(name, idx), tail))
}
_ => Err(error::Error::UnexpectedText),
}
}
}
impl<'subs, W> Demangle<'subs, W> for SpecialName
where
W: 'subs + DemangleWrite,
{
fn demangle<'prev, 'ctx>(
&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
scope: Option<ArgScopeStack<'prev, 'subs>>,
) -> fmt::Result {
let ctx = try_begin_demangle!(self, ctx, scope);
match *self {
SpecialName::VirtualTable(ref ty) => {
write!(ctx, "{{vtable(")?;
ty.demangle(ctx, scope)?;
write!(ctx, ")}}")?;
Ok(())
}
SpecialName::Vtt(ref ty) => {
write!(ctx, "{{vtt(")?;
ty.demangle(ctx, scope)?;
write!(ctx, ")}}")?;
Ok(())
}
SpecialName::Typeinfo(ref ty) => {
write!(ctx, "typeinfo for ")?;
ty.demangle(ctx, scope)
}
SpecialName::TypeinfoName(ref ty) => {
write!(ctx, "typeinfo name for ")?;
ty.demangle(ctx, scope)
}
SpecialName::VirtualOverrideThunk(ref offset, ref encoding) => {
write!(ctx, "{{virtual override thunk(")?;
offset.demangle(ctx, scope)?;
write!(ctx, ", ")?;
encoding.demangle(ctx, scope)?;
write!(ctx, ")}}")?;
Ok(())
}
SpecialName::VirtualOverrideThunkCovariant(
ref this_offset,
ref result_offset,
ref encoding,
) => {
write!(ctx, "{{virtual override thunk(")?;
this_offset.demangle(ctx, scope)?;
write!(ctx, ", ")?;
result_offset.demangle(ctx, scope)?;
write!(ctx, ", ")?;
encoding.demangle(ctx, scope)?;
write!(ctx, ")}}")?;
Ok(())
}
SpecialName::Guard(ref name) => {
write!(ctx, "guard variable for ")?;
name.demangle(ctx, scope)
}
SpecialName::GuardTemporary(ref name, n) => {
write!(ctx, "reference temporary #{} for ", n)?;
name.demangle(ctx, scope)
}
SpecialName::ConstructionVtable(ref ty1, _, ref ty2) => {
write!(ctx, "construction vtable for ")?;
ty1.demangle(ctx, scope)?;
write!(ctx, "-in-")?;
ty2.demangle(ctx, scope)
}
SpecialName::TypeinfoFunction(ref ty) => {
write!(ctx, "typeinfo fn for ")?;
ty.demangle(ctx, scope)
}
SpecialName::TlsInit(ref name) => {
write!(ctx, "TLS init function for ")?;
name.demangle(ctx, scope)
}
SpecialName::TlsWrapper(ref name) => {
write!(ctx, "TLS wrapper function for ")?;
name.demangle(ctx, scope)
}
}
}
}
#[inline]
fn consume<'a>(expected: &[u8], input: IndexStr<'a>) -> Result<IndexStr<'a>> {
match input.try_split_at(expected.len()) {
Some((head, tail)) if head == expected => Ok(tail),
Some(_) => Err(error::Error::UnexpectedText),
None => Err(error::Error::UnexpectedEnd),
}
}
fn one_or_more<'a, 'b, P>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Vec<P>, IndexStr<'b>)>
where
P: Parse,
{
let (first, mut tail) = P::parse(ctx, subs, input)?;
let mut results = vec![first];
loop {
if let Ok((parsed, tail_tail)) = P::parse(ctx, subs, tail) {
results.push(parsed);
tail = tail_tail;
} else {
return Ok((results, tail));
}
}
}
fn zero_or_more<'a, 'b, P>(
ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>,
) -> Result<(Vec<P>, IndexStr<'b>)>
where
P: Parse,
{
let mut tail = input;
let mut results = vec![];
loop {
if let Ok((parsed, tail_tail)) = P::parse(ctx, subs, tail) {
results.push(parsed);
tail = tail_tail;
} else {
return Ok((results, tail));
}
}
}
#[allow(unsafe_code)]
fn parse_number(base: u32, allow_signed: bool, mut input: IndexStr) -> Result<(isize, IndexStr)> {
if input.is_empty() {
return Err(error::Error::UnexpectedEnd);
}
let num_is_negative = if allow_signed && input.as_ref()[0] == b'n' {
input = input.range_from(1..);
if input.is_empty() {
return Err(error::Error::UnexpectedEnd);
}
true
} else {
false
};
let num_numeric = input
.as_ref()
.iter()
.map(|&c| c as char)
.take_while(|c| c.is_digit(base) && (c.is_numeric() || c.is_uppercase()))
.count();
if num_numeric == 0 {
return Err(error::Error::UnexpectedText);
}
let (head, tail) = input.split_at(num_numeric);
let head = head.as_ref();
if num_numeric > 1 && head[0] == b'0' {
return Err(error::Error::UnexpectedText);
}
let head = unsafe {
::std::str::from_utf8_unchecked(head)
};
let mut number = isize::from_str_radix(head, base).map_err(|_| error::Error::Overflow)?;
if num_is_negative {
number = -number;
}
Ok((number, tail))
}
#[cfg(test)]
mod tests {
use super::{ArrayType, BareFunctionType, BaseUnresolvedName, BuiltinType, CallOffset,
ClassEnumType, ClosureTypeName, CtorDtorName, CvQualifiers, DataMemberPrefix,
Decltype, DestructorName, Discriminator, Encoding, ExprPrimary, Expression,
FunctionParam, FunctionType, GlobalCtorDtor, Identifier, Initializer, LambdaSig,
LocalName, MangledName, MemberName, Name, NestedName, NonSubstitution, Number,
NvOffset, OperatorName, Parse, ParseContext, PointerToMemberType, Prefix,
PrefixHandle, RefQualifier, SeqId, SimpleId, SimpleOperatorName, SourceName,
SpecialName, StandardBuiltinType, Substitution, TaggedName, TemplateArg,
TemplateArgs, TemplateParam, TemplateTemplateParam, TemplateTemplateParamHandle,
Type, TypeHandle, UnnamedTypeName, UnqualifiedName, UnresolvedName,
UnresolvedQualifierLevel, UnresolvedType, UnresolvedTypeHandle, UnscopedName,
UnscopedTemplateName, UnscopedTemplateNameHandle, VOffset, VectorType,
WellKnownComponent};
use string::String;
use boxed::Box;
use error::Error;
use index_str::IndexStr;
use std::fmt::Debug;
use std::iter::FromIterator;
use subs::{Substitutable, SubstitutionTable};
fn assert_parse_ok<P, S1, S2, I1, I2>(
production: &'static str,
subs: S1,
input: I1,
expected: P,
expected_tail: I2,
expected_new_subs: S2,
) where
P: Debug + Parse + PartialEq,
S1: AsRef<[Substitutable]>,
S2: AsRef<[Substitutable]>,
I1: AsRef<[u8]>,
I2: AsRef<[u8]>,
{
let ctx = ParseContext::default();
let input = input.as_ref();
let expected_tail = expected_tail.as_ref();
let expected_subs = SubstitutionTable::from_iter(
subs.as_ref()
.iter()
.cloned()
.chain(expected_new_subs.as_ref().iter().cloned()),
);
let mut subs = SubstitutionTable::from_iter(subs.as_ref().iter().cloned());
match P::parse(&ctx, &mut subs, IndexStr::from(input)) {
Err(error) => panic!(
"Parsing {:?} as {} failed: {}",
String::from_utf8_lossy(input),
production,
error
),
Ok((value, tail)) => {
if value != expected {
panic!(
"Parsing {:?} as {} produced\n\n{:#?}\n\nbut we expected\n\n{:#?}",
String::from_utf8_lossy(input),
production,
value,
expected
);
}
if tail != expected_tail {
panic!(
"Parsing {:?} as {} left a tail of {:?}, expected {:?}",
String::from_utf8_lossy(input),
production,
tail,
String::from_utf8_lossy(expected_tail)
);
}
if subs[..] != expected_subs[..] {
panic!(
"Parsing {:?} as {} produced a substitutions table of\n\n\
{:#?}\n\n\
but we expected\n\n\
{:#?}",
String::from_utf8_lossy(input),
production,
subs,
expected_subs
);
}
}
}
log!("=== assert_parse_ok PASSED ====================================");
}
fn simple_assert_parse_ok<P, I1, I2>(
production: &'static str,
input: I1,
expected: P,
expected_tail: I2,
) where
P: Debug + Parse + PartialEq,
I1: AsRef<[u8]>,
I2: AsRef<[u8]>,
{
assert_parse_ok::<P, _, _, _, _>(production, [], input, expected, expected_tail, []);
}
fn assert_parse_err<P, S, I>(production: &'static str, subs: S, input: I, expected_error: Error)
where
P: Debug + Parse + PartialEq,
S: AsRef<[Substitutable]>,
I: AsRef<[u8]>,
{
let input = input.as_ref();
let ctx = ParseContext::default();
let mut subs = SubstitutionTable::from_iter(subs.as_ref().iter().cloned());
match P::parse(&ctx, &mut subs, IndexStr::from(input)) {
Err(ref error) if *error == expected_error => {}
Err(ref error) => {
panic!(
"Parsing {:?} as {} produced an error of kind {:?}, but we expected kind {:?}",
String::from_utf8_lossy(input),
production,
error,
expected_error
);
}
Ok((value, tail)) => {
panic!(
"Parsing {:?} as {} produced value\
\n\n\
{:#?}\
\n\n\
and tail {:?}, but we expected error kind {:?}",
String::from_utf8_lossy(input),
production,
value,
tail,
expected_error
);
}
}
log!("=== assert_parse_err PASSED ===================================");
}
fn simple_assert_parse_err<P, I>(production: &'static str, input: I, expected_error: Error)
where
P: Debug + Parse + PartialEq,
I: AsRef<[u8]>,
{
assert_parse_err::<P, _, _>(production, [], input, expected_error);
}
#[test]
fn recursion_limit() {
let mut mangled = String::new();
for _ in 0..10_000 {
mangled.push('P');
}
mangled += "c";
simple_assert_parse_err::<TypeHandle, _>("TypeHandle", mangled, Error::TooMuchRecursion);
}
macro_rules! assert_parse {
( $production:ident {
$( with subs $subs:expr => {
Ok => {
$( $input:expr => {
$expected:expr ,
$expected_tail:expr ,
$expected_new_subs:expr
} )*
}
Err => {
$( $error_input:expr => $error:expr , )*
}
} )*
} ) => {
$( $(
assert_parse_ok::<$production, _, _, _, _>(stringify!($production),
$subs,
$input,
$expected,
$expected_tail,
$expected_new_subs);
)* )*
$( $(
assert_parse_err::<$production, _, _>(stringify!($production),
$subs,
$error_input,
$error);
)* )*
};
( $production:ident {
Ok => {
$( $input:expr => {
$expected:expr ,
$expected_tail:expr
} )*
}
Err => {
$( $error_input:expr => $error:expr , )*
}
} ) => {
$(
simple_assert_parse_ok::<$production, _, _>(stringify!($production),
$input,
$expected,
$expected_tail);
)*
$(
simple_assert_parse_err::<$production, _>(stringify!($production),
$error_input,
$error);
)*
};
}
#[test]
fn parse_mangled_name() {
assert_parse!(MangledName {
Ok => {
b"_Z3foo..." => {
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
}))))), vec![]),
b"..."
}
b"_GLOBAL__I__Z3foo..." => {
MangledName::GlobalCtorDtor(
GlobalCtorDtor::Ctor(
Box::new(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 14,
end: 17,
}))))), vec![])))),
b"..."
}
}
Err => {
b"_Y" => Error::UnexpectedText,
b"_Z" => Error::UnexpectedEnd,
b"_" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
b"_GLOBAL_" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_encoding() {
assert_parse!(Encoding {
with subs [] => {
Ok => {
b"3fooi..." => {
Encoding::Function(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
})))),
BareFunctionType(vec![
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int))
])),
b"...",
[]
}
b"3foo..." => {
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
}))))),
b"...",
[]
}
b"GV3abc..." => {
Encoding::Special(
SpecialName::Guard(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
})))))),
b"...",
[]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_global_ctor_dtor() {
assert_parse!(GlobalCtorDtor {
Ok => {
b"_I__Z3foo..." => {
GlobalCtorDtor::Ctor(
Box::new(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 6,
end: 9,
}))))), vec![]))),
b"..."
}
b".I__Z3foo..." => {
GlobalCtorDtor::Ctor(
Box::new(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 6,
end: 9,
}))))), vec![]))),
b"..."
}
b"$I__Z3foo..." => {
GlobalCtorDtor::Ctor(
Box::new(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 6,
end: 9,
}))))), vec![]))),
b"..."
}
b"_D__Z3foo..." => {
GlobalCtorDtor::Dtor(
Box::new(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 6,
end: 9,
}))))), vec![]))),
b"..."
}
b".D__Z3foo..." => {
GlobalCtorDtor::Dtor(
Box::new(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 6,
end: 9,
}))))), vec![]))),
b"..."
}
b"$D__Z3foo..." => {
GlobalCtorDtor::Dtor(
Box::new(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 6,
end: 9,
}))))), vec![]))),
b"..."
}
}
Err => {
b"_I" => Error::UnexpectedEnd,
b"_" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
b"blag" => Error::UnexpectedText,
b"_J" => Error::UnexpectedText,
b"_IJ" => Error::UnexpectedText,
}
});
}
#[test]
fn parse_name() {
assert_parse!(Name {
with subs [
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Operator(OperatorName::Simple(SimpleOperatorName::New)))),
Substitutable::Prefix(
Prefix::Nested(PrefixHandle::BackReference(0),
UnqualifiedName::Operator(OperatorName::Simple(SimpleOperatorName::New)))),
] => {
Ok => {
b"NS0_3abcE..." => {
Name::Nested(NestedName::Unqualified(CvQualifiers::default(),
None,
PrefixHandle::BackReference(1),
UnqualifiedName::Source(SourceName(Identifier {
start: 5,
end: 8,
})))),
b"...",
[]
}
b"3abc..." => {
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
})))),
b"...",
[]
}
b"dlIcE..." => {
Name::UnscopedTemplate(
UnscopedTemplateNameHandle::BackReference(2),
TemplateArgs(vec![
TemplateArg::Type(
TypeHandle::Builtin(
BuiltinType::Standard(StandardBuiltinType::Char)))
])),
b"...",
[
Substitutable::UnscopedTemplateName(
UnscopedTemplateName(
UnscopedName::Unqualified(
UnqualifiedName::Operator(
OperatorName::Simple(
SimpleOperatorName::Delete))))),
]
}
b"Z3abcEs..." => {
Name::Local(
LocalName::Relative(
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 2,
end: 5,
})))))),
None,
None)),
b"...",
[]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_unscoped_template_name_handle() {
assert_parse!(UnscopedTemplateNameHandle {
with subs [
Substitutable::UnscopedTemplateName(
UnscopedTemplateName(
UnscopedName::Unqualified(
UnqualifiedName::Operator(
OperatorName::Simple(
SimpleOperatorName::New))))),
] => {
Ok => {
b"S_..." => {
UnscopedTemplateNameHandle::BackReference(0),
b"...",
[]
}
b"dl..." => {
UnscopedTemplateNameHandle::BackReference(1),
b"...",
[
Substitutable::UnscopedTemplateName(
UnscopedTemplateName(
UnscopedName::Unqualified(
UnqualifiedName::Operator(
OperatorName::Simple(
SimpleOperatorName::Delete)))))
]
}
}
Err => {
b"zzzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_nested_name() {
assert_parse!(NestedName {
with subs [
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Operator(
OperatorName::Simple(
SimpleOperatorName::New)))),
] => {
Ok => {
b"NKOS_3abcE..." => {
NestedName::Unqualified(
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(RefQualifier::RValueRef),
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 6,
end: 9,
}))),
b"...",
[]
}
b"NOS_3abcE..." => {
NestedName::Unqualified(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
Some(RefQualifier::RValueRef),
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 5,
end: 8,
}))),
b"...",
[]
}
b"NS_3abcE..." => {
NestedName::Unqualified(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
None,
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 4,
end: 7,
}))),
b"...",
[]
}
b"NKOS_3abcIJEEE..." => {
NestedName::Template(
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(RefQualifier::RValueRef),
PrefixHandle::NonSubstitution(NonSubstitution(0))),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 6,
end: 9,
})))),
]
}
b"NOS_3abcIJEEE..." => {
NestedName::Template(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
Some(RefQualifier::RValueRef),
PrefixHandle::NonSubstitution(NonSubstitution(0))),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 5,
end: 8,
})))),
]
}
b"NS_3abcIJEEE..." => {
NestedName::Template(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
None,
PrefixHandle::NonSubstitution(NonSubstitution(0))),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 4,
end: 7,
})))),
]
}
}
Err => {
b"NS_E..." => Error::UnexpectedText,
b"NS_DttrEE..." => Error::UnexpectedText,
b"zzz" => Error::UnexpectedText,
b"Nzzz" => Error::UnexpectedText,
b"NKzzz" => Error::UnexpectedText,
b"NKOzzz" => Error::UnexpectedText,
b"NKO3abczzz" => Error::UnexpectedText,
b"NKO3abc3abczzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
b"N" => Error::UnexpectedEnd,
b"NK" => Error::UnexpectedEnd,
b"NKO" => Error::UnexpectedEnd,
b"NKO3abc" => Error::UnexpectedEnd,
b"NKO3abc3abc" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_prefix_handle() {
assert_parse!(PrefixHandle {
with subs [
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Operator(
OperatorName::Simple(
SimpleOperatorName::New)))),
] => {
Ok => {
b"3foo..." => {
PrefixHandle::BackReference(1),
b"...",
[
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
}))))
]
}
b"3abc3def..." => {
PrefixHandle::BackReference(2),
b"...",
[
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
})))),
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(1),
UnqualifiedName::Source(
SourceName(Identifier {
start: 5,
end: 8,
})))),
]
}
b"3fooIJEE..." => {
PrefixHandle::BackReference(2),
b"...",
[
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
})))),
Substitutable::Prefix(
Prefix::Template(PrefixHandle::BackReference(1),
TemplateArgs(vec![
TemplateArg::ArgPack(vec![]),
])))
]
}
b"T_..." => {
PrefixHandle::BackReference(1),
b"...",
[
Substitutable::Prefix(Prefix::TemplateParam(TemplateParam(0))),
]
}
b"DTtrE..." => {
PrefixHandle::BackReference(1),
b"...",
[
Substitutable::Prefix(
Prefix::Decltype(
Decltype::Expression(Expression::Rethrow))),
]
}
b"3abc3defM..." => {
PrefixHandle::BackReference(2),
b"...",
[
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
})))),
Substitutable::Prefix(
Prefix::DataMember(
PrefixHandle::BackReference(1),
DataMemberPrefix(
SourceName(Identifier {
start: 5,
end: 8,
})))),
]
}
b"S_..." => {
PrefixHandle::BackReference(0),
b"...",
[]
}
b"3abc3defE..." => {
PrefixHandle::NonSubstitution(NonSubstitution(0)),
b"E...",
[
Substitutable::Prefix(
Prefix::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
})))),
]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_type_handle() {
assert_parse!(TypeHandle {
with subs [
Substitutable::Type(
Type::PointerTo(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Char)))),
] => {
Ok => {
b"S_..." => {
TypeHandle::BackReference(0),
b"...",
[]
}
b"c..." => {
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Char)),
b"...",
[]
}
b"FS_E..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::Function(FunctionType {
cv_qualifiers: CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
transaction_safe: false,
extern_c: false,
bare: BareFunctionType(vec![TypeHandle::BackReference(0)]),
ref_qualifier: None,
})),
]
}
b"A_S_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::Array(ArrayType::NoDimension(TypeHandle::BackReference(0)))),
]
}
b"MS_S_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::PointerToMember(
PointerToMemberType(TypeHandle::BackReference(0),
TypeHandle::BackReference(0)))),
]
}
b"T_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(Type::TemplateParam(TemplateParam(0))),
]
}
b"T_IS_E..." => {
TypeHandle::BackReference(2),
b"...",
[
Substitutable::TemplateTemplateParam(
TemplateTemplateParam(TemplateParam(0))),
Substitutable::Type(
Type::TemplateTemplate(
TemplateTemplateParamHandle::BackReference(1),
TemplateArgs(vec![
TemplateArg::Type(TypeHandle::BackReference(0))
]))),
]
}
b"DTtrE..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::Decltype(Decltype::Expression(Expression::Rethrow))),
]
}
b"KS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(Type::Qualified(CvQualifiers {
restrict: false,
volatile: false,
const_: true,
}, TypeHandle::BackReference(0)))
]
}
b"PS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(Type::PointerTo(TypeHandle::BackReference(0)))
]
}
b"RS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(Type::LvalueRef(TypeHandle::BackReference(0)))
]
}
b"OS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(Type::RvalueRef(TypeHandle::BackReference(0)))
]
}
b"CS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(Type::Complex(TypeHandle::BackReference(0)))
]
}
b"GS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(Type::Imaginary(TypeHandle::BackReference(0)))
]
}
b"U3abcS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::VendorExtension(
SourceName(Identifier {
start: 2,
end: 5,
}),
None,
TypeHandle::BackReference(0)))
]
}
b"U3abcIS_ES_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::VendorExtension(
SourceName(Identifier {
start: 2,
end: 5,
}),
Some(TemplateArgs(vec![
TemplateArg::Type(TypeHandle::BackReference(0))
])),
TypeHandle::BackReference(0)))
]
}
b"DpS_..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::PackExpansion(TypeHandle::BackReference(0))),
]
}
b"3abc..." => {
TypeHandle::BackReference(1),
b"...",
[
Substitutable::Type(
Type::ClassEnum(
ClassEnumType::Named(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
})))))))
]
}
}
Err => {
b"P" => Error::UnexpectedEnd,
b"R" => Error::UnexpectedEnd,
b"O" => Error::UnexpectedEnd,
b"C" => Error::UnexpectedEnd,
b"G" => Error::UnexpectedEnd,
b"Dp" => Error::UnexpectedEnd,
b"D" => Error::UnexpectedEnd,
b"P" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_function_type() {
assert_parse!(FunctionType {
with subs [
Substitutable::Type(
Type::PointerTo(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Char)))),
] => {
Ok => {
b"KDxFYS_RE..." => {
FunctionType {
cv_qualifiers: CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
transaction_safe: true,
extern_c: true,
bare: BareFunctionType(vec![TypeHandle::BackReference(0)]),
ref_qualifier: Some(RefQualifier::LValueRef),
},
b"...",
[]
}
b"DxFYS_RE..." => {
FunctionType {
cv_qualifiers: CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
transaction_safe: true,
extern_c: true,
bare: BareFunctionType(vec![TypeHandle::BackReference(0)]),
ref_qualifier: Some(RefQualifier::LValueRef),
},
b"...",
[]
}
b"FYS_RE..." => {
FunctionType {
cv_qualifiers: CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
transaction_safe: false,
extern_c: true,
bare: BareFunctionType(vec![TypeHandle::BackReference(0)]),
ref_qualifier: Some(RefQualifier::LValueRef),
},
b"...",
[]
}
b"FS_RE..." => {
FunctionType {
cv_qualifiers: CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
transaction_safe: false,
extern_c: false,
bare: BareFunctionType(vec![TypeHandle::BackReference(0)]),
ref_qualifier: Some(RefQualifier::LValueRef),
},
b"...",
[]
}
b"FS_E..." => {
FunctionType {
cv_qualifiers: CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
transaction_safe: false,
extern_c: false,
bare: BareFunctionType(vec![TypeHandle::BackReference(0)]),
ref_qualifier: None,
},
b"...",
[]
}
}
Err => {
b"DFYS_E" => Error::UnexpectedText,
b"KKFS_E" => Error::UnexpectedText,
b"FYS_..." => Error::UnexpectedText,
b"FYS_" => Error::UnexpectedEnd,
b"F" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_bare_function_type() {
assert_parse!(BareFunctionType {
with subs [
Substitutable::Type(
Type::PointerTo(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Char)))),
] => {
Ok => {
b"S_S_..." => {
BareFunctionType(vec![
TypeHandle::BackReference(0),
TypeHandle::BackReference(0),
]),
b"...",
[]
}
}
Err => {
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_decltype() {
assert_parse!(Decltype {
Ok => {
b"DTtrE..." => {
Decltype::Expression(Expression::Rethrow),
b"..."
}
b"DttrE..." => {
Decltype::IdExpression(Expression::Rethrow),
b"..."
}
}
Err => {
b"Dtrtz" => Error::UnexpectedText,
b"DTrtz" => Error::UnexpectedText,
b"Dz" => Error::UnexpectedText,
b"Dtrt" => Error::UnexpectedText,
b"DTrt" => Error::UnexpectedText,
b"Dt" => Error::UnexpectedEnd,
b"DT" => Error::UnexpectedEnd,
b"D" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_class_enum_type() {
assert_parse!(ClassEnumType {
Ok => {
b"3abc..." => {
ClassEnumType::Named(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 1,
end: 4,
}))))),
b"..."
}
b"Ts3abc..." => {
ClassEnumType::ElaboratedStruct(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
}))))),
b"..."
}
b"Tu3abc..." => {
ClassEnumType::ElaboratedUnion(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
}))))),
b"..."
}
b"Te3abc..." => {
ClassEnumType::ElaboratedEnum(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
}))))),
b"..."
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"Tzzz" => Error::UnexpectedText,
b"T" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_array_type() {
assert_parse!(ArrayType {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"A10_S_..." => {
ArrayType::DimensionNumber(10, TypeHandle::BackReference(0)),
b"...",
[]
}
b"A10_Sb..." => {
ArrayType::DimensionNumber(10,
TypeHandle::WellKnown(
WellKnownComponent::StdString1)),
b"...",
[]
}
b"Atr_S_..." => {
ArrayType::DimensionExpression(Expression::Rethrow,
TypeHandle::BackReference(0)),
b"...",
[]
}
b"A_S_..." => {
ArrayType::NoDimension(TypeHandle::BackReference(0)),
b"...",
[]
}
}
Err => {
b"A10_" => Error::UnexpectedEnd,
b"A10" => Error::UnexpectedEnd,
b"A" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
b"A10_..." => Error::UnexpectedText,
b"A10..." => Error::UnexpectedText,
b"A..." => Error::UnexpectedText,
b"..." => Error::UnexpectedText,
}
}
});
}
#[test]
fn parse_vector_type() {
assert_parse!(VectorType {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"Dv10_S_..." => {
VectorType::DimensionNumber(10, TypeHandle::BackReference(0)),
b"...",
[]
}
b"Dv10_Sb..." => {
VectorType::DimensionNumber(10,
TypeHandle::WellKnown(
WellKnownComponent::StdString1)),
b"...",
[]
}
b"Dv_tr_S_..." => {
VectorType::DimensionExpression(Expression::Rethrow,
TypeHandle::BackReference(0)),
b"...",
[]
}
}
Err => {
b"Dq" => Error::UnexpectedText,
b"Dv" => Error::UnexpectedEnd,
b"Dv42_" => Error::UnexpectedEnd,
b"Dv42_..." => Error::UnexpectedText,
b"Dvtr_" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
b"..." => Error::UnexpectedText,
}
}
});
}
#[test]
fn parse_pointer_to_member_type() {
assert_parse!(PointerToMemberType {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"MS_S_..." => {
PointerToMemberType(TypeHandle::BackReference(0),
TypeHandle::BackReference(0)),
b"...",
[]
}
}
Err => {
b"MS_S" => Error::UnexpectedEnd,
b"MS_" => Error::UnexpectedEnd,
b"MS" => Error::UnexpectedEnd,
b"M" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
b"MS_..." => Error::UnexpectedText,
b"M..." => Error::UnexpectedText,
b"..." => Error::UnexpectedText,
}
}
});
}
#[test]
fn parse_template_template_param_handle() {
assert_parse!(TemplateTemplateParamHandle {
with subs [
Substitutable::TemplateTemplateParam(TemplateTemplateParam(TemplateParam(0)))
] => {
Ok => {
b"S_..." => {
TemplateTemplateParamHandle::BackReference(0),
b"...",
[]
}
b"T1_..." => {
TemplateTemplateParamHandle::BackReference(1),
b"...",
[
Substitutable::TemplateTemplateParam(TemplateTemplateParam(TemplateParam(2)))
]
}
}
Err => {
b"S" => Error::UnexpectedText,
b"T" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
b"S..." => Error::UnexpectedText,
b"T..." => Error::UnexpectedText,
b"..." => Error::UnexpectedText,
}
}
});
}
#[test]
fn parse_template_args() {
assert_parse!(TemplateArgs {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"IS_E..." => {
TemplateArgs(vec![TemplateArg::Type(TypeHandle::BackReference(0))]),
b"...",
[]
}
b"IS_S_S_S_E..." => {
TemplateArgs(vec![
TemplateArg::Type(TypeHandle::BackReference(0)),
TemplateArg::Type(TypeHandle::BackReference(0)),
TemplateArg::Type(TypeHandle::BackReference(0)),
TemplateArg::Type(TypeHandle::BackReference(0)),
]),
b"...",
[]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"IE" => Error::UnexpectedText,
b"IS_" => Error::UnexpectedEnd,
b"I" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_template_arg() {
assert_parse!(TemplateArg {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"S_..." => {
TemplateArg::Type(TypeHandle::BackReference(0)),
b"...",
[]
}
b"XtrE..." => {
TemplateArg::Expression(Expression::Rethrow),
b"...",
[]
}
b"XsrS_1QE..." => {
TemplateArg::Expression(
Expression::UnresolvedName(
UnresolvedName::Nested1(
UnresolvedTypeHandle::BackReference(0),
vec![],
BaseUnresolvedName::Name(
SimpleId(
SourceName(Identifier {
start: 6,
end: 7
}),
None
)
)
)
)
),
b"...",
[]
}
b"XsrS_1QIlEE..." => {
TemplateArg::Expression(
Expression::UnresolvedName(
UnresolvedName::Nested1(
UnresolvedTypeHandle::BackReference(0),
vec![],
BaseUnresolvedName::Name(
SimpleId(
SourceName(Identifier {
start: 6,
end: 7
}),
Some(
TemplateArgs(
vec![
TemplateArg::Type(
TypeHandle::Builtin(
BuiltinType::Standard(
StandardBuiltinType::Long
)
)
)
]
)
)
)
)
)
)
),
b"...",
[]
}
b"LS_E..." => {
TemplateArg::SimpleExpression(
ExprPrimary::Literal(TypeHandle::BackReference(0), 3, 3)),
b"...",
[]
}
b"JE..." => {
TemplateArg::ArgPack(vec![]),
b"...",
[]
}
b"JS_XtrELS_EJEE..." => {
TemplateArg::ArgPack(vec![
TemplateArg::Type(TypeHandle::BackReference(0)),
TemplateArg::Expression(Expression::Rethrow),
TemplateArg::SimpleExpression(
ExprPrimary::Literal(TypeHandle::BackReference(0), 10, 10)),
TemplateArg::ArgPack(vec![]),
]),
b"...",
[]
}
}
Err => {
b"..." => Error::UnexpectedText,
b"X..." => Error::UnexpectedText,
b"J..." => Error::UnexpectedText,
b"JS_..." => Error::UnexpectedText,
b"JS_" => Error::UnexpectedEnd,
b"X" => Error::UnexpectedEnd,
b"J" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_expression() {
assert_parse!(Expression {
with subs [
Substitutable::Type(
Type::PointerTo(TypeHandle::Builtin(
BuiltinType::Standard(StandardBuiltinType::Int)))),
] => {
Ok => {
b"psLS_1E..." => {
Expression::Unary(OperatorName::Simple(SimpleOperatorName::UnaryPlus),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"rsLS_1ELS_1E..." => {
Expression::Binary(OperatorName::Simple(SimpleOperatorName::Shr),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6))),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
10,
11)))),
b"...",
[]
}
b"quLS_1ELS_2ELS_3E..." => {
Expression::Ternary(OperatorName::Simple(SimpleOperatorName::Question),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6))),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
10,
11))),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
15,
16)))),
b"...",
[]
}
b"pp_LS_1E..." => {
Expression::PrefixInc(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
6,
7)))),
b"...",
[]
}
b"mm_LS_1E..." => {
Expression::PrefixDec(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
6,
7)))),
b"...",
[]
}
b"clLS_1EE..." => {
Expression::Call(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6))),
vec![]),
b"...",
[]
}
b"cvS_LS_1E..." => {
Expression::ConversionOne(
TypeHandle::BackReference(0),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)))),
b"...",
[]
}
b"cvS__LS_1ELS_1EE..." => {
Expression::ConversionMany(
TypeHandle::BackReference(0),
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
8,
9)),
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
13,
14)),
]),
b"...",
[]
}
b"tlS_LS_1ELS_1EE..." => {
Expression::ConversionBraced(
TypeHandle::BackReference(0),
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)),
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
12,
13)),
]),
b"...",
[]
}
b"ilLS_1EE..." => {
Expression::BracedInitList(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"gsnwLS_1E_S_E..." => {
Expression::GlobalNew(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8))
],
TypeHandle::BackReference(0),
None),
b"...",
[]
}
b"nwLS_1E_S_E..." => {
Expression::New(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6))
],
TypeHandle::BackReference(0),
None),
b"...",
[]
}
b"gsnwLS_1E_S_piE..." => {
Expression::GlobalNew(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8))
],
TypeHandle::BackReference(0),
Some(Initializer(vec![]))),
b"...",
[]
}
b"nwLS_1E_S_piE..." => {
Expression::New(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6))
],
TypeHandle::BackReference(0),
Some(Initializer(vec![]))),
b"...",
[]
}
b"gsnaLS_1E_S_E..." => {
Expression::GlobalNewArray(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8))
],
TypeHandle::BackReference(0),
None),
b"...",
[]
}
b"naLS_1E_S_E..." => {
Expression::NewArray(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6))
],
TypeHandle::BackReference(0),
None),
b"...",
[]
}
b"gsnaLS_1E_S_piE..." => {
Expression::GlobalNewArray(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8))
],
TypeHandle::BackReference(0),
Some(Initializer(vec![]))),
b"...",
[]
}
b"naLS_1E_S_piE..." => {
Expression::NewArray(
vec![
Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6))
],
TypeHandle::BackReference(0),
Some(Initializer(vec![]))),
b"...",
[]
}
b"gsdlLS_1E..." => {
Expression::GlobalDelete(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)))),
b"...",
[]
}
b"dlLS_1E..." => {
Expression::Delete(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"gsdaLS_1E..." => {
Expression::GlobalDeleteArray(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)))),
b"...",
[]
}
b"daLS_1E..." => {
Expression::DeleteArray(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"dcS_LS_1E..." => {
Expression::DynamicCast(
TypeHandle::BackReference(0),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)))),
b"...",
[]
}
b"scS_LS_1E..." => {
Expression::StaticCast(
TypeHandle::BackReference(0),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)))),
b"...",
[]
}
b"ccS_LS_1E..." => {
Expression::ConstCast(
TypeHandle::BackReference(0),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)))),
b"...",
[]
}
b"rcS_LS_1E..." => {
Expression::ReinterpretCast(
TypeHandle::BackReference(0),
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
7,
8)))),
b"...",
[]
}
b"tiS_..." => {
Expression::TypeidType(TypeHandle::BackReference(0)),
b"...",
[]
}
b"teLS_1E..." => {
Expression::TypeidExpr(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"stS_..." => {
Expression::SizeofType(TypeHandle::BackReference(0)),
b"...",
[]
}
b"szLS_1E..." => {
Expression::SizeofExpr(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"atS_..." => {
Expression::AlignofType(TypeHandle::BackReference(0)),
b"...",
[]
}
b"azLS_1E..." => {
Expression::AlignofExpr(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"nxLS_1E..." => {
Expression::Noexcept(
Box::new(Expression::Primary(
ExprPrimary::Literal(
TypeHandle::BackReference(0),
5,
6)))),
b"...",
[]
}
b"T_..." => {
Expression::TemplateParam(TemplateParam(0)),
b"...",
[]
}
b"fp_..." => {
Expression::FunctionParam(FunctionParam(0, CvQualifiers::default(), Some(0))),
b"...",
[]
}
b"dtT_3abc..." => {
Expression::Member(
Box::new(Expression::TemplateParam(TemplateParam(0))),
MemberName(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 5,
end: 8,
})))))),
b"...",
[]
}
b"ptT_3abc..." => {
Expression::DerefMember(
Box::new(Expression::TemplateParam(TemplateParam(0))),
MemberName(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 5,
end: 8,
})))))),
b"...",
[]
}
b"dtfp_clI3abcE..." => {
Expression::Member(
Box::new(Expression::FunctionParam(FunctionParam(0, CvQualifiers::default(), Some(0)))),
MemberName(
Name::UnscopedTemplate(
UnscopedTemplateNameHandle::NonSubstitution(NonSubstitution(0)),
TemplateArgs(vec![
TemplateArg::Type(
TypeHandle::BackReference(1))])))),
b"...",
[
Substitutable::Type(
Type::ClassEnum(
ClassEnumType::Named(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(
Identifier {
start: 9,
end: 12
})))))))
]
}
b"dsT_T_..." => {
Expression::PointerToMember(
Box::new(Expression::TemplateParam(TemplateParam(0))),
Box::new(Expression::TemplateParam(TemplateParam(0)))),
b"...",
[]
}
b"sZT_..." => {
Expression::SizeofTemplatePack(TemplateParam(0)),
b"...",
[]
}
b"sZfp_..." => {
Expression::SizeofFunctionPack(
FunctionParam(0, CvQualifiers::default(), Some(0))),
b"...",
[]
}
b"sPE..." => {
Expression::SizeofCapturedTemplatePack(vec![]),
b"...",
[]
}
b"spT_..." => {
Expression::PackExpansion(
Box::new(Expression::TemplateParam(TemplateParam(0)))),
b"...",
[]
}
b"twT_..." => {
Expression::Throw(Box::new(Expression::TemplateParam(TemplateParam(0)))),
b"...",
[]
}
b"tr..." => {
Expression::Rethrow,
b"...",
[]
}
b"3abc..." => {
Expression::UnresolvedName(
UnresolvedName::Name(
BaseUnresolvedName::Name(
SimpleId(
SourceName(Identifier {
start: 1,
end: 4,
}),
None)))),
b"...",
[]
}
b"L_Z3abcE..." => {
Expression::Primary(
ExprPrimary::External(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 4,
end: 7,
}))))), vec![]))),
b"...",
[]
}
b"cldtdefpT4TypeadsrT_5EnterE..." => {
Expression::Call(
Box::new(Expression::Member(
Box::new(Expression::Unary(OperatorName::Simple(SimpleOperatorName::Deref),
Box::new(Expression::FunctionParam(
FunctionParam(0,
CvQualifiers::default(),
None)
))
)),
MemberName(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 10,
end: 14,
})))
)
)
)),
vec![Expression::Unary(OperatorName::Simple(SimpleOperatorName::AddressOf),
Box::new(Expression::UnresolvedName(
UnresolvedName::Nested1(
UnresolvedTypeHandle::BackReference(1),
vec![],
BaseUnresolvedName::Name(
SimpleId(
SourceName(Identifier {
start: 21,
end: 26
}
),
None
)
)
))))]
),
b"...",
[
Substitutable::UnresolvedType(UnresolvedType::Template(TemplateParam(0), None))
]
}
}
Err => {
b"dtStfp_clI3abcE..." => Error::UnexpectedText,
}
}
});
}
#[test]
fn parse_unresolved_name() {
assert_parse!(UnresolvedName {
with subs [
Substitutable::UnresolvedType(
UnresolvedType::Decltype(Decltype::Expression(Expression::Rethrow))),
] => {
Ok => {
b"gs3abc..." => {
UnresolvedName::Global(BaseUnresolvedName::Name(SimpleId(SourceName(Identifier {
start: 3,
end: 6,
}), None))),
b"...",
[]
}
b"3abc..." => {
UnresolvedName::Name(BaseUnresolvedName::Name(SimpleId(SourceName(Identifier {
start: 1,
end: 4,
}), None))),
b"...",
[]
}
b"srS_3abc..." => {
UnresolvedName::Nested1(UnresolvedTypeHandle::BackReference(0),
vec![],
BaseUnresolvedName::Name(SimpleId(SourceName(Identifier {
start: 5,
end: 8,
}), None))),
b"...",
[]
}
b"srNS_3abc3abcE3abc..." => {
UnresolvedName::Nested1(
UnresolvedTypeHandle::BackReference(0),
vec![
UnresolvedQualifierLevel(SimpleId(SourceName(Identifier {
start: 6,
end: 9,
}), None)),
UnresolvedQualifierLevel(SimpleId(SourceName(Identifier {
start: 10,
end: 13,
}), None)),
],
BaseUnresolvedName::Name(SimpleId(SourceName(Identifier {
start: 15,
end: 18,
}), None))),
b"...",
[]
}
b"gssr3abcE3abc..." => {
UnresolvedName::GlobalNested2(
vec![
UnresolvedQualifierLevel(SimpleId(SourceName(Identifier {
start: 5,
end: 8,
}), None)),
],
BaseUnresolvedName::Name(SimpleId(SourceName(Identifier {
start: 10,
end: 13,
}), None))),
b"...",
[]
}
b"sr3abcE3abc..." => {
UnresolvedName::Nested2(
vec![
UnresolvedQualifierLevel(SimpleId(SourceName(Identifier {
start: 3,
end: 6,
}), None)),
],
BaseUnresolvedName::Name(SimpleId(SourceName(Identifier {
start: 8,
end: 11,
}), None))),
b"...",
[]
}
}
Err => {
b"zzzzzz" => Error::UnexpectedText,
b"gszzz" => Error::UnexpectedText,
b"gssrzzz" => Error::UnexpectedText,
b"srNzzz" => Error::UnexpectedText,
b"srzzz" => Error::UnexpectedText,
b"srN3abczzzz" => Error::UnexpectedText,
b"srN3abcE" => Error::UnexpectedText,
b"srN3abc" => Error::UnexpectedText,
b"srN" => Error::UnexpectedEnd,
b"sr" => Error::UnexpectedEnd,
b"gssr" => Error::UnexpectedEnd,
b"gs" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_unresolved_type_handle() {
assert_parse!(UnresolvedTypeHandle {
with subs [
Substitutable::UnresolvedType(
UnresolvedType::Decltype(Decltype::Expression(Expression::Rethrow))),
] => {
Ok => {
b"S_..." => {
UnresolvedTypeHandle::BackReference(0),
b"...",
[]
}
b"T_..." => {
UnresolvedTypeHandle::BackReference(1),
b"...",
[
Substitutable::UnresolvedType(
UnresolvedType::Template(TemplateParam(0), None)),
]
}
b"T_IS_E..." => {
UnresolvedTypeHandle::BackReference(1),
b"...",
[
Substitutable::UnresolvedType(
UnresolvedType::Template(TemplateParam(0), Some(TemplateArgs(vec![
TemplateArg::Type(TypeHandle::BackReference(0))
])))),
]
}
b"DTtrE..." => {
UnresolvedTypeHandle::BackReference(1),
b"...",
[
Substitutable::UnresolvedType(
UnresolvedType::Decltype(Decltype::Expression(Expression::Rethrow)))
]
}
}
Err => {
b"zzzzzzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_unresolved_qualifier_level() {
assert_parse!(UnresolvedQualifierLevel {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"3abc..." => {
UnresolvedQualifierLevel(SimpleId(SourceName(Identifier {
start: 1,
end: 4,
}), None)),
b"...",
[]
}
b"3abcIS_E..." => {
UnresolvedQualifierLevel(SimpleId(SourceName(Identifier {
start: 1,
end: 4,
}), Some(TemplateArgs(vec![
TemplateArg::Type(TypeHandle::BackReference(0))
])))),
b"...",
[]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_simple_id() {
assert_parse!(SimpleId {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"3abc..." => {
SimpleId(SourceName(Identifier {
start: 1,
end: 4,
}), None),
b"...",
[]
}
b"3abcIS_E..." => {
SimpleId(SourceName(Identifier {
start: 1,
end: 4,
}), Some(TemplateArgs(vec![
TemplateArg::Type(TypeHandle::BackReference(0))
]))),
b"...",
[]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_base_unresolved_name() {
assert_parse!(BaseUnresolvedName {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"3abc..." => {
BaseUnresolvedName::Name(SimpleId(SourceName(Identifier {
start: 1,
end: 4,
}), None)),
b"...",
[]
}
b"onnw..." => {
BaseUnresolvedName::Operator(OperatorName::Simple(SimpleOperatorName::New), None),
b"...",
[]
}
b"onnwIS_E..." => {
BaseUnresolvedName::Operator(OperatorName::Simple(SimpleOperatorName::New),
Some(TemplateArgs(vec![
TemplateArg::Type(TypeHandle::BackReference(0))
]))),
b"...",
[]
}
b"dn3abc..." => {
BaseUnresolvedName::Destructor(DestructorName::Name(SimpleId(SourceName(Identifier {
start: 3,
end: 6,
}), None))),
b"...",
[]
}
}
Err => {
b"ozzz" => Error::UnexpectedText,
b"dzzz" => Error::UnexpectedText,
b"dn" => Error::UnexpectedEnd,
b"on" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_destructor_name() {
assert_parse!(DestructorName {
with subs [
Substitutable::UnresolvedType(
UnresolvedType::Decltype(Decltype::Expression(Expression::Rethrow))),
] => {
Ok => {
b"S_..." => {
DestructorName::Unresolved(UnresolvedTypeHandle::BackReference(0)),
b"...",
[]
}
b"3abc..." => {
DestructorName::Name(SimpleId(SourceName(Identifier {
start: 1,
end: 4,
}), None)),
b"...",
[]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_expr_primary() {
assert_parse!(ExprPrimary {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"LS_12345E..." => {
ExprPrimary::Literal(TypeHandle::BackReference(0), 3, 8),
b"...",
[]
}
b"LS_E..." => {
ExprPrimary::Literal(TypeHandle::BackReference(0), 3, 3),
b"...",
[]
}
b"L_Z3abcE..." => {
ExprPrimary::External(
MangledName::Encoding(
Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 4,
end: 7,
}))))), vec![])),
b"...",
[]
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"LS_zzz" => Error::UnexpectedEnd,
b"LS_12345" => Error::UnexpectedEnd,
b"LS_" => Error::UnexpectedEnd,
b"L" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_initializer() {
assert_parse!(Initializer {
Ok => {
b"piE..." => {
Initializer(vec![]),
b"..."
}
b"pitrtrtrE..." => {
Initializer(vec![
Expression::Rethrow,
Expression::Rethrow,
Expression::Rethrow,
]),
b"..."
}
}
Err => {
b"pirtrtrt..." => Error::UnexpectedText,
b"pi..." => Error::UnexpectedText,
b"..." => Error::UnexpectedText,
b"pirt" => Error::UnexpectedText,
b"pi" => Error::UnexpectedEnd,
b"p" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_local_name() {
assert_parse!(LocalName {
Ok => {
b"Z3abcE3def_0..." => {
LocalName::Relative(
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 2,
end: 5,
})))))),
Some(Box::new(Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 7,
end: 10,
})))))),
Some(Discriminator(0))),
b"..."
}
b"Z3abcE3def..." => {
LocalName::Relative(
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 2,
end: 5,
})))))),
Some(Box::new(Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 7,
end: 10,
})))))),
None),
b"..."
}
b"Z3abcEs_0..." => {
LocalName::Relative(
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 2,
end: 5,
})))))),
None,
Some(Discriminator(0))),
b"..."
}
b"Z3abcEs..." => {
LocalName::Relative(
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 2,
end: 5,
})))))),
None,
None),
b"..."
}
b"Z3abcEd1_3abc..." => {
LocalName::Default(
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 2,
end: 5,
})))))),
Some(1),
Box::new(Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 10,
end: 13,
})))))),
b"..."
}
b"Z3abcEd_3abc..." => {
LocalName::Default(
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 2,
end: 5,
})))))),
None,
Box::new(Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 9,
end: 12,
})))))),
b"..."
}
}
Err => {
b"A" => Error::UnexpectedText,
b"Z1a" => Error::UnexpectedEnd,
b"Z1aE" => Error::UnexpectedEnd,
b"Z" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_closure_type_name() {
assert_parse!(ClosureTypeName {
Ok => {
b"UlvE_..." => {
ClosureTypeName(LambdaSig(vec![]), None),
b"..."
}
b"UlvE36_..." => {
ClosureTypeName(LambdaSig(vec![]), Some(36)),
b"..."
}
}
Err => {
b"UlvE36zzz" => Error::UnexpectedText,
b"UlvEzzz" => Error::UnexpectedText,
b"Ulvzzz" => Error::UnexpectedText,
b"zzz" => Error::UnexpectedText,
b"UlvE10" => Error::UnexpectedEnd,
b"UlvE" => Error::UnexpectedEnd,
b"Ulv" => Error::UnexpectedEnd,
b"Ul" => Error::UnexpectedEnd,
b"U" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_lambda_sig() {
assert_parse!(LambdaSig {
with subs [
Substitutable::Type(
Type::PointerTo(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Bool))))
] => {
Ok => {
b"v..." => {
LambdaSig(vec![]),
b"...",
[]
}
b"S_S_S_..." => {
LambdaSig(vec![
TypeHandle::BackReference(0),
TypeHandle::BackReference(0),
TypeHandle::BackReference(0),
]),
b"...",
[]
}
}
Err => {
b"..." => Error::UnexpectedText,
b"S" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_substitution() {
assert_parse!(Substitution {
with subs [
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow))),
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow))),
Substitutable::Type(Type::Decltype(Decltype::Expression(Expression::Rethrow)))
] => {
Ok => {
b"S_..." => {
Substitution::BackReference(0),
b"...",
[]
}
b"S1_..." => {
Substitution::BackReference(2),
b"...",
[]
}
b"St..." => {
Substitution::WellKnown(WellKnownComponent::Std),
b"...",
[]
}
b"Sa..." => {
Substitution::WellKnown(WellKnownComponent::StdAllocator),
b"...",
[]
}
b"Sb..." => {
Substitution::WellKnown(WellKnownComponent::StdString1),
b"...",
[]
}
b"Ss..." => {
Substitution::WellKnown(WellKnownComponent::StdString2),
b"...",
[]
}
b"Si..." => {
Substitution::WellKnown(WellKnownComponent::StdIstream),
b"...",
[]
}
b"So..." => {
Substitution::WellKnown(WellKnownComponent::StdOstream),
b"...",
[]
}
b"Sd..." => {
Substitution::WellKnown(WellKnownComponent::StdIostream),
b"...",
[]
}
}
Err => {
b"S999_" => Error::BadBackReference,
b"Sz" => Error::UnexpectedText,
b"zzz" => Error::UnexpectedText,
b"S1" => Error::UnexpectedEnd,
b"S" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
}
});
}
#[test]
fn parse_special_name() {
assert_parse!(SpecialName {
Ok => {
b"TVi..." => {
SpecialName::VirtualTable(TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int))),
b"..."
}
b"TTi..." => {
SpecialName::Vtt(TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int))),
b"..."
}
b"TIi..." => {
SpecialName::Typeinfo(TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int))),
b"..."
}
b"TSi..." => {
SpecialName::TypeinfoName(TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int))),
b"..."
}
b"Tv42_36_3abc..." => {
SpecialName::VirtualOverrideThunk(
CallOffset::Virtual(VOffset(42, 36)),
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 9,
end: 12,
}))))))),
b"..."
}
b"Tcv42_36_v42_36_3abc..." => {
SpecialName::VirtualOverrideThunkCovariant(
CallOffset::Virtual(VOffset(42, 36)),
CallOffset::Virtual(VOffset(42, 36)),
Box::new(Encoding::Data(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 17,
end: 20,
}))))))),
b"..."
}
b"GV3abc..." => {
SpecialName::Guard(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
}))))),
b"..."
}
b"GR3abc_..." => {
SpecialName::GuardTemporary(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
})))),
0),
b"..."
}
b"GR3abc0_..." => {
SpecialName::GuardTemporary(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier {
start: 3,
end: 6,
})))),
1),
b"..."
}
b"TCc7_i..." => {
SpecialName::ConstructionVtable(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Char)),
7,
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int))
),
b"..."
}
b"TFi..." => {
SpecialName::TypeinfoFunction(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Int))),
b"..."
}
b"TH4name..." => {
SpecialName::TlsInit(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier { start: 3, end: 7 }))))),
b"..."
}
b"TW4name..." => {
SpecialName::TlsWrapper(
Name::Unscoped(
UnscopedName::Unqualified(
UnqualifiedName::Source(
SourceName(Identifier { start: 3, end: 7 }))))),
b"..."
}
}
Err => {
b"TZ" => Error::UnexpectedText,
b"GZ" => Error::UnexpectedText,
b"GR3abcz" => Error::UnexpectedText,
b"GR3abc0z" => Error::UnexpectedText,
b"T" => Error::UnexpectedEnd,
b"G" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
b"GR3abc" => Error::UnexpectedEnd,
b"GR3abc0" => Error::UnexpectedEnd,
b"TCcn7_i..." => Error::UnexpectedText,
}
});
}
#[test]
fn parse_function_param() {
assert_parse!(FunctionParam {
Ok => {
b"fpK_..." => {
FunctionParam(0,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(0)),
b"..."
}
b"fL1pK_..." => {
FunctionParam(1,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(0)),
b"..."
}
b"fpK3_..." => {
FunctionParam(0,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(4)),
b"..."
}
b"fL1pK4_..." => {
FunctionParam(1,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(5)),
b"..."
}
}
Err => {
b"fz" => Error::UnexpectedText,
b"fLp_" => Error::UnexpectedText,
b"fpL_" => Error::UnexpectedText,
b"fL1pK4z" => Error::UnexpectedText,
b"fL1pK4" => Error::UnexpectedEnd,
b"fL1p" => Error::UnexpectedEnd,
b"fL1" => Error::UnexpectedEnd,
b"fL" => Error::UnexpectedEnd,
b"f" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_discriminator() {
assert_parse!(Discriminator {
Ok => {
b"_0..." => {
Discriminator(0),
b"..."
}
b"_9..." => {
Discriminator(9),
b"..."
}
b"__99_..." => {
Discriminator(99),
b"..."
}
}
Err => {
b"_n1" => Error::UnexpectedText,
b"__99..." => Error::UnexpectedText,
b"__99" => Error::UnexpectedEnd,
b"..." => Error::UnexpectedText,
}
});
}
#[test]
fn parse_data_member_prefix() {
assert_parse!(DataMemberPrefix {
Ok => {
b"3fooM..." => {
DataMemberPrefix(SourceName(Identifier {
start: 1,
end: 4,
})),
b"..."
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"1" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_ref_qualifier() {
assert_parse!(RefQualifier {
Ok => {
b"R..." => {
RefQualifier::LValueRef,
b"..."
}
b"O..." => {
RefQualifier::RValueRef,
b"..."
}
}
Err => {
b"..." => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_cv_qualifiers() {
assert_parse!(CvQualifiers {
Ok => {
b"" => {
CvQualifiers { restrict: false, volatile: false, const_: false },
b""
}
b"..." => {
CvQualifiers { restrict: false, volatile: false, const_: false },
b"..."
}
b"r..." => {
CvQualifiers { restrict: true, volatile: false, const_: false },
b"..."
}
b"rV..." => {
CvQualifiers { restrict: true, volatile: true, const_: false },
b"..."
}
b"rVK..." => {
CvQualifiers { restrict: true, volatile: true, const_: true },
b"..."
}
b"V" => {
CvQualifiers { restrict: false, volatile: true, const_: false },
b""
}
b"VK" => {
CvQualifiers { restrict: false, volatile: true, const_: true },
b""
}
b"K..." => {
CvQualifiers { restrict: false, volatile: false, const_: true },
b"..."
}
}
Err => {
}
});
}
#[test]
fn parse_builtin_type() {
assert_parse!(BuiltinType {
Ok => {
b"c..." => {
BuiltinType::Standard(StandardBuiltinType::Char),
b"..."
}
b"c" => {
BuiltinType::Standard(StandardBuiltinType::Char),
b""
}
b"u3abc..." => {
BuiltinType::Extension(SourceName(Identifier {
start: 2,
end: 5,
})),
b"..."
}
}
Err => {
b"." => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_template_param() {
assert_parse!(TemplateParam {
Ok => {
b"T_..." => {
TemplateParam(0),
b"..."
}
b"T3_..." => {
TemplateParam(4),
b"..."
}
}
Err => {
b"wtf" => Error::UnexpectedText,
b"Twtf" => Error::UnexpectedText,
b"T3wtf" => Error::UnexpectedText,
b"T" => Error::UnexpectedEnd,
b"T3" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_unscoped_name() {
assert_parse!(UnscopedName {
Ok => {
b"St5hello..." => {
UnscopedName::Std(UnqualifiedName::Source(SourceName(Identifier {
start: 3,
end: 8,
}))),
b"..."
}
b"5hello..." => {
UnscopedName::Unqualified(UnqualifiedName::Source(SourceName(Identifier {
start: 1,
end: 6,
}))),
b"..."
}
}
Err => {
b"St..." => Error::UnexpectedText,
b"..." => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_unqualified_name() {
assert_parse!(UnqualifiedName {
Ok => {
b"qu.." => {
UnqualifiedName::Operator(OperatorName::Simple(SimpleOperatorName::Question)),
b".."
}
b"C1.." => {
UnqualifiedName::CtorDtor(CtorDtorName::CompleteConstructor(None)),
b".."
}
b"10abcdefghij..." => {
UnqualifiedName::Source(SourceName(Identifier {
start: 2,
end: 12,
})),
b"..."
}
b"UllE_..." => {
UnqualifiedName::ClosureType(
ClosureTypeName(
LambdaSig(vec![
TypeHandle::Builtin(
BuiltinType::Standard(
StandardBuiltinType::Long))
]),
None)),
b"..."
}
b"Ut5_..." => {
UnqualifiedName::UnnamedType(UnnamedTypeName(Some(5))),
b"..."
}
b"B5cxx11..." => {
UnqualifiedName::ABITag(TaggedName(SourceName(Identifier {
start: 2,
end: 7,
}))),
b"..."
}
b"L3foo_0..." => {
UnqualifiedName::LocalSourceName(
SourceName(Identifier {
start: 2,
end: 5
}),
Some(Discriminator(0))
),
"..."
}
b"L3foo..." => {
UnqualifiedName::LocalSourceName(
SourceName(Identifier {
start: 2,
end: 5
}),
None
),
"..."
}
}
Err => {
b"zzz" => Error::UnexpectedText,
b"Uq" => Error::UnexpectedText,
b"C" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_unnamed_type_name() {
assert_parse!(UnnamedTypeName {
Ok => {
b"Ut_abc" => {
UnnamedTypeName(None),
b"abc"
}
b"Ut42_abc" => {
UnnamedTypeName(Some(42)),
b"abc"
}
b"Ut42_" => {
UnnamedTypeName(Some(42)),
b""
}
}
Err => {
b"ut_" => Error::UnexpectedText,
b"u" => Error::UnexpectedEnd,
b"Ut" => Error::UnexpectedEnd,
b"Ut._" => Error::UnexpectedText,
b"Ut42" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_identifier() {
assert_parse!(Identifier {
Ok => {
b"1abc" => {
Identifier { start: 0, end: 4 },
b""
}
b"_Az1\0\0\0" => {
Identifier { start: 0, end: 4 },
b"\0\0\0"
}
b"$_0\0\0\0" => {
Identifier { start: 0, end: 3 },
b"\0\0\0"
}
}
Err => {
b"\0\0\0" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_source_name() {
assert_parse!(SourceName {
Ok => {
b"1abc" => {
SourceName(Identifier { start: 1, end: 2 }),
b"bc"
}
b"10abcdefghijklm" => {
SourceName(Identifier { start: 2, end: 12 }),
b"klm"
}
}
Err => {
b"0abc" => Error::UnexpectedText,
b"n1abc" => Error::UnexpectedText,
b"10abcdef" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_number() {
assert_parse!(Number {
Ok => {
b"n2n3" => {
-2,
b"n3"
}
b"12345abcdef" => {
12345,
b"abcdef"
}
b"0abcdef" => {
0,
b"abcdef"
}
b"42" => {
42,
b""
}
}
Err => {
b"001" => Error::UnexpectedText,
b"wutang" => Error::UnexpectedText,
b"n" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_call_offset() {
assert_parse!(CallOffset {
Ok => {
b"hn42_..." => {
CallOffset::NonVirtual(NvOffset(-42)),
b"..."
}
b"vn42_36_..." => {
CallOffset::Virtual(VOffset(-42, 36)),
b"..."
}
}
Err => {
b"h1..." => Error::UnexpectedText,
b"v1_1..." => Error::UnexpectedText,
b"hh" => Error::UnexpectedText,
b"vv" => Error::UnexpectedText,
b"z" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_v_offset() {
assert_parse!(VOffset {
Ok => {
b"n2_n3abcdef" => {
VOffset(-2, -3),
b"abcdef"
}
b"12345_12345abcdef" => {
VOffset(12345, 12345),
b"abcdef"
}
b"0_0abcdef" => {
VOffset(0, 0),
b"abcdef"
}
b"42_n3" => {
VOffset(42, -3),
b""
}
}
Err => {
b"001" => Error::UnexpectedText,
b"1_001" => Error::UnexpectedText,
b"wutang" => Error::UnexpectedText,
b"n_" => Error::UnexpectedText,
b"1_n" => Error::UnexpectedEnd,
b"1_" => Error::UnexpectedEnd,
b"n" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_nv_offset() {
assert_parse!(NvOffset {
Ok => {
b"n2n3" => {
NvOffset(-2),
b"n3"
}
b"12345abcdef" => {
NvOffset(12345),
b"abcdef"
}
b"0abcdef" => {
NvOffset(0),
b"abcdef"
}
b"42" => {
NvOffset(42),
b""
}
}
Err => {
b"001" => Error::UnexpectedText,
b"wutang" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_seq_id() {
assert_parse!(SeqId {
Ok => {
b"1_" => {
SeqId(1),
b"_"
}
b"42" => {
SeqId(146),
b""
}
b"ABCabc" => {
SeqId(13368),
b"abc"
}
}
Err => {
b"abc" => Error::UnexpectedText,
b"001" => Error::UnexpectedText,
b"wutang" => Error::UnexpectedText,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_ctor_dtor_name() {
assert_parse!(CtorDtorName {
Ok => {
b"D0" => {
CtorDtorName::DeletingDestructor,
b""
}
b"C101" => {
CtorDtorName::CompleteConstructor(None),
b"01"
}
}
Err => {
b"gayagaya" => Error::UnexpectedText,
b"C" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
#[test]
fn parse_operator_name() {
assert_parse!(OperatorName {
Ok => {
b"qu..." => {
OperatorName::Simple(SimpleOperatorName::Question),
b"..."
}
b"cvi..." => {
OperatorName::Conversion(
TypeHandle::Builtin(
BuiltinType::Standard(
StandardBuiltinType::Int))),
b"..."
}
b"li3Foo..." => {
OperatorName::Literal(SourceName(Identifier {
start: 3,
end: 6,
})),
b"..."
}
b"v33Foo..." => {
OperatorName::VendorExtension(3, SourceName(Identifier {
start: 3,
end: 6
})),
b"..."
}
}
Err => {
b"cv" => Error::UnexpectedEnd,
b"li3ab" => Error::UnexpectedEnd,
b"li" => Error::UnexpectedEnd,
b"v33ab" => Error::UnexpectedEnd,
b"v3" => Error::UnexpectedEnd,
b"v" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
b"q" => Error::UnexpectedText,
b"c" => Error::UnexpectedText,
b"l" => Error::UnexpectedText,
b"zzz" => Error::UnexpectedText,
}
});
}
#[test]
fn parse_simple_operator_name() {
assert_parse!(SimpleOperatorName {
Ok => {
b"qu" => {
SimpleOperatorName::Question,
b""
}
b"quokka" => {
SimpleOperatorName::Question,
b"okka"
}
}
Err => {
b"bu-buuuu" => Error::UnexpectedText,
b"q" => Error::UnexpectedEnd,
b"" => Error::UnexpectedEnd,
}
});
}
}