diff options
author | Kartik Agaram <vc@akkartik.com> | 2020-11-15 22:54:56 -0800 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2020-11-15 22:54:56 -0800 |
commit | 2715d377b6108b0a607d9322d470bedd77c9c717 (patch) | |
tree | 34c13145f3d4e6a2a24520409a7e8334da734dea /mu.md | |
parent | b6b94712a1cd01081c4faf914501e08771242ac6 (diff) | |
download | mu-2715d377b6108b0a607d9322d470bedd77c9c717.tar.gz |
7247
Diffstat (limited to 'mu.md')
-rw-r--r-- | mu.md | 69 |
1 files changed, 60 insertions, 9 deletions
diff --git a/mu.md b/mu.md index bb8b68c9..a2581f9e 100644 --- a/mu.md +++ b/mu.md @@ -45,7 +45,9 @@ will provide good error messages to support you. Further down, this page enumerates all available primitives in Mu, and [a separate page](http://akkartik.github.io/mu/html/mu_instructions.html) -describes how each primitive is translated to machine code. +describes how each primitive is translated to machine code. There is also a +useful list of pre-defined functions (implemented in unsafe machine code) in [400.mu](http://akkartik.github.io/mu/html/400.mu.html) +and [vocabulary.md](vocabulary.md). ## Functions and calls @@ -471,34 +473,49 @@ Here `var2` can't live in a register. ## Array operations -Mu arrays are size-prefixed so that operations on them can check bounds as -necessary at run-time. The `length` statement returns the number of elements -in an array. +Here's an example definition of a fixed-length array: + +``` +var x: (array int 3) +``` + +The length (here `3`) must be an integer literal. We'll show how to create +dynamically-sized arrays further down. + +Arrays can be large; to avoid copying them around on every function call +you'll usually want to manage `addr`s to them. Here's an example computing the +address of an array. + +``` +var n/eax: (addr array int) <- address x +``` + +Addresses to arrays don't include the array length in their type. However, you +can obtain the length of an array like this: ``` var/reg: int <- length arr/reg: (addr array T) ``` -The `index` statement takes an `addr` to an `array` and returns an `addr` to -one of its elements, that can be read from or written to. +To operate on elements of an array, use the `index` statement: ``` var/reg: (addr T) <- index arr/reg: (addr array T), n -var/reg: (addr T) <- index arr: (array T sz), n +var/reg: (addr T) <- index arr: (array T len), n ``` The index can also be a variable in a register, with a caveat: ``` var/reg: (addr T) <- index arr/reg: (addr array T), idx/reg: int -var/reg: (addr T) <- index arr: (array T sz), idx/reg: int +var/reg: (addr T) <- index arr: (array T len), idx/reg: int ``` The caveat: the size of T must be 1, 2, 4 or 8 bytes. The x86 instruction set has complex addressing modes that can index into an array in a single instruction in these situations. -For types in general you'll need to split up the work, performing a `compute-offset` +For other sizes of T you'll need to split up the work, performing a `compute-offset` before the `index`. ``` @@ -514,6 +531,40 @@ performing any necessary bounds checking. Now the offset can be passed to var/reg: (addr T) <- index arr/reg: (addr array T), idx/reg: (offset T) ``` +## Stream operations + +A common use for arrays is as buffers. Save a few items to a scratch space and +then process them. This pattern is so common (we use it in files) that there's +special support for it with a built-in type: `stream`. + +Streams are like arrays in many ways. You can initialize them with a length: + +``` +var x: (stream int 3) +``` + +However, streams don't provide random access with an `index` instruction. +Instead, you write to them sequentially, and read back what you wrote. + +``` +read-from-stream s: (addr stream T), out: (addr T) +write-to-stream s: (addr stream T), in: (addr T) +var/eax: boolean <- stream-empty? s: (addr stream) +var/eax: boolean <- stream-full? s: (addr stream) +``` + +You can clear streams: + +``` +clear-stream f: (addr stream _) +``` + +You can also rewind them to reread what's been written: + +``` +rewind-stream f: (addr stream _) +``` + ## Compound types Primitive types can be combined together using the `type` keyword. For |