Generalized lookahead

This commit is contained in:
Aleksey Kladov 2018-01-08 22:40:14 +03:00
parent bdddfc9eb8
commit 0cf2d6afee
6 changed files with 78 additions and 38 deletions

View File

@ -9,16 +9,15 @@ pub(super) fn outer_attributes(_: &mut Parser) {
fn attribute(p: &mut Parser, inner: bool) -> bool {
let attr_start = inner && p.lookahead(&[POUND, EXCL, L_BRACK])
|| !inner && p.lookahead(&[POUND, L_BRACK]);
if !attr_start {
return false;
}
node(p, ATTR, |p| {
p.bump_n(if inner { 3 } else { 2 });
fn attr_tail(p: &mut Parser) {
meta_item(p) && p.expect(R_BRACK);
});
true
}
if inner {
node_if(p, [POUND, EXCL, L_BRACK], ATTR, attr_tail)
} else {
node_if(p, [POUND, L_BRACK], ATTR, attr_tail)
}
}
fn meta_item(p: &mut Parser) -> bool {

View File

@ -1,16 +1,11 @@
use super::*;
pub(super) fn literal(p: &mut Parser) -> bool {
match p.current() {
TRUE_KW | FALSE_KW
| INT_NUMBER | FLOAT_NUMBER
| BYTE | CHAR
|STRING | RAW_STRING | BYTE_STRING | RAW_BYTE_STRING => {
node(p, LITERAL, |p| {
p.bump();
});
true
}
_ => false
}
let literals = [
TRUE_KW, FALSE_KW,
INT_NUMBER, FLOAT_NUMBER,
BYTE, CHAR,
STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING,
];
node_if(p, AnyOf(&literals), LITERAL, |_| ())
}

View File

@ -58,7 +58,7 @@ fn struct_field(p: &mut Parser) -> bool {
fn fn_item(p: &mut Parser) {
p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN)
&& p.curly_block(|p| ());
&& p.curly_block(|_| ());
}

View File

@ -18,13 +18,13 @@ pub(crate) fn file(p: &mut Parser) {
fn visibility(_: &mut Parser) {
}
fn node_if<F: FnOnce(&mut Parser)>(
fn node_if<F: FnOnce(&mut Parser), L: Lookahead>(
p: &mut Parser,
first: SyntaxKind,
first: L,
node_kind: SyntaxKind,
rest: F
) -> bool {
p.current() == first && { node(p, node_kind, |p| { p.bump(); rest(p); }); true }
first.is_ahead(p) && { node(p, node_kind, |p| { L::consume(p); rest(p); }); true }
}
fn node<F: FnOnce(&mut Parser)>(p: &mut Parser, node_kind: SyntaxKind, rest: F) {
@ -99,13 +99,63 @@ impl<'p> Parser<'p> {
}
}
fn bump_n(&mut self, n: u8) {
for _ in 0..n {
self.bump();
}
}
fn eat(&mut self, kind: SyntaxKind) -> bool {
self.current() == kind && { self.bump(); true }
}
}
trait Lookahead: Copy {
fn is_ahead(self, p: &Parser) -> bool;
fn consume(p: &mut Parser);
}
impl Lookahead for SyntaxKind {
fn is_ahead(self, p: &Parser) -> bool {
p.current() == self
}
fn consume(p: &mut Parser) {
p.bump();
}
}
impl Lookahead for [SyntaxKind; 2] {
fn is_ahead(self, p: &Parser) -> bool {
p.current() == self[0]
&& p.raw_lookahead(1) == self[1]
}
fn consume(p: &mut Parser) {
p.bump();
p.bump();
}
}
impl Lookahead for [SyntaxKind; 3] {
fn is_ahead(self, p: &Parser) -> bool {
p.current() == self[0]
&& p.raw_lookahead(1) == self[1]
&& p.raw_lookahead(2) == self[2]
}
fn consume(p: &mut Parser) {
p.bump();
p.bump();
p.bump();
}
}
#[derive(Clone, Copy)]
struct AnyOf<'a>(&'a [SyntaxKind]);
impl<'a> Lookahead for AnyOf<'a> {
fn is_ahead(self, p: &Parser) -> bool {
let curr = p.current();
self.0.iter().any(|&k| k == curr)
}
fn consume(p: &mut Parser) {
p.bump();
}
}

View File

@ -88,12 +88,8 @@ impl<'t> Parser<'t> {
kind
}
pub(crate) fn lookahead(&self, kinds: &[SyntaxKind]) -> bool {
if self.tokens[self.pos..].len() < kinds.len() {
return false
}
kinds.iter().zip(self.tokens[self.pos..].iter().map(|t| t.kind))
.all(|(&k1, k2)| k1 == k2)
pub(crate) fn raw_lookahead(&self, n: usize) -> SyntaxKind {
self.tokens.get(self.pos + n).map(|t| t.kind).unwrap_or(EOF)
}
pub(crate) fn curly_block<F: FnOnce(&mut Parser)>(&mut self, f: F) -> bool {

View File

@ -56,4 +56,4 @@ fn is_insignificant(kind: SyntaxKind) -> bool {
WHITESPACE | COMMENT => true,
_ => false,
}
}
}