From 35dec9340d33411b2d9e7f391d022e64859db084 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 7 Nov 2012 13:41:02 -0800 Subject: [PATCH 1/4] cleanup: convert some remaining #foo invocations to foo! form. --- src/librustc/front/intrinsic.rs | 2 +- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/ty.rs | 2 +- src/librustc/middle/typeck/check.rs | 2 +- src/libstd/serialization.rs | 2 +- src/libsyntax/ext/source_util.rs | 6 +++--- src/test/bench/core-std.rs | 10 ++++------ src/test/bench/msgsend-ring-pipes.rs | 9 +++------ src/test/bench/shootout-k-nucleotide-pipes.rs | 2 +- src/test/bench/shootout-k-nucleotide.rs | 2 +- src/test/compile-fail/issue-2823.rs | 4 ++-- src/test/run-pass/issue-2904.rs | 2 +- src/test/run-pass/macro-2.rs | 7 ------- src/test/run-pass/syntax-extension-shell.rs | 2 +- src/test/run-pass/syntax-extension-source-utils.rs | 2 +- 15 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs index 2a87f089c8db4..9a9229ebaef12 100644 --- a/src/librustc/front/intrinsic.rs +++ b/src/librustc/front/intrinsic.rs @@ -1,4 +1,4 @@ -// NB: this file is #include_str'ed into the compiler, re-parsed +// NB: this file is include_str!'ed into the compiler, re-parsed // and injected into each crate the compiler builds. Keep it small. mod intrinsic { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ec7c2ffc6f1da..0790208244e9a 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1536,7 +1536,7 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) { // Probably a bad error message (what's an rvalue?) // but I can't think of anything better self.tcx.sess.span_err(arg_expr.span, - #fmt("Move mode argument must be an rvalue: try \ + fmt!("Move mode argument must be an rvalue: try \ (move %s) instead", expr_to_str(*arg_expr, self.tcx.sess.intr()))); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 52f05eb44de01..eaf4d565f16a8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1510,7 +1510,7 @@ fn subst(cx: ctxt, cx, typ, |r| match r { re_bound(br_self) => substs.self_r.expect( - #fmt("ty::subst: \ + fmt!("ty::subst: \ Reference to self region when given substs with no \ self region, ty = %s", ty_to_str(cx, typ))), _ => r diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs index d9ab7306ac3aa..d892719328146 100644 --- a/src/librustc/middle/typeck/check.rs +++ b/src/librustc/middle/typeck/check.rs @@ -2425,7 +2425,7 @@ fn check_enum_variants(ccx: @crate_ctxt, } Err(err) => { ccx.tcx.sess.span_err(e.span, - #fmt("expected constant: %s", err)); + fmt!("expected constant: %s", err)); } } diff --git a/src/libstd/serialization.rs b/src/libstd/serialization.rs index 1b2cd0aaa3db8..93d025a778600 100644 --- a/src/libstd/serialization.rs +++ b/src/libstd/serialization.rs @@ -376,7 +376,7 @@ pub impl> Option: Deserializable { match i { 0 => None, 1 => Some(d.read_enum_variant_arg(0u, || deserialize(d))), - _ => fail(#fmt("Bad variant for option: %u", i)) + _ => fail(fmt!("Bad variant for option: %u", i)) } } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 9b41d90e6d045..45c8fd76e4f2c 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -57,7 +57,7 @@ fn expand_mod(cx: ext_ctxt, sp: span, arg: ast::mac_arg, _body: ast::mac_body) fn expand_include(cx: ext_ctxt, sp: span, arg: ast::mac_arg, _body: ast::mac_body) -> @ast::expr { let args = get_mac_args(cx, sp, arg, 1u, option::Some(1u), ~"include"); - let file = expr_to_str(cx, args[0], ~"#include_str requires a string"); + let file = expr_to_str(cx, args[0], ~"include_str! requires a string"); let p = parse::new_parser_from_file(cx.parse_sess(), cx.cfg(), &res_rel_file(cx, sp, &Path(file)), parse::parser::SOURCE_FILE); @@ -68,7 +68,7 @@ fn expand_include_str(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, _body: ast::mac_body) -> @ast::expr { let args = get_mac_args(cx,sp,arg,1u,option::Some(1u),~"include_str"); - let file = expr_to_str(cx, args[0], ~"#include_str requires a string"); + let file = expr_to_str(cx, args[0], ~"include_str! requires a string"); let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path(file))); match res { @@ -85,7 +85,7 @@ fn expand_include_bin(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, _body: ast::mac_body) -> @ast::expr { let args = get_mac_args(cx,sp,arg,1u,option::Some(1u),~"include_bin"); - let file = expr_to_str(cx, args[0], ~"#include_bin requires a string"); + let file = expr_to_str(cx, args[0], ~"include_bin! requires a string"); match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) { result::Ok(src) => { diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 6f90a2c99e810..3cc1163eb22b1 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -8,14 +8,12 @@ use std::map::{Map, HashMap}; use io::{Reader, ReaderUtil}; +macro_rules! bench ( + ($id:ident) => (maybe_run_test(argv, stringify!($id), $id)) +) + fn main() { let argv = os::args(); - #macro[ - [#bench[id], - maybe_run_test(argv, #stringify(id), id) - ] - ]; - let tests = vec::view(argv, 1, argv.len()); bench!(shift_push); diff --git a/src/test/bench/msgsend-ring-pipes.rs b/src/test/bench/msgsend-ring-pipes.rs index 636fef53732db..da49b006cd9e4 100644 --- a/src/test/bench/msgsend-ring-pipes.rs +++ b/src/test/bench/msgsend-ring-pipes.rs @@ -18,12 +18,9 @@ proto! ring ( } ) -fn macros() { - #macro[ - [#move_out[x], - unsafe { let y = move *ptr::addr_of(&x); move y }] - ]; -} +macro_rules! move_out ( + ($x:expr) => { unsafe { let y = move *ptr::addr_of(&$x); move y } } +) fn thread_ring(i: uint, count: uint, diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 3a3c609853b37..c395ff39430cc 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -132,7 +132,7 @@ fn main() { let args = os::args(); let rdr = if os::getenv(~"RUST_BENCH").is_some() { // FIXME: Using this compile-time env variable is a crummy way to - // get to this massive data set, but #include_bin chokes on it (#2598) + // get to this massive data set, but include_bin! chokes on it (#2598) let path = Path(env!("CFG_SRC_DIR")) .push_rel(&Path("src/test/bench/shootout-k-nucleotide.data")); result::get(&io::file_reader(&path)) diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index e4373d55c1792..a4ff9ef164079 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -129,7 +129,7 @@ fn main() { let args = os::args(); let rdr = if os::getenv(~"RUST_BENCH").is_some() { // FIXME: Using this compile-time env variable is a crummy way to - // get to this massive data set, but #include_bin chokes on it (#2598) + // get to this massive data set, but include_bin! chokes on it (#2598) let path = Path(env!("CFG_SRC_DIR")) .push_rel(&Path("src/test/bench/shootout-k-nucleotide.data")); result::get(&io::file_reader(&path)) diff --git a/src/test/compile-fail/issue-2823.rs b/src/test/compile-fail/issue-2823.rs index fd2c17584581c..67e028dcd46d3 100644 --- a/src/test/compile-fail/issue-2823.rs +++ b/src/test/compile-fail/issue-2823.rs @@ -1,12 +1,12 @@ struct C { x: int, drop { - #error("dropping: %?", self.x); + error!("dropping: %?", self.x); } } fn main() { let c = C{ x: 2}; let d = copy c; //~ ERROR copying a noncopyable value - #error("%?", d.x); + error!("%?", d.x); } \ No newline at end of file diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index 5cc39f4d683d2..132fd47636bba 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -71,7 +71,7 @@ mod test { #[test] fn read_simple_board() { - let s = #include_str("./maps/contest1.map"); + let s = include_str!("./maps/contest1.map"); io::with_str_reader(s, read_board_grid) } } diff --git a/src/test/run-pass/macro-2.rs b/src/test/run-pass/macro-2.rs index 31f6d60df23a5..595583d2cefeb 100644 --- a/src/test/run-pass/macro-2.rs +++ b/src/test/run-pass/macro-2.rs @@ -1,13 +1,6 @@ // xfail-pretty - token trees can't pretty print fn main() { - #macro[[#mylambda[x, body], - { - fn f(x: int) -> int { return body; } - f - }]]; - - assert (mylambda!(y, y * 2)(8) == 16); macro_rules! mylambda_tt( ($x:ident, $body:expr) => { diff --git a/src/test/run-pass/syntax-extension-shell.rs b/src/test/run-pass/syntax-extension-shell.rs index 6ec80db8d55bf..2507057c64818 100644 --- a/src/test/run-pass/syntax-extension-shell.rs +++ b/src/test/run-pass/syntax-extension-shell.rs @@ -1,5 +1,5 @@ // xfail-test fn main() { - auto s = #shell { uname -a }; + let s = shell!( uname -a ); log(debug, s); } diff --git a/src/test/run-pass/syntax-extension-source-utils.rs b/src/test/run-pass/syntax-extension-source-utils.rs index 7afb74fa12172..2a6b5d644f1a0 100644 --- a/src/test/run-pass/syntax-extension-source-utils.rs +++ b/src/test/run-pass/syntax-extension-source-utils.rs @@ -1,5 +1,5 @@ // This test is brittle! -// xfail-pretty - the pretty tests lose path information, breaking #include +// xfail-pretty - the pretty tests lose path information, breaking include! #[legacy_exports]; mod m1 { From 0799c998e9a94f255febaa15c9749485f6bc7bcb Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 7 Nov 2012 15:16:58 -0800 Subject: [PATCH 2/4] Revert "`m1!{...}` is now forbidden. Use `m1!(...)` instead." This reverts commit 89bbaff84fed6e6796c82f5a9fd200e693d47beb. --- src/libsyntax/parse/parser.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2b42dcc0ed06a..9d95b1378b24a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1080,10 +1080,15 @@ impl Parser { /* `!`, as an operator, is prefix, so we know this isn't that */ if self.token == token::NOT { self.bump(); - let tts = self.parse_unspanned_seq( - token::LPAREN, token::RPAREN, seq_sep_none(), - |p| p.parse_token_tree()); - + let tts = match self.token { + token::LPAREN | token::LBRACE | token::LBRACKET => { + let ket = token::flip_delimiter(self.token); + self.parse_unspanned_seq(copy self.token, ket, + seq_sep_none(), + |p| p.parse_token_tree()) + } + _ => self.fatal(~"expected open delimiter") + }; let hi = self.span.hi; return self.mk_mac_expr( @@ -3410,9 +3415,15 @@ impl Parser { let pth = self.parse_path_without_tps(); self.expect(token::NOT); let id = self.parse_ident(); - let tts = self.parse_unspanned_seq( - token::LPAREN, token::RPAREN, seq_sep_none(), - |p| p.parse_token_tree()); + let tts = match self.token { + token::LPAREN | token::LBRACE | token::LBRACKET => { + let ket = token::flip_delimiter(self.token); + self.parse_unspanned_seq(copy self.token, ket, + seq_sep_none(), + |p| p.parse_token_tree()) + } + _ => self.fatal(~"expected open delimiter") + }; let m = ast::mac_invoc_tt(pth, tts); let m: ast::mac = {node: m, span: {lo: self.span.lo, From e226a625747edd55601afc80c82330b36bc1f1fa Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 7 Nov 2012 15:30:28 -0800 Subject: [PATCH 3/4] rustc: Remove the case of foo![...] as invocation syntax. foo!(...) and foo!{...} only. --- src/libsyntax/parse/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9d95b1378b24a..2ed44406889d8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1081,7 +1081,7 @@ impl Parser { if self.token == token::NOT { self.bump(); let tts = match self.token { - token::LPAREN | token::LBRACE | token::LBRACKET => { + token::LPAREN | token::LBRACE => { let ket = token::flip_delimiter(self.token); self.parse_unspanned_seq(copy self.token, ket, seq_sep_none(), @@ -3416,7 +3416,7 @@ impl Parser { self.expect(token::NOT); let id = self.parse_ident(); let tts = match self.token { - token::LPAREN | token::LBRACE | token::LBRACKET => { + token::LPAREN | token::LBRACE => { let ket = token::flip_delimiter(self.token); self.parse_unspanned_seq(copy self.token, ket, seq_sep_none(), From a66575b1e51e9bee82d44414d4a9f4ec12286517 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 8 Nov 2012 17:00:55 -0800 Subject: [PATCH 4/4] rustc: add new token-tree based quasiquoter. --- src/libsyntax/ext/base.rs | 2 + src/libsyntax/ext/build.rs | 70 ++++++-- src/libsyntax/ext/quote.rs | 307 ++++++++++++++++++++++++++++++++++ src/libsyntax/parse/parser.rs | 5 +- src/libsyntax/syntax.rc | 3 + 5 files changed, 368 insertions(+), 19 deletions(-) create mode 100644 src/libsyntax/ext/quote.rs diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ddf58ce0fef1c..3f5d0f13b31c6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -96,6 +96,8 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { ext::log_syntax::expand_syntax_ext)); syntax_expanders.insert(~"ast", builtin(ext::qquote::expand_ast)); + syntax_expanders.insert(~"quote", + builtin_expr_tt(ext::quote::expand_quote)); syntax_expanders.insert(~"line", builtin(ext::source_util::expand_line)); syntax_expanders.insert(~"col", diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a43b0cb69f4b6..10f853495e3ce 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -34,12 +34,14 @@ fn mk_unary(cx: ext_ctxt, sp: span, op: ast::unop, e: @ast::expr) cx.next_id(); // see ast_util::op_expr_callee_id mk_expr(cx, sp, ast::expr_unary(op, e)) } +fn mk_raw_path(sp: span, idents: ~[ast::ident]) -> @ast::path { + let p : @ast::path = @{span: sp, global: false, idents: idents, + rp: None, types: ~[]}; + return p; +} fn mk_path(cx: ext_ctxt, sp: span, idents: ~[ast::ident]) -> @ast::expr { - let path = @{span: sp, global: false, idents: idents, - rp: None, types: ~[]}; - let pathexpr = ast::expr_path(path); - mk_expr(cx, sp, pathexpr) + mk_expr(cx, sp, ast::expr_path(mk_raw_path(sp, idents))) } fn mk_access_(cx: ext_ctxt, sp: span, p: @ast::expr, m: ast::ident) -> @ast::expr { @@ -53,7 +55,6 @@ fn mk_access(cx: ext_ctxt, sp: span, p: ~[ast::ident], m: ast::ident) fn mk_addr_of(cx: ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { return mk_expr(cx, sp, ast::expr_addr_of(ast::m_imm, e)); } - fn mk_call_(cx: ext_ctxt, sp: span, fn_expr: @ast::expr, args: ~[@ast::expr]) -> @ast::expr { mk_expr(cx, sp, ast::expr_call(fn_expr, args, false)) @@ -90,19 +91,54 @@ fn mk_base_str(cx: ext_ctxt, sp: span, s: ~str) -> @ast::expr { fn mk_uniq_str(cx: ext_ctxt, sp: span, s: ~str) -> @ast::expr { mk_vstore_e(cx, sp, mk_base_str(cx, sp, s), ast::expr_vstore_uniq) } - +fn mk_field(sp: span, f: &{ident: ast::ident, ex: @ast::expr}) + -> ast::field { + {node: {mutbl: ast::m_imm, ident: f.ident, expr: f.ex}, span: sp} +} +fn mk_fields(sp: span, fields: ~[{ident: ast::ident, ex: @ast::expr}]) -> + ~[ast::field] { + move fields.map(|f| mk_field(sp, f)) +} fn mk_rec_e(cx: ext_ctxt, sp: span, fields: ~[{ident: ast::ident, ex: @ast::expr}]) -> @ast::expr { - let mut astfields: ~[ast::field] = ~[]; - for fields.each |field| { - let ident = field.ident; - let val = field.ex; - let astfield = - {node: {mutbl: ast::m_imm, ident: ident, expr: val}, span: sp}; - astfields.push(astfield); - } - let recexpr = ast::expr_rec(astfields, option::None::<@ast::expr>); - mk_expr(cx, sp, recexpr) + mk_expr(cx, sp, ast::expr_rec(mk_fields(sp, fields), + option::None::<@ast::expr>)) +} +fn mk_struct_e(cx: ext_ctxt, sp: span, + ctor_path: ~[ast::ident], + fields: ~[{ident: ast::ident, ex: @ast::expr}]) -> + @ast::expr { + mk_expr(cx, sp, + ast::expr_struct(mk_raw_path(sp, ctor_path), + mk_fields(sp, fields), + option::None::<@ast::expr>)) +} +fn mk_glob_use(cx: ext_ctxt, sp: span, + path: ~[ast::ident]) -> @ast::view_item { + let glob = @{node: ast::view_path_glob(mk_raw_path(sp, path), + cx.next_id()), + span: sp}; + @{node: ast::view_item_import(~[glob]), + attrs: ~[], + vis: ast::private, + span: sp} +} +fn mk_block(cx: ext_ctxt, sp: span, + view_items: ~[@ast::view_item], + stmts: ~[@ast::stmt], + expr: Option<@ast::expr>) -> @ast::expr { + let blk = {node: {view_items: view_items, + stmts: stmts, + expr: expr, + id: cx.next_id(), + rules: ast::default_blk }, + span: sp }; + mk_expr(cx, sp, ast::expr_block(blk)) +} +fn mk_copy(cx: ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { + mk_expr(cx, sp, ast::expr_copy(e)) +} +fn mk_managed(cx: ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { + mk_expr(cx, sp, ast::expr_unary(ast::box(ast::m_imm), e)) } - diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs new file mode 100644 index 0000000000000..68a3c4a139962 --- /dev/null +++ b/src/libsyntax/ext/quote.rs @@ -0,0 +1,307 @@ +use mod ast; +use mod parse::token; + +use codemap::span; +use ext::base::ext_ctxt; +use token::*; + +/** +* +* Quasiquoting works via token trees. +* +* This is registered as a expression syntax extension called quote! that lifts +* its argument token-tree to an AST representing the construction of the same +* token tree, with ast::tt_nonterminal nodes interpreted as antiquotes +* (splices). +* +*/ + +pub fn expand_quote(cx: ext_ctxt, + sp: span, + tts: ~[ast::token_tree]) -> base::mac_result +{ + + // NB: It appears that the main parser loses its mind if we consider + // $foo as a tt_nonterminal during the main parse, so we have to re-parse + // under quote_depth > 0. This is silly and should go away; the _guess_ is + // it has to do with transition away from supporting old-style macros, so + // try removing it when enough of them are gone. + let p = parse::new_parser_from_tt(cx.parse_sess(), cx.cfg(), tts); + p.quote_depth += 1u; + let tq = dvec::DVec(); + while p.token != token::EOF { + tq.push(p.parse_token_tree()); + } + let tts = tq.get(); + + // We want to emit a block expression that does a sequence of 'use's to + // import the AST and token constructors, followed by a tt expression. + let uses = ~[ build::mk_glob_use(cx, sp, ids_ext(cx, ~[~"syntax", + ~"ast"])), + build::mk_glob_use(cx, sp, ids_ext(cx, ~[~"syntax", + ~"parse", + ~"token"])) ]; + base::mr_expr(build::mk_block(cx, sp, uses, ~[], + Some(mk_tt(cx, sp, &ast::tt_delim(tts))))) +} + +fn ids_ext(cx: ext_ctxt, strs: ~[~str]) -> ~[ast::ident] { + strs.map(|str| cx.parse_sess().interner.intern(@*str)) +} + +fn id_ext(cx: ext_ctxt, str: ~str) -> ast::ident { + cx.parse_sess().interner.intern(@str) +} + +fn mk_option_span(cx: ext_ctxt, + qsp: span, + sp: Option) -> @ast::expr { + match sp { + None => build::mk_path(cx, qsp, ids_ext(cx, ~[~"None"])), + Some(sp) => { + build::mk_call(cx, qsp, + ids_ext(cx, ~[~"Some"]), + ~[build::mk_managed(cx, qsp, + mk_span(cx, qsp, sp))]) + } + } +} + +fn mk_span(cx: ext_ctxt, qsp: span, sp: span) -> @ast::expr { + + let e_expn_info = match sp.expn_info { + None => build::mk_path(cx, qsp, ids_ext(cx, ~[~"None"])), + Some(@codemap::expanded_from(cr)) => { + let e_callee = + build::mk_rec_e( + cx, qsp, + ~[{ident: id_ext(cx, ~"name"), + ex: build::mk_uniq_str(cx, qsp, + cr.callie.name)}, + {ident: id_ext(cx, ~"span"), + ex: mk_option_span(cx, qsp, cr.callie.span)}]); + + let e_expn_info_ = + build::mk_call( + cx, qsp, + ids_ext(cx, ~[~"expanded_from"]), + ~[build::mk_rec_e( + cx, qsp, + ~[{ident: id_ext(cx, ~"call_site"), + ex: mk_span(cx, qsp, cr.call_site)}, + {ident: id_ext(cx, ~"callie"), + ex: e_callee}])]); + + build::mk_call(cx, qsp, + ids_ext(cx, ~[~"Some"]), + ~[build::mk_managed(cx, qsp, e_expn_info_)]) + } + }; + + build::mk_rec_e(cx, qsp, + ~[{ident: id_ext(cx, ~"lo"), + ex: build::mk_uint(cx, qsp, sp.lo) }, + + {ident: id_ext(cx, ~"hi"), + ex: build::mk_uint(cx, qsp, sp.hi) }, + + {ident: id_ext(cx, ~"expn_info"), + ex: e_expn_info}]) +} + +// Lift an ident to the expr that evaluates to that ident. +// +// NB: this identifies the interner used when re-parsing the token tree +// with the interner used during initial parse. This is _wrong_ and we +// should be emitting a &str here and the token type should be ok with +// &static/str or &session/str. Longer-term issue. +fn mk_ident(cx: ext_ctxt, sp: span, ident: ast::ident) -> @ast::expr { + build::mk_struct_e(cx, sp, + ids_ext(cx, ~[~"ident"]), + ~[{ident: id_ext(cx, ~"repr"), + ex: build::mk_uint(cx, sp, ident.repr) }]) +} + + +fn mk_binop(cx: ext_ctxt, sp: span, bop: token::binop) -> @ast::expr { + let name = match bop { + PLUS => "PLUS", + MINUS => "MINUS", + STAR => "STAR", + SLASH => "SLASH", + PERCENT => "PERCENT", + CARET => "CARET", + AND => "AND", + OR => "OR", + SHL => "SHL", + SHR => "SHR" + }; + build::mk_path(cx, sp, + ids_ext(cx, ~[name.to_owned()])) +} + +fn mk_token(cx: ext_ctxt, sp: span, tok: token::Token) -> @ast::expr { + + match tok { + BINOP(binop) => { + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"BINOP"]), + ~[mk_binop(cx, sp, binop)]); + } + BINOPEQ(binop) => { + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"BINOPEQ"]), + ~[mk_binop(cx, sp, binop)]); + } + + LIT_INT(i, ity) => { + let s_ity = match ity { + ast::ty_i => ~"ty_i", + ast::ty_char => ~"ty_char", + ast::ty_i8 => ~"ty_i8", + ast::ty_i16 => ~"ty_i16", + ast::ty_i32 => ~"ty_i32", + ast::ty_i64 => ~"ty_i64" + }; + let e_ity = + build::mk_path(cx, sp, + ids_ext(cx, ~[s_ity])); + + let e_i64 = build::mk_lit(cx, sp, ast::lit_int(i, ast::ty_i64)); + + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"LIT_INT"]), + ~[e_i64, e_ity]); + } + + LIT_UINT(u, uty) => { + let s_uty = match uty { + ast::ty_u => ~"ty_u", + ast::ty_u8 => ~"ty_u8", + ast::ty_u16 => ~"ty_u16", + ast::ty_u32 => ~"ty_u32", + ast::ty_u64 => ~"ty_u64" + }; + let e_uty = + build::mk_path(cx, sp, + ids_ext(cx, ~[s_uty])); + + let e_u64 = build::mk_lit(cx, sp, ast::lit_uint(u, ast::ty_u64)); + + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"LIT_UINT"]), + ~[e_u64, e_uty]); + } + + LIT_INT_UNSUFFIXED(i) => { + let e_i64 = build::mk_lit(cx, sp, + ast::lit_int(i, ast::ty_i64)); + + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"LIT_INT_UNSUFFIXED"]), + ~[e_i64]); + } + + LIT_FLOAT(fident, fty) => { + let s_fty = match fty { + ast::ty_f => ~"ty_f", + ast::ty_f32 => ~"ty_f32", + ast::ty_f64 => ~"ty_f64" + }; + let e_fty = + build::mk_path(cx, sp, + ids_ext(cx, ~[s_fty])); + + let e_fident = mk_ident(cx, sp, fident); + + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"LIT_FLOAT"]), + ~[e_fident, e_fty]); + } + + LIT_STR(ident) => { + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"LIT_STR"]), + ~[mk_ident(cx, sp, ident)]); + } + + IDENT(ident, b) => { + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"IDENT"]), + ~[mk_ident(cx, sp, ident), + build::mk_lit(cx, sp, ast::lit_bool(b))]); + } + + DOC_COMMENT(ident) => { + return build::mk_call(cx, sp, + ids_ext(cx, ~[~"DOC_COMMENT"]), + ~[mk_ident(cx, sp, ident)]); + } + + INTERPOLATED(_) => fail ~"quote! with interpolated token", + + _ => () + } + + let name = match tok { + EQ => "EQ", + LT => "LT", + LE => "LE", + EQEQ => "EQEQ", + NE => "NE", + GE => "GE", + GT => "GT", + ANDAND => "ANDAND", + OROR => "OROR", + NOT => "NOT", + TILDE => "TILDE", + AT => "AT", + DOT => "DOT", + DOTDOT => "DOTDOT", + ELLIPSIS => "ELLIPSIS", + COMMA => "COMMA", + SEMI => "SEMI", + COLON => "COLON", + MOD_SEP => "MOD_SEP", + RARROW => "RARROW", + LARROW => "LARROW", + DARROW => "DARROW", + FAT_ARROW => "FAT_ARROW", + LPAREN => "LPAREN", + RPAREN => "RPAREN", + LBRACKET => "LBRACKET", + RBRACKET => "RBRACKET", + LBRACE => "LBRACE", + RBRACE => "RBRACE", + POUND => "POUND", + DOLLAR => "DOLLAR", + UNDERSCORE => "UNDERSCORE", + EOF => "EOF", + _ => fail + }; + build::mk_path(cx, sp, + ids_ext(cx, ~[name.to_owned()])) +} + + +fn mk_tt(cx: ext_ctxt, sp: span, tt: &ast::token_tree) -> @ast::expr { + match *tt { + ast::tt_tok(sp, tok) => + build::mk_call(cx, sp, + ids_ext(cx, ~[~"tt_tok"]), + ~[mk_span(cx, sp, sp), + mk_token(cx, sp, tok)]), + + ast::tt_delim(tts) => { + let e_tts = tts.map(|tt| mk_tt(cx, sp, tt)); + build::mk_call(cx, sp, + ids_ext(cx, ~[~"tt_delim"]), + ~[build::mk_uniq_vec_e(cx, sp, e_tts)]) + } + + ast::tt_seq(*) => fail ~"tt_seq in quote!", + + ast::tt_nonterminal(sp, ident) => + build::mk_copy(cx, sp, build::mk_path(cx, sp, ~[ident])) + } +} \ No newline at end of file diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2ed44406889d8..b388ce2907296 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1082,7 +1082,7 @@ impl Parser { self.bump(); let tts = match self.token { token::LPAREN | token::LBRACE => { - let ket = token::flip_delimiter(self.token); + let ket = token::flip_delimiter(copy self.token); self.parse_unspanned_seq(copy self.token, ket, seq_sep_none(), |p| p.parse_token_tree()) @@ -1277,6 +1277,7 @@ impl Parser { maybe_whole!(deref self, nt_tt); fn parse_tt_tok(p: Parser, delim_ok: bool) -> token_tree { + maybe_whole!(deref p, nt_tt); match p.token { token::RPAREN | token::RBRACE | token::RBRACKET if !delim_ok => { @@ -3417,7 +3418,7 @@ impl Parser { let id = self.parse_ident(); let tts = match self.token { token::LPAREN | token::LBRACE => { - let ket = token::flip_delimiter(self.token); + let ket = token::flip_delimiter(copy self.token); self.parse_unspanned_seq(copy self.token, ket, seq_sep_none(), |p| p.parse_token_tree()) diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 7c73deed1a91f..d0a9154b00e27 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -102,6 +102,9 @@ mod ext { mod expand; #[legacy_exports] mod qquote; + + mod quote; + #[legacy_exports] mod build;