extern crate fixedbitset;
use error::{self, Result};
use index_str::IndexStr;
use self::fixedbitset::FixedBitSet;
#[cfg(feature = "logging")]
use std::cell::{RefCell};
use std::cell::Cell;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::mem;
use std::ops;
use subs::{Substitutable, SubstitutionTable};
use super::DemangleOptions;
struct AutoLogParse;
thread_local! {
#[cfg(feature = "logging")]
static LOG_DEPTH: RefCell<usize> = RefCell::new(0);
}
impl AutoLogParse {
#[cfg(feature = "logging")]
fn new<'a>(production: &'static str, input: IndexStr<'a>) -> 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 = try!(AutoRecursion::new($ctx));
}
}
struct AutoLogDemangle;
impl AutoLogDemangle {
#[cfg(feature = "logging")]
fn new<P, W>(production: &P,
ctx: &DemangleContext<W>,
stack: Option<ArgScopeStack>)
-> AutoLogDemangle
where P: ?Sized + fmt::Debug,
W: io::Write
{
LOG_DEPTH.with(|depth| {
if *depth.borrow() == 0 {
println!("");
}
let indent: String = (0..*depth.borrow() * 4).map(|_| ' ').collect();
log!("{}(", indent);
log!("{} {:?}", indent, production);
log!("{} inner = {:?}", indent, ctx.inner);
log!("{} stack = {:?}", indent, stack);
*depth.borrow_mut() += 1;
});
AutoLogDemangle
}
#[cfg(not(feature = "logging"))]
#[inline(always)]
fn new<P, W>(_: &P,
_: &DemangleContext<W>,
_: Option<ArgScopeStack>)
-> AutoLogDemangle
where P: ?Sized + fmt::Debug,
W: io::Write
{
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! log_demangle {
( $production:expr , $ctx:expr , $stack:expr ) => {
let _log = AutoLogDemangle::new($production, $ctx, $stack);
}
}
#[derive(Debug, Clone)]
pub struct ParseContext {
max_recursion: u32,
recursion_level: Cell<u32>,
}
impl Default for ParseContext {
fn default() -> ParseContext {
ParseContext {
max_recursion: 64,
recursion_level: Cell::new(0),
}
}
}
impl ParseContext {
pub fn recursion_level(&self) -> u32 {
self.recursion_level.get()
}
#[inline]
fn enter_recursion(&self) -> error::Result<()> {
let new_recursion_level = self.recursion_level.get() + 1;
if new_recursion_level >= self.max_recursion {
log!("Hit too much recursion at level {}", self.max_recursion);
Err(error::Error::TooMuchRecursion)
} else {
self.recursion_level.set(new_recursion_level);
Ok(())
}
}
#[inline]
fn exit_recursion(&self) {
debug_assert!(self.recursion_level.get() >= 1);
self.recursion_level.set(self.recursion_level.get() - 1);
}
}
struct AutoRecursion<'a>(&'a ParseContext);
impl<'a> AutoRecursion<'a> {
#[inline]
fn new(ctx: &'a ParseContext) -> error::Result<AutoRecursion<'a>> {
try!(ctx.enter_recursion());
Ok(AutoRecursion(ctx))
}
}
impl<'a> Drop for AutoRecursion<'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 StartsWith {
fn starts_with(byte: u8) -> bool;
}
trait GetTemplateArgs {
fn get_template_args<'a>(&'a self,
subs: &'a SubstitutionTable)
-> Option<&'a TemplateArgs>;
}
trait ArgScope<'me, 'ctx>: fmt::Debug {
fn get_template_arg(&'me self, idx: usize) -> Result<&'ctx TemplateArg>;
fn get_function_arg(&'me self, idx: usize) -> Result<&'ctx Type>;
}
#[derive(Copy, Clone, Debug)]
pub struct ArgScopeStack<'prev, 'subs>
where 'subs: 'prev
{
item: &'subs ArgScope<'subs, 'subs>,
prev: Option<&'prev ArgScopeStack<'prev, 'subs>>,
}
trait ArgScopeStackExt<'prev, 'subs> {
fn push(&'prev self, item: &'subs ArgScope<'subs, 'subs>) -> Option<ArgScopeStack<'prev, 'subs>>;
}
impl<'prev, 'subs> ArgScopeStackExt<'prev, 'subs> for Option<ArgScopeStack<'prev, 'subs>> {
fn push(&'prev self, item: &'subs ArgScope<'subs, 'subs>) -> Option<ArgScopeStack<'prev, 'subs>> {
Some(ArgScopeStack {
prev: self.as_ref(),
item: item,
})
}
}
impl<'prev, 'subs> ArgScope<'prev, 'subs> for Option<ArgScopeStack<'prev, 'subs>> {
fn get_template_arg(&'prev self, idx: usize) -> Result<&'subs TemplateArg> {
let mut stack = *self;
while let Some(s) = stack {
if let Ok(arg) = s.item.get_template_arg(idx) {
return Ok(arg);
}
stack = s.prev.cloned();
}
Err(error::Error::BadTemplateArgReference)
}
fn get_function_arg(&'prev self, idx: usize) -> Result<&'subs Type> {
let mut stack = *self;
while let Some(s) = stack {
if let Ok(arg) = s.item.get_function_arg(idx) {
return Ok(arg);
}
stack = s.prev.cloned();
}
Err(error::Error::BadFunctionArgReference)
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct DemangleContext<'a, W>
where W: 'a + io::Write
{
subs: &'a SubstitutionTable,
inner: Vec<&'a DemangleAsInner<'a, W>>,
input: &'a [u8],
out: W,
bytes_written: usize,
last_byte_written: Option<u8>,
mark_bits: FixedBitSet,
template_params_to_args: HashMap<&'a TemplateParam, &'a TemplateArg>,
options: &'a DemangleOptions,
}
impl<'a, W> io::Write for DemangleContext<'a, W>
where W: 'a + io::Write
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
log!("DemangleContext::write: '{}'", String::from_utf8_lossy(buf));
self.out.write(buf).map(|n| {
self.last_byte_written = buf.last().cloned();
self.bytes_written += n;
n
})
}
fn flush(&mut self) -> io::Result<()> {
self.out.flush()
}
}
impl<'a, W> DemangleContext<'a, W>
where W: 'a + io::Write
{
pub fn new(subs: &'a SubstitutionTable,
input: &'a [u8],
options: &'a DemangleOptions,
out: W)
-> DemangleContext<'a, W> {
DemangleContext {
subs: subs,
inner: vec![],
input: input,
out: out,
bytes_written: 0,
last_byte_written: None,
mark_bits: FixedBitSet::with_capacity(subs.len()),
template_params_to_args: HashMap::new(),
options: options,
}
}
fn set_mark_bit(&mut self, idx: usize) {
self.mark_bits.set(idx, true);
}
fn clear_mark_bit(&mut self, idx: usize) {
self.mark_bits.set(idx, false);
}
fn mark_bit_is_set(&self, idx: usize) -> bool {
self.mark_bits[idx]
}
fn ensure(&mut self, ch: char) -> io::Result<()> {
if self.last_byte_written.map(|b| b as char) == Some(ch) {
Ok(())
} else {
try!(write!(self, "{}", ch));
Ok(())
}
}
fn ensure_space(&mut self) -> io::Result<()> {
self.ensure(' ')
}
}
#[doc(hidden)]
pub trait Demangle<'subs, W>: fmt::Debug
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>;
}
#[doc(hidden)]
pub trait DemangleAsInner<'subs, W>: fmt::Debug
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>;
fn downcast_to_type(&self) -> Option<&Type> {
None
}
fn downcast_to_array_type(&self) -> Option<&ArrayType> {
None
}
fn downcast_to_pointer_to_member(&self) -> Option<&PointerToMemberType> {
None
}
fn downcast_to_encoding(&self) -> Option<&Encoding> {
None
}
}
macro_rules! reference_newtype {
( $newtype_name:ident , $oldtype:ty ) => {
#[derive(Debug)]
struct $newtype_name($oldtype);
impl $newtype_name {
#[allow(ptr_arg)]
#[allow(unsafe_code)]
fn new(types: &$oldtype) -> &$newtype_name {
unsafe {
mem::transmute(types)
}
}
}
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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
if ctx.options.no_params && stack.is_none() {
return Ok(());
}
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::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_byte_written {
Some(b'(') | Some(b'*') => false,
_ => true,
};
if needs_space {
try!(ctx.ensure_space());
}
try!(write!(ctx, "{}", '('));
}
let mut new_inner = vec![];
while let Some(inner) = ctx.inner.pop() {
if inner.downcast_to_encoding().is_some() {
new_inner.push(inner);
} else {
try!(inner.demangle_as_inner(ctx, stack));
}
}
ctx.inner = new_inner;
if needs_paren {
try!(write!(ctx, "{}", ')'));
}
try!(write!(ctx, "("));
if self.len() == 1 && self[0].is_void() {
try!(write!(ctx, ")"));
return Ok(());
}
let mut need_comma = false;
for arg in self.iter() {
if need_comma {
try!(write!(ctx, ", "));
}
try!(arg.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ")"));
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for FunctionArgList
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
FunctionArgSlice::new(&self.0[..]).demangle(ctx, stack)
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for FunctionArgListAndReturnType
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
FunctionArgSlice::new(&self.0[1..]).demangle(ctx, stack)
}
}
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 + io::Write
{
#[inline]
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
match *self {
$typename::WellKnown(ref comp) => comp.demangle(ctx, stack),
$typename::BackReference(idx) => {
if ctx.mark_bit_is_set(idx) {
return Err(io::Error::new(io::ErrorKind::Other,
error::Error::RecursiveDemangling.description()));
}
ctx.set_mark_bit(idx);
let ret = ctx.subs[idx].demangle(ctx, stack);
ctx.clear_mark_bit(idx);
ret
}
$(
$typename::$extra_variant(ref extra) => extra.demangle(ctx, stack),
)*
}
}
}
};
}
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 $typename {
fn demangle<'me, 'prev, 'ctx, 'subs, W>(&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>
where W: 'subs + io::Write
{
log_demangle!(self, ctx, stack);
write!(ctx, "{}", match *self {
$(
$typename::$variant => $printable
),*
})
}
}
impl StartsWith for $typename {
#[inline]
fn starts_with(byte: u8) -> bool {
$(
if $mangled[0] == byte {
return true;
}
)*
false
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MangledName {
Encoding(Encoding),
Type(TypeHandle),
}
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);
let tail = if let Ok(tail) = consume(b"__Z", input) {
tail
} else if let Ok(tail) = consume(b"_Z", input) {
tail
} else {
input
};
if let Ok((encoding, tail)) = Encoding::parse(ctx, subs, tail) {
return Ok((MangledName::Encoding(encoding), tail));
};
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, input));
Ok((MangledName::Type(ty), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for MangledName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
MangledName::Encoding(ref enc) => enc.demangle(ctx, stack),
MangledName::Type(ref ty) => ty.demangle(ctx, stack),
}
}
}
#[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) = try!(SpecialName::parse(ctx, subs, input));
Ok((Encoding::Special(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Encoding
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
Encoding::Function(ref name, ref fun_ty) => {
debug_assert!(fun_ty.0.len() >= 1);
let stack = if let Some(template_args) = name.get_template_args(ctx.subs) {
let stack = stack.push(template_args);
try!(fun_ty.0[0].demangle(ctx, stack));
try!(write!(ctx, " "));
stack
} else {
stack
};
ctx.inner.push(self);
try!(name.demangle(ctx, stack));
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
Encoding::Data(ref name) => name.demangle(ctx, stack),
Encoding::Special(ref name) => name.demangle(ctx, stack),
}
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for Encoding
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
if let Encoding::Function(ref name, ref fun_ty) = *self {
let (stack, function_args) = if let Some(template_args) =
name.get_template_args(ctx.subs) {
let stack = stack.push(template_args);
let function_args = FunctionArgListAndReturnType::new(&fun_ty.0);
(stack, function_args as &DemangleAsInner<W>)
} else {
let function_args = FunctionArgList::new(&fun_ty.0);
(stack, function_args as &DemangleAsInner<W>)
};
function_args.demangle_as_inner(ctx, stack)
} else {
unreachable!("we only push Encoding::Function onto the inner stack");
}
}
fn downcast_to_encoding(&self) -> Option<&Encoding> {
Some(self)
}
}
#[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) = try!(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) = try!(TemplateArgs::parse(ctx, subs, tail));
return Ok((Name::UnscopedTemplate(name, args), tail));
}
let (name, tail) = try!(LocalName::parse(ctx, subs, input));
Ok((Name::Local(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Name
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
Name::Nested(ref nested) => nested.demangle(ctx, stack),
Name::Unscoped(ref unscoped) => unscoped.demangle(ctx, stack),
Name::UnscopedTemplate(ref template, ref args) => {
try!(template.demangle(ctx, stack.push(args)));
args.demangle(ctx, stack)
}
Name::Local(ref local) => local.demangle(ctx, stack),
}
}
}
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,
}
}
}
#[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) = try!(UnqualifiedName::parse(ctx, subs, tail));
return Ok((UnscopedName::Std(name), tail));
}
let (name, tail) = try!(UnqualifiedName::parse(ctx, subs, input));
Ok((UnscopedName::Unqualified(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for UnscopedName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
UnscopedName::Unqualified(ref unqualified) => {
unqualified.demangle(ctx, stack)
}
UnscopedName::Std(ref std) => {
try!(write!(ctx, "std::"));
std.demangle(ctx, stack)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnscopedTemplateName(UnscopedName);
define_handle! {
pub enum UnscopedTemplateNameHandle
}
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) = try!(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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
self.0.demangle(ctx, stack)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NestedName(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 = try!(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) = try!(PrefixHandle::parse(ctx, subs, tail));
if let PrefixHandle::BackReference(idx) = prefix {
match (*subs)[idx] {
Substitutable::Prefix(Prefix::Nested(..)) |
Substitutable::Prefix(Prefix::Template(..)) => {}
_ => return Err(error::Error::UnexpectedText),
}
}
let tail = try!(consume(b"E", tail));
Ok((NestedName(cv_qualifiers, ref_qualifier, prefix), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for NestedName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(self.2.demangle(ctx, stack));
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
if self.0 != CvQualifiers::default() {
try!(self.0.demangle(ctx, stack));
}
if let Some(ref refs) = self.1 {
try!(ctx.ensure_space());
try!(refs.demangle(ctx, stack));
}
Ok(())
}
}
impl GetTemplateArgs for NestedName {
fn get_template_args<'a>(&'a self,
subs: &'a SubstitutionTable)
-> Option<&'a TemplateArgs> {
self.2.get_template_args(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
}
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);
fn add_to_subs(subs: &mut SubstitutionTable, prefix: Prefix) -> PrefixHandle {
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() {
None => {
if let Some(handle) = current {
return Ok((handle, tail));
} else {
return Err(error::Error::UnexpectedEnd);
}
}
Some(b'S') => {
let (sub, tail_tail) = try!(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) = try!(TemplateParam::parse(ctx, subs, tail));
current = Some(add_to_subs(subs, Prefix::TemplateParam(param)));
tail = tail_tail;
}
Some(b'D') => {
if let Ok((decltype, tail_tail)) = Decltype::parse(ctx, subs, tail) {
current = Some(add_to_subs(subs, Prefix::Decltype(decltype)));
tail = tail_tail;
} else {
let (name, tail_tail) = try!(UnqualifiedName::parse(ctx, subs, tail));
let prefix = match current {
None => Prefix::Unqualified(name),
Some(handle) => Prefix::Nested(handle, name),
};
current = Some(add_to_subs(subs, prefix));
tail = tail_tail;
}
}
Some(b'I') if current.is_some() &&
current.as_ref().unwrap().is_template_prefix(subs) => {
let (args, tail_tail) = try!(TemplateArgs::parse(ctx, subs, tail));
let prefix = Prefix::Template(current.unwrap(), args);
current = Some(add_to_subs(subs, prefix));
tail = tail_tail;
}
Some(c) if current.is_some() && SourceName::starts_with(c) => {
debug_assert!(UnqualifiedName::starts_with(c));
debug_assert!(DataMemberPrefix::starts_with(c));
let (name, tail_tail) = try!(SourceName::parse(ctx, subs, tail));
if tail_tail.peek() == Some(b'M') {
let prefix = Prefix::DataMember(current.unwrap(),
DataMemberPrefix(name));
current = Some(add_to_subs(subs, prefix));
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(add_to_subs(subs, prefix));
tail = tail_tail;
}
}
Some(c) if UnqualifiedName::starts_with(c) => {
let (name, tail_tail) = try!(UnqualifiedName::parse(ctx, subs, tail));
let prefix = match current {
None => Prefix::Unqualified(name),
Some(handle) => Prefix::Nested(handle, name),
};
current = Some(add_to_subs(subs, prefix));
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 Prefix {
fn is_template_prefix(&self) -> bool {
match *self {
Prefix::Unqualified(..) |
Prefix::Nested(..) |
Prefix::TemplateParam(..) => true,
_ => false,
}
}
}
impl PrefixHandle {
fn is_template_prefix(&self, subs: &SubstitutionTable) -> bool {
match *self {
PrefixHandle::BackReference(idx) => {
if let Some(&Substitutable::Prefix(ref p)) = subs.get(idx) {
p.is_template_prefix()
} else {
false
}
}
_ => false,
}
}
fn get_template_args<'me, 'ctx>(&'me self,
subs: &'ctx SubstitutionTable)
-> Option<&'ctx TemplateArgs> {
match *self {
PrefixHandle::BackReference(idx) => {
if let Some(&Substitutable::Prefix(ref p)) = subs.get(idx) {
p.get_template_args(subs)
} else {
None
}
}
_ => None,
}
}
}
impl<'subs, W> Demangle<'subs, W> for Prefix
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
Prefix::Unqualified(ref unqualified) => unqualified.demangle(ctx, stack),
Prefix::Nested(ref prefix, ref unqualified) => {
try!(prefix.demangle(ctx, stack));
try!(write!(ctx, "::"));
unqualified.demangle(ctx, stack)
}
Prefix::Template(ref prefix, ref args) => {
try!(prefix.demangle(ctx, stack));
args.demangle(ctx, stack)
}
Prefix::TemplateParam(ref param) => param.demangle(ctx, stack),
Prefix::Decltype(ref dt) => dt.demangle(ctx, stack),
Prefix::DataMember(ref prefix, ref member) => {
try!(prefix.demangle(ctx, stack));
member.demangle(ctx, stack)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnqualifiedName {
Operator(OperatorName),
CtorDtor(CtorDtorName),
Source(SourceName),
UnnamedType(UnnamedTypeName),
}
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((source, tail)) = SourceName::parse(ctx, subs, input) {
return Ok((UnqualifiedName::Source(source), tail));
}
UnnamedTypeName::parse(ctx, subs, input)
.map(|(unnamed, tail)| (UnqualifiedName::UnnamedType(unnamed), tail))
}
}
impl StartsWith for UnqualifiedName {
#[inline]
fn starts_with(byte: u8) -> bool {
OperatorName::starts_with(byte) || CtorDtorName::starts_with(byte) ||
SourceName::starts_with(byte) || UnnamedTypeName::starts_with(byte)
}
}
impl<'subs, W> Demangle<'subs, W> for UnqualifiedName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
UnqualifiedName::Operator(ref op_name) => {
try!(write!(ctx, "operator"));
op_name.demangle(ctx, stack)
}
UnqualifiedName::CtorDtor(ref ctor_dtor) => ctor_dtor.demangle(ctx, stack),
UnqualifiedName::Source(ref name) => name.demangle(ctx, stack),
UnqualifiedName::UnnamedType(ref unnamed) => unnamed.demangle(ctx, stack),
}
}
}
#[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) = try!(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) = try!(Identifier::parse(ctx, subs, head));
if !empty.is_empty() {
return Err(error::Error::UnexpectedText);
}
let source_name = SourceName(identifier);
Ok((source_name, tail))
}
}
impl StartsWith for SourceName {
#[inline]
fn starts_with(byte: u8) -> bool {
byte == b'0' || (b'0' <= byte && byte <= b'9')
}
}
impl SourceName {
#[inline]
fn demangle<'me, 'prev, 'ctx, 'subs, W>(&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>
where W: 'subs + io::Write
{
log_demangle!(self, ctx, stack);
self.0.demangle(ctx, stack)
}
}
#[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.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 Identifier {
#[inline]
fn demangle<'me, 'prev, 'ctx, 'subs, W>(&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>
where W: 'subs + io::Write
{
log_demangle!(self, ctx, stack);
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') => {
try!(write!(ctx, "(anonymous namespace)"));
return Ok(());
}
_ => {
}
}
}
try!(write!(ctx, "{}", String::from_utf8_lossy(ident)));
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),
Literal(SourceName),
VendorExtension(u8, SourceName),
}
impl StartsWith for OperatorName {
fn starts_with(byte: u8) -> bool {
byte == b'c' || byte == b'l' || byte == b'v' ||
SimpleOperatorName::starts_with(byte)
}
}
impl Parse for OperatorName {
fn parse<'a, 'b>(ctx: &'a ParseContext,
subs: &'a mut SubstitutionTable,
input: IndexStr<'b>)
-> 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 (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
return Ok((OperatorName::Cast(ty), tail));
}
if let Ok(tail) = consume(b"li", input) {
let (name, tail) = try!(SourceName::parse(ctx, subs, tail));
return Ok((OperatorName::Literal(name), tail));
}
let tail = try!(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) = try!(SourceName::parse(ctx, subs, tail));
Ok((OperatorName::VendorExtension(arity, name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for OperatorName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
OperatorName::Simple(ref simple) => simple.demangle(ctx, stack),
OperatorName::Cast(ref ty) => {
try!(ctx.ensure_space());
let stack = ty.get_template_args(ctx.subs)
.map_or(stack, |args| stack.push(args));
try!(ty.demangle(ctx, stack));
Ok(())
}
OperatorName::Literal(ref name) => {
try!(name.demangle(ctx, stack));
try!(write!(ctx, "::operator \"\""));
Ok(())
}
OperatorName::VendorExtension(arity, ref name) => {
try!(name.demangle(ctx, stack));
try!(write!(ctx, "::operator {}", arity));
Ok(())
}
}
}
}
define_vocabulary! {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SimpleOperatorName {
New (b"nw", "new"),
NewArray (b"na", "new[]"),
Delete (b"dl", "delete"),
DeleteArray (b"da", "delete[]"),
UnaryPlus (b"ps", "+"), Neg (b"ng", "-"), AddressOf (b"ad", "&"), Deref (b"de", "*"), BitNot (b"co", "~"),
Add (b"pl", "+"),
Sub (b"mi", "-"),
Mul (b"ml", "*"),
Div (b"dv", "/"),
Rem (b"rm", "%"),
BitAnd (b"an", "&"),
BitOr (b"or", "|"),
BitXor (b"eo", "^"),
Assign (b"aS", "="),
AddAssign (b"pL", "+="),
SubAssign (b"mI", "-="),
MulAssign (b"mL", "*="),
DivAssign (b"dV", "/="),
RemAssign (b"rM", "%="),
BitAndAssign (b"aN", "&="),
BitOrAssign (b"oR", "|="),
BitXorAssign (b"eO", "^="),
Shl (b"ls", "<<"),
Shr (b"rs", ">>"),
ShlAssign (b"lS", "<<="),
ShrAssign (b"rS", ">>="),
Eq (b"eq", "=="),
Ne (b"ne", "!="),
Less (b"lt", "<"),
Greater (b"gt", ">"),
LessEq (b"le", "<="),
GreaterEq (b"ge", ">="),
Not (b"nt", "!"),
LogicalAnd (b"aa", "&&"),
LogicalOr (b"oo", "||"),
PostInc (b"pp", "++"), PostDec (b"mm", "--"), Comma (b"cm", ","),
DerefMemberPtr (b"pm", "->*"),
DerefMember (b"pt", "->"),
Call (b"cl", "()"),
Index (b"ix", "[]"),
Question (b"qu", "?:")
}
}
#[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) = try!(NvOffset::parse(ctx, subs, tail));
let tail = try!(consume(b"_", tail));
return Ok((CallOffset::NonVirtual(offset), tail));
}
if let Ok(tail) = consume(b"v", input) {
let (offset, tail) = try!(VOffset::parse(ctx, subs, tail));
let tail = try!(consume(b"_", tail));
return Ok((CallOffset::Virtual(offset), tail));
}
Err(error::Error::UnexpectedText)
}
}
impl<'subs, W> Demangle<'subs, W> for CallOffset
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
CallOffset::NonVirtual(NvOffset(offset)) => {
try!(write!(ctx, "{{offset({})}}", offset));
}
CallOffset::Virtual(VOffset(vbase, vcall)) => {
try!(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) = try!(Number::parse(ctx, subs, input));
let tail = try!(consume(b"_", tail));
let (virtual_offset, tail) = try!(Number::parse(ctx, subs, tail));
Ok((VOffset(offset, virtual_offset), tail))
}
}
define_vocabulary! {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CtorDtorName {
CompleteConstructor (b"C1", "complete object constructor"),
BaseConstructor (b"C2", "base object constructor"),
CompleteAllocatingConstructor (b"C3", "complete object allocating constructor"),
DeletingDestructor (b"D0", "deleting destructor"),
CompleteDestructor (b"D1", "complete object destructor"),
BaseDestructor (b"D2", "base object destructor")
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
Function(FunctionType),
ClassEnum(ClassEnumType),
Array(ArrayType),
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)) = 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);
}
}
if let Ok((ttp, tail)) = TemplateTemplateParamHandle::parse(ctx, subs, input) {
let (args, tail) = try!(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) = try!(TypeHandle::parse(ctx, subs, tail));
return if let TypeHandle::Builtin(builtin) = ty {
Ok((TypeHandle::QualifiedBuiltin(QualifiedBuiltin(qualifiers, builtin)),
tail))
} else {
let ty = Type::Qualified(qualifiers, ty);
insert_and_return_handle(ty, subs, tail)
};
}
}
if let Ok(tail) = consume(b"P", input) {
let (ty, tail) = try!(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) = try!(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) = try!(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) = try!(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) = try!(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) = try!(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) = try!(TypeHandle::parse(ctx, subs, tail));
let ty = Type::VendorExtension(name, args, ty);
return insert_and_return_handle(ty, subs, tail);
}
let tail = try!(consume(b"Dp", input));
let (ty, tail) = try!(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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
Type::Function(ref func_ty) => func_ty.demangle(ctx, stack),
Type::ClassEnum(ref cls_enum_ty) => cls_enum_ty.demangle(ctx, stack),
Type::Array(ref array_ty) => array_ty.demangle(ctx, stack),
Type::PointerToMember(ref ptm) => ptm.demangle(ctx, stack),
Type::TemplateParam(ref param) => param.demangle(ctx, stack),
Type::TemplateTemplate(ref tt_param, ref args) => {
try!(tt_param.demangle(ctx, stack));
args.demangle(ctx, stack)
}
Type::Decltype(ref dt) => dt.demangle(ctx, stack),
Type::Qualified(ref quals, ref ty) => {
ctx.inner.push(quals);
try!(ty.demangle(ctx, stack));
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
Type::PointerTo(ref ty) |
Type::LvalueRef(ref ty) |
Type::RvalueRef(ref ty) => {
ctx.inner.push(self);
try!(ty.demangle(ctx, stack));
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
Type::Complex(ref ty) => {
try!(ty.demangle(ctx, stack));
try!(write!(ctx, " complex"));
Ok(())
}
Type::Imaginary(ref ty) => {
try!(ty.demangle(ctx, stack));
try!(write!(ctx, " imaginary"));
Ok(())
}
Type::VendorExtension(ref name, ref template_args, ref ty) => {
try!(ty.demangle(ctx, stack));
try!(write!(ctx, " "));
try!(name.demangle(ctx, stack));
if let Some(ref args) = *template_args {
try!(args.demangle(ctx, stack));
}
Ok(())
}
Type::PackExpansion(ref ty) => {
try!(ty.demangle(ctx, stack));
try!(write!(ctx, "..."));
Ok(())
}
}
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for Type
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
Type::PointerTo(_) => {
try!(write!(ctx, "*"));
}
Type::LvalueRef(_) => {
try!(write!(ctx, "&"));
}
Type::RvalueRef(_) => {
try!(write!(ctx, "&&"));
}
_ => unreachable!("We shouldn't ever put any other types on the inner stack"),
}
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
fn downcast_to_type(&self) -> Option<&Type> {
Some(self)
}
}
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)
}
_ => None
}
}
}
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
pub struct CvQualifiers {
pub restrict: bool,
pub volatile: bool,
pub const_: bool,
}
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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
if self.const_ {
try!(ctx.ensure_space());
try!(write!(ctx, "const"));
}
if self.volatile {
try!(ctx.ensure_space());
try!(write!(ctx, "volatile"));
}
if self.restrict {
try!(ctx.ensure_space());
try!(write!(ctx, "restrict"));
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for CvQualifiers
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
self.demangle(ctx, stack)
}
}
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", "decimal16"),
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 = try!(consume(b"u", input));
let (name, tail) = try!(SourceName::parse(ctx, subs, tail));
Ok((BuiltinType::Extension(name), tail))
}
}
impl BuiltinType {
fn demangle<'me, 'prev, 'ctx, 'subs, W>(&'me self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>
where W: 'subs + io::Write
{
log_demangle!(self, ctx, stack);
match *self {
BuiltinType::Standard(ref ty) => ty.demangle(ctx, stack),
BuiltinType::Extension(ref name) => name.demangle(ctx, stack),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QualifiedBuiltin(CvQualifiers, BuiltinType);
impl<'subs, W> Demangle<'subs, W> for QualifiedBuiltin
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>
{
log_demangle!(self, ctx, stack);
ctx.inner.push(&self.0);
try!(self.1.demangle(ctx, stack));
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
}
#[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 = try!(consume(b"F", tail));
let (extern_c, tail) = if let Ok(tail) = consume(b"Y", tail) {
(true, tail)
} else {
(false, tail)
};
let (bare, tail) = try!(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 = try!(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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(self.bare.demangle(ctx, stack));
try!(self.cv_qualifiers.demangle(ctx, stack));
Ok(())
}
}
#[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) = try!(one_or_more::<TypeHandle>(ctx, subs, input));
Ok((BareFunctionType(types), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for BareFunctionType
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
ctx.inner.push(self);
try!(self.ret().demangle(ctx, stack));
if let Some(inner) = ctx.inner.pop() {
try!(ctx.ensure_space());
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for BareFunctionType
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(self.args().demangle_as_inner(ctx, stack));
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 = try!(consume(b"D", input));
if let Ok(tail) = consume(b"t", tail) {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
return Ok((Decltype::IdExpression(expr), tail));
}
let tail = try!(consume(b"T", tail));
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
Ok((Decltype::Expression(expr), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Decltype
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
Decltype::Expression(ref expr) |
Decltype::IdExpression(ref expr) => {
try!(write!(ctx, "decltype ("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
}
}
}
#[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 = try!(consume(b"T", input));
if let Ok(tail) = consume(b"s", tail) {
let (name, tail) = try!(Name::parse(ctx, subs, tail));
return Ok((ClassEnumType::ElaboratedStruct(name), tail));
}
if let Ok(tail) = consume(b"u", tail) {
let (name, tail) = try!(Name::parse(ctx, subs, tail));
return Ok((ClassEnumType::ElaboratedUnion(name), tail));
}
let tail = try!(consume(b"e", tail));
let (name, tail) = try!(Name::parse(ctx, subs, tail));
Ok((ClassEnumType::ElaboratedEnum(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ClassEnumType
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
ClassEnumType::Named(ref name) => name.demangle(ctx, stack),
ClassEnumType::ElaboratedStruct(ref name) => {
try!(write!(ctx, "class "));
name.demangle(ctx, stack)
}
ClassEnumType::ElaboratedUnion(ref name) => {
try!(write!(ctx, "union "));
name.demangle(ctx, stack)
}
ClassEnumType::ElaboratedEnum(ref name) => {
try!(write!(ctx, "enum "));
name.demangle(ctx, stack)
}
}
}
}
#[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 = try!(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 = try!(consume(b"_", input));
Ok((UnnamedTypeName(number), input))
}
}
impl StartsWith for UnnamedTypeName {
#[inline]
fn starts_with(byte: u8) -> bool {
byte == b'U'
}
}
impl<'subs, W> Demangle<'subs, W> for UnnamedTypeName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(write!(ctx, "{{unnamed type {}}}", self.0.map_or(0, |n| n + 1)));
Ok(())
}
}
#[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 = try!(consume(b"A", input));
if let Ok((num, tail)) = parse_number(10, false, tail) {
debug_assert!(num >= 0);
let tail = try!(consume(b"_", tail));
let (ty, tail) = try!(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 = try!(consume(b"_", tail));
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
return Ok((ArrayType::DimensionExpression(expr, ty), tail));
}
let tail = try!(consume(b"_", tail));
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
Ok((ArrayType::NoDimension(ty), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ArrayType
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
ctx.inner.push(self);
match *self {
ArrayType::DimensionNumber(_, ref ty) |
ArrayType::DimensionExpression(_, ref ty) |
ArrayType::NoDimension(ref ty) => {
try!(ty.demangle(ctx, stack));
}
}
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for ArrayType
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
let mut inner_is_array = false;
while let Some(inner) = ctx.inner.pop() {
inner_is_array = inner.downcast_to_array_type().is_some();
if !inner_is_array {
try!(ctx.ensure_space());
try!(write!(ctx, "("));
}
try!(inner.demangle_as_inner(ctx, stack));
if !inner_is_array {
try!(write!(ctx, ")"));
}
}
if !inner_is_array {
try!(ctx.ensure_space());
}
match *self {
ArrayType::DimensionNumber(n, _) => {
try!(write!(ctx, "[{}]", n));
}
ArrayType::DimensionExpression(ref expr, _) => {
try!(write!(ctx, "["));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, "]"));
}
ArrayType::NoDimension(_) => {
try!(write!(ctx, "[]"));
}
}
Ok(())
}
fn downcast_to_array_type(&self) -> Option<&ArrayType> {
Some(self)
}
}
#[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 = try!(consume(b"M", input));
let (ty1, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let (ty2, tail) = try!(TypeHandle::parse(ctx, subs, tail));
Ok((PointerToMemberType(ty1, ty2), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for PointerToMemberType
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
ctx.inner.push(self);
try!(self.1.demangle(ctx, stack));
if let Some(inner) = ctx.inner.pop() {
try!(inner.demangle_as_inner(ctx, stack));
}
Ok(())
}
}
impl<'subs, W> DemangleAsInner<'subs, W> for PointerToMemberType
where W: 'subs + io::Write
{
fn demangle_as_inner<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
if ctx.last_byte_written != Some(b'(') {
try!(ctx.ensure_space());
}
try!(self.0.demangle(ctx, stack));
try!(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 = try!(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 = try!(consume(b"_", input));
Ok((TemplateParam(number), input))
}
}
impl<'subs, W> Demangle<'subs, W> for TemplateParam
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()>
{
log_demangle!(self, ctx, stack);
let arg = try!(self.resolve(ctx, stack));
arg.demangle(ctx, stack)
}
}
impl TemplateParam {
fn resolve<'subs, 'prev, 'ctx, W>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<&'subs TemplateArg>
where W: 'subs + io::Write
{
let e = match ctx.template_params_to_args.entry(self) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let arg = try!(stack.get_template_arg(self.0)
.map_err(|e| io::Error::new(io::ErrorKind::Other,
e.description())));
e.insert(arg)
}
};
Ok(*e)
}
}
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 _;
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) = try!(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 + io::Write
{
#[inline]
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
self.0.demangle(ctx, stack)
}
}
#[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 = try!(consume(b"f", input));
if tail.is_empty() {
return Err(error::Error::UnexpectedEnd);
}
let (scope, tail) = if let Ok(tail) = consume(b"L", tail) {
try!(parse_number(10, false, tail))
} else {
(0, tail)
};
let tail = try!(consume(b"p", tail));
let (qualifiers, tail) = try!(CvQualifiers::parse(ctx, subs, tail));
let (param, tail) = if let Ok((num, tail)) = parse_number(10, false, tail) {
(Some(num as _), tail)
} else {
(None, tail)
};
let tail = try!(consume(b"_", tail));
Ok((FunctionParam(scope as _, qualifiers, param), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for FunctionParam
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
let ty = try!(stack.get_function_arg(self.0)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.description())));
ty.demangle(ctx, stack)
}
}
#[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 = try!(consume(b"I", input));
let (args, tail) = try!(one_or_more::<TemplateArg>(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
Ok((TemplateArgs(args), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for TemplateArgs
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(write!(ctx, "<"));
let mut need_comma = false;
for arg in &self.0[..] {
if need_comma {
try!(write!(ctx, ", "));
}
try!(arg.demangle(ctx, stack));
need_comma = true;
}
if ctx.last_byte_written == Some(b'>') {
try!(write!(ctx, " "));
}
try!(write!(ctx, ">"));
Ok(())
}
}
impl<'subs> ArgScope<'subs, 'subs> for TemplateArgs {
fn get_template_arg(&'subs self, idx: usize) -> Result<&'subs TemplateArg> {
self.0.get(idx).ok_or(error::Error::BadTemplateArgReference)
}
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) = try!(Expression::parse(ctx, subs, tail));
let tail = try!(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 = try!(consume(b"J", input));
let (args, tail) = if tail.peek() == Some(b'E') {
(vec![], tail)
} else {
try!(zero_or_more::<TemplateArg>(ctx, subs, tail))
};
let tail = try!(consume(b"E", tail));
Ok((TemplateArg::ArgPack(args), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for TemplateArg
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
TemplateArg::Type(ref ty) => ty.demangle(ctx, stack),
TemplateArg::Expression(ref expr) => expr.demangle(ctx, stack),
TemplateArg::SimpleExpression(ref expr) => expr.demangle(ctx, stack),
TemplateArg::ArgPack(ref args) => {
let mut need_comma = false;
for arg in &args[..] {
if need_comma {
try!(write!(ctx, ", "));
}
try!(arg.demangle(ctx, stack));
need_comma = true;
}
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>, UnresolvedName),
DerefMember(Box<Expression>, UnresolvedName),
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) = try!(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) = try!(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) = try!(Expression::parse(ctx, subs, tail));
let (args, tail) = try!(zero_or_more::<Expression>(ctx, subs, tail));
let expr = Expression::Call(Box::new(func), args);
return Ok((expr, tail));
}
b"cv" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
if let Ok(tail) = consume(b"_", tail) {
let (exprs, tail) = try!(zero_or_more::<Expression>(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
let expr = Expression::ConversionMany(ty, exprs);
return Ok((expr, tail));
} else {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::ConversionOne(ty, Box::new(expr));
return Ok((expr, tail));
}
}
b"tl" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let (exprs, tail) = try!(zero_or_more::<Expression>(ctx, subs, tail));
let expr = Expression::ConversionBraced(ty, exprs);
let tail = try!(consume(b"E", tail));
return Ok((expr, tail));
}
b"il" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
let expr = Expression::BracedInitList(Box::new(expr));
return Ok((expr, tail));
}
b"dc" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::DynamicCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"sc" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::StaticCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"cc" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::ConstCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"rc" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::ReinterpretCast(ty, Box::new(expr));
return Ok((expr, tail));
}
b"ti" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let expr = Expression::TypeidType(ty);
return Ok((expr, tail));
}
b"te" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::TypeidExpr(Box::new(expr));
return Ok((expr, tail));
}
b"st" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let expr = Expression::SizeofType(ty);
return Ok((expr, tail));
}
b"sz" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::SizeofExpr(Box::new(expr));
return Ok((expr, tail));
}
b"at" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
let expr = Expression::AlignofType(ty);
return Ok((expr, tail));
}
b"az" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::AlignofExpr(Box::new(expr));
return Ok((expr, tail));
}
b"nx" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::Noexcept(Box::new(expr));
return Ok((expr, tail));
}
b"dt" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let (name, tail) = try!(UnresolvedName::parse(ctx, subs, tail));
let expr = Expression::Member(Box::new(expr), name);
return Ok((expr, tail));
}
b"pt" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let (name, tail) = try!(UnresolvedName::parse(ctx, subs, tail));
let expr = Expression::DerefMember(Box::new(expr), name);
return Ok((expr, tail));
}
b"ds" => {
let (first, tail) = try!(Expression::parse(ctx, subs, tail));
let (second, tail) = try!(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) = try!(FunctionParam::parse(ctx, subs, tail));
let expr = Expression::SizeofFunctionPack(param);
return Ok((expr, tail));
}
b"sP" => {
let (args, tail) = try!(zero_or_more::<TemplateArg>(ctx, subs, tail));
let expr = Expression::SizeofCapturedTemplatePack(args);
let tail = try!(consume(b"E", tail));
return Ok((expr, tail));
}
b"sp" => {
let (expr, tail) = try!(Expression::parse(ctx, subs, tail));
let expr = Expression::PackExpansion(Box::new(expr));
return Ok((expr, tail));
}
b"tw" => {
let (expr, tail) = try!(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" => {
return can_be_global(true, ctx, subs, 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 (opname, tail) = try!(OperatorName::parse(ctx, subs, input));
let (first, tail) = try!(Expression::parse(ctx, subs, tail));
return if let Ok((second, tail)) = Expression::parse(ctx, subs, tail) {
if let Ok((third, tail)) = Expression::parse(ctx, subs, tail) {
let expr = Expression::Ternary(opname,
Box::new(first),
Box::new(second),
Box::new(third));
Ok((expr, tail))
} else {
let expr = Expression::Binary(opname, Box::new(first), Box::new(second));
Ok((expr, tail))
}
} else {
let expr = Expression::Unary(opname, Box::new(first));
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) = try!(zero_or_more::<Expression>(ctx,
subs,
tail));
let tail = try!(consume(b"_", tail));
let (ty, tail) = try!(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) = try!(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) = try!(zero_or_more::<Expression>(ctx,
subs,
tail));
let tail = try!(consume(b"_", tail));
let (ty, tail) = try!(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) = try!(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) = try!(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) = try!(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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
Expression::Unary(ref op, ref expr) => {
try!(op.demangle(ctx, stack));
try!(write!(ctx, " "));
expr.demangle(ctx, stack)
}
Expression::Binary(ref op, ref lhs, ref rhs) => {
try!(write!(ctx, "("));
try!(lhs.demangle(ctx, stack));
try!(write!(ctx, ")"));
try!(op.demangle(ctx, stack));
try!(write!(ctx, "("));
try!(rhs.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::Ternary(OperatorName::Simple(SimpleOperatorName::Question),
ref condition,
ref consequent,
ref alternative) => {
try!(condition.demangle(ctx, stack));
try!(write!(ctx, " ? "));
try!(consequent.demangle(ctx, stack));
try!(write!(ctx, " : "));
alternative.demangle(ctx, stack)
}
Expression::Ternary(ref op, ref e1, ref e2, ref e3) => {
try!(op.demangle(ctx, stack));
try!(write!(ctx, "("));
try!(e1.demangle(ctx, stack));
try!(write!(ctx, ", "));
try!(e2.demangle(ctx, stack));
try!(write!(ctx, ", "));
try!(e3.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::PrefixInc(ref expr) => {
try!(write!(ctx, "++"));
expr.demangle(ctx, stack)
}
Expression::PrefixDec(ref expr) => {
try!(write!(ctx, "--"));
expr.demangle(ctx, stack)
}
Expression::Call(ref functor_expr, ref args) => {
try!(write!(ctx, "("));
try!(functor_expr.demangle(ctx, stack));
try!(write!(ctx, ")("));
let mut need_comma = false;
for arg in args {
if need_comma {
try!(write!(ctx, ", "));
}
try!(arg.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ")"));
Ok(())
}
Expression::ConversionOne(ref ty, ref expr) => {
try!(ty.demangle(ctx, stack));
try!(write!(ctx, "("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::ConversionMany(ref ty, ref exprs) => {
try!(ty.demangle(ctx, stack));
try!(write!(ctx, "("));
let mut need_comma = false;
for expr in exprs {
if need_comma {
try!(write!(ctx, ", "));
}
try!(expr.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ")"));
Ok(())
}
Expression::ConversionBraced(ref ty, ref exprs) => {
try!(ty.demangle(ctx, stack));
try!(write!(ctx, "{{"));
let mut need_comma = false;
for expr in exprs {
if need_comma {
try!(write!(ctx, ", "));
}
try!(expr.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, "}}"));
Ok(())
}
Expression::BracedInitList(ref expr) => {
try!(write!(ctx, "{{"));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, "}}"));
Ok(())
}
Expression::New(ref exprs, ref ty, ref init) => {
try!(write!(ctx, "new ("));
let mut need_comma = false;
for expr in exprs {
if need_comma {
try!(write!(ctx, ", "));
}
try!(expr.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ") "));
try!(ty.demangle(ctx, stack));
if let Some(ref init) = *init {
try!(init.demangle(ctx, stack));
}
Ok(())
}
Expression::GlobalNew(ref exprs, ref ty, ref init) => {
try!(write!(ctx, "::new ("));
let mut need_comma = false;
for expr in exprs {
if need_comma {
try!(write!(ctx, ", "));
}
try!(expr.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ") "));
try!(ty.demangle(ctx, stack));
if let Some(ref init) = *init {
try!(init.demangle(ctx, stack));
}
Ok(())
}
Expression::NewArray(ref exprs, ref ty, ref init) => {
try!(write!(ctx, "new[] ("));
let mut need_comma = false;
for expr in exprs {
if need_comma {
try!(write!(ctx, ", "));
}
try!(expr.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ") "));
try!(ty.demangle(ctx, stack));
if let Some(ref init) = *init {
try!(init.demangle(ctx, stack));
}
Ok(())
}
Expression::GlobalNewArray(ref exprs, ref ty, ref init) => {
try!(write!(ctx, "::new[] ("));
let mut need_comma = false;
for expr in exprs {
if need_comma {
try!(write!(ctx, ", "));
}
try!(expr.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ") "));
try!(ty.demangle(ctx, stack));
if let Some(ref init) = *init {
try!(init.demangle(ctx, stack));
}
Ok(())
}
Expression::Delete(ref expr) => {
try!(write!(ctx, "delete "));
expr.demangle(ctx, stack)
}
Expression::GlobalDelete(ref expr) => {
try!(write!(ctx, "::delete "));
expr.demangle(ctx, stack)
}
Expression::DeleteArray(ref expr) => {
try!(write!(ctx, "delete[] "));
expr.demangle(ctx, stack)
}
Expression::GlobalDeleteArray(ref expr) => {
try!(write!(ctx, "::delete[] "));
expr.demangle(ctx, stack)
}
Expression::DynamicCast(ref ty, ref expr) => {
try!(write!(ctx, "dynamic_cast<"));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ">("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::StaticCast(ref ty, ref expr) => {
try!(write!(ctx, "static_cast<"));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ">("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::ConstCast(ref ty, ref expr) => {
try!(write!(ctx, "const_cast<"));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ">("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::ReinterpretCast(ref ty, ref expr) => {
try!(write!(ctx, "reinterpret_cast<"));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ">("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::TypeidType(ref ty) => {
try!(write!(ctx, "typeid ("));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::TypeidExpr(ref expr) => {
try!(write!(ctx, "typeid ("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::SizeofType(ref ty) => {
try!(write!(ctx, "sizeof ("));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::SizeofExpr(ref expr) => {
try!(write!(ctx, "sizeof ("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::AlignofType(ref ty) => {
try!(write!(ctx, "alignof ("));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::AlignofExpr(ref expr) => {
try!(write!(ctx, "alignof ("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::Noexcept(ref expr) => {
try!(write!(ctx, "noexcept ("));
try!(expr.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::TemplateParam(ref param) => param.demangle(ctx, stack),
Expression::FunctionParam(ref param) => param.demangle(ctx, stack),
Expression::Member(ref expr, ref name) => {
try!(expr.demangle(ctx, stack));
try!(write!(ctx, "."));
name.demangle(ctx, stack)
}
Expression::DerefMember(ref expr, ref name) => {
try!(expr.demangle(ctx, stack));
try!(write!(ctx, "->"));
name.demangle(ctx, stack)
}
Expression::PointerToMember(ref e1, ref e2) => {
try!(e1.demangle(ctx, stack));
try!(write!(ctx, ".*"));
e2.demangle(ctx, stack)
}
Expression::SizeofTemplatePack(ref param) => {
try!(write!(ctx, "sizeof...("));
try!(param.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::SizeofFunctionPack(ref param) => {
try!(write!(ctx, "sizeof...("));
try!(param.demangle(ctx, stack));
try!(write!(ctx, ")"));
Ok(())
}
Expression::SizeofCapturedTemplatePack(ref args) => {
try!(write!(ctx, "sizeof...("));
let mut need_comma = false;
for arg in args {
if need_comma {
try!(write!(ctx, ", "));
}
try!(arg.demangle(ctx, stack));
need_comma = true;
}
try!(write!(ctx, ")"));
Ok(())
}
Expression::PackExpansion(ref pack) => {
try!(pack.demangle(ctx, stack));
try!(write!(ctx, "..."));
Ok(())
}
Expression::Throw(ref expr) => {
try!(write!(ctx, "throw "));
expr.demangle(ctx, stack)
}
Expression::Rethrow => {
try!(write!(ctx, "throw"));
Ok(())
}
Expression::UnresolvedName(ref name) => name.demangle(ctx, stack),
Expression::Primary(ref expr) => expr.demangle(ctx, stack),
}
}
}
#[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 = try!(consume(b"sr", tail));
let (levels, tail) = try!(one_or_more::<UnresolvedQualifierLevel>(ctx,
subs,
tail));
let tail = try!(consume(b"E", tail));
let (name, tail) = try!(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 = try!(consume(b"sr", input));
if tail.peek() == Some(b'N') {
let tail = consume(b"N", tail).unwrap();
let (ty, tail) = try!(UnresolvedTypeHandle::parse(ctx, subs, tail));
let (levels, tail) = try!(one_or_more::<UnresolvedQualifierLevel>(ctx,
subs,
tail));
let tail = try!(consume(b"E", tail));
let (name, tail) = try!(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) = try!(BaseUnresolvedName::parse(ctx, subs, tail));
return Ok((UnresolvedName::Nested1(ty, vec![], name), tail));
}
let (levels, tail) = try!(one_or_more::<UnresolvedQualifierLevel>(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
let (name, tail) = try!(BaseUnresolvedName::parse(ctx, subs, tail));
Ok((UnresolvedName::Nested2(levels, name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for UnresolvedName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
UnresolvedName::Name(ref name) => name.demangle(ctx, stack),
UnresolvedName::Global(ref name) => {
try!(write!(ctx, "::"));
name.demangle(ctx, stack)
}
UnresolvedName::Nested1(ref ty, ref levels, ref name) => {
try!(ty.demangle(ctx, stack));
for lvl in &levels[..] {
try!(write!(ctx, "::"));
try!(lvl.demangle(ctx, stack));
}
name.demangle(ctx, stack)
}
UnresolvedName::Nested2(ref levels, ref name) => {
for lvl in &levels[..] {
try!(write!(ctx, "::"));
try!(lvl.demangle(ctx, stack));
}
name.demangle(ctx, stack)
}
UnresolvedName::GlobalNested2(ref levels, ref name) => {
try!(write!(ctx, "::"));
for lvl in &levels[..] {
try!(write!(ctx, "::"));
try!(lvl.demangle(ctx, stack));
}
name.demangle(ctx, stack)
}
}
}
}
#[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) = try!(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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
UnresolvedType::Decltype(ref dt) => dt.demangle(ctx, stack),
UnresolvedType::Template(ref param, ref args) => {
if let Some(ref args) = *args {
let stack = stack.push(args);
try!(param.demangle(ctx, stack));
try!(args.demangle(ctx, stack));
} else {
try!(param.demangle(ctx, stack));
}
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) = try!(SimpleId::parse(ctx, subs, input));
Ok((UnresolvedQualifierLevel(id), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for UnresolvedQualifierLevel
where W: 'subs + io::Write
{
#[inline]
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
self.0.demangle(ctx, stack)
}
}
#[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) = try!(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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(self.0.demangle(ctx, stack));
if let Some(ref args) = self.1 {
try!(args.demangle(ctx, stack));
}
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) = try!(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 = try!(consume(b"dn", input));
let (name, tail) = try!(DestructorName::parse(ctx, subs, tail));
Ok((BaseUnresolvedName::Destructor(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for BaseUnresolvedName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
BaseUnresolvedName::Name(ref name) => name.demangle(ctx, stack),
BaseUnresolvedName::Destructor(ref dtor) => dtor.demangle(ctx, stack),
BaseUnresolvedName::Operator(ref op, ref args) => {
try!(op.demangle(ctx, stack));
if let Some(ref args) = *args {
try!(args.demangle(ctx, stack));
}
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) = try!(SimpleId::parse(ctx, subs, input));
Ok((DestructorName::Name(name), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for DestructorName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(write!(ctx, "~"));
match *self {
DestructorName::Unresolved(ref ty) => ty.demangle(ctx, stack),
DestructorName::Name(ref name) => name.demangle(ctx, stack),
}
}
}
#[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 = try!(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 = try!(consume(b"E", tail));
let expr = ExprPrimary::Literal(ty, start, end);
return Ok((expr, tail));
}
let (name, tail) = try!(MangledName::parse(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
let expr = ExprPrimary::External(name);
Ok((expr, tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ExprPrimary
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
ExprPrimary::External(ref name) => name.demangle(ctx, stack),
ExprPrimary::Literal(
TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Nullptr)),
_,
_) => {
try!(write!(ctx, "nullptr"));
Ok(())
}
ExprPrimary::Literal(ref type_handle, start, end) => {
debug_assert!(start <= end);
if start == end {
type_handle.demangle(ctx, stack)
} else {
try!(write!(ctx,
"{}",
String::from_utf8_lossy(&ctx.input[start..end])));
Ok(())
}
}
}
}
}
#[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 = try!(consume(b"pi", input));
let (exprs, tail) = try!(zero_or_more::<Expression>(ctx, subs, tail));
let tail = try!(consume(b"E", tail));
Ok((Initializer(exprs), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for Initializer
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(write!(ctx, "("));
let mut need_comma = false;
for expr in &self.0 {
if need_comma {
try!(write!(ctx, ", "));
}
try!(expr.demangle(ctx, stack));
need_comma = true;
}
try!(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 = try!(consume(b"Z", input));
let (encoding, tail) = try!(Encoding::parse(ctx, subs, tail));
let tail = try!(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 = try!(consume(b"_", tail));
let (name, tail) = try!(Name::parse(ctx, subs, tail));
return Ok((LocalName::Default(Box::new(encoding), param, Box::new(name)),
tail));
}
let (name, tail) = try!(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 + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
LocalName::Relative(ref encoding, Some(ref name), _) => {
try!(encoding.demangle(ctx, stack));
try!(write!(ctx, "::"));
name.demangle(ctx, stack)
}
LocalName::Relative(ref encoding, None, _) => {
try!(encoding.demangle(ctx, stack));
try!(write!(ctx, "::string literal"));
Ok(())
}
LocalName::Default(ref encoding, _, _) => encoding.demangle(ctx, stack),
}
}
}
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),
}
}
}
#[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 = try!(consume(b"_", input));
if let Ok(tail) = consume(b"_", tail) {
let (num, tail) = try!(parse_number(10, false, tail));
debug_assert!(num >= 0);
if num < 10 {
return Err(error::Error::UnexpectedText);
}
let tail = try!(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 = try!(consume(b"Ul", input));
let (sig, tail) = try!(LambdaSig::parse(ctx, subs, tail));
let tail = try!(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 = try!(consume(b"_", tail));
Ok((ClosureTypeName(sig, num), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for ClosureTypeName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
try!(write!(ctx, "{{lambda("));
try!(self.0.demangle(ctx, stack));
try!(write!(ctx, ")#{}}}", self.1.map_or(0, |n| n + 1)));
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LambdaSig(Vec<TypeHandle>);
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 {
try!(one_or_more::<TypeHandle>(ctx, subs, input))
};
Ok((LambdaSig(types), tail))
}
}
impl<'subs, W> Demangle<'subs, W> for LambdaSig
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
let mut need_comma = false;
for ty in &self.0 {
if need_comma {
try!(write!(ctx, ", "));
}
try!(ty.demangle(ctx, stack));
need_comma = true;
}
Ok(())
}
}
#[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) = try!(SourceName::parse(ctx, subs, input));
let tail = try!(consume(b"M", tail));
Ok((DataMemberPrefix(name), tail))
}
}
impl StartsWith for DataMemberPrefix {
fn starts_with(byte: u8) -> bool {
SourceName::starts_with(byte)
}
}
impl<'subs, W> Demangle<'subs, W> for DataMemberPrefix
where W: 'subs + io::Write
{
#[inline]
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
self.0.demangle(ctx, stack)
}
}
#[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 = try!(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 = try!(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> >")
}
}
#[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),
}
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) = try!(TypeHandle::parse(ctx, subs, tail));
Ok((SpecialName::VirtualTable(ty), tail))
}
b"TT" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
Ok((SpecialName::Vtt(ty), tail))
}
b"TI" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
Ok((SpecialName::Typeinfo(ty), tail))
}
b"TS" => {
let (ty, tail) = try!(TypeHandle::parse(ctx, subs, tail));
Ok((SpecialName::TypeinfoName(ty), tail))
}
b"Tc" => {
let (first, tail) = try!(CallOffset::parse(ctx, subs, tail));
let (second, tail) = try!(CallOffset::parse(ctx, subs, tail));
let (base, tail) = try!(Encoding::parse(ctx, subs, tail));
Ok((SpecialName::VirtualOverrideThunkCovariant(first,
second,
Box::new(base)),
tail))
}
b"GV" => {
let (name, tail) = try!(Name::parse(ctx, subs, tail));
Ok((SpecialName::Guard(name), tail))
}
b"GR" => {
let (name, tail) = try!(Name::parse(ctx, subs, tail));
let (idx, tail) = if let Ok(tail) = consume(b"_", tail) {
(0, tail)
} else {
let (idx, tail) = try!(SeqId::parse(ctx, subs, tail));
let tail = try!(consume(b"_", tail));
(idx.0 + 1, tail)
};
Ok((SpecialName::GuardTemporary(name, idx), tail))
}
_ => {
if let Ok(tail) = consume(b"T", input) {
let (offset, tail) = try!(CallOffset::parse(ctx, subs, tail));
let (base, tail) = try!(Encoding::parse(ctx, subs, tail));
Ok((SpecialName::VirtualOverrideThunk(offset, Box::new(base)), tail))
} else {
Err(error::Error::UnexpectedText)
}
}
}
}
}
impl<'subs, W> Demangle<'subs, W> for SpecialName
where W: 'subs + io::Write
{
fn demangle<'prev, 'ctx>(&'subs self,
ctx: &'ctx mut DemangleContext<'subs, W>,
stack: Option<ArgScopeStack<'prev, 'subs>>)
-> io::Result<()> {
log_demangle!(self, ctx, stack);
match *self {
SpecialName::VirtualTable(ref ty) => {
try!(write!(ctx, "{{vtable("));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ")}}"));
Ok(())
}
SpecialName::Vtt(ref ty) => {
try!(write!(ctx, "{{vtt("));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ")}}"));
Ok(())
}
SpecialName::Typeinfo(ref ty) => {
try!(write!(ctx, "typeinfo for "));
ty.demangle(ctx, stack)
}
SpecialName::TypeinfoName(ref ty) => {
try!(write!(ctx, "{{typeinfo name("));
try!(ty.demangle(ctx, stack));
try!(write!(ctx, ")}}"));
Ok(())
}
SpecialName::VirtualOverrideThunk(ref offset, ref encoding) => {
try!(write!(ctx, "{{virtual override thunk("));
try!(offset.demangle(ctx, stack));
try!(write!(ctx, ", "));
try!(encoding.demangle(ctx, stack));
try!(write!(ctx, ")}}"));
Ok(())
}
SpecialName::VirtualOverrideThunkCovariant(ref this_offset,
ref result_offset,
ref encoding) => {
try!(write!(ctx, "{{virtual override thunk("));
try!(this_offset.demangle(ctx, stack));
try!(write!(ctx, ", "));
try!(result_offset.demangle(ctx, stack));
try!(write!(ctx, ", "));
try!(encoding.demangle(ctx, stack));
try!(write!(ctx, ")}}"));
Ok(())
}
SpecialName::Guard(ref name) => {
try!(write!(ctx, "{{static initialization guard("));
try!(name.demangle(ctx, stack));
try!(write!(ctx, ")}}"));
Ok(())
}
SpecialName::GuardTemporary(ref name, n) => {
try!(write!(ctx, "{{static initialization guard temporary("));
try!(name.demangle(ctx, stack));
try!(write!(ctx, ", {})}}", n));
Ok(())
}
}
}
}
#[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) = try!(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 = try!(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, Identifier,
Initializer, LambdaSig, LocalName, MangledName, Name, NestedName, Number,
NvOffset, OperatorName, Parse, ParseContext, PointerToMemberType, Prefix, PrefixHandle,
RefQualifier, SeqId, SimpleId, SimpleOperatorName, SourceName,
SpecialName, StandardBuiltinType, Substitution, TemplateArg, TemplateArgs,
TemplateParam, TemplateTemplateParam, TemplateTemplateParamHandle, Type,
TypeHandle, UnnamedTypeName, UnqualifiedName, UnresolvedName,
UnresolvedQualifierLevel, UnresolvedType, UnresolvedTypeHandle,
UnscopedName, UnscopedTemplateName, UnscopedTemplateNameHandle, VOffset,
WellKnownComponent};
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\nand 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,
})))))),
b"..."
}
}
Err => {
b"_Y" => Error::UnexpectedText,
b"_Z" => Error::UnexpectedText,
b"_" => Error::UnexpectedEnd,
b"" => 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_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_E..." => {
Name::Nested(NestedName(CvQualifiers::default(),
None,
PrefixHandle::BackReference(1))),
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(
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(RefQualifier::RValueRef),
PrefixHandle::BackReference(1)),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 6,
end: 9,
}))))
]
}
b"NOS_3abcE..." => {
NestedName(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
Some(RefQualifier::RValueRef),
PrefixHandle::BackReference(1)),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 5,
end: 8,
}))))
]
}
b"NS_3abcE..." => {
NestedName(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
None,
PrefixHandle::BackReference(1)),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 4,
end: 7,
}))))
]
}
b"NKOS_3abcIJEEE..." => {
NestedName(
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(RefQualifier::RValueRef),
PrefixHandle::BackReference(2)),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 6,
end: 9,
})))),
Substitutable::Prefix(
Prefix::Template(
PrefixHandle::BackReference(1),
TemplateArgs(vec![TemplateArg::ArgPack(vec![])]))),
]
}
b"NOS_3abcIJEEE..." => {
NestedName(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
Some(RefQualifier::RValueRef),
PrefixHandle::BackReference(2)),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 5,
end: 8,
})))),
Substitutable::Prefix(
Prefix::Template(
PrefixHandle::BackReference(1),
TemplateArgs(vec![TemplateArg::ArgPack(vec![])]))),
]
}
b"NS_3abcIJEEE..." => {
NestedName(
CvQualifiers {
restrict: false,
volatile: false,
const_: false,
},
None,
PrefixHandle::BackReference(2)),
b"...",
[
Substitutable::Prefix(
Prefix::Nested(
PrefixHandle::BackReference(0),
UnqualifiedName::Source(
SourceName(Identifier {
start: 4,
end: 7,
})))),
Substitutable::Prefix(
Prefix::Template(
PrefixHandle::BackReference(1),
TemplateArgs(vec![TemplateArg::ArgPack(vec![])]))),
]
}
}
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::UnexpectedText,
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::BackReference(2),
b"E...",
[
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,
})))),
]
}
}
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_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"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_1E..." => {
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(), None)),
b"...",
[]
}
b"dtT_3abc..." => {
Expression::Member(
Box::new(Expression::TemplateParam(TemplateParam(0))),
UnresolvedName::Name(
BaseUnresolvedName::Name(
SimpleId(
SourceName(
Identifier {
start: 5,
end: 8,
}),
None)))),
b"...",
[]
}
b"ptT_3abc..." => {
Expression::DerefMember(
Box::new(Expression::TemplateParam(TemplateParam(0))),
UnresolvedName::Name(
BaseUnresolvedName::Name(
SimpleId(
SourceName(
Identifier {
start: 5,
end: 8,
}),
None)))),
b"...",
[]
}
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(), None)),
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,
})))))))),
b"...",
[]
}
}
Err => {
}
}
});
}
#[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,
}))))))),
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"..."
}
}
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,
}
});
}
#[test]
fn parse_function_param() {
assert_parse!(FunctionParam {
Ok => {
b"fpK_..." => {
FunctionParam(0,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
None),
b"..."
}
b"fL1pK_..." => {
FunctionParam(1,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
None),
b"..."
}
b"fpK3_..." => {
FunctionParam(0,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(3)),
b"..."
}
b"fL1pK4_..." => {
FunctionParam(1,
CvQualifiers {
restrict: false,
volatile: false,
const_: true,
},
Some(4)),
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),
b".."
}
b"10abcdefghij..." => {
UnqualifiedName::Source(SourceName(Identifier {
start: 2,
end: 12,
})),
b"..."
}
b"Ut5_..." => {
UnqualifiedName::UnnamedType(UnnamedTypeName(Some(5))),
b"..."
}
}
Err => {
b"zzz" => 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"
}
}
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,
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::Cast(
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,
}
});
}
}