"""Tree-sitter parser integration for multi-language support."""
import importlib
from typing import Optional
import tree_sitter
from ..config import LANGUAGE_GRAMMARS
class TreeSitterManager:
"""Manages tree-sitter parsers for different languages."""
def __init__(self) -> None:
"""Initialize the parser manager."""
self._parsers: dict[str, tree_sitter.Parser] = {}
self._languages: dict[str, tree_sitter.Language] = {}
def get_parser(self, language: str) -> Optional[tree_sitter.Parser]:
"""Get or create a parser for the given language."""
if language not in LANGUAGE_GRAMMARS:
return None
if language not in self._parsers:
lang = self._get_language(language)
if lang is None:
return None
parser = tree_sitter.Parser(lang)
self._parsers[language] = parser
return self._parsers[language]
def _get_language(self, language: str) -> Optional[tree_sitter.Language]:
"""Get or load a language grammar."""
if language in self._languages:
return self._languages[language]
try:
grammar_name = LANGUAGE_GRAMMARS[language]
module = importlib.import_module(grammar_name)
self._languages[language] = tree_sitter.Language(module.language())
return self._languages[language]
except ImportError:
return None
def parse(self, source_code: bytes, language: str) -> Optional[tree_sitter.Tree]:
"""Parse source code and return the AST."""
parser = self.get_parser(language)
if parser is None:
return None
return parser.parse(source_code)
def get_node_text(self, node: tree_sitter.Node, source_code: bytes) -> str:
"""Get the text content of a node."""
return source_code[node.start_byte : node.end_byte].decode("utf-8")
def get_node_line_range(self, node: tree_sitter.Node) -> tuple[int, int]:
"""Get the line range of a node (start_line, end_line)."""
# tree-sitter uses 0-based line numbers
return (node.start_point.row + 1, node.end_point.row + 1)
# Global parser manager instance
_parser_manager: Optional[TreeSitterManager] = None
def get_parser_manager() -> TreeSitterManager:
"""Get the global parser manager instance."""
global _parser_manager
if _parser_manager is None:
_parser_manager = TreeSitterManager()
return _parser_manager