From 0aef78e512bfa271e8ff411359072dc1132e2c65 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 7 Jan 2018 21:41:00 +0300 Subject: grammar.rs is folder --- src/parser/event_parser/grammar/mod.rs | 194 +++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 src/parser/event_parser/grammar/mod.rs (limited to 'src/parser/event_parser/grammar') diff --git a/src/parser/event_parser/grammar/mod.rs b/src/parser/event_parser/grammar/mod.rs new file mode 100644 index 000000000..acf27aec9 --- /dev/null +++ b/src/parser/event_parser/grammar/mod.rs @@ -0,0 +1,194 @@ +use super::parser::Parser; +use {SyntaxKind}; +use tree::EOF; +use syntax_kinds::*; + +// Items // + +pub(crate) fn file(p: &mut Parser) { + node(p, FILE, |p| { + p.optional(SHEBANG); + inner_attributes(p); + many(p, |p| { + skip_to_first( + p, item_first, item, + "expected item", + ) + }); + }) +} + +fn item_first(p: &Parser) -> bool { + match p.current() { + STRUCT_KW | FN_KW => true, + _ => false, + } +} + +fn item(p: &mut Parser) { + outer_attributes(p); + visibility(p); + node_if(p, STRUCT_KW, STRUCT_ITEM, struct_item) + || node_if(p, FN_KW, FN_ITEM, fn_item); +} + +fn struct_item(p: &mut Parser) { + p.expect(IDENT) + && p.curly_block(|p| comma_list(p, EOF, struct_field)); +} + +fn struct_field(p: &mut Parser) -> bool { + node_if(p, IDENT, STRUCT_FIELD, |p| { + p.expect(COLON) && p.expect(IDENT); + }) +} + +fn fn_item(p: &mut Parser) { + p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN) + && p.curly_block(|p| ()); +} + + +// Paths, types, attributes, and stuff // + +fn inner_attributes(p: &mut Parser) { + many(p, |p| attribute(p, true)) +} + +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 }); + meta_item(p) && p.expect(R_BRACK); + }); + true +} + +fn meta_item(p: &mut Parser) -> bool { + node_if(p, IDENT, META_ITEM, |p| { + if p.eat(EQ) { + if !literal(p) { + p.error() + .message("expected literal") + .emit(); + } + } else if p.eat(L_PAREN) { + comma_list(p, R_PAREN, meta_item_inner); + p.expect(R_PAREN); + } + }) +} + +fn meta_item_inner(p: &mut Parser) -> bool { + meta_item(p) || literal(p) +} + +fn literal(p: &mut Parser) -> bool { + p.eat(INT_NUMBER) || p.eat(FLOAT_NUMBER) +} + +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() == 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, end: SyntaxKind, f: F) { + many(p, |p| { + if !f(p) || p.current() == end { + false + } else { + p.expect(COMMA); + true + } + }) +} + + +fn skip_to_first(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> { + pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { + if self.current() == kind { + self.bump(); + true + } else { + self.error() + .message(format!("expected {:?}", kind)) + .emit(); + false + } + } + + fn optional(&mut self, kind: SyntaxKind) { + if self.current() == kind { + self.bump(); + } + } + + 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 } + } +} \ No newline at end of file -- cgit v1.2.3