lib_ruby_parser/
context.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4#[derive(Debug, Clone, Eq, PartialEq, Default)]
5pub(crate) struct SharedContext {
6    value: Rc<RefCell<Context>>,
7}
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
10pub(crate) struct Context {
11    value: usize,
12}
13
14macro_rules! context_flag {
15    ($upper:ident, $getter:ident, $setter: ident, $value:expr) => {
16        impl Context {
17            const $upper: usize = $value;
18
19            pub(crate) fn $getter(&self) -> bool {
20                (self.value & Self::$upper) != 0
21            }
22
23            pub(crate) fn $setter(&mut self, value: bool) {
24                if cfg!(feature = "debug-parser") {
25                    println!("{}({})", stringify!($setter), value);
26                }
27                if value {
28                    self.value |= Self::$upper;
29                } else {
30                    self.value &= !Self::$upper;
31                }
32            }
33        }
34
35        impl SharedContext {
36            #[allow(dead_code)]
37            pub(crate) fn $getter(&self) -> bool {
38                self.value.borrow().$getter()
39            }
40
41            pub(crate) fn $setter(&mut self, value: bool) {
42                self.value.borrow_mut().$setter(value)
43            }
44        }
45    };
46}
47
48context_flag!(IN_DEFINED, in_defined, set_in_defined, 1 << 0);
49context_flag!(IN_KWARG, in_kwarg, set_in_kwarg, 1 << 1);
50context_flag!(IN_ARGDEF, in_argdef, set_in_argdef, 1 << 2);
51context_flag!(IN_DEF, in_def, set_in_def, 1 << 3);
52context_flag!(IN_CLASS, in_class, set_in_class, 1 << 4);
53context_flag!(IN_LAMBDA, in_lambda, set_in_lambda, 1 << 5);
54context_flag!(IN_BLOCK, in_block, set_in_block, 1 << 6);
55
56impl SharedContext {
57    pub(crate) fn new() -> Self {
58        Self::default()
59    }
60
61    pub(crate) fn dump(&self) -> Context {
62        *self.value.borrow()
63    }
64
65    pub(crate) fn is_in_dynamic_block(&self) -> bool {
66        self.in_block() || self.in_lambda()
67    }
68
69    pub(crate) fn is_empty(&self) -> bool {
70        self.value.borrow().is_empty()
71    }
72}
73
74impl Context {
75    fn is_empty(&self) -> bool {
76        if cfg!(debug_assertions) && self.value != 0 {
77            println!(
78                "Context is not empty;
79    value = {};
80    IN_DEFINED = {}
81    IN_KWARG = {}
82    IN_ARGDEF = {}
83    IN_DEF = {}
84    IN_CLASS = {}
85    IN_LAMBDA = {}
86    IN_BLOCK = {}",
87                self.value,
88                self.in_defined(),
89                self.in_kwarg(),
90                self.in_argdef(),
91                self.in_def(),
92                self.in_class(),
93                self.in_lambda(),
94                self.in_block(),
95            );
96        }
97        self.value == 0
98    }
99}
100
101#[test]
102fn test_context() {
103    let mut context = Context::default();
104
105    context.set_in_def(true);
106    context.set_in_class(true);
107    assert!(context.in_def());
108    assert!(context.in_class());
109
110    context.set_in_def(false);
111    assert!(!context.in_def());
112    assert!(context.in_class());
113
114    context.set_in_class(false);
115    assert!(!context.in_def());
116    assert!(!context.in_class());
117
118    assert!(context.is_empty());
119}