Skip to content

Commit 6dcd12d

Browse files
committed
Implement quasi-quoting of multiple syntatic categories.
1 parent 35a199c commit 6dcd12d

File tree

3 files changed

+114
-24
lines changed

3 files changed

+114
-24
lines changed

src/comp/syntax/ext/expand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import vec;
88
import syntax::ast::{crate, expr_, expr_mac, mac_invoc, mac_qq};
99
import syntax::fold::*;
1010
import syntax::ext::base::*;
11-
import syntax::ext::qquote::expand_qquote;
11+
import syntax::ext::qquote::{expand_qquote,qq_helper};
1212
import syntax::parse::parser::parse_expr_from_source_str;
1313

1414
import codemap::span;

src/comp/syntax/ext/qquote.rs

Lines changed: 111 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import syntax::visit::*;
99
import syntax::ext::base::*;
1010
import syntax::ext::build::*;
1111
import syntax::parse::parser;
12-
import syntax::parse::parser::{parse_from_source_str};
12+
import syntax::parse::parser::{parser, parse_from_source_str};
1313

1414
import syntax::print::*;
1515
import std::io::*;
@@ -19,12 +19,53 @@ import codemap::span;
1919
type aq_ctxt = @{lo: uint,
2020
mutable gather: [{lo: uint, hi: uint, e: @ast::expr}]};
2121

22-
fn gather_anti_quotes(lo: uint, e: @ast::expr) -> aq_ctxt
22+
iface qq_helper {
23+
fn span() -> span;
24+
fn visit(aq_ctxt, vt<aq_ctxt>);
25+
fn mk_parse_fn(ext_ctxt,span) -> @ast::expr;
26+
}
27+
impl of qq_helper for @ast::expr {
28+
fn span() -> span {self.span}
29+
fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_expr(self, cx, v);}
30+
fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
31+
mk_path(cx, sp, ["syntax", "parse", "parser", "parse_expr"])
32+
}
33+
}
34+
impl of qq_helper for @ast::ty {
35+
fn span() -> span {self.span}
36+
fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_ty(self, cx, v);}
37+
fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
38+
mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_ty"])
39+
}
40+
}
41+
impl of qq_helper for @ast::item {
42+
fn span() -> span {self.span}
43+
fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_item(self, cx, v);}
44+
fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
45+
mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_item"])
46+
}
47+
}
48+
impl of qq_helper for @ast::stmt {
49+
fn span() -> span {self.span}
50+
fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_stmt(self, cx, v);}
51+
fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
52+
mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_stmt"])
53+
}
54+
}
55+
impl of qq_helper for @ast::pat {
56+
fn span() -> span {self.span}
57+
fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_pat(self, cx, v);}
58+
fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
59+
mk_path(cx, sp, ["syntax", "parse", "parser", "parse_pat"])
60+
}
61+
}
62+
63+
fn gather_anti_quotes<N: qq_helper>(lo: uint, node: N) -> aq_ctxt
2364
{
2465
let v = @{visit_expr: visit_expr_aq
2566
with *default_visitor()};
2667
let cx = @{lo:lo, mutable gather: []};
27-
visit_expr_aq(e, cx, mk_vt(v));
68+
node.visit(cx, mk_vt(v));
2869
ret cx;
2970
}
3071

@@ -43,31 +84,78 @@ fn is_space(c: char) -> bool {
4384
syntax::parse::lexer::is_whitespace(c)
4485
}
4586

