scryer-engine 0.2.0

Tree-sitter and stack-graphs AST indexing engine for Scryer code intelligence
use std::path::{Path, PathBuf};

use crate::payload::{RawScope, RawSymbol};

/// Resolution result produced by the Tier 2 Tree-sitter SCM heuristics fallback.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FallbackResolution {
    pub symbol_name: String,
    pub qualified_name: String,
    pub file_path: PathBuf,
    pub kind: String,
    pub start_line: u32,
    pub start_col: u32,
    pub end_line: u32,
    pub end_col: u32,
}

/// Fallback resolver utilizing Tree-sitter AST queries and lexical scope matching.
pub struct ScmFallbackResolver;

impl ScmFallbackResolver {
    /// Attempt to resolve an identifier reference using lexical scopes and declared symbols.
    pub fn resolve_identifier(
        identifier: &str,
        file_path: &Path,
        line: u32,
        _col: u32,
        scopes: &[RawScope],
        symbols: &[RawSymbol],
    ) -> Option<FallbackResolution> {
        // 1. Find innermost enclosing scope covering line
        let mut enclosing_scope = None;
        for scope in scopes {
            if line >= scope.start_line && line <= scope.end_line {
                match enclosing_scope {
                    None => enclosing_scope = Some(scope),
                    Some(prev) => {
                        // Choose smaller/nested scope
                        if (scope.end_line - scope.start_line) < (prev.end_line - prev.start_line) {
                            enclosing_scope = Some(scope);
                        }
                    }
                }
            }
        }

        // 2. Check if a symbol in current file matches identifier
        // First prefer symbols inside the enclosing scope or module
        if let Some(scope) = enclosing_scope {
            for sym in symbols {
                if sym.name == identifier && sym.scope_local_id == Some(scope.local_id) {
                    return Some(FallbackResolution {
                        symbol_name: sym.name.clone(),
                        qualified_name: sym.qualified_name.clone(),
                        file_path: file_path.to_path_buf(),
                        kind: sym.kind.clone(),
                        start_line: sym.start_line,
                        start_col: 0,
                        end_line: sym.end_line,
                        end_col: 0,
                    });
                }
            }
        }

        // 3. Check any symbol in file
        for sym in symbols {
            if sym.name == identifier {
                return Some(FallbackResolution {
                    symbol_name: sym.name.clone(),
                    qualified_name: sym.qualified_name.clone(),
                    file_path: file_path.to_path_buf(),
                    kind: sym.kind.clone(),
                    start_line: sym.start_line,
                    start_col: 0,
                    end_line: sym.end_line,
                    end_col: 0,
                });
            }
        }

        None
    }
}