summary refs log tree commit diff stats
path: root/lib/pure/math.nim
Commit message (Collapse)AuthorAgeFilesLines
* move since from inclrtl to std/private/since (#14188)hlaaftana2020-05-021-1/+1
| | | | * move since from inclrtl to std/private/since * move since import in system below for HCR
* Error -> Defect for defects (#13908)Jacek Sieka2020-04-281-1/+1
| | | | | | | | | | | | | | * Error -> Defect for defects The distinction between Error and Defect is subjective, context-dependent and somewhat arbitrary, so when looking at an exception, it's hard to guess what it is - this happens often when looking at a `raises` list _without_ opening the corresponding definition and digging through layers of inheritance. With the help of a little consistency in naming, it's at least possible to start disentangling the two error types and the standard lib can set a good example here.
* style fix: change 'JS' to 'js' to make it consistent (#13168)Miran2020-01-161-5/+5
|
* fixes #13032Araq2020-01-041-2/+2
|
* Fixes classify function to detect subnormal floating points (#12836)KeepCoolWithCoolidge2019-12-081-16/+20
| | | | | | | | * Fix classify to test for subnormality. * Minor fix. * Modified to maintain existing API. * Minor change. * Removed 32-bit case since float is always 64-bit.
* Fix for 16 bit platforms (#12760) [backend]PMunch2019-11-281-1/+3
| | | | | This fixes some tiny issues with using Nim on 16-bit platforms. Not entirely sure why the AVR chip I was compiling for with "cpu = avr" was detected as 16-bit, but that's probably another issue..
* added support for openArray's for `gcd` and `lcm` (#12621)Yanis Zafirópulos2019-11-071-1/+25
|
* fix several typos in documentation and comments (#12553)Nindaleth2019-10-301-1/+1
|
* Fix many broken links and prefer relative links within docs (#12463)Miran2019-10-241-1/+1
|\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Fix many broken links Note that contrary to what docgen.rst currently says, the ids have to match exactly or else most web browsers will not jump to the intended symbol. * Prefer relative links for Nim documentation This is more friendly to those browsing the documentation without a network connection. The nim-doc package in Debian allows this, for example. Also, the domain name being used was not consistent. It could have been either nim-lang.org or nim-lang.github.io, and those reading the stable docs could have found themselves suddenly reading the devel docs instead. * koch.rst: remove link to nonexistent section * manual.rst: remove unintended link cast[T](0) is interpreted as a link to id 0 with text T, so escape the opening parentheses to display the intended output. * asyncstreams: replace unintended link with emphasis * Fix word wrapping
| * Fix many broken linksJjp1372019-10-221-1/+1
| | | | | | | | | | | | Note that contrary to what docgen.rst currently says, the ids have to match exactly or else most web browsers will not jump to the intended symbol.
* | [backport] Documentation Math module (#12460)Juan Carlos2019-10-241-0/+2
|/
* [backport] run nimpretty on numbers stuffnarimiran2019-09-301-27/+33
|
* Fix the broken link in math.nim (#11653) [ci skip]Graeme Cross2019-07-041-1/+1
|
* [documentation] fix #4630, document unsupported functions for JSnarimiran2019-06-241-0/+8
|
* Add `cbrt()` bindings for the JS Target (#11528)Benjamin Summerton2019-06-181-0/+3
| | | | | | `Math.cbrt()` exists: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt The binding was missing for the JavaScript backend.
* Render deprecated pragmas (#8886)LemonBoy2019-06-031-13/+7
| | | | | | | | | * Render deprecated pragmas * fix the expected html * clean up the documentation regarding deprecations * fix typo * fix system.nim * fix random
* stdlib: more consistent formattingAraq2019-05-221-5/+5
|
* fix #10910, optimize squaring and cubing (#11291)Miran2019-05-211-16/+21
|
* code cleanup (#10874)Arne Döring2019-03-281-6/+4
|
* 32 bit fixes (#10608)Arne Döring2019-02-131-1/+1
|
* Genode fixes (#10491)Emery Hemingway2019-01-291-1/+1
| | | Readline pasthru, add linker to config, do not pass -lm to linker.
* documentation: remove author field [ci skip]narimiran2019-01-171-3/+0
|
* better docs: mathnarimiran2019-01-161-97/+420
|
* Resolve things raised in https://github.com/nim-lang/Nim/issues/10081 ? (#10084)c-blake2018-12-311-0/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Resolve things raised in https://github.com/nim-lang/Nim/issues/10081 ? CDF is a standard ident in all things related to random numbers/sampling, and full words "cumulativeDistributionFunction" would be silly long, in this case, IMO. We use lowercase `cdf` to make it not look like a type, remove all looping from `sample` letting callers do it. Besides just side-stepping any `sampleSize` name choice, callers may want to filter out samples anyway which this makes slightly simpler. Also add two variants of `cumsum`, value return and in-place update distinguished by the var-ness of the first argument. Add tests for `int` and `float` for both `cumsum` and the new `sample`. (The sample tests exercise the value return mode of `cumsum`.) Functionality pre-this-PR `sample(a, w)` is now the almost as simple `for i in 0..<n: sample(a, w.cumsum)`, but this new code factoring is almost surely better. The statistical tests pass, as before. * Address Araq comment in https://github.com/nim-lang/Nim/pull/10084 We can always add in some `var` version later if desired to save memory, but this change now at least firms up the `sample` interface. * Rename `cumsum` -> `cumsummed` to honor NEP1 style. Re-instate `cumsum` as the in-place transformation. Test both in `tests/stdlib/tmath.nim` and use `cumsummed` in the example code for sample since that's a simpler example. * Fix requests from https://github.com/nim-lang/Nim/pull/10084 : example in lib/pure/math.nim and comment whitespace in lib/pure/random.nim
* Fix #9585 hypot in jsB3liever2018-10-311-1/+2
|
* more examples for mod and div, plus corrections [ci skip]narimiran2018-10-281-8/+46
|
* Documentation improved for `math` module (#9266)eqperes2018-10-101-79/+171
|
* fix for #9082 (#9089)Arne Döring2018-10-091-14/+16
|
* math.nim: document what to use instead of 'fmod'Araq2018-09-251-2/+2
|
* fixes 8594 (#8721)cooldome2018-08-221-1/+1
|
* Merge pull request #8628 from hlaaftana/patch-1Dominik Picheta2018-08-141-2/+2
|\ | | | | Small documentation typo in math
| * Small documentation typo in mathhlaaf2018-08-141-2/+2
| |
* | Haiku support for Nim (#8542)alaviss2018-08-141-1/+1
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * posix_other: Haiku now has spawn.h This is added per https://dev.haiku-os.org/ticket/13446 * posix_other: Add Haiku specific Dirent members * cpuinfo: Add an implementation for Haiku * distros: Add basic Haiku support * encodings: update Haiku support * fenv, math: Haiku now provides libm * times: Add Haiku struct members * ansi_c, osalloc: Add Haiku constants * threads: Add Haiku support * testament: Haiku uses LIBRARY_PATH * nim.cfg: Update Haiku support libnetwork should only be linked if network functions are used * threads: Haiku does not support -pthread switch * tworkingdir: Haiku's env is in /bin * posix_other: add SIGKILLTHR for Haiku * sockets: link with libnetwork on Haiku * coro: correct ucontext.h location http://pubs.opengroup.org/onlinepubs/009696699/basedefs/ucontext.h.html * coro: ucontext backend is not available on Haiku Haiku doesn't provide the <ucontext.h> header, as it was removed from POSIX * coro: fix setjmp backend The compiler does not allow statements after a noreturn function * nativesockets: Haiku doesn't support AI_V4MAPPED * system: hostOS can contains "haiku" * os: add support for Haiku's packagefs packagefs is read-only, but there are writable holes to the underlying file system as well * os: update constant for Haiku
* fixes #8421, fixes #7968, Nim compiler compiles with MSVC C89 version (#8556)andri lim2018-08-071-24/+58
|
* Merge pull request #7950 from Paalon/math-logAndreas Rumpf2018-06-141-5/+15
|\ | | | | Add log for base b of x
| * Fix a testKoki Fushimi2018-06-141-1/+1
| |
| * Use one same type for two parametersKoki Fushimi2018-06-141-5/+1
| |
| * Use concrete expressionKoki Fushimi2018-06-051-7/+6
| |
| * Bug fixKoki Fushimi2018-06-051-2/+3
| |
| * Change to use log(x, base)Koki Fushimi2018-06-051-3/+3
| |
| * Broaden the argument typesKoki Fushimi2018-06-041-1/+6
| |
| * Generalize and add testKoki Fushimi2018-06-041-7/+14
| |
| * Add log proc for base b of xKoki Fushimi2018-06-041-1/+3
| |
* | Rename tgamma to gamma (#7929)Koki Fushimi2018-06-051-3/+10
| | | | | | | | | | | | | | | | * Rename tgamma to gamma * set the deprecating version 0.19.0 * update changelog and use description in deprecated pragma
* | Add product proc (#7951)Koki Fushimi2018-06-041-1/+13
|/ | | | | | * Add product proc * Update changelog
* Removed spaces in math moduledata-man2018-05-301-1/+1
|
* Use truncation division in mod for floats (#7118)Oscar Nihlgård2018-05-301-11/+40
| | | | | | | | | | * Use truncation division in mod for floats * Add changelog entry * Add floorDiv/floorMod to math.nim * Update changelog
* Add inverse hyperbolic, and cot, sec and csc; and their hyperbolic, inverse, ↵Koki Fushimi2018-05-301-61/+96
| | | | | | | | | | | | | | | | inverse hyperbolic, and change to use defined functions in C or JS for logs and hyperbolics. (#7893) * Add secant, cosecant and cotangent. * Add hyperbolic functions of cotangent, secant and cosecant. * Add inverse hyperbolic functions. * Change to use defined function of C and JS. * Bug fix and refactoring. * Add change to changelog.md
* Faster binary gcd algorithm (#7849)Koki Fushimi2018-05-261-2/+30
| | | | | | | | | | | | * Faster binary gcd algorithm. * Use built in countTrailingZeroBits to calculate gcd. * Add definitions of gcd for integers and other types. * Unified signed case and unsinged case in one proc by using when syntax. * Change to faster one.
* Fixes factorial's bugdata-man2018-05-171-1/+12
|
                




                                                                                                                                                                       
                









                                                                                                                                                                       
                          












































                                                                                                                                                                            
                




                                                                                                                                                                       
                









                                                                                                                                                                       
                          























                                                                                                                                                                              
                


                                                                                                                                                                       
















































                                                                                                                                                                              



























































                                                                                                                                                                              
# Tokenize by whitespace.

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 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

# (re)compute the bounds of the next word in the line (surrounded by whitespace,
# treating '#' comments as a single word)
# return empty string on reaching end of file
next-word:  # line: (addr stream byte), out: (addr slice)
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = line
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # edi = out
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
    # skip-chars-matching-whitespace(line)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  skip-chars-matching-whitespace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$next-word:check0:
    # if (line->read >= line->write) clear out and return
    # . eax = line->read
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
    # . if (eax < line->write) goto next check
    3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # compare eax with *esi
    7c/jump-if-<  $next-word:check-for-comment/disp8
    # . return out
    c7          0/subop/copy        0/mod/direct    7/rm32/edi    .           .             .           .           .               0/imm32           # copy to *edi
    c7          0/subop/copy        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         0/imm32           # copy to *(edi+4)
    e9/jump  $next-word:end/disp32
$next-word:check-for-comment:
    # out->start = &line->data[line->read]
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
    89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to *edi
    # if (line->data[line->read] == '#') return rest of line
    # . eax = line->data[line->read]
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(esi+ecx+12) to AL
    # . compare
    3d/compare-eax-and  0x23/imm32/pound
    0f 85/jump-if-!=  $next-word:regular-word/disp32
$next-word:comment:
    # out->end = out->start
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
    89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
    # var write/ecx: int = line->write
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
$next-word:comment-loop:
    # if (line->read >= line->write) break
    39/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare *(esi+4) with ecx
    0f 8d/jump-if->=  $next-word:comment-break/disp32
    # ++line->read
    ff          0/subop/increment   1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # increment *(esi+4)
    # ++out->end
    ff          0/subop/increment   1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         .                 # increment *(edi+4)
    # if (*out->end == newline) break
    8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(edi+4) to eax
    8a/copy-byte                    0/mod/indirect  0/rm32/eax    .           .             .           0/r32/AL    .               .                 # copy byte at *eax to AL
    25/and-eax-with  0xff/imm32
    3d/compare-eax-and  0xa/imm32/newline
    0f 84/jump-if-=  $next-word:comment-break/disp32
    # loop
    e9/jump  $next-word:comment-loop/disp32
$next-word:comment-break:
    # return
    e9/jump  $next-word:end/disp32
$next-word:regular-word:
    # otherwise skip-chars-not-matching-whitespace(line)  # including trailing newline
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  skip-chars-not-matching-whitespace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # out->end = &line->data[line->read]
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
    89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
$next-word:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-word:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var slice/ecx: slice
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write(_test-stream, "  ab")
    # . . push args
    68/push  "  ab"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # next-word(_test-stream, slice)
    # . . push args
    51/push-ecx
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(slice->start - _test-stream->data, 2, msg)
    # . check-ints-equal(slice->start - _test-stream, 14, msg)
    # . . push args
    68/push  "F - test-next-word: start"/imm32
    68/push  0xe/imm32
    # . . push slice->start - _test-stream
    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # check-ints-equal(slice->end - _test-stream->data, 4, msg)
    # . check-ints-equal(slice->end - _test-stream, 16, msg)
    # . . push args
    68/push  "F - test-next-word: end"/imm32
    68/push  0x10/imm32
    # . . push slice->end - _test-stream
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-word-returns-whole-comment:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var slice/ecx: slice
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write(_test-stream, "  # a")
    # . . push args
    68/push  "  # a"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # next-word(_test-stream, slice)
    # . . push args
    51/push-ecx
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(slice->start - _test-stream->data, 2, msg)
    # . check-ints-equal(slice->start - _test-stream, 14, msg)
    # . . push args
    68/push  "F - test-next-word-returns-whole-comment: start"/imm32
    68/push  0xe/imm32
    # . . push slice->start - _test-stream
    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # check-ints-equal(slice->end - _test-stream->data, 5, msg)
    # . check-ints-equal(slice->end - _test-stream, 17, msg)
    # . . push args
    68/push  "F - test-next-word-returns-whole-comment: end"/imm32
    68/push  0x11/imm32
    # . . push slice->end - _test-stream
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-word-returns-empty-string-on-eof:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var slice/ecx: slice
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write nothing to _test-stream
    # next-word(_test-stream, slice)
    # . . push args
    51/push-ecx
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(slice->end - slice->start, 0, msg)
    # . . push args
    68/push  "F - test-next-word-returns-empty-string-on-eof"/imm32
    68/push  0/imm32
    # . . push slice->end - slice->start
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
    2b/subtract                     0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract *ecx from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-word-returns-empty-string-on-newline:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var slice/ecx: slice
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write some whitespace and a newline
    # . . push args
    68/push  "  \n"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # next-word(_test-stream, slice)
    # . . push args
    51/push-ecx
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(slice->end - slice->start, 0, msg)
    # . . push args
    68/push  "F - test-next-word-returns-empty-string-on-newline"/imm32
    68/push  0/imm32
    # . . push slice->end - slice->start
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
    2b/subtract                     0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract *ecx from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# (re)compute the bounds of the next word in the line (separated by whitespace)
# return empty string on reaching end of file
next-raw-word:  # line: (addr stream byte), out: (addr slice)
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = line
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # edi = out
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
    # skip-chars-matching-whitespace(line)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  skip-chars-matching-whitespace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$next-raw-word:check0:
    # if (line->read >= line->write) clear out and return
    # . eax = line->read
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
    # . if (eax < line->write) goto next check
    3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # compare eax with *esi
    7c/jump-if-<  $next-raw-word:word-exists/disp8
    # . return out
    c7          0/subop/copy        0/mod/direct    7/rm32/edi    .           .             .           .           .               0/imm32           # copy to *edi
    c7          0/subop/copy        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         0/imm32           # copy to *(edi+4)
    eb/jump  $next-raw-word:end/disp8
$next-raw-word:word-exists:
    # out->start = &line->data[line->read]
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
    89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to *edi
    # skip-chars-not-matching-whitespace(line)  # including trailing newline
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  skip-chars-not-matching-whitespace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # out->end = &line->data[line->read]
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
    89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
$next-raw-word:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return