phase15: update CLAUDE.md and sync with current progress
- Update phase indicator to Phase 15 (Self-Hosting) - Update documentation links to Phase 15 resources - Reflect completion of R1-R5 tasks and ongoing work - Fix CURRENT_TASK.md location to root directory Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1
apps/ny-mir-samples/arithmetic.nyash
Normal file
1
apps/ny-mir-samples/arithmetic.nyash
Normal file
@ -0,0 +1 @@
|
||||
return 1 + 2 * 3
|
||||
1
apps/ny-mir-samples/return_42.nyash
Normal file
1
apps/ny-mir-samples/return_42.nyash
Normal file
@ -0,0 +1 @@
|
||||
return 42
|
||||
14
apps/ny-parser-nyash/README.md
Normal file
14
apps/ny-parser-nyash/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Ny Parser (v0) — Minimal Nyash-made Parser
|
||||
|
||||
- Scope: integers, + - * /, parentheses, and a single `return` statement.
|
||||
- Output: JSON IR v0 as documented in CURRENT_TASK.md (Program/Return/Int/Binary).
|
||||
|
||||
Usage (Unix)
|
||||
- echo "return 1+2*3" | ./tools/ny_parser_run.sh
|
||||
|
||||
Usage (Windows PowerShell)
|
||||
- Get-Content .\apps\ny-mir-samples\arithmetic.nyash | .\tools\ny_parser_run.ps1
|
||||
|
||||
Notes
|
||||
- This is a minimal educational parser to bootstrap the self-host loop.
|
||||
- Errors print a JSON envelope: {"version":0,"kind":"Error",...}.
|
||||
29
apps/ny-parser-nyash/main.nyash
Normal file
29
apps/ny-parser-nyash/main.nyash
Normal file
@ -0,0 +1,29 @@
|
||||
// Entry: read stdin, parse with ParserV0, print JSON IR or error JSON
|
||||
|
||||
include("./apps/ny-parser-nyash/parser_minimal.nyash")
|
||||
|
||||
static box Main {
|
||||
main(args) {
|
||||
local console = new ConsoleBox()
|
||||
// Read all stdin
|
||||
local buf = ""
|
||||
loop(true) {
|
||||
local line = console.readLine()
|
||||
if line == null { break }
|
||||
buf = buf + line + "\n"
|
||||
}
|
||||
if buf == "" { buf = "return 0\n" }
|
||||
local ir = ParserV0.parse_program(buf)
|
||||
// If already an Error envelope, print as-is
|
||||
local s = ir.as_any().toString()
|
||||
if s.indexOf("\"kind\":\"Error\"") >= 0 {
|
||||
console.log(s)
|
||||
return 1
|
||||
}
|
||||
// Expect MapBox with Program; toJson available on MapBox
|
||||
local json = ir.toJson()
|
||||
console.log(json)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
88
apps/ny-parser-nyash/parser_minimal.nyash
Normal file
88
apps/ny-parser-nyash/parser_minimal.nyash
Normal file
@ -0,0 +1,88 @@
|
||||
// Minimal recursive-descent parser for Ny v0 producing JSON IR v0 (MapBox)
|
||||
|
||||
include("./apps/ny-parser-nyash/tokenizer.nyash")
|
||||
|
||||
static box ParserV0 {
|
||||
init { tokens, pos }
|
||||
|
||||
parse_program(input) {
|
||||
me.tokens = Tokenizer.tokenize(input)
|
||||
// Error passthrough
|
||||
if me.tokens.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 {
|
||||
return me.tokens
|
||||
}
|
||||
me.pos = 0
|
||||
local stmt = me.parse_stmt()
|
||||
if stmt.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 { return stmt }
|
||||
local body = new ArrayBox(); body.push(stmt)
|
||||
local prog = new MapBox(); prog.set("version", 0); prog.set("kind", "Program"); prog.set("body", body)
|
||||
return prog
|
||||
}
|
||||
|
||||
parse_stmt() {
|
||||
local tok = me.peek()
|
||||
if tok.get("type") == "RETURN" {
|
||||
me.next()
|
||||
local expr = me.parse_expr()
|
||||
if expr.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 { return expr }
|
||||
local ret = new MapBox(); ret.set("type", "Return"); ret.set("expr", expr)
|
||||
return ret
|
||||
}
|
||||
return me.err("Expected 'return'")
|
||||
}
|
||||
|
||||
parse_expr() {
|
||||
local left = me.parse_term()
|
||||
loop(true) {
|
||||
local t = me.peek(); local ty = t.get("type")
|
||||
if ty == "+" || ty == "-" {
|
||||
me.next(); local right = me.parse_term()
|
||||
left = me.bin(ty, left, right)
|
||||
} else { break }
|
||||
}
|
||||
return left
|
||||
}
|
||||
|
||||
parse_term() {
|
||||
local left = me.parse_factor()
|
||||
loop(true) {
|
||||
local t = me.peek(); local ty = t.get("type")
|
||||
if ty == "*" || ty == "/" {
|
||||
me.next(); local right = me.parse_factor()
|
||||
left = me.bin(ty, left, right)
|
||||
} else { break }
|
||||
}
|
||||
return left
|
||||
}
|
||||
|
||||
parse_factor() {
|
||||
local t = me.peek(); local ty = t.get("type")
|
||||
if ty == "INT" {
|
||||
me.next();
|
||||
local node = new MapBox(); node.set("type", "Int"); node.set("value", t.get("value"))
|
||||
return node
|
||||
}
|
||||
if ty == "(" {
|
||||
me.next();
|
||||
local e = me.parse_expr()
|
||||
local r = me.peek(); if r.get("type") != ")" { return me.err(") expected") } else { me.next() }
|
||||
return e
|
||||
}
|
||||
return me.err("factor expected")
|
||||
}
|
||||
|
||||
// helpers
|
||||
peek() { return me.tokens.get(me.pos) }
|
||||
next() { me.pos = me.pos + 1; return me.tokens.get(me.pos-1) }
|
||||
bin(op, lhs, rhs) {
|
||||
local m = new MapBox(); m.set("type", "Binary"); m.set("op", op); m.set("lhs", lhs); m.set("rhs", rhs); return m
|
||||
}
|
||||
err(msg) {
|
||||
local err = new MapBox(); err.set("version", 0); err.set("kind", "Error")
|
||||
local e = new MapBox(); e.set("message", msg)
|
||||
local sp = new MapBox(); sp.set("start", me.pos); sp.set("end", me.pos)
|
||||
e.set("span", sp); err.set("error", e)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
55
apps/ny-parser-nyash/tokenizer.nyash
Normal file
55
apps/ny-parser-nyash/tokenizer.nyash
Normal file
@ -0,0 +1,55 @@
|
||||
// Minimal tokenizer for Ny v0 (ints, + - * /, ( ), return)
|
||||
|
||||
static box Tokenizer {
|
||||
tokenize(input) {
|
||||
local tokens = new ArrayBox()
|
||||
local i = 0
|
||||
local n = input.length()
|
||||
// helper: skip whitespace
|
||||
fn skip_ws() {
|
||||
loop(i < n) {
|
||||
local ch = input.substring(i, i+1)
|
||||
if ch == " " || ch == "\t" || ch == "\r" || ch == "\n" { i = i + 1 } else { return }
|
||||
}
|
||||
}
|
||||
// main loop
|
||||
loop(i < n) {
|
||||
skip_ws()
|
||||
if i >= n { break }
|
||||
local ch = input.substring(i, i+1)
|
||||
if ch == "+" || ch == "-" || ch == "*" || ch == "/" || ch == "(" || ch == ")" {
|
||||
local tok = new MapBox(); tok.set("type", ch)
|
||||
tokens.push(tok); i = i + 1; continue
|
||||
}
|
||||
// keyword: return
|
||||
if i + 6 <= n {
|
||||
local kw = input.substring(i, i+6)
|
||||
if kw == "return" {
|
||||
local t = new MapBox(); t.set("type", "RETURN")
|
||||
tokens.push(t); i = i + 6; continue
|
||||
}
|
||||
}
|
||||
// integer literal
|
||||
if ch >= "0" && ch <= "9" {
|
||||
local j = i
|
||||
loop(j < n) {
|
||||
local cj = input.substring(j, j+1)
|
||||
if cj >= "0" && cj <= "9" { j = j + 1 } else { break }
|
||||
}
|
||||
local num_str = input.substring(i, j)
|
||||
local tnum = new MapBox(); tnum.set("type", "INT"); tnum.set("value", num_str)
|
||||
tokens.push(tnum); i = j; continue
|
||||
}
|
||||
// unknown
|
||||
local err = new MapBox(); err.set("version", 0); err.set("kind", "Error")
|
||||
local e = new MapBox(); e.set("message", "Unknown token");
|
||||
local sp = new MapBox(); sp.set("start", i); sp.set("end", i+1)
|
||||
e.set("span", sp); err.set("error", e)
|
||||
return err
|
||||
}
|
||||
// EOF
|
||||
local eof = new MapBox(); eof.set("type", "EOF"); tokens.push(eof)
|
||||
return tokens
|
||||
}
|
||||
}
|
||||
|
||||
63
apps/std/ny-config.nyash
Normal file
63
apps/std/ny-config.nyash
Normal file
@ -0,0 +1,63 @@
|
||||
// ny-config.nyash - Load nyash.toml and expose minimal helpers
|
||||
|
||||
static box NyConfig {
|
||||
// Read nyash.toml (or given path) and return JSON string via TOMLBox.toJson()
|
||||
load_toml(path) {
|
||||
local p = path
|
||||
if p == null || p == "" { p = "nyash.toml" }
|
||||
local f = new FileBox()
|
||||
// Open read-only if supported; fallback to default if mode not required
|
||||
// Many plugins accept open(path, mode). Use "r" here.
|
||||
f.open(p, "r")
|
||||
local content = f.read()
|
||||
f.close()
|
||||
local t = new TOMLBox()
|
||||
// parse(content) returns Result.Ok(bool) in some variants; call and ignore return here
|
||||
t.parse(content)
|
||||
local json = t.toJson()
|
||||
return json
|
||||
}
|
||||
|
||||
// Return counts for env/tasks/box_types/plugins (approx by '=' occurrences per table)
|
||||
counts() {
|
||||
// Parse nyash.toml
|
||||
local f2 = new FileBox()
|
||||
f2.open("nyash.toml", "r")
|
||||
local content2 = f2.read()
|
||||
f2.close()
|
||||
local t = new TOMLBox()
|
||||
t.parse(content2)
|
||||
local out = new MapBox()
|
||||
out.setS("env", me.count_keys_in_string(t.get("env")))
|
||||
out.setS("tasks", me.count_keys_in_string(t.get("tasks")))
|
||||
out.setS("box_types", me.count_keys_in_string(t.get("box_types")))
|
||||
out.setS("plugins", me.count_keys_in_string(t.get("plugins")))
|
||||
return out
|
||||
}
|
||||
|
||||
// helper: count '=' in a string
|
||||
count_keys_in_string(s) {
|
||||
local i = 0
|
||||
local n = s.length()
|
||||
local c = 0
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "=" { c = c + 1 }
|
||||
i = i + 1
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Convert JSON back to TOML-like display if needed (placeholder: returns empty to force parse to no-op)
|
||||
json_to_toml_hint(js) { return "" }
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main(args) {
|
||||
local console = new ConsoleBox()
|
||||
local json = NyConfig.load_toml(null)
|
||||
local c = NyConfig.counts(json)
|
||||
console.println("ny-config: env=" + c.getS("env").toString() + ", tasks=" + c.getS("tasks").toString() + ", plugins=" + c.getS("plugins").toString() + ", box_types=" + c.getS("box_types").toString())
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user