about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKevin Atkinson <kevina@cs.utah.edu>2012-02-01 08:01:21 -0700
committerKevin Atkinson <kevina@cs.utah.edu>2012-02-03 20:41:49 -0700
commit6dcd12dc22eb891c726dbf5c1c4177d4e72874d8 (patch)
tree7def5cc5933131b87e0bc3223eaf93e7622e305b
parent35a199c0361946fbab75212c3a7d23ab03520598 (diff)
downloadrust-6dcd12dc22eb891c726dbf5c1c4177d4e72874d8.tar.gz
rust-6dcd12dc22eb891c726dbf5c1c4177d4e72874d8.zip
Implement quasi-quoting of multiple syntatic categories.
-rw-r--r--src/comp/syntax/ext/expand.rs2
-rw-r--r--src/comp/syntax/ext/qquote.rs132
-rw-r--r--src/comp/syntax/parse/parser.rs4
3 files changed, 114 insertions, 24 deletions
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<aq_ctxt>);
+    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<aq_ctxt>) {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<aq_ctxt>) {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<aq_ctxt>) {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<aq_ctxt>) {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<aq_ctxt>) {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<N: qq_helper>(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 expand_qquote(ecx: ext_ctxt, sp: span, maybe_str: option::t<str>,
-                 e: @ast::expr)
+    fn finish<T: qq_helper>(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 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<N: qq_helper>
+    (ecx: ext_ctxt, sp: span, maybe_str: option::t<str>, 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<str>,
                                      []);
     let pcall = mk_call(cx,sp,
                        ["syntax", "parse", "parser",
-                        "parse_expr_from_source_str"],
-                       [mk_str(cx,sp, "<anon>"),
+                        "parse_from_source_str"],
+                       [node.mk_parse_fn(cx,sp),
+                        mk_str(cx,sp, "<anon>"),
+                        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<T>(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,