Skip to content

Commit 56f7de5

Browse files
paulstansifergraydon
authored andcommitted
---
yaml --- r: 3396 b: refs/heads/master c: c3901cd h: refs/heads/master v: v3
1 parent 9755c04 commit 56f7de5

File tree

16 files changed

+291
-61
lines changed

16 files changed

+291
-61
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: b6326817803079ed33b13b87429ef7d77ce5f4cb
2+
refs/heads/master: c3901cdf8e1723dc07b5bfa202fe31b573d44561

trunk/src/comp/front/ext.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1-
1+
import std::vec;
22
import std::option;
33
import std::map::hashmap;
44
import driver::session::session;
55
import front::parser::parser;
66
import util::common::span;
77
import util::common::new_str_hash;
88

9-
type syntax_expander =
10-
fn(&ext_ctxt, span, &vec[@ast::expr], option::t[str]) -> @ast::expr ;
11-
12-
13-
// Temporary: to introduce a tag in order to make a recursive type work
14-
tag syntax_extension { x(syntax_expander); }
9+
type syntax_expander =
10+
fn(&ext_ctxt, span, &vec[@ast::expr], option::t[str]) -> @ast::expr;
11+
type macro_definer = fn(&ext_ctxt, span, &vec[@ast::expr],
12+
option::t[str]) -> tup(str, syntax_extension);
1513

14+
tag syntax_extension {
15+
normal(syntax_expander);
16+
macro_defining(macro_definer);
17+
}
1618

1719
// A temporary hard-coded map of methods for expanding syntax extension
1820
// AST nodes into full ASTs
1921
fn syntax_expander_table() -> hashmap[str, syntax_extension] {
2022
auto syntax_expanders = new_str_hash[syntax_extension]();
21-
syntax_expanders.insert("fmt", x(extfmt::expand_syntax_ext));
22-
syntax_expanders.insert("env", x(extenv::expand_syntax_ext));
23+
syntax_expanders.insert("fmt", normal(extfmt::expand_syntax_ext));
24+
syntax_expanders.insert("env", normal(extenv::expand_syntax_ext));
25+
syntax_expanders.insert("simplext",
26+
macro_defining(extsimplext::add_new_extension));
2327
ret syntax_expanders;
2428
}
2529

@@ -51,6 +55,37 @@ fn mk_ctxt(parser parser) -> ext_ctxt {
5155
span_unimpl=ext_span_unimpl,
5256
next_id=ext_next_id);
5357
}
58+
59+
fn expr_to_str(&ext_ctxt cx, @ast::expr expr, str error) -> str {
60+
alt (expr.node) {
61+
case (ast::expr_lit(?l)) {
62+
alt (l.node) {
63+
case (ast::lit_str(?s, _)) { ret s; }
64+
case (_) { cx.span_fatal(l.span, error); }
65+
}
66+
}
67+
case (_) { cx.span_fatal(expr.span, error); }
68+
}
69+
}
70+
71+
fn expr_to_ident(&ext_ctxt cx, @ast::expr expr, str error) -> ast::ident {
72+
alt(expr.node) {
73+
case (ast::expr_path(?p)) {
74+
if (vec::len(p.node.types) > 0u
75+
|| vec::len(p.node.idents) != 1u) {
76+
cx.span_fatal(expr.span, error);
77+
} else {
78+
ret p.node.idents.(0);
79+
}
80+
}
81+
case (_) {
82+
cx.span_fatal(expr.span, error);
83+
}
84+
}
85+
}
86+
87+
88+
5489
//
5590
// Local Variables:
5691
// mode: rust

trunk/src/comp/front/extenv.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,13 @@ fn expand_syntax_ext(&ext_ctxt cx, common::span sp, &vec[@ast::expr] args,
2121
// FIXME: if this was more thorough it would manufacture an
2222
// option::t[str] rather than just an maybe-empty string.
2323

24-
auto var = expr_to_str(cx, args.(0));
24+
auto var = expr_to_str(cx, args.(0), "#env requires a string");
2525
alt (generic_os::getenv(var)) {
2626
case (option::none) { ret make_new_str(cx, sp, ""); }
2727
case (option::some(?s)) { ret make_new_str(cx, sp, s); }
2828
}
2929
}
3030

