use std::{ collections::{ BTreeMap, BTreeSet }, ops::{ Index, IndexMut }, sync::Arc };
use crate::language::{ parser::{ EditorAnalysis, editor::analyze_editor_tree },
text::span::SourceSpan };
mod semantic;
pub mod highlight;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SymbolKind
{
Variable,
Type,
Function,
Method,
Builtin,
Alias,
ExternalCommand,
Field,
EnumVariant,
Module,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SymbolDescriptor
{
pub kind: SymbolKind,
pub type_id: Option<usize>,
pub return_type: Option<usize>,
}
impl SymbolDescriptor
{
pub fn new(kind: SymbolKind, type_id: Option<usize>) -> Self
{ Self { kind, type_id, return_type: None } }
}
#[derive(Clone, Debug, Default)]
pub struct TypeDescriptor
{
pub name: String,
pub parent: Option<usize>,
pub item: Option<usize>,
pub key: Option<usize>,
pub fields: BTreeMap<String, SymbolDescriptor>,
pub variants: BTreeSet<String>,
pub methods: BTreeMap<String, SymbolDescriptor>,
pub call_result: Option<usize>,
}
#[derive(Clone, Debug, Default)]
pub struct SymbolSnapshot
{
pub symbols: BTreeMap<String, SymbolDescriptor>,
pub types: Arc<Vec<TypeDescriptor>>,
pub external_commands: BTreeSet<String>,
}
#[derive(Clone, Debug)]
pub struct TypeTable
{
registered: Arc<Vec<TypeDescriptor>>,
local: Vec<TypeDescriptor>,
}
impl TypeTable
{
pub(super) fn new(registered: Arc<Vec<TypeDescriptor>>) -> Self
{ Self { registered, local: Vec::new() } }
pub fn get(&self, id: usize) -> Option<&TypeDescriptor>
{
if id < self.registered.len() { self.registered.get(id) }
else { self.local.get(id - self.registered.len()) }
}
pub(super) fn len(&self) -> usize { self.registered.len() + self.local.len() }
pub(super) fn push(&mut self, descriptor: TypeDescriptor) { self.local.push(descriptor); }
}
impl Index<usize> for TypeTable
{
type Output = TypeDescriptor;
fn index(&self, id: usize) -> &Self::Output { self.get(id).unwrap() }
}
impl IndexMut<usize> for TypeTable
{
fn index_mut(&mut self, id: usize) -> &mut Self::Output
{
&mut self.local[id - self.registered.len()]
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SemanticFact
{
pub span: SourceSpan,
pub kind: SymbolKind,
pub type_id: Option<usize>,
}
pub struct SemanticAnalysis
{
pub source: EditorAnalysis,
pub facts: Vec<SemanticFact>,
pub types: TypeTable,
}
pub fn analyze_semantics(source: &str, snapshot: &SymbolSnapshot) -> SemanticAnalysis
{
let (analysis, statements) = analyze_editor_tree(source);
let (facts, types) = semantic::classify(source, &analysis, &statements, snapshot);
SemanticAnalysis { source: analysis, facts, types }
}