1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import { assertExhaustive } from "../Common/utils";
9
-import {
10
- BlockId,
11
- HIRFunction,
12
- Instruction,
13
- InstructionId,
14
- InstructionValue,
15
-} from "./HIR";
16
-import { BlockTerminal, Visitor, visitTree } from "./HIRTreeVisitor";
17
-import { printLValue, printMixedHIR } from "./PrintHIR";
18
-
19
-/**
20
- * Returns a text description of the HIR that has the overall tree shape
21
- * of the original AST, but with the contents of each block printed
22
- * similarly to printHIR's instruction formatting.
23
- */
24
-export function printHIRTree(fn: HIRFunction): string {
25
- return visitTree(fn, new PrintVisitor());
26
-}
27
-
28
-class PrintVisitor
29
- implements
30
- Visitor<
31
- Array<string>,
32
- string,
33
- Array<string>,
34
- Array<string>,
35
- string,
36
- string,
37
- string
38
- >
39
-{
40
- depth: number = 0; // for indentation
41
-
42
- enterBlock(): string[] {
43
- this.depth++;
44
- return [];
45
- }
46
- enterValueBlock(): string[] {
47
- return this.enterBlock();
48
- }
49
- leaveValueBlock(block: string[], value: string): string {
50
- return this.leaveBlock(block);
51
- }
52
- enterInitBlock(block: string[]): string[] {
53
- return this.enterBlock();
54
- }
55
- leaveInitBlock(block: string[]): string[] {
56
- return block;
57
- }
58
- visitValue(value: InstructionValue): string {
59
- return printMixedHIR(value);
60
- }
61
- visitInstruction(instr: Instruction, value: string): string {
62
- if (instr.lvalue !== null) {
63
- return `[${instr.id}] ${printLValue(instr.lvalue)} = ${value}`;
64
- } else {
65
- return `[${instr.id}] ${value}`;
66
- }
67
- }
68
- visitTerminalId(id: InstructionId): void {}
69
- visitImplicitTerminal(): string | null {
70
- return null;
71
- }
72
- visitTerminal(
73
- terminal: BlockTerminal<string[], string, string, string>
74
- ): string {
75
- let value: string;
76
- switch (terminal.kind) {
77
- case "break": {
78
- if (terminal.label !== null) {
79
- value = `Break ${terminal.label}`;
80
- } else {
81
- value = "Break";
82
- }
83
- break;
84
- }
85
- case "continue": {
86
- if (terminal.label !== null) {
87
- value = `Continue ${terminal.label}`;
88
- } else {
89
- value = "Continue";
90
- }
91
- break;
92
- }
93
- case "if": {
94
- if (terminal.alternate !== null) {
95
- value = `If (${
96
- terminal.test
97
- }) ${terminal.consequent.trimStart()} else ${terminal.alternate}`;
98
- } else {
99
- value = `If (${terminal.test}) ${terminal.consequent.trimStart()}`;
100
- }
101
- break;
102
- }
103
- case "switch": {
104
- const prefix = " ".repeat(this.depth);
105
- value = `Switch (${terminal.test}) {\n${terminal.cases
106
- .flatMap((case_) => case_.split("\n").map((line) => ` ${line}`))
107
- .join("\n")}\n${prefix}}`;
108
- break;
109
- }
110
- case "while": {
111
- value = `While (${terminal.test}) ${terminal.loop.trimStart()}`;
112
- break;
113
- }
114
- case "for": {
115
- value = `For (TODO) (${
116
- terminal.test
117
- }) (TODO) ${terminal.loop.trimStart()}`;
118
- break;
119
- }
120
- case "return": {
121
- if (terminal.value !== null) {
122
- value = `Return ${terminal.value}`;
123
- } else {
124
- value = "Return";
125
- }
126
- break;
127
- }
128
- case "throw": {
129
- value = `Throw ${terminal.value}`;
130
- break;
131
- }
132
- default: {
133
- assertExhaustive(
134
- terminal,
135
- `Unexpected terminal kind '${(terminal as any).kind}'`
136
- );
137
- }
138
- }
139
- return value;
140
- }
141
- visitCase(test: string | null, block: string): string {
142
- const prefix = " ".repeat(this.depth);
143
- if (test === null) {
144
- return `${prefix}default: ${block.trimStart()}`;
145
- } else {
146
- return `${prefix}case ${test}: ${block.trimStart()}`;
147
- }
148
- }
149
- appendBlock(
150
- block: string[],
151
- item: string,
152
- label?: BlockId | undefined
153
- ): void {
154
- const prefix = " ".repeat(this.depth);
155
- if (item !== "") {
156
- block.push(`${prefix}${item.trimStart()}`);
157
- }
158
- if (label !== undefined) {
159
- block.push(`${prefix}bb${label}:`);
160
- }
161
- }
162
- appendValueBlock(block: string[], item: string): void {
163
- this.appendBlock(block, item);
164
- }
165
- appendInitBlock(block: string[], item: string): void {
166
- this.appendBlock(block, item);
167
- }
168
- leaveBlock(block: string[]): string {
169
- this.depth--;
170
- const prefix = " ".repeat(this.depth);
171
- return `${prefix}{\n${block.join("\n")}\n${prefix}}`;
172
- }
173
-}