1 //! Types dealing with the substitutions table.
2 
3 use super::DemangleWrite;
4 use ast;
5 use std::fmt;
6 use std::iter::FromIterator;
7 use std::ops::Deref;
8 use vec::Vec;
9 
10 /// An enumeration of all of the types that can end up in the substitution
11 /// table.
12 #[doc(hidden)]
13 #[derive(Clone, Debug, PartialEq, Eq)]
14 #[allow(clippy::large_enum_variant)]
15 pub enum Substitutable {
16     /// An `<unscoped-template-name>` production.
17     UnscopedTemplateName(ast::UnscopedTemplateName),
18 
19     /// A `<type>` production.
20     Type(ast::Type),
21 
22     /// A `<template-template-param>` production.
23     TemplateTemplateParam(ast::TemplateTemplateParam),
24 
25     /// An `<unresolved-type>` production.
26     UnresolvedType(ast::UnresolvedType),
27 
28     /// A `<prefix>` production.
29     Prefix(ast::Prefix),
30 }
31 
32 impl<'subs, W> ast::Demangle<'subs, W> for Substitutable
33 where
34     W: 'subs + DemangleWrite,
35 {
demangle<'prev, 'ctx>( &'subs self, ctx: &'ctx mut ast::DemangleContext<'subs, W>, scope: Option<ast::ArgScopeStack<'prev, 'subs>>, ) -> fmt::Result36     fn demangle<'prev, 'ctx>(
37         &'subs self,
38         ctx: &'ctx mut ast::DemangleContext<'subs, W>,
39         scope: Option<ast::ArgScopeStack<'prev, 'subs>>,
40     ) -> fmt::Result {
41         match *self {
42             Substitutable::UnscopedTemplateName(ref name) => name.demangle(ctx, scope),
43             Substitutable::Type(ref ty) => ty.demangle(ctx, scope),
44             Substitutable::TemplateTemplateParam(ref ttp) => ttp.demangle(ctx, scope),
45             Substitutable::UnresolvedType(ref ty) => ty.demangle(ctx, scope),
46             Substitutable::Prefix(ref prefix) => prefix.demangle(ctx, scope),
47         }
48     }
49 }
50 
51 impl<'a> ast::GetLeafName<'a> for Substitutable {
get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<ast::LeafName<'a>>52     fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<ast::LeafName<'a>> {
53         match *self {
54             Substitutable::UnscopedTemplateName(ref name) => name.get_leaf_name(subs),
55             Substitutable::Prefix(ref prefix) => prefix.get_leaf_name(subs),
56             Substitutable::Type(ref ty) => ty.get_leaf_name(subs),
57             _ => None,
58         }
59     }
60 }
61 
62 impl ast::IsCtorDtorConversion for Substitutable {
is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool63     fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool {
64         match *self {
65             Substitutable::Prefix(ref prefix) => prefix.is_ctor_dtor_conversion(subs),
66             _ => false,
67         }
68     }
69 }
70 
71 /// The table of substitutable components that we have parsed thus far, and for
72 /// which there are potential back-references.
73 #[doc(hidden)]
74 #[derive(Clone, Default, PartialEq, Eq)]
75 pub struct SubstitutionTable {
76     substitutions: Vec<Substitutable>,
77     // There are components which are typically candidates for substitution, but
78     // in some particular circumstances are not. Instances of such components
79     // which are not candidates for substitution end up in this part of the
80     // table. See `<prefix>` parsing for further details.
81     non_substitutions: Vec<Substitutable>,
82 }
83 
84 impl fmt::Debug for SubstitutionTable {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result85     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86         f.pad("SubstitutionTable ")?;
87         f.debug_map()
88             .entries(self.substitutions.iter().enumerate())
89             .finish()?;
90         f.pad("non_substitutions ")?;
91         f.debug_map()
92             .entries(self.non_substitutions.iter().enumerate())
93             .finish()
94     }
95 }
96 
97 impl SubstitutionTable {
98     /// Construct a new `SubstitutionTable`.
new() -> SubstitutionTable99     pub fn new() -> SubstitutionTable {
100         Default::default()
101     }
102 
103     /// Insert a freshly-parsed substitutable component into the table and
104     /// return the index at which it now lives.
insert(&mut self, entity: Substitutable) -> usize105     pub fn insert(&mut self, entity: Substitutable) -> usize {
106         let idx = self.substitutions.len();
107         log!("SubstitutionTable::insert @ {}: {:?}", idx, entity);
108         self.substitutions.push(entity);
109         idx
110     }
111 
112     /// Insert a an entity into the table that is not a candidate for
113     /// substitution.
insert_non_substitution(&mut self, entity: Substitutable) -> usize114     pub fn insert_non_substitution(&mut self, entity: Substitutable) -> usize {
115         let idx = self.non_substitutions.len();
116         self.non_substitutions.push(entity);
117         idx
118     }
119 
120     /// Does this substitution table contain a component at the given index?
contains(&self, idx: usize) -> bool121     pub fn contains(&self, idx: usize) -> bool {
122         idx < self.substitutions.len()
123     }
124 
125     /// Get the type referenced by the given handle, or None if there is no such
126     /// entry, or there is an entry that is not a type.
get_type(&self, handle: &ast::TypeHandle) -> Option<&ast::Type>127     pub fn get_type(&self, handle: &ast::TypeHandle) -> Option<&ast::Type> {
128         if let ast::TypeHandle::BackReference(idx) = *handle {
129             self.substitutions.get(idx).and_then(|s| match *s {
130                 Substitutable::Type(ref ty) => Some(ty),
131                 _ => None,
132             })
133         } else {
134             None
135         }
136     }
137 
138     /// Remove the last entry from the substitutions table and return it, or
139     /// `None` if the table is empty.
pop(&mut self) -> Option<Substitutable>140     pub fn pop(&mut self) -> Option<Substitutable> {
141         log!("SubstitutionTable::pop @ {}: {:?}", self.len(), self.last());
142         self.substitutions.pop()
143     }
144 
145     /// Get the `idx`th entity that is not a candidate for substitution. Panics
146     /// if `idx` is out of bounds.
non_substitution(&self, idx: usize) -> &Substitutable147     pub fn non_substitution(&self, idx: usize) -> &Substitutable {
148         &self.non_substitutions[idx]
149     }
150 
151     /// Get the `idx`th entity that is not a candidate for substitution. Returns
152     /// `None` if `idx` is out of bounds.
get_non_substitution(&self, idx: usize) -> Option<&Substitutable>153     pub fn get_non_substitution(&self, idx: usize) -> Option<&Substitutable> {
154         self.non_substitutions.get(idx)
155     }
156 }
157 
158 impl FromIterator<Substitutable> for SubstitutionTable {
from_iter<I: IntoIterator<Item = Substitutable>>(iter: I) -> Self159     fn from_iter<I: IntoIterator<Item = Substitutable>>(iter: I) -> Self {
160         SubstitutionTable {
161             substitutions: Vec::from_iter(iter),
162             non_substitutions: vec![],
163         }
164     }
165 }
166 
167 impl Deref for SubstitutionTable {
168     type Target = [Substitutable];
169 
deref(&self) -> &Self::Target170     fn deref(&self) -> &Self::Target {
171         &self.substitutions[..]
172     }
173 }
174