1#![feature(type_name_of_val)]
2#![feature(or_patterns)]
3use std::any::type_name_of_val;
4
5use logos::{Lexer, Logos};
6
7#[derive(Logos, Debug, Copy, Clone, PartialEq)]
8enum Token {
9 #[regex(r"[a-zA-Z_][\w_]*")]
10 Ident,
11
12 #[regex(r"\d+")]
13 #[regex(r"\d+[uU]")]
14 #[regex(r"\d+[lL]")]
15 #[regex(r"\d+[uU][lL]")]
16 #[regex(r"\d+[uU][lL][lL]")]
17 Num,
18
19 #[regex(r"\d+\.\d*f?")]
20 Real,
21
22 #[regex(r"[\[\{\(]")]
23 LDelim,
24 #[regex(r"[\]\}\)]")]
25 RDelim,
26
27 #[token("->")]
28 Access,
29 #[token("&&")]
30 And,
31 #[token("||")]
32 Or,
33 #[token(">>")]
34 Shr,
35 #[token("<<")]
36 Shl,
37 #[token("==")]
38 Eq,
39 #[token("!=")]
40 Ne,
41 #[token("<=")]
42 Le,
43 #[token(">=")]
44 Ge,
45
46 #[token("++")]
47 Inc,
48 #[token("--")]
49 Dec,
50
51 #[regex(r"[~!&|^=?.,;:*/%+-]", |it| it.slice().as_bytes()[0] as char)]
52 Punct(char),
53
54 #[error]
55 #[regex(r"[ \t\n\f]+", logos::skip)]
56 Error,
57}
58
59impl Token {
60 fn op(self) -> Binop {
61 use Token::*;
62 match self {
63 Access => Binop::PtrField,
64 Punct('.') => Binop::Field,
65 Punct('*') => Binop::Mul,
66 Punct('/') => Binop::Div,
67 Punct('%') => Binop::Rem,
68 Punct('+') => Binop::Add,
69 Punct('-') => Binop::Sub,
70 Shr => Binop::Shl,
71 Shr => Binop::Shr,
72 Le => Binop::Le,
73 Ge => Binop::Ge,
74 Punct('<') => Binop::Lt,
75 Punct('>') => Binop::Gt,
76 Eq => Binop::Eq,
77 Ne => Binop::Ne,
78 Punct('&') => Binop::And,
79 Punct('^') => Binop::Xor,
80 Punct('|') => Binop::Or,
81 And => Binop::Logand,
82 Or => Binop::Logor,
83 _ => unreachable!(),
84 }
85 }
86
87 fn prec(self) -> u32 {
88 use Token::*;
89 match self {
90 Access | Punct('.') => 11,
91 Punct('*' | '/' | '%') => 10,
92 Punct('+' | '-') => 9,
93 Shr | Shl => 8,
94 Le | Ge | Punct('>' | '<') => 7,
95 Eq | Ne => 6,
96 Punct('&') => 5,
97 Punct('^') => 4,
98 Punct('|') => 3,
99 And => 2,
100 Or => 1,
101 _ => 0,
102 }
103 }
104}
105
106#[derive(Debug, Clone, Copy)]
107pub enum Unop {
108 Neg,
109 Not,
110 Flip,
111 PostInc,
112 PostDec,
113 PreInc,
114 PreDec,
115}
116
117#[derive(Debug, Clone, Copy)]
118pub enum Binop {
119 Field,
120 PtrField,
121 Add,
122 Sub,
123 Mul,
124 Div,
125 Rem,
126 And,
127 Xor,
128 Or,
129 Shr,
130 Shl,
131 Eq,
132 Ne,
133 Le,
134 Ge,
135 Lt,
136 Gt,
137 Logand,
138 Logor,
139 Subs,
140}
141
142#[derive(Debug, Clone, Copy)]
143pub enum Suffix {
144 U,
145 UL,
146 ULL,
147 I,
148 L,
149 LL,
150}
151
152#[derive(Debug, Clone)]
153pub enum Expr {
154 Var(String),
155 Num(u64, Suffix),
156 Real(f64),
157 Unary(Unop, Box<Expr>),
158 Binop(Binop, Box<Expr>, Box<Expr>),
159}
160
161#[derive(Debug, Clone, Copy)]
162pub enum Value {
163 Uint(u64),
164 Sint(i64),
165 Real(f64),
166 Bool(bool),
167}
168
169impl Expr {
170 pub fn new(s: &str) -> Option<Expr> {
171 parse_expr(&mut Token::lexer(s)).ok()
172 }
173}
174
175fn check_postfix(it: &mut Lexer<Token>, x: Expr) -> Result<Expr, ()> {
176 use Token::*;
177 Ok(match it.clone().next() {
178 Some(Punct('[')) => {
179 it.next();
180 let y = parse_expr(it)?;
181 match it.next() {
182 Some(Punct(']')) => Expr::Binop(Binop::Subs, Box::new(x), Box::new(y)),
183 _ => return Err(()),
184 }
185 }
186 Some(Inc) => Expr::Unary(Unop::PostInc, Box::new(x)),
187 Some(Dec) => Expr::Unary(Unop::PostDec, Box::new(x)),
188 _ => x,
189 })
190}
191
192fn parse_term(it: &mut Lexer<Token>) -> Result<Expr, ()> {
193 use Token::*;
194 let x = match it.next().ok_or(())? {
195 Ident => Expr::Var(it.slice().to_owned()),
196 Num => {
197 let s: &str = it.slice();
198 let mut cc = s.len();
199 let mut v = String::with_capacity(4);
200 while !(s.as_bytes()[cc - 1] as char).is_digit(10) {
201 v.push(s.as_bytes()[cc - 1].to_ascii_lowercase() as char);
202 cc -= 1;
203 }
204 let ss = match v.as_str() {
205 "llu" => Suffix::ULL,
206 "ll" => Suffix::LL,
207 "lu" => Suffix::UL,
208 "l" => Suffix::L,
209 "u" => Suffix::U,
210 _ => Suffix::I,
211 };
212 Expr::Num(it.slice()[..cc].parse().unwrap(), ss)
213 }
214 Real => Expr::Real(it.slice().replace("f", "").parse().unwrap()),
215 LDelim => {
216 let x = parse_expr(it)?;
217 match it.next() {
218 Some(RDelim) => x,
219 _ => return Err(()),
220 }
221 }
222 Punct('~') => Expr::Unary(Unop::Flip, Box::new(parse_term(it)?)),
223 Punct('!') => Expr::Unary(Unop::Not, Box::new(parse_term(it)?)),
224 Punct('-') => Expr::Unary(Unop::Neg, Box::new(parse_term(it)?)),
225 Inc => Expr::Unary(Unop::PreInc, Box::new(parse_term(it)?)),
226 Dec => Expr::Unary(Unop::PreDec, Box::new(parse_term(it)?)),
227 _ => return Err(()),
228 };
229 check_postfix(it, x)
230}
231
232fn parse_prec(it: &mut Lexer<Token>, mut lhs: Expr, prec: u32) -> Result<Expr, ()> {
241 while it.clone().next().map(|t| t.prec() >= prec) == Some(true) {
242 let t: Token = it.next().unwrap();
243 let prec2 = t.prec();
244 let mut rhs = parse_term(it)?;
245 while it.clone().next().map(|t| t.prec() >= prec2) == Some(true) {
246 rhs = parse_prec(it, rhs, prec + 1)?;
247 }
248 lhs = Expr::Binop(t.op(), Box::new(lhs), Box::new(rhs));
249 }
250
251 Ok(lhs)
252}
253
254fn parse_expr(it: &mut Lexer<Token>) -> Result<Expr, ()> {
255 let x = parse_term(it)?;
256 parse_prec(it, x, 1)
257}
258
259#[test]
260fn tests() {
261 Expr::new("(rasterizationSamples + 31) / 32").unwrap();
262 Expr::new("9 / 2 + a-b").unwrap();
263 Expr::new("abc->abc + abc.abc - x12 * 12").unwrap();
264 Expr::new("(~0U-2)").unwrap();
265 println!("{:?}", Expr::new("(~0U-2)").unwrap());
266}