Skip to content

More regex_macros tweaks & some quasiquoter/AST fixes #13879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 2, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 37 additions & 87 deletions src/libregex_macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
extern crate regex;
extern crate syntax;

use std::rc::Rc;

use syntax::ast;
use syntax::codemap;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{
SyntaxExtension, ExtCtxt, MacResult, MacExpr, DummyResult,
NormalTT, BasicMacroExpander,
Expand Down Expand Up @@ -112,24 +115,26 @@ impl<'a> NfaGen<'a> {
// expression returned.
let num_cap_locs = 2 * self.prog.num_captures();
let num_insts = self.prog.insts.len();
let cap_names = self.vec_expr(self.names.as_slice(),
|cx, name| match name {
&Some(ref name) => {
let cap_names = self.vec_expr(self.names.as_slice().iter(),
|cx, name| match *name {
Some(ref name) => {
let name = name.as_slice();
quote_expr!(cx, Some(~$name))
}
&None => quote_expr!(cx, None),
None => cx.expr_none(self.sp),
}
);
let prefix_anchor =
match self.prog.insts.as_slice()[1] {
EmptyBegin(flags) if flags & FLAG_MULTI == 0 => true,
_ => false,
};
let init_groups = self.vec_from_fn(num_cap_locs,
|cx| quote_expr!(cx, None));
let prefix_bytes = self.vec_expr(self.prog.prefix.as_slice().as_bytes(),
|cx, b| quote_expr!(cx, $b));
let init_groups = self.vec_expr(range(0, num_cap_locs),
|cx, _| cx.expr_none(self.sp));

let prefix_lit = Rc::new(Vec::from_slice(self.prog.prefix.as_slice().as_bytes()));
let prefix_bytes = self.cx.expr_lit(self.sp, ast::LitBinary(prefix_lit));

let check_prefix = self.check_prefix();
let step_insts = self.step_insts();
let add_insts = self.add_insts();
Expand Down Expand Up @@ -320,12 +325,11 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
let nextpc = pc + 1;
let body = match *inst {
EmptyBegin(flags) => {
let nl = '\n';
let cond =
if flags & FLAG_MULTI > 0 {
quote_expr!(self.cx,
self.chars.is_begin()
|| self.chars.prev == Some($nl)
|| self.chars.prev == Some('\n')
)
} else {
quote_expr!(self.cx, self.chars.is_begin())
Expand All @@ -336,12 +340,11 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
})
}
EmptyEnd(flags) => {
let nl = '\n';
let cond =
if flags & FLAG_MULTI > 0 {
quote_expr!(self.cx,
self.chars.is_end()
|| self.chars.cur == Some($nl)
|| self.chars.cur == Some('\n')
)
} else {
quote_expr!(self.cx, self.chars.is_end())
Expand Down Expand Up @@ -489,16 +492,16 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
if flags & FLAG_DOTNL > 0 {
quote_expr!(self.cx, self.add(nlist, $nextpc, caps))
} else {
let nl = '\n'; // no char lits allowed? wtf?
quote_expr!(self.cx, {
if self.chars.prev != Some($nl) {
if self.chars.prev != Some('\n') {
self.add(nlist, $nextpc, caps)
}
()
})
}
}
// EmptyBegin, EmptyEnd, EmptyWordBoundary, Save, Jump, Split
_ => quote_expr!(self.cx, {}),
_ => self.empty_block(),
};
self.arm_inst(pc, body)
}).collect::<Vec<ast::Arm>>();
Expand All @@ -510,36 +513,30 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
// This avoids a binary search (and is hopefully replaced by a jump
// table).
fn match_class(&self, casei: bool, ranges: &[(char, char)]) -> @ast::Expr {
let expr_true = quote_expr!(self.cx, true);

let mut arms = ranges.iter().map(|&(mut start, mut end)| {
if casei {
start = start.to_uppercase();
end = end.to_uppercase();
}
ast::Arm {
attrs: vec!(),
pats: vec!(@ast::Pat{
id: ast::DUMMY_NODE_ID,
span: self.sp,
node: ast::PatRange(quote_expr!(self.cx, $start),
quote_expr!(self.cx, $end)),
}),
guard: None,
body: quote_expr!(self.cx, true),
}
let pat = self.cx.pat(self.sp, ast::PatRange(quote_expr!(self.cx, $start),
quote_expr!(self.cx, $end)));
self.cx.arm(self.sp, vec!(pat), expr_true)
}).collect::<Vec<ast::Arm>>();

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

let match_on = quote_expr!(self.cx, c);
self.dummy_expr(ast::ExprMatch(match_on, arms))
self.cx.expr_match(self.sp, match_on, arms)
}

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

fn empty_block(&self) -> @ast::Expr {
quote_expr!(self.cx, {})
}

// Creates a match arm for the instruction at `pc` with the expression
// `body`.
fn arm_inst(&self, pc: uint, body: @ast::Expr) -> ast::Arm {
ast::Arm {
attrs: vec!(),
pats: vec!(@ast::Pat{
id: ast::DUMMY_NODE_ID,
span: self.sp,
node: ast::PatLit(quote_expr!(self.cx, $pc)),
}),
guard: None,
body: body,
}
let pc_pat = self.cx.pat_lit(self.sp, quote_expr!(self.cx, $pc));

self.cx.arm(self.sp, vec!(pc_pat), body)
}

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

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

// Converts `xs` to a `[x1, x2, .., xN]` expression by calling `to_expr`
// on each element in `xs`.
fn vec_expr<T>(&self, xs: &[T], to_expr: |&ExtCtxt, &T| -> @ast::Expr)
fn vec_expr<T, It: Iterator<T>>(&self, xs: It, to_expr: |&ExtCtxt, T| -> @ast::Expr)
-> @ast::Expr {
let mut exprs = vec!();
for x in xs.iter() {
exprs.push(to_expr(self.cx, x))
}
let vec_exprs = self.dummy_expr(ast::ExprVec(exprs));
quote_expr!(self.cx, $vec_exprs)
}

// Creates an expression with a dummy node ID given an underlying
// `ast::Expr_`.
fn dummy_expr(&self, e: ast::Expr_) -> @ast::Expr {
@ast::Expr {
id: ast::DUMMY_NODE_ID,
node: e,
span: self.sp,
}
}
}

// This trait is defined in the quote module in the syntax crate, but I
// don't think it's exported.
// Interestingly, quote_expr! only requires that a 'to_tokens' method be
// defined rather than satisfying a particular trait.
#[doc(hidden)]
trait ToTokens {
fn to_tokens(&self, cx: &ExtCtxt) -> Vec<ast::TokenTree>;
}

impl ToTokens for char {
fn to_tokens(&self, _: &ExtCtxt) -> Vec<ast::TokenTree> {
vec!(ast::TTTok(codemap::DUMMY_SP, token::LIT_CHAR((*self) as u32)))
}
}

impl ToTokens for bool {
fn to_tokens(&self, _: &ExtCtxt) -> Vec<ast::TokenTree> {
let ident = token::IDENT(token::str_to_ident(self.to_str()), false);
vec!(ast::TTTok(codemap::DUMMY_SP, ident))
let exprs = xs.map(|x| to_expr(self.cx, x)).collect();
self.cx.expr_vec(self.sp, exprs)
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/librustdoc/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use rustc::metadata::decoder;

use std::local_data;
use std::strbuf::StrBuf;
use std;

use core;
use doctree;
Expand Down Expand Up @@ -1246,7 +1245,7 @@ fn lit_to_str(lit: &ast::Lit) -> ~str {
match lit.node {
ast::LitStr(ref st, _) => st.get().to_owned(),
ast::LitBinary(ref data) => format!("{:?}", data.as_slice()),
ast::LitChar(c) => "'".to_owned() + std::char::from_u32(c).unwrap().to_str() + "'",
ast::LitChar(c) => format!("'{}'", c),
ast::LitInt(i, _t) => i.to_str(),
ast::LitUint(u, _t) => u.to_str(),
ast::LitIntUnsuffixed(i) => i.to_str(),
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ pub type Lit = Spanned<Lit_>;
pub enum Lit_ {
LitStr(InternedString, StrStyle),
LitBinary(Rc<Vec<u8> >),
LitChar(u32),
LitChar(char),
LitInt(i64, IntTy),
LitUint(u64, UintTy),
LitIntUnsuffixed(i64),
Expand Down
4 changes: 1 addition & 3 deletions src/libsyntax/ext/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ use ext::base::*;
use ext::base;
use ext::build::AstBuilder;

use std::char;

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult {
// Gather all argument expressions
let exprs = match get_exprs_from_tts(cx, sp, tts) {
Expand Down Expand Up @@ -59,7 +57,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ->

// char literal, push to vector expression
ast::LitChar(v) => {
if char::from_u32(v).unwrap().is_ascii() {
if v.is_ascii() {
bytes.push(cx.expr_u8(expr.span, v as u8));
} else {
cx.span_err(expr.span, "non-ascii char literal in bytes!")
Expand Down
3 changes: 1 addition & 2 deletions src/libsyntax/ext/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use ext::base;
use ext::build::AstBuilder;
use parse::token;

use std::char;
use std::strbuf::StrBuf;

pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
Expand All @@ -35,7 +34,7 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
accumulator.push_str(s.get());
}
ast::LitChar(c) => {
accumulator.push_char(char::from_u32(c).unwrap());
accumulator.push_char(c);
}
ast::LitInt(i, _) | ast::LitIntUnsuffixed(i) => {
accumulator.push_str(format!("{}", i));
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ impl<'a, 'b> Context<'a, 'b> {

// Translate the format
let fill = match arg.format.fill { Some(c) => c, None => ' ' };
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill as u32));
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
let align = match arg.format.align {
parse::AlignLeft => {
self.ecx.path_global(sp, self.parsepath("AlignLeft"))
Expand Down
23 changes: 23 additions & 0 deletions src/libsyntax/ext/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,26 @@ pub mod rt {
}
}

impl ToSource for () {
fn to_source(&self) -> ~str {
"()".to_owned()
}
}

impl ToSource for bool {
fn to_source(&self) -> ~str {
let lit = dummy_spanned(ast::LitBool(*self));
pprust::lit_to_str(&lit)
}
}

impl ToSource for char {
fn to_source(&self) -> ~str {
let lit = dummy_spanned(ast::LitChar(*self));
pprust::lit_to_str(&lit)
}
}

impl ToSource for int {
fn to_source(&self) -> ~str {
let lit = dummy_spanned(ast::LitInt(*self as i64, ast::TyI));
Expand Down Expand Up @@ -227,6 +247,9 @@ pub mod rt {
impl_to_tokens!(@ast::Expr)
impl_to_tokens!(ast::Block)
impl_to_tokens_self!(&'a str)
impl_to_tokens!(())
impl_to_tokens!(char)
impl_to_tokens!(bool)
impl_to_tokens!(int)
impl_to_tokens!(i8)
impl_to_tokens!(i16)
Expand Down
10 changes: 5 additions & 5 deletions src/libsyntax/parse/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ fn next_token_inner(rdr: &mut StringReader) -> token::Token {
"unterminated character constant".to_owned());
}
bump(rdr); // advance curr past token
return token::LIT_CHAR(c2 as u32);
return token::LIT_CHAR(c2);
}
'"' => {
let mut accum_str = StrBuf::new();
Expand Down Expand Up @@ -1097,17 +1097,17 @@ mod test {

#[test] fn character_a() {
assert_eq!(setup(&mk_sh(), "'a'".to_owned()).next_token().tok,
token::LIT_CHAR('a' as u32));
token::LIT_CHAR('a'));
}

#[test] fn character_space() {
assert_eq!(setup(&mk_sh(), "' '".to_owned()).next_token().tok,
token::LIT_CHAR(' ' as u32));
token::LIT_CHAR(' '));
}

#[test] fn character_escaped() {
assert_eq!(setup(&mk_sh(), "'\\n'".to_owned()).next_token().tok,
token::LIT_CHAR('\n' as u32));
token::LIT_CHAR('\n'));
}

#[test] fn lifetime_name() {
Expand All @@ -1128,7 +1128,7 @@ mod test {

#[test] fn nested_block_comments() {
assert_eq!(setup(&mk_sh(), "/* /* */ */'a'".to_owned()).next_token().tok,
token::LIT_CHAR('a' as u32));
token::LIT_CHAR('a'));
}

}
Loading