Files
hakorune/apps/selfhost/tools/dep_tree_min_string.nyash

160 lines
4.6 KiB
Plaintext
Raw Normal View History

// 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
} else if in_str == 1 {
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
} 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 "..."
local j = i + 9
// find closing quote (respect escapes) without using break
local found = 0
loop(j < n && found == 0) {
if src.substring(j, j+1) == "\"" {
local prev = src.substring(j-1, j)
if prev != "\\" { found = 1 } else { j = j + 1 }
} else {
j = j + 1
}
}
if found == 1 {
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
} else {
i = i + 1
}
} else {
i = i + 1
}
}
return "{\\\"path\\\":\\\"" + me.esc_json(path) + "\\\",\\\"includes\\\":[" + incs + "],\\\"children\\\":[" + children + "]}"
}
main(args) {
local console = new ConsoleBox()
// Determine entry path (avoid stdin to keep VM path simple)
local entry = null
if args != null && args.length() >= 1 { entry = args.get(0) }
if entry == null || entry == "" { entry = "apps/selfhost/ny-parser-nyash/main.nyash" }
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
}
}