Drop high-order combinators

This commit is contained in:
Aleksey Kladov 2018-01-20 17:21:13 +03:00
parent 3c612bfa3a
commit 410f948c5f
4 changed files with 136 additions and 137 deletions

View File

@ -2,93 +2,90 @@ use super::*;
pub(super) fn mod_contents(p: &mut Parser) { pub(super) fn mod_contents(p: &mut Parser) {
attributes::inner_attributes(p); attributes::inner_attributes(p);
repeat(p, |p| { while !p.at(EOF) {
skip_to_first( item(p);
p, item_first, mod_contents_item,
"expected item",
)
});
}
fn item_first(p: &Parser) -> bool {
match p.current() {
STRUCT_KW | FN_KW | EXTERN_KW | MOD_KW | USE_KW | POUND | PUB_KW => true,
_ => false,
} }
} }
fn mod_contents_item(p: &mut Parser) { fn item(p: &mut Parser){
if item(p) {
if p.current() == SEMI {
node(p, ERROR, |p| {
p.error()
.message("expected item, found `;`\n\
consider removing this semicolon")
.emit();
p.bump();
})
}
}
}
fn item(p: &mut Parser) -> bool {
let attrs_start = p.mark(); let attrs_start = p.mark();
attributes::outer_attributes(p); attributes::outer_attributes(p);
visibility(p); visibility(p);
// node_if(p, USE_KW, USE_ITEM, use_item) let la = p.raw_lookahead(1);
// || extern crate_fn
// || node_if(p, STATIC_KW, STATIC_ITEM, static_item)
// || node_if(p, CONST_KW, CONST_ITEM, const_item) or const FN!
// || unsafe trait, impl
// || node_if(p, FN_KW, FN_ITEM, fn_item)
// || node_if(p, TYPE_KW, TYPE_ITEM, type_item)
let item_start = p.mark(); let item_start = p.mark();
let item_parsed = node_if(p, [EXTERN_KW, CRATE_KW], EXTERN_CRATE_ITEM, extern_crate_item) match p.current() {
|| node_if(p, MOD_KW, MOD_ITEM, mod_item) EXTERN_KW if la == CRATE_KW => extern_crate_item(p),
|| node_if(p, USE_KW, USE_ITEM, use_item) MOD_KW => mod_item(p),
|| node_if(p, STRUCT_KW, STRUCT_ITEM, struct_item) USE_KW => use_item(p),
|| node_if(p, FN_KW, FN_ITEM, fn_item); STRUCT_KW => struct_item(p),
FN_KW => fn_item(p),
err_token => {
p.start(ERROR);
let message = if err_token == SEMI {
//TODO: if the item is incomplete, this messsage is misleading
"expected item, found `;`\n\
consider removing this semicolon"
} else {
"expected item"
};
p.error()
.message(message)
.emit();
p.bump();
p.finish();
return;
}
};
p.forward_parent(attrs_start, item_start); p.forward_parent(attrs_start, item_start);
item_parsed
} }
fn struct_item(p: &mut Parser) { fn struct_item(p: &mut Parser) {
if !p.expect(IDENT) { p.start(STRUCT_ITEM);
return
} assert!(p.at(STRUCT_KW));
generic_parameters(p); p.bump();
match p.current() {
WHERE_KW => { struct_inner(p);
where_clause(p); p.finish();
match p.current() {
SEMI => { fn struct_inner(p: &mut Parser) {
p.bump(); if !p.expect(IDENT) {
return p.finish();
} return
L_CURLY => named_fields(p), }
_ => { //TODO: special case `(` error message generic_parameters(p);
p.error() match p.current() {
.message("expected `;` or `{`") WHERE_KW => {
.emit(); where_clause(p);
return match p.current() {
SEMI => {
p.bump();
return
}
L_CURLY => named_fields(p),
_ => { //TODO: special case `(` error message
p.error()
.message("expected `;` or `{`")
.emit();
return
}
} }
} }
} SEMI => {
SEMI => { p.bump();
p.bump(); return
return }
} L_CURLY => named_fields(p),
L_CURLY => named_fields(p), L_PAREN => {
L_PAREN => { tuple_fields(p);
tuple_fields(p); p.expect(SEMI);
p.expect(SEMI); },
}, _ => {
_ => { p.error()
p.error() .message("expected `;`, `{`, or `(`")
.message("expected `;`, `{`, or `(`") .emit();
.emit(); return
return }
} }
} }
} }
@ -135,17 +132,28 @@ fn where_clause(_: &mut Parser) {
} }
fn extern_crate_item(p: &mut Parser) { fn extern_crate_item(p: &mut Parser) {
p.start(EXTERN_CRATE_ITEM);
assert!(p.at(EXTERN_KW));
p.bump();
assert!(p.at(CRATE_KW));
p.bump();
p.expect(IDENT) && alias(p) && p.expect(SEMI); p.expect(IDENT) && alias(p) && p.expect(SEMI);
p.finish();
} }
fn mod_item(p: &mut Parser) { fn mod_item(p: &mut Parser) {
if !p.expect(IDENT) { p.start(MOD_ITEM);
return;
assert!(p.at(MOD_KW));
p.bump();
if p.expect(IDENT) && !p.eat(SEMI) {
p.curly_block(mod_contents);
} }
if p.eat(SEMI) { p.finish()
return;
}
p.curly_block(mod_contents);
} }
pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool { pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool {
@ -153,8 +161,13 @@ pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool {
} }
fn use_item(p: &mut Parser) { fn use_item(p: &mut Parser) {
p.start(USE_ITEM);
assert!(p.at(USE_KW));
p.bump();
use_tree(p); use_tree(p);
p.expect(SEMI); p.expect(SEMI);
p.finish();
fn use_tree(p: &mut Parser) -> bool{ fn use_tree(p: &mut Parser) -> bool{
if node_if(p, STAR, USE_TREE, |_| ()) { if node_if(p, STAR, USE_TREE, |_| ()) {
@ -210,8 +223,14 @@ fn use_item(p: &mut Parser) {
fn fn_item(p: &mut Parser) { fn fn_item(p: &mut Parser) {
p.start(FN_ITEM);
assert!(p.at(FN_KW));
p.bump();
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.curly_block(|_| ());
p.finish();
} }

View File

@ -10,37 +10,39 @@ mod types;
mod paths; mod paths;
pub(crate) fn file(p: &mut Parser) { pub(crate) fn file(p: &mut Parser) {
node(p, FILE, |p| { p.start(FILE);
p.eat(SHEBANG); p.eat(SHEBANG);
items::mod_contents(p); items::mod_contents(p);
}) p.finish()
} }
fn visibility(p: &mut Parser) { fn visibility(p: &mut Parser) {
node_if(p, PUB_KW, VISIBILITY, |p| { if p.at(PUB_KW) {
if p.current() != L_PAREN { p.start(VISIBILITY);
return p.bump();
} if p.at(L_PAREN) {
match p.raw_lookahead(1) { match p.raw_lookahead(1) {
CRATE_KW | SELF_KW | SUPER_KW => { CRATE_KW | SELF_KW | SUPER_KW | IN_KW => {
p.bump(); p.bump();
p.bump(); if p.bump() == IN_KW {
paths::use_path(p);
}
p.expect(R_PAREN);
}
_ => ()
} }
IN_KW => {
p.bump();
p.bump();
paths::use_path(p);
}
_ => return
} }
p.expect(R_PAREN); p.finish();
}); }
} }
fn alias(p: &mut Parser) -> bool { fn alias(p: &mut Parser) -> bool {
node_if(p, AS_KW, ALIAS, |p| { if p.at(AS_KW) {
p.start(ALIAS);
p.bump();
p.expect(IDENT); p.expect(IDENT);
}); p.finish();
}
true //FIXME: return false if three are errors true //FIXME: return false if three are errors
} }
@ -92,40 +94,13 @@ fn comma_list<F: Fn(&mut Parser) -> bool>(p: &mut Parser, end: SyntaxKind, f: F)
} }
fn skip_to_first<C, F>(p: &mut Parser, cond: C, f: F, message: &str) -> bool
where
C: Fn(&Parser) -> bool,
F: FnOnce(&mut Parser),
{
let mut skipped = false;
loop {
if cond(p) {
if skipped {
p.finish();
}
f(p);
return true;
}
if p.current() == EOF {
if skipped {
p.finish();
}
return false;
}
if !skipped {
p.start(ERROR);
p.error()
.message(message)
.emit();
}
p.bump();
skipped = true;
}
}
impl<'p> Parser<'p> { impl<'p> Parser<'p> {
fn at(&self, kind: SyntaxKind) -> bool {
self.current() == kind
}
pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
if self.current() == kind { if self.at(kind) {
self.bump(); self.bump();
true true
} else { } else {

View File

@ -1,8 +1,10 @@
FILE@[0; 21) FILE@[0; 21)
ERROR@[0; 10) ERROR@[0; 3)
err: `expected item` err: `expected item`
IDENT@[0; 2) IDENT@[0; 2)
WHITESPACE@[2; 3) WHITESPACE@[2; 3)
ERROR@[3; 10)
err: `expected item`
IDENT@[3; 8) IDENT@[3; 8)
WHITESPACE@[8; 10) WHITESPACE@[8; 10)
STRUCT_ITEM@[10; 21) STRUCT_ITEM@[10; 21)

View File

@ -11,7 +11,10 @@ FILE@[0; 12)
PATH_SEGMENT@[9; 9) PATH_SEGMENT@[9; 9)
err: `expected identifier` err: `expected identifier`
err: `expected SEMI` err: `expected SEMI`
ERROR@[9; 12) ERROR@[9; 11)
err: `expected item` err: `expected item`
INT_NUMBER@[9; 11) INT_NUMBER@[9; 11)
ERROR@[11; 12)
err: `expected item, found `;`
consider removing this semicolon`
SEMI@[11; 12) SEMI@[11; 12)