rs-asm6805 1.0.0

6805 Datalink Assembler in Rust
Documentation
use std::collections::HashMap;
use std::rc::{Rc, Weak};
use std::cell::RefCell;

#[derive(Debug)]
pub struct SourceLine {
    pub definition: Option<Weak<RefCell<Symbol>>>,
    pub references: Vec<Weak<RefCell<Symbol>>>,
    pub is_dirty: bool,
    pub line_offset: i32,
    pub is_origin: bool,
    pub data_bytes: Vec<u8>,
    pub relative_offset: i32,
    pub include_bytes_read: Option<usize>,
}

impl SourceLine {
    pub fn new() -> Self {
        Self {
            definition: None,
            references: Vec::new(),
            is_dirty: false,
            line_offset: 0,
            is_origin: false,
            data_bytes: Vec::new(),
            relative_offset: -1,
            include_bytes_read: None,
        }
    }

    pub fn get_offset(&self) -> i32 {
        self.line_offset
    }

    pub fn get_byte_count(&self) -> usize {
        self.data_bytes.len()
    }

    pub fn set_data(&mut self, data: &[u8]) -> i32 {
        let delta = data.len() as i32 - self.data_bytes.len() as i32;
        self.data_bytes = data.to_vec();
        delta
    }

    pub fn get_data(&self) -> &[u8] {
        &self.data_bytes
    }

    pub fn set_offset(&mut self, byte_offset: i32, is_origin: bool) {
        self.line_offset = byte_offset;
        self.is_origin = is_origin;
    }

    pub fn adjust_offset(&mut self, offset: i32) {
        self.set_offset(self.line_offset + offset, false);
    }

    pub fn mark_dirty(&mut self, is_dirty: bool) {
        self.is_dirty = is_dirty;
    }

    pub fn is_dirty(&self) -> bool {
        self.is_dirty
    }

    pub fn is_origin(&self) -> bool {
        self.is_origin
    }

    pub fn set_relative(&mut self, offset: i32) {
        self.relative_offset = offset;
    }

    pub fn get_relative_offset(&self) -> i32 {
        self.relative_offset
    }

    pub fn reset_references(&mut self, self_ref: Weak<RefCell<SourceLine>>) {
        // Remove this line from all symbols it was referencing
        for weak_symbol in &self.references {
            if let Some(symbol) = weak_symbol.upgrade() {
                symbol.borrow_mut().remove_reference(self_ref.clone());
            }
        }
        // Clear the local reference list
        self.references.clear();
    }

    pub fn add_reference(&mut self, symbol: Weak<RefCell<Symbol>>) {
        self.references.push(symbol);
    }

    pub fn set_include_bytes_read(&mut self, bytes: usize) {
        self.include_bytes_read = Some(bytes);
    }

    pub fn set_definition(&mut self, symbol: Option<Weak<RefCell<Symbol>>>, self_ref: Weak<RefCell<SourceLine>>) {
        // Remove the old definition if it exists
        if let Some(old_def) = &self.definition {
            if let Some(old_symbol) = old_def.upgrade() {
                old_symbol.borrow_mut().remove_definition_for_line(self_ref.clone());
            }
        }
        self.definition = symbol;
    }
}

#[derive(Debug)]
pub struct Symbol {
    pub value: i32,
    pub definitions: u32,
    pub is_keyword: bool,
    pub defined_lines: Vec<Weak<RefCell<SourceLine>>>,
    pub referenced_lines: Vec<Weak<RefCell<SourceLine>>>,
}

impl Symbol {
    pub fn new() -> Self {
        Self {
            value: 0,
            definitions: 0,
            is_keyword: false,
            defined_lines: Vec::new(),
            referenced_lines: Vec::new(),
        }
    }

    pub fn set_keyword(&mut self, value: i32) {
        self.is_keyword = true;
        self.value = value;
    }

    pub fn is_keyword(&self) -> bool {
        self.is_keyword
    }

    pub fn is_referenced(&self) -> bool {
        !self.referenced_lines.is_empty()
    }

    pub fn get_value(&self) -> i32 {
        self.value
    }

    pub fn set_value(&mut self, value: i32) {
        if value == self.value {
            return;
        }
        self.value = value;
        // Mark all references as dirty
        self.referenced_lines.retain(|weak_ref| {
            if let Some(line) = weak_ref.upgrade() {
                line.borrow_mut().mark_dirty(true);
                true
            } else {
                false
            }
        });
    }

