Skip to main content

rs_asm6805/
symbol_table.rs

1use std::collections::HashMap;
2use std::rc::{Rc, Weak};
3use std::cell::RefCell;
4
5#[derive(Debug)]
6pub struct SourceLine {
7    pub definition: Option<Weak<RefCell<Symbol>>>,
8    pub references: Vec<Weak<RefCell<Symbol>>>,
9    pub is_dirty: bool,
10    pub line_offset: i32,
11    pub is_origin: bool,
12    pub data_bytes: Vec<u8>,
13    pub relative_offset: i32,
14    pub include_bytes_read: Option<usize>,
15}
16
17impl SourceLine {
18    pub fn new() -> Self {
19        Self {
20            definition: None,
21            references: Vec::new(),
22            is_dirty: false,
23            line_offset: 0,
24            is_origin: false,
25            data_bytes: Vec::new(),
26            relative_offset: -1,
27            include_bytes_read: None,
28        }
29    }
30
31    pub fn get_offset(&self) -> i32 {
32        self.line_offset
33    }
34
35    pub fn get_byte_count(&self) -> usize {
36        self.data_bytes.len()
37    }
38
39    pub fn set_data(&mut self, data: &[u8]) -> i32 {
40        let delta = data.len() as i32 - self.data_bytes.len() as i32;
41        self.data_bytes = data.to_vec();
42        delta
43    }
44
45    pub fn get_data(&self) -> &[u8] {
46        &self.data_bytes
47    }
48
49    pub fn set_offset(&mut self, byte_offset: i32, is_origin: bool) {
50        self.line_offset = byte_offset;
51        self.is_origin = is_origin;
52    }
53
54    pub fn adjust_offset(&mut self, offset: i32) {
55        self.set_offset(self.line_offset + offset, false);
56    }
57
58    pub fn mark_dirty(&mut self, is_dirty: bool) {
59        self.is_dirty = is_dirty;
60    }
61
62    pub fn is_dirty(&self) -> bool {
63        self.is_dirty
64    }
65
66    pub fn is_origin(&self) -> bool {
67        self.is_origin
68    }
69
70    pub fn set_relative(&mut self, offset: i32) {
71        self.relative_offset = offset;
72    }
73
74    pub fn get_relative_offset(&self) -> i32 {
75        self.relative_offset
76    }
77
78    pub fn reset_references(&mut self, self_ref: Weak<RefCell<SourceLine>>) {
79        // Remove this line from all symbols it was referencing
80        for weak_symbol in &self.references {
81            if let Some(symbol) = weak_symbol.upgrade() {
82                symbol.borrow_mut().remove_reference(self_ref.clone());
83            }
84        }
85        // Clear the local reference list
86        self.references.clear();
87    }
88
89    pub fn add_reference(&mut self, symbol: Weak<RefCell<Symbol>>) {
90        self.references.push(symbol);
91    }
92
93    pub fn set_include_bytes_read(&mut self, bytes: usize) {
94        self.include_bytes_read = Some(bytes);
95    }
96
97    pub fn set_definition(&mut self, symbol: Option<Weak<RefCell<Symbol>>>, self_ref: Weak<RefCell<SourceLine>>) {
98        // Remove the old definition if it exists
99        if let Some(old_def) = &self.definition {
100            if let Some(old_symbol) = old_def.upgrade() {
101                old_symbol.borrow_mut().remove_definition_for_line(self_ref.clone());
102            }
103        }
104        self.definition = symbol;
105    }
106}
107
108#[derive(Debug)]
109pub struct Symbol {
110    pub value: i32,
111    pub definitions: u32,
112    pub is_keyword: bool,
113    pub defined_lines: Vec<Weak<RefCell<SourceLine>>>,
114    pub referenced_lines: Vec<Weak<RefCell<SourceLine>>>,
115}
116
117impl Symbol {
118    pub fn new() -> Self {
119        Self {
120            value: 0,
121            definitions: 0,
122            is_keyword: false,
123            defined_lines: Vec::new(),
124            referenced_lines: Vec::new(),
125        }
126    }
127
128    pub fn set_keyword(&mut self, value: i32) {
129        self.is_keyword = true;
130        self.value = value;
131    }
132
133    pub fn is_keyword(&self) -> bool {
134        self.is_keyword
135    }
136
137    pub fn is_referenced(&self) -> bool {
138        !self.referenced_lines.is_empty()
139    }
140
141    pub fn get_value(&self) -> i32 {
142        self.value
143    }
144
145    pub fn set_value(&mut self, value: i32) {
146        if value == self.value {
147            return;
148        }
149        self.value = value;
150        // Mark all references as dirty
151        self.referenced_lines.retain(|weak_ref| {
152            if let Some(line) = weak_ref.upgrade() {
153                line.borrow_mut().mark_dirty(true);
154                true
155            } else {
156                false
157            }
158        });
159    }
160
161    pub fn add_definition(&mut self, source_line: Weak<RefCell<SourceLine>>) {
162        self.definitions += 1;
163        self.defined_lines.push(source_line);
164    }
165
166    pub fn add_reference(&mut self, source_line: Weak<RefCell<SourceLine>>) {
167        self.referenced_lines.push(source_line);
168    }
169
170    pub fn get_definition_count(&self) -> u32 {
171        self.definitions
172    }
173
174    pub fn remove_definition_for_line(&mut self, source_line: Weak<RefCell<SourceLine>>) {
175        // Find and remove the specific source line from defined_lines
176        self.defined_lines.retain(|weak_ref| {
177            if let (Some(existing), Some(target)) = (weak_ref.upgrade(), source_line.upgrade()) {
178                !Rc::ptr_eq(&existing, &target)
179            } else {
180                false // Remove dead weak references
181            }
182        });
183        
184        // Update the definition count to match the actual number of definitions
185        self.definitions = self.defined_lines.len() as u32;
186        
187        // Mark all remaining definition lines as dirty
188        for weak_def in &self.defined_lines {
189            if let Some(def_line) = weak_def.upgrade() {
190                def_line.borrow_mut().mark_dirty(true);
191            }
192        }
193    }
194
195    pub fn remove_reference(&mut self, source_line: Weak<RefCell<SourceLine>>) {
196        // Remove the specific source line from referenced_lines
197        self.referenced_lines.retain(|weak_ref| {
198            if let (Some(existing), Some(target)) = (weak_ref.upgrade(), source_line.upgrade()) {
199                !Rc::ptr_eq(&existing, &target)
200            } else {
201                false // Remove dead weak references
202            }
203        });
204    }
205}
206
207pub struct SymbolTable {
208    symbols: HashMap<String, Rc<RefCell<Symbol>>>,
209}
210
211impl SymbolTable {
212    pub fn new() -> Self {
213        Self {
214            symbols: HashMap::new(),
215        }
216    }
217
218    pub fn lookup_symbol(&mut self, name: &str) -> Rc<RefCell<Symbol>> {
219        let symbol_name = name.to_uppercase();
220        if let Some(symbol) = self.symbols.get(&symbol_name) {
221            symbol.clone()
222        } else {
223            let symbol = Rc::new(RefCell::new(Symbol::new()));
224            self.symbols.insert(symbol_name, symbol.clone());
225            symbol
226        }
227    }
228
229    pub fn lookup_symbol_with_reference(&mut self, name: &str, source_line: Weak<RefCell<SourceLine>>) -> Rc<RefCell<Symbol>> {
230        let symbol_name = name.to_uppercase();
231        let symbol = if let Some(existing) = self.symbols.get(&symbol_name) {
232            existing.clone()
233        } else {
234            let new_symbol = Rc::new(RefCell::new(Symbol::new()));
235            self.symbols.insert(symbol_name, new_symbol.clone());
236            new_symbol
237        };
238        
239        // Add reference if it's not a keyword
240        if !symbol.borrow().is_keyword() {
241            symbol.borrow_mut().add_reference(source_line.clone());
242            // Also add the symbol to the source line's reference list
243            if let Some(line) = source_line.upgrade() {
244                line.borrow_mut().add_reference(Rc::downgrade(&symbol));
245            }
246        }
247        
248        symbol
249    }
250
251    pub fn lookup_keyword(&self, name: &str) -> Option<i32> {
252        let symbol_name = name.to_uppercase();
253        if let Some(symbol) = self.symbols.get(&symbol_name) {
254            let symbol_ref = symbol.borrow();
255            if symbol_ref.is_keyword() {
256                Some(symbol_ref.get_value())
257            } else {
258                None
259            }
260        } else {
261            None
262        }
263    }
264
265    pub fn define_symbol(&mut self, name: &str, source_line: Weak<RefCell<SourceLine>>, value: i32) -> Rc<RefCell<Symbol>> {
266        let symbol = self.lookup_symbol(name);
267        {
268            let mut symbol_ref = symbol.borrow_mut();
269            symbol_ref.set_value(value);
270            symbol_ref.add_definition(source_line.clone());
271        }
272        
273        // Set the definition on the source line as well
274        if let Some(line) = source_line.upgrade() {
275            line.borrow_mut().set_definition(Some(Rc::downgrade(&symbol)), source_line.clone());
276        }
277        
278        symbol
279    }
280
281    pub fn define_keyword(&mut self, name: &str, value: i32) -> Rc<RefCell<Symbol>> {
282        let symbol_name = name.to_uppercase();
283        let symbol = if let Some(existing) = self.symbols.get(&symbol_name) {
284            existing.clone()
285        } else {
286            let new_symbol = Rc::new(RefCell::new(Symbol::new()));
287            self.symbols.insert(symbol_name, new_symbol.clone());
288            new_symbol
289        };
290        
291        symbol.borrow_mut().set_keyword(value);
292        symbol
293    }
294}