Files
hakorune/docs/private/roadmap/selfhosting/front_mvp.md

5.1 KiB
Raw Blame History

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 12)

  • 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 34.
  • 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 12 (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.shIf/Loop/Call/Return, meta.usings 確認)。
  • Edge normalization: tools/smokes/v2/profiles/quick/selfhost/selfhost_json_normalize_edges.shLoop body null→[]、Call args null→[]、Null ノード維持)。
  • Harness comparator: tools/smokes/v2/run.sh --profile quickselfhost_front_min_vm_llvm.shLLVM 環境があれば)

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.)