Skip to content

Commit 1ad0cba

Browse files
committed
regex_macros: simplify using AstBuilder & the improved quoting.
char literals now work in a quotation. There were several instances of duplicated functionality in regex_macros compared to AstBuilder so refactor those out.
1 parent 1d43a98 commit 1ad0cba

File tree

1 file changed

+37
-87
lines changed

1 file changed

+37
-87
lines changed

src/libregex_macros/lib.rs

Lines changed: 37 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424
extern crate regex;
2525
extern crate syntax;
2626

27+
use std::rc::Rc;
28+
2729
use syntax::ast;
2830
use syntax::codemap;
31+
use syntax::ext::build::AstBuilder;
2932
use syntax::ext::base::{
3033
SyntaxExtension, ExtCtxt, MacResult, MacExpr, DummyResult,
3134
NormalTT, BasicMacroExpander,
@@ -112,24 +115,26 @@ impl<'a> NfaGen<'a> {
112115
// expression returned.
113116
let num_cap_locs = 2 * self.prog.num_captures();
114117
let num_insts = self.prog.insts.len();
115-
let cap_names = self.vec_expr(self.names.as_slice(),
116-
|cx, name| match name {
117-
&Some(ref name) => {
118+
let cap_names = self.vec_expr(self.names.as_slice().iter(),
119+
|cx, name| match *name {
120+
Some(ref name) => {
118121
let name = name.as_slice();
119122
quote_expr!(cx, Some(~$name))
120123
}
121-
&None => quote_expr!(cx, None),
124+
None => cx.expr_none(self.sp),
122125
}
123126
);
124127
let prefix_anchor =
125128
match self.prog.insts.as_slice()[1] {
126129
EmptyBegin(flags) if flags & FLAG_MULTI == 0 => true,
127130
_ => false,
128131
};
129-
let init_groups = self.vec_from_fn(num_cap_locs,
130-
|cx| quote_expr!(cx, None));
131-
let prefix_bytes = self.vec_expr(self.prog.prefix.as_slice().as_bytes(),
132-
|cx, b| quote_expr!(cx, $b));
132+
let init_groups = self.vec_expr(range(0, num_cap_locs),
133+
|cx, _| cx.expr_none(self.sp));
134+
135+
let prefix_lit = Rc::new(Vec::from_slice(self.prog.prefix.as_slice().as_bytes()));
136+
let prefix_bytes = self.cx.expr_lit(self.sp, ast::LitBinary(prefix_lit));
137+
133138
let check_prefix = self.check_prefix();
134139
let step_insts = self.step_insts();
135140
let add_insts = self.add_insts();
@@ -320,12 +325,11 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
320325
let nextpc = pc + 1;
321326
let body = match *inst {
322327
EmptyBegin(flags) => {
323-
let nl = '\n';
324328
let cond =
325329
if flags & FLAG_MULTI > 0 {
326330
quote_expr!(self.cx,
327331
self.chars.is_begin()
328-
|| self.chars.prev == Some($nl)
332+
|| self.chars.prev == Some('\n')
329333
)
330334
} else {
331335
quote_expr!(self.cx, self.chars.is_begin())
@@ -336,12 +340,11 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
336340
})
337341
}
338342
EmptyEnd(flags) => {
339-
let nl = '\n';
340343
let cond =
341344
if flags & FLAG_MULTI > 0 {
342345
quote_expr!(self.cx,
343346
self.chars.is_end()
344-
|| self.chars.cur == Some($nl)
347+
|| self.chars.cur == Some('\n')
345348
)
346349
} else {
347350
quote_expr!(self.cx, self.chars.is_end())
@@ -489,16 +492,16 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
489492
if flags & FLAG_DOTNL > 0 {
490493
quote_expr!(self.cx, self.add(nlist, $nextpc, caps))
491494
} else {
492-
let nl = '\n'; // no char lits allowed? wtf?
493495
quote_expr!(self.cx, {
494-
if self.chars.prev != Some($nl) {
496+
if self.chars.prev != Some('\n') {
495497
self.add(nlist, $nextpc, caps)
496498
}
499+
()
497500
})
498501
}
499502
}
500503
// EmptyBegin, EmptyEnd, EmptyWordBoundary, Save, Jump, Split
501-
_ => quote_expr!(self.cx, {}),
504+
_ => self.empty_block(),
502505
};
503506
self.arm_inst(pc, body)
504507
}).collect::<Vec<ast::Arm>>();
@@ -510,36 +513,30 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
510513
// This avoids a binary search (and is hopefully replaced by a jump
511514
// table).
512515
fn match_class(&self, casei: bool, ranges: &[(char, char)]) -> @ast::Expr {
516+
let expr_true = quote_expr!(self.cx, true);
517+
513518
let mut arms = ranges.iter().map(|&(mut start, mut end)| {
514519
if casei {
515520
start = start.to_uppercase();
516521
end = end.to_uppercase();
517522
}
518-
ast::Arm {
519-
attrs: vec!(),
520-
pats: vec!(@ast::Pat{
521-
id: ast::DUMMY_NODE_ID,
522-
span: self.sp,
523-
node: ast::PatRange(quote_expr!(self.cx, $start),
524-
quote_expr!(self.cx, $end)),
525-
}),
526-
guard: None,
527-
body: quote_expr!(self.cx, true),
528-
}
523+
let pat = self.cx.pat(self.sp, ast::PatRange(quote_expr!(self.cx, $start),
524+
quote_expr!(self.cx, $end)));
525+
self.cx.arm(self.sp, vec!(pat), expr_true)
529526
}).collect::<Vec<ast::Arm>>();
530527

531528
arms.push(self.wild_arm_expr(quote_expr!(self.cx, false)));
532529

533530
let match_on = quote_expr!(self.cx, c);
534-
self.dummy_expr(ast::ExprMatch(match_on, arms))
531+
self.cx.expr_match(self.sp, match_on, arms)
535532
}
536533

537534
// Generates code for checking a literal prefix of the search string.
538535
// The code is only generated if the regex *has* a literal prefix.
539536
// Otherwise, a no-op is returned.
540537
fn check_prefix(&self) -> @ast::Expr {
541538
if self.prog.prefix.len() == 0 {
542-
quote_expr!(self.cx, {})
539+
self.empty_block()
543540
} else {
544541
quote_expr!(self.cx,
545542
if clist.size == 0 {
@@ -562,24 +559,20 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
562559
// never be used, but is added to satisfy the compiler complaining about
563560
// non-exhaustive patterns.
564561
fn match_insts(&self, mut arms: Vec<ast::Arm>) -> @ast::Expr {
565-
let mat_pc = quote_expr!(self.cx, pc);
566-
arms.push(self.wild_arm_expr(quote_expr!(self.cx, {})));
567-
self.dummy_expr(ast::ExprMatch(mat_pc, arms))
562+
arms.push(self.wild_arm_expr(self.empty_block()));
563+
self.cx.expr_match(self.sp, quote_expr!(self.cx, pc), arms)
564+
}
565+
566+
fn empty_block(&self) -> @ast::Expr {
567+
quote_expr!(self.cx, {})
568568
}
569569

570570
// Creates a match arm for the instruction at `pc` with the expression
571571
// `body`.
572572
fn arm_inst(&self, pc: uint, body: @ast::Expr) -> ast::Arm {
573-
ast::Arm {
574-
attrs: vec!(),
575-
pats: vec!(@ast::Pat{
576-
id: ast::DUMMY_NODE_ID,
577-
span: self.sp,
578-
node: ast::PatLit(quote_expr!(self.cx, $pc)),
579-
}),
580-
guard: None,
581-
body: body,
582-
}
573+
let pc_pat = self.cx.pat_lit(self.sp, quote_expr!(self.cx, $pc));
574+
575+
self.cx.arm(self.sp, vec!(pc_pat), body)
583576
}
584577

585578
// Creates a wild-card match arm with the expression `body`.
@@ -596,56 +589,13 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
596589
}
597590
}
598591

599-
// Builds a `[a, b, .., len]` expression where each element is the result
600-
// of executing `to_expr`.
601-
fn vec_from_fn(&self, len: uint, to_expr: |&ExtCtxt| -> @ast::Expr)
602-
-> @ast::Expr {
603-
self.vec_expr(Vec::from_elem(len, ()).as_slice(),
604-
|cx, _| to_expr(cx))
605-
}
606592

607593
// Converts `xs` to a `[x1, x2, .., xN]` expression by calling `to_expr`
608594
// on each element in `xs`.
609-
fn vec_expr<T>(&self, xs: &[T], to_expr: |&ExtCtxt, &T| -> @ast::Expr)
595+
fn vec_expr<T, It: Iterator<T>>(&self, xs: It, to_expr: |&ExtCtxt, T| -> @ast::Expr)
610596
-> @ast::Expr {
611-
let mut exprs = vec!();
612-
for x in xs.iter() {
613-
exprs.push(to_expr(self.cx, x))
614-
}
615-
let vec_exprs = self.dummy_expr(ast::ExprVec(exprs));
616-
quote_expr!(self.cx, $vec_exprs)
617-
}
618-
619-
// Creates an expression with a dummy node ID given an underlying
620-
// `ast::Expr_`.
621-
fn dummy_expr(&self, e: ast::Expr_) -> @ast::Expr {
622-
@ast::Expr {
623-
id: ast::DUMMY_NODE_ID,
624-
node: e,
625-
span: self.sp,
626-
}
627-
}
628-
}
629-
630-
// This trait is defined in the quote module in the syntax crate, but I
631-
// don't think it's exported.
632-
// Interestingly, quote_expr! only requires that a 'to_tokens' method be
633-
// defined rather than satisfying a particular trait.
634-
#[doc(hidden)]
635-
trait ToTokens {
636-
fn to_tokens(&self, cx: &ExtCtxt) -> Vec<ast::TokenTree>;
637-
}
638-
639-
impl ToTokens for char {
640-
fn to_tokens(&self, _: &ExtCtxt) -> Vec<ast::TokenTree> {
641-
vec!(ast::TTTok(codemap::DUMMY_SP, token::LIT_CHAR((*self) as u32)))
642-
}
643-
}
644-
645-
impl ToTokens for bool {
646-
fn to_tokens(&self, _: &ExtCtxt) -> Vec<ast::TokenTree> {
647-
let ident = token::IDENT(token::str_to_ident(self.to_str()), false);
648-
vec!(ast::TTTok(codemap::DUMMY_SP, ident))
597+
let exprs = xs.map(|x| to_expr(self.cx, x)).collect();
598+
self.cx.expr_vec(self.sp, exprs)
649599
}
650600
}
651601

0 commit comments

Comments
 (0)