@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
JavaScript
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
};