]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/deriving/ty.rs
a9fdafc80141662efbd17aa4f3465208bc3d6868
[rust.git] / src / libsyntax / ext / deriving / ty.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12 A mini version of ast::Ty, which is easier to use, and features an
13 explicit `Self` type to use when specifying impls to be derived.
14 */
15
16 use ast;
17 use ast::{Expr,Generics,Ident};
18 use ext::base::ExtCtxt;
19 use ext::build::AstBuilder;
20 use codemap::{Span,respan};
21 use opt_vec;
22
23 /// The types of pointers
24 pub enum PtrTy<'self> {
25     Send, // ~
26     Managed(ast::Mutability), // @[mut]
27     Borrowed(Option<&'self str>, ast::Mutability), // &['lifetime] [mut]
28 }
29
30 /// A path, e.g. `::std::option::Option::<int>` (global). Has support
31 /// for type parameters and a lifetime.
32 pub struct Path<'self> {
33     path: ~[&'self str],
34     lifetime: Option<&'self str>,
35     params: ~[~Ty<'self>],
36     global: bool
37 }
38
39 impl<'self> Path<'self> {
40     pub fn new<'r>(path: ~[&'r str]) -> Path<'r> {
41         Path::new_(path, None, ~[], true)
42     }
43     pub fn new_local<'r>(path: &'r str) -> Path<'r> {
44         Path::new_(~[ path ], None, ~[], false)
45     }
46     pub fn new_<'r>(path: ~[&'r str],
47                     lifetime: Option<&'r str>,
48                     params: ~[~Ty<'r>],
49                     global: bool)
50                     -> Path<'r> {
51         Path {
52             path: path,
53             lifetime: lifetime,
54             params: params,
55             global: global
56         }
57     }
58
59     pub fn to_ty(&self,
60                  cx: @ExtCtxt,
61                  span: Span,
62                  self_ty: Ident,
63                  self_generics: &Generics)
64                  -> ast::Ty {
65         cx.ty_path(self.to_path(cx, span, self_ty, self_generics), None)
66     }
67     pub fn to_path(&self,
68                    cx: @ExtCtxt,
69                    span: Span,
70                    self_ty: Ident,
71                    self_generics: &Generics)
72                    -> ast::Path {
73         let idents = self.path.map(|s| cx.ident_of(*s) );
74         let lt = mk_lifetime(cx, span, &self.lifetime);
75         let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics));
76
77         cx.path_all(span, self.global, idents, lt, tys)
78     }
79 }
80
81 /// A type. Supports pointers (except for *), Self, and literals
82 pub enum Ty<'self> {
83     Self,
84     // &/~/@ Ty
85     Ptr(~Ty<'self>, PtrTy<'self>),
86     // mod::mod::Type<[lifetime], [Params...]>, including a plain type
87     // parameter, and things like `int`
88     Literal(Path<'self>),
89     // includes nil
90     Tuple(~[Ty<'self>])
91 }
92
93 pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
94     Borrowed(None, ast::MutImmutable)
95 }
96 pub fn borrowed<'r>(ty: ~Ty<'r>) -> Ty<'r> {
97     Ptr(ty, borrowed_ptrty())
98 }
99
100 pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
101     Some(Some(borrowed_ptrty()))
102 }
103
104 pub fn borrowed_self<'r>() -> Ty<'r> {
105     borrowed(~Self)
106 }
107
108 pub fn nil_ty() -> Ty<'static> {
109     Tuple(~[])
110 }
111
112 fn mk_lifetime(cx: @ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
113     match *lt {
114         Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s))),
115         None => None
116     }
117 }
118
119 impl<'self> Ty<'self> {
120     pub fn to_ty(&self,
121                  cx: @ExtCtxt,
122                  span: Span,
123                  self_ty: Ident,
124                  self_generics: &Generics)
125                  -> ast::Ty {
126         match *self {
127             Ptr(ref ty, ref ptr) => {
128                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
129                 match *ptr {
130                     Send => {
131                         cx.ty_uniq(span, raw_ty)
132                     }
133                     Managed(mutbl) => {
134                         cx.ty_box(span, raw_ty, mutbl)
135                     }
136                     Borrowed(ref lt, mutbl) => {
137                         let lt = mk_lifetime(cx, span, lt);
138                         cx.ty_rptr(span, raw_ty, lt, mutbl)
139                     }
140                 }
141             }
142             Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
143             Self  => {
144                 cx.ty_path(self.to_path(cx, span, self_ty, self_generics), None)
145             }
146             Tuple(ref fields) => {
147                 let ty = if fields.is_empty() {
148                     ast::ty_nil
149                 } else {
150                     ast::ty_tup(fields.map(|f| f.to_ty(cx, span, self_ty, self_generics)))
151                 };
152
153                 cx.ty(span, ty)
154             }
155         }
156     }
157
158     pub fn to_path(&self,
159                    cx: @ExtCtxt,
160                    span: Span,
161                    self_ty: Ident,
162                    self_generics: &Generics)
163                    -> ast::Path {
164         match *self {
165             Self => {
166                 let self_params = do self_generics.ty_params.map |ty_param| {
167                     cx.ty_ident(span, ty_param.ident)
168                 };
169                 let lifetime = if self_generics.lifetimes.is_empty() {
170                     None
171                 } else {
172                     Some(*self_generics.lifetimes.get(0))
173                 };
174
175                 cx.path_all(span, false, ~[self_ty], lifetime,
176                             opt_vec::take_vec(self_params))
177             }
178             Literal(ref p) => {
179                 p.to_path(cx, span, self_ty, self_generics)
180             }
181             Ptr(*) => { cx.span_bug(span, "Pointer in a path in generic `deriving`") }
182             Tuple(*) => { cx.span_bug(span, "Tuple in a path in generic `deriving`") }
183         }
184     }
185 }
186
187
188 fn mk_ty_param(cx: @ExtCtxt, span: Span, name: &str, bounds: &[Path],
189                self_ident: Ident, self_generics: &Generics) -> ast::TyParam {
190     let bounds = opt_vec::from(
191         do bounds.map |b| {
192             let path = b.to_path(cx, span, self_ident, self_generics);
193             cx.typarambound(path)
194         });
195     cx.typaram(cx.ident_of(name), bounds)
196 }
197
198 fn mk_generics(lifetimes: ~[ast::Lifetime],  ty_params: ~[ast::TyParam]) -> Generics {
199     Generics {
200         lifetimes: opt_vec::from(lifetimes),
201         ty_params: opt_vec::from(ty_params)
202     }
203 }
204
205 /// Lifetimes and bounds on type parameters
206 pub struct LifetimeBounds<'self> {
207     lifetimes: ~[&'self str],
208     bounds: ~[(&'self str, ~[Path<'self>])]
209 }
210
211 impl<'self> LifetimeBounds<'self> {
212     pub fn empty() -> LifetimeBounds<'static> {
213         LifetimeBounds {
214             lifetimes: ~[], bounds: ~[]
215         }
216     }
217     pub fn to_generics(&self,
218                        cx: @ExtCtxt,
219                        span: Span,
220                        self_ty: Ident,
221                        self_generics: &Generics)
222                        -> Generics {
223         let lifetimes = do self.lifetimes.map |lt| {
224             cx.lifetime(span, cx.ident_of(*lt))
225         };
226         let ty_params = do self.bounds.map |t| {
227             match t {
228                 &(ref name, ref bounds) => {
229                     mk_ty_param(cx, span, *name, *bounds, self_ty, self_generics)
230                 }
231             }
232         };
233         mk_generics(lifetimes, ty_params)
234     }
235 }
236
237
238 pub fn get_explicit_self(cx: @ExtCtxt, span: Span, self_ptr: &Option<PtrTy>)
239     -> (@Expr, ast::explicit_self) {
240     let self_path = cx.expr_self(span);
241     match *self_ptr {
242         None => {
243             (self_path, respan(span, ast::sty_value(ast::MutImmutable)))
244         }
245         Some(ref ptr) => {
246             let self_ty = respan(
247                 span,
248                 match *ptr {
249                     Send => ast::sty_uniq,
250                     Managed(mutbl) => ast::sty_box(mutbl),
251                     Borrowed(ref lt, mutbl) => {
252                         let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s)));
253                         ast::sty_region(lt, mutbl)
254                     }
255                 });
256             let self_expr = cx.expr_deref(span, self_path);
257             (self_expr, self_ty)
258         }
259     }
260 }