https://github.com/akkartik/mu/blob/main/linux/dquotes.subx
   1 # Translate literal strings within double quotes.
   2 # Replace them with references to new variables in the data segment.
   3 #
   4 # To run:
   5 #   $ bootstrap/bootstrap translate [01]*.subx subx-params.subx dquotes.subx  -o dquotes
   6 #   $ cat x
   7 #   == code
   8 #   ab "cd ef"/imm32
   9 #   $ cat x  |bootstrap/bootstrap run dquotes
  10 #   == code
  11 #   ab __string1/imm32
  12 #   == data
  13 #   __string1:
  14 #     5/imm32
  15 #     0x63/c 0x64/d 0x20/  0x65/e 0x66/f
  16 
  17 == code
  18 #   instruction                     effective address                                                   register    displacement    immediate
  19 # . op          subop               mod             rm32          base        index         scale       r32
  20 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
  21 
  22 Entry:  # run tests if necessary, convert stdin if not
  23     # . prologue
  24     89/copy                         3/mod/direct    5/rm32/ebp    .           . 
c{0: 0 (((1 integer)) <- ((copy)) ((0 literal))) -- nil
c{0: 1 (((2 integer)) <- ((copy)) ((0 literal))) -- nil
c{0: 2 (((3 integer)) <- ((copy)) ((0 literal))) -- nil
c{0: 3 (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer))) -- ((open 3))
c{0: 4 (((break-if)) ((4 boolean))) -- ((open 3))
c{0: 5 (((5 integer)) <- ((copy)) ((0 literal))) -- ((open 5) (open 3))
c{0: 6 (((reply))) -- ((close 6) (close 6) (open 5) (open 3))
c{1: 0 ✓ (((1 integer)) <- ((copy)) ((0 literal)))
c{1: 1 ✓ (((2 integer)) <- ((copy)) ((0 literal)))
c{1: 2 ✓ (((3 integer)) <- ((copy)) ((0 literal)))
c{1: 3 ✓ (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer)))
c{1: 4 X (((break-if)) ((4 boolean))) => (((jump-if)) ((4 boolean)) ((1 offset)))
c{1: 5 ✓ (((5 integer)) <- ((copy)) ((0 literal)))
c{1: 6 ✓ (((reply)))
py 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax 65 # subx-dquotes(Stdin, Stdout, Stderr, ed) 66 # . . push args 67 50/push-eax/ed 68 68/push Stderr/imm32 69 68/push Stdout/imm32 70 68/push Stdin/imm32 71 # . . call 72 e8/call subx-dquotes/disp32 73 # . . discard args 74 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 75 # syscall(exit, 0) 76 bb/copy-to-ebx 0/imm32 77 $subx-dquotes-main:end: 78 e8/call syscall_exit/disp32 79 80 # conceptual hierarchy within a line: 81 # line = words separated by ' ', maybe followed by comment starting with '#' 82 # word = datum until '/', then 0 or more metadata separated by '/' 83 84 subx-dquotes: # in: (addr buffered-file), out: (addr buffered-file) 85 # pseudocode: 86 # var line: (stream byte 512) 87 # var new-data-segment-handle: (handle stream byte) 88 # new-stream(Heap, Segment-size, 1, new-data-segment-handle) 89 # var new-data-segment: (addr stream byte) = lookup(new-data-segment-handle) 90 # 91 # write(new-data-segment, "== data\n") 92 # # TODO: When it was originally written dquotes ran before assort, so 93 # # it assumes lots of segment headers, and emits a new segment of its 94 # # own. We've since had to reorder the phases (see the explanation 95 # # for a.assort2 in translate_subx). We could clean up a.assort2 if we 96 # # conditionally emit the previous line. But this would require 97 # # teaching dquotes to parse segment headers, so maybe that's not 98 # # best.. 99 # 100 # while true 101 # clear-stream(line) 102 # read-line-buffered(in, line) 103 # if (line->write == 0) break # end of file 104 # while true 105 # var word-slice = next-word-or-string(line) 106 # if slice-empty?(word-slice) # end of line 107 # break 108 # if slice-starts-with?(word-slice, "#") # comment 109 # continue 110 # if slice-starts-with?(word-slice, '"') # string literal <== what we're here for 111 # process-string-literal(word-slice, out, new-data-segment) 112 # else 113 # write-slice-buffered(out, word-slice) 114 # write(out, " ") 115 # write(out, "\n\n") 116 # write-stream-data(out, new-data-segment) 117 # flush(out) 118 # 119 # . prologue 120 55/push-ebp 121 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 122 # . save registers 123 50/push-eax 124 51/push-ecx 125 52/push-edx 126 53/push-ebx 127 56/push-esi 128 57/push-edi 129 # var line/ecx: (stream byte 512) 130 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp 131 68/push 0x200/imm32/length 132 68/push 0/imm32/read 133 68/push 0/imm32/write 134 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 135 # var word-slice/edx: slice 136 68/push 0/imm32/end 137 68/push 0/imm32/start 138 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 139 # var new-data-segment-handle/edi: (handle stream byte) 140 68/push 0/imm32 141 68/push 0/imm32 142 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi 143 # new-stream(Heap, Segment-size, 1, new-data-segment-handle) 144 # . . push args 145 57/push-edi 146 68/push 1/imm32 147 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size 148 68/push Heap/imm32 149 # . . call 150 e8/call new-stream/disp32 151 # . . discard args 152 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 153 # var new-data-segment/edi: (addr stream byte) = lookup(*new-data-segment-handle) 154 # . eax = lookup(*new-data-segment-handle) 155 # . . push args 156 ff 6/subop/push 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 . # push *(edi+4) 157 ff 6/subop/push 0/mod/indirect 7/rm32/edi . . . . . . # push *edi 158 # . . call 159 e8/call lookup/disp32 160 # . . discard args 161 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 162 # . new-data-segment = eax 163 89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi 164 # write(new-data-segment, "== data\n") 165 # . . push args 166 68/push "== data\n"/imm32 167 57/push-edi 168 # . . call 169 e8/call write/disp32 170 # . . discard args 171 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 172 $subx-dquotes:line-loop: 173 # clear-stream(line) 174 # . . push args 175 51/push-ecx 176 # . . call 177 e8/call clear-stream/disp32 178 # . . discard args 179 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 180 # read-line-buffered(in, line) 181 # . . push args 182 51/push-ecx 183 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 184 # . . call 185 e8/call read-line-buffered/disp32 186 # . . discard args 187 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 188 $subx-dquotes:check0: 189 # if (line->write == 0) break 190 81 7/subop/compare 0/mod/indirect 1/rm32/ecx . . . . . 0/imm32 # compare *ecx 191 0f 84/jump-if-= $subx-dquotes:break/disp32 192 $subx-dquotes:word-loop: 193 # next-word-or-string(line, word-slice) 194 # . . push args 195 52/push-edx 196 51/push-ecx 197 # . . call 198 e8/call next-word-or-string/disp32 199 # . . discard args 200 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 201 $subx-dquotes:check1: 202 # if (slice-empty?(word-slice)) break 203 # . eax = slice-empty?(word-slice) 204 # . . push args 205 52/push-edx 206 # . . call 207 e8/call slice-empty?/disp32 208 # . . discard args 209 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 210 # . if (eax != false) break 211 3d/compare-eax-and 0/imm32/false 212 0f 85/jump-if-!= $subx-dquotes:next-line/disp32 213 $subx-dquotes:check-for-comment: 214 # if (slice-starts-with?(word-slice, "#")) continue 215 # . var start/esi: (addr byte) = word-slice->start 216 8b/copy 0/mod/indirect 2/rm32/edx . . . 6/r32/esi . . # copy *edx to esi 217 # . var c/eax: byte = *start 218 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 219 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL 220 # . if (c == '#') continue 221 3d/compare-eax-and 0x23/imm32/hash 222 74/jump-if-= $subx-dquotes:word-loop/disp8 223 $subx-dquotes:check-for-string-literal: 224 # if (slice-starts-with?(word-slice, '"')) continue 225 3d/compare-eax-and 0x22/imm32/dquote 226 75/jump-if-!= $subx-dquotes:regular-word/disp8 227 $subx-dquotes:string-literal: 228 # process-string-literal(word-slice, out, new-data-segment) 229 # . . push args 230 57/push-edi 231 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 232 52/push-edx 233 # . . call 234 e8/call process-string-literal/disp32 235 # . . discard args 236 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 237 # continue 238 eb/jump $subx-dquotes:next-word/disp8 239 $subx-dquotes:regular-word: 240 # write-slice-buffered(out, word-slice) 241 # . . push args 242 52/push-edx 243 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 244 # . . call 245 e8/call write-slice-buffered/disp32 246 # . . discard args 247 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 248 # fall through 249 $subx-dquotes:next-word: 250 # write-buffered(out, " ") 251 # . . push args 252 68/push Space/imm32 253 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 254 # . . call 255 e8/call write-buffered/disp32 256 # . . discard args 257 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 258 # loop 259 eb/jump $subx-dquotes:word-loop/disp8 260 $subx-dquotes:next-line: 261 # write-buffered(out, "\n") 262 # . . push args 263 68/push Newline/imm32 264 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 265 # . . call 266 e8/call write-buffered/disp32 267 # . . discard args 268 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 269 # loop 270 e9/jump $subx-dquotes:line-loop/disp32 271 $subx-dquotes:break: 272 # write-stream-data(out, new-data-segment) 273 # . . push args 274 57/push-edi 275 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 276 # . . call 277 e8/call write-stream-data/disp32 278 # . . discard args 279 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 280 # flush(out) 281 # . . push args 282 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 283 # . . call 284 e8/call flush/disp32 285 # . . discard args 286 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 287 $subx-dquotes:end: 288 # . reclaim locals 289 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x21c/imm32 # add to esp 290 # . restore registers 291 5f/pop-to-edi 292 5e/pop-to-esi 293 5b/pop-to-ebx 294 5a/pop-to-edx 295 59/pop-to-ecx 296 58/pop-to-eax 297 # . epilogue 298 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 299 5d/pop-to-ebp 300 c3/return 301 302 # Write out 'string-literal' in a new format to 'out-segment', assign it a new 303 # label, and write the new label out to 'out'. 304 process-string-literal: # string-literal: (addr slice), out: (addr buffered-file), out-segment: (addr stream byte) 305 # pseudocode: 306 # print(out-segment, "_string#{Next-string-literal}:\n") 307 # emit-string-literal-data(out-segment, string-literal) 308 # print(out, "_string#{Next-string-literal}") 309 # emit-metadata(out, string-literal) 310 # ++ *Next-string-literal 311 # 312 # . prologue 313 55/push-ebp 314 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 315 # . save registers 316 51/push-ecx 317 # var int32-stream/ecx: (stream byte 10) # number of decimal digits a 32-bit number can have 318 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xa/imm32 # subtract from esp 319 68/push 0xa/imm32/decimal-digits-in-32bit-number 320 68/push 0/imm32/read 321 68/push 0/imm32/write 322 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 323 # print(out-segment, "_string#{Next-string-literal}:\n") 324 # . write(out-segment, "_string") 325 # . . push args 326 68/push "_string"/imm32 327 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 328 # . . call 329 e8/call write/disp32 330 # . . discard args 331 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 332 # . write-int32-decimal(out-segment, *Next-string-literal) 333 # . . push args 334 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal 335 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 336 # . . call 337 e8/call write-int32-decimal/disp32 338 # . . discard args 339 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 340 # . write(out-segment, ":\n") 341 # . . push args 342 68/push ":\n"/imm32 343 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 344 # . . call 345 e8/call write/disp32 346 # . . discard args 347 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 348 # emit-string-literal-data(out-segment, string-literal) 349 # . . push args 350 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 351 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 352 # . . call 353 e8/call emit-string-literal-data/disp32 354 # . . discard args 355 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 356 # write(out-segment, "\n") 357 # . . push args 358 68/push Newline/imm32 359 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 360 # . . call 361 e8/call write/disp32 362 # . . discard args 363 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 364 # print(out, "_string#{Next-string-literal}") 365 # . write-buffered(out, "_string") 366 # . . push args 367 68/push "_string"/imm32 368 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 369 # . . call 370 e8/call write-buffered/disp32 371 # . . discard args 372 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 373 # . write-int32-decimal(int32-stream, *Next-string-literal) 374 # . . push args 375 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal 376 51/push-ecx 377 # . . call 378 e8/call write-int32-decimal/disp32 379 # . . discard args 380 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 381 # . write-stream-data(out, int32-stream) 382 # . . push args 383 51/push-ecx 384 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 385 # . . call 386 e8/call write-stream-data/disp32 387 # . . discard args 388 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 389 # emit-metadata(out, string-literal) 390 # . . push args 391 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 392 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) 393 # . . call 394 e8/call emit-metadata/disp32 395 # . . discard args 396 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 397 # ++ *Next-string-literal 398 ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # increment *Num-test-failures 399 $process-string-literal:end: 400 # . reclaim locals 401 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x16/imm32 # add to esp 402 # . restore registers 403 59/pop-to-ecx 404 # . epilogue 405 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 406 5d/pop-to-ebp 407 c3/return 408 409 test-subx-dquotes-is-idempotent-by-default: 410 # . prologue 411 55/push-ebp 412 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 413 # setup 414 # . clear-stream(_test-input-stream) 415 # . . push args 416 68/push _test-input-stream/imm32 417 # . . call 418 e8/call clear-stream/disp32 419 # . . discard args 420 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 421 # . clear-stream($_test-input-buffered-file->buffer) 422 # . . push args 423 68/push $_test-input-buffered-file->buffer/imm32 424 # . . call 425 e8/call clear-stream/disp32 426 # . . discard args 427 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 428 # . clear-stream(_test-output-stream) 429 # . . push args 430 68/push _test-output-stream/imm32 431 # . . call 432 e8/call clear-stream/disp32 433 # . . discard args 434 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 435 # . clear-stream($_test-output-buffered-file->buffer) 436 # . . push args 437 68/push $_test-output-buffered-file->buffer/imm32 438 # . . call 439 e8/call clear-stream/disp32 440 # . . discard args 441 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 442 # initialize input (meta comments in parens) 443 # # comment 1 444 # # comment 2 indented 445 # == code 0x1 (new segment) 446 # # comment 3 inside a segment 447 # 1 448 # (empty line) 449 # 2 3 # comment 4 inline with other contents 450 # == data 0x2 (new segment) 451 # 4 5/imm32 452 # . write(_test-input-stream, "# comment 1\n") 453 # . . push args 454 68/push "# comment 1\n"/imm32 455 68/push _test-input-stream/imm32 456 # . . call 457 e8/call write/disp32 458 # . . discard args 459 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 460 # . write(_test-input-stream, " # comment 2 indented\n") 461 # . . push args 462 68/push " # comment 2 indented\n"/imm32 463 68/push _test-input-stream/imm32 464 # . . call 465 e8/call write/disp32 466 # . . discard args 467 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 468 # . write(_test-input-stream, "== code 0x1\n") 469 # . . push args 470 68/push "== code 0x1\n"/imm32 471 68/push _test-input-stream/imm32 472 # . . call 473 e8/call write/disp32 474 # . . discard args 475 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 476 # . write(_test-input-stream, "# comment 3 inside a segment\n") 477 # . . push args 478 68/push "# comment 3 inside a segment\n"/imm32 479 68/push _test-input-stream/imm32 480 # . . call 481 e8/call write/disp32 482 # . . discard args 483 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 484 # . write(_test-input-stream, "1\n") 485 # . . push args 486 68/push "1\n"/imm32 487 68/push _test-input-stream/imm32 488 # . . call 489 e8/call write/disp32 490 # . . discard args 491 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 492 # . write(_test-input-stream, "\n") # empty line 493 # . . push args 494 68/push Newline/imm32 495 68/push _test-input-stream/imm32 496 # . . call 497 e8/call write/disp32 498 # . . discard args 499 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 500 # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") 501 # . . push args 502 68/push "2 3 # comment 4 inline with other contents\n"/imm32 503 68/push _test-input-stream/imm32 504 # . . call 505 e8/call write/disp32 506 # . . discard args 507 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 508 # . write(_test-input-stream, "== data 0x2\n") 509 # . . push args 510 68/push "== data 0x2\n"/imm32 511 68/push _test-input-stream/imm32 512 # . . call 513 e8/call write/disp32 514 # . . discard args 515 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 516 # . write(_test-input-stream, "4 5/imm32\n") 517 # . . push args 518 68/push "4 5/imm32\n"/imm32 519 68/push _test-input-stream/imm32 520 # . . call 521 e8/call write/disp32 522 # . . discard args 523 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 524 # subx-dquotes(_test-input-buffered-file, _test-output-buffered-file) 525 # . . push args 526 68/push _test-output-buffered-file/imm32 527 68/push _test-input-buffered-file/imm32 528 # . . call 529 e8/call subx-dquotes/disp32 530 # . . discard args 531 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 532 # . flush(_test-output-buffered-file) 533 # . . push args 534 68/push _test-output-buffered-file/imm32 535 # . . call 536 e8/call flush/disp32 537 # . . discard args 538 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 539 # check output 540 # (comment dropped for now) 541 # (comment dropped for now) 542 # == code 0x1 543 # (comment dropped for now) 544 # 1 545 # (comment dropped for now) 546 # 2 3 547 # == data 0x2 548 # 4 5/imm32 549 # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. 550 +-- 26 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 576 # . check-next-stream-line-equal(_test-output-stream, "", msg) 577 # . . push args 578 68/push "F - test-subx-dquotes-is-idempotent-by-default/0"/imm32 579 68/push ""/imm32 580 68/push _test-output-stream/imm32 581 # . . call 582 e8/call check-next-stream-line-equal/disp32 583 # . . discard args 584 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 585 # . check-next-stream-line-equal(_test-output-stream, "", msg) 586 # . . push args 587 68/push "F - test-subx-dquotes-is-idempotent-by-default/1"/imm32 588 68/push ""/imm32 589 68/push _test-output-stream/imm32 590 # . . call 591 e8/call check-next-stream-line-equal/disp32 592 # . . discard args 593 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 594 # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) 595 # . . push args 596 68/push "F - test-subx-dquotes-is-idempotent-by-default/2"/imm32 597 68/push "== code 0x1 "/imm32 598 68/push _test-output-stream/imm32 599 # . . call 600 e8/call check-next-stream-line-equal/disp32 601 # . . discard args 602 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 603 # . check-next-stream-line-equal(_test-output-stream, "", msg) 604 # . . push args 605 68/push "F - test-subx-dquotes-is-idempotent-by-default/3"/imm32 606 68/push ""/imm32 607 68/push _test-output-stream/imm32 608 # . . call 609 e8/call check-next-stream-line-equal/disp32 610 # . . discard args 611 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 612 # . check-next-stream-line-equal(_test-output-stream, "1 ", msg) 613 # . . push args 614 68/push "F - test-subx-dquotes-is-idempotent-by-default/4"/imm32 615 68/push "1 "/imm32 616 68/push _test-output-stream/imm32 617 # . . call 618 e8/call check-next-stream-line-equal/disp32 619 # . . discard args 620 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 621 # . check-next-stream-line-equal(_test-output-stream, "", msg) 622 # . . push args 623 68/push "F - test-subx-dquotes-is-idempotent-by-default/5"/imm32 624 68/push ""/imm32 625 68/push _test-output-stream/imm32 626 # . . call 627 e8/call check-next-stream-line-equal/disp32 628 # . . discard args 629 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 630 # . check-next-stream-line-equal(_test-output-stream, "2 3 ", msg) 631 # . . push args 632 68/push "F - test-subx-dquotes-is-idempotent-by-default/6"/imm32 633 68/push "2 3 "/imm32 634 68/push _test-output-stream/imm32 635 # . . call 636 e8/call check-next-stream-line-equal/disp32 637 # . . discard args 638 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 639 # . check-next-stream-line-equal(_test-output-stream, "== data 0x2 ", msg) 640 # . . push args 641 68/push "F - test-subx-dquotes-is-idempotent-by-default/7"/imm32 642 68/push "== data 0x2 "/imm32 643 68/push _test-output-stream/imm32 644 # . . call 645 e8/call check-next-stream-line-equal/disp32 646 # . . discard args 647 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 648 # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32 ", msg) 649 # . . push args 650 68/push "F - test-subx-dquotes-is-idempotent-by-default/8"/imm32 651 68/push "4 5/imm32 "/imm32 652 68/push _test-output-stream/imm32 653 # . . call 654 e8/call check-next-stream-line-equal/disp32 655 # . . discard args 656 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 657 # . epilogue 658 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 659 5d/pop-to-ebp 660 c3/return 661 662 test-subx-dquotes-processes-string-literals: 663 # . prologue 664 55/push-ebp 665 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 666 # setup 667 # . clear-stream(_test-input-stream) 668 # . . push args 669 68/push _test-input-stream/imm32 670 # . . call 671 e8/call clear-stream/disp32 672 # . . discard args 673 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 674 # . clear-stream($_test-input-buffered-file->buffer) 675 # . . push args 676 68/push $_test-input-buffered-file->buffer/imm32 677 # . . call 678 e8/call clear-stream/disp32 679 # . . discard args 680 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 681 # . clear-stream(_test-output-stream) 682 # . . push args 683 68/push _test-output-stream/imm32 684 # . . call 685 e8/call clear-stream/disp32 686 # . . discard args 687 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 688 # . clear-stream($_test-output-buffered-file->buffer) 689 # . . push args 690 68/push $_test-output-buffered-file->buffer/imm32 691 # . . call 692 e8/call clear-stream/disp32 693 # . . discard args 694 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 695 # initialize input (meta comments in parens) 696 # == code (new segment) 697 # 1 "a"/x 698 # 2 "bc"/y 699 68/push "== code 0x1\n"/imm32 700 68/push _test-input-stream/imm32 701 # . . call 702 e8/call write/disp32 703 # . . discard args 704 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 705 # . write(_test-input-stream, "1 \"a\"/x\n") 706 # . . push args 707 68/push "1 \"a\"/x\n"/imm32 708 68/push _test-input-stream/imm32 709 # . . call 710 e8/call write/disp32 711 # . . discard args 712 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 713 # . write(_test-input-stream, "2 \"bc\"/y\n") 714 # . . push args 715 68/push "2 \"bc\"/y\n"/imm32 716 68/push _test-input-stream/imm32 717 # . . call 718 e8/call write/disp32 719 # . . discard args 720 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 721 # subx-dquotes(_test-input-buffered-file, _test-output-buffered-file) 722 # . . push args 723 68/push _test-output-buffered-file/imm32 724 68/push _test-input-buffered-file/imm32 725 # . . call 726 e8/call subx-dquotes/disp32 727 # . . discard args 728 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 729 # . flush(_test-output-buffered-file) 730 # . . push args 731 68/push _test-output-buffered-file/imm32 732 # . . call 733 e8/call flush/disp32 734 # . . discard args 735 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 736 # check output 737 # == code 0x1 738 # 1 _string1/x 739 # 2 _string2/y 740 # == data 741 # _string1: 742 # 1/imm32 61/a 743 # _string2: 744 # 2/imm32 62/b 63/c 745 # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. 746 # 747 # Open question: how to make this check more robust. 748 # We don't actually care what the auto-generated string variables are 749 # called. We just want to make sure instructions using string literals 750 # switch to a string variable with the right value. 751 # (Modifying string literals completely off the radar for now.) 752 +-- 33 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 785 # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) 786 # . . push args 787 68/push "F - test-subx-dquotes-processes-string-literals/0"/imm32 788 68/push "== code 0x1 "/imm32 789 68/push _test-output-stream/imm32 790 # . . call 791 e8/call check-next-stream-line-equal/disp32 792 # . . discard args 793 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 794 # . check-next-stream-line-equal(_test-output-stream, "1 _string1/x ", msg) 795 # . . push args 796 68/push "F - test-subx-dquotes-processes-string-literals/1"/imm32 797 68/push "1 _string1/x "/imm32 798 68/push _test-output-stream/imm32 799 # . . call 800 e8/call check-next-stream-line-equal/disp32 801 # . . discard args 802 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 803 # . check-next-stream-line-equal(_test-output-stream, "2 _string2/y ", msg) 804 # . . push args 805 68/push "F - test-subx-dquotes-processes-string-literals/2"/imm32 806 68/push "2 _string2/y "/imm32 807 68/push _test-output-stream/imm32 808 # . . call 809 e8/call check-next-stream-line-equal/disp32 810 # . . discard args 811 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 812 # . check-next-stream-line-equal(_test-output-stream, "== data", msg) 813 # . . push args 814 68/push "F - test-subx-dquotes-processes-string-literals/3"/imm32 815 68/push "== data"/imm32 816 68/push _test-output-stream/imm32 817 # . . call 818 e8/call check-next-stream-line-equal/disp32 819 # . . discard args 820 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 821 # . check-next-stream-line-equal(_test-output-stream, "_string1: ", msg) 822 # . . push args 823 68/push "F - test-subx-dquotes-processes-string-literals/4"/imm32 824 68/push "_string1:"/imm32 825 68/push _test-output-stream/imm32 826 # . . call 827 e8/call check-next-stream-line-equal/disp32 828 # . . discard args 829 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 830 # . check-next-stream-line-equal(_test-output-stream, "1/imm32 61/a ", msg) 831 # . . push args 832 68/push "F - test-subx-dquotes-processes-string-literals/5"/imm32 833 68/push "0x00000001/imm32 61/a "/imm32 834 68/push _test-output-stream/imm32 835 # . . call 836 e8/call check-next-stream-line-equal/disp32 837 # . . discard args 838 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 839 # . check-next-stream-line-equal(_test-output-stream, "_string2: ", msg) 840 # . . push args 841 68/push "F - test-subx-dquotes-processes-string-literals/6"/imm32 842 68/push "_string2:"/imm32 843 68/push _test-output-stream/imm32 844 # . . call 845 e8/call check-next-stream-line-equal/disp32 846 # . . discard args 847 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 848 # . check-next-stream-line-equal(_test-output-stream, "2/imm32 62/b 63/c ", msg) 849 # . . push args 850 68/push "F - test-subx-dquotes-processes-string-literals/7"/imm32 851 68/push "0x00000002/imm32 62/b 63/c "/imm32 852 68/push _test-output-stream/imm32 853 # . . call 854 e8/call check-next-stream-line-equal/disp32 855 # . . discard args 856 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 857 # . epilogue 858 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 859 5d/pop-to-ebp 860 c3/return 861 862 # generate the data segment contents byte by byte for a given slice 863 emit-string-literal-data: # out: (addr stream byte), word: (addr slice) 864 # pseudocode 865 # len = string-length-at-start-of-slice(word->start, word->end) 866 # print(out, "#{len}/imm32 ") 867 # curr = word->start 868 # ++curr # skip '"' 869 # idx = 0 870 # while true 871 # if (curr >= word->end) break 872 # c = *curr 873 # if (c == '"') break 874 # if (c == '\') { 875 # ++curr 876 # c = *curr 877 # if (c == 'n') 878 # c = newline 879 # } 880 # append-byte-hex(out, c) 881 # if c is alphanumeric: 882 # write(out, "/") 883 # append-byte(out, c) 884 # write(out, " ") 885 # ++curr 886 # ++idx 887 # if idx >= 0x40 888 # idx = 0 889 # write(out, "\n") 890 # 891 # . prologue 892 55/push-ebp 893 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 894 # . save registers 895 50/push-eax 896 51/push-ecx 897 52/push-edx 898 53/push-ebx 899 56/push-esi 900 # esi = word 901 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi 902 # var idx/ebx: int = 0 903 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 904 # var curr/edx: (addr byte) = word->start 905 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 906 # var max/esi: (addr byte) = word->end 907 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi 908 $emit-string-literal-data:emit-length: 909 # var len/eax: int = string-length-at-start-of-slice(word->start, word->end) 910 # . . push args 911 56/push-esi 912 52/push-edx 913 # . . call 914 e8/call string-length-at-start-of-slice/disp32 915 # . . discard args 916 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 917 # print(out, "#{len}/imm32 ") 918 # . write-int32-hex(out, len) 919 # . . push args 920 50/push-eax 921 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 922 # . . call 923 e8/call write-int32-hex/disp32 924 # . . discard args 925 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 926 # . write(out, "/imm32 ") 927 # . . push args 928 68/push "/imm32 "/imm32 929 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 930 # . . call 931 e8/call write/disp32 932 # . . discard args 933 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 934 $emit-string-literal-data:loop-init: 935 # ++curr # skip initial '"' 936 42/increment-edx 937 # var c/ecx: byte = 0 938 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx 939 $emit-string-literal-data:loop: 940 # if (curr >= max) break 941 39/compare 3/mod/direct 2/rm32/edx . . . 6/r32/esi . . # compare edx with esi 942 0f 83/jump-if-addr>= $emit-string-literal-data:end/disp32 943 # CL = *curr 944 8a/copy-byte 0/mod/indirect 2/rm32/edx . . . 1/r32/CL . . # copy byte at *edx to CL 945 # if (c == '"') break 946 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x22/imm32/dquote # compare ecx 947 0f 84/jump-if-= $emit-string-literal-data:end/disp32 948 # if (c != '\') goto emit 949 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x5c/imm32/backslash # compare ecx 950 75/jump-if-!= $emit-string-literal-data:emit/disp8 951 # ++curr 952 42/increment-edx 953 # if (curr >= max) break 954 39/compare 3/mod/direct 2/rm32/edx . . . 6/r32/esi . . # compare edx with esi 955 0f 83/jump-if-addr>= $emit-string-literal-data:end/disp32 956 # c = *curr 957 8a/copy-byte 0/mod/indirect 2/rm32/edx . . . 1/r32/CL . . # copy byte at *edx to CL 958 # if (c == 'n') c = newline 959 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x6e/imm32/n # compare ecx 960 75/jump-if-!= $emit-string-literal-data:emit/disp8 961 b9/copy-to-ecx 0x0a/imm32/newline 962 $emit-string-literal-data:emit: 963 # append-byte-hex(out, CL) 964 # . . push args 965 51/push-ecx 966 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 967 # . . call 968 e8/call append-byte-hex/disp32 969 # . . discard args 970 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 971 # if (alphanumeric?(*curr)) print(out, "/#{*curr}") 972 # . var eax: boolean = alphanumeric?(CL) 973 # . . push args 974 51/push-ecx 975 # . . call 976 e8/call alphanumeric?/disp32 977 # . . discard args 978 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 979 # . if (eax == false) goto char-done 980 3d/compare-eax-and 0/imm32/false 981 74/jump-if-= $emit-string-literal-data:char-done/disp8 982 # . write(out, "/") 983 # . . push args 984 68/push Slash/imm32 985 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 986 # . . call 987 e8/call write/disp32 988 # . . discard args 989 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 990 # . append-byte(out, *curr) 991 # . . push args 992 51/push-ecx 993 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 994 # . . call 995 e8/call append-byte/disp32 996 # . . discard args 997 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 998 $emit-string-literal-data:char-done: 999 # write(out, " ") 1000 # . . push args 1001 68/push Space/imm32 1002 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1003 # . . call 1004 e8/call write/disp32 1005 # . . discard args 1006 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1007 # ++curr 1008 42/increment-edx 1009 # ++ idx 1010 43/increment-ebx 1011 # if (idx < 0x40) continue 1012 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x40/imm32 # compare ebx 1013 7c/jump-if-< $emit-string-literal-data:next-char/disp8 1014 # idx = 0 1015 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 1016 # write(out, "\n") 1017 # . . push args 1018 68/push Newline/imm32 1019 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1020 # . . call 1021 e8/call write/disp32 1022 # . . discard args 1023 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1024 $emit-string-literal-data:next-char: 1025 e9/jump $emit-string-literal-data:loop/disp32 1026 $emit-string-literal-data:end: 1027 # . restore registers 1028 5e/pop-to-esi 1029 5b/pop-to-ebx 1030 5a/pop-to-edx 1031 59/pop-to-ecx 1032 58/pop-to-eax 1033 # . epilogue 1034 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1035 5d/pop-to-ebp 1036 c3/return 1037 1038 alphanumeric?: # c: int -> eax: boolean 1039 # . prologue 1040 55/push-ebp 1041 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1042 # eax = c 1043 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax 1044 # if (c < '0') return false 1045 3d/compare-eax-with 0x30/imm32/0 1046 7c/jump-if-< $alphanumeric?:false/disp8 1047 # if (c <= '9') return true 1048 3d/compare-eax-with 0x39/imm32/9 1049 7e/jump-if-<= $alphanumeric?:true/disp8 1050 # if (c < 'A') return false 1051 3d/compare-eax-with 0x41/imm32/A 1052 7c/jump-if-< $alphanumeric?:false/disp8 1053 # if (c <= 'Z') return true 1054 3d/compare-eax-with 0x5a/imm32/Z 1055 7e/jump-if-<= $alphanumeric?:true/disp8 1056 # if (c < 'a') return false 1057 3d/compare-eax-with 0x61/imm32/a 1058 7c/jump-if-< $alphanumeric?:false/disp8 1059 # if (c <= 'z') return true 1060 3d/compare-eax-with 0x7a/imm32/z 1061 7e/jump-if-<= $alphanumeric?:true/disp8 1062 # return false 1063 $alphanumeric?:false: 1064 b8/copy-to-eax 0/imm32/false 1065 eb/jump $alphanumeric?:end/disp8 1066 $alphanumeric?:true: 1067 b8/copy-to-eax 1/imm32/true 1068 $alphanumeric?:end: 1069 # . epilogue 1070 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1071 5d/pop-to-ebp 1072 c3/return 1073 1074 test-emit-string-literal-data: 1075 # . prologue 1076 55/push-ebp 1077 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1078 # setup 1079 # . clear-stream(_test-output-stream) 1080 # . . push args 1081 68/push _test-output-stream/imm32 1082 # . . call 1083 e8/call clear-stream/disp32 1084 # . . discard args 1085 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1086 # var slice/ecx = '"abc"/d' 1087 68/push _test-slice-abc-limit/imm32 1088 68/push _test-slice-abc/imm32 1089 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1090 # emit-string-literal-data(_test-output-stream, slice) 1091 # . . push args 1092 51/push-ecx 1093 68/push _test-output-stream/imm32 1094 # . . call 1095 e8/call emit-string-literal-data/disp32 1096 # . . discard args 1097 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1098 +-- 26 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 1124 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 62/b 63/c ", msg) 1125 # . . push args 1126 68/push "F - test-emit-string-literal-data"/imm32 1127 68/push "0x00000003/imm32 61/a 62/b 63/c "/imm32 1128 68/push _test-output-stream/imm32 1129 # . . call 1130 e8/call check-stream-equal/disp32 1131 # . . discard args 1132 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1133 # . epilogue 1134 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1135 5d/pop-to-ebp 1136 c3/return 1137 1138 test-emit-string-literal-data-empty: 1139 # . prologue 1140 55/push-ebp 1141 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1142 # setup 1143 # . clear-stream(_test-output-stream) 1144 # . . push args 1145 68/push _test-output-stream/imm32 1146 # . . call 1147 e8/call clear-stream/disp32 1148 # . . discard args 1149 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1150 # var slice/ecx = '""' 1151 68/push 0/imm32/end 1152 68/push 0/imm32/start 1153 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1154 # emit-string-literal-data(_test-output-stream, slice) 1155 # . . push args 1156 51/push-ecx 1157 68/push _test-output-stream/imm32 1158 # . . call 1159 e8/call emit-string-literal-data/disp32 1160 # . . discard args 1161 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1162 +-- 26 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 1188 # . check-stream-equal(_test-output-stream, "0/imm32 ", msg) 1189 # . . push args 1190 68/push "F - test-emit-string-literal-data-empty"/imm32 1191 68/push "0x00000000/imm32 "/imm32 1192 68/push _test-output-stream/imm32 1193 # . . call 1194 e8/call check-stream-equal/disp32 1195 # . . discard args 1196 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1197 # . epilogue 1198 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1199 5d/pop-to-ebp 1200 c3/return 1201 1202 # just to keep things simple 1203 test-emit-string-literal-data-no-metadata-for-non-alphanumerics: 1204 # . prologue 1205 55/push-ebp 1206 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1207 # setup 1208 # . clear-stream(_test-output-stream) 1209 # . . push args 1210 68/push _test-output-stream/imm32 1211 # . . call 1212 e8/call clear-stream/disp32 1213 # . . discard args 1214 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1215 # var slice/ecx = '"a b"' 1216 68/push _test-slice-a-space-b-limit/imm32 1217 68/push _test-slice-a-space-b/imm32 1218 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1219 # emit-string-literal-data(_test-output-stream, slice) 1220 # . . push args 1221 51/push-ecx 1222 68/push _test-output-stream/imm32 1223 # . . call 1224 e8/call emit-string-literal-data/disp32 1225 # . . discard args 1226 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1227 +-- 26 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 1253 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints 1254 # . . push args 1255 68/push "F - test-emit-string-literal-data-no-metadata-for-non-alphanumerics"/imm32 1256 68/push "0x00000003/imm32 61/a 20 62/b "/imm32 1257 68/push _test-output-stream/imm32 1258 # . . call 1259 e8/call check-stream-equal/disp32 1260 # . . discard args 1261 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1262 # . epilogue 1263 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1264 5d/pop-to-ebp 1265 c3/return 1266 1267 test-emit-string-literal-data-handles-escape-sequences: 1268 # . prologue 1269 55/push-ebp 1270 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1271 # setup 1272 # . clear-stream(_test-output-stream) 1273 # . . push args 1274 68/push _test-output-stream/imm32 1275 # . . call 1276 e8/call clear-stream/disp32 1277 # . . discard args 1278 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1279 # var slice/ecx = '"a\"b"' 1280 68/push _test-slice-a-dquote-b-limit/imm32 1281 68/push _test-slice-a-dquote-b/imm32 1282 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1283 # emit-string-literal-data(_test-output-stream, slice) 1284 # . . push args 1285 51/push-ecx 1286 68/push _test-output-stream/imm32 1287 # . . call 1288 e8/call emit-string-literal-data/disp32 1289 # . . discard args 1290 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1291 +-- 26 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 1317 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 22 62/b ", msg) 1318 # . . push args 1319 68/push "F - test-emit-string-literal-data-handles-escape-sequences"/imm32 1320 68/push "0x00000003/imm32 61/a 22 62/b "/imm32 1321 68/push _test-output-stream/imm32 1322 # . . call 1323 e8/call check-stream-equal/disp32 1324 # . . discard args 1325 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1326 # . epilogue 1327 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1328 5d/pop-to-ebp 1329 c3/return 1330 1331 test-emit-string-literal-data-handles-newline-escape: 1332 # . prologue 1333 55/push-ebp 1334 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1335 # setup 1336 # . clear-stream(_test-output-stream) 1337 # . . push args 1338 68/push _test-output-stream/imm32 1339 # . . call 1340 e8/call clear-stream/disp32 1341 # . . discard args 1342 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1343 # var slice/ecx = '"a\nb"' 1344 68/push _test-slice-a-newline-b-limit/imm32 1345 68/push _test-slice-a-newline-b/imm32 1346 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1347 # emit-string-literal-data(_test-output-stream, slice) 1348 # . . push args 1349 51/push-ecx 1350 68/push _test-output-stream/imm32 1351 # . . call 1352 e8/call emit-string-literal-data/disp32 1353 # . . discard args 1354 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1355 +-- 26 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 1381 # . check-stream-equal(_test-output-stream, "3/imm32 61/a 0a 62/b ", msg) 1382 # . . push args 1383 68/push "F - test-emit-string-literal-data-handles-newline-escape"/imm32 1384 68/push "0x00000003/imm32 61/a 0a 62/b "/imm32 1385 68/push _test-output-stream/imm32 1386 # . . call 1387 e8/call check-stream-equal/disp32 1388 # . . discard args 1389 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1390 # . epilogue 1391 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1392 5d/pop-to-ebp 1393 c3/return 1394 1395 # emit everything from a word except the initial datum 1396 emit-metadata: # out: (addr buffered-file), word: (addr slice) 1397 # pseudocode 1398 # var slice: slice = {0, word->end} 1399 # curr = word->start 1400 # if *curr == '"' 1401 # curr = skip-string-in-slice(curr, word->end) 1402 # else 1403 # while true 1404 # if curr == word->end 1405 # return 1406 # if *curr == '/' 1407 # break 1408 # ++curr 1409 # slice->start = curr 1410 # write-slice-buffered(out, slice) 1411 # 1412 # . prologue 1413 55/push-ebp 1414 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1415 # . save registers 1416 50/push-eax 1417 51/push-ecx 1418 52/push-edx 1419 53/push-ebx 1420 56/push-esi 1421 # esi = word 1422 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi 1423 # var curr/ecx: (addr byte) = word->start 1424 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 1425 # var end/edx: (addr byte) = word->end 1426 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 4/disp8 . # copy *(esi+4) to edx 1427 # var slice/ebx: slice = {0, end} 1428 52/push-edx 1429 68/push 0/imm32 1430 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx 1431 # eax = 0 1432 b8/copy-to-eax 0/imm32 1433 $emit-metadata:check-for-string-literal: 1434 # - if (*curr == '"') curr = skip-string-in-slice(curr, end) 1435 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 1436 3d/compare-eax-and 0x22/imm32/dquote 1437 75/jump-if-!= $emit-metadata:skip-datum-loop/disp8 1438 $emit-metadata:skip-string-literal: 1439 # . eax = skip-string-in-slice(curr, end) 1440 # . . push args 1441 52/push-edx 1442 51/push-ecx 1443 # . . call 1444 e8/call skip-string-in-slice/disp32 1445 # . . discard args 1446 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1447 # . curr = eax 1448 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx 1449 eb/jump $emit-metadata:emit/disp8 1450 $emit-metadata:skip-datum-loop: 1451 # - otherwise scan for '/' 1452 # if (curr == end) return 1453 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx and edx 1454 74/jump-if-= $emit-metadata:end/disp8 1455 # if (*curr == '/') break 1456 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 1457 3d/compare-eax-and 0x2f/imm32/slash 1458 74/jump-if-= $emit-metadata:emit/disp8 1459 # ++curr 1460 41/increment-ecx 1461 eb/jump $emit-metadata:skip-datum-loop/disp8 1462 $emit-metadata:emit: 1463 # slice->start = ecx 1464 89/copy 0/mod/indirect 3/rm32/ebx . . . 1/r32/ecx . . # copy ecx to *ebx 1465 # write-slice-buffered(out, slice) 1466 # . . push args 1467 53/push-ebx 1468 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 1469 # . . call 1470 e8/call write-slice-buffered/disp32 1471 # . . discard args 1472 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . 8/imm32 . # add to esp 1473 $emit-metadata:end: 1474 # . reclaim locals 1475 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . 8/imm32 . # add to esp 1476 # . restore registers 1477 5e/pop-to-esi 1478 5b/pop-to-ebx 1479 5a/pop-to-edx 1480 59/pop-to-ecx 1481 58/pop-to-eax 1482 # . epilogue 1483 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1484 5d/pop-to-ebp 1485 c3/return 1486 1487 test-emit-metadata: 1488 # . prologue 1489 55/push-ebp 1490 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1491 # setup 1492 # . clear-stream(_test-output-stream) 1493 # . . push args 1494 68/push _test-output-stream/imm32 1495 # . . call 1496 e8/call clear-stream/disp32 1497 # . . discard args 1498 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1499 # . clear-stream($_test-output-buffered-file->buffer) 1500 # . . push args 1501 68/push $_test-output-buffered-file->buffer/imm32 1502 # . . call 1503 e8/call clear-stream/disp32 1504 # . . discard args 1505 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1506 # (eax..ecx) = "abc/def" 1507 b8/copy-to-eax "abc/def"/imm32 1508 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1509 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1510 05/add-to-eax 4/imm32 1511 # var slice/ecx = {eax, ecx} 1512 51/push-ecx 1513 50/push-eax 1514 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1515 # emit-metadata(_test-output-buffered-file, slice) 1516 # . . push args 1517 51/push-ecx 1518 68/push _test-output-buffered-file/imm32 1519 # . . call 1520 e8/call emit-metadata/disp32 1521 # . . discard args 1522 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1523 # flush(_test-output-buffered-file) 1524 # . . push args 1525 68/push _test-output-buffered-file/imm32 1526 # . . call 1527 e8/call flush/disp32 1528 # . . discard args 1529 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1530 # check-stream-equal(_test-output-stream, "/def", msg) # important that there's no leading space 1531 # . . push args 1532 68/push "F - test-emit-metadata"/imm32 1533 68/push "/def"/imm32 1534 68/push _test-output-stream/imm32 1535 # . . call 1536 e8/call check-stream-equal/disp32 1537 # . . discard args 1538 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1539 # . epilogue 1540 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1541 5d/pop-to-ebp 1542 c3/return 1543 1544 test-emit-metadata-none: 1545 # . prologue 1546 55/push-ebp 1547 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1548 # setup 1549 # . clear-stream(_test-output-stream) 1550 # . . push args 1551 68/push _test-output-stream/imm32 1552 # . . call 1553 e8/call clear-stream/disp32 1554 # . . discard args 1555 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1556 # . clear-stream($_test-output-buffered-file->buffer) 1557 # . . push args 1558 68/push $_test-output-buffered-file->buffer/imm32 1559 # . . call 1560 e8/call clear-stream/disp32 1561 # . . discard args 1562 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1563 # (eax..ecx) = "abc" 1564 b8/copy-to-eax "abc"/imm32 1565 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1566 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1567 05/add-to-eax 4/imm32 1568 # var slice/ecx = {eax, ecx} 1569 51/push-ecx 1570 50/push-eax 1571 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1572 # emit-metadata(_test-output-buffered-file, slice) 1573 # . . push args 1574 51/push-ecx 1575 68/push _test-output-buffered-file/imm32 1576 # . . call 1577 e8/call emit-metadata/disp32 1578 # . . discard args 1579 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1580 # flush(_test-output-buffered-file) 1581 # . . push args 1582 68/push _test-output-buffered-file/imm32 1583 # . . call 1584 e8/call flush/disp32 1585 # . . discard args 1586 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1587 # check-stream-equal(_test-output-stream, "", msg) 1588 # . . push args 1589 68/push "F - test-emit-metadata-none"/imm32 1590 68/push ""/imm32 1591 68/push _test-output-stream/imm32 1592 # . . call 1593 e8/call check-stream-equal/disp32 1594 # . . discard args 1595 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1596 # . epilogue 1597 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1598 5d/pop-to-ebp 1599 c3/return 1600 1601 test-emit-metadata-multiple: 1602 # . prologue 1603 55/push-ebp 1604 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1605 # setup 1606 # . clear-stream(_test-output-stream) 1607 # . . push args 1608 68/push _test-output-stream/imm32 1609 # . . call 1610 e8/call clear-stream/disp32 1611 # . . discard args 1612 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1613 # . clear-stream($_test-output-buffered-file->buffer) 1614 # . . push args 1615 68/push $_test-output-buffered-file->buffer/imm32 1616 # . . call 1617 e8/call clear-stream/disp32 1618 # . . discard args 1619 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1620 # (eax..ecx) = "abc/def/ghi" 1621 b8/copy-to-eax "abc/def/ghi"/imm32 1622 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1623 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1624 05/add-to-eax 4/imm32 1625 # var slice/ecx = {eax, ecx} 1626 51/push-ecx 1627 50/push-eax 1628 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1629 # emit-metadata(_test-output-buffered-file, slice) 1630 # . . push args 1631 51/push-ecx 1632 68/push _test-output-buffered-file/imm32 1633 # . . call 1634 e8/call emit-metadata/disp32 1635 # . . discard args 1636 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1637 # flush(_test-output-buffered-file) 1638 # . . push args 1639 68/push _test-output-buffered-file/imm32 1640 # . . call 1641 e8/call flush/disp32 1642 # . . discard args 1643 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1644 # check-stream-equal(_test-output-stream, "/def/ghi", msg) # important that there's no leading space 1645 # . . push args 1646 68/push "F - test-emit-metadata-multiple"/imm32 1647 68/push "/def/ghi"/imm32 1648 68/push _test-output-stream/imm32 1649 # . . call 1650 e8/call check-stream-equal/disp32 1651 # . . discard args 1652 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1653 # . epilogue 1654 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1655 5d/pop-to-ebp 1656 c3/return 1657 1658 test-emit-metadata-when-no-datum: 1659 # . prologue 1660 55/push-ebp 1661 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1662 # setup 1663 # . clear-stream(_test-output-stream) 1664 # . . push args 1665 68/push _test-output-stream/imm32 1666 # . . call 1667 e8/call clear-stream/disp32 1668 # . . discard args 1669 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1670 # . clear-stream($_test-output-buffered-file->buffer) 1671 # . . push args 1672 68/push $_test-output-buffered-file->buffer/imm32 1673 # . . call 1674 e8/call clear-stream/disp32 1675 # . . discard args 1676 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1677 # var slice/ecx = "/abc" 1678 b8/copy-to-eax "/abc"/imm32 1679 # . push end/ecx 1680 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1681 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1682 51/push-ecx 1683 # . push curr/eax 1684 05/add-to-eax 4/imm32 1685 50/push-eax 1686 # . save stack pointer 1687 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1688 # emit-metadata(_test-output-buffered-file, slice) 1689 # . . push args 1690 51/push-ecx 1691 68/push _test-output-buffered-file/imm32 1692 # . . call 1693 e8/call emit-metadata/disp32 1694 # . . discard args 1695 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1696 # flush(_test-output-buffered-file) 1697 # . . push args 1698 68/push _test-output-buffered-file/imm32 1699 # . . call 1700 e8/call flush/disp32 1701 # . . discard args 1702 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1703 # check-stream-equal(_test-output-stream, "/abc", msg) # nothing skipped 1704 # . . push args 1705 68/push "F - test-emit-metadata-when-no-datum"/imm32 1706 68/push "/abc"/imm32 1707 68/push _test-output-stream/imm32 1708 # . . call 1709 e8/call check-stream-equal/disp32 1710 # . . discard args 1711 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1712 # . epilogue 1713 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1714 5d/pop-to-ebp 1715 c3/return 1716 1717 test-emit-metadata-in-string-literal: 1718 # . prologue 1719 55/push-ebp 1720 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1721 # setup 1722 # . clear-stream(_test-output-stream) 1723 # . . push args 1724 68/push _test-output-stream/imm32 1725 # . . call 1726 e8/call clear-stream/disp32 1727 # . . discard args 1728 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1729 # . clear-stream($_test-output-buffered-file->buffer) 1730 # . . push args 1731 68/push $_test-output-buffered-file->buffer/imm32 1732 # . . call 1733 e8/call clear-stream/disp32 1734 # . . discard args 1735 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1736 # var slice/ecx = "\"abc/def\"/ghi" 1737 68/push _test-slice-literal-string-with-limit/imm32 1738 68/push _test-slice-literal-string/imm32/start 1739 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1740 # emit-metadata(_test-output-buffered-file, slice) 1741 # . . push args 1742 51/push-ecx 1743 68/push _test-output-buffered-file/imm32 1744 # . . call 1745 e8/call emit-metadata/disp32 1746 # . . discard args 1747 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1748 # flush(_test-output-buffered-file) 1749 # . . push args 1750 68/push _test-output-buffered-file/imm32 1751 # . . call 1752 e8/call flush/disp32 1753 # . . discard args 1754 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 1755 +-- 26 lines: #? # dump output ----------------------------------------------------------------------------------------------------------------------------------------- 1781 # check-stream-equal(_test-output-stream, "/ghi", msg) # important that there's no leading space 1782 # . . push args 1783 68/push "F - test-emit-metadata-in-string-literal"/imm32 1784 68/push "/ghi"/imm32 1785 68/push _test-output-stream/imm32 1786 # . . call 1787 e8/call check-stream-equal/disp32 1788 # . . discard args 1789 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1790 # . epilogue 1791 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1792 5d/pop-to-ebp 1793 c3/return 1794 1795 string-length-at-start-of-slice: # curr: (addr byte), end: (addr byte) -> length/eax 1796 # . prologue 1797 55/push-ebp 1798 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1799 # . save registers 1800 51/push-ecx 1801 52/push-edx 1802 53/push-ebx 1803 # ecx = curr 1804 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx 1805 # edx = end 1806 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx 1807 # var length/eax: int = 0 1808 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 1809 # var c/ebx: byte = 0 1810 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx 1811 # skip initial dquote 1812 41/increment-ecx 1813 $string-length-at-start-of-slice:loop: 1814 # if (curr >= end) return length 1815 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 1816 73/jump-if-addr>= $string-length-at-start-of-slice:end/disp8 1817 # c = *curr 1818 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL 1819 $string-length-at-start-of-slice:dquote: 1820 # if (c == '"') break 1821 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x22/imm32/dquote # compare ebx 1822 74/jump-if-= $string-length-at-start-of-slice:end/disp8 1823 $string-length-at-start-of-slice:check-for-escape: 1824 # if (c == '\') escape next char 1825 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x5c/imm32/backslash # compare ebx 1826 75/jump-if-!= $string-length-at-start-of-slice:continue/disp8 1827 $string-length-at-start-of-slice:escape: 1828 # increment curr but not result 1829 41/increment-ecx 1830 $string-length-at-start-of-slice:continue: 1831 # ++result 1832 40/increment-eax 1833 # ++curr 1834 41/increment-ecx 1835 eb/jump $string-length-at-start-of-slice:loop/disp8 1836 $string-length-at-start-of-slice:end: 1837 # . restore registers 1838 5b/pop-to-ebx 1839 5a/pop-to-edx 1840 59/pop-to-ecx 1841 # . epilogue 1842 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1843 5d/pop-to-ebp 1844 c3/return 1845 1846 test-string-length-at-start-of-slice: 1847 # . prologue 1848 55/push-ebp 1849 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1850 # setup: (eax..ecx) = "\"abc\" def" 1851 b8/copy-to-eax "\"abc\" def"/imm32 1852 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1853 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1854 05/add-to-eax 4/imm32 1855 # eax = string-length-at-start-of-slice(eax, ecx) 1856 # . . push args 1857 51/push-ecx 1858 50/push-eax 1859 # . . call 1860 e8/call string-length-at-start-of-slice/disp32 1861 # . . discard args 1862 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1863 # check-ints-equal(eax, 3, msg) 1864 # . . push args 1865 68/push "F - test-string-length-at-start-of-slice"/imm32 1866 68/push 3/imm32 1867 50/push-eax 1868 # . . call 1869 e8/call check-ints-equal/disp32 1870 # . . discard args 1871 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1872 # . epilogue 1873 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1874 5d/pop-to-ebp 1875 c3/return 1876 1877 test-string-length-at-start-of-slice-escaped: 1878 # . prologue 1879 55/push-ebp 1880 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 1881 # setup: (eax..ecx) = "\"ab\\c\" def" 1882 b8/copy-to-eax "\"ab\\c\" def"/imm32 1883 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 1884 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx 1885 05/add-to-eax 4/imm32 1886 # eax = string-length-at-start-of-slice(eax, ecx) 1887 # . . push args 1888 51/push-ecx 1889 50/push-eax 1890 # . . call 1891 e8/call string-length-at-start-of-slice/disp32 1892 # . . discard args 1893 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1894 # check-ints-equal(eax, 3, msg) 1895 # . . push args 1896 68/push "F - test-string-length-at-start-of-slice-escaped"/imm32 1897 68/push 3/imm32 1898 50/push-eax 1899 # . . call 1900 e8/call check-ints-equal/disp32 1901 # . . discard args 1902 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1903 # . epilogue 1904 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1905 5d/pop-to-ebp 1906 c3/return 1907 1908 == data 1909 1910 Next-string-literal: # tracks the next auto-generated variable name 1911 1/imm32 1912 1913 _test-slice-abc: 1914 22/dquote 61/a 62/b 63/c 22/dquote # "abc" 1915 2f/slash 64/d 1916 _test-slice-abc-limit: 1917 1918 _test-slice-a-space-b: 1919 22/dquote 61/a 20/space 62/b 22/dquote # "a b" 1920 _test-slice-a-space-b-limit: 1921 1922 _test-slice-a-dquote-b: 1923 22/dquote 61/a 5c/backslash 22/dquote 62/b 22/dquote # "a\"b" 1924 _test-slice-a-dquote-b-limit: 1925 1926 _test-slice-a-newline-b: 1927 22/dquote 61/a 5c/backslash 6e/n 62/b 22/dquote # "a\nb" 1928 _test-slice-a-newline-b-limit: 1929 1930 # "abc/def"/ghi 1931 _test-slice-literal-string: 1932 22/dquote 1933 61/a 62/b 63/c # abc 1934 2f/slash 64/d 65/e 66/f # /def 1935 22/dquote 1936 2f/slash 67/g 68/h 69/i # /ghi 1937 _test-slice-literal-string-with-limit: 1938 1939 # . . vim:nowrap:textwidth=0