aboutsummaryrefslogtreecommitdiff
path: root/src/grammar/attributes.rs
blob: c411d4d7f387922b0a0b0b62ca625aa687c29aba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use super::*;

pub(super) fn inner_attributes(p: &mut Parser) {
    while p.current() == POUND && p.nth(1) == EXCL {
        attribute(p, true)
    }
}

pub(super) fn outer_attributes(p: &mut Parser) {
    while p.at(POUND) {
        attribute(p, false)
    }
}

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();
        match p.current() {
            EQ => {
                p.bump();
                if expressions::literal(p).is_none() {
                    p.error("expected literal");
                }
            }
            L_PAREN => meta_item_arg_list(p),
            _ => (),
        }
        meta_item.complete(p, META_ITEM);
    } else {
        p.error("expected attribute value");
    }
}

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).is_none() {
                let message = "expected attribute";

                if items::ITEM_FIRST.contains(c) {
                    p.error(message);
                    return;
                }

                let err = p.start();
                p.error(message);
                p.bump();
                err.complete(p, ERROR);
                continue;
            },
        }
        if !p.at(R_PAREN) {
            p.expect(COMMA);
        }
    }
    p.expect(R_PAREN);
}