summaryrefslogtreecommitdiffstats
path: root/llparse-frontend/src/peephole.ts
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--llparse-frontend/src/peephole.ts52
1 files changed, 52 insertions, 0 deletions
diff --git a/llparse-frontend/src/peephole.ts b/llparse-frontend/src/peephole.ts
new file mode 100644
index 0000000..19ac13f
--- /dev/null
+++ b/llparse-frontend/src/peephole.ts
@@ -0,0 +1,52 @@
+import { Node, Empty } from './node';
+import { IWrap } from './wrap';
+
+type WrapNode = IWrap<Node>;
+type WrapList = ReadonlyArray<WrapNode>;
+
+export class Peephole {
+ public optimize(root: WrapNode, nodes: WrapList): WrapNode {
+ let changed = new Set(nodes);
+
+ while (changed.size !== 0) {
+ const previous = changed;
+ changed = new Set();
+
+ for (const node of previous) {
+ if (this.optimizeNode(node)) {
+ changed.add(node);
+ }
+ }
+ }
+
+ while (root.ref instanceof Empty) {
+ if (!root.ref.otherwise!.noAdvance) {
+ break;
+ }
+
+ root = root.ref.otherwise!.node;
+ }
+
+ return root;
+ }
+
+ public optimizeNode(node: WrapNode): boolean {
+ let changed = false;
+ for (const slot of node.ref.getSlots()) {
+ if (!(slot.node.ref instanceof Empty)) {
+ continue;
+ }
+
+ const otherwise = slot.node.ref.otherwise!;
+
+ // Node actively skips, can't optimize!
+ if (!otherwise.noAdvance) {
+ continue;
+ }
+
+ slot.node = otherwise.node;
+ changed = true;
+ }
+ return changed;
+ }
+}