syster-base 0.1.12-alpha

Core library for SysML v2 and KerML parsing, AST, and semantic analysis
Documentation
use crate::core::Span;
use crate::semantic::types::SemanticRole;

/// Unique identifier for a symbol in the arena.
/// Uses u32 for compact storage (supports ~4 billion symbols).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SymbolId(pub u32);

impl SymbolId {
    /// Create a new SymbolId from an index
    pub fn new(index: usize) -> Self {
        Self(index as u32)
    }

    /// Get the index into the arena
    pub fn index(self) -> usize {
        self.0 as usize
    }
}

/// Represents a named element in a SysML/KerML model
#[derive(Debug, Clone, PartialEq)]
pub enum Symbol {
    Package {
        name: String,
        qualified_name: String,
        scope_id: usize,
        source_file: Option<String>,
        span: Option<Span>,
        documentation: Option<String>,
    },
    Classifier {
        name: String,
        qualified_name: String,
        kind: String,
        is_abstract: bool,
        scope_id: usize,
        source_file: Option<String>,
        span: Option<Span>,
        documentation: Option<String>,
        specializes: Vec<String>,
    },
    Feature {
        name: String,
        qualified_name: String,
        scope_id: usize,
        feature_type: Option<String>,
        source_file: Option<String>,
        span: Option<Span>,
        documentation: Option<String>,
        subsets: Vec<String>,
        redefines: Vec<String>,
    },
    Definition {
        name: String,
        qualified_name: String,
        kind: String,
        semantic_role: Option<SemanticRole>,
        scope_id: usize,
        source_file: Option<String>,
        span: Option<Span>,
        documentation: Option<String>,
        specializes: Vec<String>,
    },
    Usage {
        name: String,
        qualified_name: String,
        kind: String,
        semantic_role: Option<SemanticRole>,
        usage_type: Option<String>,
        scope_id: usize,
        source_file: Option<String>,
        span: Option<Span>,
        documentation: Option<String>,
        subsets: Vec<String>,
        redefines: Vec<String>,
        /// Perform targets (e.g., from `perform startVehicle.trigger1;` nested in this usage)
        performs: Vec<String>,
        /// References targets (e.g., from `lugNutCompositePort ::> wheel1.lugNutCompositePort`)
        references: Vec<String>,
    },
    Alias {
        name: String,
        qualified_name: String,
        target: String,
        target_span: Option<Span>,
        scope_id: usize,
        source_file: Option<String>,
        span: Option<Span>,
    },
    /// An import statement (e.g., `import ScalarValues::*`)
    Import {
        /// The import path (e.g., "ScalarValues::*")
        path: String,
        /// Span of the import path for semantic highlighting
        path_span: Option<Span>,
        /// Unique key for this import (path + scope)
        qualified_name: String,
        is_recursive: bool,
        scope_id: usize,
        source_file: Option<String>,
        span: Option<Span>,
    },
    /// A named comment (e.g., `comment cmt /* text */`)
    Comment {
        name: String,
        qualified_name: String,
        scope_id: usize,
        source_file: Option<String>,
        span: Option<Span>,
        documentation: Option<String>,
    },
}

impl Symbol {
    /// Returns the qualified name of this symbol
    pub fn qualified_name(&self) -> &str {
        match self {
            Symbol::Package { qualified_name, .. }
            | Symbol::Classifier { qualified_name, .. }
            | Symbol::Feature { qualified_name, .. }
            | Symbol::Definition { qualified_name, .. }
            | Symbol::Usage { qualified_name, .. }
            | Symbol::Alias { qualified_name, .. }
            | Symbol::Import { qualified_name, .. }
            | Symbol::Comment { qualified_name, .. } => qualified_name,
        }
    }