46-
fn expand_ast(ecx: ext_ctxt, _sp: span, _arg:
47-
ast::mac_arg, body: ast::mac_body)
87+
fn expand_ast(ecx: ext_ctxt, _sp: span,
88+
arg: ast::mac_arg, body: ast::mac_body)
4889
-> @ast::expr
4990
{
91+
let what = "expr";
92+
option::may(arg) {|arg|
93+
let args: [@ast::expr] =
94+
alt arg.node {
95+
ast::expr_vec(elts, _) { elts }
96+
_ {
97+
ecx.span_fatal
98+
(_sp, "#ast requires arguments of the form `[...]`.")
99+
}
100+
};
101+
if vec::len::<@ast::expr>(args) != 1u {
102+
ecx.span_fatal(_sp, "#ast requires exactly one arg");
103+
}
104+
alt (args[0].node) {
105+
ast::expr_path(@{node: {idents: id, _},_}) if vec::len(id) == 1u
106+
{what = id[0]}
107+
_ {ecx.span_fatal(args[0].span, "expected an identifier");}
108+
}
109+
}
50110
let body = get_mac_body(ecx,_sp,body);
51-
let cm = ecx.session().parse_sess.cm;
52-
let str = @codemap::span_to_snippet(body.span, cm);
53-
let (fname, ss) = codemap::get_substr_info(cm,
54-
body.span.lo, body.span.hi);
55-
let {node: e, _} = parse_from_source_str(parser::parse_expr,
56-
fname, some(ss), str,
57-
ecx.session().opts.cfg,
58-
ecx.session().parse_sess);
59-
ret expand_qquote(ecx, e.span, some(*str), e);
60-
}
61-
62-
fn expand_qquote(ecx: ext_ctxt, sp: span, maybe_str: option::t<str>,
63-
e: @ast::expr)
111+
fn finish<T: qq_helper>(ecx: ext_ctxt, body: ast::mac_body_,
112+
f: fn (p: parser) -> T)
113+
-> @ast::expr
114+
{
115+
let cm = ecx.session().parse_sess.cm;
116+
let str = @codemap::span_to_snippet(body.span, cm);
117+
let (fname, ss) = codemap::get_substr_info
118+
(cm, body.span.lo, body.span.hi);
119+
let node = parse_from_source_str
120+
(f, fname, some(ss), str,
121+
ecx.session().opts.cfg, ecx.session().parse_sess);
122+
ret expand_qquote(ecx, node.span(), some(*str), node);
123+
}
124+
125+
ret alt what {
126+
"expr" {finish(ecx, body, parser::parse_expr)}
127+
"ty" {finish(ecx, body, parse_ty)}
128+
"item" {finish(ecx, body, parse_item)}
129+
"stmt" {finish(ecx, body, parse_stmt)}
130+
"pat" {finish(ecx, body, parser::parse_pat)}
131+
_ {ecx.span_fatal(_sp, "unsupported ast type")}
132+
};
133+
}
134+
135+
fn parse_ty(p: parser) -> @ast::ty {
136+
parser::parse_ty(p, false)
137+
}
138+
139+
fn parse_stmt(p: parser) -> @ast::stmt {
140+
parser::parse_stmt(p, [])
141+
}
142+
143+
fn parse_item(p: parser) -> @ast::item {
144+
alt (parser::parse_item(p, [])) {
145+
some(item) {item}
146+
none {fail; /* FIXME: Error message, somehow */}
147+
}
148+
}
149+
150+
fn expand_qquote<N: qq_helper>
151+
(ecx: ext_ctxt, sp: span, maybe_str: option::t<str>, node: N)
64152
-> @ast::expr
65153
{
66154
let str = alt(maybe_str) {
67155
some(s) {s}
68156
none {codemap::span_to_snippet(sp, ecx.session().parse_sess.cm)}
69157
};
70-
let qcx = gather_anti_quotes(sp.lo, e);
158+
let qcx = gather_anti_quotes(sp.lo, node);
71159
let cx = qcx;
72160
let prev = 0u;
73161
for {lo: lo, _} in cx.gather {
@@ -107,8 +195,10 @@ fn expand_qquote(ecx: ext_ctxt, sp: span, maybe_str: option::t<str>,
107195
[]);
108196
let pcall = mk_call(cx,sp,
109197
["syntax", "parse", "parser",
110-
"parse_expr_from_source_str"],
111-
[mk_str(cx,sp, "<anon>"),
198+
"parse_from_source_str"],
199+
[node.mk_parse_fn(cx,sp),
200+
mk_str(cx,sp, "<anon>"),
201+
mk_path(cx,sp, ["option","none"]),
112202
mk_unary(cx,sp, ast::box(ast::imm),
113203
mk_str(cx,sp, str2)),
114204
mk_access_(cx,sp,

src/comp/syntax/parse/parser.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,13 +2548,13 @@ fn parse_from_source_str<T>(f: fn (p: parser) -> T,
25482548
name: str, ss: codemap::file_substr,
25492549
source: @str, cfg: ast::crate_cfg,
25502550
sess: parse_sess)
2551-
-> {node: T, fm: codemap::filemap}
2551+
-> T
25522552
{
25532553
let p = new_parser_from_source_str(sess, cfg, name, ss, source);
25542554
let r = f(p);
25552555
sess.chpos = p.reader.chpos;
25562556
sess.byte_pos = sess.byte_pos + p.reader.pos;
2557-
ret {node: r, fm: option::get(vec::last(sess.cm.files))};
2557+
ret r;
25582558
}
25592559

25602560
fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,

0 commit comments

Comments
 (0)