| 1 | const char HTMLLogger_html[] = | 
|---|
| 2 | R"x(<!doctype html>)x" "\n" | 
|---|
| 3 | R"x(<html>)x" "\n" | 
|---|
| 4 | R"x(<!-- HTMLLogger.cpp ----------------------------------------------------)x" "\n" | 
|---|
| 5 | R"x()x" "\n" | 
|---|
| 6 | R"x( Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.)x" "\n" | 
|---|
| 7 | R"x( See https://llvm.org/LICENSE.txt for license information.)x" "\n" | 
|---|
| 8 | R"x( SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception)x" "\n" | 
|---|
| 9 | R"x()x" "\n" | 
|---|
| 10 | R"x(//===------------------------------------------------------------------------>)x" "\n" | 
|---|
| 11 | R"x()x" "\n" | 
|---|
| 12 | R"x(<head>)x" "\n" | 
|---|
| 13 | R"x(<?INJECT?>)x" "\n" | 
|---|
| 14 | R"x()x" "\n" | 
|---|
| 15 | R"x(<template id="value-template">)x" "\n" | 
|---|
| 16 | R"x(  <details class="value" open>)x" "\n" | 
|---|
| 17 | R"x(    <summary>)x" "\n" | 
|---|
| 18 | R"x(      <span>{{v.kind}})x" "\n" | 
|---|
| 19 | R"x(        <template data-if="v.value_id"><span class="address">#{{v.value_id}}</span></template>)x" "\n" | 
|---|
| 20 | R"x(      </span>)x" "\n" | 
|---|
| 21 | R"x(      <template data-if="v.location">)x" "\n" | 
|---|
| 22 | R"x(        <span class="location">{{v.type}} <span class="address">@{{v.location}}</span></span>)x" "\n" | 
|---|
| 23 | R"x(      </template>)x" "\n" | 
|---|
| 24 | R"x(    </summary>)x" "\n" | 
|---|
| 25 | R"x(    <template)x" "\n" | 
|---|
| 26 | R"x(        data-for="kv in Object.entries(v)")x" "\n" | 
|---|
| 27 | R"x(        data-if="['kind', 'value_id', 'type', 'location'].indexOf(kv[0]) < 0">)x" "\n" | 
|---|
| 28 | R"x(      <div class="property"><span class="key">{{kv[0]}}</span>)x" "\n" | 
|---|
| 29 | R"x(        <template data-if="typeof(kv[1]) != 'object'">{{kv[1]}}</template>)x" "\n" | 
|---|
| 30 | R"x(        <template data-if="typeof(kv[1]) == 'object'" data-let="v = kv[1]">)x" "\n" | 
|---|
| 31 | R"x(          <template data-use="value-template"></template>)x" "\n" | 
|---|
| 32 | R"x(        </template>)x" "\n" | 
|---|
| 33 | R"x(      </div>)x" "\n" | 
|---|
| 34 | R"x(    </template>)x" "\n" | 
|---|
| 35 | R"x(  </details>)x" "\n" | 
|---|
| 36 | R"x(</template>)x" "\n" | 
|---|
| 37 | R"x()x" "\n" | 
|---|
| 38 | R"x(</head>)x" "\n" | 
|---|
| 39 | R"x()x" "\n" | 
|---|
| 40 | R"x(<body>)x" "\n" | 
|---|
| 41 | R"x()x" "\n" | 
|---|
| 42 | R"x(<section id="timeline" data-selection="">)x" "\n" | 
|---|
| 43 | R"x(<header>Timeline</header>)x" "\n" | 
|---|
| 44 | R"x(<template data-for="entry in timeline">)x" "\n" | 
|---|
| 45 | R"x(  <div id="{{entry.block}}:{{entry.iter}}" data-bb="{{entry.block}}" class="entry">)x" "\n" | 
|---|
| 46 | R"x(    <span class="counter"></span>)x" "\n" | 
|---|
| 47 | R"x(    {{entry.block}})x" "\n" | 
|---|
| 48 | R"x(    <template data-if="entry.post_visit">(post-visit)</template>)x" "\n" | 
|---|
| 49 | R"x(    <template data-if="!entry.post_visit">({{entry.iter}})</template>)x" "\n" | 
|---|
| 50 | R"x(    <template data-if="entry.converged"> →|<!--Rightwards arrow, vertical line--></template>)x" "\n" | 
|---|
| 51 | R"x(  </div>)x" "\n" | 
|---|
| 52 | R"x(</template>)x" "\n" | 
|---|
| 53 | R"x(</section>)x" "\n" | 
|---|
| 54 | R"x()x" "\n" | 
|---|
| 55 | R"x(<section id="function" data-selection="">)x" "\n" | 
|---|
| 56 | R"x(<header>Function</header>)x" "\n" | 
|---|
| 57 | R"x(<div id="code"></div>)x" "\n" | 
|---|
| 58 | R"x(<div id="cfg"></div>)x" "\n" | 
|---|
| 59 | R"x(</section>)x" "\n" | 
|---|
| 60 | R"x()x" "\n" | 
|---|
| 61 | R"x(<section id="block" data-selection="bb">)x" "\n" | 
|---|
| 62 | R"x(<header><template>Block {{selection.bb}}</template></header>)x" "\n" | 
|---|
| 63 | R"x(<div id="iterations">)x" "\n" | 
|---|
| 64 | R"x(  <template data-for="iter in cfg[selection.bb].iters">)x" "\n" | 
|---|
| 65 | R"x(    <a class="chooser {{selection.bb}}:{{iter.iter}}" data-iter="{{selection.bb}}:{{iter.iter}}">)x" "\n" | 
|---|
| 66 | R"x(      <template data-if="iter.post_visit">Post-visit</template>)x" "\n" | 
|---|
| 67 | R"x(      <template data-if="!iter.post_visit">{{iter.iter}}</template>)x" "\n" | 
|---|
| 68 | R"x(      <template data-if="iter.converged"> →|<!--Rightwards arrow, vertical line--></template>)x" "\n" | 
|---|
| 69 | R"x(    </a>)x" "\n" | 
|---|
| 70 | R"x(  </template>)x" "\n" | 
|---|
| 71 | R"x(</div>)x" "\n" | 
|---|
| 72 | R"x(<table id="bb-elements">)x" "\n" | 
|---|
| 73 | R"x(<template>)x" "\n" | 
|---|
| 74 | R"x(  <tr id="{{selection.bb}}.0">)x" "\n" | 
|---|
| 75 | R"x(    <td class="{{selection.bb}}">{{selection.bb}}.0</td>)x" "\n" | 
|---|
| 76 | R"x(    <td>(initial state)</td>)x" "\n" | 
|---|
| 77 | R"x(  </tr>)x" "\n" | 
|---|
| 78 | R"x(</template>)x" "\n" | 
|---|
| 79 | R"x(<template data-for="elt in cfg[selection.bb].elements">)x" "\n" | 
|---|
| 80 | R"x(  <tr id="{{selection.bb}}.{{elt_index+1}}">)x" "\n" | 
|---|
| 81 | R"x(    <td class="{{selection.bb}}">{{selection.bb}}.{{elt_index+1}}</td>)x" "\n" | 
|---|
| 82 | R"x(    <td>{{elt}}</td>)x" "\n" | 
|---|
| 83 | R"x(  </tr>)x" "\n" | 
|---|
| 84 | R"x(</template>)x" "\n" | 
|---|
| 85 | R"x(</table>)x" "\n" | 
|---|
| 86 | R"x(</section>)x" "\n" | 
|---|
| 87 | R"x()x" "\n" | 
|---|
| 88 | R"x(<section id="element" data-selection="iter,elt">)x" "\n" | 
|---|
| 89 | R"x(<template data-let="state = states[selection.iter + '_' + selection.elt]">)x" "\n" | 
|---|
| 90 | R"x(<header>)x" "\n" | 
|---|
| 91 | R"x(  <template data-if="state.element == 0">{{state.block}} initial state</template>)x" "\n" | 
|---|
| 92 | R"x(  <template data-if="state.element != 0">Element {{selection.elt}}</template>)x" "\n" | 
|---|
| 93 | R"x(  <template data-if="state.post_visit"> (post-visit)</template>)x" "\n" | 
|---|
| 94 | R"x(  <template data-if="!state.post_visit"> (iteration {{state.iter}})</template>)x" "\n" | 
|---|
| 95 | R"x(</header>)x" "\n" | 
|---|
| 96 | R"x(<template data-if="state.value" data-let="v = state.value">)x" "\n" | 
|---|
| 97 | R"x(  <h2>Value</h2>)x" "\n" | 
|---|
| 98 | R"x(  <template data-use="value-template"></template>)x" "\n" | 
|---|
| 99 | R"x(</template>)x" "\n" | 
|---|
| 100 | R"x(<template data-if="state.logs">)x" "\n" | 
|---|
| 101 | R"x(  <h2>Logs</h2>)x" "\n" | 
|---|
| 102 | R"x(  <pre>{{state.logs}}</pre>)x" "\n" | 
|---|
| 103 | R"x(</template>)x" "\n" | 
|---|
| 104 | R"x(<h2>Built-in lattice</h2>)x" "\n" | 
|---|
| 105 | R"x(<pre>{{state.builtinLattice}}</pre>)x" "\n" | 
|---|
| 106 | R"x(</template>)x" "\n" | 
|---|
| 107 | R"x(</section>)x" "\n" | 
|---|
| 108 | R"x()x" "\n" | 
|---|
| 109 | R"x(<script>)x" "\n" | 
|---|
| 110 | R"x(addBBColors(Object.keys(HTMLLoggerData.cfg).length);)x" "\n" | 
|---|
| 111 | R"x(watchSelection(HTMLLoggerData);)x" "\n" | 
|---|
| 112 | R"x(updateSelection({}, HTMLLoggerData);)x" "\n" | 
|---|
| 113 | R"x(// Copy code and cfg from <template>s into the body.)x" "\n" | 
|---|
| 114 | R"x(for (tmpl of document.querySelectorAll('template[data-copy]')))x" "\n" | 
|---|
| 115 | R"x(  document.getElementById(tmpl.dataset.copy).replaceChildren()x" "\n" | 
|---|
| 116 | R"x(      ...tmpl.content.cloneNode(/*deep=*/true).childNodes);)x" "\n" | 
|---|
| 117 | R"x(</script>)x" "\n" | 
|---|
| 118 | R"x()x" "\n" | 
|---|
| 119 | R"x(</body>)x" "\n" | 
|---|
| 120 | R"x(</html>)x" "\n" | 
|---|
| 121 | R"x()x" "\n" | 
|---|
| 122 | ; | 
|---|
| 123 | const char HTMLLogger_css[] = | 
|---|
| 124 | R"x(/*===-- HTMLLogger.css ----------------------------------------------------===)x" "\n" | 
|---|
| 125 | R"x(*)x" "\n" | 
|---|
| 126 | R"x(* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.)x" "\n" | 
|---|
| 127 | R"x(* See https://llvm.org/LICENSE.txt for license information.)x" "\n" | 
|---|
| 128 | R"x(* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception)x" "\n" | 
|---|
| 129 | R"x(*)x" "\n" | 
|---|
| 130 | R"x(*===----------------------------------------------------------------------===*/)x" "\n" | 
|---|
| 131 | R"x(html { font-family: sans-serif; })x" "\n" | 
|---|
| 132 | R"x(body { margin: 0; display: flex; justify-content: left; })x" "\n" | 
|---|
| 133 | R"x(body > * { box-sizing: border-box; })x" "\n" | 
|---|
| 134 | R"x(body > section {)x" "\n" | 
|---|
| 135 | R"x(  border: 1px solid black;)x" "\n" | 
|---|
| 136 | R"x(  min-width: 20em;)x" "\n" | 
|---|
| 137 | R"x(  overflow: auto;)x" "\n" | 
|---|
| 138 | R"x(  max-height: 100vh;)x" "\n" | 
|---|
| 139 | R"x(})x" "\n" | 
|---|
| 140 | R"x(section header {)x" "\n" | 
|---|
| 141 | R"x(  background-color: #008;)x" "\n" | 
|---|
| 142 | R"x(  color: white;)x" "\n" | 
|---|
| 143 | R"x(  font-weight: bold;)x" "\n" | 
|---|
| 144 | R"x(  font-size: large;)x" "\n" | 
|---|
| 145 | R"x(  padding-right: 0.5em;)x" "\n" | 
|---|
| 146 | R"x(})x" "\n" | 
|---|
| 147 | R"x(section h2 {)x" "\n" | 
|---|
| 148 | R"x(  font-size: medium;)x" "\n" | 
|---|
| 149 | R"x(  margin-bottom: 0.5em;)x" "\n" | 
|---|
| 150 | R"x(  padding-top: 0.5em;)x" "\n" | 
|---|
| 151 | R"x(  border-top: 1px solid #aaa;)x" "\n" | 
|---|
| 152 | R"x(})x" "\n" | 
|---|
| 153 | R"x(#timeline {)x" "\n" | 
|---|
| 154 | R"x(  min-width: max-content;)x" "\n" | 
|---|
| 155 | R"x(  counter-reset: entry_counter;)x" "\n" | 
|---|
| 156 | R"x(})x" "\n" | 
|---|
| 157 | R"x(#timeline .entry .counter::before {)x" "\n" | 
|---|
| 158 | R"x(  counter-increment: entry_counter;)x" "\n" | 
|---|
| 159 | R"x(  content: counter(entry_counter) ":";)x" "\n" | 
|---|
| 160 | R"x(})x" "\n" | 
|---|
| 161 | R"x(#timeline .entry .counter {)x" "\n" | 
|---|
| 162 | R"x(  display: inline-block;)x" "\n" | 
|---|
| 163 | R"x(  min-width: 2em; /* Enough space for two digits and a colon */)x" "\n" | 
|---|
| 164 | R"x(  text-align: right;)x" "\n" | 
|---|
| 165 | R"x(})x" "\n" | 
|---|
| 166 | R"x(#timeline .entry.hover {)x" "\n" | 
|---|
| 167 | R"x(  background-color: #aaa;)x" "\n" | 
|---|
| 168 | R"x(})x" "\n" | 
|---|
| 169 | R"x(#timeline .entry.iter-select {)x" "\n" | 
|---|
| 170 | R"x(  background-color: #aac;)x" "\n" | 
|---|
| 171 | R"x(})x" "\n" | 
|---|
| 172 | R"x()x" "\n" | 
|---|
| 173 | R"x(#bb-elements {)x" "\n" | 
|---|
| 174 | R"x(  font-family: monospace;)x" "\n" | 
|---|
| 175 | R"x(  font-size: x-small;)x" "\n" | 
|---|
| 176 | R"x(  border-collapse: collapse;)x" "\n" | 
|---|
| 177 | R"x(})x" "\n" | 
|---|
| 178 | R"x(#bb-elements td:nth-child(1) {)x" "\n" | 
|---|
| 179 | R"x(  text-align: right;)x" "\n" | 
|---|
| 180 | R"x(  width: 4em;)x" "\n" | 
|---|
| 181 | R"x(  border-right: 1px solid #008;)x" "\n" | 
|---|
| 182 | R"x(  padding: 0.3em 0.5em;)x" "\n" | 
|---|
| 183 | R"x()x" "\n" | 
|---|
| 184 | R"x(  font-weight: bold;)x" "\n" | 
|---|
| 185 | R"x(  color: #888;)x" "\n" | 
|---|
| 186 | R"x(};)x" "\n" | 
|---|
| 187 | R"x(#bb-elements tr.hover {)x" "\n" | 
|---|
| 188 | R"x(  background-color: #abc;)x" "\n" | 
|---|
| 189 | R"x(})x" "\n" | 
|---|
| 190 | R"x(#bb-elements tr.elt-select {)x" "\n" | 
|---|
| 191 | R"x(  background-color: #acf;)x" "\n" | 
|---|
| 192 | R"x(})x" "\n" | 
|---|
| 193 | R"x(#iterations {)x" "\n" | 
|---|
| 194 | R"x(  display: flex;)x" "\n" | 
|---|
| 195 | R"x(})x" "\n" | 
|---|
| 196 | R"x(#iterations .chooser {)x" "\n" | 
|---|
| 197 | R"x(  flex-grow: 1;)x" "\n" | 
|---|
| 198 | R"x(  text-align: center;)x" "\n" | 
|---|
| 199 | R"x(  padding-left: 0.2em;)x" "\n" | 
|---|
| 200 | R"x(})x" "\n" | 
|---|
| 201 | R"x(#iterations .chooser :last-child {)x" "\n" | 
|---|
| 202 | R"x(  padding-right: 0.2em;)x" "\n" | 
|---|
| 203 | R"x(})x" "\n" | 
|---|
| 204 | R"x(#iterations .chooser:not(.iter-select).hover {)x" "\n" | 
|---|
| 205 | R"x(  background-color: #ddd;)x" "\n" | 
|---|
| 206 | R"x(})x" "\n" | 
|---|
| 207 | R"x(#iterations .iter-select {)x" "\n" | 
|---|
| 208 | R"x(  font-weight: bold;)x" "\n" | 
|---|
| 209 | R"x(})x" "\n" | 
|---|
| 210 | R"x(#iterations .chooser:not(.iter-select) {)x" "\n" | 
|---|
| 211 | R"x(  text-decoration: underline;)x" "\n" | 
|---|
| 212 | R"x(  color: blue;)x" "\n" | 
|---|
| 213 | R"x(  cursor: pointer;)x" "\n" | 
|---|
| 214 | R"x(  background-color: #ccc;)x" "\n" | 
|---|
| 215 | R"x(})x" "\n" | 
|---|
| 216 | R"x()x" "\n" | 
|---|
| 217 | R"x(code.filename {)x" "\n" | 
|---|
| 218 | R"x(  font-weight: bold;)x" "\n" | 
|---|
| 219 | R"x(  color: black;)x" "\n" | 
|---|
| 220 | R"x(  background-color: #ccc;)x" "\n" | 
|---|
| 221 | R"x(  display: block;)x" "\n" | 
|---|
| 222 | R"x(  text-align: center;)x" "\n" | 
|---|
| 223 | R"x(})x" "\n" | 
|---|
| 224 | R"x(code.line {)x" "\n" | 
|---|
| 225 | R"x(  display: block;)x" "\n" | 
|---|
| 226 | R"x(  white-space: pre;)x" "\n" | 
|---|
| 227 | R"x(})x" "\n" | 
|---|
| 228 | R"x(code.line:before { /* line numbers */)x" "\n" | 
|---|
| 229 | R"x(  content: attr(data-line);)x" "\n" | 
|---|
| 230 | R"x(  display: inline-block;)x" "\n" | 
|---|
| 231 | R"x(  width: 2em;)x" "\n" | 
|---|
| 232 | R"x(  text-align: right;)x" "\n" | 
|---|
| 233 | R"x(  padding-right: 2px;)x" "\n" | 
|---|
| 234 | R"x(  background-color: #ccc;)x" "\n" | 
|---|
| 235 | R"x(  border-right: 1px solid #888;)x" "\n" | 
|---|
| 236 | R"x(  margin-right: 8px;)x" "\n" | 
|---|
| 237 | R"x(})x" "\n" | 
|---|
| 238 | R"x(code.line:has(.bb-select):before {)x" "\n" | 
|---|
| 239 | R"x(  border-right: 4px solid black;)x" "\n" | 
|---|
| 240 | R"x(  margin-right: 5px;)x" "\n" | 
|---|
| 241 | R"x(})x" "\n" | 
|---|
| 242 | R"x(.c.hover, .bb.hover {)x" "\n" | 
|---|
| 243 | R"x(  filter: saturate(200%) brightness(90%);)x" "\n" | 
|---|
| 244 | R"x(})x" "\n" | 
|---|
| 245 | R"x(.c.elt-select {)x" "\n" | 
|---|
| 246 | R"x(  box-shadow: inset 0 -4px 2px -2px #a00;)x" "\n" | 
|---|
| 247 | R"x(})x" "\n" | 
|---|
| 248 | R"x(.bb.bb-select polygon {)x" "\n" | 
|---|
| 249 | R"x(  stroke-width: 4px;)x" "\n" | 
|---|
| 250 | R"x(  filter: brightness(70%) saturate(150%);)x" "\n" | 
|---|
| 251 | R"x(})x" "\n" | 
|---|
| 252 | R"x(.bb { user-select: none; })x" "\n" | 
|---|
| 253 | R"x(.bb polygon { fill: white; })x" "\n" | 
|---|
| 254 | R"x(#cfg {)x" "\n" | 
|---|
| 255 | R"x(  position: relative;)x" "\n" | 
|---|
| 256 | R"x(  margin-left: 0.5em;)x" "\n" | 
|---|
| 257 | R"x(})x" "\n" | 
|---|
| 258 | R"x()x" "\n" | 
|---|
| 259 | R"x(.value {)x" "\n" | 
|---|
| 260 | R"x(  border: 1px solid #888;)x" "\n" | 
|---|
| 261 | R"x(  font-size: x-small;)x" "\n" | 
|---|
| 262 | R"x(  flex-grow: 1;)x" "\n" | 
|---|
| 263 | R"x(})x" "\n" | 
|---|
| 264 | R"x(.value > summary {)x" "\n" | 
|---|
| 265 | R"x(  background-color: #ace;)x" "\n" | 
|---|
| 266 | R"x(  display: flex;)x" "\n" | 
|---|
| 267 | R"x(  cursor: pointer;)x" "\n" | 
|---|
| 268 | R"x(})x" "\n" | 
|---|
| 269 | R"x(.value > summary::before {)x" "\n" | 
|---|
| 270 | R"x(  content: '\25ba';  /* Black Right-Pointing Pointer */)x" "\n" | 
|---|
| 271 | R"x(  margin-right: 0.5em;)x" "\n" | 
|---|
| 272 | R"x(  font-size: 0.9em;)x" "\n" | 
|---|
| 273 | R"x(})x" "\n" | 
|---|
| 274 | R"x(.value[open] > summary::before {)x" "\n" | 
|---|
| 275 | R"x(  content: '\25bc';  /* Black Down-Pointing Triangle */)x" "\n" | 
|---|
| 276 | R"x(})x" "\n" | 
|---|
| 277 | R"x(.value > summary > .location {)x" "\n" | 
|---|
| 278 | R"x(  margin-left: auto;)x" "\n" | 
|---|
| 279 | R"x(})x" "\n" | 
|---|
| 280 | R"x(.value .address {)x" "\n" | 
|---|
| 281 | R"x(  font-size: xx-small;)x" "\n" | 
|---|
| 282 | R"x(  font-family: monospace;)x" "\n" | 
|---|
| 283 | R"x(  color: #888;)x" "\n" | 
|---|
| 284 | R"x(})x" "\n" | 
|---|
| 285 | R"x(.value .property {)x" "\n" | 
|---|
| 286 | R"x(  display: flex;)x" "\n" | 
|---|
| 287 | R"x(  margin-top: 0.5em;)x" "\n" | 
|---|
| 288 | R"x(})x" "\n" | 
|---|
| 289 | R"x(.value .property .key {)x" "\n" | 
|---|
| 290 | R"x(  font-weight: bold;)x" "\n" | 
|---|
| 291 | R"x(  min-width: 5em;)x" "\n" | 
|---|
| 292 | R"x(})x" "\n" | 
|---|
| 293 | R"x()x" "\n" | 
|---|
| 294 | ; | 
|---|
| 295 | const char HTMLLogger_js[] = | 
|---|
| 296 | R"x(//===-- HTMLLogger.js -----------------------------------------------------===//)x" "\n" | 
|---|
| 297 | R"x(//)x" "\n" | 
|---|
| 298 | R"x(// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.)x" "\n" | 
|---|
| 299 | R"x(// See https://llvm.org/LICENSE.txt for license information.)x" "\n" | 
|---|
| 300 | R"x(// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception)x" "\n" | 
|---|
| 301 | R"x(//)x" "\n" | 
|---|
| 302 | R"x(//===----------------------------------------------------------------------===//)x" "\n" | 
|---|
| 303 | R"x()x" "\n" | 
|---|
| 304 | R"x(// Based on selected objects, hide/show sections & populate data from templates.)x" "\n" | 
|---|
| 305 | R"x(//)x" "\n" | 
|---|
| 306 | R"x(// For example, if the selection is {bb="BB4", elt="BB4.6" iter="BB4:2"}:)x" "\n" | 
|---|
| 307 | R"x(//   - show the "block" and "element" sections)x" "\n" | 
|---|
| 308 | R"x(//   - re-render templates within these sections (if selection changed))x" "\n" | 
|---|
| 309 | R"x(//   - apply "bb-select" to items with class class "BB4", etc)x" "\n" | 
|---|
| 310 | R"x(let selection = {};)x" "\n" | 
|---|
| 311 | R"x(function updateSelection(changes, data) {)x" "\n" | 
|---|
| 312 | R"x(  Object.assign(selection, changes);)x" "\n" | 
|---|
| 313 | R"x()x" "\n" | 
|---|
| 314 | R"x(  data = Object.create(data);)x" "\n" | 
|---|
| 315 | R"x(  data.selection = selection;)x" "\n" | 
|---|
| 316 | R"x(  for (root of document.querySelectorAll('[data-selection]')))x" "\n" | 
|---|
| 317 | R"x(    updateSection(root, data);)x" "\n" | 
|---|
| 318 | R"x()x" "\n" | 
|---|
| 319 | R"x(  for (var k in changes))x" "\n" | 
|---|
| 320 | R"x(    applyClassIf(k + '-select', classSelector(changes[k]));)x" "\n" | 
|---|
| 321 | R"x(})x" "\n" | 
|---|
| 322 | R"x()x" "\n" | 
|---|
| 323 | R"x(// Given <section data-selection="x,y">:)x" "\n" | 
|---|
| 324 | R"x(//  - hide section if selections x or y are null)x" "\n" | 
|---|
| 325 | R"x(//  - re-render templates if x or y have changed)x" "\n" | 
|---|
| 326 | R"x(function updateSection(root, data) {)x" "\n" | 
|---|
| 327 | R"x(  let changed = root.selection == null;)x" "\n" | 
|---|
| 328 | R"x(  root.selection ||= {};)x" "\n" | 
|---|
| 329 | R"x(  for (key of root.dataset.selection.split(',')) {)x" "\n" | 
|---|
| 330 | R"x(    if (!key) continue;)x" "\n" | 
|---|
| 331 | R"x(    if (data.selection[key] != root.selection[key]) {)x" "\n" | 
|---|
| 332 | R"x(      root.selection[key] = data.selection[key];)x" "\n" | 
|---|
| 333 | R"x(      changed = true;)x" "\n" | 
|---|
| 334 | R"x(    })x" "\n" | 
|---|
| 335 | R"x(    if (data.selection[key] == null) {)x" "\n" | 
|---|
| 336 | R"x(      root.hidden = true;)x" "\n" | 
|---|
| 337 | R"x(      return;)x" "\n" | 
|---|
| 338 | R"x(    })x" "\n" | 
|---|
| 339 | R"x(  })x" "\n" | 
|---|
| 340 | R"x(  if (changed) {)x" "\n" | 
|---|
| 341 | R"x(    root.hidden = false;)x" "\n" | 
|---|
| 342 | R"x(    for (tmpl of root.getElementsByTagName('template')))x" "\n" | 
|---|
| 343 | R"x(      reinflate(tmpl, data);)x" "\n" | 
|---|
| 344 | R"x(  })x" "\n" | 
|---|
| 345 | R"x(})x" "\n" | 
|---|
| 346 | R"x()x" "\n" | 
|---|
| 347 | R"x(// Expands template `tmpl` based on input `data`:)x" "\n" | 
|---|
| 348 | R"x(//  - interpolates {{expressions}} in text and attributes)x" "\n" | 
|---|
| 349 | R"x(//  - <template> tags can modify expansion: if, for etc)x" "\n" | 
|---|
| 350 | R"x(// Outputs to `parent` element, inserting before `next`.)x" "\n" | 
|---|
| 351 | R"x(function inflate(tmpl, data, parent, next) {)x" "\n" | 
|---|
| 352 | R"x(  // We use eval() as our expression language in templates!)x" "\n" | 
|---|
| 353 | R"x(  // The templates are static and trusted.)x" "\n" | 
|---|
| 354 | R"x(  let evalExpr = (expr, data) => eval('with (data) { ' + expr + ' }');)x" "\n" | 
|---|
| 355 | R"x(  let interpolate = (str, data) =>)x" "\n" | 
|---|
| 356 | R"x(      str.replace(/\{\{(.*?)\}\}/g, (_, expr) => evalExpr(expr, data)))x" "\n" | 
|---|
| 357 | R"x(  // Anything other than <template> tag: copy, interpolate, recursively inflate.)x" "\n" | 
|---|
| 358 | R"x(  if (tmpl.nodeName != 'TEMPLATE') {)x" "\n" | 
|---|
| 359 | R"x(    let clone = tmpl.cloneNode();)x" "\n" | 
|---|
| 360 | R"x(    clone.inflated = true;)x" "\n" | 
|---|
| 361 | R"x(    if (clone instanceof Text))x" "\n" | 
|---|
| 362 | R"x(      clone.textContent = interpolate(clone.textContent, data);)x" "\n" | 
|---|
| 363 | R"x(    if (clone instanceof Element) {)x" "\n" | 
|---|
| 364 | R"x(      for (attr of clone.attributes))x" "\n" | 
|---|
| 365 | R"x(        attr.value = interpolate(attr.value, data);)x" "\n" | 
|---|
| 366 | R"x(      for (c of tmpl.childNodes))x" "\n" | 
|---|
| 367 | R"x(        inflate(c, data, clone, /*next=*/null);)x" "\n" | 
|---|
| 368 | R"x(    })x" "\n" | 
|---|
| 369 | R"x(    return parent.insertBefore(clone, next);)x" "\n" | 
|---|
| 370 | R"x(  })x" "\n" | 
|---|
| 371 | R"x(  // data-use="xyz": use <template id="xyz"> instead. (Allows recursion.))x" "\n" | 
|---|
| 372 | R"x(  if ('use' in tmpl.dataset))x" "\n" | 
|---|
| 373 | R"x(    return inflate(document.getElementById(tmpl.dataset.use), data, parent, next);)x" "\n" | 
|---|
| 374 | R"x(  // <template> tag handling. Base case: recursively inflate.)x" "\n" | 
|---|
| 375 | R"x(  function handle(data) {)x" "\n" | 
|---|
| 376 | R"x(    for (c of tmpl.content.childNodes))x" "\n" | 
|---|
| 377 | R"x(      inflate(c, data, parent, next);)x" "\n" | 
|---|
| 378 | R"x(  })x" "\n" | 
|---|
| 379 | R"x(  // Directives on <template> tags modify behavior.)x" "\n" | 
|---|
| 380 | R"x(  const directives = {)x" "\n" | 
|---|
| 381 | R"x(    // data-for="x in expr": expr is enumerable, bind x to each in turn)x" "\n" | 
|---|
| 382 | R"x(    'for': (nameInExpr, data, proceed) => {)x" "\n" | 
|---|
| 383 | R"x(      let [name, expr] = nameInExpr.split(' in ');)x" "\n" | 
|---|
| 384 | R"x(      let newData = Object.create(data);)x" "\n" | 
|---|
| 385 | R"x(      let index = 0;)x" "\n" | 
|---|
| 386 | R"x(      for (val of evalExpr(expr, data) || []) {)x" "\n" | 
|---|
| 387 | R"x(        newData[name] = val;)x" "\n" | 
|---|
| 388 | R"x(        newData[name + '_index'] = index++;)x" "\n" | 
|---|
| 389 | R"x(        proceed(newData);)x" "\n" | 
|---|
| 390 | R"x(      })x" "\n" | 
|---|
| 391 | R"x(    },)x" "\n" | 
|---|
| 392 | R"x(    // data-if="expr": only include contents if expression is truthy)x" "\n" | 
|---|
| 393 | R"x(    'if': (expr, data, proceed) => { if (evalExpr(expr, data)) proceed(data); },)x" "\n" | 
|---|
| 394 | R"x(    // data-let="x = expr": bind x to value of expr)x" "\n" | 
|---|
| 395 | R"x(    'let': (nameEqExpr, data, proceed) => {)x" "\n" | 
|---|
| 396 | R"x(      let [name, expr] = nameEqExpr.split(' = ');)x" "\n" | 
|---|
| 397 | R"x(      let newData = Object.create(data);)x" "\n" | 
|---|
| 398 | R"x(      newData[name] = evalExpr(expr, data);)x" "\n" | 
|---|
| 399 | R"x(      proceed(newData);)x" "\n" | 
|---|
| 400 | R"x(    },)x" "\n" | 
|---|
| 401 | R"x(  })x" "\n" | 
|---|
| 402 | R"x(  // Compose directive handlers on top of the base handler.)x" "\n" | 
|---|
| 403 | R"x(  for (let [dir, value] of Object.entries(tmpl.dataset).reverse()) {)x" "\n" | 
|---|
| 404 | R"x(    if (dir in directives) {)x" "\n" | 
|---|
| 405 | R"x(      let proceed = handle;)x" "\n" | 
|---|
| 406 | R"x(      handle = (data) => directives[dir](value, data, proceed);)x" "\n" | 
|---|
| 407 | R"x(    })x" "\n" | 
|---|
| 408 | R"x(  })x" "\n" | 
|---|
| 409 | R"x(  handle(data);)x" "\n" | 
|---|
| 410 | R"x(})x" "\n" | 
|---|
| 411 | R"x(// Expand a template, after first removing any prior expansion of it.)x" "\n" | 
|---|
| 412 | R"x(function reinflate(tmpl, data) {)x" "\n" | 
|---|
| 413 | R"x(  // Clear previously rendered template contents.)x" "\n" | 
|---|
| 414 | R"x(  while (tmpl.nextSibling && tmpl.nextSibling.inflated))x" "\n" | 
|---|
| 415 | R"x(    tmpl.parentNode.removeChild(tmpl.nextSibling);)x" "\n" | 
|---|
| 416 | R"x(  inflate(tmpl, data, tmpl.parentNode, tmpl.nextSibling);)x" "\n" | 
|---|
| 417 | R"x(})x" "\n" | 
|---|
| 418 | R"x()x" "\n" | 
|---|
| 419 | R"x(// Handle a mouse event on a region containing selectable items.)x" "\n" | 
|---|
| 420 | R"x(// This might end up changing the hover state or the selection state.)x" "\n" | 
|---|
| 421 | R"x(//)x" "\n" | 
|---|
| 422 | R"x(// targetSelector describes what target HTML element is selectable.)x" "\n" | 
|---|
| 423 | R"x(// targetToID specifies how to determine the selection from it:)x" "\n" | 
|---|
| 424 | R"x(//   hover: a function from target to the class name to highlight)x" "\n" | 
|---|
| 425 | R"x(//   bb: a function from target to the basic-block name to select (BB4))x" "\n" | 
|---|
| 426 | R"x(//   elt: a function from target to the CFG element name to select (BB4.5))x" "\n" | 
|---|
| 427 | R"x(//   iter: a function from target to the BB iteration to select (BB4:2))x" "\n" | 
|---|
| 428 | R"x(// If an entry is missing, the selection is unmodified.)x" "\n" | 
|---|
| 429 | R"x(// If an entry is null, the selection is always cleared.)x" "\n" | 
|---|
| 430 | R"x(function mouseEventHandler(event, targetSelector, targetToID, data) {)x" "\n" | 
|---|
| 431 | R"x(  var target = event.type == "mouseout" ? null : event.target.closest(targetSelector);)x" "\n" | 
|---|
| 432 | R"x(  let selTarget = k => (target && targetToID[k]) ? targetToID[k](target) : null;)x" "\n" | 
|---|
| 433 | R"x(  if (event.type == "click") {)x" "\n" | 
|---|
| 434 | R"x(    let newSel = {};)x" "\n" | 
|---|
| 435 | R"x(    for (var k in targetToID) {)x" "\n" | 
|---|
| 436 | R"x(      if (k == 'hover') continue;)x" "\n" | 
|---|
| 437 | R"x(      let t = selTarget(k);)x" "\n" | 
|---|
| 438 | R"x(      newSel[k] = t;)x" "\n" | 
|---|
| 439 | R"x(    })x" "\n" | 
|---|
| 440 | R"x(    updateSelection(newSel, data);)x" "\n" | 
|---|
| 441 | R"x(  } else if ("hover" in targetToID) {)x" "\n" | 
|---|
| 442 | R"x(    applyClassIf("hover", classSelector(selTarget("hover")));)x" "\n" | 
|---|
| 443 | R"x(  })x" "\n" | 
|---|
| 444 | R"x(})x" "\n" | 
|---|
| 445 | R"x(function watch(rootSelector, targetSelector, targetToID, data) {)x" "\n" | 
|---|
| 446 | R"x(  var root = document.querySelector(rootSelector);)x" "\n" | 
|---|
| 447 | R"x(  for (event of ['mouseout', 'mousemove', 'click']))x" "\n" | 
|---|
| 448 | R"x(    root.addEventListener(event, e => mouseEventHandler(e, targetSelector, targetToID, data));)x" "\n" | 
|---|
| 449 | R"x(})x" "\n" | 
|---|
| 450 | R"x(function watchSelection(data) {)x" "\n" | 
|---|
| 451 | R"x(  let lastIter = (bb) => `${bb}:${data.cfg[bb].iters}`;)x" "\n" | 
|---|
| 452 | R"x(  watch('#code', '.c', {)x" "\n" | 
|---|
| 453 | R"x(    hover: e => e.dataset.elt,)x" "\n" | 
|---|
| 454 | R"x(    bb: e => e.dataset.bb,)x" "\n" | 
|---|
| 455 | R"x(    elt: e => e.dataset.elt,)x" "\n" | 
|---|
| 456 | R"x(    // If we're already viewing an iteration of this BB, stick with the same.)x" "\n" | 
|---|
| 457 | R"x(    iter: e => (selection.iter && selection.bb == e.dataset.bb) ? selection.iter : lastIter(e.dataset.bb),)x" "\n" | 
|---|
| 458 | R"x(  }, data);)x" "\n" | 
|---|
| 459 | R"x(  watch('#cfg', '.bb', {)x" "\n" | 
|---|
| 460 | R"x(    hover: e => e.id,)x" "\n" | 
|---|
| 461 | R"x(    bb: e => e.id,)x" "\n" | 
|---|
| 462 | R"x(    elt: e => e.id + ".0",)x" "\n" | 
|---|
| 463 | R"x(    iter: e => lastIter(e.id),)x" "\n" | 
|---|
| 464 | R"x(  }, data);)x" "\n" | 
|---|
| 465 | R"x(  watch('#timeline', '.entry', {)x" "\n" | 
|---|
| 466 | R"x(    hover: e => [e.id, e.dataset.bb],)x" "\n" | 
|---|
| 467 | R"x(    bb: e => e.dataset.bb,)x" "\n" | 
|---|
| 468 | R"x(    elt: e => e.dataset.bb + ".0",)x" "\n" | 
|---|
| 469 | R"x(    iter: e => e.id,)x" "\n" | 
|---|
| 470 | R"x(  }, data);)x" "\n" | 
|---|
| 471 | R"x(  watch('#bb-elements', 'tr', {)x" "\n" | 
|---|
| 472 | R"x(    hover: e => e.id,)x" "\n" | 
|---|
| 473 | R"x(    elt: e => e.id,)x" "\n" | 
|---|
| 474 | R"x(  }, data);)x" "\n" | 
|---|
| 475 | R"x(  watch('#iterations', '.chooser', {)x" "\n" | 
|---|
| 476 | R"x(    hover: e => e.dataset.iter,)x" "\n" | 
|---|
| 477 | R"x(    iter: e => e.dataset.iter,)x" "\n" | 
|---|
| 478 | R"x(  }, data);)x" "\n" | 
|---|
| 479 | R"x(  updateSelection({}, data);)x" "\n" | 
|---|
| 480 | R"x(})x" "\n" | 
|---|
| 481 | R"x(function applyClassIf(cls, query) {)x" "\n" | 
|---|
| 482 | R"x(  document.querySelectorAll('.' + cls).forEach(elt => elt.classList.remove(cls));)x" "\n" | 
|---|
| 483 | R"x(  document.querySelectorAll(query).forEach(elt => elt.classList.add(cls));)x" "\n" | 
|---|
| 484 | R"x(})x" "\n" | 
|---|
| 485 | R"x(// Turns a class name into a CSS selector matching it, with some wrinkles:)x" "\n" | 
|---|
| 486 | R"x(// - we treat id="foo" just like class="foo" to avoid repetition in the HTML)x" "\n" | 
|---|
| 487 | R"x(// - cls can be an array of strings, we match them all)x" "\n" | 
|---|
| 488 | R"x(function classSelector(cls) {)x" "\n" | 
|---|
| 489 | R"x(  if (cls == null) return null;)x" "\n" | 
|---|
| 490 | R"x(  if (Array.isArray(cls)) return cls.map(classSelector).join(', ');)x" "\n" | 
|---|
| 491 | R"x(  var escaped = cls.replace('.', '\\.').replace(':', '\\:');)x" "\n" | 
|---|
| 492 | R"x(  // don't require id="foo" class="foo")x" "\n" | 
|---|
| 493 | R"x(  return '.' + escaped + ", #" + escaped;)x" "\n" | 
|---|
| 494 | R"x(})x" "\n" | 
|---|
| 495 | R"x()x" "\n" | 
|---|
| 496 | R"x(// Add a stylesheet defining colors for n basic blocks.)x" "\n" | 
|---|
| 497 | R"x(function addBBColors(n) {)x" "\n" | 
|---|
| 498 | R"x(  let sheet = new CSSStyleSheet();)x" "\n" | 
|---|
| 499 | R"x(  // hex values to subtract from fff to get a base color)x" "\n" | 
|---|
| 500 | R"x(  options = [0x001, 0x010, 0x011, 0x100, 0x101, 0x110, 0x111];)x" "\n" | 
|---|
| 501 | R"x(  function color(hex) {)x" "\n" | 
|---|
| 502 | R"x(    return "#" + hex.toString(16).padStart(3, "0");)x" "\n" | 
|---|
| 503 | R"x(  })x" "\n" | 
|---|
| 504 | R"x(  function add(selector, property, hex) {)x" "\n" | 
|---|
| 505 | R"x(    sheet.insertRule(`${selector} { ${property}: ${color(hex)}; }`))x" "\n" | 
|---|
| 506 | R"x(  })x" "\n" | 
|---|
| 507 | R"x(  for (var i = 0; i < n; ++i) {)x" "\n" | 
|---|
| 508 | R"x(    let opt = options[i%options.length];)x" "\n" | 
|---|
| 509 | R"x(    add(`.B${i}`, 'background-color', 0xfff - 2*opt);)x" "\n" | 
|---|
| 510 | R"x(    add(`#B${i} polygon`, 'fill', 0xfff - 2*opt);)x" "\n" | 
|---|
| 511 | R"x(    add(`#B${i} polygon`, 'stroke', 0x888 - 4*opt);)x" "\n" | 
|---|
| 512 | R"x(  })x" "\n" | 
|---|
| 513 | R"x(  document.adoptedStyleSheets.push(sheet);)x" "\n" | 
|---|
| 514 | R"x(})x" "\n" | 
|---|
| 515 | R"x()x" "\n" | 
|---|
| 516 | ; | 
|---|
| 517 |  | 
|---|