1use std::sync::atomic::{AtomicU64, Ordering};
6
7use crate::intern::InternedStr;
8use crate::source::SourceLocation;
9use crate::token::Comment;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
19pub struct ExprId(pub u64);
20
21static EXPR_ID_COUNTER: AtomicU64 = AtomicU64::new(1); impl ExprId {
25 pub fn next() -> Self {
27 Self(EXPR_ID_COUNTER.fetch_add(1, Ordering::Relaxed))
28 }
29
30 pub const INVALID: Self = Self(0);
32
33 pub fn is_valid(&self) -> bool {
35 self.0 != 0
36 }
37}
38
39impl std::fmt::Display for ExprId {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 write!(f, "ExprId({})", self.0)
42 }
43}
44
45#[derive(Debug, Clone, PartialEq)]
51pub struct MacroInvocation {
52 pub name: InternedStr,
54 pub call_loc: SourceLocation,
56 pub args: Option<Vec<String>>,
58}
59
60impl MacroInvocation {
61 pub fn new(name: InternedStr, call_loc: SourceLocation) -> Self {
63 Self {
64 name,
65 call_loc,
66 args: None,
67 }
68 }
69
70 pub fn with_args(name: InternedStr, call_loc: SourceLocation, args: Vec<String>) -> Self {
72 Self {
73 name,
74 call_loc,
75 args: Some(args),
76 }
77 }
78}
79
80#[derive(Debug, Clone, Default, PartialEq)]
85pub struct MacroExpansionInfo {
86 pub chain: Vec<MacroInvocation>,
88}
89
90impl MacroExpansionInfo {
91 pub fn new() -> Self {
93 Self { chain: Vec::new() }
94 }
95
96 pub fn is_empty(&self) -> bool {
98 self.chain.is_empty()
99 }
100
101 pub fn push(&mut self, invocation: MacroInvocation) {
103 self.chain.push(invocation);
104 }
105
106 pub fn innermost(&self) -> Option<&MacroInvocation> {
108 self.chain.last()
109 }
110
111 pub fn outermost(&self) -> Option<&MacroInvocation> {
113 self.chain.first()
114 }
115
116 pub fn len(&self) -> usize {
118 self.chain.len()
119 }
120}
121
122#[derive(Debug, Clone, Default, PartialEq)]
127pub struct NodeInfo {
128 pub loc: SourceLocation,
130 pub macro_expansion: Option<Box<MacroExpansionInfo>>,
132}
133
134impl NodeInfo {
135 pub fn new(loc: SourceLocation) -> Self {
137 Self {
138 loc,
139 macro_expansion: None,
140 }
141 }
142
143 pub fn with_macro_info(loc: SourceLocation, macro_info: MacroExpansionInfo) -> Self {
147 Self {
148 loc,
149 macro_expansion: if macro_info.is_empty() {
150 None
151 } else {
152 Some(Box::new(macro_info))
153 },
154 }
155 }
156
157 pub fn is_from_macro(&self) -> bool {
159 self.macro_expansion.is_some()
160 }
161
162 pub fn macro_info(&self) -> Option<&MacroExpansionInfo> {
164 self.macro_expansion.as_deref()
165 }
166}
167
168#[derive(Debug, Clone)]
174pub struct TranslationUnit {
175 pub decls: Vec<ExternalDecl>,
176}
177
178#[derive(Debug, Clone)]
180pub enum ExternalDecl {
181 FunctionDef(FunctionDef),
183 Declaration(Declaration),
185}
186
187impl ExternalDecl {
188 pub fn is_target(&self) -> bool {
190 match self {
191 ExternalDecl::FunctionDef(f) => f.is_target,
192 ExternalDecl::Declaration(d) => d.is_target,
193 }
194 }
195}
196
197#[derive(Debug, Clone)]
199pub struct FunctionDef {
200 pub specs: DeclSpecs,
201 pub declarator: Declarator,
202 pub body: CompoundStmt,
203 pub info: NodeInfo,
204 pub comments: Vec<Comment>,
205 pub is_target: bool,
207 pub function_call_count: usize,
209 pub deref_count: usize,
211}
212
213impl FunctionDef {
214 pub fn loc(&self) -> &SourceLocation {
216 &self.info.loc
217 }
218}
219
220#[derive(Debug, Clone)]
222pub struct Declaration {
223 pub specs: DeclSpecs,
224 pub declarators: Vec<InitDeclarator>,
225 pub info: NodeInfo,
226 pub comments: Vec<Comment>,
227 pub is_target: bool,
229}
230
231impl Declaration {
232 pub fn loc(&self) -> &SourceLocation {
234 &self.info.loc
235 }
236}
237
238#[derive(Debug, Clone, Default)]
240pub struct DeclSpecs {
241 pub storage: Option<StorageClass>,
242 pub type_specs: Vec<TypeSpec>,
243 pub qualifiers: TypeQualifiers,
244 pub is_inline: bool,
245}
246
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
249pub enum StorageClass {
250 Typedef,
251 Extern,
252 Static,
253 Auto,
254 Register,
255}
256
257#[derive(Debug, Clone)]
259pub enum TypeSpec {
260 Void,
261 Char,
262 Short,
263 Int,
264 Long,
265 Float,
266 Double,
267 Signed,
268 Unsigned,
269 Bool,
270 Complex,
271 Float16,
273 Float32,
274 Float64,
275 Float128,
276 Float32x,
277 Float64x,
278 Int128,
280 TypeofExpr(Box<Expr>),
282 Struct(StructSpec),
283 Union(StructSpec),
284 Enum(EnumSpec),
285 TypedefName(InternedStr),
286}
287
288#[derive(Debug, Clone, Default, PartialEq)]
290pub struct TypeQualifiers {
291 pub is_const: bool,
292 pub is_volatile: bool,
293 pub is_restrict: bool,
294 pub is_atomic: bool,
295}
296
297impl TypeQualifiers {
298 pub fn is_empty(&self) -> bool {
299 !self.is_const && !self.is_volatile && !self.is_restrict && !self.is_atomic
300 }
301}
302
303#[derive(Debug, Clone)]
305pub struct StructSpec {
306 pub name: Option<InternedStr>,
307 pub members: Option<Vec<StructMember>>,
308 pub loc: SourceLocation,
309}
310
311#[derive(Debug, Clone)]
313pub struct StructMember {
314 pub specs: DeclSpecs,
315 pub declarators: Vec<StructDeclarator>,
316}
317
318#[derive(Debug, Clone)]
320pub struct StructDeclarator {
321 pub declarator: Option<Declarator>,
322 pub bitfield: Option<Box<Expr>>,
323}
324
325#[derive(Debug, Clone)]
327pub struct EnumSpec {
328 pub name: Option<InternedStr>,
329 pub enumerators: Option<Vec<Enumerator>>,
330 pub loc: SourceLocation,
331}
332
333#[derive(Debug, Clone)]
335pub struct Enumerator {
336 pub name: InternedStr,
337 pub value: Option<Box<Expr>>,
338 pub loc: SourceLocation,
339}
340
341#[derive(Debug, Clone)]
343pub struct ParamDecl {
344 pub specs: DeclSpecs,
345 pub declarator: Option<Declarator>,
346 pub loc: SourceLocation,
347}
348
349#[derive(Debug, Clone)]
351pub struct ParamList {
352 pub params: Vec<ParamDecl>,
353 pub is_variadic: bool,
354}
355
356#[derive(Debug, Clone)]
358pub struct InitDeclarator {
359 pub declarator: Declarator,
360 pub init: Option<Initializer>,
361}
362
363#[derive(Debug, Clone)]
365pub struct Declarator {
366 pub name: Option<InternedStr>,
367 pub derived: Vec<DerivedDecl>,
368 pub loc: SourceLocation,
369}
370
371#[derive(Debug, Clone)]
373pub enum DerivedDecl {
374 Pointer(TypeQualifiers),
375 Array(ArrayDecl),
376 Function(ParamList),
377}
378
379#[derive(Debug, Clone)]
381pub struct ArrayDecl {
382 pub size: Option<Box<Expr>>,
383 pub qualifiers: TypeQualifiers,
384 pub is_static: bool,
385 pub is_vla: bool,
386}
387
388#[derive(Debug, Clone)]
390pub enum Initializer {
391 Expr(Box<Expr>),
392 List(Vec<InitializerItem>),
393}
394
395#[derive(Debug, Clone)]
397pub struct InitializerItem {
398 pub designation: Vec<Designator>,
399 pub init: Initializer,
400}
401
402#[derive(Debug, Clone)]
404pub enum Designator {
405 Index(Box<Expr>),
406 Member(InternedStr),
407}
408
409#[derive(Debug, Clone)]
411pub enum Stmt {
412 Compound(CompoundStmt),
414 Expr(Option<Box<Expr>>, SourceLocation),
416 If {
418 cond: Box<Expr>,
419 then_stmt: Box<Stmt>,
420 else_stmt: Option<Box<Stmt>>,
421 loc: SourceLocation,
422 },
423 Switch {
425 expr: Box<Expr>,
426 body: Box<Stmt>,
427 loc: SourceLocation,
428 },
429 While {
431 cond: Box<Expr>,
432 body: Box<Stmt>,
433 loc: SourceLocation,
434 },
435 DoWhile {
437 body: Box<Stmt>,
438 cond: Box<Expr>,
439 loc: SourceLocation,
440 },
441 For {
443 init: Option<ForInit>,
444 cond: Option<Box<Expr>>,
445 step: Option<Box<Expr>>,
446 body: Box<Stmt>,
447 loc: SourceLocation,
448 },
449 Goto(InternedStr, SourceLocation),
451 Continue(SourceLocation),
453 Break(SourceLocation),
455 Return(Option<Box<Expr>>, SourceLocation),
457 Label {
459 name: InternedStr,
460 stmt: Box<Stmt>,
461 loc: SourceLocation,
462 },
463 Case {
465 expr: Box<Expr>,
466 stmt: Box<Stmt>,
467 loc: SourceLocation,
468 },
469 Default {
471 stmt: Box<Stmt>,
472 loc: SourceLocation,
473 },
474 Asm {
476 loc: SourceLocation,
477 },
478}
479
480#[derive(Debug, Clone)]
482pub enum ForInit {
483 Expr(Box<Expr>),
484 Decl(Declaration),
485}
486
487#[derive(Debug, Clone)]
489pub struct CompoundStmt {
490 pub items: Vec<BlockItem>,
491 pub info: NodeInfo,
492}
493
494impl CompoundStmt {
495 pub fn loc(&self) -> &SourceLocation {
497 &self.info.loc
498 }
499}
500
501#[derive(Debug, Clone)]
503pub enum BlockItem {
504 Decl(Declaration),
505 Stmt(Stmt),
506}
507
508#[derive(Debug, Clone)]
512pub enum BuiltinArg {
513 Expr(Box<Expr>),
514 TypeName(Box<TypeName>),
515}
516
517#[derive(Debug, Clone)]
519pub enum ExprKind {
520 Ident(InternedStr),
522 IntLit(i64),
523 UIntLit(u64),
524 FloatLit(f64),
525 CharLit(u8),
526 StringLit(Vec<u8>),
527
528 Index {
530 expr: Box<Expr>,
531 index: Box<Expr>,
532 },
533 Call {
534 func: Box<Expr>,
535 args: Vec<Expr>,
536 },
537 Member {
538 expr: Box<Expr>,
539 member: InternedStr,
540 },
541 PtrMember {
542 expr: Box<Expr>,
543 member: InternedStr,
544 },
545 PostInc(Box<Expr>),
546 PostDec(Box<Expr>),
547 CompoundLit {
548 type_name: Box<TypeName>,
549 init: Vec<InitializerItem>,
550 },
551
552 PreInc(Box<Expr>),
554 PreDec(Box<Expr>),
555 AddrOf(Box<Expr>),
556 Deref(Box<Expr>),
557 UnaryPlus(Box<Expr>),
558 UnaryMinus(Box<Expr>),
559 BitNot(Box<Expr>),
560 LogNot(Box<Expr>),
561 Sizeof(Box<Expr>),
562 SizeofType(Box<TypeName>),
563 Alignof(Box<TypeName>),
564 Cast {
565 type_name: Box<TypeName>,
566 expr: Box<Expr>,
567 },
568
569 Binary {
571 op: BinOp,
572 lhs: Box<Expr>,
573 rhs: Box<Expr>,
574 },
575
576 Conditional {
578 cond: Box<Expr>,
579 then_expr: Box<Expr>,
580 else_expr: Box<Expr>,
581 },
582
583 Assign {
585 op: AssignOp,
586 lhs: Box<Expr>,
587 rhs: Box<Expr>,
588 },
589
590 Comma {
592 lhs: Box<Expr>,
593 rhs: Box<Expr>,
594 },
595
596 StmtExpr(CompoundStmt),
598
599 Assert {
601 kind: AssertKind,
602 condition: Box<Expr>,
603 },
604
605 MacroCall {
611 name: InternedStr,
613 args: Vec<Expr>,
615 expanded: Box<Expr>,
617 call_loc: SourceLocation,
619 },
620
621 BuiltinCall {
626 name: InternedStr,
627 args: Vec<BuiltinArg>,
628 },
629}
630
631#[derive(Debug, Clone)]
633pub struct Expr {
634 pub id: ExprId,
636 pub kind: ExprKind,
638 pub loc: SourceLocation,
640}
641
642impl Expr {
643 pub fn new(kind: ExprKind, loc: SourceLocation) -> Self {
645 Self {
646 id: ExprId::next(),
647 kind,
648 loc,
649 }
650 }
651
652 pub fn loc(&self) -> &SourceLocation {
654 &self.loc
655 }
656}
657
658#[derive(Debug, Clone)]
660pub struct TypeName {
661 pub specs: DeclSpecs,
662 pub declarator: Option<AbstractDeclarator>,
663}
664
665#[derive(Debug, Clone)]
667pub struct AbstractDeclarator {
668 pub derived: Vec<DerivedDecl>,
669}
670
671#[derive(Debug, Clone, Copy, PartialEq, Eq)]
673pub enum BinOp {
674 Mul,
676 Div,
677 Mod,
678 Add,
680 Sub,
681 Shl,
683 Shr,
684 Lt,
686 Gt,
687 Le,
688 Ge,
689 Eq,
690 Ne,
691 BitAnd,
693 BitXor,
694 BitOr,
695 LogAnd,
697 LogOr,
698}
699
700#[derive(Debug, Clone, Copy, PartialEq, Eq)]
702pub enum AssignOp {
703 Assign,
704 MulAssign,
705 DivAssign,
706 ModAssign,
707 AddAssign,
708 SubAssign,
709 ShlAssign,
710 ShrAssign,
711 AndAssign,
712 XorAssign,
713 OrAssign,
714}
715
716#[derive(Debug, Clone, Copy, PartialEq, Eq)]
718pub enum AssertKind {
719 Assert,
721 AssertUnderscore,
723}
724#[cfg(test)]
725mod tests {
726 use super::*;
727 use crate::intern::StringInterner;
728
729 #[test]
730 fn test_type_qualifiers_is_empty() {
731 let empty = TypeQualifiers::default();
732 assert!(empty.is_empty());
733
734 let with_const = TypeQualifiers {
735 is_const: true,
736 ..Default::default()
737 };
738 assert!(!with_const.is_empty());
739 }
740
741 #[test]
744 fn test_macro_invocation_new() {
745 let mut interner = StringInterner::new();
746 let name = interner.intern("FOO");
747 let loc = SourceLocation::default();
748
749 let inv = MacroInvocation::new(name, loc.clone());
750
751 assert_eq!(inv.name, name);
752 assert_eq!(inv.call_loc, loc);
753 assert!(inv.args.is_none());
754 }
755
756 #[test]
757 fn test_macro_invocation_with_args() {
758 let mut interner = StringInterner::new();
759 let name = interner.intern("ADD");
760 let loc = SourceLocation::default();
761 let args = vec!["a".to_string(), "b".to_string()];
762
763 let inv = MacroInvocation::with_args(name, loc.clone(), args.clone());
764
765 assert_eq!(inv.name, name);
766 assert_eq!(inv.call_loc, loc);
767 assert_eq!(inv.args, Some(args));
768 }
769
770 #[test]
773 fn test_macro_expansion_info_new() {
774 let info = MacroExpansionInfo::new();
775 assert!(info.is_empty());
776 assert_eq!(info.len(), 0);
777 assert!(info.innermost().is_none());
778 assert!(info.outermost().is_none());
779 }
780
781 #[test]
782 fn test_macro_expansion_info_push() {
783 let mut interner = StringInterner::new();
784 let mut info = MacroExpansionInfo::new();
785
786 let inv1 = MacroInvocation::new(interner.intern("FOO"), SourceLocation::default());
787 let inv2 = MacroInvocation::new(interner.intern("BAR"), SourceLocation::default());
788
789 info.push(inv1.clone());
790 assert_eq!(info.len(), 1);
791 assert!(!info.is_empty());
792
793 info.push(inv2.clone());
794 assert_eq!(info.len(), 2);
795
796 assert_eq!(info.outermost().unwrap().name, inv1.name);
798 assert_eq!(info.innermost().unwrap().name, inv2.name);
800 }
801
802 #[test]
803 fn test_macro_expansion_info_chain() {
804 let mut interner = StringInterner::new();
805 let mut info = MacroExpansionInfo::new();
806
807 info.push(MacroInvocation::new(interner.intern("A"), SourceLocation::default()));
809 info.push(MacroInvocation::new(interner.intern("B"), SourceLocation::default()));
810 info.push(MacroInvocation::new(interner.intern("C"), SourceLocation::default()));
811
812 assert_eq!(info.chain.len(), 3);
813 assert_eq!(interner.get(info.chain[0].name), "A");
814 assert_eq!(interner.get(info.chain[1].name), "B");
815 assert_eq!(interner.get(info.chain[2].name), "C");
816 }
817
818 #[test]
821 fn test_node_info_new() {
822 let loc = SourceLocation::new(crate::source::FileId::default(), 10, 5);
823 let info = NodeInfo::new(loc.clone());
824
825 assert_eq!(info.loc, loc);
826 assert!(!info.is_from_macro());
827 assert!(info.macro_info().is_none());
828 }
829
830 #[test]
831 fn test_node_info_with_empty_macro_info() {
832 let loc = SourceLocation::default();
833 let macro_info = MacroExpansionInfo::new();
834
835 let info = NodeInfo::with_macro_info(loc.clone(), macro_info);
836
837 assert!(!info.is_from_macro());
839 assert!(info.macro_info().is_none());
840 }
841
842 #[test]
843 fn test_node_info_with_macro_info() {
844 let mut interner = StringInterner::new();
845 let loc = SourceLocation::default();
846
847 let mut macro_info = MacroExpansionInfo::new();
848 macro_info.push(MacroInvocation::new(interner.intern("FOO"), SourceLocation::default()));
849
850 let info = NodeInfo::with_macro_info(loc.clone(), macro_info);
851
852 assert!(info.is_from_macro());
853 assert!(info.macro_info().is_some());
854 assert_eq!(info.macro_info().unwrap().len(), 1);
855 }
856
857 #[test]
858 fn test_node_info_default() {
859 let info = NodeInfo::default();
860
861 assert_eq!(info.loc, SourceLocation::default());
862 assert!(!info.is_from_macro());
863 }
864}