diff --git a/src/tampy/transpiler.py b/src/tampy/transpiler.py index e69de29..63fe2f1 100644 --- a/src/tampy/transpiler.py +++ b/src/tampy/transpiler.py @@ -0,0 +1,82 @@ +"""Parse Tamil code into Python AST.""" + +from typing import Any +import ast + + +class TamilParser(ast.NodeVisitor): + """Parse Tamil code and map keywords to Python.""" + + def __init__(self, keywords: dict[str, str]): + self.keywords = keywords + self.errors: list[str] = [] + + def parse(self, code: str) -> ast.AST: + """Parse Tamil code and return Python AST.""" + try: + tree = ast.parse(code) + self._transform(tree) + return tree + except SyntaxError as e: + self.errors.append(f"SyntaxError at line {e.lineno}: {e.msg}") + raise + + def _transform(self, node: ast.AST) -> None: + """Transform node to handle Tamil keywords.""" + node = self._visit(node) + if isinstance(node, ast.AST): + for field, value in ast.iter_fields(node): + if isinstance(value, list): + for i, item in enumerate(value): + if isinstance(item, ast.AST): + value[i] = self._visit(item) + elif isinstance(value, ast.AST): + setattr(node, field, self._visit(value)) + + def _visit(self, node: ast.AST) -> Any: + """Visit and transform a single node.""" + if not hasattr(node, "lineno"): + return node + + line = node.lineno + col = getattr(node, "col_offset", 0) + + keyword = self._get_keyword_at_position(node, line, col) + if keyword: + node.keywords = self.keywords.get(keyword, keyword) + + visitor = self._get_visitor_type(type(node)) + if visitor: + return visitor(node) + + return node + + def _get_keyword_at_position(self, node: ast.AST, lineno: int, col: int) -> str | None: + """Check if keyword appears at given position.""" + # This is a placeholder - actual keyword detection will use tokens + # For now, we'll handle common keywords by name + node_type = type(node).__name__ + + keyword_map = { + "FunctionDef": "def", + "Return": "return", + "If": "if", + "For": "for", + "While": "while", + "ClassDef": "class", + "Import": "import", + "From": "from", + "Try": "try", + "ExceptHandler": "except", + "With": "with", + "BoolOp": "and" if isinstance(node, ast.BoolOp) and node.op.__class__.__name__ == "And" else "or", + "Compare": "in", + "NamedExpr": "if", + } + + return keyword_map.get(node_type) + + def _get_visitor_type(self, node_type: type) -> Any | None: + """Get visitor method for node type.""" + visitor_name = f"visit_{node_type.__name__}" + return getattr(self, visitor_name, None) diff --git a/tests/test_parser.py b/tests/test_parser.py new file mode 100644 index 0000000..7e0da5d --- /dev/null +++ b/tests/test_parser.py @@ -0,0 +1,44 @@ +"""Test parser functionality.""" + +import pytest +from src.tampy.transpiler import TamilParser + + +def test_parse_simple_python(): + """Test parsing simple Python code.""" + code = "print('hello')" + keywords = {"print": "இருப்பு"} + + parser = TamilParser(keywords) + tree = parser.parse(code) + + assert isinstance(tree, ast.Module) + + +def test_parse_import_statement(): + """Test parsing import statement.""" + code = "import sys" + keywords = {"import": "மேற்கோள்கள்"} + + parser = TamilParser(keywords) + tree = parser.parse(code) + + assert isinstance(tree, ast.Module) + + +def test_parse_function_definition(): + """Test parsing function definition.""" + code = "def foo(): pass" + keywords = {"def": "வரையறை"} + + parser = TamilParser(keywords) + tree = parser.parse(code) + + assert isinstance(tree, ast.Module) + + +if __name__ == "__main__": + test_parse_simple_python() + test_parse_import_statement() + test_parse_function_definition() + print("All tests passed")