selfhost/tools: add dep_tree_simple.nyash (single-box functional) and run dep_tree.sh with interpreter + plugin builtins; groundwork for include+using/module JSON deps
This commit is contained in:
231
apps/selfhost/tools/dep_tree_simple.nyash
Normal file
231
apps/selfhost/tools/dep_tree_simple.nyash
Normal file
@ -0,0 +1,231 @@
|
||||
// dep_tree_simple.nyash — dependency tree (include + using/module) in a single static box
|
||||
|
||||
static box Main {
|
||||
// ---- file utils ----
|
||||
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
|
||||
}
|
||||
|
||||
file_exists(path) {
|
||||
local fb = new FileBox()
|
||||
local ok = fb.open(path, "r")
|
||||
if ok == false { return false }
|
||||
fb.close()
|
||||
return true
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// ---- text utils ----
|
||||
split_lines(src) {
|
||||
local out = new ArrayBox()
|
||||
local i = 0
|
||||
local n = src.length()
|
||||
local start = 0
|
||||
loop(true) {
|
||||
if i == n { out.push(src.substring(start, i)) return out }
|
||||
local ch = src.substring(i, i+1)
|
||||
if ch == "\n" { out.push(src.substring(start, i)) start = i + 1 }
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ---- scanners ----
|
||||
scan_includes(src) {
|
||||
local out = new ArrayBox()
|
||||
if src == null { return out }
|
||||
local lines = me.split_lines(src)
|
||||
local i = 0
|
||||
loop(i < lines.length()) {
|
||||
local t = lines.get(i).trim()
|
||||
if t.startsWith("include \"") {
|
||||
local rest = t.substring(9, t.length())
|
||||
local j = 0
|
||||
local q = -1
|
||||
loop(j < rest.length()) {
|
||||
if rest.substring(j, j+1) == "\"" { q = j j = rest.length() }
|
||||
j = j + 1
|
||||
}
|
||||
if q >= 0 { out.push(rest.substring(0, q)) }
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
scan_usings(src) {
|
||||
local out = new ArrayBox()
|
||||
if src == null { return out }
|
||||
local lines = me.split_lines(src)
|
||||
local i = 0
|
||||
loop(i < lines.length()) {
|
||||
local t0 = lines.get(i).trim()
|
||||
local matched = false
|
||||
local t = t0
|
||||
if t0.startsWith("// @using ") { t = t0.substring(10, t0.length()) matched = true } else {
|
||||
if t0.startsWith("using ") { t = t0.substring(6, t0.length()) matched = true }
|
||||
}
|
||||
if matched {
|
||||
local as_pos = t.indexOf(" as ")
|
||||
local target = t
|
||||
local alias = null
|
||||
if as_pos >= 0 { target = t.substring(0, as_pos).trim() alias = t.substring(as_pos+4, t.length()).trim() }
|
||||
local rec = new MapBox()
|
||||
rec.set("target", target)
|
||||
if alias != null { rec.set("alias", alias) }
|
||||
if target.startsWith("./") || target.startsWith("/") || target.endsWith(".nyash") { rec.set("kind", "path") } else { rec.set("kind", "namespace") }
|
||||
out.push(rec)
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
scan_modules(src) {
|
||||
local out = new ArrayBox()
|
||||
if src == null { return out }
|
||||
local lines = me.split_lines(src)
|
||||
local i = 0
|
||||
loop(i < lines.length()) {
|
||||
local t = lines.get(i).trim()
|
||||
if t.startsWith("// @module ") {
|
||||
local rest = t.substring(11, t.length())
|
||||
local eq = rest.indexOf("=")
|
||||
if eq > 0 {
|
||||
local ns = rest.substring(0, eq).trim()
|
||||
local path = rest.substring(eq+1, t.length()).trim()
|
||||
local m = new MapBox()
|
||||
m.set("namespace", ns)
|
||||
m.set("path", path)
|
||||
out.push(m)
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
default_using_paths() {
|
||||
local a = new ArrayBox()
|
||||
a.push("apps/selfhost")
|
||||
a.push("apps")
|
||||
a.push("lib")
|
||||
a.push(".")
|
||||
return a
|
||||
}
|
||||
|
||||
resolve_ns(base_dir, ns) {
|
||||
local rel = ns.replace(".", "/") + ".nyash"
|
||||
local cand0 = me.join(base_dir, rel)
|
||||
if me.file_exists(cand0) { return cand0 }
|
||||
local paths = me.default_using_paths()
|
||||
local i = 0
|
||||
loop(i < paths.length()) {
|
||||
local cand = me.join(paths.get(i), rel)
|
||||
if me.file_exists(cand) { return cand }
|
||||
i = i + 1
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
node_for(path, visited) {
|
||||
if visited.has(path) {
|
||||
local m = new MapBox()
|
||||
m.set("path", path)
|
||||
m.set("children", new ArrayBox())
|
||||
m.set("includes", new ArrayBox())
|
||||
m.set("uses", new ArrayBox())
|
||||
m.set("modules", new ArrayBox())
|
||||
m.set("note", "visited")
|
||||
return m
|
||||
}
|
||||
visited.set(path, true)
|
||||
local out = new MapBox()
|
||||
out.set("path", path)
|
||||
local src = me.read_all(path)
|
||||
if src == null {
|
||||
out.set("error", "read_fail")
|
||||
out.set("includes", new ArrayBox())
|
||||
out.set("uses", new ArrayBox())
|
||||
out.set("modules", new ArrayBox())
|
||||
out.set("children", new ArrayBox())
|
||||
return out
|
||||
}
|
||||
local base = me.dirname(path)
|
||||
local incs = me.scan_includes(src)
|
||||
local uses = me.scan_usings(src)
|
||||
local mods = me.scan_modules(src)
|
||||
out.set("includes", incs)
|
||||
out.set("uses", uses)
|
||||
out.set("modules", mods)
|
||||
local mod_map = new MapBox()
|
||||
local mi = 0
|
||||
loop(mi < mods.length()) {
|
||||
local mm = mods.get(mi)
|
||||
mod_map.set(mm.get("namespace"), mm.get("path"))
|
||||
mi = mi + 1
|
||||
}
|
||||
local children = new ArrayBox()
|
||||
local i = 0
|
||||
loop(i < incs.length()) {
|
||||
local child_path = me.join(base, incs.get(i))
|
||||
children.push(me.node_for(child_path, visited))
|
||||
i = i + 1
|
||||
}
|
||||
i = 0
|
||||
loop(i < uses.length()) {
|
||||
local u = uses.get(i)
|
||||
if u.get("kind") == "path" {
|
||||
local p = me.join(base, u.get("target"))
|
||||
if me.file_exists(p) { u.set("resolved", p) children.push(me.node_for(p, visited)) } else { u.set("unresolved", true) u.set("hint", p) }
|
||||
} else {
|
||||
local tgt = u.get("target")
|
||||
local via = mod_map.get(tgt)
|
||||
if via != null {
|
||||
if me.file_exists(via) { u.set("resolved", via) children.push(me.node_for(via, visited)) } else { u.set("unresolved", true) u.set("hint", via) }
|
||||
} else {
|
||||
local found = me.resolve_ns(base, tgt)
|
||||
if found != null { u.set("resolved", found) children.push(me.node_for(found, visited)) } else { u.set("unresolved", true) u.set("hint", tgt) }
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
out.set("children", children)
|
||||
return out
|
||||
}
|
||||
|
||||
main(args) {
|
||||
local console = new ConsoleBox()
|
||||
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 visited = new MapBox()
|
||||
local tree = me.node_for(entry, visited)
|
||||
local root = new MapBox()
|
||||
root.set("version", 1)
|
||||
root.set("root_path", entry)
|
||||
root.set("tree", tree)
|
||||
console.println(root.toJson())
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user