py_lex/
ops.rs

1#[macro_export]
2macro_rules! parse_unit_impl {
3    ($enum_name:ident {
4        $($string:literal -> $var:ident,)*
5    }) => {
6        #[cfg(feature = "parse")]
7        impl terl::ParseUnit<$crate::Token> for $enum_name {
8            type Target = $enum_name;
9
10            fn parse(p: &mut terl::Parser<$crate::Token>) -> terl::ParseResult<Self, $crate::Token> {
11                use std::collections::HashMap;
12                use terl::WithSpanExt;
13
14                thread_local! {
15                    static MAP: HashMap<&'static str, $enum_name> = {
16                        let mut map = HashMap::new();
17                        $(
18                            if let Some(previous) = map.get($string) {
19                                panic!("conflicting: both `{}` and `{}` are `{}`",
20                                    $enum_name::$var, previous, $string
21                                );
22                            }
23                            map.insert($string, $enum_name::$var);
24                        )*
25                        map
26                    };
27                }
28
29                // use peek here to avoid mutable borrow
30                let Some(next) = p.peek() else {
31                    let msg = format!("expect a `{}`, but there are no token left", stringify!($enum_name));
32                    return p.unmatch(msg)
33                };
34
35
36                match MAP.with(|map| map.get(&**next).copied()) {
37                    Some(item) => {
38                        // and use next here to actually use a token
39                        p.next();
40                        Ok(item)
41                    },
42                    None => {
43                        p.unmatch(
44                            format!("{} matched non of {}", &**next , stringify!($enum_name)),
45                        )
46                    }
47                }
48            }
49        }
50    };
51}
52
53macro_rules! operators {
54    (
55        $(#[$metas:meta])*
56        $(
57            symbols $sub_class:ident {
58                $($string:literal -> $var:ident : $ass:ident $priority:expr),*
59            }
60        )*
61
62    ) => {
63        $(#[$metas])*
64        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
65        pub enum OperatorAssociativity {
66            Binary,
67            Unary,
68            None,
69        }
70
71        impl OperatorAssociativity {
72            pub fn cost(&self) -> usize {
73                match self {
74                    Self::Binary => 2,
75                    Self::Unary => 1,
76                    Self::None => 0
77                }
78            }
79        }
80
81        $(#[$metas])*
82        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
83        pub enum OperatorTypes {
84            $($sub_class,)*
85        }
86
87        $crate::reverse_parse_keywords! {
88            $(#[$metas])*
89            keywords Operators {
90                $(
91                    $($string -> $var,)*
92                )*
93            }
94        }
95
96        parse_unit_impl!{
97            Operators {
98                $(
99                $($string -> $var,)*
100                )*
101            }
102        }
103
104        impl Operators {
105            pub fn op_ty(&self) -> OperatorTypes {
106                match *self {
107                    $(
108                        $(Self::$var => OperatorTypes::$sub_class,)*
109                    )*
110                }
111            }
112
113            pub fn associativity(&self) -> OperatorAssociativity {
114                match *self {
115                    $(
116                        $(Self::$var => OperatorAssociativity::$ass,)*
117                    )*
118                }
119            }
120
121            pub fn cost(&self) -> usize {
122                self.associativity().cost()
123            }
124
125            /// return the priority of the symbol
126            ///
127            /// samller number means higher priority
128            pub fn priority(&self) -> usize {
129                match *self {
130                    $(
131                        $(Self::$var => $priority,)*
132                    )*
133                }
134            }
135        }
136
137        pub mod sub_classes {
138            use super::*;
139
140            $crate::reverse_parse_keywords! {
141                $(
142                keywords $sub_class {
143                    $($string -> $var,)*
144                }
145                )*
146            }
147
148
149
150            $(
151            impl From<$sub_class> for Operators {
152                fn from(value: $sub_class) -> Operators {
153                    match value {
154                        $($sub_class::$var => Operators::$var,)*
155                    }
156                }
157            }
158
159            impl TryFrom<Operators> for $sub_class {
160                type Error = ();
161
162                fn try_from(value: Operators) -> Result<Self, Self::Error> {
163                    match value {
164                        $(Operators::$var => Ok(Self::$var),)*
165                        _ => Err(())
166                    }
167                }
168            }
169
170            impl $sub_class {
171                pub fn associativity(&self) -> OperatorAssociativity {
172                    match self {
173                        $(Self::$var => OperatorAssociativity::$ass,)*
174                    }
175                }
176
177                pub fn priority(&self) -> usize {
178                    match self {
179                        $(Self::$var => $priority,)*
180                    }
181                }
182            }
183
184        )*
185        }
186    };
187}
188
189operators! {
190    #[derive(serde::Serialize,serde::Deserialize)]
191    symbols AlgebraOperator {
192        "jia1"   -> Add : Binary 6,
193        "jian3"  -> Sub : Binary 6,
194        "cheng2" -> Mul : Binary 5,
195        "chu2"   -> Div : Binary 5,
196        "mo2"    -> Mod : Binary 5,
197        "mi4"    -> Pow : Binary 4,
198        "dui4"   -> Log : Binary 4
199    }
200    symbols CompareOperator {
201        "tong2"      -> Eq  : Binary 10,
202        "fei1tong2"  -> Neq : Binary 10,
203        "da4"        -> Gt  : Binary 8,
204        "xiao3"      -> Lt  : Binary 8,
205        "da4deng3"   -> Ge  : Binary 8,
206        "xiao3deng3" -> Le  : Binary 8
207    }
208    symbols LogicalOperator {
209        "yu3"  -> And : Binary 14,
210        "huo4" -> Or  : Binary 15,
211        "fei1" -> Not : Unary  3
212    }
213    symbols ArithmeticOperator {
214        "wei4yu3"     -> Band : Binary 11,
215        "wei4huo4"    -> Bor  : Binary 13,
216        "wei4fei1"    -> Bnot : Unary  3,
217        "wei4yi4huo4" -> Xor  : Binary 12,
218        "zuo3yi2"     -> Shl  : Binary 7,
219        "you4yi2"     -> Shr  : Binary 7
220    }
221    symbols SpecialOperator {
222        "qu3zhi3"   -> AddrOf     : Unary  3,
223        "fang3zhi3" -> Deref      : Unary  3,
224        "fang3su4"  -> GetElement : Binary 2,
225        "zhuan3"    -> Cast       : Unary  2,
226        "chang2du4" -> SizeOf     : Unary  3
227    }
228    symbols StructOperator {
229        "jie2"      -> BracketL   : None 0,
230        "he2"       -> BracketR   : None 0
231    }
232}