    pub fn add_definition(&mut self, source_line: Weak<RefCell<SourceLine>>) {
        self.definitions += 1;
        self.defined_lines.push(source_line);
    }

    pub fn add_reference(&mut self, source_line: Weak<RefCell<SourceLine>>) {
        self.referenced_lines.push(source_line);
    }

    pub fn get_definition_count(&self) -> u32 {
        self.definitions
    }

    pub fn remove_definition_for_line(&mut self, source_line: Weak<RefCell<SourceLine>>) {
        // Find and remove the specific source line from defined_lines
        self.defined_lines.retain(|weak_ref| {
            if let (Some(existing), Some(target)) = (weak_ref.upgrade(), source_line.upgrade()) {
                !Rc::ptr_eq(&existing, &target)
            } else {
                false // Remove dead weak references
            }
        });
        
        // Update the definition count to match the actual number of definitions
        self.definitions = self.defined_lines.len() as u32;
        
        // Mark all remaining definition lines as dirty
        for weak_def in &self.defined_lines {
            if let Some(def_line) = weak_def.upgrade() {
                def_line.borrow_mut().mark_dirty(true);
            }
        }
    }

    pub fn remove_reference(&mut self, source_line: Weak<RefCell<SourceLine>>) {
        // Remove the specific source line from referenced_lines
        self.referenced_lines.retain(|weak_ref| {
            if let (Some(existing), Some(target)) = (weak_ref.upgrade(), source_line.upgrade()) {
                !Rc::ptr_eq(&existing, &target)
            } else {
                false // Remove dead weak references
            }
        });
    }
}

pub struct SymbolTable {
    symbols: HashMap<String, Rc<RefCell<Symbol>>>,
}

impl SymbolTable {
    pub fn new() -> Self {
        Self {
            symbols: HashMap::new(),
        }
    }

    pub fn lookup_symbol(&mut self, name: &str) -> Rc<RefCell<Symbol>> {
        let symbol_name = name.to_uppercase();
        if let Some(symbol) = self.symbols.get(&symbol_name) {
            symbol.clone()
        } else {
            let symbol = Rc::new(RefCell::new(Symbol::new()));
            self.symbols.insert(symbol_name, symbol.clone());
            symbol
        }
    }

    pub fn lookup_symbol_with_reference(&mut self, name: &str, source_line: Weak<RefCell<SourceLine>>) -> Rc<RefCell<Symbol>> {
        let symbol_name = name.to_uppercase();
        let symbol = if let Some(existing) = self.symbols.get(&symbol_name) {
            existing.clone()
        } else {
            let new_symbol = Rc::new(RefCell::new(Symbol::new()));
            self.symbols.insert(symbol_name, new_symbol.clone());
            new_symbol
        };
        
        // Add reference if it's not a keyword
        if !symbol.borrow().is_keyword() {
            symbol.borrow_mut().add_reference(source_line.clone());
            // Also add the symbol to the source line's reference list
            if let Some(line) = source_line.upgrade() {
                line.borrow_mut().add_reference(Rc::downgrade(&symbol));
            }
        }
        
        symbol
    }

    pub fn lookup_keyword(&self, name: &str) -> Option<i32> {
        let symbol_name = name.to_uppercase();
        if let Some(symbol) = self.symbols.get(&symbol_name) {
            let symbol_ref = symbol.borrow();
            if symbol_ref.is_keyword() {
                Some(symbol_ref.get_value())
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn define_symbol(&mut self, name: &str, source_line: Weak<RefCell<SourceLine>>, value: i32) -> Rc<RefCell<Symbol>> {
        let symbol = self.lookup_symbol(name);
        {
            let mut symbol_ref = symbol.borrow_mut();
            symbol_ref.set_value(value);
            symbol_ref.add_definition(source_line.clone());
        }
        
        // Set the definition on the source line as well
        if let Some(line) = source_line.upgrade() {
            line.borrow_mut().set_definition(Some(Rc::downgrade(&symbol)), source_line.clone());
        }
        
        symbol
    }

    pub fn define_keyword(&mut self, name: &str, value: i32) -> Rc<RefCell<Symbol>> {
        let symbol_name = name.to_uppercase();
        let symbol = if let Some(existing) = self.symbols.get(&symbol_name) {
            existing.clone()
        } else {
            let new_symbol = Rc::new(RefCell::new(Symbol::new()));
            self.symbols.insert(symbol_name, new_symbol.clone());
            new_symbol
        };
        
        symbol.borrow_mut().set_keyword(value);
        symbol
    }
}