🔧 Fix peek expression terminator issues and add ternary operator support

- Fix LLVM IR terminator missing in peek expression entry blocks
- Add proper jump instructions between peek blocks
- Implement ternary operator (? :) as syntactic sugar for peek
- Update Python LLVM externcall handling for improved compatibility
- Add comprehensive test cases for peek and ternary expressions
- Update language guide with ternary operator documentation

ChatGPTが頑張って修正してくれたにゃ!🐱

Co-Authored-By: ChatGPT <noreply@openai.com>
This commit is contained in:
Selfhosting Dev
2025-09-14 20:30:38 +09:00
parent 8f1b2ffa12
commit 5cad0ab20c
17 changed files with 241 additions and 38 deletions

View File

@ -15,6 +15,39 @@ Common Constructs
- Null-coalesce: `x ?? y``peek x { null => y, else => x }`
- Safe access: `a?.b``peek a { null => null, else => a.b }`
Minimal Examples
- Ternary
```nyash
static box Main {
main(args) {
local a = 3
local b = 5
// Nested ternary is supported
local v = (a < b) ? ((b < 0) ? 40 : 50) : 60
return v
}
}
```
- Peek as expression block (last expression is the value)
```nyash
static box Main {
main(args) {
local d = "1"
// Each arm can be a block; the last expression becomes the value
local dv = peek d {
"0" => { print("found zero") 0 }
"1" => { print("found one") 1 }
else => { print("other") 0 }
}
return dv
}
}
```
must_use Notes
- Peek arms are expressions. When using a block arm `{ ... }`, the last expression is the resulting value; statements without a final expression yield no usable value.
- Ternary is an expression; ensure both branches are type-compatible at MIR level (e.g., both yield integer or both yield string handle in current phase).
When you need the implementation details
- Tokenizer: src/tokenizer.rs
- Parser: src/parser/expressions.rs, src/parser/statements.rs

View File

@ -0,0 +1,59 @@
# Parser MVP Stage-2 Design (Phase 15)
Scope
- Expand Stage-1 (const/binop/return) to cover the minimal everyday surface:
- local bindings: `local x = expr`
- if/else: `if cond { ... } else { ... }`
- loop: `loop(cond) { ... }` and `loop cond { ... }`
- call: `f(a, b)` (free function)
- method: `obj.method(a, b)`
- constructor: `new BoxType(args)`
- implicit receiver `me` in box methods
- String methods: `substring`, `length`, `lastIndexOf`
Grammar Sketch (incremental)
- Expression
- precedence keeps Phase 12.7: ternary inside pipe; ternary lowers to if/branch
- postfix: method call, field access
- primary: literals, identifiers, parenthesized
- Statement
- `local ident = expr` (no rebind in Stage-2)
- expression statement (for side effects)
- return
AST Nodes (delta)
- Add nodes for Local, If, Loop, Call, MethodCall, New, Identifier, Return.
- Keep Peek and Ternary in the AST; lower to MIR via the same builder hooks.
Lowering to MIR JSON v0
- Local → assign to fresh value id, store into vmap
- If/Ternary → compare + branch blocks; PHI for join values when used as expression
- Loop → cond block → body block → back-edge; loop-carried values explicitly phied
- Call → `call { func: "name", args: [...] }`
- Method → `boxcall { box: vid, method: "name", args: [...] }`
- New → `newbox { type: "BoxType", args: [...] }`
- String ops
- `length()` → i64 length on string handle (VM: Python len; LLVM: handle→ptr at call sites only)
- `substring(a,b)``nyash.string.substring_hh` equivalent
- `lastIndexOf(x)` → returns i64 index or -1
Type Meta (emitted with JSON where needed)
- Compare: when both sides are string → `cmp_kind: "string"`
- BinOp `+`: if `dst_type = { kind: "handle", box_type: "StringBox" }`, force concat_hh
- Known APIs: annotate `dst_type` for Console.println (i64), dirname/join/read as `StringBox(handle)`
Policy & Invariants
- Resolver-only: do not wire PHIs in-lowering; snapshots + `finalize_phis` bind incomings
- Strings: inter-block are handle(i64) only; i8* materialized at call sites
- PHI placeholders: created at block heads from JSON-declared phi
Acceptance
- Parity on:
- `apps/tests/min_str_cat_loop/main.nyash`
- `apps/tests/esc_dirname_smoke.nyash`
- Stage-2 new smokes (ternary nested, peek return)
- `tools/parity.sh --lhs pyvm --rhs llvmlite --show-diff <app>` → green
Notes
- Keep Stage-2 additive and test-driven; avoid broad refactors.
- Future: numeric methods, map/array minimal, and using/namespace gate.