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.
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.
11 // Functions for building ASTs, without having to fuss with spans.
13 // To start with, it will be use dummy spans, but it might someday do
18 use ast::{ident, node_id};
20 use ast_util::{ident_to_path};
23 use codemap::{span, respan, dummy_sp};
25 use ext::base::{ext_ctxt, mk_ctxt};
26 use ext::quote::rt::*;
30 // Transitional reexports so qquote can find the paths it is looking for
36 pub fn path(ids: ~[ident], span: span) -> @ast::path {
37 @ast::path { span: span,
44 pub fn path_global(ids: ~[ident], span: span) -> @ast::path {
45 @ast::path { span: span,
52 pub trait append_types {
53 fn add_ty(ty: @ast::Ty) -> @ast::path;
54 fn add_tys(+tys: ~[@ast::Ty]) -> @ast::path;
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),
63 fn add_tys(+tys: ~[@ast::Ty]) -> @ast::path {
64 @ast::path { types: vec::append(self.types, tys),
69 pub trait ext_ctxt_ast_builder {
70 fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound])
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,
79 +ty_params: ~[ast::ty_param],
80 +body: ast::blk) -> @ast::item;
81 fn item_fn(name: ident,
84 +body: ast::blk) -> @ast::item;
85 fn item_enum_poly(name: ident,
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,
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];
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))
128 fn block_expr(b: ast::blk) -> @ast::expr {
131 callee_id: self.next_id(),
132 node: ast::expr_block(b),
137 fn stmt_expr(e: @ast::expr) -> @ast::stmt {
138 @spanned { node: ast::stmt_expr(e, self.next_id()),
142 fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt {
144 quote_stmt!( let $ident = $e; )
147 fn field_imm(name: ident, e: @ast::expr) -> ast::field {
149 node: ast::field_ { mutbl: ast::m_imm, ident: name, expr: e },
154 fn ty_field_imm(name: ident, ty: @ast::Ty) -> ast::ty_field {
156 node: ast::ty_field_ {
158 mt: ast::mt { ty: ty, mutbl: ast::m_imm },
164 fn ty_infer() -> @ast::Ty {
172 fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound])
175 ast::ty_param { ident: id, id: self.next_id(), bounds: @bounds }
178 fn arg(name: ident, ty: @ast::Ty) -> ast::arg {
180 mode: ast::infer(self.next_id()),
185 node: ast::pat_ident(
187 ast_util::ident_to_path(dummy_sp(), name),
195 fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk {
196 let blk = ast::blk_ {
201 rules: ast::default_blk,
204 spanned { node: blk, span: dummy_sp() }
207 fn expr_block(e: @ast::expr) -> ast::blk {
211 fn fn_decl(+inputs: ~[ast::arg],
212 output: @ast::Ty) -> ast::fn_decl {
222 +node: ast::item_) -> @ast::item {
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", ~[
231 ast::meta_word(~"non_camel_case_types"))
233 is_sugared_doc: false
236 @ast::item { ident: name,
237 attrs: ~[non_camel_case_attribute],
244 fn item_fn_poly(name: ident,
245 +inputs: ~[ast::arg],
247 +ty_params: ~[ast::ty_param],
248 +body: ast::blk) -> @ast::item {
251 ast::item_fn(self.fn_decl(inputs, output),
257 fn item_fn(name: ident,
258 +inputs: ~[ast::arg],
260 +body: ast::blk) -> @ast::item {
261 self.item_fn_poly(name, inputs, output, ~[], body)
264 fn item_enum_poly(name: ident,
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))
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, ~[])
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, ~[])
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))
287 fn struct_expr(path: @ast::path, fields: ~[ast::field]) -> @ast::expr {
290 callee_id: self.next_id(),
291 node: ast::expr_struct(path, fields, None),
296 fn variant(name: ident,
298 +tys: ~[@ast::Ty]) -> ast::variant {
299 let args = do tys.map |ty| {
300 ast::variant_arg { ty: *ty, id: self.next_id() }
304 node: ast::variant_ {
307 kind: ast::tuple_variant_kind(args),
316 fn item_mod(name: ident,
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(~[
323 node: ast::view_path_simple(
324 self.ident_of(~"Owned"),
327 self.ident_of(~"core"),
328 self.ident_of(~"kinds"),
329 self.ident_of(~"Owned")
336 span: codemap::dummy_sp()
339 let vi = @ast::view_item {
343 span: codemap::dummy_sp()
349 ast::item_mod(ast::_mod {
356 fn ty_path_ast_builder(path: @ast::path) -> @ast::Ty {
359 node: ast::ty_path(path, self.next_id()),
364 fn ty_nil_ast_builder() -> @ast::Ty {
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 }
378 fn item_ty_poly(name: ident,
381 +params: ~[ast::ty_param]) -> @ast::item {
382 self.item(name, span, ast::item_ty(ty, params))
385 fn item_ty(name: ident, span: span, ty: @ast::Ty) -> @ast::item {
386 self.item_ty_poly(name, span, ty, ~[])
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())))
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())))