Files
foreignthon-core/src/foreignthon/cli.py

102 lines
3.0 KiB
Python

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"