31-
32-
// FIXME: duplicate code copied from extfmt:
33-
fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str {
34-
alt (expr.node) {
35-
case (ast::expr_lit(?l)) {
36-
alt (l.node) {
37-
case (ast::lit_str(?s, _)) { ret s; }
38-
case (_) { cx.span_fatal(l.span, "malformed #env call"); }
39-
}
40-
}
41-
case (_) { cx.span_fatal(expr.span, "malformed #env call"); }
42-
}
43-
}
44-
4531
fn make_new_lit(&ext_ctxt cx, common::span sp, ast::lit_ lit) -> @ast::expr {
4632
auto sp_lit = @rec(node=lit, span=sp);
4733
ret @rec(id=cx.next_id(), node=ast::expr_lit(sp_lit), span=sp);

trunk/src/comp/front/extfmt.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ fn expand_syntax_ext(&ext_ctxt cx, common::span sp, &vec[@ast::expr] args,
2020
if (vec::len[@ast::expr](args) == 0u) {
2121
cx.span_fatal(sp, "#fmt requires a format string");
2222
}
23-
auto fmt = expr_to_str(cx, args.(0));
23+
auto fmt = expr_to_str(cx, args.(0), "first argument to #fmt must be a "
24+
+ "string literal.");
2425
auto fmtspan = args.(0).span;
2526
log "Format string:";
2627
log fmt;
@@ -32,20 +33,6 @@ fn expand_syntax_ext(&ext_ctxt cx, common::span sp, &vec[@ast::expr] args,
3233
ret pieces_to_expr(cx, sp, pieces, args);
3334
}
3435

35-
fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str {
36-
auto err_msg = "first argument to #fmt must be a string literal";
37-
alt (expr.node) {
38-
case (ast::expr_lit(?l)) {
39-
alt (l.node) {
40-
case (ast::lit_str(?s, _)) { ret s; }
41-
case (_) { cx.span_fatal(l.span, err_msg); }
42-
}
43-
}
44-
case (_) { cx.span_fatal(expr.span, err_msg); }
45-
}
46-
}
47-
48-
4936
// FIXME: A lot of these functions for producing expressions can probably
5037
// be factored out in common with other code that builds expressions.
5138
// FIXME: Cleanup the naming of these functions

trunk/src/comp/front/extsimplext.rs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
use std;
2+
3+
import util::common::span;
4+
import std::vec;
5+
import std::option;
6+
import vec::map;
7+
import vec::len;
8+
import option::some;
9+
import option::none;
10+
11+
import ext::syntax_extension;
12+
import ext::ext_ctxt;
13+
import ext::normal;
14+
import ext::expr_to_str;
15+
import ext::expr_to_ident;
16+
17+
import fold::*;
18+
import ast::ident;
19+
import ast::path_;
20+
import ast::expr_path;
21+
22+
export add_new_extension;
23+
24+
25+
//temporary, until 'position' shows up in the snapshot
26+
fn position[T](&T x, &vec[T] v) -> option::t[uint] {
27+
let uint i = 0u;
28+
while (i < len(v)) {
29+
if (x == v.(i)) { ret some[uint](i); }
30+
i += 1u;
31+
}
32+
ret none[uint];
33+
}
34+
35+
// substitute, in a position that's required to be an ident
36+
fn subst_ident(&ext_ctxt cx, &vec[@ast::expr] args,
37+
@vec[ident] param_names, &ident i, ast_fold fld) -> ident {
38+
alt (position(i, *param_names)) {
39+
case (some[uint](?idx)) {
40+
ret expr_to_ident(cx, args.(idx),
41+
"This argument is expanded as an "
42+
+ "identifier; it must be one.");
43+
}
44+
case (none[uint]) {
45+
ret i;
46+
}
47+
}
48+
}
49+
50+
fn subst_path(&ext_ctxt cx, &vec[@ast::expr] args,
51+
@vec[ident] param_names, &path_ p, ast_fold fld) -> path_ {
52+
// Don't substitute into qualified names.
53+
if (len(p.types) > 0u || len(p.idents) != 1u) { ret p; }
54+
alt (position(p.idents.(0), *param_names)) {
55+
case (some[uint](?idx)) {
56+
alt (args.(idx).node) {
57+
case (expr_path(?new_path)) {
58+
ret new_path.node;
59+
}
60+
case (_) {
61+
cx.span_fatal(args.(idx).span,
62+
"This argument is expanded as a path; "
63+
+ "it must be one.");
64+
}
65+
}
66+
}
67+
case (none[uint]) { ret p; }
68+
}
69+
}
70+
71+
72+
fn subst_expr(&ext_ctxt cx, &vec[@ast::expr] args, @vec[ident] param_names,
73+
&ast::expr_ e, ast_fold fld,
74+
fn(&ast::expr_, ast_fold) -> ast::expr_ orig) -> ast::expr_ {
75+
ret alt(e) {
76+
case (expr_path(?p)){
77+
// Don't substitute into qualified names.
78+
if (len(p.node.types) > 0u || len(p.node.idents) != 1u) { e }
79+
alt (position(p.node.idents.(0), *param_names)) {
80+
case (some[uint](?idx)) {
81+
args.(idx).node
82+
}
83+
case (none[uint]) { e }
84+
}
85+
}
86+
case (_) { orig(e,fld) }
87+
}
88+
}
89+
90+
91+
fn add_new_extension(&ext_ctxt cx, span sp, &vec[@ast::expr] args,
92+
option::t[str] body) -> tup(str, syntax_extension) {
93+
if (len(args) < 2u) {
94+
cx.span_fatal(sp, "malformed extension description");
95+
}
96+
97+
fn generic_extension(&ext_ctxt cx, span sp, &vec[@ast::expr] args,
98+
option::t[str] body, @vec[ident] param_names,
99+
@ast::expr dest_form) -> @ast::expr {
100+
if (len(args) != len(*param_names)) {
101+
cx.span_fatal(sp, #fmt("extension expects %u arguments, got %u",
102+
len(*param_names), len(args)));
103+
}
104+
105+
auto afp = default_ast_fold();
106+
auto f_pre =
107+
rec(fold_ident = bind subst_ident(cx, args, param_names, _, _),
108+
fold_path = bind subst_path(cx, args, param_names, _, _),
109+
fold_expr = bind subst_expr(cx, args, param_names, _, _,
110+
afp.fold_expr)
111+
with *afp);
112+
auto f = make_fold(f_pre);
113+
auto result = f.fold_expr(dest_form);
114+
dummy_out(f); //temporary: kill circular reference
115+
ret result;
116+
117+
}
118+
119+
let vec[ident] param_names = vec::empty[ident]();
120+
let uint idx = 1u;
121+
while(1u+idx < len(args)) {
122+
param_names +=
123+
[expr_to_ident(cx, args.(idx),
124+
"this parameter name must be an identifier.")];
125+
idx += 1u;
126+
}
127+
128+
ret tup(expr_to_str(cx, args.(0), "first arg must be a literal string."),
129+
normal(bind generic_extension(_,_,_,_,@param_names,
130+
args.(len(args)-1u))));
131+
}
132+
133+
134+
135+
//
136+
// Local Variables:
137+
// mode: rust
138+
// fill-column: 78;
139+
// indent-tabs-mode: nil
140+
// c-basic-offset: 4
141+
// buffer-file-coding-system: utf-8-unix
142+
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
143+
// End:
144+
//

trunk/src/comp/front/parser.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -963,10 +963,19 @@ fn expand_syntax_ext(&parser p, common::span sp, &ast::path path,
963963
auto extname = path.node.idents.(0);
964964
alt (p.get_syntax_expanders().find(extname)) {
965965
case (none) { p.fatal("unknown syntax expander: '" + extname + "'"); }
966-
case (some(ext::x(?ext))) {
966+
case (some(ext::normal(?ext))) {
967967
auto ext_cx = ext::mk_ctxt(p);
968968
ret ast::expr_ext(path, args, body, ext(ext_cx, sp, args, body));
969969
}
970+
// because we have expansion inside parsing, new macros are only
971+
// visible further down the file
972+
case (some(ext::macro_defining(?ext))) {
973+
auto ext_cx = ext::mk_ctxt(p);
974+
auto name_and_extension = ext(ext_cx, sp, args, body);
975+
p.get_syntax_expanders().insert(name_and_extension._0,
976+
name_and_extension._1);
977+
ret ast::expr_tup(vec::empty[ast::elt]());
978+
}
970979
}
971980
}
972981

trunk/src/comp/middle/resolve.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,8 +597,6 @@ fn lookup_in_scope(&env e, scopes sc, &span sp, &ident name, namespace ns) ->
597597
option::t[def] {
598598
fn in_scope(&env e, &span sp, &ident name, &scope s, namespace ns) ->
599599
option::t[def] {
600-
//not recursing through globs
601-
602600
alt (s) {
603601
case (scope_crate(?c)) {
604602
ret lookup_in_local_mod(e, -1, sp, name, ns, inside);

trunk/src/comp/rustc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ mod front {
4848
mod ext;
4949
mod extfmt;
5050
mod extenv;
51+
mod extsimplext;
5152
mod fold;
5253
mod codemap;
5354
mod lexer;

trunk/src/lib/vec.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,24 @@ fn find[T](fn(&T) -> bool f, &vec[T] v) -> option::t[T] {
228228
ret none[T];
229229
}
230230

231+
fn position[T](&T x, &array[T] v) -> option::t[uint] {
232+
let uint i = 0u;
233+
while (i < len(v)) {
234+
if (x == v.(i)) { ret some[uint](i); }
235+
i += 1u;
236+
}
237+
ret none[uint];
238+
}
239+
240+
fn position_pred[T](fn (&T) -> bool f, &vec[T] v) -> option::t[uint] {
241+
let uint i = 0u;
242+
while (i < len(v)) {
243+
if (f(v.(i))) { ret some[uint](i); }
244+
i += 1u;
245+
}
246+
ret none[uint];
247+
}
248+
231249
fn member[T](&T x, &array[T] v) -> bool {
232250
for (T elt in v) { if (x == elt) { ret true; } }
233251
ret false;

trunk/src/test/compile-fail/extenv-not-string-literal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// error-pattern:malformed #env call
1+
// error-pattern:requires a string
22

33
fn main() {
44
#env(10);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//error-pattern:expanded as an identifier
2+
fn main() {
3+
#simplext("mylambda", x, body, {fn f(int x) -> int {ret body}; f});
4+
5+
assert(#mylambda(y*1, y*2)(8) == 16);
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//error-pattern:expects 0 arguments, got 16
2+
3+
fn main() {
4+
#simplext("trivial", 1*2*4*2*1);
5+
6+
assert(#trivial(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) == 16);
7+
}

0 commit comments

Comments
 (0)