97 lines
5.1 KiB
Markdown
97 lines
5.1 KiB
Markdown
# Self-Hosting Front MVP — Ny → JSON v0
|
||
|
||
Status: drafting (Phase 15.9 entry)
|
||
|
||
## Purpose
|
||
- Deliver a Ny-written front-end that lowers Stage-3 Ny source into JSON v0 accepted by the existing MIR/VM/LLVM lines.
|
||
- Keep Core (`src/`) untouched; all implementation resides under `lang/src/compiler/`(旧 `apps/selfhost-compiler/` は互換ライン)。
|
||
- Fail fast: unsupported syntax must abort with a precise diagnostic, never fall back to Rust-side parser.
|
||
|
||
## Scope (Day 1–2)
|
||
- Expressions: integer literal, boolean literal, null, binary ops (`+ - * / %`, comparisons `== != < <= > >=`), logical `&& ||`, grouped `(...)`.
|
||
- Statements: `return`, `local`, `assignment`, `if/else`, `loop` (while-style), `break`, `continue`.
|
||
- Calls: direct function call (`foo()`), method call sugar (`obj.method()`), builtin boxes (Array/Map/String minimal) deferred to Day 3–4.
|
||
- Metadata: `meta.usings` populated from `ParserBox.extract_usings` (already implemented).
|
||
- JSON normalization: `JsonProgramBox` fixes key orderと既定値を整備(Local/Const/If/Loop/Return/Call、空配列は常に`[]`、null配列は[]に正規化)。
|
||
|
||
## Interfaces
|
||
| box | responsibility |
|
||
| --- | --- |
|
||
| `ParserBox` | Tokenize/parse Ny source into Stage-1 AST JSON. Already handles Stage-2 constructs; ensure Stage-3 gating by `stage3_enable`. |
|
||
| `EmitterBox` | Convert Stage-1 AST JSON to JSON v0 Program. Delegates normalization/meta injection to `JsonProgramBox`. Must guarantee single-line output when `NYASH_JSON_ONLY=1`. |
|
||
| `MirEmitterBox` | Out of scope for Day 1–2 (stub remains). |
|
||
|
||
### Contracts
|
||
- `ParserBox.parse_program2(src)` returns a `Program` JSON string with `version/kind/body/meta` keys.
|
||
- `EmitterBox.emit_program(ast_json, usings_json)` injects metadata and *must* avoid altering the AST when `ast_json` already conforms to JSON v0.
|
||
- `Main.main(args)` (`lang/src/compiler/entry/compiler.hako`) orchestrates: read source → parse → emit → print.
|
||
|
||
## Deliverables
|
||
1. **Documentation**
|
||
- This file (living roadmap).
|
||
- Update `CURRENT_TASK_SELFHOST.md` with checklists and timeline (done).
|
||
- README snippet explaining how to run the front MVP via `hakorune` flags.
|
||
2. **Code**
|
||
- Extend `ParserBox` where gaps exist (Stage-3 gating, diagnostics).
|
||
- Add `lang/src/compiler/stage1/json_program_box.hako` — normalization box for Program/Stmt/Expr + `meta.usings` injection.
|
||
- Keep `EmitterBox` thin by delegating to `JsonProgramBox`.
|
||
3. **Tests**
|
||
- Quick smokes: `tools/smokes/v2/profiles/quick/selfhost/selfhost_min_const_ret_vm.sh` など。
|
||
- Normalization shape: `tools/smokes/v2/profiles/quick/selfhost/selfhost_json_normalize_shapes.sh`(If/Loop/Call/Return, meta.usings 確認)。
|
||
- Edge normalization: `tools/smokes/v2/profiles/quick/selfhost/selfhost_json_normalize_edges.sh`(Loop body null→[]、Call args null→[]、Null ノード維持)。
|
||
- Harness comparator: `tools/smokes/v2/run.sh --profile quick` の `selfhost_front_min_vm_llvm.sh`(LLVM 環境があれば)
|
||
|
||
## Fail-Fast Checklist
|
||
- Parser errors include position info (gpos) and stop compilation.
|
||
- Unsupported statements/expressions raise `StageUnsupported` error (box-based), not silent drop.
|
||
- JSON builder ensures key order (`version`, `kind`, `body`, `meta`) for deterministic output.
|
||
|
||
## Box Layout Proposal (migrated)
|
||
```
|
||
lang/src/compiler/
|
||
├── parser/ # Stage-1/2/3 parser boxes
|
||
│ ├── parser_box.hako
|
||
│ ├── parser_expr_box.hako
|
||
│ └── parser_stmt_box.hako
|
||
├── emitter/ # emit helpers and normalization
|
||
│ ├── emitter_box.hako
|
||
│ └── json_program_box.hako
|
||
├── entry/
|
||
│ └── compiler.hako # entry (Ny→JSON v0)
|
||
└── docs/
|
||
└── front_mvp.md # this file
|
||
```
|
||
|
||
## Execution Examples
|
||
Emit-only (JSON header, pipeline v2):
|
||
```
|
||
NYASH_USE_NY_COMPILER=1 \
|
||
NYASH_NY_COMPILER_MIN_JSON=1 \
|
||
NYASH_NY_COMPILER_CHILD_ARGS="--pipeline-v2" \
|
||
NYASH_NY_COMPILER_EMIT_ONLY=1 \
|
||
NYASH_JSON_ONLY=1 \
|
||
./target/release/hakorune --backend vm apps/tests/selfhost_min/const_ret.hako
|
||
```
|
||
Expected output: `{"version":0,...}` single-line JSON.
|
||
|
||
Execute via VM (Result comparison):
|
||
```
|
||
NYASH_USE_NY_COMPILER=1 \
|
||
NYASH_NY_COMPILER_EMIT_ONLY=0 \
|
||
NYASH_SELFHOST_READ_TMP=1 \
|
||
./target/release/hakorune --backend vm apps/tests/selfhost_min/const_ret.hako
|
||
```
|
||
Expected output: `Result: 42`
|
||
|
||
## Timeline (rolling)
|
||
- **Day 1**: Docs + const/return + binop. Add selfhost_min_const_ret smoke.
|
||
- **Day 2**: if/else, loop sum smoke, branch diagnostics.
|
||
- **Day 3**: Calls/BoxCall minimal, DP integration reuse.
|
||
- **Day 4**: externcall string primitives, verify via `run_llvm_extended.sh`.
|
||
- **Day 5**: CLI polish + docs cleanup + bench harness alignment.
|
||
|
||
## Open Questions
|
||
- Should Stage-3 acceptance (`break`, `continue`, `throw`) be gated by CLI flag? (Currently via `--stage3`.)
|
||
- JSON v0 normalization: do we normalize binary op names (`+` → `Add`) or keep literal symbols? (Existing Stage-1 uses symbols; MIR builder already maps them.)
|
||
- How much of `ParserBox` should move into dedicated modules for maintainability? (Deferred; focus on MVP shipping.)
|