2025-09-08 04:35:50 +09:00
|
|
|
// dep_tree_min_string.nyash — minimal include-only dependency tree (no Array/Map plugins)
|
|
|
|
|
|
|
|
|
|
static box Main {
|
|
|
|
|
has_in_stack(stack, p) {
|
|
|
|
|
// check if stack contains "\n" + p + "\n"
|
|
|
|
|
local t = "\n" + p + "\n"
|
|
|
|
|
local n = stack.length()
|
|
|
|
|
local m = t.length()
|
|
|
|
|
if m == 0 { return 0 }
|
|
|
|
|
local i = 0
|
|
|
|
|
loop(i + m <= n) {
|
|
|
|
|
if stack.substring(i, i+m) == t { return 1 }
|
|
|
|
|
i = i + 1
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
read_all(path) {
|
|
|
|
|
local fb = new FileBox()
|
|
|
|
|
local ok = fb.open(path, "r")
|
|
|
|
|
if ok == false { return null }
|
|
|
|
|
local s = fb.read()
|
|
|
|
|
fb.close()
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dirname(path) {
|
|
|
|
|
local pb = new PathBox()
|
|
|
|
|
local d = pb.dirname(path)
|
|
|
|
|
if d != null { return d }
|
|
|
|
|
local i = path.lastIndexOf("/")
|
|
|
|
|
if i < 0 { return "." }
|
|
|
|
|
return path.substring(0, i)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
join(base, rel) {
|
|
|
|
|
local pb = new PathBox()
|
|
|
|
|
local j = pb.join(base, rel)
|
|
|
|
|
if j != null { return j }
|
|
|
|
|
return base + "/" + rel
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esc_json(s) {
|
|
|
|
|
// very small escaper: replace \ and "
|
|
|
|
|
local out = ""
|
|
|
|
|
local i = 0
|
|
|
|
|
local n = s.length()
|
|
|
|
|
loop(i < n) {
|
|
|
|
|
local ch = s.substring(i, i+1)
|
|
|
|
|
if ch == "\\" { out = out + "\\\\" } else {
|
|
|
|
|
if ch == "\"" { out = out + "\\\"" } else { out = out + ch }
|
|
|
|
|
}
|
|
|
|
|
i = i + 1
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node_json(path, stack, depth) {
|
|
|
|
|
// safety valve: max depth
|
|
|
|
|
if depth >= 64 {
|
|
|
|
|
return "{\\\"path\\\":\\\"" + me.esc_json(path) + "\\\",\\\"includes\\\":[],\\\"children\\\":[]}"
|
|
|
|
|
}
|
|
|
|
|
local src = me.read_all(path)
|
|
|
|
|
if src == null {
|
|
|
|
|
return "{\\\"path\\\":\\\"" + me.esc_json(path) + "\\\",\\\"includes\\\":[],\\\"children\\\":[]}"
|
|
|
|
|
}
|
|
|
|
|
local base = me.dirname(path)
|
|
|
|
|
local incs = ""
|
|
|
|
|
local inc_first = 1
|
|
|
|
|
local children = ""
|
|
|
|
|
local child_first = 1
|
|
|
|
|
local i = 0
|
|
|
|
|
local n = src.length()
|
|
|
|
|
local in_str = 0
|
|
|
|
|
local in_cmt = 0
|
|
|
|
|
loop(i < n) {
|
|
|
|
|
local ch = src.substring(i, i+1)
|
|
|
|
|
// handle line comments (// or #)
|
|
|
|
|
if in_cmt == 1 {
|
|
|
|
|
if ch == "\n" { in_cmt = 0 }
|
|
|
|
|
i = i + 1
|
2025-09-08 11:20:13 +09:00
|
|
|
} else if in_str == 1 {
|
2025-09-08 04:35:50 +09:00
|
|
|
if ch == "\"" {
|
|
|
|
|
// if previous is not backslash, close
|
|
|
|
|
if i == 0 { in_str = 0 } else {
|
|
|
|
|
local prev = src.substring(i-1, i)
|
|
|
|
|
if prev != "\\" { in_str = 0 }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
i = i + 1
|
2025-09-08 11:20:13 +09:00
|
|
|
} else if ch == "/" && i + 1 < n && src.substring(i+1, i+2) == "/" {
|
|
|
|
|
// start // comment
|
|
|
|
|
in_cmt = 1
|
|
|
|
|
i = i + 2
|
|
|
|
|
} else if ch == "#" {
|
|
|
|
|
// start # comment
|
|
|
|
|
in_cmt = 1
|
|
|
|
|
i = i + 1
|
|
|
|
|
} else if ch == "\"" {
|
|
|
|
|
// enter string
|
|
|
|
|
in_str = 1
|
|
|
|
|
i = i + 1
|
|
|
|
|
} else if i + 9 <= n && src.substring(i, i+9) == "include \"" {
|
|
|
|
|
// look for include "..."
|
2025-09-08 04:35:50 +09:00
|
|
|
local j = i + 9
|
2025-09-08 11:20:13 +09:00
|
|
|
// find closing quote (respect escapes) without using break
|
|
|
|
|
local found = 0
|
|
|
|
|
loop(j < n && found == 0) {
|
2025-09-08 04:35:50 +09:00
|
|
|
if src.substring(j, j+1) == "\"" {
|
|
|
|
|
local prev = src.substring(j-1, j)
|
2025-09-08 11:20:13 +09:00
|
|
|
if prev != "\\" { found = 1 } else { j = j + 1 }
|
|
|
|
|
} else {
|
|
|
|
|
j = j + 1
|
2025-09-08 04:35:50 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-08 11:20:13 +09:00
|
|
|
if found == 1 {
|
2025-09-08 04:35:50 +09:00
|
|
|
local p = src.substring(i+9, j)
|
|
|
|
|
if inc_first == 1 {
|
|
|
|
|
incs = incs + "\"" + me.esc_json(p) + "\""
|
|
|
|
|
inc_first = 0
|
|
|
|
|
} else {
|
|
|
|
|
incs = incs + ",\"" + me.esc_json(p) + "\""
|
|
|
|
|
}
|
|
|
|
|
local child_path = me.join(base, p)
|
|
|
|
|
// cycle detection: if child_path already in stack, do not recurse
|
|
|
|
|
local cj = null
|
|
|
|
|
if me.has_in_stack(stack, child_path) == 1 {
|
|
|
|
|
cj = "{\\\"path\\\":\\\"" + me.esc_json(child_path) + "\\\",\\\"includes\\\":[],\\\"children\\\":[]}"
|
|
|
|
|
} else {
|
|
|
|
|
cj = me.node_json(child_path, stack + child_path + "\n", depth + 1)
|
|
|
|
|
}
|
|
|
|
|
if child_first == 1 {
|
|
|
|
|
children = children + cj
|
|
|
|
|
child_first = 0
|
|
|
|
|
} else {
|
|
|
|
|
children = children + "," + cj
|
|
|
|
|
}
|
|
|
|
|
i = j + 1
|
2025-09-08 11:20:13 +09:00
|
|
|
} else {
|
|
|
|
|
i = i + 1
|
2025-09-08 04:35:50 +09:00
|
|
|
}
|
2025-09-08 11:20:13 +09:00
|
|
|
} else {
|
|
|
|
|
i = i + 1
|
2025-09-08 04:35:50 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return "{\\\"path\\\":\\\"" + me.esc_json(path) + "\\\",\\\"includes\\\":[" + incs + "],\\\"children\\\":[" + children + "]}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main(args) {
|
|
|
|
|
local console = new ConsoleBox()
|
2025-09-08 11:20:13 +09:00
|
|
|
// Determine entry path (avoid stdin to keep VM path simple)
|
2025-09-08 04:35:50 +09:00
|
|
|
local entry = null
|
|
|
|
|
if args != null && args.length() >= 1 { entry = args.get(0) }
|
2025-09-08 11:20:13 +09:00
|
|
|
if entry == null || entry == "" { entry = "apps/selfhost/ny-parser-nyash/main.nyash" }
|
2025-09-08 04:35:50 +09:00
|
|
|
local tree = me.node_json(entry, "\n" + entry + "\n", 0)
|
|
|
|
|
local out = "{\\\"version\\\":1,\\\"root_path\\\":\\\"" + me.esc_json(entry) + "\\\",\\\"tree\\\":" + tree + "}"
|
|
|
|
|
console.println(out)
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
}
|