from __future__ import annotations import sys from pathlib import Path import click from . import __version__ from .errors import activate from .transpiler import run_transpiled, transpile_file @click.group() @click.version_option(__version__, prog_name="fpy") def main(): """ForeignThon — write Python in any language.""" pass @main.command() @click.argument("file", type=click.Path(exists=True, path_type=Path)) @click.option("--lang", "-l", default=None, help="Override language code (e.g. es, ta)") @click.option("--keep", is_flag=True, help="Keep the compiled .py alongside the source") def run(file: Path, lang: str | None, keep: bool): """Transpile and run a foreign-language Python file.""" if lang: source = file.read_text(encoding="utf-8") if not source.startswith("# foreignthon:"): source = f"# foreignthon: {lang}\n" + source file.write_text(source, encoding="utf-8") transpiled = transpile_file(file) detected_lang = lang or _lang_from_file(file) activate(detected_lang) if keep: out_path = file.with_suffix("").with_suffix(".compiled.py") out_path.write_text(transpiled, encoding="utf-8") click.echo(f"Compiled: {out_path}") run_transpiled(file, transpiled) @main.command() @click.argument("file", type=click.Path(exists=True, path_type=Path)) @click.option("--output", "-o", default=None, help="Output path (default: beside source)") def compile(file: Path, output: str | None): """Transpile a file to standard Python without running it.""" transpiled = transpile_file(file) out_path = ( Path(output) if output else file.with_suffix("").with_suffix(".compiled.py") ) out_path.write_text(transpiled, encoding="utf-8") click.echo(f"Compiled: {out_path}") @main.command() @click.argument("file", type=click.Path(exists=True, path_type=Path)) def check(file: Path): """Validate a foreign-language file without running it.""" import ast try: transpiled = transpile_file(file) ast.parse(transpiled) click.echo(f"✓ {file.name} looks good.") except SyntaxError as e: click.echo(f"✗ Syntax error: {e}", err=True) sys.exit(1) except Exception as e: click.echo(f"✗ {e}", err=True) sys.exit(1) @main.command("pack") @click.argument("json_file", type=click.Path(exists=True, path_type=Path)) def validate_pack(json_file: Path): """Validate a language pack JSON file.""" import json from .pack import REQUIRED_SECTIONS with open(json_file, encoding="utf-8") as f: data = json.load(f) missing = REQUIRED_SECTIONS - data.keys() if missing: click.echo(f"✗ Missing sections: {missing}", err=True) sys.exit(1) click.echo(f"✓ Pack '{data['meta']['name']}' is valid.") def _lang_from_file(path: Path) -> str: suffixes = path.suffixes if len(suffixes) >= 2 and suffixes[-1] == ".py": return suffixes[-2].lstrip(".") return "en"