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 { fn attribute(p: &mut Parser, inner: bool) -> bool {
let attr_start = inner && p.lookahead(&[POUND, EXCL, L_BRACK]) fn attr_tail(p: &mut Parser) {
|| !inner && p.lookahead(&[POUND, L_BRACK]);
if !attr_start {
return false;
}
node(p, ATTR, |p| {
p.bump_n(if inner { 3 } else { 2 });
meta_item(p) && p.expect(R_BRACK); 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 { fn meta_item(p: &mut Parser) -> bool {

View File

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

View File

@ -58,7 +58,7 @@ fn struct_field(p: &mut Parser) -> bool {
fn fn_item(p: &mut Parser) { fn fn_item(p: &mut Parser) {
p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN) 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 visibility(_: &mut Parser) {
} }
fn node_if<F: FnOnce(&mut Parser)>( fn node_if<F: FnOnce(&mut Parser), L: Lookahead>(
p: &mut Parser, p: &mut Parser,
first: SyntaxKind, first: L,
node_kind: SyntaxKind, node_kind: SyntaxKind,
rest: F rest: F
) -> bool { ) -> 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) { 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 { fn eat(&mut self, kind: SyntaxKind) -> bool {
self.current() == kind && { self.bump(); true } 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 kind
} }
pub(crate) fn lookahead(&self, kinds: &[SyntaxKind]) -> bool { pub(crate) fn raw_lookahead(&self, n: usize) -> SyntaxKind {
if self.tokens[self.pos..].len() < kinds.len() { self.tokens.get(self.pos + n).map(|t| t.kind).unwrap_or(EOF)
return false
}
kinds.iter().zip(self.tokens[self.pos..].iter().map(|t| t.kind))
.all(|(&k1, k2)| k1 == k2)
} }
pub(crate) fn curly_block<F: FnOnce(&mut Parser)>(&mut self, f: F) -> bool { 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, WHITESPACE | COMMENT => true,
_ => false, _ => false,
} }
} }