Files
hakorune/docs/reference/language/repl.md
tomoaki c117a04035 fix(rewrite): toString normalization to BoxCall(slot #0) - Phase 287 P4
Root cause: toString/stringify/str were being rewritten to Global/Method calls
with class inference, causing Main.toString/0 to be called for primitives.

Fix (Box-First + Legacy Deletion):
1.  MIR Builder - toString normalization (special.rs)
   - ALWAYS emit BoxCall with method_id=0 for toString/stringify/str
   - Do NOT rewrite to Global(Class.str/0) or Method calls
   - DELETED 70+ lines of complex class inference logic
   - Primitive guard with method name filter (known.rs)

2.  JSON Serializer - method_id output (mir_json_emit.rs)
   - Include method_id field in BoxCall JSON for LLVM

3.  LLVM Backend - universal slot #0 support
   - Extract method_id from JSON (instruction_lower.py)
   - Box primitives via nyash.box.from_i64 (boxcall.py)
   - Invoke toString via plugin system with method_id=0
   - ⚠️ TODO: Add nyash.integer.tostring_h to kernel

Test Results:
 VM: local x = 1; print(x.toString()) → "1" (PASS)
 VM: array_length test (boxed Integer) → PASS
⚠️ LLVM: Compiles successfully, needs kernel function

SSOT: slot_registry - toString is ALWAYS universal slot #0

Legacy Deleted:
- special.rs: Complex class inference rewrite (~70 lines)
- special.rs: Unique suffix fallback for toString
- special.rs: Main box special handling

Files changed:
- src/mir/builder/rewrite/special.rs (try_early_str_like_to_dst)
- src/mir/builder/rewrite/known.rs (primitive guards x4)
- src/runner/mir_json_emit.rs (method_id serialization x2)
- src/llvm_py/builders/instruction_lower.py (method_id extraction)
- src/llvm_py/instructions/boxcall.py (slot #0 handler)
- docs/reference/language/quick-reference.md (toString SSOT)

🎊 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-25 11:38:05 +09:00

123 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# REPL Mode (ReadEvalPrint Loop) — Specification (SSOT)
Status: Draft (design locked; implementation may lag)
This document defines Nyash REPL mode semantics. The primary design goal is:
- **File mode** stays strict and box-oriented (no mutable globals at top-level).
- **REPL mode** is convenience-oriented (interactive, persistent session scope, implicit locals).
- **Parser stays the same**; the difference is primarily **binding (name resolution)** rules.
## Terms
- **Top-level**: Code that is not inside a function/method body.
- **File mode**: Normal execution of a `.hako`/Nyash file via the runner.
- **REPL mode**: Interactive execution session (future CLI: `--repl`).
- **Global variable (in this project)**: A mutable binding created at file top-level (e.g., `x = 1` or `local x = 1` at top-level).
## 1) File Mode vs REPL Mode (high-level contract)
### File mode (strict)
- Top-level allows **declarations only** (e.g., `box`, `static box`, `function`, `static function`, `using`).
- Top-level **statements are rejected** (Fail-Fast):
- assignment (`x = 1`)
- `local` declarations (`local x = 1`)
- expression statements (`f()`), `print(...)`, control flow statements, etc.
- Rationale: prevents mutable globals; keeps “state lives in boxes” discipline.
### REPL mode (convenient)
- The REPL has exactly one **persistent session scope**.
- Session scope is conceptually a **lexical frame that persists across inputs**.
- Assignments can create bindings implicitly (see §2).
- Reads of undefined names are errors (Fail-Fast; no silent `void`).
CLI entry (initial policy):
- Start explicitly with `hakorune --repl` (optional short alias: `-i`).
## 2) Binding Rules in REPL Mode
### 2.1 Implicit local on assignment (key feature)
When executing `name = expr` in REPL mode:
- If `name` already exists in the session scope, update it.
- If `name` does not exist, **create a new session binding** and assign to it.
This applies to compound assignments as well (if supported): `name += expr`, etc.
### 2.2 Reads are strict
When evaluating `name` in REPL mode:
- If `name` exists in the session scope, return its value.
- Otherwise, raise **NameError / undeclared variable** (Fail-Fast).
### 2.3 `local` is accepted but not required
REPL accepts `local name = expr` / `local name` as explicit declarations.
- Semantics: declare/update `name` in the session scope (same end result as implicit assignment).
- Guidance: `local` remains useful for clarity, but REPL users are not forced to write it.
## 3) Output Rules (REPL UX contract)
REPL output distinguishes expressions vs statements:
- If the input is an **expression**, print its value (pretty display) unless it is `void`.
- If the input is a **statement**, do not auto-print.
### 3.1 Convenience binding `_`
- `_` is bound to the **last auto-printed value** (expressions only).
- `_` is not updated when the value is `void`.
### 3.2 Output suppression (planned)
- A trailing `;` may suppress auto-print for expressions (planned; should be implemented without changing the core parser).
## 4) REPL Meta Commands
REPL supports dot-commands (not part of the language grammar):
- `.help` — show help
- `.exit` — exit the REPL
- `.reset` — clear the session scope (remove all bindings and definitions created in the session)
Additional commands may be added for debugging (e.g., `.ast`, `.mir`), but they must remain REPL-only and default-off for CI.
## 5) Compatibility and `strip_local_decl` policy
Historical compatibility code exists that can strip top-level `local` from certain inputs.
SSOT policy:
- **File mode must not “strip and accept” top-level `local`** (would violate the “no globals” rule).
- If compatibility behavior is kept, it must be **REPL-only** and/or explicitly gated (e.g., `--compat`), with a stable warning tag.
## 6) Error Messages (Fail-Fast wording)
Recommended file-mode errors:
- `Error: top-level statements are not allowed in file mode. Put code inside Main.main() or run with --repl.`
- `Error: 'local' is not allowed at top-level in file mode. Use Main.main() or REPL mode.`
## 7) Minimal Conformance Tests (spec lock)
### File mode
1. `x = 1` at top-level → error (top-level statements not allowed)
2. `local x = 1` at top-level → error (local not allowed at top-level)
3. `print("hi")` at top-level → error
4. Declarations at top-level → OK
5. Statements inside `Main.main()` or `main()` → OK
### REPL mode
1. `x = 1` then `x` → prints `1`
2. `y` (undefined) → NameError
3. `x = 1; x = 2; x` → prints `2`
4. `local z = 3; z` → prints `3`
5. `x = 1; .reset; x` → NameError