]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/pipes/ast_builder.rs
da2f9d433739aa2d1c1808a5d694b04c4ae1c861
[rust.git] / src / libsyntax / ext / pipes / ast_builder.rs
1 // Functions for building ASTs, without having to fuss with spans.
2 //
3 // To start with, it will be use dummy spans, but it might someday do
4 // something smarter.
5
6 import ast::{ident, node_id};
7 import codemap::span;
8 import ext::base::mk_ctxt;
9
10 // Transitional reexports so qquote can find the paths it is looking for
11 mod syntax {
12     import ext;
13     export ext;
14     import parse;
15     export parse;
16 }
17
18 fn ident(s: &str) -> ast::ident {
19     @(s.to_unique())
20 }
21
22 fn path(id: ident, span: span) -> @ast::path {
23     @{span: span,
24       global: false,
25       idents: ~[id],
26       rp: none,
27       types: ~[]}
28 }
29
30 fn empty_span() -> span {
31     {lo: 0, hi: 0, expn_info: none}
32 }
33
34 trait append_types {
35     fn add_ty(ty: @ast::ty) -> @ast::path;
36     fn add_tys(+tys: ~[@ast::ty]) -> @ast::path;
37 }
38
39 impl @ast::path: append_types {
40     fn add_ty(ty: @ast::ty) -> @ast::path {
41         @{types: vec::append_one(self.types, ty)
42           with *self}
43     }
44
45     fn add_tys(+tys: ~[@ast::ty]) -> @ast::path {
46         @{types: vec::append(self.types, tys)
47           with *self}
48     }
49 }
50
51 trait ext_ctxt_ast_builder {
52     fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound])
53         -> ast::ty_param;
54     fn arg(name: ident, ty: @ast::ty) -> ast::arg;
55     fn arg_mode(name: ident, ty: @ast::ty, mode: ast::rmode) -> ast::arg;
56     fn expr_block(e: @ast::expr) -> ast::blk;
57     fn fn_decl(+inputs: ~[ast::arg], output: @ast::ty) -> ast::fn_decl;
58     fn item(name: ident, span: span, +node: ast::item_) -> @ast::item;
59     fn item_fn_poly(name: ident,
60                     +inputs: ~[ast::arg],
61                     output: @ast::ty,
62                     +ty_params: ~[ast::ty_param],
63                     +body: ast::blk) -> @ast::item;
64     fn item_fn(name: ident,
65                +inputs: ~[ast::arg],
66                output: @ast::ty,
67                +body: ast::blk) -> @ast::item;
68     fn item_enum_poly(name: ident,
69                       span: span,
70                       +enum_definition: ast::enum_def,
71                       +ty_params: ~[ast::ty_param]) -> @ast::item;
72     fn item_enum(name: ident, span: span, 
73                  +enum_definition: ast::enum_def) -> @ast::item;
74     fn variant(name: ident, span: span, +tys: ~[@ast::ty]) -> ast::variant;
75     fn item_mod(name: ident, span: span, +items: ~[@ast::item]) -> @ast::item;
76     fn ty_path_ast_builder(path: @ast::path) -> @ast::ty;
77     fn item_ty_poly(name: ident,
78                     span: span,
79                     ty: @ast::ty,
80                     +params: ~[ast::ty_param]) -> @ast::item;
81     fn item_ty(name: ident, span: span, ty: @ast::ty) -> @ast::item;
82     fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::ty];
83     fn ty_field_imm(name: ident, ty: @ast::ty) -> ast::ty_field;
84     fn ty_rec(+~[ast::ty_field]) -> @ast::ty;
85     fn field_imm(name: ident, e: @ast::expr) -> ast::field;
86     fn rec(+~[ast::field]) -> @ast::expr;
87     fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk;
88     fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt;
89     fn stmt_expr(e: @ast::expr) -> @ast::stmt;
90     fn block_expr(b: ast::blk) -> @ast::expr;
91     fn empty_span() -> span;
92     fn ty_option(ty: @ast::ty) -> @ast::ty;
93 }
94
95 impl ext_ctxt: ext_ctxt_ast_builder {
96     fn ty_option(ty: @ast::ty) -> @ast::ty {
97         self.ty_path_ast_builder(path(@~"option", self.empty_span())
98                                  .add_ty(ty))
99     }
100
101     fn empty_span() -> span {
102         {lo: 0, hi: 0, expn_info: self.backtrace()}
103     }
104
105     fn block_expr(b: ast::blk) -> @ast::expr {
106         @{id: self.next_id(),
107           callee_id: self.next_id(),
108           node: ast::expr_block(b),
109           span: self.empty_span()}
110     }
111
112     fn stmt_expr(e: @ast::expr) -> @ast::stmt {
113         @{node: ast::stmt_expr(e, self.next_id()),
114           span: self.empty_span()}
115     }
116
117     fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt {
118         // If the quasiquoter could interpolate idents, this is all
119         // we'd need.
120         //
121         //let ext_cx = self;
122         //#ast[stmt] { let $(ident) = $(e) }
123
124         @{node: ast::stmt_decl(@{node: ast::decl_local(~[
125             @{node: {is_mutbl: false,
126                      ty: self.ty_infer(),
127                      pat: @{id: self.next_id(),
128                             node: ast::pat_ident(ast::bind_by_implicit_ref,
129                                                  path(ident,
130                                                       self.empty_span()),
131                                                  none),
132                             span: self.empty_span()},
133                      init: some({op: ast::init_move,
134                                  expr: e}),
135                      id: self.next_id()},
136               span: self.empty_span()}]),
137                                span: self.empty_span()}, self.next_id()),
138          span: self.empty_span()}
139     }
140
141     fn field_imm(name: ident, e: @ast::expr) -> ast::field {
142         {node: {mutbl: ast::m_imm, ident: name, expr: e},
143          span: self.empty_span()}
144     }
145
146     fn rec(+fields: ~[ast::field]) -> @ast::expr {
147         @{id: self.next_id(),
148           callee_id: self.next_id(),
149           node: ast::expr_rec(fields, none),
150           span: self.empty_span()}
151     }
152
153     fn ty_field_imm(name: ident, ty: @ast::ty) -> ast::ty_field {
154         {node: {ident: name, mt: { ty: ty, mutbl: ast::m_imm } },
155           span: self.empty_span()}
156     }
157
158     fn ty_rec(+fields: ~[ast::ty_field]) -> @ast::ty {
159         @{id: self.next_id(),
160           node: ast::ty_rec(fields),
161           span: self.empty_span()}
162     }
163
164     fn ty_infer() -> @ast::ty {
165         @{id: self.next_id(),
166           node: ast::ty_infer,
167           span: self.empty_span()}
168     }
169
170     fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound])
171         -> ast::ty_param
172     {
173         {ident: id, id: self.next_id(), bounds: @bounds}
174     }
175
176     fn arg(name: ident, ty: @ast::ty) -> ast::arg {
177         {mode: ast::infer(self.next_id()),
178          ty: ty,
179          ident: name,
180          id: self.next_id()}
181     }
182
183     fn arg_mode(name: ident, ty: @ast::ty, mode: ast::rmode) -> ast::arg {
184         {mode: ast::expl(mode),
185          ty: ty,
186          ident: name,
187          id: self.next_id()}
188     }
189
190     fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk {
191         let blk = {view_items: ~[],
192                    stmts: stmts,
193                    expr: some(e),
194                    id: self.next_id(),
195                    rules: ast::default_blk};
196
197         {node: blk,
198          span: self.empty_span()}
199     }
200
201     fn expr_block(e: @ast::expr) -> ast::blk {
202         self.block(~[], e)
203     }
204
205     fn fn_decl(+inputs: ~[ast::arg],
206                output: @ast::ty) -> ast::fn_decl {
207         {inputs: inputs,
208          output: output,
209          purity: ast::impure_fn,
210          cf: ast::return_val}
211     }
212
213     fn item(name: ident,
214             span: span,
215             +node: ast::item_) -> @ast::item {
216         @{ident: name,
217          attrs: ~[],
218          id: self.next_id(),
219          node: node,
220          vis: ast::public,
221          span: span}
222     }
223
224     fn item_fn_poly(name: ident,
225                     +inputs: ~[ast::arg],
226                     output: @ast::ty,
227                     +ty_params: ~[ast::ty_param],
228                     +body: ast::blk) -> @ast::item {
229         self.item(name,
230                   self.empty_span(),
231                   ast::item_fn(self.fn_decl(inputs, output),
232                                ty_params,
233                                body))
234     }
235
236     fn item_fn(name: ident,
237                +inputs: ~[ast::arg],
238                output: @ast::ty,
239                +body: ast::blk) -> @ast::item {
240         self.item_fn_poly(name, inputs, output, ~[], body)
241     }
242
243     fn item_enum_poly(name: ident,
244                       span: span,
245                       +enum_definition: ast::enum_def,
246                       +ty_params: ~[ast::ty_param]) -> @ast::item {
247         self.item(name, span, ast::item_enum(enum_definition, ty_params))
248     }
249
250     fn item_enum(name: ident, span: span,
251                  +enum_definition: ast::enum_def) -> @ast::item {
252         self.item_enum_poly(name, span, enum_definition, ~[])
253     }
254
255     fn variant(name: ident,
256                span: span,
257                +tys: ~[@ast::ty]) -> ast::variant {
258         let args = tys.map(|ty| {ty: ty, id: self.next_id()});
259
260         {node: {name: name,
261                 attrs: ~[],
262                 kind: ast::tuple_variant_kind(args),
263                 id: self.next_id(),
264                 disr_expr: none,
265                 vis: ast::public},
266          span: span}
267     }
268
269     fn item_mod(name: ident,
270                 span: span,
271                 +items: ~[@ast::item]) -> @ast::item {
272         self.item(name,
273                   span,
274                   ast::item_mod({
275                       view_items: ~[],
276                       items: items}))
277     }
278
279     fn ty_path_ast_builder(path: @ast::path) -> @ast::ty {
280         @{id: self.next_id(),
281           node: ast::ty_path(path, self.next_id()),
282           span: path.span}
283     }
284
285     fn ty_nil_ast_builder() -> @ast::ty {
286         @{id: self.next_id(),
287           node: ast::ty_nil,
288           span: self.empty_span()}
289     }
290
291     fn item_ty_poly(name: ident,
292                     span: span,
293                     ty: @ast::ty,
294                     +params: ~[ast::ty_param]) -> @ast::item {
295         self.item(name, span, ast::item_ty(ty, params))
296     }
297
298     fn item_ty(name: ident, span: span, ty: @ast::ty) -> @ast::item {
299         self.item_ty_poly(name, span, ty, ~[])
300     }
301
302     fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::ty] {
303         ty_params.map(|p| self.ty_path_ast_builder(
304             path(p.ident, self.empty_span())))
305     }
306 }