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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::lexer::token::TokenKind;

pub enum Associativity {
    Non,
    Left,
    Right,
}

#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Precedence {
    Lowest,
    Print,
    Yield,
    YieldFrom,
    IncDec,
    KeyOr,
    KeyXor,
    KeyAnd,
    Assignment,
    Ternary,
    NullCoalesce,
    Or,
    And,
    BitwiseOr,
    BitwiseXor,
    BitwiseAnd,
    Equality,
    LtGt,
    Concat,
    BitShift,
    AddSub,
    MulDivMod,
    Bang,
    Instanceof,
    Prefix,
    Pow,
    CallDim,
    ObjectAccess,
    CloneOrNew,
}

impl Precedence {
    pub fn infix(kind: &TokenKind) -> Self {
        use TokenKind::*;

        match kind {
            Pow => Self::Pow,
            Instanceof => Self::Instanceof,
            Asterisk | Slash | Percent => Self::MulDivMod,
            Plus | Minus => Self::AddSub,
            LeftShift | RightShift => Self::BitShift,
            Dot => Self::Concat,
            LessThan | LessThanEquals | GreaterThan | GreaterThanEquals => Self::LtGt,
            DoubleEquals | BangEquals | TripleEquals | BangDoubleEquals | AngledLeftRight
            | Spaceship => Self::Equality,
            Ampersand => Self::BitwiseAnd,
            Caret => Self::BitwiseXor,
            Pipe => Self::BitwiseOr,
            BooleanAnd => Self::And,
            BooleanOr => Self::Or,
            DoubleQuestion => Self::NullCoalesce,
            Question | QuestionColon => Self::Ternary,
            Equals | PlusEquals | MinusEquals | AsteriskEquals | PowEquals | SlashEquals
            | DotEquals | AndEquals | DoubleQuestionEquals | PercentEquals | AmpersandEquals
            | PipeEquals | CaretEquals | LeftShiftEquals | RightShiftEquals => Self::Assignment,
            Yield => Self::Yield,
            LogicalAnd => Self::KeyAnd,
            LogicalOr => Self::KeyOr,
            LogicalXor => Self::KeyXor,
            _ => unimplemented!("precedence for op {:?}", kind),
        }
    }

    pub fn postfix(kind: &TokenKind) -> Self {
        use TokenKind::*;

        match kind {
            DoubleQuestion => Self::NullCoalesce,
            Increment | Decrement => Self::IncDec,
            LeftParen | LeftBracket => Self::CallDim,
            Arrow | QuestionArrow | DoubleColon => Self::ObjectAccess,
            _ => unimplemented!("postfix precedence for op {:?}", kind),
        }
    }

    pub fn associativity(&self) -> Option<Associativity> {
        Some(match self {
            Self::Instanceof
            | Self::MulDivMod
            | Self::AddSub
            | Self::BitShift
            | Self::Concat
            | Self::BitwiseAnd
            | Self::BitwiseOr
            | Self::BitwiseXor
            | Self::And
            | Self::Or
            | Self::KeyAnd
            | Self::KeyOr
            | Self::KeyXor => Associativity::Left,
            Self::Pow | Self::NullCoalesce | Self::Assignment => Associativity::Right,
            Self::Ternary | Self::Equality | Self::LtGt => Associativity::Non,
            _ => return None,
        })
    }
}