    /// Returns the simple name of this symbol
    pub fn name(&self) -> &str {
        match self {
            Symbol::Package { name, .. }
            | Symbol::Classifier { name, .. }
            | Symbol::Feature { name, .. }
            | Symbol::Definition { name, .. }
            | Symbol::Usage { name, .. }
            | Symbol::Alias { name, .. }
            | Symbol::Comment { name, .. } => name,
            Symbol::Import { path, .. } => path,
        }
    }

    /// Returns the scope ID where this symbol was defined
    pub fn scope_id(&self) -> usize {
        match self {
            Symbol::Package { scope_id, .. }
            | Symbol::Classifier { scope_id, .. }
            | Symbol::Feature { scope_id, .. }
            | Symbol::Definition { scope_id, .. }
            | Symbol::Usage { scope_id, .. }
            | Symbol::Alias { scope_id, .. }
            | Symbol::Import { scope_id, .. }
            | Symbol::Comment { scope_id, .. } => *scope_id,
        }
    }

    /// Returns the source file path where this symbol was defined
    pub fn source_file(&self) -> Option<&str> {
        match self {
            Symbol::Package { source_file, .. }
            | Symbol::Classifier { source_file, .. }
            | Symbol::Feature { source_file, .. }
            | Symbol::Definition { source_file, .. }
            | Symbol::Usage { source_file, .. }
            | Symbol::Alias { source_file, .. }
            | Symbol::Import { source_file, .. }
            | Symbol::Comment { source_file, .. } => source_file.as_deref(),
        }
    }

    /// Returns the source span where this symbol was defined
    pub fn span(&self) -> Option<Span> {
        match self {
            Symbol::Package { span, .. }
            | Symbol::Classifier { span, .. }
            | Symbol::Feature { span, .. }
            | Symbol::Definition { span, .. }
            | Symbol::Usage { span, .. }
            | Symbol::Alias { span, .. }
            | Symbol::Import { span, .. }
            | Symbol::Comment { span, .. } => *span,
        }
    }

    /// Returns true if this symbol can be used as a type
    pub fn is_type(&self) -> bool {
        matches!(self, Symbol::Classifier { .. } | Symbol::Definition { .. })
    }

    /// Returns the type reference for Features that have one
    pub fn type_reference(&self) -> Option<&str> {
        match self {
            Symbol::Feature { feature_type, .. } => feature_type.as_deref(),
            _ => None,
        }
    }

    /// Returns the documentation for this symbol, if any
    pub fn documentation(&self) -> Option<&str> {
        match self {
            Symbol::Package { documentation, .. }
            | Symbol::Classifier { documentation, .. }
            | Symbol::Feature { documentation, .. }
            | Symbol::Definition { documentation, .. }
            | Symbol::Usage { documentation, .. }
            | Symbol::Comment { documentation, .. } => documentation.as_deref(),
            Symbol::Alias { .. } | Symbol::Import { .. } => None,
        }
    }

    /// Returns the subsets relationships for Features and Usages
    pub fn subsets(&self) -> &[String] {
        match self {
            Symbol::Feature { subsets, .. } | Symbol::Usage { subsets, .. } => subsets,
            _ => &[],
        }
    }

    /// Returns the redefines relationships for Features and Usages
    pub fn redefines(&self) -> &[String] {
        match self {
            Symbol::Feature { redefines, .. } | Symbol::Usage { redefines, .. } => redefines,
            _ => &[],
        }
    }

    /// Returns the performs relationships for Usages (from nested perform statements)
    pub fn performs(&self) -> &[String] {
        match self {
            Symbol::Usage { performs, .. } => performs,
            _ => &[],
        }
    }

    /// Returns the references relationships for Usages (from `::>` featured_by)
    pub fn references(&self) -> &[String] {
        match self {
            Symbol::Usage { references, .. } => references,
            _ => &[],
        }
    }

    /// Returns the specializes relationships for Definitions and Classifiers
    pub fn specializes(&self) -> &[String] {
        match self {
            Symbol::Definition { specializes, .. } | Symbol::Classifier { specializes, .. } => {
                specializes
            }
            _ => &[],
        }
    }
}