| // Functions for building ASTs, without having to fuss with spans. |
| // |
| // To start with, it will be use dummy spans, but it might someday do |
| // something smarter. |
| |
| use ast::{ident, node_id}; |
| use ast_util::respan; |
| use codemap::span; |
| use ext::base::mk_ctxt; |
| |
| // Transitional reexports so qquote can find the paths it is looking for |
| mod syntax { |
| #[legacy_exports]; |
| pub use ext; |
| pub use parse; |
| } |
| |
| fn path(ids: ~[ident], span: span) -> @ast::path { |
| @{span: span, |
| global: false, |
| idents: ids, |
| rp: None, |
| types: ~[]} |
| } |
| |
| fn empty_span() -> span { |
| {lo: 0, hi: 0, expn_info: None} |
| } |
| |
| trait append_types { |
| fn add_ty(ty: @ast::ty) -> @ast::path; |
| fn add_tys(+tys: ~[@ast::ty]) -> @ast::path; |
| } |
| |
| impl @ast::path: append_types { |
| fn add_ty(ty: @ast::ty) -> @ast::path { |
| @{types: vec::append_one(self.types, ty), |
| .. *self} |
| } |
| |
| fn add_tys(+tys: ~[@ast::ty]) -> @ast::path { |
| @{types: vec::append(self.types, tys), |
| .. *self} |
| } |
| } |
| |
| trait ext_ctxt_ast_builder { |
| fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound]) |
| -> ast::ty_param; |
| fn arg(name: ident, ty: @ast::ty) -> ast::arg; |
| fn expr_block(e: @ast::expr) -> ast::blk; |
| fn fn_decl(+inputs: ~[ast::arg], output: @ast::ty) -> ast::fn_decl; |
| fn item(name: ident, span: span, +node: ast::item_) -> @ast::item; |
| fn item_fn_poly(name: ident, |
| +inputs: ~[ast::arg], |
| output: @ast::ty, |
| +ty_params: ~[ast::ty_param], |
| +body: ast::blk) -> @ast::item; |
| fn item_fn(name: ident, |
| +inputs: ~[ast::arg], |
| output: @ast::ty, |
| +body: ast::blk) -> @ast::item; |
| fn item_enum_poly(name: ident, |
| span: span, |
| +enum_definition: ast::enum_def, |
| +ty_params: ~[ast::ty_param]) -> @ast::item; |
| fn item_enum(name: ident, span: span, |
| +enum_definition: ast::enum_def) -> @ast::item; |
| fn variant(name: ident, span: span, +tys: ~[@ast::ty]) -> ast::variant; |
| fn item_mod(name: ident, span: span, +items: ~[@ast::item]) -> @ast::item; |
| fn ty_path_ast_builder(path: @ast::path) -> @ast::ty; |
| fn item_ty_poly(name: ident, |
| span: span, |
| ty: @ast::ty, |
| +params: ~[ast::ty_param]) -> @ast::item; |
| fn item_ty(name: ident, span: span, ty: @ast::ty) -> @ast::item; |
| fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::ty]; |
| fn ty_field_imm(name: ident, ty: @ast::ty) -> ast::ty_field; |
| fn ty_rec(+v: ~[ast::ty_field]) -> @ast::ty; |
| fn field_imm(name: ident, e: @ast::expr) -> ast::field; |
| fn rec(+v: ~[ast::field]) -> @ast::expr; |
| fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk; |
| fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt; |
| fn stmt_expr(e: @ast::expr) -> @ast::stmt; |
| fn block_expr(b: ast::blk) -> @ast::expr; |
| fn empty_span() -> span; |
| fn ty_option(ty: @ast::ty) -> @ast::ty; |
| } |
| |
| impl ext_ctxt: ext_ctxt_ast_builder { |
| fn ty_option(ty: @ast::ty) -> @ast::ty { |
| self.ty_path_ast_builder(path(~[self.ident_of(~"Option")], |
| self.empty_span()) |
| .add_ty(ty)) |
| } |
| |
| fn empty_span() -> span { |
| {lo: 0, hi: 0, expn_info: self.backtrace()} |
| } |
| |
| fn block_expr(b: ast::blk) -> @ast::expr { |
| @{id: self.next_id(), |
| callee_id: self.next_id(), |
| node: ast::expr_block(b), |
| span: self.empty_span()} |
| } |
| |
| fn stmt_expr(e: @ast::expr) -> @ast::stmt { |
| @{node: ast::stmt_expr(e, self.next_id()), |
| span: self.empty_span()} |
| } |
| |
| fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt { |
| // If the quasiquoter could interpolate idents, this is all |
| // we'd need. |
| // |
| //let ext_cx = self; |
| //#ast[stmt] { let $(ident) = $(e) } |
| |
| @{node: ast::stmt_decl(@{node: ast::decl_local(~[ |
| @{node: {is_mutbl: false, |
| ty: self.ty_infer(), |
| pat: @{id: self.next_id(), |
| node: ast::pat_ident(ast::bind_by_implicit_ref, |
| path(~[ident], |
| self.empty_span()), |
| None), |
| span: self.empty_span()}, |
| init: Some({op: ast::init_move, |
| expr: e}), |
| id: self.next_id()}, |
| span: self.empty_span()}]), |
| span: self.empty_span()}, self.next_id()), |
| span: self.empty_span()} |
| } |
| |
| fn field_imm(name: ident, e: @ast::expr) -> ast::field { |
| {node: {mutbl: ast::m_imm, ident: name, expr: e}, |
| span: self.empty_span()} |
| } |
| |
| fn rec(+fields: ~[ast::field]) -> @ast::expr { |
| @{id: self.next_id(), |
| callee_id: self.next_id(), |
| node: ast::expr_rec(fields, None), |
| span: self.empty_span()} |
| } |
| |
| fn ty_field_imm(name: ident, ty: @ast::ty) -> ast::ty_field { |
| {node: {ident: name, mt: { ty: ty, mutbl: ast::m_imm } }, |
| span: self.empty_span()} |
| } |
| |
| fn ty_rec(+fields: ~[ast::ty_field]) -> @ast::ty { |
| @{id: self.next_id(), |
| node: ast::ty_rec(fields), |
| span: self.empty_span()} |
| } |
| |
| fn ty_infer() -> @ast::ty { |
| @{id: self.next_id(), |
| node: ast::ty_infer, |
| span: self.empty_span()} |
| } |
| |
| fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound]) |
| -> ast::ty_param |
| { |
| {ident: id, id: self.next_id(), bounds: @bounds} |
| } |
| |
| fn arg(name: ident, ty: @ast::ty) -> ast::arg { |
| {mode: ast::infer(self.next_id()), |
| ty: ty, |
| ident: name, |
| id: self.next_id()} |
| } |
| |
| fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk { |
| let blk = {view_items: ~[], |
| stmts: stmts, |
| expr: Some(e), |
| id: self.next_id(), |
| rules: ast::default_blk}; |
| |
| {node: blk, |
| span: self.empty_span()} |
| } |
| |
| fn expr_block(e: @ast::expr) -> ast::blk { |
| self.block(~[], e) |
| } |
| |
| fn fn_decl(+inputs: ~[ast::arg], |
| output: @ast::ty) -> ast::fn_decl { |
| {inputs: inputs, |
| output: output, |
| cf: ast::return_val} |
| } |
| |
| fn item(name: ident, |
| span: span, |
| +node: ast::item_) -> @ast::item { |
| |
| // XXX: Would be nice if our generated code didn't violate |
| // Rust coding conventions |
| let non_camel_case_attribute = respan(self.empty_span(), { |
| style: ast::attr_outer, |
| value: respan(self.empty_span(), |
| ast::meta_list(~"allow", ~[ |
| @respan(self.empty_span(), |
| ast::meta_word(~"non_camel_case_types")) |
| ])), |
| is_sugared_doc: false |
| }); |
| |
| @{ident: name, |
| attrs: ~[non_camel_case_attribute], |
| id: self.next_id(), |
| node: node, |
| vis: ast::public, |
| span: span} |
| } |
| |
| fn item_fn_poly(name: ident, |
| +inputs: ~[ast::arg], |
| output: @ast::ty, |
| +ty_params: ~[ast::ty_param], |
| +body: ast::blk) -> @ast::item { |
| self.item(name, |
| self.empty_span(), |
| ast::item_fn(self.fn_decl(inputs, output), |
| ast::impure_fn, |
| ty_params, |
| body)) |
| } |
| |
| fn item_fn(name: ident, |
| +inputs: ~[ast::arg], |
| output: @ast::ty, |
| +body: ast::blk) -> @ast::item { |
| self.item_fn_poly(name, inputs, output, ~[], body) |
| } |
| |
| fn item_enum_poly(name: ident, |
| span: span, |
| +enum_definition: ast::enum_def, |
| +ty_params: ~[ast::ty_param]) -> @ast::item { |
| self.item(name, span, ast::item_enum(enum_definition, ty_params)) |
| } |
| |
| fn item_enum(name: ident, span: span, |
| +enum_definition: ast::enum_def) -> @ast::item { |
| self.item_enum_poly(name, span, enum_definition, ~[]) |
| } |
| |
| fn variant(name: ident, |
| span: span, |
| +tys: ~[@ast::ty]) -> ast::variant { |
| let args = tys.map(|ty| {ty: *ty, id: self.next_id()}); |
| |
| {node: {name: name, |
| attrs: ~[], |
| kind: ast::tuple_variant_kind(args), |
| id: self.next_id(), |
| disr_expr: None, |
| vis: ast::public}, |
| span: span} |
| } |
| |
| fn item_mod(name: ident, |
| span: span, |
| +items: ~[@ast::item]) -> @ast::item { |
| self.item(name, |
| span, |
| ast::item_mod({ |
| view_items: ~[], |
| items: items})) |
| } |
| |
| fn ty_path_ast_builder(path: @ast::path) -> @ast::ty { |
| @{id: self.next_id(), |
| node: ast::ty_path(path, self.next_id()), |
| span: path.span} |
| } |
| |
| fn ty_nil_ast_builder() -> @ast::ty { |
| @{id: self.next_id(), |
| node: ast::ty_nil, |
| span: self.empty_span()} |
| } |
| |
| fn item_ty_poly(name: ident, |
| span: span, |
| ty: @ast::ty, |
| +params: ~[ast::ty_param]) -> @ast::item { |
| self.item(name, span, ast::item_ty(ty, params)) |
| } |
| |
| fn item_ty(name: ident, span: span, ty: @ast::ty) -> @ast::item { |
| self.item_ty_poly(name, span, ty, ~[]) |
| } |
| |
| fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::ty] { |
| ty_params.map(|p| self.ty_path_ast_builder( |
| path(~[p.ident], self.empty_span()))) |
| } |
| } |