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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::ns::*;
use serde::{Serialize, Deserialize};

/// Represents an ActionScript operator.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub enum Operator {
    PostIncrement,
    PostDecrement,
    NonNull,
    Delete,
    Void,
    Typeof,
    Await,
    Yield,
    PreIncrement,
    PreDecrement,
    Positive,
    Negative,
    BitwiseNot,
    LogicalNot,

    Power,
    Multiply,
    Divide,
    Remainder,
    Add,
    Subtract,
    ShiftLeft,
    ShiftRight,
    ShiftRightUnsigned,
    Lt,
    Gt,
    Le,
    Ge,
    Instanceof,
    In,
    NotIn,
    Is,
    IsNot,
    As,
    Equals,
    NotEquals,
    StrictEquals,
    StrictNotEquals,
    BitwiseAnd,
    BitwiseXor,
    BitwiseOr,
    LogicalAnd,
    LogicalXor,
    LogicalOr,
    NullCoalescing,
}

/// Represents binary operator associativity.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum BinaryAssociativity {
    LeftToRight,
    RightToLeft,
}

/// Represents an ActionScript binary operator.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct BinaryOperator(pub Operator, pub OperatorPrecedence, pub BinaryAssociativity);

impl BinaryOperator {
    pub fn operator(&self) -> Operator {
        self.0
    }

    pub fn precedence(&self) -> OperatorPrecedence {
        self.1
    }

    pub fn associativity(&self) -> BinaryAssociativity {
        self.2
    }

    pub fn right_precedence(&self) -> OperatorPrecedence {
        if self.operator() == Operator::NullCoalescing {
            OperatorPrecedence::BitwiseOr
        } else {
            self.precedence().add(if self.associativity() == BinaryAssociativity::LeftToRight { 1 } else { 0 }).unwrap()
        }
    }
}

impl TryFrom<Operator> for BinaryOperator {
    type Error = ();
    /// Constructs `BinaryOperator` from abstract operator.
    fn try_from(value: Operator) -> Result<Self, Self::Error> {
        match value {
            Operator::Multiply => Ok(BinaryOperator(value, OperatorPrecedence::Multiplicative, BinaryAssociativity::LeftToRight)),
            Operator::Divide => Ok(BinaryOperator(value, OperatorPrecedence::Multiplicative, BinaryAssociativity::LeftToRight)),
            Operator::Remainder => Ok(BinaryOperator(value, OperatorPrecedence::Multiplicative, BinaryAssociativity::LeftToRight)),
            Operator::Add => Ok(BinaryOperator(value, OperatorPrecedence::Additive, BinaryAssociativity::LeftToRight)),
            Operator::Subtract => Ok(BinaryOperator(value, OperatorPrecedence::Additive, BinaryAssociativity::LeftToRight)),
            Operator::ShiftLeft => Ok(BinaryOperator(value, OperatorPrecedence::Shift, BinaryAssociativity::LeftToRight)),
            Operator::ShiftRight => Ok(BinaryOperator(value, OperatorPrecedence::Shift, BinaryAssociativity::LeftToRight)),
            Operator::ShiftRightUnsigned => Ok(BinaryOperator(value, OperatorPrecedence::Shift, BinaryAssociativity::LeftToRight)),
            Operator::Lt => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::Gt => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::Le => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::Ge => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::As => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::In => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::NotIn => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::Instanceof => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::Is => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::IsNot => Ok(BinaryOperator(value, OperatorPrecedence::Relational, BinaryAssociativity::LeftToRight)),
            Operator::Equals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
            Operator::NotEquals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
            Operator::StrictEquals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
            Operator::StrictNotEquals => Ok(BinaryOperator(value, OperatorPrecedence::Equality, BinaryAssociativity::LeftToRight)),
            Operator::BitwiseAnd => Ok(BinaryOperator(value, OperatorPrecedence::BitwiseAnd, BinaryAssociativity::LeftToRight)),
            Operator::BitwiseXor => Ok(BinaryOperator(value, OperatorPrecedence::BitwiseXor, BinaryAssociativity::LeftToRight)),
            Operator::BitwiseOr => Ok(BinaryOperator(value, OperatorPrecedence::BitwiseOr, BinaryAssociativity::LeftToRight)),
            Operator::LogicalAnd => Ok(BinaryOperator(value, OperatorPrecedence::LogicalAnd, BinaryAssociativity::LeftToRight)),
            Operator::LogicalXor => Ok(BinaryOperator(value, OperatorPrecedence::LogicalXor, BinaryAssociativity::LeftToRight)),
            Operator::LogicalOr => Ok(BinaryOperator(value, OperatorPrecedence::LogicalOrAndOther, BinaryAssociativity::LeftToRight)),
            Operator::NullCoalescing => Ok(BinaryOperator(value, OperatorPrecedence::LogicalOrAndOther, BinaryAssociativity::LeftToRight)),

            Operator::Power => Ok(BinaryOperator(value, OperatorPrecedence::Exponentiation, BinaryAssociativity::RightToLeft)),

            _ => Err(()),
        }
    }
}