diff --git a/src/parser/event_parser/grammar/attributes.rs b/src/parser/event_parser/grammar/attributes.rs index 2d04a1a410..045840059a 100644 --- a/src/parser/event_parser/grammar/attributes.rs +++ b/src/parser/event_parser/grammar/attributes.rs @@ -1,60 +1,84 @@ use super::*; -#[derive(PartialEq, Eq)] -enum AttrKind { - Inner, Outer -} - pub(super) fn inner_attributes(p: &mut Parser) { - repeat(p, |p| attribute(p, AttrKind::Inner)) + while p.at([POUND, EXCL]) { + attribute(p, true) + } } pub(super) fn outer_attributes(p: &mut Parser) { - repeat(p, |p| attribute(p, AttrKind::Outer)) -} - - -fn attribute(p: &mut Parser, kind: AttrKind) -> bool { - if p.at(POUND) { - if kind == AttrKind::Inner && p.raw_lookahead(1) != EXCL { - return false; - } - let attr = p.start(); - p.bump(); - if kind == AttrKind::Inner { - p.bump(); - } - p.expect(L_BRACK) && meta_item(p) && p.expect(R_BRACK); - attr.complete(p, ATTR); - true - } else { - false + while p.at(POUND) { + attribute(p, false) } } -fn meta_item(p: &mut Parser) -> bool { + +fn attribute(p: &mut Parser, inner: bool){ + let attr = p.start(); + assert!(p.at(POUND)); + p.bump(); + + if inner { + assert!(p.at(EXCL)); + p.bump(); + } + + if p.expect(L_BRACK) { + meta_item(p); + p.expect(R_BRACK); + } + attr.complete(p, ATTR); +} + +fn meta_item(p: &mut Parser) { if p.at(IDENT) { let meta_item = p.start(); p.bump(); - if p.eat(EQ) { - if !expressions::literal(p) { - p.error() - .message("expected literal") - .emit(); + match p.current() { + EQ => { + p.bump(); + if !expressions::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); + L_PAREN => meta_item_arg_list(p), + _ => (), } meta_item.complete(p, META_ITEM); - true } else { - false + p.error() + .message("expected attribute value") + .emit() } - } -fn meta_item_inner(p: &mut Parser) -> bool { - meta_item(p) || expressions::literal(p) -} +fn meta_item_arg_list(p: &mut Parser) { + assert!(p.at(L_PAREN)); + p.bump(); + loop { + match p.current() { + EOF | R_PAREN => break, + IDENT => meta_item(p), + c => if !expressions::literal(p) { + let message = "expected attribute"; + if items::ITEM_FIRST.contains(c) { + p.error().message(message).emit(); + return; + } + + let err = p.start(); + p.error().message(message).emit(); + p.bump(); + err.complete(p, ERROR); + continue + } + } + if !p.at(R_PAREN) { + p.expect(COMMA); + } + } + p.expect(R_PAREN); +} diff --git a/src/parser/event_parser/grammar/items.rs b/src/parser/event_parser/grammar/items.rs index c9a8905531..12b6d06c73 100644 --- a/src/parser/event_parser/grammar/items.rs +++ b/src/parser/event_parser/grammar/items.rs @@ -7,6 +7,16 @@ pub(super) fn mod_contents(p: &mut Parser) { } } +pub(super) const ITEM_FIRST: TokenSet = token_set![ + EXTERN_KW, + MOD_KW, + USE_KW, + STRUCT_KW, + FN_KW, + PUB_KW, + POUND, +]; + fn item(p: &mut Parser) { let item = p.start(); attributes::outer_attributes(p); diff --git a/src/parser/event_parser/grammar/mod.rs b/src/parser/event_parser/grammar/mod.rs index d3b63c4c1d..32e4db698e 100644 --- a/src/parser/event_parser/grammar/mod.rs +++ b/src/parser/event_parser/grammar/mod.rs @@ -1,4 +1,4 @@ -use super::parser::Parser; +use super::parser::{Parser, TokenSet}; use {SyntaxKind}; use tree::EOF; use syntax_kinds::*; @@ -80,8 +80,8 @@ fn comma_list bool>(p: &mut Parser, end: SyntaxKind, f: F) impl<'p> Parser<'p> { - fn at(&self, kind: SyntaxKind) -> bool { - self.current() == kind + fn at(&self, l: L) -> bool { + l.is_ahead(self) } pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { diff --git a/src/parser/event_parser/mod.rs b/src/parser/event_parser/mod.rs index 7c81182e3e..b9ffded9dd 100644 --- a/src/parser/event_parser/mod.rs +++ b/src/parser/event_parser/mod.rs @@ -1,7 +1,8 @@ use {Token, SyntaxKind}; -mod grammar; +#[macro_use] mod parser; +mod grammar; #[derive(Debug)] pub(crate) enum Event { diff --git a/src/parser/event_parser/parser.rs b/src/parser/event_parser/parser.rs index 2bc9dd34f5..2cbe370be4 100644 --- a/src/parser/event_parser/parser.rs +++ b/src/parser/event_parser/parser.rs @@ -67,6 +67,29 @@ impl CompleteMarker { } } +pub(crate) struct TokenSet { + pub tokens: &'static [SyntaxKind] +} + +impl TokenSet { + pub fn contains(&self, kind: SyntaxKind) -> bool { + self.tokens.contains(&kind) + } +} + +#[macro_export] +macro_rules! token_set { + ($($t:ident),*) => { + TokenSet { + tokens: &[$($t),*], + } + }; + + ($($t:ident),* ,) => { + token_set!($($t),*) + }; +} + pub(crate) struct Parser<'t> { #[allow(unused)]