-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib.rs
103 lines (86 loc) · 2.71 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#[crate_type="dylib"];
#[crate_id="sort"];
#[feature(macro_registrar, managed_boxes)];
extern crate syntax;
use syntax::ast::{Name,
TokenTree,
Expr,
ExprLit,
ExprVec,
LitStr,
DUMMY_NODE_ID,
MutImmutable};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
ExtCtxt,
MacResult,
MRExpr,
NormalTT,
BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};
#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
register(token::intern("sort"),
NormalTT(~BasicMacroExpander {
expander: expand_sort,
span: None,
},
None));
}
struct Entry {
str: InternedString,
expr: @Expr
}
fn expand_sort(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
let mut entries = match parse_entries(cx, tts) {
Some(entries) => entries,
None => return MacResult::dummy_expr(sp),
};
entries.sort_by(|a, b| a.str.cmp(&b.str));
MRExpr(create_slice(sp, entries))
}
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<~[Entry]> {
let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
tts.to_owned());
let mut entries = ~[];
let mut error = false;
while parser.token != EOF {
let entry = parser.parse_expr();
let entry_str = match entry.node {
ExprLit(lit) => {
match lit.node {
LitStr(ref s, _) => s.clone(),
_ => {
cx.span_err(entry.span, "expected string literal");
error = true;
InternedString::new("")
}
}
}
_ => {
cx.span_err(entry.span, "expected string literal");
error = true;
InternedString::new("")
}
};
entries.push(Entry { str: entry_str, expr: entry });
if !parser.eat(&COMMA) && parser.token != EOF {
cx.span_err(parser.span, "expected `,`");
return None;
}
}
if error {
return None;
}
Some(entries)
}
fn create_slice(sp: Span, entries: ~[Entry]) -> @Expr {
let contents: ~[@Expr] = entries.iter().map(|entry| entry.expr).collect();
@Expr {
id: DUMMY_NODE_ID,
node: ExprVec(contents, MutImmutable),
span: sp,
}
}