readmes and mds plus fixed ruff
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
# Contributing to ForeignThon
|
||||||
|
|
||||||
|
## Project structure
|
||||||
|
foreignthon/
|
||||||
|
├── packages/
|
||||||
|
│ ├── foreignthon/ # core engine + fpy CLI
|
||||||
|
│ │ ├── src/foreignthon/
|
||||||
|
│ │ │ ├── cli.py # fpy commands
|
||||||
|
│ │ │ ├── transpiler.py # tokenizer-based transpiler
|
||||||
|
│ │ │ ├── pack.py # language pack loader
|
||||||
|
│ │ │ └── errors.py # bilingual error hook
|
||||||
|
│ │ └── tests/
|
||||||
|
│ └── langs/
|
||||||
|
│ └── es/ # Spanish language pack
|
||||||
|
│ └── src/foreignthon_es/es.json
|
||||||
|
|
||||||
|
## Setting up
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m venv .venv && source .venv/bin/activate
|
||||||
|
pip install -e "packages/foreignthon[dev]"
|
||||||
|
pip install -e packages/langs/es
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pytest packages/foreignthon/tests/ -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding a new language pack
|
||||||
|
|
||||||
|
1. Copy `packages/langs/es/` to `packages/langs/<code>/`
|
||||||
|
2. Rename `foreignthon_es` → `foreignthon_<code>` throughout
|
||||||
|
3. Fill in `<code>.json` following the same schema as `es.json`
|
||||||
|
4. Validate it: `fpy pack packages/langs/<code>/src/foreignthon_<code>/<code>.json`
|
||||||
|
5. Add tests if the language has tricky characters or edge cases
|
||||||
|
6. Open a PR or publish independently as `foreignthon-<code>` on PyPI
|
||||||
|
|
||||||
|
## Language pack schema
|
||||||
|
|
||||||
|
Every pack must have these top-level keys:
|
||||||
|
`meta`, `keywords`, `builtins`, `exceptions`, `error_messages`, `stdlib`
|
||||||
|
|
||||||
|
See `packages/langs/es/src/foreignthon_es/es.json` as the reference.
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ruff check packages/foreignthon/src
|
||||||
|
```
|
||||||
|
|||||||
89
README.md
89
README.md
@@ -0,0 +1,89 @@
|
|||||||
|
DME.md << 'EOF'
|
||||||
|
# ForeignThon
|
||||||
|
|
||||||
|
Write Python in any human language. ForeignThon transpiles `.es.py`, `.ta.py` (and more) files into standard Python — keywords, builtins, exceptions, all of it.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# hola.es.py
|
||||||
|
definir saludar(nombre):
|
||||||
|
retornar f"Hola, {nombre}!"
|
||||||
|
|
||||||
|
para i en rango(3):
|
||||||
|
imprimir(saludar(f"mundo {i}"))
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fpy run hola.es.py
|
||||||
|
# Hola, mundo 0!
|
||||||
|
# Hola, mundo 1!
|
||||||
|
# Hola, mundo 2!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install foreignthon
|
||||||
|
pip install foreignthon-es # Spanish
|
||||||
|
pip install foreignthon-ta # Tamil
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fpy run script.es.py # transpile and run
|
||||||
|
fpy compile script.es.py # output a .compiled.py file
|
||||||
|
fpy check script.es.py # validate without running
|
||||||
|
fpy pack mylang.json # validate a language pack
|
||||||
|
```
|
||||||
|
|
||||||
|
### Language override
|
||||||
|
|
||||||
|
```python
|
||||||
|
# foreignthon: es
|
||||||
|
# ^ overrides the file extension
|
||||||
|
```
|
||||||
|
|
||||||
|
Or via CLI flag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fpy run script.py --lang es
|
||||||
|
```
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
Errors are shown in your language first, English below:
|
||||||
|
[ES] ErrorDeDivisionCero: Error: división por cero
|
||||||
|
[EN] ZeroDivisionError: division by zero
|
||||||
|
|
||||||
|
## Language Packs
|
||||||
|
|
||||||
|
A language pack is a JSON file + a tiny Python wrapper published as `foreignthon-xx` on PyPI.
|
||||||
|
See `packages/langs/es/` for the reference implementation.
|
||||||
|
|
||||||
|
The JSON covers:
|
||||||
|
- **keywords** — `si → if`, `para → for`, `definir → def` …
|
||||||
|
- **builtins** — `imprimir → print`, `rango → range` …
|
||||||
|
- **exceptions** — `ErrorDeValor → ValueError` …
|
||||||
|
- **error_messages** — bilingual error output
|
||||||
|
- **stdlib** — `matematicas → math` …
|
||||||
|
|
||||||
|
Validate your pack before publishing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fpy pack mylang.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <your-repo>
|
||||||
|
cd foreignthon
|
||||||
|
python -m venv .venv && source .venv/bin/activate
|
||||||
|
pip install -e "packages/foreignthon[dev]"
|
||||||
|
pip install -e packages/langs/es
|
||||||
|
pytest packages/foreignthon/tests/ -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
GPL
|
||||||
|
|||||||
@@ -52,3 +52,7 @@ src = ["src"]
|
|||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "I"]
|
select = ["E", "F", "I"]
|
||||||
|
ignore = ["E501"]
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"pack.py" = ["E501"]
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import click
|
|||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .errors import activate
|
from .errors import activate
|
||||||
from .transpiler import transpile_file, run_transpiled
|
from .transpiler import run_transpiled, transpile_file
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
@@ -20,7 +20,7 @@ def main():
|
|||||||
@main.command()
|
@main.command()
|
||||||
@click.argument("file", type=click.Path(exists=True, path_type=Path))
|
@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("--lang", "-l", default=None, help="Override language code (e.g. es, ta)")
|
||||||
@click.option("--keep", is_flag=True, help="Keep the compiled .py file alongside the source")
|
@click.option("--keep", is_flag=True, help="Keep the compiled .py alongside the source")
|
||||||
def run(file: Path, lang: str | None, keep: bool):
|
def run(file: Path, lang: str | None, keep: bool):
|
||||||
"""Transpile and run a foreign-language Python file."""
|
"""Transpile and run a foreign-language Python file."""
|
||||||
if lang:
|
if lang:
|
||||||
@@ -44,12 +44,15 @@ def run(file: Path, lang: str | None, keep: bool):
|
|||||||
|
|
||||||
@main.command()
|
@main.command()
|
||||||
@click.argument("file", type=click.Path(exists=True, path_type=Path))
|
@click.argument("file", type=click.Path(exists=True, path_type=Path))
|
||||||
@click.option("--output", "-o", default=None, help="Output path (default: same dir as source)")
|
@click.option("--output", "-o", default=None, help="Output path (default: beside source)")
|
||||||
def compile(file: Path, output: str | None):
|
def compile(file: Path, output: str | None):
|
||||||
"""Transpile a file to standard Python without running it."""
|
"""Transpile a file to standard Python without running it."""
|
||||||
transpiled = transpile_file(file)
|
transpiled = transpile_file(file)
|
||||||
|
|
||||||
out_path = Path(output) if output else file.with_suffix("").with_suffix(".compiled.py")
|
out_path = (
|
||||||
|
Path(output) if output
|
||||||
|
else file.with_suffix("").with_suffix(".compiled.py")
|
||||||
|
)
|
||||||
out_path.write_text(transpiled, encoding="utf-8")
|
out_path.write_text(transpiled, encoding="utf-8")
|
||||||
click.echo(f"Compiled: {out_path}")
|
click.echo(f"Compiled: {out_path}")
|
||||||
|
|
||||||
@@ -77,6 +80,7 @@ def check(file: Path):
|
|||||||
def validate_pack(json_file: Path):
|
def validate_pack(json_file: Path):
|
||||||
"""Validate a language pack JSON file."""
|
"""Validate a language pack JSON file."""
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from .pack import REQUIRED_SECTIONS
|
from .pack import REQUIRED_SECTIONS
|
||||||
|
|
||||||
with open(json_file, encoding="utf-8") as f:
|
with open(json_file, encoding="utf-8") as f:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from .pack import load_pack, PackNotFoundError
|
from .pack import PackNotFoundError, load_pack
|
||||||
|
|
||||||
_active_lang: str | None = None
|
_active_lang: str | None = None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user