use super::parser::Parser; use {SyntaxKind}; use syntax_kinds::*; // Items // pub fn file(p: &mut Parser) { node(p, FILE, |p| { shebang(p); inner_attributes(p); many(p, |p| skip_to_first(p, item_first, item)); }) } fn shebang(_: &mut Parser) { //TODO } fn inner_attributes(_: &mut Parser) { //TODO } fn item_first(p: &Parser) -> bool { match p.current() { Some(STRUCT_KW) => true, _ => false, } } fn item(p: &mut Parser) { outer_attributes(p); visibility(p); node_if(p, STRUCT_KW, STRUCT_ITEM, struct_item); } fn struct_item(p: &mut Parser) { p.expect(IDENT) && p.curly_block(|p| comma_list(p, struct_field)); } fn struct_field(p: &mut Parser) -> bool { node_if(p, IDENT, STRUCT_FIELD, |p| { p.expect(COLON) && p.expect(IDENT); }) } // Paths, types, attributes, and stuff // fn outer_attributes(_: &mut Parser) { } fn visibility(_: &mut Parser) { } // Expressions // // Error recovery and high-order utils // fn node_if(p: &mut Parser, first: SyntaxKind, node_kind: SyntaxKind, rest: F) -> bool { p.current_is(first) && { node(p, node_kind, |p| { p.bump(); rest(p); }); true } } fn node(p: &mut Parser, node_kind: SyntaxKind, rest: F) { p.start(node_kind); rest(p); p.finish(); } fn many bool>(p: &mut Parser, f: F) { while f(p) { } } fn comma_list bool>(p: &mut Parser, f: F) { many(p, |p| { f(p); p.is_eof() || p.expect(COMMA) }) } fn skip_to_first(p: &mut Parser, cond: C, f: F) -> bool where C: Fn(&Parser) -> bool, F: FnOnce(&mut Parser), { loop { if cond(p) { f(p); return true; } if p.bump().is_none() { return false; } } } impl<'p> Parser<'p> { fn current_is(&self, kind: SyntaxKind) -> bool { self.current() == Some(kind) } pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { if self.current_is(kind) { self.bump(); true } else { self.error() .message(format!("expected {:?}", kind)) .emit(); false } } }