UNPKG

@thi.ng/shader-ast

Version:

DSL to define shader code in TypeScript and cross-compile to GLSL, JS and other targets

68 lines (67 loc) 2.2 kB
import { isArray } from "@thi.ng/checks/is-array"; import { DGraph } from "@thi.ng/dgraph"; import { isMat, isTerm, isVec } from "./checks.js"; const scopedChildren = (t) => { let children; switch (t.tag) { case "scope": return t.body; case "fn": return t.scope.body; case "for": children = [t.test, ...t.scope.body]; if (t.init) children.push(t.init); if (t.iter) children.push(t.iter); return children; case "while": return [t.test, ...t.scope.body]; case "if": children = [t.test, ...t.t.body]; if (t.f) children.push(...t.f.body); return children; } }; const allChildren = (t) => scopedChildren(t) || (t.tag === "scope" ? t.body : t.tag === "ternary" ? [t.test, t.t, t.f] : t.tag === "ret" ? t.val !== void 0 ? [t.val] : void 0 : t.tag === "call" || t.tag === "call_i" ? t.args : t.tag === "sym" && t.init ? [t.init] : t.tag === "decl" ? [t.id] : t.tag === "op1" || t.tag === "swizzle" ? [t.val] : t.tag === "op2" ? [t.l, t.r] : t.tag === "assign" ? [t.r] : isVec(t) || isMat(t) ? t.val : isTerm(t.val) ? t.val : void 0); const walk = (visit, children, acc, tree, pre = true) => { if (isArray(tree)) { tree.forEach((x) => acc = walk(visit, children, acc, x, pre)); } else { pre && (acc = visit(acc, tree)); const c = children(tree); c && (acc = walk(visit, children, acc, c, pre)); !pre && (acc = visit(acc, tree)); } return acc; }; const buildCallGraph = (fn, graph = new DGraph()) => fn.deps?.length ? fn.deps.reduce( (graph2, d) => buildCallGraph(d, graph2.addDependency(fn, d)), graph ) : graph.addNode(fn); const decl = (id) => ({ tag: "decl", type: id.type, id }); const scope = (body, global = false) => ({ tag: "scope", type: "void", body: body.filter((x) => x != null).map((x) => x.tag === "sym" ? decl(x) : x), global }); const program = (body) => { const syms = body.filter((x) => x.tag !== "fn"); const g = body.reduce( (acc, x) => x.tag === "fn" ? buildCallGraph(x, acc) : acc, new DGraph() ); return scope(syms.concat(g.sort()), true); }; export { allChildren, buildCallGraph, decl, program, scope, scopedChildren, walk };