Simplify parser a bit

This commit is contained in:
Chris Wong 2015-01-11 11:50:52 +13:00
parent 6a8ce2cf34
commit b826788be4

View file

@ -1,4 +1,5 @@
use syntax::ast::{Expr, Lit, TokenTree, TtDelimited, TtToken}; use syntax::ast::{Expr, Lit, TokenTree, TtDelimited, TtToken};
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::parse; use syntax::parse;
use syntax::parse::parser::Parser as RustParser; use syntax::parse::parser::Parser as RustParser;
@ -11,25 +12,6 @@ macro_rules! guard {
($e:expr) => (if !$e { return false; }) ($e:expr) => (if !$e { return false; })
} }
macro_rules! branch {
($self_:expr;) => (return false);
($self_:expr; $e:expr) => (branch!($self_; $e,));
($self_:expr; $e:expr, $($es:expr),*) => ({
let start_ptr = $self_.input.as_ptr();
if $e {
true
} else {
if $self_.input.as_ptr() == start_ptr {
// Parsing failed, but did not consume input.
// Keep going.
branch!($self_; $($es),*)
} else {
return false;
}
}
})
}
macro_rules! dollar { macro_rules! dollar {
() => (TtToken(_, token::Dollar)) () => (TtToken(_, token::Dollar))
} }
@ -46,7 +28,8 @@ macro_rules! literal {
() => (TtToken(_, token::Literal(..))) () => (TtToken(_, token::Literal(..)))
} }
macro_rules! ident { macro_rules! ident {
($x:pat) => (TtToken(_, token::Ident($x, token::IdentStyle::Plain))) ($x:pat) => (ident!(_, $x));
($sp:pat, $x:pat) => (TtToken($sp, token::Ident($x, token::IdentStyle::Plain)))
} }
pub fn parse(cx: &mut ExtCtxt, input: &[TokenTree]) -> Option<P<Expr>> { pub fn parse(cx: &mut ExtCtxt, input: &[TokenTree]) -> Option<P<Expr>> {
@ -88,36 +71,52 @@ impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> {
match self.input { match self.input {
[] => return true, [] => return true,
[semi!(), ..] => self.shift(1), [semi!(), ..] => self.shift(1),
[ref tt, ..] => { [_, ..] => guard!(self.markup()),
if !self.markup() {
self.render.cx.span_err(tt.get_span(), "invalid syntax");
return false;
}
}
} }
} }
} }
fn markup(&mut self) -> bool { fn markup(&mut self) -> bool {
branch!(self; match self.input {
self.literal(), // Literal
self.splice(),
self.block(),
!self.in_attr && self.element())
}
fn literal(&mut self) -> bool {
let (tt, minus) = match self.input {
[minus!(), ref tt @ literal!(), ..] => { [minus!(), ref tt @ literal!(), ..] => {
self.shift(2); self.shift(2);
(tt, true) self.literal(tt, true)
}, },
[ref tt @ literal!(), ..] => { [ref tt @ literal!(), ..] => {
self.shift(1); self.shift(1);
(tt, false) self.literal(tt, false)
}, },
_ => return false, // Splice
}; [ref tt @ dollar!(), dollar!(), ..] => {
self.shift(2);
self.splice(Escape::PassThru, tt.get_span())
},
[ref tt @ dollar!(), ..] => {
self.shift(1);
self.splice(Escape::Escape, tt.get_span())
},
// Element
[ident!(sp, name), ..] => {
self.shift(1);
self.element(name.as_str(), sp)
},
// Block
[TtDelimited(_, ref d), ..] if d.delim == token::DelimToken::Brace => {
self.shift(1);
self.block(d.tts.as_slice())
},
// ???
_ => {
if let [ref tt, ..] = self.input {
self.render.cx.span_err(tt.get_span(), "invalid syntax");
}
false
},
}
}
fn literal(&mut self, tt: &TokenTree, minus: bool) -> bool {
let lit = self.new_rust_parser(vec![tt.clone()]).parse_lit(); let lit = self.new_rust_parser(vec![tt.clone()]).parse_lit();
match lit_to_string(self.render.cx, lit, minus) { match lit_to_string(self.render.cx, lit, minus) {
Some(s) => self.render.string(s.as_slice(), Escape::Escape), Some(s) => self.render.string(s.as_slice(), Escape::Escape),
@ -126,18 +125,7 @@ impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> {
true true
} }
fn splice(&mut self) -> bool { fn splice(&mut self, escape: Escape, sp: Span) -> bool {
let (escape, sp) = match self.input {
[ref tt @ dollar!(), dollar!(), ..] => {
self.shift(2);
(Escape::PassThru, tt.get_span())
},
[ref tt @ dollar!(), ..] => {
self.shift(1);
(Escape::Escape, tt.get_span())
},
_ => return false,
};
let tt = match self.input { let tt = match self.input {
[ref tt, ..] => { [ref tt, ..] => {
self.shift(1); self.shift(1);
@ -152,15 +140,11 @@ impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> {
true true
} }
fn element(&mut self) -> bool { fn element(&mut self, name: &str, sp: Span) -> bool {
let name = match self.input { if self.in_attr {
[ident!(name), ..] => { self.render.cx.span_err(sp, "unexpected element, you silly bumpkin");
self.shift(1); return false;
name.as_str().to_string() }
},
_ => return false,
};
let name = name.as_slice();
self.render.element_open_start(name); self.render.element_open_start(name);
guard!(self.attrs()); guard!(self.attrs());
self.render.element_open_end(); self.render.element_open_end();
@ -184,18 +168,12 @@ impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> {
true true
} }
fn block(&mut self) -> bool { fn block(&mut self, tts: &[TokenTree]) -> bool {
match self.input { Parser {
[TtDelimited(_, ref d), ..] if d.delim == token::DelimToken::Brace => { in_attr: self.in_attr,
self.shift(1); input: tts,
Parser { render: self.render,
in_attr: self.in_attr, }.markups()
input: d.tts.as_slice(),
render: self.render,
}.markups()
},
_ => false,
}
} }
} }