diff --git a/src/comp/syntax/ext/expand.rs b/src/comp/syntax/ext/expand.rs index be1fb2b3e26..20f04bf5cd5 100644 --- a/src/comp/syntax/ext/expand.rs +++ b/src/comp/syntax/ext/expand.rs @@ -8,7 +8,7 @@ import vec; import syntax::ast::{crate, expr_, expr_mac, mac_invoc, mac_qq}; import syntax::fold::*; import syntax::ext::base::*; -import syntax::ext::qquote::expand_qquote; +import syntax::ext::qquote::{expand_qquote,qq_helper}; import syntax::parse::parser::parse_expr_from_source_str; import codemap::span; diff --git a/src/comp/syntax/ext/qquote.rs b/src/comp/syntax/ext/qquote.rs index 2f600c9f9ec..174c58d807c 100644 --- a/src/comp/syntax/ext/qquote.rs +++ b/src/comp/syntax/ext/qquote.rs @@ -9,7 +9,7 @@ import syntax::visit::*; import syntax::ext::base::*; import syntax::ext::build::*; import syntax::parse::parser; -import syntax::parse::parser::{parse_from_source_str}; +import syntax::parse::parser::{parser, parse_from_source_str}; import syntax::print::*; import std::io::*; @@ -19,12 +19,53 @@ import codemap::span; type aq_ctxt = @{lo: uint, mutable gather: [{lo: uint, hi: uint, e: @ast::expr}]}; -fn gather_anti_quotes(lo: uint, e: @ast::expr) -> aq_ctxt +iface qq_helper { + fn span() -> span; + fn visit(aq_ctxt, vt); + fn mk_parse_fn(ext_ctxt,span) -> @ast::expr; +} +impl of qq_helper for @ast::expr { + fn span() -> span {self.span} + fn visit(cx: aq_ctxt, v: vt) {visit_expr(self, cx, v);} + fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { + mk_path(cx, sp, ["syntax", "parse", "parser", "parse_expr"]) + } +} +impl of qq_helper for @ast::ty { + fn span() -> span {self.span} + fn visit(cx: aq_ctxt, v: vt) {visit_ty(self, cx, v);} + fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { + mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_ty"]) + } +} +impl of qq_helper for @ast::item { + fn span() -> span {self.span} + fn visit(cx: aq_ctxt, v: vt) {visit_item(self, cx, v);} + fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { + mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_item"]) + } +} +impl of qq_helper for @ast::stmt { + fn span() -> span {self.span} + fn visit(cx: aq_ctxt, v: vt) {visit_stmt(self, cx, v);} + fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { + mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_stmt"]) + } +} +impl of qq_helper for @ast::pat { + fn span() -> span {self.span} + fn visit(cx: aq_ctxt, v: vt) {visit_pat(self, cx, v);} + fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { + mk_path(cx, sp, ["syntax", "parse", "parser", "parse_pat"]) + } +} + +fn gather_anti_quotes(lo: uint, node: N) -> aq_ctxt { let v = @{visit_expr: visit_expr_aq with *default_visitor()}; let cx = @{lo:lo, mutable gather: []}; - visit_expr_aq(e, cx, mk_vt(v)); + node.visit(cx, mk_vt(v)); ret cx; } @@ -43,31 +84,78 @@ fn is_space(c: char) -> bool { syntax::parse::lexer::is_whitespace(c) } -fn expand_ast(ecx: ext_ctxt, _sp: span, _arg: - ast::mac_arg, body: ast::mac_body) +fn expand_ast(ecx: ext_ctxt, _sp: span, + arg: ast::mac_arg, body: ast::mac_body) -> @ast::expr { + let what = "expr"; + option::may(arg) {|arg| + let args: [@ast::expr] = + alt arg.node { + ast::expr_vec(elts, _) { elts } + _ { + ecx.span_fatal + (_sp, "#ast requires arguments of the form `[...]`.") + } + }; + if vec::len::<@ast::expr>(args) != 1u { + ecx.span_fatal(_sp, "#ast requires exactly one arg"); + } + alt (args[0].node) { + ast::expr_path(@{node: {idents: id, _},_}) if vec::len(id) == 1u + {what = id[0]} + _ {ecx.span_fatal(args[0].span, "expected an identifier");} + } + } let body = get_mac_body(ecx,_sp,body); - let cm = ecx.session().parse_sess.cm; - let str = @codemap::span_to_snippet(body.span, cm); - let (fname, ss) = codemap::get_substr_info(cm, - body.span.lo, body.span.hi); - let {node: e, _} = parse_from_source_str(parser::parse_expr, - fname, some(ss), str, - ecx.session().opts.cfg, - ecx.session().parse_sess); - ret expand_qquote(ecx, e.span, some(*str), e); + fn finish(ecx: ext_ctxt, body: ast::mac_body_, + f: fn (p: parser) -> T) + -> @ast::expr + { + let cm = ecx.session().parse_sess.cm; + let str = @codemap::span_to_snippet(body.span, cm); + let (fname, ss) = codemap::get_substr_info + (cm, body.span.lo, body.span.hi); + let node = parse_from_source_str + (f, fname, some(ss), str, + ecx.session().opts.cfg, ecx.session().parse_sess); + ret expand_qquote(ecx, node.span(), some(*str), node); + } + + ret alt what { + "expr" {finish(ecx, body, parser::parse_expr)} + "ty" {finish(ecx, body, parse_ty)} + "item" {finish(ecx, body, parse_item)} + "stmt" {finish(ecx, body, parse_stmt)} + "pat" {finish(ecx, body, parser::parse_pat)} + _ {ecx.span_fatal(_sp, "unsupported ast type")} + }; } -fn expand_qquote(ecx: ext_ctxt, sp: span, maybe_str: option::t, - e: @ast::expr) +fn parse_ty(p: parser) -> @ast::ty { + parser::parse_ty(p, false) +} + +fn parse_stmt(p: parser) -> @ast::stmt { + parser::parse_stmt(p, []) +} + +fn parse_item(p: parser) -> @ast::item { + alt (parser::parse_item(p, [])) { + some(item) {item} + none {fail; /* FIXME: Error message, somehow */} + } +} + +fn expand_qquote + (ecx: ext_ctxt, sp: span, maybe_str: option::t, node: N) -> @ast::expr { let str = alt(maybe_str) { some(s) {s} none {codemap::span_to_snippet(sp, ecx.session().parse_sess.cm)} }; - let qcx = gather_anti_quotes(sp.lo, e); + let qcx = gather_anti_quotes(sp.lo, node); let cx = qcx; let prev = 0u; for {lo: lo, _} in cx.gather { @@ -107,8 +195,10 @@ fn expand_qquote(ecx: ext_ctxt, sp: span, maybe_str: option::t, []); let pcall = mk_call(cx,sp, ["syntax", "parse", "parser", - "parse_expr_from_source_str"], - [mk_str(cx,sp, ""), + "parse_from_source_str"], + [node.mk_parse_fn(cx,sp), + mk_str(cx,sp, ""), + mk_path(cx,sp, ["option","none"]), mk_unary(cx,sp, ast::box(ast::imm), mk_str(cx,sp, str2)), mk_access_(cx,sp, diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 94fa51cc814..2327350eb82 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -2548,13 +2548,13 @@ fn parse_from_source_str(f: fn (p: parser) -> T, name: str, ss: codemap::file_substr, source: @str, cfg: ast::crate_cfg, sess: parse_sess) - -> {node: T, fm: codemap::filemap} + -> T { let p = new_parser_from_source_str(sess, cfg, name, ss, source); let r = f(p); sess.chpos = p.reader.chpos; sess.byte_pos = sess.byte_pos + p.reader.pos; - ret {node: r, fm: option::get(vec::last(sess.cm.files))}; + ret r; } fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,