Remove high-order bits from attributes

This commit is contained in:
Aleksey Kladov 2018-01-21 00:31:29 +03:00
parent 0b5d39f2a2
commit efd538d793
5 changed files with 102 additions and 44 deletions

View file

@ -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);
}

View file

@ -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);

View file

@ -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<F: Fn(&mut Parser) -> bool>(p: &mut Parser, end: SyntaxKind, f: F)
impl<'p> Parser<'p> {
fn at(&self, kind: SyntaxKind) -> bool {
self.current() == kind
fn at<L: Lookahead>(&self, l: L) -> bool {
l.is_ahead(self)
}
pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {

View file

@ -1,7 +1,8 @@
use {Token, SyntaxKind};
mod grammar;
#[macro_use]
mod parser;
mod grammar;
#[derive(Debug)]
pub(crate) enum Event {

View file

@ -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)]