]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/pipes/ast_builder.rs
a8bcb9dbfc4cd2e1f6c56845308b7a5a719ef54d
[rust.git] / src / libsyntax / ext / pipes / ast_builder.rs
1 // Copyright 2012 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 // Functions for building ASTs, without having to fuss with spans.
12 //
13 // To start with, it will be use dummy spans, but it might someday do
14 // something smarter.
15
16 use core::prelude::*;
17
18 use ast::{ident, node_id};
19 use ast;
20 use ast_util::{ident_to_path};
21 use ast_util;
22 use attr;
23 use codemap::{span, respan, dummy_sp};
24 use codemap;
25 use ext::base::{ext_ctxt, mk_ctxt};
26 use ext::quote::rt::*;
27
28 use core::vec;
29
30 // Transitional reexports so qquote can find the paths it is looking for
31 mod syntax {
32     pub use ext;
33     pub use parse;
34 }
35
36 pub fn path(ids: ~[ident], span: span) -> @ast::path {
37     @ast::path { span: span,
38                  global: false,
39                  idents: ids,
40                  rp: None,
41                  types: ~[] }
42 }
43
44 pub fn path_global(ids: ~[ident], span: span) -> @ast::path {
45     @ast::path { span: span,
46                  global: true,
47                  idents: ids,
48                  rp: None,
49                  types: ~[] }
50 }
51
52 pub trait append_types {
53     fn add_ty(ty: @ast::Ty) -> @ast::path;
54     fn add_tys(+tys: ~[@ast::Ty]) -> @ast::path;
55 }
56
57 pub impl append_types for @ast::path {
58     fn add_ty(ty: @ast::Ty) -> @ast::path {
59         @ast::path { types: vec::append_one(self.types, ty),
60                      .. *self}
61     }
62
63     fn add_tys(+tys: ~[@ast::Ty]) -> @ast::path {
64         @ast::path { types: vec::append(self.types, tys),
65                      .. *self}
66     }
67 }
68
69 pub trait ext_ctxt_ast_builder {
70     fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound])
71         -> ast::ty_param;
72     fn arg(name: ident, ty: @ast::Ty) -> ast::arg;
73     fn expr_block(e: @ast::expr) -> ast::blk;
74     fn fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl;
75     fn item(name: ident, span: span, +node: ast::item_) -> @ast::item;
76     fn item_fn_poly(name: ident,
77                     +inputs: ~[ast::arg],
78                     output: @ast::Ty,
79                     +ty_params: ~[ast::ty_param],
80                     +body: ast::blk) -> @ast::item;
81     fn item_fn(name: ident,
82                +inputs: ~[ast::arg],
83                output: @ast::Ty,
84                +body: ast::blk) -> @ast::item;
85     fn item_enum_poly(name: ident,
86                       span: span,
87                       +enum_definition: ast::enum_def,
88                       +ty_params: ~[ast::ty_param]) -> @ast::item;
89     fn item_enum(name: ident, span: span,
90                  +enum_definition: ast::enum_def) -> @ast::item;
91     fn item_struct_poly(name: ident, span: span,
92                         struct_def: ast::struct_def,
93                         ty_params: ~[ast::ty_param]) -> @ast::item;
94     fn item_struct(name: ident, span: span,
95                    struct_def: ast::struct_def) -> @ast::item;
96     fn struct_expr(path: @ast::path, fields: ~[ast::field]) -> @ast::expr;
97     fn variant(name: ident, span: span, +tys: ~[@ast::Ty]) -> ast::variant;
98     fn item_mod(name: ident, span: span, +items: ~[@ast::item]) -> @ast::item;
99     fn ty_path_ast_builder(path: @ast::path) -> @ast::Ty;
100     fn item_ty_poly(name: ident,
101                     span: span,
102                     ty: @ast::Ty,
103                     +params: ~[ast::ty_param]) -> @ast::item;
104     fn item_ty(name: ident, span: span, ty: @ast::Ty) -> @ast::item;
105     fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::Ty];
106     fn ty_vars_global(+ty_params: ~[ast::ty_param]) -> ~[@ast::Ty];
107     fn ty_field_imm(name: ident, ty: @ast::Ty) -> ast::ty_field;
108     fn field_imm(name: ident, e: @ast::expr) -> ast::field;
109     fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk;
110     fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt;
111     fn stmt_expr(e: @ast::expr) -> @ast::stmt;
112     fn block_expr(b: ast::blk) -> @ast::expr;
113     fn ty_option(ty: @ast::Ty) -> @ast::Ty;
114     fn ty_infer() -> @ast::Ty;
115     fn ty_nil_ast_builder() -> @ast::Ty;
116     fn strip_bounds(bounds: &[ast::ty_param]) -> ~[ast::ty_param];
117 }
118
119 pub impl ext_ctxt_ast_builder for ext_ctxt {
120     fn ty_option(ty: @ast::Ty) -> @ast::Ty {
121         self.ty_path_ast_builder(path_global(~[
122             self.ident_of(~"core"),
123             self.ident_of(~"option"),
124             self.ident_of(~"Option")
125         ], dummy_sp()).add_ty(ty))
126     }
127
128     fn block_expr(b: ast::blk) -> @ast::expr {
129         @expr {
130             id: self.next_id(),
131             callee_id: self.next_id(),
132             node: ast::expr_block(b),
133             span: dummy_sp(),
134         }
135     }
136
137     fn stmt_expr(e: @ast::expr) -> @ast::stmt {
138         @spanned { node: ast::stmt_expr(e, self.next_id()),
139                    span: dummy_sp()}
140     }
141
142     fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt {
143         let ext_cx = self;
144         quote_stmt!( let $ident = $e; )
145     }
146
147     fn field_imm(name: ident, e: @ast::expr) -> ast::field {
148         spanned {
149             node: ast::field_ { mutbl: ast::m_imm, ident: name, expr: e },
150             span: dummy_sp(),
151         }
152     }
153
154     fn ty_field_imm(name: ident, ty: @ast::Ty) -> ast::ty_field {
155         spanned {
156             node: ast::ty_field_ {
157                 ident: name,
158                 mt: ast::mt { ty: ty, mutbl: ast::m_imm },
159             },
160             span: dummy_sp(),
161         }
162     }
163
164     fn ty_infer() -> @ast::Ty {
165         @ast::Ty {
166             id: self.next_id(),
167             node: ast::ty_infer,
168             span: dummy_sp(),
169         }
170     }
171
172     fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound])
173         -> ast::ty_param
174     {
175         ast::ty_param { ident: id, id: self.next_id(), bounds: @bounds }
176     }
177
178     fn arg(name: ident, ty: @ast::Ty) -> ast::arg {
179         ast::arg {
180             mode: ast::infer(self.next_id()),
181             is_mutbl: false,
182             ty: ty,
183             pat: @ast::pat {
184                 id: self.next_id(),
185                 node: ast::pat_ident(
186                     ast::bind_by_copy,
187                     ast_util::ident_to_path(dummy_sp(), name),
188                     None),
189                 span: dummy_sp(),
190             },
191             id: self.next_id(),
192         }
193     }
194
195     fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk {
196         let blk = ast::blk_ {
197             view_items: ~[],
198             stmts: stmts,
199             expr: Some(e),
200             id: self.next_id(),
201             rules: ast::default_blk,
202         };
203
204         spanned { node: blk, span: dummy_sp() }
205     }
206
207     fn expr_block(e: @ast::expr) -> ast::blk {
208         self.block(~[], e)
209     }
210
211     fn fn_decl(+inputs: ~[ast::arg],
212                output: @ast::Ty) -> ast::fn_decl {
213         ast::fn_decl {
214             inputs: inputs,
215             output: output,
216             cf: ast::return_val,
217         }
218     }
219
220     fn item(name: ident,
221             span: span,
222             +node: ast::item_) -> @ast::item {
223
224         // XXX: Would be nice if our generated code didn't violate
225         // Rust coding conventions
226         let non_camel_case_attribute = respan(dummy_sp(), ast::attribute_ {
227             style: ast::attr_outer,
228             value: respan(dummy_sp(),
229                           ast::meta_list(~"allow", ~[
230                               @respan(dummy_sp(),
231                                       ast::meta_word(~"non_camel_case_types"))
232                           ])),
233             is_sugared_doc: false
234         });
235
236         @ast::item { ident: name,
237                      attrs: ~[non_camel_case_attribute],
238                      id: self.next_id(),
239                      node: node,
240                      vis: ast::public,
241                      span: span }
242     }
243
244     fn item_fn_poly(name: ident,
245                     +inputs: ~[ast::arg],
246                     output: @ast::Ty,
247                     +ty_params: ~[ast::ty_param],
248                     +body: ast::blk) -> @ast::item {
249         self.item(name,
250                   dummy_sp(),
251                   ast::item_fn(self.fn_decl(inputs, output),
252                                ast::impure_fn,
253                                ty_params,
254                                body))
255     }
256
257     fn item_fn(name: ident,
258                +inputs: ~[ast::arg],
259                output: @ast::Ty,
260                +body: ast::blk) -> @ast::item {
261         self.item_fn_poly(name, inputs, output, ~[], body)
262     }
263
264     fn item_enum_poly(name: ident,
265                       span: span,
266                       +enum_definition: ast::enum_def,
267                       +ty_params: ~[ast::ty_param]) -> @ast::item {
268         self.item(name, span, ast::item_enum(enum_definition, ty_params))
269     }
270
271     fn item_enum(name: ident, span: span,
272                  +enum_definition: ast::enum_def) -> @ast::item {
273         self.item_enum_poly(name, span, enum_definition, ~[])
274     }
275
276     fn item_struct(name: ident, span: span,
277                    struct_def: ast::struct_def) -> @ast::item {
278         self.item_struct_poly(name, span, struct_def, ~[])
279     }
280
281     fn item_struct_poly(name: ident, span: span,
282                         struct_def: ast::struct_def,
283                         ty_params: ~[ast::ty_param]) -> @ast::item {
284         self.item(name, span, ast::item_struct(@struct_def, ty_params))
285     }
286
287     fn struct_expr(path: @ast::path, fields: ~[ast::field]) -> @ast::expr {
288         @ast::expr {
289             id: self.next_id(),
290             callee_id: self.next_id(),
291             node: ast::expr_struct(path, fields, None),
292             span: dummy_sp()
293         }
294     }
295
296     fn variant(name: ident,
297                span: span,
298                +tys: ~[@ast::Ty]) -> ast::variant {
299         let args = do tys.map |ty| {
300             ast::variant_arg { ty: *ty, id: self.next_id() }
301         };
302
303         spanned {
304             node: ast::variant_ {
305                 name: name,
306                 attrs: ~[],
307                 kind: ast::tuple_variant_kind(args),
308                 id: self.next_id(),
309                 disr_expr: None,
310                 vis: ast::public
311             },
312             span: span,
313         }
314     }
315
316     fn item_mod(name: ident,
317                 span: span,
318                 +items: ~[@ast::item]) -> @ast::item {
319         // XXX: Total hack: import `core::kinds::Owned` to work around a
320         // parser bug whereby `fn f<T: ::kinds::Owned>` doesn't parse.
321         let vi = ast::view_item_import(~[
322             @codemap::spanned {
323                 node: ast::view_path_simple(
324                     self.ident_of(~"Owned"),
325                     path(
326                         ~[
327                             self.ident_of(~"core"),
328                             self.ident_of(~"kinds"),
329                             self.ident_of(~"Owned")
330                         ],
331                         codemap::dummy_sp()
332                     ),
333                     ast::type_value_ns,
334                     self.next_id()
335                 ),
336                 span: codemap::dummy_sp()
337             }
338         ]);
339         let vi = @ast::view_item {
340             node: vi,
341             attrs: ~[],
342             vis: ast::private,
343             span: codemap::dummy_sp()
344         };
345
346         self.item(
347             name,
348             span,
349             ast::item_mod(ast::_mod {
350                 view_items: ~[vi],
351                 items: items,
352             })
353         )
354     }
355
356     fn ty_path_ast_builder(path: @ast::path) -> @ast::Ty {
357         @ast::Ty {
358             id: self.next_id(),
359             node: ast::ty_path(path, self.next_id()),
360             span: path.span,
361         }
362     }
363
364     fn ty_nil_ast_builder() -> @ast::Ty {
365         @ast::Ty {
366             id: self.next_id(),
367             node: ast::ty_nil,
368             span: dummy_sp(),
369         }
370     }
371
372     fn strip_bounds(bounds: &[ast::ty_param]) -> ~[ast::ty_param] {
373         do bounds.map |ty_param| {
374             ast::ty_param { bounds: @~[], ..copy *ty_param }
375         }
376     }
377
378     fn item_ty_poly(name: ident,
379                     span: span,
380                     ty: @ast::Ty,
381                     +params: ~[ast::ty_param]) -> @ast::item {
382         self.item(name, span, ast::item_ty(ty, params))
383     }
384
385     fn item_ty(name: ident, span: span, ty: @ast::Ty) -> @ast::item {
386         self.item_ty_poly(name, span, ty, ~[])
387     }
388
389     fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::Ty] {
390         ty_params.map(|p| self.ty_path_ast_builder(
391             path(~[p.ident], dummy_sp())))
392     }
393
394     fn ty_vars_global(+ty_params: ~[ast::ty_param]) -> ~[@ast::Ty] {
395         ty_params.map(|p| self.ty_path_ast_builder(
396             path(~[p.ident], dummy_sp())))
397     }
398 }