thalir-core 0.1.0

Core IR types and builders for ThalIR smart contract analysis
Documentation
use crate::{
    block::BlockId,
    types::TypeRegistry,
    values::{TempId, VarId},
};
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct SourceMapping {
    pub file: String,
    pub line: u32,
    pub column: u32,
    pub length: u32,
}

#[derive(Debug, Default)]
pub struct SSATracker {
    variables: HashMap<String, VarId>,
    versions: HashMap<VarId, u32>,
    next_var_id: u32,
    next_temp_id: u32,
}

impl SSATracker {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn get_or_create_var(&mut self, name: &str) -> VarId {
        if let Some(&id) = self.variables.get(name) {
            id
        } else {
            let id = VarId(self.next_var_id);
            self.next_var_id += 1;
            self.variables.insert(name.to_string(), id);
            self.versions.insert(id, 0);
            id
        }
    }

    pub fn new_temp(&mut self) -> TempId {
        let id = TempId(self.next_temp_id);
        self.next_temp_id += 1;
        id
    }

    pub fn get_version(&self, var: VarId) -> u32 {
        self.versions.get(&var).copied().unwrap_or(0)
    }

    pub fn increment_version(&mut self, var: VarId) -> u32 {
        let version = self.get_version(var) + 1;
        self.versions.insert(var, version);
        version
    }
}

pub struct IRContext {
    source_mappings: HashMap<String, SourceMapping>,
    id_counter: u64,
    type_registry: TypeRegistry,
    ssa_tracker: SSATracker,
    current_contract: Option<String>,
    current_function: Option<String>,
    current_block: Option<BlockId>,
    errors: Vec<String>,
}

impl IRContext {
    pub fn new() -> Self {
        Self {
            source_mappings: HashMap::new(),
            id_counter: 1,
            type_registry: TypeRegistry::new(),
            ssa_tracker: SSATracker::new(),
            current_contract: None,
            current_function: None,
            current_block: None,
            errors: Vec::new(),
        }
    }

    pub fn next_id(&mut self) -> u64 {
        let id = self.id_counter;
        self.id_counter += 1;
        id
    }

    pub fn next_string_id(&mut self, prefix: &str) -> String {
        format!("{}_{}", prefix, self.next_id())
    }

    pub fn add_source_mapping(&mut self, id: String, mapping: SourceMapping) {
        self.source_mappings.insert(id, mapping);
    }

    pub fn get_source_mapping(&self, id: &str) -> Option<&SourceMapping> {
        self.source_mappings.get(id)
    }

    pub fn set_current_contract(&mut self, name: String) {
        self.current_contract = Some(name);
    }

    pub fn current_contract(&self) -> Option<&str> {
        self.current_contract.as_deref()
    }

    pub fn set_current_function(&mut self, name: String) {
        self.current_function = Some(name);
    }

    pub fn current_function(&self) -> Option<&str> {
        self.current_function.as_deref()
    }

    pub fn set_current_block(&mut self, block: BlockId) {
        self.current_block = Some(block);
    }

    pub fn current_block(&self) -> Option<BlockId> {
        self.current_block
    }

    pub fn ssa(&mut self) -> &mut SSATracker {
        &mut self.ssa_tracker
    }

    pub fn types(&mut self) -> &mut TypeRegistry {
        &mut self.type_registry
    }

    pub fn add_error(&mut self, error: String) {
        self.errors.push(error);
    }

    pub fn has_errors(&self) -> bool {
        !self.errors.is_empty()
    }

    pub fn errors(&self) -> &[String] {
        &self.errors
    }

    pub fn clear(&mut self) {
        self.source_mappings.clear();
        self.id_counter = 1;
        self.ssa_tracker = SSATracker::new();
        self.current_contract = None;
        self.current_function = None;
        self.current_block = None;
        self.errors.clear();
    }
}