summaryrefslogtreecommitdiffstats
path: root/llparse-frontend/src/peephole.ts
blob: 19ac13f33c5c4ead879b6d9ccfd4824f80302703 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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;
  }
}