1use crate::error::{CompileError, PPError};
6use crate::intern::{InternedStr, StringInterner};
7use crate::macro_def::MacroTable;
8use crate::source::SourceLocation;
9use crate::token::{Token, TokenKind};
10
11pub struct PPExprEvaluator<'a> {
13 tokens: &'a [Token],
14 pos: usize,
15 interner: &'a StringInterner,
16 macros: &'a MacroTable,
17 loc: SourceLocation,
18 defined_id: Option<InternedStr>,
20}
21
22impl<'a> PPExprEvaluator<'a> {
23 pub fn new(
25 tokens: &'a [Token],
26 interner: &'a StringInterner,
27 macros: &'a MacroTable,
28 loc: SourceLocation,
29 ) -> Self {
30 let defined_id = interner.lookup("defined");
32
33 Self {
34 tokens,
35 pos: 0,
36 interner,
37 macros,
38 loc,
39 defined_id,
40 }
41 }
42
43 pub fn evaluate(&mut self) -> Result<i64, CompileError> {
45 let result = self.expr()?;
46 Ok(result)
47 }
48
49 fn current(&self) -> Option<&Token> {
51 self.tokens.get(self.pos)
52 }
53
54 fn current_kind(&self) -> Option<&TokenKind> {
56 self.current().map(|t| &t.kind)
57 }
58
59 fn advance(&mut self) {
61 if self.pos < self.tokens.len() {
62 self.pos += 1;
63 }
64 }
65
66 fn error(&self, msg: &str) -> CompileError {
68 CompileError::Preprocess {
69 loc: self.loc.clone(),
70 kind: PPError::InvalidCondition(msg.to_string()),
71 }
72 }
73
74 fn expr(&mut self) -> Result<i64, CompileError> {
76 let cond = self.logical_or()?;
77
78 if matches!(self.current_kind(), Some(TokenKind::Question)) {
79 self.advance();
80 let then_val = self.expr()?;
81 if !matches!(self.current_kind(), Some(TokenKind::Colon)) {
82 return Err(self.error("expected ':' in ternary expression"));
83 }
84 self.advance();
85 let else_val = self.expr()?;
86 Ok(if cond != 0 { then_val } else { else_val })
87 } else {
88 Ok(cond)
89 }
90 }
91
92 fn logical_or(&mut self) -> Result<i64, CompileError> {
94 let mut left = self.logical_and()?;
95
96 while matches!(self.current_kind(), Some(TokenKind::PipePipe)) {
97 self.advance();
98 let right = self.logical_and()?;
99 left = if left != 0 || right != 0 { 1 } else { 0 };
100 }
101
102 Ok(left)
103 }
104
105 fn logical_and(&mut self) -> Result<i64, CompileError> {
107 let mut left = self.bitwise_or()?;
108
109 while matches!(self.current_kind(), Some(TokenKind::AmpAmp)) {
110 self.advance();
111 let right = self.bitwise_or()?;
112 left = if left != 0 && right != 0 { 1 } else { 0 };
113 }
114
115 Ok(left)
116 }
117
118 fn bitwise_or(&mut self) -> Result<i64, CompileError> {
120 let mut left = self.bitwise_xor()?;
121
122 while matches!(self.current_kind(), Some(TokenKind::Pipe)) {
123 self.advance();
124 let right = self.bitwise_xor()?;
125 left |= right;
126 }
127
128 Ok(left)
129 }
130
131 fn bitwise_xor(&mut self) -> Result<i64, CompileError> {
133 let mut left = self.bitwise_and()?;
134
135 while matches!(self.current_kind(), Some(TokenKind::Caret)) {
136 self.advance();
137 let right = self.bitwise_and()?;
138 left ^= right;
139 }
140
141 Ok(left)
142 }
143
144 fn bitwise_and(&mut self) -> Result<i64, CompileError> {
146 let mut left = self.equality()?;
147
148 while matches!(self.current_kind(), Some(TokenKind::Amp)) {
149 self.advance();
150 let right = self.equality()?;
151 left &= right;
152 }
153
154 Ok(left)
155 }
156
157 fn equality(&mut self) -> Result<i64, CompileError> {
159 let mut left = self.relational()?;
160
161 loop {
162 match self.current_kind() {
163 Some(TokenKind::EqEq) => {
164 self.advance();
165 let right = self.relational()?;
166 left = if left == right { 1 } else { 0 };
167 }
168 Some(TokenKind::BangEq) => {
169 self.advance();
170 let right = self.relational()?;
171 left = if left != right { 1 } else { 0 };
172 }
173 _ => break,
174 }
175 }
176
177 Ok(left)
178 }
179
180 fn relational(&mut self) -> Result<i64, CompileError> {
182 let mut left = self.shift()?;
183
184 loop {
185 match self.current_kind() {
186 Some(TokenKind::Lt) => {
187 self.advance();
188 let right = self.shift()?;
189 left = if left < right { 1 } else { 0 };
190 }
191 Some(TokenKind::Gt) => {
192 self.advance();
193 let right = self.shift()?;
194 left = if left > right { 1 } else { 0 };
195 }
196 Some(TokenKind::LtEq) => {
197 self.advance();
198 let right = self.shift()?;
199 left = if left <= right { 1 } else { 0 };
200 }
201 Some(TokenKind::GtEq) => {
202 self.advance();
203 let right = self.shift()?;
204 left = if left >= right { 1 } else { 0 };
205 }
206 _ => break,
207 }
208 }
209
210 Ok(left)
211 }
212
213 fn shift(&mut self) -> Result<i64, CompileError> {
215 let mut left = self.additive()?;
216
217 loop {
218 match self.current_kind() {
219 Some(TokenKind::LtLt) => {
220 self.advance();
221 let right = self.additive()?;
222 left <<= right;
223 }
224 Some(TokenKind::GtGt) => {
225 self.advance();
226 let right = self.additive()?;
227 left >>= right;
228 }
229 _ => break,
230 }
231 }
232
233 Ok(left)
234 }
235
236 fn additive(&mut self) -> Result<i64, CompileError> {
238 let mut left = self.multiplicative()?;
239
240 loop {
241 match self.current_kind() {
242 Some(TokenKind::Plus) => {
243 self.advance();
244 let right = self.multiplicative()?;
245 left = left.wrapping_add(right);
246 }
247 Some(TokenKind::Minus) => {
248 self.advance();
249 let right = self.multiplicative()?;
250 left = left.wrapping_sub(right);
251 }
252 _ => break,
253 }
254 }
255
256 Ok(left)
257 }
258
259 fn multiplicative(&mut self) -> Result<i64, CompileError> {
261 let mut left = self.unary()?;
262
263 loop {
264 match self.current_kind() {
265 Some(TokenKind::Star) => {
266 self.advance();
267 let right = self.unary()?;
268 left = left.wrapping_mul(right);
269 }
270 Some(TokenKind::Slash) => {
271 self.advance();
272 let right = self.unary()?;
273 if right == 0 {
274 return Err(self.error("division by zero"));
275 }
276 left /= right;
277 }
278 Some(TokenKind::Percent) => {
279 self.advance();
280 let right = self.unary()?;
281 if right == 0 {
282 return Err(self.error("modulo by zero"));
283 }
284 left %= right;
285 }
286 _ => break,
287 }
288 }
289
290 Ok(left)
291 }
292
293 fn unary(&mut self) -> Result<i64, CompileError> {
295 match self.current_kind() {
296 Some(TokenKind::Plus) => {
297 self.advance();
298 self.unary()
299 }
300 Some(TokenKind::Minus) => {
301 self.advance();
302 Ok(-self.unary()?)
303 }
304 Some(TokenKind::Bang) => {
305 self.advance();
306 let val = self.unary()?;
307 Ok(if val == 0 { 1 } else { 0 })
308 }
309 Some(TokenKind::Tilde) => {
310 self.advance();
311 Ok(!self.unary()?)
312 }
313 _ => self.primary(),
314 }
315 }
316
317 fn primary(&mut self) -> Result<i64, CompileError> {
319 match self.current_kind().cloned() {
320 Some(TokenKind::IntLit(n)) => {
321 self.advance();
322 Ok(n)
323 }
324 Some(TokenKind::UIntLit(n)) => {
325 self.advance();
326 Ok(n as i64)
327 }
328 Some(TokenKind::CharLit(c)) => {
329 self.advance();
330 Ok(c as i64)
331 }
332 Some(TokenKind::WideCharLit(c)) => {
333 self.advance();
334 Ok(c as i64)
335 }
336 Some(TokenKind::LParen) => {
337 self.advance();
338 let val = self.expr()?;
339 if !matches!(self.current_kind(), Some(TokenKind::RParen)) {
340 return Err(self.error("expected ')'"));
341 }
342 self.advance();
343 Ok(val)
344 }
345 Some(TokenKind::Ident(id)) => {
346 if Some(id) == self.defined_id {
348 self.advance();
349 return self.parse_defined();
350 }
351
352 self.advance();
354 Ok(0)
355 }
356 Some(_) => Err(self.error("unexpected token in preprocessor expression")),
357 None => Err(self.error("unexpected end of expression")),
358 }
359 }
360
361 fn parse_defined(&mut self) -> Result<i64, CompileError> {
363 let has_paren = matches!(self.current_kind(), Some(TokenKind::LParen));
364 if has_paren {
365 self.advance();
366 }
367
368 let name = match self.current_kind() {
371 Some(TokenKind::Ident(id)) => Some(*id),
372 Some(kind) if kind.is_keyword() => {
373 let kw_name = kind.format(self.interner);
376 self.interner.lookup(&kw_name)
377 }
378 _ => return Err(self.error("expected identifier after 'defined'")),
379 };
380 self.advance();
381
382 if has_paren {
383 if !matches!(self.current_kind(), Some(TokenKind::RParen)) {
384 return Err(self.error("expected ')' after identifier in 'defined'"));
385 }
386 self.advance();
387 }
388
389 Ok(match name {
391 Some(n) if self.macros.is_defined(n) => 1,
392 _ => 0,
393 })
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400 use crate::macro_def::MacroDef;
401 use crate::source::FileId;
402
403 fn make_token(kind: TokenKind) -> Token {
404 Token::new(kind, SourceLocation::default())
405 }
406
407 fn eval_tokens(tokens: &[Token], interner: &StringInterner, macros: &MacroTable) -> i64 {
408 let loc = SourceLocation::new(FileId::default(), 1, 1);
409 let mut eval = PPExprEvaluator::new(tokens, interner, macros, loc);
410 eval.evaluate().unwrap()
411 }
412
413 #[test]
414 fn test_simple_number() {
415 let interner = StringInterner::new();
416 let macros = MacroTable::new();
417 let tokens = vec![make_token(TokenKind::IntLit(42))];
418
419 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 42);
420 }
421
422 #[test]
423 fn test_arithmetic() {
424 let interner = StringInterner::new();
425 let macros = MacroTable::new();
426
427 let tokens = vec![
429 make_token(TokenKind::IntLit(2)),
430 make_token(TokenKind::Plus),
431 make_token(TokenKind::IntLit(3)),
432 ];
433 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 5);
434
435 let tokens = vec![
437 make_token(TokenKind::IntLit(10)),
438 make_token(TokenKind::Minus),
439 make_token(TokenKind::IntLit(4)),
440 make_token(TokenKind::Star),
441 make_token(TokenKind::IntLit(2)),
442 ];
443 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 2);
444 }
445
446 #[test]
447 fn test_comparison() {
448 let interner = StringInterner::new();
449 let macros = MacroTable::new();
450
451 let tokens = vec![
453 make_token(TokenKind::IntLit(5)),
454 make_token(TokenKind::Gt),
455 make_token(TokenKind::IntLit(3)),
456 ];
457 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 1);
458
459 let tokens = vec![
461 make_token(TokenKind::IntLit(2)),
462 make_token(TokenKind::EqEq),
463 make_token(TokenKind::IntLit(3)),
464 ];
465 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 0);
466 }
467
468 #[test]
469 fn test_logical() {
470 let interner = StringInterner::new();
471 let macros = MacroTable::new();
472
473 let tokens = vec![
475 make_token(TokenKind::IntLit(1)),
476 make_token(TokenKind::AmpAmp),
477 make_token(TokenKind::IntLit(0)),
478 ];
479 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 0);
480
481 let tokens = vec![
483 make_token(TokenKind::IntLit(1)),
484 make_token(TokenKind::PipePipe),
485 make_token(TokenKind::IntLit(0)),
486 ];
487 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 1);
488 }
489
490 #[test]
491 fn test_ternary() {
492 let interner = StringInterner::new();
493 let macros = MacroTable::new();
494
495 let tokens = vec![
497 make_token(TokenKind::IntLit(1)),
498 make_token(TokenKind::Question),
499 make_token(TokenKind::IntLit(10)),
500 make_token(TokenKind::Colon),
501 make_token(TokenKind::IntLit(20)),
502 ];
503 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 10);
504
505 let tokens = vec![
507 make_token(TokenKind::IntLit(0)),
508 make_token(TokenKind::Question),
509 make_token(TokenKind::IntLit(10)),
510 make_token(TokenKind::Colon),
511 make_token(TokenKind::IntLit(20)),
512 ];
513 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 20);
514 }
515
516 #[test]
517 fn test_defined() {
518 let mut interner = StringInterner::new();
519 let mut macros = MacroTable::new();
520
521 let foo = interner.intern("FOO");
522 let defined = interner.intern("defined");
523 let _ = defined; macros.define(MacroDef::object(foo, vec![], SourceLocation::default()), &interner);
527
528 let tokens = vec![
530 make_token(TokenKind::Ident(interner.lookup("defined").unwrap())),
531 make_token(TokenKind::LParen),
532 make_token(TokenKind::Ident(foo)),
533 make_token(TokenKind::RParen),
534 ];
535 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 1);
536
537 let bar = interner.intern("BAR");
539 let tokens = vec![
540 make_token(TokenKind::Ident(interner.lookup("defined").unwrap())),
541 make_token(TokenKind::LParen),
542 make_token(TokenKind::Ident(bar)),
543 make_token(TokenKind::RParen),
544 ];
545 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 0);
546 }
547
548 #[test]
549 fn test_unary() {
550 let interner = StringInterner::new();
551 let macros = MacroTable::new();
552
553 let tokens = vec![
555 make_token(TokenKind::Minus),
556 make_token(TokenKind::IntLit(5)),
557 ];
558 assert_eq!(eval_tokens(&tokens, &interner, ¯os), -5);
559
560 let tokens = vec![
562 make_token(TokenKind::Bang),
563 make_token(TokenKind::IntLit(0)),
564 ];
565 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 1);
566
567 let tokens = vec![
569 make_token(TokenKind::Bang),
570 make_token(TokenKind::IntLit(1)),
571 ];
572 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 0);
573 }
574
575 #[test]
576 fn test_parentheses() {
577 let interner = StringInterner::new();
578 let macros = MacroTable::new();
579
580 let tokens = vec![
582 make_token(TokenKind::LParen),
583 make_token(TokenKind::IntLit(2)),
584 make_token(TokenKind::Plus),
585 make_token(TokenKind::IntLit(3)),
586 make_token(TokenKind::RParen),
587 make_token(TokenKind::Star),
588 make_token(TokenKind::IntLit(4)),
589 ];
590 assert_eq!(eval_tokens(&tokens, &interner, ¯os), 20);
591 }
592}