diff options
Diffstat (limited to 'doc')
30 files changed, 5338 insertions, 0 deletions
diff --git a/doc/api/index.txt b/doc/api/index.txt new file mode 100644 index 0000000..cac4744 --- /dev/null +++ b/doc/api/index.txt @@ -0,0 +1,91 @@ +{ + title: API Reference + description: Myrddin API Reference +} + +This is the page where the Myrddin language is documented. You want to know +all the boring, dull details? Well, they're here. + +APIs +---- + +### [Libstd](libstd) + +The standard library. You'll probably be using it in all your code, because +it's the standard. It's intended to cover a good portion of the functionality +that you'll need for any program. It's a bit of a grab bag, but can be roughly +categorized into the following subsections: + +- [Memory Allocation](libstd/alloc): All of your memory allocation needs. +- [Error Handling](libstd/err): Convenient utilities for aborting your program. +- [OS Interfaces](libstd/os): Ask not what you can do for your OS, ask what + your OS can do for you. +- [File Handling](libstd/files): Sometimes data just wants to persist. +- [Networking](libstd/networking): Communicating with other sytems isn't just + a fad. +- [Command Line Parsing](libstd/cli): Makes it easy to parse options from the + commad line. +- [Formatted Output](libstd/fmt): I/O. Without monads. +- [Variadic Arguments](libstd/varargs): If you want ugly APIs, we've got you + covered. +- [Slice manipulation](libstd/slices): Some generic functions. Easy to write + yourself, but a bit tedious. +- [String Manipulation](libstd/strings): Some unicode aware string poking. +- [Unicode](libstd/unicode): Wait a second, all languages aren't english? +- [Pervasive Data Structures](libstd/datastruct): At least, I use them a lot. + If you use them too, we've got you covered. +- [Misc](libstd/misc): Random crap that doesn't really fit into a category. + +### [Libsys](libsys) + +Libsys is a direct interface to system calls provided by the platform. It is + +- [Linux Syscalls](libsys/linux) +- [OSX Syscalls](libsys/osx) +- [FreeBSD Syscalls](libsys/freebsd) +- [Plan 9 Syscalls](libsys/plan9) + +### [Libbio](/myrddin/doc/libbio) + +This is a buffered IO library. It allows for many small reads and writes to be +done with better performance than writing a system call for each one. On top +of that, it allows for more convenient interfaces to handle linewise or +delimited input, where peeking at the input stream may be necessary. + +### [Libregex](/myrddin/doc/libregex) + +This is a regex library, as implied by the name. It implements a simple but +powerful regex syntax, with full unicode support. It also exposes the regex +syntax tree if needed, which is useful for code that wants custom regex +handling, but wants to remain consistent with the regexes in hairless. + +### [Libcryptohash](/myrddin/doc/libcryptohash) + +This is a library that handles cryptographic hashes. It implements many of the +most common cryptographic hashes, and provides a fairly consistent interface +to it. + +### [Libdate](/myrddin/doc/libdate) + +Libdate provides a fairly complete interface for manipulating dates, times, +and timezones. It handles adding durations and periods to dates, formatting +and parsing dates. + +### [Libthread](/myrddin/doc/libthread) + +Libthread is currently half assed and broken, and it doesn't work very well +with libstd, which is not yet thread aware. This needs work. + +Utilities +--------- + +### [Mbld](/myrddin/doc/mbld) + +Mbld is the Myrddin build tool. It knows how to handle source and library +dependencies, as well as build generated sources. + +### [Hairless](/myrddin/doc/mbld) + +Hairless is the Myrddin parser generator. It's currently in a half-finished +state, but is quit + diff --git a/doc/api/libbio/index.txt b/doc/api/libbio/index.txt new file mode 100644 index 0000000..c0099b4 --- /dev/null +++ b/doc/api/libbio/index.txt @@ -0,0 +1,416 @@ +{ + title: libbio + description: BIO library description +} + +Myrddin's BIO library is used for buffered input and output. It is a fairly +simple library that handles reading and writing from file descriptors. + +The concepts in libbio should be familiar to anyone that has used a buffered +IO library in most languages. The usual concepts are supported: Files, +formatted output, binary and ascii reads, and so on. There are also some +utility functions to deal with reading integers in a known endianness. + +One thing to keep in mind with libbio that it does not attempt to flush +buffers on program exit, which means that any unwritten, unflushed data +will be lost. Closing the bio files will prevent this issue. + +Summary +------- + + pkg bio = + type mode + const Rd : mode + const Wr : mode + const Rw : mode + + type file = struct + ;; + + type lineiter + + type status(@a) = union + `Eof + `Ok @a + `Err ioerr + ;; + + type ioerr = union + `Ebadfile + `Ebadbuf + `Ebadfd + `Eioerr + ;; + + impl iterable lineiter + + /* creation */ + const mkfile : (fd : std.fd, mode : mode -> file#) + const open : (path : byte[:], mode : mode -> std.result(file#, byte[:])) + const dial : (srv : byte[:], mode : mode -> std.result(file#, byte[:])) + const create : (path : byte[:], mode : mode, perm : int -> std.result(file#, byte[:])) + const close : (f : file# -> bool) + const free : (f : file# -> void) + + /* basic i/o. Returns sub-buffer when applicable. */ + const write : (f : file#, src : byte[:] -> status(std.size)) + const read : (f : file#, dst : byte[:] -> status(byte[:])) + const flush : (f : file# -> bool) + + /* seeking */ + const seek : (f : file#, std.off -> std.result(std.off, ioerr)) + + /* single unit operations */ + const putb : (f : file#, b : byte -> status(std.size)) + const putc : (f : file#, c : char -> status(std.size)) + const getb : (f : file# -> status(byte)) + const getc : (f : file# -> status(char)) + + /* peeking */ + const peekb : (f : file# -> status(byte)) + const peekc : (f : file# -> status(char)) + + /* delimited read; returns freshly allocated buffer. */ + const readln : (f : file# -> status(byte[:])) + const readto : (f : file#, delim : byte[:] -> status(byte[:])) + const skipto : (f : file#, delim : byte[:] -> bool) + const skipspace : (f : file# -> bool) + + /* iterators */ + const lineiter : (f : file# -> lineiter) + + /* formatted i/o */ + const put : (f : file#, fmt : byte[:], args : ... -> status(std.size)) + + /* unsigned big endian reads */ + generic getbe8 : (f : file# -> status(@a::(numeric,integral))) + generic getbe16 : (f : file# -> status(@a::(numeric,integral))) + generic getbe32 : (f : file# -> status(@a::(numeric,integral))) + generic getbe64 : (f : file# -> status(@a::(numeric,integral))) + + /* signed big endian reads */ + generic getle8 : (f : file# -> status(@a::(numeric,integral))) + generic getle16 : (f : file# -> status(@a::(numeric,integral))) + generic getle32 : (f : file# -> status(@a::(numeric,integral))) + generic getle64 : (f : file# -> status(@a::(numeric,integral))) + + /* unsigned big endian */ + generic putbe8 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putbe16 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putbe32 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putbe64 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + + /* unsigned little endian */ + generic putle8 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putle16 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putle32 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putle64 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + ;; + +The Data Structures +------------------- + + type file = struct + fd : std.fd + ;; + +The `bio.file` type contains the state required to implement buffered files. +All of the state is internal, except for the file descriptor, which is exposed +for the purposes of poll() and friends. Reading from it directly may lead to +inconsistent buffer state, and is strongly not recommended. + + type ioerr = union + `Ebadfile + `Ebadbuf + `Ebadfd + `Eioerr + ;; + + type status(@a) = union + `Eof + `Ok @a + `Err ioerr + ;; + +The `bio.status(@a)` union returns the result of the read operation, which +is going to either be a result of type '@a', an error-free end of file, or +an error of type `ioerr`. All of these conditions are transient, and are +retried on subsequent calls to the IO operations. For example, if reading +a file returns `Eof, but data is appended to a file, then a subsequent read +will return data again. + +In general, errors will be queued up, so if there is a buffered read or +write that partly succeeds but is interrupted halfway, the error will be +reported on the next operation. This way, partial operations are not lost. + +File Creation and Opening +------------------------- + + const Rd : mode + const Wr : mode + const Rw : mode + +When opening a file, one of the above flags must be passed to set the mode +of the file. `Rd` indicates that the bio file should be read only, `Wr` +indicates that it should be write only, and `Rw` indicates that it should be +both readable and writable. + +Bio file creation +------------- + + const mkfile : (fd : std.fd, mode : mode -> file#) + +This function creates a bio file from a file descriptor and mode, returning a +`bio.file#` which will buffer reads and/or writes from the fd. This function +assumes that you are passing it a correctly initialized fd, and will always +succeed. If the FD is incorrectly configured, uses of it will error out. + +Returns: A buffered file wrapping the file descriptor `fd` + + const open : (path : byte[:], mode : mode -> std.result(file#, byte[:])) + +This function attempts to open the path passed in with the mode, returning +a result which is either a file, or a string representing the error that +prevented the file from being opened. + +Returns: A buffered file representing `path` opened with the requested +permissions. + + const dial : (srv : byte[:], mode : mode -> std.result(file#, byte[:])) + +This function is similar to open, however, this function will open a +connection via a dialstring (as in `std.dial`), and buffer the fd returned +from that. + +Returns: A buffered file representing `dialstr` opened with the requested +permissions. + + const create : (path : byte[:], mode : mode, perm : int -> std.result(file#, byte[:])) + +This function is similar to open, however, this function will attempt to +atomically create and open the file descriptor. + +Returns: A buffered file representing `path` opened with the requested +permissions. + + const close : (f : file# -> bool) + +Closes the file descriptor that the bio file is wrapping, and frees any +resources used for buffering it. Any data that has not yet been written is +flushed. + +Returns: `true` if flushing the file succeeded, `false` if it failed. + + const free : (f : file# -> void) + +Frees any resources used for the file descriptor, but leaves it open. This is +useful if the file descriptor has been 'stolen' using bio.mkfile, and is not +owned by the bio file. + + const flush : (f : file# -> bool) + +Clears any data that has not been sent to the backing file descriptor. + +Returns: `true` if flushing the file succeeded, `false` if it failed. + +Binary I/O +----------- + + const write : (f : file#, src : byte[:] -> result(std.size, byte[:])) + +Writes bytes from the buffer `src` to a bio file, returning the number of +bytes written in the case of success. This number may be smaller than the size +of the buffer, but will never be larger. + + const read : (f : file#, dst : byte[:] -> result(byte[:])) + +Reads from a bio file, into the buffer 'dst', returning the section of the +buffer that was read in the result. + + const seek : (f : file#, std.off -> std.result(std.off, ioerr)) + +Seeks the bio file to the given absolute offset. + + const flush : (f : file# -> bool) + +Flush attempts to clear the buffers within `f`, writing everything within +the buffers and discarding them. If writing fails, `false` is returned. + + +Single Unit Operations +---------------------- + + /* single unit operations */ + const putb : (f : file#, b : byte -> status(std.size)) + +Writes a single byte out to the file 'f', returning a status. If +it is successful, the return value represents the number of bytes written. +For single byte writes, this value is unsurprisingly always 1. + + const putc : (f : file#, c : char -> status(std.size)) + +Writes a single unicode character out to the file 'f', returning a status. +This character is encoded in utf-8. If it is successful, the return value +represents the number of bytes written, varying between 1 and 4. + + const getb : (f : file# -> status(byte)) + +Reads a single byte from the file `f`, returning a status. If this read +succeeds, the next byte in the file is returned. + + const getc : (f : file# -> status(char)) + +Reads a unicode character from the file `f`, returning a status. If this read +was successful, the next character is returned from the file. The file is +assumed to be encoded in utf-8. + + /* peeking */ + const peekb : (f : file# -> status(byte)) + const peekc : (f : file# -> status(char)) + +Both peekb and peekc are similar to getb and getc respectively, although +they return the value without advancing the position within the buffer. + + +Delimited Operations +-------------------- + + /* delimited read; returns freshly allocated buffer. */ + const readln : (f : file# -> status(byte[:])) + +Readln reads a single line of input from the file 'f', returning the line +with the line ending characters removed. '\n', '\r', and '\r\n' are all +accepted as valid line endings, and are treated interchangably when reading. + +The buffer is heap allocated, and must be freed with std.slfree + + const readto : (f : file#, delim : byte[:] -> status(byte[:])) + +Readto is similar to readln, but instead of reading to a line ending, it will +read up to the point where it finds the requested delimiter. The delimiter is +an arbitrary sequence of bytes. If an end of file is reached, then the buffer +up to the Eof is returned. + +The buffer is heap allocated, and must be freed with std.slfree + + const skipto : (f : file#, delim : byte[:] -> bool) + +Skipto is identical to readto, but instead of allocating a buffer and reading +into it, skipto will ignore the values and drop them. It returns true for +any successful reads, and false if an error was encountered. + + const skipspace : (f : file# -> bool) + +Skipspace will consume any space tokens from the start of the input stream, It +returns true for any successful reads, and false if an error was encountered. + +Iteration +--------- + + const lineiter : (f : file# -> lineiter) + +Lineiter will return an interable type that will iterate through each line +in a file. These lines are allocated on the heap, and are automatically freed +at the end of the iteration. + +The returned iterator object is a value type, and does not need to be freed. + +Formatted IO +------------- + + const put : (f : file#, fmt : byte[:], args : ... -> status(std.size)) + +This formats the output using the std.fmt api, and writes it to the file `f`. +All custom formatters installed for `std.fmt` are used for this formatting. +This call returns the number of bytes written on success. + +Endian Aware Reads +------------------ + + generic getbe8 : (f : file# -> status(@a::(numeric,integral))) + generic getbe16 : (f : file# -> status(@a::(numeric,integral))) + generic getbe32 : (f : file# -> status(@a::(numeric,integral))) + generic getbe64 : (f : file# -> status(@a::(numeric,integral))) + + generic getle8 : (f : file# -> status(@a::(numeric,integral))) + generic getle16 : (f : file# -> status(@a::(numeric,integral))) + generic getle32 : (f : file# -> status(@a::(numeric,integral))) + generic getle64 : (f : file# -> status(@a::(numeric,integral))) + +The functions above all read from a bio file, and return the value read on +success. The 'be' variants read big endian values, and the `le' variants +read little endian values. They final result is converted to whatever +numeric, integral type is desired. If the value does not fit within the bounds +of the type, it is truncated. + +The number of bytes read is determined by the number at the end of the +function call. For eample, `getbe8()` will read 8 bits, or one byte from the +stream. `getle64` will get a 64 bit, or 8 byte, value. The number of bytes +consumed is independent of the size of the type being assigned to. + + generic putbe8 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putbe16 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putbe32 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putbe64 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + + generic putle8 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putle16 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putle32 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + generic putle64 : (f : file#, v : @a::(numeric,integral) -> status(std.size)) + +The functions above all write to a bio file, and return the number of bytes +written on success. The number of bytes written will always be the size of the +type. The 'be' variants write the value in a big endian representation, and +the 'le' variants write it in a little endian representation. + +The number of bytes written is determined by the number at the end of the +function call. For eample, `putbe8()` will write 8 bits, or one byte. +`putbe64` will write 64 bits, or 8 bytes. The number of +bytes consumed is independent of the size of the type being assigned to. + +Examples +--------- + +The example below is the simplest program that creates and opens a file, and +writes to it. It creates it with 0o644 permissions (ie, rw-r--r--), and then +immediately closes it. The result of this program should be a file called +`create-example` containing the words. + + use std + use bio + + const main = { + var f + + match bio.create("create-example", bio.Wr, 0o644) + | `std.Some bio: f = bio + | `std.None: std.fatal(1, "Failed to open file\n") + ;; + bio.write(f, "Hello user\n") + bio.close(f) + } + +The next example shows reading from a file called "lines", line by line. It +should echo the lines, numbering them as it prints them: + + use std + use bio + + const main = { + var f + var i + + match bio.open("lines", bio.Rd) + | `std.Some bio: f = bio + | `std.None: std.fatal(1, "Unable to open data file\n") + ;; + + while true + match bio.readlin(f) + | `std.Some ln: + std.put("line %i: %s\n", i, ln) + | `std.None: + break; + ;; + ;; + } diff --git a/doc/api/libdate/formatting.txt b/doc/api/libdate/formatting.txt new file mode 100644 index 0000000..c09f2cb --- /dev/null +++ b/doc/api/libdate/formatting.txt @@ -0,0 +1,99 @@ +{ + title: Formatting + description: Libdate API documentation. +} + +Date and Time Formatting +--------------------- + +Formatting in libdate is done through the standard formatting +functionality, and there are actually no functions exposed by libdate. +Instead, you would write something like: + +```{runmyr stdfmt1} +use date + +const main = { + std.put("{}\n", date.now()) +} +``` + +Custom formatting is done with a format option passed to std.format that +looks like `f=dateformat`. The format strings used resemble the strings +provided in strptime. Any characters preceded with a '%' are format +characters, otherwise they are copied to the output stream directly. + +The format strings used to control formatting are also used to control parsing. + +An example would look like: + +```{runmyr stdfmt1} +use date + +const main = { + std.put("{f=year is %Y, the day is %d}\n", date.now()) +} + + +There are a number of short format options installed, specifically, `d`, +`D`, and `t`, which respectively map to the default date format, the +default date and time format, and the default time only format. + +```{runmyr stdfmt1} +use date + +const main = { + std.put("{d}\n", date.now()) + std.put("{D}\n", date.now()) + std.put("{T}\n", date.now()) +} +``` + +Date and Time Formatting +--------------------- + +Both parsing and formatting use the same format strings. The +modifiers that are supported by libdate are listed below. + +When possible, the default format verbs `D`, `d`, or `t` +should be used for formatting, and the default constants +`Datefmt`, `Datetimefmt`, or `Timefmt` should be used for +parsing. + + +Char | Meaning +------|---------------------------------------------- +_%a_ | Abbreviated day of week: Mon, Tues, etc +_%A_ | Full day of week: Monday, Tuesday, Wednesday, etc +_%b_ | Abbreviated month of year: Jan, Feb, Mar, etc. +_%B_ | Full month of year: January, February, etc +_%c_ | Short for %Y-%m-%d %H:%M:%S %z (ISO 8601) +_%C_ | Century number of year, as two digit integer. +_%d_ | Day of month as a decimal number, 00 to 31. +_%D_ | Short for "%m/%d/%y (wtf america)" +_%e_ | Same as d, but space padded instead of zero padded. +_%F_ | Short for ISO 8601 date format %Y-%m-%d +_%h_ | Same as '%b'. +_%H_ | Hour number using the 24 hour clock, zero padded. +_%I_ | Hour number using the 12 hour clock, zero padded. +_%j_ | Day of year as a decimal number, 001 to 366. +_%k_ | Hour number using the 24 hour clock, space padded. +_%l_ | Hour number using the 12 hour clock, space padded. +_%m_ | The month number, zero padded. +_%M_ | The minute number, zero padded. +_%p_ | AM or PM, according to the time provided. +_%P_ | am or pm, according to the time provided. +_%r_ | 12 hour time: %I:%M %p +_%R_ | 24 hour time: %H:%M +_%s_ | The number of seconds since the Epoch +_%S_ | The second number, zero padded. 0 to 60. +_%T_ | The time including seconds in 24 hour format. +_%u_ | The day of the week in decimal, 0 to 7. +_%x_ | The date without the time. Same as %F +_%X_ | The date with the time. Same as %c +_%y_ | The final two digits of year. +_%Y_ | The full year, including century. BC dates are negative. +_%z_ | Timezone offset. +_%Z_ | Timezone name or abbreviation. Offset if this is not available. +_%%_ | A literal '%' + diff --git a/doc/api/libdate/index.txt b/doc/api/libdate/index.txt new file mode 100644 index 0000000..7b9cafa --- /dev/null +++ b/doc/api/libdate/index.txt @@ -0,0 +1,95 @@ +{ + title: libdate + description: Libdate API documentation. +} + +Summary +------- + +Libdate is a date API designed to cover most date related functinality in a +sane, easy to use way. It will format, parse, and do basic manipulations on +dates. All operations are done on the proleptic Gregorian calendar, and the +Julian to transition is not handled. + +Core Concepts +------------- + +### Instants + +An instant is a point in time. Immovable, unchanging for eternity, it is +anchored in one spot through the microseconds of unix time in the UTC time +zone. It is broken up into a local representation, consisting of years, +months, days, weekdays, hours, minutes, seconds, and microseconds, with a +timezone attached. + +### Durations + +A duration is a difference between two instants. It has a fixed magnitude, and +is independent of timezones and the oddities of human calendars. It may be +added or subtracted from instants of other durations. Durations have a +resolution of microseconds. It is signed, and negative durations move instants +backwards in time. + +### Periods + +A period is another form of differece between two instants. However, a period +is a flighty creature, which does not anchor itself to the world of men in any +strong way. A year may be 365 or 366 days, according to the whims and vagaries +of the local calendar. An hour added to a time may jump ahead by two hours, if +it so desires to follow the savings of daylight. These creatures attempt to +mold themselves to the irrationalities of man's mind, and eschew the divine +ordering of absolute time handed down by the prophets. + +### Timezones + +A timezone is a named zone, as decreed by the mighty IANA timezone database. +It may take the form of a location such as "America/New_York", a well-known +abbreviation like "EST", or a special value such as "local" or "", which mean, +respectively, the current zone or UTC. + +Conventions +----------- + +Timezones are pervasive, and no time is manipulated in this API without +the awareness of the timezone. As a result, it is useful to know that dates +are represeted using IANA zoneinfo database names. These are documented +fully here: http://www.iana.org/time-zones + +There are two extensions that libdate supports: The empty string represents +the UTC timezone, and "local" represents the time zone of the system that +the system libdate is running on has been configured to. + +In the case of ambiguous timezones -- for example, parsing a date with no +time attached, while using API call that does not specify the timezone, +libdate will assume UTC dates. + +Functionality +------------- + +The functionality in libdate can be grouped into three main sections: Parsing, +Manipulation, and Formatting. + +### [Types](types) + +This covers the set of all types provided by, and used throughout, the API +of libdate, including all public fields and types. + +### [Parsing](parsing) + +This covers parse formatted dates in a manner similar to strptime. There are +currently plans for an flexible parse() function, but this has not yet been +implemented. + +### [Creation and Manipulation](manipulation) + +Manipulation covers date and time creation, and transition aware APIs that +will work for timezone crossings, daylight savings time, and so on. + +#### Formatting + +This covers date formatting, which is done through strftime-like format +strings. There are actually no functions exposed for formatting, as this is +done through custom formatters for libstd, however, the format strings used +to customize the date output are described here. + + diff --git a/doc/api/libdate/manipulation.txt b/doc/api/libdate/manipulation.txt new file mode 100644 index 0000000..22f9b9e --- /dev/null +++ b/doc/api/libdate/manipulation.txt @@ -0,0 +1,130 @@ + +{ + title: Creation and Manipulation + description: Libdate API documentation. +} + +Creation and Manipulation +------------------------- + pkg date = + /* useful constructors */ + const utcnow : (-> instant) + const now : (tz : byte[:] -> instant) + const tozone : (d : instant, zone : byte[:] -> instant) + const mkdate : (y : int, m : int, day : int, zone : byte[:] -> instant) + const mkdatetime : (year : int, mon : int, day : int, \ + h : int, m : int, s : int, zone : byte[:] -> instant) + const mkinstant : (tm : std.time, zone : byte[:] -> instant) + + const localoff : (tm : std.time -> duration) + const tzoff : (tzname : byte[:], tm : std.time -> duration) + const tzname : (tzoff : int -> byte[:]) + const isleap : (d : instant -> bool) + + /* date differences */ + const add : (d : instant, dt : duration -> instant) + const sub : (d : instant, dt : duration -> instant) + const addperiod : (d : instant, dt : period -> instant) + const subperiod : (d : instant, dt : period -> instant) + + const duration : (a : instant, b : instant -> duration) + + pkglocal const recalc : (inst : instant# -> std.time) + ;; + +Creation +----------- + + const utcnow : (-> instant) + +Creates an instant representing the current time. The timezone is UTC. As a +general philosophical point, dates written out persisetntly should generally +be in UTC, so this function should generally be used to get dates. + +Returns: An instant representing the current time in the UTC timezone. + + const now : (tz : byte[:] -> instant) + +Creates an instant representing the current time. The timezone is the local +time. This is useful for displaying dates and times to the user. + +Returns: An instant representing the current time in the local timezone. + + const tozone : (d : instant, zone : byte[:] -> instant) + +Takes an instant and converts it to a new timezone. This takes the instants by +value, and therefore, does not mutate any of its arguments. + +Returns: An instant representing provided time in the requested timezone. + + const mkdate : (y : int, m : int, day : int, zone : byte[:] -> instant) + +Creates a date with the given year, month, and day in the given timezone. The +time is set to 0:00:00 + +Returns: A date representing the given ymd + + const mkdatetime : (year : int, mon : int, day : int, \ + h : int, m : int, s : int, zone : byte[:] -> instant) + +Creates a date and time pair with the given year, month, day, at the time +h, m, s, in the provided timezone. The microseconds are zeroed. + +Returns: A date representing the given ymd:hms + + const mkinstant : (tm : std.time, zone : byte[:] -> instant) + +Creates an instant from a time type. This time can be derived from the +standard library, or computed from any other source. The time is in +microseconds since the Unix epoch (Jan 1 1970, 0:00, UTC). + +Returns: An instant representing a std.time in the requested timezone + +Timezones +--------- + + const localoff : (tm : std.time -> duration) + +Gets the local timezone offset for a time. Note that timezones can change due +daylight savings, politics, and other similar factors, so a timezone offset +needs to be associated with a specific instant. + +Returns: a duration representing the local timezone offset. + + const tzoff : (tzname : byte[:], tm : std.time -> duration) + +Gets the timezone offset for a time and timezone pair. Note that timezones can +change due daylight savings, politics, and other similar factors, so a +timezone offset needs to be associated with a specific instant. + +Returns: a duration representing the requested timezone offset. + + const isleap : (d : instant -> bool) + +Returns: whether a specific instant is within a leap year or not. + +Manipulation +------------ + + const add : (d : instant, dt : duration -> instant) + const sub : (d : instant, dt : duration -> instant) + +Adds or subtracts a duration from a date. A duration is an absolute length of +time, and is not adjusted for calendar shifts around DST and similar events. + +Returns: an instant representing the adjusted time. + + const addperiod : (d : instant, dt : period -> instant) + const subperiod : (d : instant, dt : period -> instant) + +Adds or subtracts a period from a date. A period is a humanized length of +time, and is adjusted for calendar shifts around DST and similar events. + +Returns: an instant representing the adjusted time. + + const duration : (a : instant, b : instant -> duration) + +Returns: the duration representing the difference between the two provided +instants. + + diff --git a/doc/api/libdate/parsing.txt b/doc/api/libdate/parsing.txt new file mode 100644 index 0000000..fc4aa4e --- /dev/null +++ b/doc/api/libdate/parsing.txt @@ -0,0 +1,74 @@ +{ + title: Date Parsing + description: Libdate API documentation. +} + +Date and time parsing +--------------------- + + type parsefail = union + `Doublefmt char + `Badsep (char, char) + `Badfmt char + `Badzone byte[:] + `Badname byte[:] + `Badchar + `Badampm + `Shortint + `Badint + ;; + + const Datetimefmt + const Datefmt + const Timefmt + + /* date i/o */ + const parsefmt : (fmt : byte[:], s: byte[:] -> std.result(instant, parsefail)) + const parsefmtl : (fmt : byte[:], s: byte[:] -> std.result(instant, parsefail)) + const parsefmtz : (fmt : byte[:], s: byte[:], tz : byte[:] -> std.result(instant, parsefail)) + +Descriptions +------------ + + const Datetimefmt = "%Y-%m-%d %H:%M:%S %z" + const Datefmt = "%H:%M:%S %z" + const Timefmt = "%Y-%m-%d %z" + +These are "sane defaults" for date and time formats, and can be passed in +where a format is required. + + type parsefail + +Parsefail is an error type, returning descriptions of the error that the +parsing code saw. Strings returned within the error point into the format +string, and will be invalid when the format string is freed. + + const parsefmt : (fmt : byte[:], s: byte[:] -> std.result(instant, parsefail)) + +Parses a format string with a format. If there is a timezone specified in the +format string, that format string will be used. If there is no format, the +timezone will be assumed to be UTC. + +The format string used is similar to strptime, and is documented fully in +the [description of formatting](/libdate/formatting) + +Returns: Either an instant representing the time parsed, or an error +describing the failure. + + const parsefmtl : (fmt : byte[:], s: byte[:] -> std.result(instant, parsefail)) + +Parses a format into the local time. If a timezone is specified, the +conversion will be done from the instant of the timezone to the local time. +The format strings are the same as 'parsefmt'. + +Returns: Either an instant representing the time parsed, or an error +describing the failure. + + const parsefmtz : (fmt : byte[:], s: byte[:], tz : byte[:] -> std.result(instant, parsefail)) + +Parses a format into the specified timezone. If a timezone is specified in the +parsed date, the conversion will be done from the timezone to the provided +timezone. The format strings are the same as 'parsefmt'. + +Returns: Either an instant representing the time parsed, or an error +describing the failure. diff --git a/doc/api/libdate/types.txt b/doc/api/libdate/types.txt new file mode 100644 index 0000000..71c3ebe --- /dev/null +++ b/doc/api/libdate/types.txt @@ -0,0 +1,71 @@ +{ + title: Types + description: Libdate API documentation. +} + +Contents +-------- + + pkg date = + type instant = struct + actual : std.time /* epoch time in microseconds */ + tzoff : duration /* timezone offset in microseconds */ + year : int /* year, != 0 */ + mon : int /* month, [1..12] */ + day : int /* day, [1..31] */ + wday : int /* weekday, [0..6] */ + h : int /* hour: [0..23] */ + m : int /* minute: [0..59] */ + s : int /* second: [0..59] */ + us : int /* microsecond: [0..999,999] */ + tzname : byte[:] /* current time zone name */ + ;; + + type duration = std.time + + type period = union + `Year int + `Month int + `Day int + `Hour int + `Minute int + `Second int + ;; + ;; + +Descriptions +------------ + + type instant + +Instant represents a single instant of time, with a resolution +of microseconds. It contains the actual instant in the member +`actual`, which is a timestamp in microseconds since Jan 1, 1970 +at 00:00 in UTC, and breaks out the "humanized" time out into the +various members that are exposed. + +The instant type always has a timezone attached, and the humanized +time components are always in that timezone. + + type duration + +A duration is an absolute number of microseconds that can be added +or subtracted from an instant. This is not timezone adjusted. + + type period + +A period is a time delta that is adjusted for crossing timezones, +daylight savings, and other similar events. If you add a day to +an instant, you would get the same wallclock time the next day, +should that wallclock time exist. + +For example, if I were to add `\`Day 2` to the instant +`Oct 31 2015 3:00`, then the result would be the date +`Nov 2 2015 3:00`, regardless of the daylight savings time adjustment. +However, adding `\`Hour 48` would not have that effect. + +In cases where the adjustment does not exist -- for example, leap years, +then the time will "wrap around" to the next available day. For example, +Feb 29th on a leap year will become Mar 1st. + + diff --git a/doc/api/libinifile/index.txt b/doc/api/libinifile/index.txt new file mode 100644 index 0000000..3952796 --- /dev/null +++ b/doc/api/libinifile/index.txt @@ -0,0 +1,135 @@ +{ + title: libinifile + description: Libinifile API documentation. +} + +Summary +------- + + pkg inifile = + type error = union + `Fileerr + `Parseerr int + `Dupkey int + ;; + + type inifile = + ;; + + /* reading */ + const load : (path : byte[:] -> std.result(inifile#, error)) + const loadf : (file : std.fd -> std.result(inifile#, error)) + const free : (ini : inifile# -> void) + + /* writing */ + const write : (ini : inifile#, path : byte[:] -> bool) + + /* key getting/setting */ + const get : (ini : inifile#, sect : byte[:], key : byte[:] -> std.option(byte[:])) + const getv : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> byte[:]) + const has : (ini : inifile#, sect : byte[:], key : byte[:] -> bool) + const put : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> void) + ;; + + +Overview +-------- + +Libinifile is a simple ini file parser. It does little interpretation of the +data, and provides little in the way of convenience features. Loading will +read the file into memory, and will not reflect changes of the on-disk data. + +Functions +--------- + + const load : (path : byte[:] -> std.result(inifile#, error)) + +Load will read a file from disk, parsing it, and returning either a pointer to +an `inifile` data structure, or an error reporting the problem parsing it, and +if applicable, the line that the error occurred on. + +This data structure must be freed with `inifile.free()`. + + const loadf : (file : std.fd -> std.result(inifile#, error)) + +This is identical to `inifile.load`, only it reads from a `std.fd` that has +already been opened in read mode, instead of a path. + + const free : (ini : inifile# -> void) + +Releases all storage associated with an inifile data structure. + + const write : (ini : inifile#, path : byte[:] -> bool) + +Write will take the content of an infile, and serialize it to disk. Comments +from the original ini file are not currently preserved. + + const get : (ini : inifile#, sect : byte[:], key : byte[:] -> std.option(byte[:])) + const getv : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> byte[:]) + +Get and getv act like `std.hget` and `std.htgetv`. They will retrieve an entry +from the ini file. + +Htget will return `\`std.Some val` if the key is present in the given section, +or `\`std.None` if there is no value present in the ini file. Htgetv will +return the default value `val` passed to it if the key is not found. + +For a key that is outside of a section, the empty string (`""`) should be +passed for the section name. + + const has : (ini : inifile#, sect : byte[:], key : byte[:] -> bool) + +Queries whether a key is present in the ini file. Returns true if the key is +present, or false if it is not. + + const put : (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:] -> void) + +Places a key value pair into the in-memory representation of the .ini file. +This key value pair added if it is not present, and replaced if it is. The key +and value are both copied, and ownership is not taken. The responsibility for +freeing the previous value lies with the ini file implementation. + +Supported Syntax +-------------- + +The dialect that it supports allows for a list of zero or more key-value pairs +before any sections are declared, followed by a list of sections containing +more key value pairs. + +Keys are any sequence of characters, excluding an '=' sign. Values are any +sequence of characters. For both of these, both leading and trailing white +space is ignored. + +Sections are lists of characters started by `[` and end by `]`. The only +character disallowed within a section name is `]`. Leading and trailing +whitespace is stripped from a section. + +Keys within a file must be unique, otherwise this is an error. + +Section declarations may repeat throughout the file, but this will merely +switch back into the old section. + +Example +------ + +Assuming that an file named `demo.ini` exists, and contains the following +text: + + toplev = hey, there's a value! + [section] + key = wait, there's another + +Then the following program will read it and show the values of the keys: + + use std + use inifile + + const main = { + var ini + + ini = std.try(inifile.load("demo.ini")) + std.put("{}\n", inifile.getv(ini, "", "toplev", "not present") + std.put("{}\n", inifile.getv(ini, "section", "key", "not present") + inifile.free(ini) + } + diff --git a/doc/api/libregex/index.txt b/doc/api/libregex/index.txt new file mode 100644 index 0000000..5cf4716 --- /dev/null +++ b/doc/api/libregex/index.txt @@ -0,0 +1,279 @@ +{ + title: libregex + description: Libregex API documentation. +} + +Summary +------- + + pkg regex = + type ast = union + /* basic string building */ + `Alt (ast#, ast#) + `Cat (ast#, ast#) + + /* repetition */ + `Star ast# + `Rstar ast# + `Plus ast# + `Rplus ast# + `Quest ast# + + /* end matches */ + `Chr char + `Ranges char[2][:] + + /* meta */ + `Cap (std.size, ast#) /* id, ast */ + `Bol /* beginning of line */ + `Eol /* end of line */ + `Bow /* beginning of word */ + `Eow /* end of word */ + ;; + + type status = union + `Noimpl + `Incomplete + `Unbalanced char + `Emptyparen + `Badrep char + `Badrange byte[:] + `Badescape char + ;; + + /* regex compilation */ + const parse : (re : byte[:] -> std.result(ast#, status)) + const compile : (re : byte[:] -> std.result(regex#, status)) + const dbgcompile : (re : byte[:] -> std.result(regex#, status)) + const free : (re : regex# -> void) + + /* regex execution */ + const exec : (re : regex#, str : byte[:] -> std.option(byte[:][:])) + const search : (re : regex#, str : byte[:] -> std.option(byte[:][:])) + + const sub : (re : regex#, str : byte[:], subst : byte[:][:] -> std.option(byte[:])) + const sbsub : (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> bool) + const suball : (re : regex#, str : byte[:], subst : byte[:][:] -> byte[:]) + const sbsuball : (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> void) + + const matchfree : (pat : byte[:][:] -> void) + ;; + + +Overview +-------- + +Libregex is a simple regex API that uses a parallel NFA implementation. This +means that while it is not blazingly fast, it does not exhibit pathological +behavior on regexes like `(aa|aab?)\*` that many common regex APIs will see. + +Regex Syntax +------------- + +The grammar for regexes that are accepted is sketched out below. + + regex : altexpr + altexpr : catexpr ('|' altexpr)+ + catexpr : repexpr (catexpr)+ + repexpr : baseexpr[*+?][?] + baseexpr : literal + | charclass + | charrange + | '.' + | '^' + | '$' + | '(' regex ')' + charclass : see below + charrange : '[' (literal('-' literal)?)+']' + +The following metacharacters have the meanings listed below: + +Matches a single unicode character + +<table> + <tr><tr><th>Metachar</th> <th>Description</th></tr> + <tr><td><code>^</td></code> <td>Matches the beginning of a line. Does not consume any characters.</td></tr> + <tr><td><code>$</td></code> <td>Matches the end of a line. Does not consume any characters.</td></tr> + <tr><td><code>*</td></code> <td>Matches any number of repetitions of the preceding regex fragment.</td></tr> + <tr><td><code>+</td></code> <td>Matches one or more repetitions of the preceding regex fragment.</td></tr> + <tr><td><code>?</td></code> <td>Matches zero or one of the preceding regex fragment.</td></tr> +</table> + +In order to match a literal metacharacter, it needs to be preceded by a '\' character. + +The following character classes are supported: + +<table> + <tr><tr><th>Charclass</th> <th>Description</th></tr> + <tr><td><code>\d </code></td> <td>ASCII digits</td></tr> + <tr><td><code>\D </code></td> <td>Negation of ASCII digits</td></tr> + <tr><td><code>\x </code></td> <td>ASCII Hex digits</td></tr> + <tr><td><code>\X </code></td> <td>Negation of ASCII Hex digits</td></tr> + <tr><td><code>\s </code></td> <td>ASCII spaces</td></tr> + <tr><td><code>\S </code></td> <td>Negation of ASCII spaces</td></tr> + <tr><td><code>\w </code></td> <td>ASCII word characters</td></tr> + <tr><td><code>\W </code></td> <td>Negation of ASCII word characters</td></tr> + <tr><td><code>\h </code></td> <td>ASCII whitespace characters</td></tr> + <tr><td><code>\H </code></td> <td>Negation of ASCII whitespace characters</td></tr> + <tr><td><code>\pX</code></td> <td>Characters with unicode property 'X'</td></tr> + <tr><td><code>\PX</code></td> <td>Negation of characters with property 'X'</td></tr> +</table> + +The current list of supported Unicode character classes `X` are + +<table> + <tr><th>Abbrev</th> <th>Full name</th> <th>Description</th></tr> + <tr> + <td><code>L</code></td> <td><code>Letter</code></td> + <td>All letters, including lowercase, uppercase, titlecase, + and uncased.</td> + </tr> + <tr> + <td><code>Lu</code></td> <td><code>Uppercase_Letter</code></td> + <td>All uppercase letters.</td> + </tr> + <tr> + <td><code>Ll</code></td> <td><code>Lowercase_Letter</code></td> + <td>All lowercase letters.</td> + </tr> + <tr> + <td><code>Lt</code></td> <td><code>Titlecase_Letter</code></td> + <td>All titlecase letters.</td> + </tr> + <tr> + <td><code>N</code></td> <td><code>Number</code></td> + <td>All numbers.</td> + </tr> + <tr> + <td><code>Z</code></td> <td><code>Separator</code></td> + <td>All separators, including spaces and control characers.</td> + </tr> + <tr> + <td><code>Zs</code></td> <td><code>Space_Separator</code></td> + <td>All space separators, including tabs and ASCII spaces.</td> + </tr> +</table> + +Functions +--------- + + const parse : (re : byte[:] -> std.result(ast#, status)) + +Parse takes a regex string, and converts it to a regex syntax tree, returning +`\`std.Success ast#` if the regex was valid, or a `\`std.Failure r` if the +regex could not be parsed. This AST can be used to further process the regex, +possibly turning it into a multiregex as in Hairless, or using it for NFA and +DFA tricks. + + const compile : (re : byte[:] -> std.result(regex#, status)) + const dbgcompile : (re : byte[:] -> std.result(regex#, status)) + +`compile` takes a regex string, and converts it to a compiled regex, returning +`\`std.Success regex` if the regex was valid, or a `\`std.Failure r` with the +reason that the compilation failed. `dbgcompile` is similar, however, the +regex is compiled so it will spit out a good deal of debugging output. Unless +you are intent on debugging the internals of the regex engine, this is likely +only of academic interest. + + const free : (re : regex# -> void) + +`free` must be called on a compiled regex to release it's resources after you +are finished using it. + + const exec : (re : regex#, str : byte[:] -> std.option(byte[:][:]) + +`exec` runs the regex over the specified text, returning an `\`std.Some matches` +if the text matched, or `std.None` if the text did not match. matches[0] is +always the full text that was matched, and will always be returned regardless +of whether capture groups are specified. + + const search : (re : regex#, str : byte[:] -> std.option(byte[:][:])) + +`search` searches for a matching sub-segment of the regex over the specified +text, returning an `\`std.Some matches` if the text matched, or `std.None` if +the text did not match. matches[0] is always the full text that was matched, +and will always be returned regardless of whether capture groups are +specified. `search` returns the the earliest match in the string provided. + + + const sub : (re : regex#, str : byte[:], subst : byte[:][:] -> std.option(byte[:])) + const sbsub : (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> bool) + +`sub` will take a pattern, an input string, and a set of substitutions, and +attempt to match. If the match is successful, it will replace each group +within `str` with `subst`, returning a freshly allocated string. `sbsub` +behaves identically, however it inserts the new string into the string +buffer provided, instead of allocating a new string. + +If there is no match, then `\`std.None` will be returned. + + const suball : (re : regex#, str : byte[:], subst : byte[:][:] -> byte[:]) + const sbsuball : (sb : std.strbuf#, re : regex#, str : byte[:], subst : byte[:][:] -> void) + +`suball` replaces every match within the string using the given substitutions. +Only captured groups will be substituted. The remaining text will be left in +place. + +Example +------ + +#### Pattern matching + +```{runmyr regex} +use std +use regex + +const main = { + match regex.compile("ab(c+)") + | `std.Ok re: runwith(re, "abccc") + | `std.Fail m: std.fatal("Failed to compile regex\n") + ;; +} + +const runwith = {re, txt + match regex.exec(re, txt) + | `std.Some matches: + std.put("matched {}, got {} matches\n", txt, matches.len) + for m in matches + std.put("Match: {}\n", m) + ;; + regex.matchfree(matches) + | `std.None: + std.put("%s did not match\n") + ;; +} +``` + +#### Substitution + +```{runmyr regex} +use std +use regex + +const main = { + var re + + re = std.try(regex.compile("(a*)bc(d)e")) + match regex.sub(re, "aaabcdef", ["HEY", "X"][:]) + | `std.Some sub: + std.put("{}\n", sub[0]) + regex.matchfree(matches) + | `std.None: + std.fatal("should have matched") + ;; +} +``` + +```{runmyr regex} +use std +use regex + +const main = { + var re, sub + + re = std.try(regex.compile("(b|e)")) + sub = regex.suball(re, "aaabbbcdef", ["SUB"][:]) + std.put("subst: {}\n", sub) + std.slfree(sub) +} +``` diff --git a/doc/api/libstd/algorithms.txt b/doc/api/libstd/algorithms.txt new file mode 100644 index 0000000..0787d43 --- /dev/null +++ b/doc/api/libstd/algorithms.txt @@ -0,0 +1,129 @@ +{ + title: Algorithms + description: libstd: Algorithms +} + +Algorithms +---------- + + pkg std = + /* the result of a comparison */ + type order = union + `Before + `Equal + `After + ;; + + /* sorting and searching */ + generic sort : (sl:@a[:], cmp:(a:@a, b:@a -> order) -> @a[:]) + generic lsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric))) + generic bsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric))) + generic swap : (a : @a#, b : @a# -> void) + + /* prepackaged comparisons */ + generic numcmp : (a : @a, b : @a -> order) + const strcmp : (a : byte[:], b : byte[:] -> order) + const strncmp : (a : byte[:], b : byte[:], n : size -> order) + + /* extrema and absolute values */ + generic min : (a : @a::numeric, b : @a::numeric -> @a::numeric) + generic max : (a : @a::numeric, b : @a::numeric -> @a::numeric) + generic clamp : (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric) + generic abs : (a : @a::numeric -> @a::numeric) + ;; + +Overview +-------- + +There are a number of algorithms that are pervasive through many programs. +These include sorting, searching, and similar + +We only cover sorting and searching here, although more would be a good +addition. Maybe in a separate library. + +Types +----- + + type order = union + `Before + `Equal + `After + ;; + +When comparing, it's useful to have an ordering between values. The order type +is the result of a comparison, `a CMP b` describing whether the first value +`a` comes before, after, or is equivalent to `b`. + +Functions: Sorting and Searching +-------------------------------- + + generic sort : (sl:@a[:], cmp:(a:@a, b:@a -> order) -> @a[:]) + +This function will sort a slice, modifying it in place. The comparison +function `cmp` is used to decide how to order the slice. This comparison +function must be transitive -- in otherwords, if A comes before B, and B comes +before C, then A must come before C. This is true of most comparisons, but +some care should be taken when attempting to provide "humanized" sorting. + +Returns: the same slice it was pased. The slice will not be reallocated or +moved. + + generic lsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric))) + +Performs a linear search for a value using the comparison predicate `cmp`. The +slice is walked in order until the first value where `cmp` returns `\`Equal`. + +Returns: `\`Some idx`, or `\`None` if the value is not present. + + generic bsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric))) + +Performs a binary search for a value using the comparison predicate `cmp`. The +input slice `sl` must be sorted according to the comparsion function `cmp` +such that for a value at index `idx`, the comparison `cmp(sl[idx - 1], +sl[idx])` must return either `\`Before` or `\`Equal`. + +If there are multiple equal copies value within a list, the index retuned is +not defined. + +Returns: `\`Some idx`, or `\`None` if the value is not present. + + generic swap : (a : @a#, b : @a# -> void) + +Takes two pointers to two values, and switches them. If the pointers are +equal, this is a no-op. + + generic numcmp : (a : @a::numeric, b : @a::numeric -> order) + const strcmp : (a : byte[:], b : byte[:] -> order) + const strncmp : (a : byte[:], b : byte[:], n : size -> order) + +These functions are helpers for comparing values. They will compare any two +numeric values, and will return the ordering between the two. + +Numcmp simply returns the result comparing whether `a` is less than `b`, +relying on the behavior of the built in operators. + +Strcmp and strncmp will do a lexicographical comparison, comparing strings +byte by byte. This is a useful and correct behavior for both strings of +arbitrary data, and utf8 encoded strings, where it is equivalent to doing +a comparison by codepoint. + +Functions: Extrema and Clamping +------------------------------- + + generic min : (a : @a::numeric, b : @a::numeric -> @a::numeric) + generic max : (a : @a::numeric, b : @a::numeric -> @a::numeric) + +Min and max return the larger or smaller of the two numeric values passed to +them, respectively. They rely on the built in comparison functions. + + generic clamp : (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric) + +Clamp clamps the value `a` to the range [min, max], and returns it. This means +that if `a` is lower than `min`, or greater than `max`, it is adjusted to +those bounds and returned. + + generic abs : (a : @a::numeric -> @a::numeric) + +Abs returns the absolute value of a number. This means that if the number is +less than 0, it is retuned with the sign inverted. If the type `@a` is +unsigned, then this function is a no-op. diff --git a/doc/api/libstd/alloc.txt b/doc/api/libstd/alloc.txt new file mode 100644 index 0000000..c2692a4 --- /dev/null +++ b/doc/api/libstd/alloc.txt @@ -0,0 +1,160 @@ +{ + title: Allocation + description: libstd: Allocation +} + +Memory Allocation +----------------- + + pkg std = + generic mk : (val : @a -> @a#) + generic alloc : ( -> @a#) + generic zalloc : ( -> @a#) + generic free : (v:@a# -> void) + generic slalloc : (len : size -> @a[:]) + generic slzalloc : (len : size -> @a[:]) + generic slgrow : (sl : @a[:]#, len : size -> @a[:]) + generic slzgrow : (sl : @a[:]#, len : size -> @a[:]) + generic slfree : (sl : @a[:] -> void) + const bytealloc : (sz:size -> byte#) + const zbytealloc : (sz:size -> byte#) + const bytefree : (m:byte#, sz:size -> void) + ;; + + generic mk : (val : @a -> @a#) + +`mk` creates a shallow copy of variable passed to it on the heap, returning a +pointer to the value that it allocated. It is conventionally used for creating +new copies of larger complex data structures, although it can be used to +heapify any value. + +Returns: Pointer to fully initialized value of type '@a', based on the value +passed in. + + generic alloc : ( -> @a#) + generic zalloc : ( -> @a#) + +`alloc` allocates or free a single element of type @a, respectively. `zalloc` +does the same, but zeros the memory allocated before returning it. `free` is +used to return the memory allocated by these functions to the system. In +general, `mk` is preferred over these functions, as it does not leave any +values uninitialized., + + generic slalloc : (len : size -> @a[:]) + generic slzalloc : (len : size -> @a[:]) + +`slalloc` allocates or frees a slice of `len` items of type @a. `slzalloc` +does the same, but zeros the memory allocated before returning it. `slfree` +is used to return the memory to the system. + + generic slgrow : (sl : @a[:]#, len : size -> @a[:]) + generic slzgrow : (sl : @a[:]#, len : size -> @a[:]) + +`slgrow` resizes the slize `sl` to length `len`, allocating the appropriate +amount of memory. `slzgrow` does the same, but any elements between the old +and new length are zeroed, as in slzalloc. + + generic free : (v:@a# -> void) + generic slfree : (sl : @a[:] -> void) + +`free` and `slfree` free the storage allocated allocated for the value or +slice passed to them , allowing it to be reused again later in the program. +This memory may be unmapped and returned to the operating system, or it may be +cached within the program. + +Any uses of memory after a `free` call is invalid. + + const bytealloc : (sz:size -> byte#) + const zbytealloc : (sz:size -> byte#) + const bytefree : (m:byte#, sz:size -> void) + +`bytealloc` `bytezalloc`, and `bytefree` are the low level raw-byte allocation +interface, returning blobs of bytes. Since the only way to use more than one +of these bytes is to cast to a different type, the generic versions are +generally a better choice. + +Examples +--------- + +Overall, the examples here should not be unfamiliar to anyone who has used +either C or C++. + +### Mk + +`std.mk` should be used to create new, fully constructed values wherever +possible. The code for this looks like: + +```{runmyr mk-example} +use std + +type mytype = + a : int + b : char + c : byte[:[ +;; + +const main = { + var v + + v = std.mk([ + .a = 123 + .b = 'x' + .c = "my string" /* this isn't heapified */ + ]) + + std.free(v) +} +``` + +### Alloc and Zalloc + +`alloc` and `zalloc` know the type that they're being assigned to, and use +this to calulate the size to allocate: + + +```{runmyr mk-example} +use std + +const main = { + var x : int# + var y : int# + + x = std.alloc() + y = std.zalloc() + std.free(x) + std.free(y) +} +``` + +### Slalloc and Slzalloc + +`slalloc` and `slzalloc` take a size to allocate, but infer the type similar +to `alloc` and `zalloc`. They're freed with std.slfree() and slzfree(). +Thankfully, unlike C++ delete and delete[], it's impossible to pass a slice +to the wrong free function. + + +```{runmyr mk-example} +use std + +const main = { + var x : int[:] + + x = std.slalloc(10) /* slice of 10 ints */ + std.slfree(x) +} +``` + +Growing slices can be done using slgrow() and slzgrow(): + +```{runmyr mk-example} +use std + +const main = { + var x : int[:] + + x = std.slalloc(10) /* slice of 10 ints */ + x = std.slzgrow(x, 20) /* x[10:20] are guaranteed to be zeroed.*/ + std.slfree(x) +} +``` diff --git a/doc/api/libstd/bigint.txt b/doc/api/libstd/bigint.txt new file mode 100644 index 0000000..dfcc180 --- /dev/null +++ b/doc/api/libstd/bigint.txt @@ -0,0 +1,208 @@ +{ + title: Bigints + description: libstd: Bigints +} + +Bigints +------- + + pkg std = + type bigint = struct + ;; + + generic mkbigint : (v : @a::(numeric,integral) -> bigint#) + const bigfree : (a : bigint# -> void) + const bigdup : (a : bigint# -> bigint#) + const bigassign : (d : bigint#, s : bigint# -> bigint#) + const bigmove : (d : bigint#, s : bigint# -> bigint#) + const bigparse : (s : byte[:] -> option(bigint#)) + const bigclear : (a : bigint# -> bigint#) + const bigbfmt : (b : byte[:], a : bigint#, base : int -> size) + const bigtoint : (a : bigint# -> @a::(numeric,integral)) + const bigiszero : (a : bigint# -> bool) + const bigeq : (a : bigint#, b : bigint# -> bool) + const bigcmp : (a : bigint#, b : bigint# -> order) + const bigadd : (a : bigint#, b : bigint# -> bigint#) + const bigsub : (a : bigint#, b : bigint# -> bigint#) + const bigmul : (a : bigint#, b : bigint# -> bigint#) + const bigdiv : (a : bigint#, b : bigint# -> bigint#) + const bigmod : (a : bigint#, b : bigint# -> bigint#) + const bigdivmod : (a : bigint#, b : bigint# -> (bigint#, bigint#)) + const bigshl : (a : bigint#, b : bigint# -> bigint#) + const bigshr : (a : bigint#, b : bigint# -> bigint#) + const bigmodpow : (b : bigint#, e : bigint#, m : bigint# -> bigint#) + const bigpow : (a : bigint#, b : bigint# -> bigint#) + generic bigeqi : (a : bigint#, b : @a::(numeric,integral) -> bool) + generic bigaddi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigsubi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigmuli : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigdivi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigshli : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigshri : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + const bigpowi : (a : bigint#, b : uint64 -> bigint#) + ;; + + +Overview +-------- + +While bigint usage in most programs is relatively rare, libstd needs them +internally for handling floats, and several other widely used pieces of +functionality also need them. + +This set of code covers the bulk of common big integer operations: Creation, +input, output, and various arithmetic operations + +By convention, with a few exceptions, all operations on bigintegers will +modify the bigint in place, and return a pointer to the first argument +of the function. This allows for easy chaining of operations. + +A formatter for bigintegers is installed by default, so `std.put("{}\n", +mybig)` will show a reasonably formatted big integer. The standard `x` +modifier is recognized to print the value in hex. + +Types +----- + + type bigint = struct + ;; + +This is a big integer. It stores big integers. Like it was an integer. But +bigger. + + + +Functions: Bookkeeping and IO +----------------------- + + generic mkbigint : (v : @a::(numeric,integral) -> bigint#) + +Mkbigint takes a regular small int, and creates a biginteger from that +value. It allocates the value on the heap, returning a pointer to the bigint +instance. This instance must be freed with `bigfree`. + + const bigfree : (a : bigint# -> void) + +Cleans up the storage associated with the bigint `a`. + + const bigdup : (a : bigint# -> bigint#) + +Bigdup creates a new biginteger, and copies the value from the original +biginteger `a` into it. It returns a new biginteger. + + const bigassign : (d : bigint#, s : bigint# -> bigint#) + +Bigassign copies the value of the bigint `s` to `d`, and returns +a pointer to `d`. No allocations or new values are created. + + const bigmove : (d : bigint#, s : bigint# -> bigint#) + +Bigmove clears the value of `d`, and moves the value from `s` into +it efficiently, tearing down the value of `s` in the process. It +returns a pointer to `d`. + +For example, if you had the `a=123` and `b=246`, then moving `a <= b`, +the final values would be `a = 246` and `b = 0`. + +No new values are allocated. + + const bigparse : (s : byte[:] -> option(bigint#)) + +Bigparse converts a string representation of an integer into a bigint, +returning `\`Some val` if the string is a valid bigint, or `\`None` otherwise. + +Decimal, hex, octal, and binary biginteger strings are recognized. Decimal +is the default, and is recognized unprefixed. Hex must be prefixed with `0x`, +octal must be prefixed with `0o`, and binary must be prefixed with `0b`. As +with all Myrddin integers, '_' is accepted and ignored within numerical +constants. + + const bigclear : (a : bigint# -> bigint#) + +Bigclear zeroes out a biginteger, returning it. + + const bigtoint : (a : bigint# -> @a::(numeric,integral)) + + +Bigtoint returns the low order digits of a bigint as an integer value. Care +must be taken when using this function to ensure that values are not +undesirably truncated. + +Functions: Arithmetic +--------------------- + + const bigiszero : (a : bigint# -> bool) + +Bigiszero checks if a bigint is zero, and returns true if it is, or false if +it is not. + + const bigeq : (a : bigint#, b : bigint# -> bool) + +Bigeq compares whether two integers are equal. + + const bigcmp : (a : bigint#, b : bigint# -> order) + +Bigcmp compares two big integers, and returns the ordering between them. +`\`Before` if a < b, `\`After` if a > b, and `\`Equal` if the two values +are equal. + + const bigadd : (a : bigint#, b : bigint# -> bigint#) + const bigsub : (a : bigint#, b : bigint# -> bigint#) + const bigmul : (a : bigint#, b : bigint# -> bigint#) + const bigdiv : (a : bigint#, b : bigint# -> bigint#) + const bigmod : (a : bigint#, b : bigint# -> bigint#) + const bigshl : (a : bigint#, b : bigint# -> bigint#) + const bigshr : (a : bigint#, b : bigint# -> bigint#) + const bigmodpow : (b : bigint#, e : bigint#, m : bigint# -> bigint#) + const bigpow : (a : bigint#, b : bigint# -> bigint#) + +All of these functions follow the convention mentioned in the summary: They +apply the operation `a = a OP b`, where `a` is the first argument, and `b` +is the second argument. They return `a`, without allocating a new result. + + const bigdivmod : (a : bigint#, b : bigint# -> (bigint#, bigint#)) + +Bigdivmod is an exception to the above convention. Because it needs to return +two values, it returns a tuple of newly allocated bigints. + + generic bigeqi : (a : bigint#, b : @a::(numeric,integral) -> bool) + generic bigaddi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigsubi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigmuli : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigdivi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigshli : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigshri : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + const bigpowi : (a : bigint#, b : uint64 -> bigint#) + +All of these are identical ot the bigint operations above, however instead of +taking a bigint for their second operand, they take an integer. This is useful +for when operations like multiplication or division by a small constant is +needed. + +Examples +-------- + +```{runmyr bigcmp} + +use std +use bio + +const main = {args : byte[:][:] + var f + + a = try(std.bigparse("1234_5678_1234_6789_6666_7777_8888")) + b = try(std.bigparse("0x75f3_fffc_1123_5ce4")) + + match std.bigcmp(a, b) + | `std.Equal: "{} is equal to {}\n", a, b) + | `std.Before: "{} is less than {}\n", a, b) + | `std.After: "{} is greater than {}\n", a, b) + ;; + + std.bigmul(a, b) + std.bigdivi(a, 42) + std.put("a * b / 42 = {}\n", a) + + std.bigfree(a, b) +} +``` diff --git a/doc/api/libstd/cli.txt b/doc/api/libstd/cli.txt new file mode 100644 index 0000000..b850a2a --- /dev/null +++ b/doc/api/libstd/cli.txt @@ -0,0 +1,290 @@ +{ + title: CLI Parsing + description: libstd: CLI Parsing +} + + +Command Line Parsing +-------------------- + +Command line parsing is something that nearly every program needs. This +section of libstd provides simple command line parsing with autogenerated +help. + + pkg std = + type optdef = struct + argdesc : byte[:] /* the description for the usage */ + minargs : std.size /* the minimum number of positional args */ + maxargs : std.size /* the maximum number of positional args (0 = unlimited) */ + noargs : std.bool /* whether we accept args at all */ + opts : optdesc[:] /* the description of the options */ + ;; + type optdesc = struct + opt : char + arg : byte[:] + desc : byte[:] + optional : bool + ;; + type optparsed = struct + opts : (char, byte[:])[:] + args : byte[:][:] + ;; + + const optparse : (optargs : byte[:][:], def : optdef# -> optparsed) + const optusage : (prog : byte[:], def : optdef# -> void) + ;; + +Syntax +------- + +A command line is composed of a list of words, known as. These arguments may +be options that the program can act on, known as "flags". These flags may take +up to one argument. To avoid confusing with the top level arguments, this +document will refer to them as "values". Anything that is not a flag is a +"positional argument", or simply an "argument". + +In general, the POSIX syntax for arguments is followed, with a few minor +enhancements. Myrddin program will use the following semantics for command +line options: + + - Arguments are groupls of flags if they follow a '-'. A flag is any + single unicode character, potentially followed by a single value. This + value may be optional. + - Flags that take values will consume the remainder of the argument as + the value. If the remainder of the argument is empty, then the next + argument is consumed as the value. For example, `-foo` and `-f oo` + are equivalent. + - Any flags that do not take arguments may be placed before other + flags within the same argument. For example, `-x -y -z` is equivalent + to `-xyz`, as long as `-x` and `-y` have no optional arguments. + - The first '--' stops flags from being recognized, and treats them + as arguments. + - Flags may be supplied in any order, intermingled with arguments, + and repeated as many times as desired. An unrecognized flag is an + error, and will trigger a usage message. + +Types +------ + +The API provided for command line parsing is relatively declarative, with the +options specified in a struct passed to the parsing. + + type optdef = struct + argdesc : byte[:] + minargs : std.size + maxargs : std.size + noargs : std.bool + opts : optdesc[:] + ;; + +The optdef is the top level structure describing the command line arguments. +It contains the following fields: + +<dl> + <dt><code>argdesc</code></dt> + <dd> + <p>Argdesc is a string describing the positional arguments passed to the + program. It doesn't change the way that the arguments are parsed, but is + used to document the arguments to the user.</p> + + <p>In general, this should be a summary of any expected argument. If a + variable number of them are expected, the argument should be followed + with a <code>...</code>.</p> + + <p>For example, a program that takes an output and a list of inputs may + provide the following for <code>argdesc</code>:</p> + + <p><code>"output inputs..."</code></p> + + <p>When the help string is generated, the output would look like:</p> + <p><code>myprog [-o option] output inputs...</code></p> + </dd> + + <dt><code>minargs</code></dt> + <dd> + <p>This argument limits the minimum number of arguments that the + program will accept without error. If at minimum 3 inputs are needed, for + example, then this value should be set to 3. This does not count flags, + nor does it count the program name.</p> + <p> If set to 0, this value is ignored. This is the default value.</p> + </dd> + + <dt><code>maxargs</code></dt> + <dd> + <p>This argument limits the maximum number of arguments that the program + will accept without error. If the program takes at most 1 argument, for + example, example, then this value should be set to 3. Just like + <code>maxargs</code>, this does not count flags or the program name. + </p> + <p> If set to 0, this value is ignored. This is the default value.</p> + </dd> + + <dt><code>noargs</code></dt> + <dd> + <p>This argument causes the program to reject any arguments at all.</p> + </dd> + <dt><code>opts</code></dt> + <dd><p>This is a list of descriptions of the options that this program + takes. This list may be empty, at which point this api still provides a + good way of checking that no invalid arguments are passed.</p> + </dd> +</dl> + + + type optdesc = struct + opt : char + arg : byte[:] + desc : byte[:] + optional : bool + ;; + +This is a description of a command line argument. It contains the following +fields to be set by the user: + +<dl> + <dt><code>opt</code></dt> + <dd> + <p>This is a single unicode character that is used for the option + flag.</p> + </dd> + <dt><code>arg</code></dt> + <dd> + <p>This is a single word description of the argument. If it is not present + or has zero length, this indicates that the flag takes no value. + Otherwise, the value is mandatory, unless the <code>optional</code> flag + is set.</p> + </dd> + <dt><code>optional</code></dt> + <dd> + <p>This is a boolean that allows for the value <code>arg</code> to be + optionally omitted when using the flag. It is disabled by default. + </p> + </dd> + <dt><code>desc</code></dt> + <dd> + <p>This is a short sentence describing <code>arg</code>. It has no + semantic effect on the option parsing, and is only used in generating + help output for the arguments. + </p> + </dd> +</dl> + + + type optparsed = struct + opts : (char, byte[:])[:] + args : byte[:][:] + prog : byte[:] + ;; + +This is the final result of parsing the options. The `opts` member contains a +list of options in the form of `(opt, val)` pairs. The option `opt` will be +repeated once for every time that the flag `opt` is seen within the command +line. + +If there is no value passed with the flag, then the string will be the empty +string. Otherwise, it will contain the string passed. + +The `args` member contains the arguments, collected for easy iteration, and the +`prog` member contains the binary name. + +Functions +---------- + + const optparse : (optargs : byte[:][:], def : optdef# -> optparsed) + +Optparse takes an array `optargs` containing the command line arguments passed +to the program, as well as an `optdef` pointer describing the expected +arguments, and spits out out an `optparsed`. The arguments `optargs` are +expected to contain the program name. + + const optusage : (prog : byte[:], def : optdef# -> void) + + +Optusage takes the string `prog` containing the program name, and an `def` +containing an `optdef` which describes the arguments to provide help for. It +prints these out on `stderr` (fd 1), and returns. + + +Examples: +-------- + +This example is a trivial one, which parses no flags, and merely +errors if given any. + + const main = {args + var cmd + + cmd = std.optparse(args, &[ + .argdesc = "vals", + ]) + for arg in cmd.args + std.put("arg: {}\n", arg) + ;; + } + +This example shows some more advanced usage, and is extracted from +mbld. + + const main = {args + var dumponly + var targname + var bintarg + var cmd + var libpath + + cmd = std.optparse(args, &[ + .argdesc = "[inputs...]", + .opts = [ + [.opt='t', .desc="list all available targets"], + [.opt='T', .arg="tag", .desc="build with specified systag"], + [.opt='S', .desc="generate assembly when building"], + [.opt='d', .desc="dump debugging information for mbld"], + [.opt='I', .arg="inc", .desc="add 'inc' to your include path"], + [.opt='R', .arg="root", .desc="install into 'root'"], + [.opt='b', .arg="bin", .desc="compile binary named 'bin' from inputs"], + [.opt='l', .arg="lib", .desc="compile lib named 'lib' from inputs"], + [.opt='r', .arg="rt", .desc="link against runtime 'rt' instead of default"], + [.opt='C', .arg="mc", .desc="compile with 'mc' instead of the default compiler"], + [.opt='M', .arg="mu", .desc="merge uses with 'mu' instead of the default muse"], + ][:] + ]) + targname = "" + tags = [][:] + for opt in cmd.opts + match opt + | ('t', ""): dumponly = true + | ('S', ""): bld.opt_genasm = true + | ('I', arg): bld.opt_incpaths = std.slpush(bld.opt_incpaths, arg) + | ('R', arg): bld.opt_instroot = arg + | ('T', tag): tags = std.slpush(tags, tag) + | ('b', arg): + targname = arg + bintarg = true + | ('l', arg): + targname = arg + bintarg = false + | ('r', arg): + if std.sleq(arg, "none") + bld.opt_runtime = "" + else + bld.opt_runtime = arg + ;; + /* + internal undocumented args; used by compiler suite for + building with an uninstalled compiler. + */ + | ('d', arg): bld.opt_debug = true + | ('C', arg): bld.opt_mc = arg + | ('M', arg): bld.opt_muse = arg + | _: std.die("unreachable\n") + + ;; + ;; + + for arg in cmd.args + /* build stuff */ + ;; + } + + + diff --git a/doc/api/libstd/datastruct.txt b/doc/api/libstd/datastruct.txt new file mode 100644 index 0000000..651cd0a --- /dev/null +++ b/doc/api/libstd/datastruct.txt @@ -0,0 +1,181 @@ +{ + title: Data Structures + description: libstd: Data Structures +} + + +Data Structures +---------------- + + pkg std = + type htab(@k, @v) = struct + ;; + + type bitset = struct + ;; + + /* hash tables */ + generic mkht : (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#) + generic htfree : (ht : htab(@k, @v)# -> void) + generic htput : (ht : htab(@k, @v)#, k : @k, v : @v -> void) + generic htdel : (ht : htab(@k, @v)#, k : @k -> void) + generic htget : (ht : htab(@k, @v)#, k : @k -> option(@v)) + generic htgetv : (ht : htab(@k, @v)#, k : @k, fallback : @v-> @v) + generic hthas : (ht : htab(@k, @v)#, k : @k -> bool) + generic htkeys : (ht : htab(@k, @v)# -> @k[:]) + + /* bit sets */ + const mkbs : (-> bitset#) + const bsdup : (bs : bitset# -> bitset#) + const bsfree : (bs : bitset# -> void) + const bsmax : (a : bitset# -> size) + generic bsput : (bs : bitset#, v : @a::(integral,numeric) -> bool) + generic bsdel : (bs : bitset#, v : @a::(integral,numeric) -> bool) + generic bshas : (bs : bitset#, v : @a::(integral,numeric) -> bool) + const bsdiff : (a : bitset#, b : bitset# -> void) + const bsintersect : (a : bitset#, b : bitset# -> void) + const bsunion : (a : bitset#, b : bitset# -> void) + const bseq : (a : bitset#, b : bitset# -> bool) + const bsissubset : (a : bitset#, b : bitset# -> bool) + const bsclear : (bs : bitset# -> bitset#) + + /* prepackaged hashing and equality tests */ + const strhash : (s : byte[:] -> uint32) + const streq : (a : byte[:], b : byte[:] -> bool) + generic ptrhash : (p : @a# -> uint32) + generic ptreq : (a : @a#, b : @a# -> bool) + generic inthash : (v : @a::(integral,numeric) -> uint32) + generic inteq : (a : @a::(integral,numeric), b : @a::(integral,numeric) -> bool) + generic slhash : (sl : @a[:] -> uint32) + ;; + +Hash Tables +----------- + +The need for key value lookup shows up everywhere, so libstd contains an +implementation of hash tables. + + type htab(@k, @v) = struct + ;; + +The hash table is a generic type which contains any key and any value. The +key used is `@k`, and the value is `@v`. + + generic mkht : (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#) + +Mkht creates a hash table on the heap. It accepts two functions, for hashing +and equality comparison. The hash table should be freed with `htfree`. + + generic htfree : (ht : htab(@k, @v)# -> void) + +Htfree frees a hash table and associated storage. The keys and values remain +untouched. + + generic htput : (ht : htab(@k, @v)#, k : @k, v : @v -> void) + +Inserts a key value pair into the hash table `ht`. If there is already a value +with the key `k`, then the key value pair will be replaced. + + generic htdel : (ht : htab(@k, @v)#, k : @k -> void) + +Removes a key value pair from the hash table `ht`. + + generic htget : (ht : htab(@k, @v)#, k : @k -> option(@v)) + +Looks up a value from a hash table, returning `\`Some v` if the key is +present, or `\`None` if the value is not present. + + generic htgetv : (ht : htab(@k, @v)#, k : @k, fallback : @v-> @v) + +Looks up a value from a hash table, returning the value if the key is +present, or `fallback` if it is not present. + + generic hthas : (ht : htab(@k, @v)#, k : @k -> bool) + +Looks up a value from a hash table, returning `true` if the key is +present, or `falase` if the value is not present. + + generic htkeys : (ht : htab(@k, @v)# -> @k[:]) + +Returns a list of all the keys present in the hash table. This list is +heap allocated, and must be freed with `slfree`. + + +Bit Sets +-------- + +The need for sets lookup shows up in many places, so libstd contains an +implementation of bit sets. Any numeric value can be put into the set, +and with the current API they may be freely intermixed [BUG?] + + type bitset = struct + ;; + +The bitset holds a set of integers. It works well for relatively dense, small +integers, as storage used is `O(max_value)`. + + const mkbs : (-> bitset#) + +Creates an empty bit set. The returned bit set should be freed with `bsfree`. + + const bsdup : (bs : bitset# -> bitset#) + +Duplicates an existing bit set. The returned bit set should be freed with +`bsfree`. + + const bsfree : (bs : bitset# -> void) + +Frees all resources associated with the bitset `bs`. + + const bsmax : (a : bitset# -> size) + +Returns the maximum value that the bitset contains. This is an approximation +of the capacity of the bitset, not a hard limit on the number of elements. + + const bscount : (a : bitset# -> size) + +Returns the total number of elements that the bitset contains. This is an +O(n) operation that involves iterating all of the bits. + + generic bsput : (bs : bitset#, v : @a::(integral,numeric) -> bool) + +Inserts the integer value `v` into the bit set `bs`. Returns `true` if this +operation changed the set, or `false` otherwise. + + generic bsdel : (bs : bitset#, v : @a::(integral,numeric) -> bool) + +Removes the integer value `v` from the bit set `bs`. Returns `true` if this +operation changed the set, or `false` otherwise. + + generic bshas : (bs : bitset#, v : @a::(integral,numeric) -> bool) + +Returns whether the bit set `bs` contains the value `v`. + + const bsdiff : (a : bitset#, b : bitset# -> void) + +Takes the set difference between `a` and `b`, storing the result back into +`a`. + + const bsintersect : (a : bitset#, b : bitset# -> void) + +Takes the set intersection between `a` and `b`, storing the result back into +`a`. + + const bsunion : (a : bitset#, b : bitset# -> void) + +Takes the set union between `a` and `b`, storing the result back into `a`. + + const bseq : (a : bitset#, b : bitset# -> bool) + +Tests whether the bitsets `a` and `b` contain the same elements, returning +`true` if they are equivalent and `false` otherwise. + + const bsissubset : (a : bitset#, b : bitset# -> bool) + +Tests whether every element of `b` is also within `a`, returning `true` if +`true` if `b` is a subset of `a`, and `false` otherwise. + + const bsclear : (bs : bitset# -> bitset#) + +Zeros every value within the bitset `bs`. This is equivalent to iterating +through it and deleting every element. diff --git a/doc/api/libstd/dns.txt b/doc/api/libstd/dns.txt new file mode 100644 index 0000000..86cf5f4 --- /dev/null +++ b/doc/api/libstd/dns.txt @@ -0,0 +1,102 @@ +{ + title: DNS + description: libstd: DNS +} + +Networking +---------- + + pkg std = + type rectype = union + `DnsA /* host address */ + `DnsNS /* authoritative name server */ + `DnsCNAME /* canonical name for an alias */ + `DnsSOA /* marks the start of a zone of authority */ + `DnsWKS /* well known service description */ + `DnsPTR /* domain name pointer */ + `DnsHINFO /* host information */ + `DnsMINFO /* mailbox or mail list information */ + `DnsMX /* mail exchange */ + `DnsTXT /* text strings */ + `DnsAAAA /* ipv6 host address */ + ;; + + type resolveerr = union + `Badhost + `Badsrv + `Badquery + `Badresp + ;; + + type hostinfo = struct + fam : sys.sockfam + stype : sys.socktype + ttl : uint32 + addr : netaddr + ;; + + const resolve : (host : byte[:] -> result(hostinfo[:], resolveerr)) + const resolvemx : (host : byte[:] -> result(hostinfo[:], resolveerr)) + const resolverec : (host : byte[:], t : rectype -> result(hostinfo[:], resolveerr)) + ;; + + +Data Types +---------- + + type rectype = union + `DnsA /* host address */ + `DnsNS /* authoritative name server */ + `DnsCNAME /* canonical name for an alias */ + `DnsSOA /* marks the start of a zone of authority */ + `DnsWKS /* well known service description */ + `DnsPTR /* domain name pointer */ + `DnsHINFO /* host information */ + `DnsMINFO /* mailbox or mail list information */ + `DnsMX /* mail exchange */ + `DnsTXT /* text strings */ + `DnsAAAA /* ipv6 host address */ + ;; + +This union contains all of the record types that we claim to know how to +resolve. At the moment, few of them have been tested sufficiently (only A +records can reasonably be said to be exercised). + + type resolveerr = union + `Badhost + `Badsrv + `Badquery + `Badresp + ;; + +This union contains the errors that we can encounter when trying to resolve a +host. + + type hostinfo = struct + fam : sys.sockfam + stype : sys.socktype + ttl : uint32 + addr : netaddr + ;; + +DNS Resolution +-------------- + + const resolve : (host : byte[:] -> result(hostinfo[:], resolveerr)) + +Resolves the A or AAAA record for the host `host` using DNS. This function +does caching, expiring based on the TTL. Returns all of the host info entries sent +back by DNS or found in the cache on success, or a resolve error on failure. + + const resolvemx : (host : byte[:] -> result(hostinfo[:], resolveerr)) + +Resolves the MX record for the host `host` using DNS. This function does +caching, expiring based on the TTL. Returns all of the host info entries sent +back by DNS or found in the cache on success, or a resolve error on failure. + + const resolverec : (host : byte[:], t : rectype -> result(hostinfo[:], resolveerr)) + +Resolves a record from DNS. This function's interface is slightly broken, as +it will never work for TXT or CNAME records. + + diff --git a/doc/api/libstd/err.txt b/doc/api/libstd/err.txt new file mode 100644 index 0000000..53904e7 --- /dev/null +++ b/doc/api/libstd/err.txt @@ -0,0 +1,116 @@ +{ + title: Error Handling + description: libstd: Error Handling +} + + +Error Handling +-------------- + + pkg std = + type option(@a) = union + `Some @a + `None + ;; + + type result(@a, @b) = union + `Ok @a + `Fail @b + ;; + + $noret const fatalv : (fmt : byte[:], ap : valist# -> void) + $noret const fatal : (fmt : byte[:], args : ... -> void) + const assert : (cond : bool, fmt : byte[:], args : ... -> void) + const die : (msg : byte[:] -> void) + const suicide : ( -> void) + + generic try : (v : result(@a, @b) -> @a) + generic tryv : (v : result(@a, @b), d : @a -> @a) + generic get : (v : option(@a) -> @a) + generic getv : (v : option(@a), d : @a -> @a) + ;; + +Overview +-------- + +Myrddin does not have exceptions. By convention, code will abort on +programmer errors, such as passing invalid values where valid ones +were expected -- for example, calling `std.fmt("{}")` with the wrong +number of arguments int the list. + +For recoverable error conditions that depend on the environment, and +not the developer making a mistake, one of the branched return types +are conventionally used. + +For conditions where something can be either present or not, the `option(@a)` +type is used. For places where there can be either a result or an error, the +`result(@a, @e)` type is used. + +Generally, by convention, the type returned for the result should have a +custom that converts it to something directly displayable to the user. + +Types +----- + + type option(@a) = union + `Some @a + `None + ;; + +As mentioned in the overview, `option(@a)` is a type that wraps up a result +and error type. It is typically used in places where a missing value is the +only exceptional condition. + + type result(@a, @b) = union + `Ok @a + `Fail @b + ;; + + +The type `result(@a, @e)` is used to signal either success or an error +condition. The first type parameter, `@a` is what is returned on success, +and the second, `@b` is returned on failure. + + +Functions +--------- + $noret const fatalv : (fmt : byte[:], ap : valist# -> void) + $noret const fatal : (fmt : byte[:], args : ... -> void) + +Both fatal and fatalv exit the program with an error message, formatted as +in `std.fmt`. They do not return. + +They exit with a failure status. On Unix, this status is `1`. On Plan 9, +the status is the failure message that it prints out before exiting. + + const assert : (cond : bool, fmt : byte[:], args : ... -> void) + +Assert checks that condition is true. If it is not true, then the message +is printed as in `std.fmt`, and the program is aborted with `suicide()`. + + const suicide : ( -> void) + +Suicide aborts a program. It does not print any message, it simply sends +the program a SIGABRT or segfaults it. All threads are terminated, and the +program goes away. + + generic try : (v : result(@a, @b) -> @a) + generic get : (v : option(@a) -> @a) + +Try and get both return the value from the successful branch of their type: +`try` returns the value contained in `\`std.Ok`, and `get` returns the value +in `\`std.Some`. + +If this does not match the union, a diagnostic message is printed and the +program is aborted. + + generic tryv : (v : result(@a, @b), default : @a -> @a) + generic getv : (v : option(@a), default : @a -> @a) + +Try and get both return the value from the successful branch of their type: +`try` returns the value contained in `\`std.Ok`, and `get` returns the value +in `\`std.Some`. + +If this does not match the union, the default value is returned to the +caller, as though the type had contained `\`Some default` or `\`Ok default` + diff --git a/doc/api/libstd/files.txt b/doc/api/libstd/files.txt new file mode 100644 index 0000000..f75e765 --- /dev/null +++ b/doc/api/libstd/files.txt @@ -0,0 +1,369 @@ +{ + title: File Handling + description: libstd: File Handling +} + +File Handling +------------- + + + pkg std = + type dir = struct + ;; + + /* seek options */ + const Seekset : whence + const Seekcur : whence + const Seekend : whence + + /* open options */ + const Ordonly : fdopt + const Owronly : fdopt + const Ordwr : fdopt + const Otrunc : fdopt + const Ocreat : fdopt + const Oappend : fdopt + const Odir : fdopt + + /* directory handling */ + const diropen : (p : byte[:] -> std.result(dir#, byte[:])) + const dirread : (d : dir# -> std.option(byte[:])) + const dirclose : (d : dir# -> void) + const dirname : (p : byte[:] -> byte[:]) + const mkdir : (path : byte[:], mode : int64 -> int64) + const mkpath : (p : byte[:] -> bool) + const chdir : (path : byte[:] -> bool) + + /* file handling */ + const open : (path : byte[:], opts : fdopt -> std.result(fd, errno)) + const openmode : (path : byte[:], opts : fdopt, mode : int64 -> std.result(fd, errno)) + const mktemp : (base : byte[:], opts : fdopt, mode : int64 -> std.result((fd, byte[:]), errno) + const close : (fd : fd -> int64) + const creat : (path : byte[:], mode : int64 -> fd) + const read : (fd : fd, buf : byte[:] -> size) + const write : (fd : fd, buf : byte[:] -> size) + const seek : (fd : fd, delta : off, whence : whence -> off) + const pipe : (fds : fd[2]# -> int64) + const dup2 : (ofd : fd, nfd : fd -> fd) + const remove : (path : byte[:] -> bool) + const unlink : (path : byte[:] -> int) + + /* path manipulation */ + const basename : (p : byte[:] -> byte[:]) + const pathcat : (a : byte[:], b : byte[:] -> byte[:]) + const pathjoin : (p : byte[:][:] -> byte[:]) + const pathnorm : (p : byte[:] -> byte[:]) + const getcwd : (-> byte[:]) + + /* file properties */ + const fmtime : (f : byte[:] -> result(time, errno)) + const fsize : (f : byte[:] -> result(off, errno)) + const fexists : (f : byte[:] -> bool) + const fisdir : (f : byte[:] -> bool) + + /* convenience functions */ + const slurp : (path : byte[:] -> result(byte[:], byte[:])) + const fslurp : (path : fd -> result(byte[:], byte[:])) + const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool) + const fblat : (f : fd, buf : byte[:] -> bool) + ;; + + +Data Types and Constants +------------------------ + +Libstd's file APIs are generally relatively thin wrappers around the host OS +functions. They are a portable subset of this functionality, designed for both +ease of use and portability. + + type dir = struct + ;; + +The directory struct represents the current state of a directory walk. + + /* seek options */ + const Seekset : whence + const Seekcur : whence + const Seekend : whence + +These are a set of values which describe from where to seek within the file. + + /* open options */ + const Oread : fdopt + const Owrite : fdopt + const Ordwr : fdopt + const Otrunc : fdopt + const Ocreat : fdopt + +These are a set of options that are passed to the open variants describing +what mode to open the file in. These are bit masks which be OR'ed together to +combine them. + +`Oread` and `Owrite` request permission to read and write the file, respectively. +`Ordwr` is a convenience flag which ors read and write together. `Otrunc` +indicates that the file should be truncated to zero bytes in length before it +is opened. `Ocreat` indicates that the file should be created if it does not +exist instead of returning an error. `Odir` indicates that this file should +be opened as a directory. + +`Ocreat` does not create the path leading to it, and will return an error if +that path does not exist. + + +Directories +----------- + + const diropen : (p : byte[:] -> std.result(dir#, byte[:])) + +The `diropen` function opens a path as a directory, and returns a pointer +to an object which tracks the state of the directory, allowing for reading +file names one by one from this directory. + +Returns: Either a directory wrapped up in the `\`Ok` branch of the result, +or a string describing the failure reason in the `\`Fail` branch. + + const dirread : (d : dir# -> result(option(byte[:]), errno) + +The `dirread` reads a single entry from the directory, opened with `diropen`, +returning it as a string. + +Returns `\`Some entry`, or `\`None` at the end of the directory. + + const dirclose : (d : dir# -> void) + +`dirclose` closes a directory for reading. This frees all associated +resources, returning them to the system. The directory passed in must have +been opened with `diropen`. + +Returns: Nothing. + + const mkdir : (path : byte[:], mode : int64 -> errno) + +`mkdir` creates the directory specified in `path`. with the mode `mode`. It +requires the parent directory to exist and be writable. Absolute paths will +be created relative to the root of the file system, and relative paths will +be created relative to the current working directory, as usual. + +If the directory already exists, this is counted as a failure to create the +directory. + +Returns: Enone on success, or the error that caused the failure if it fails. + + const mkpath : (path : byte[:] -> errno) + +`mkpath` creates a full path specified by `path`. It creates all of the +path components required to create the full path specified. It requires +the parent of the first directory entry that is not currently in existence +to be writable. + +Absolute paths will be created relative to the root of the file system, and +relative paths will be created relative to the current working directory, as +usual. + +Returns: Enone on success, or the error that caused the directory creation +to fail on failure. + + const chdir : (path : byte[:] -> bool) + +Chdir changes the current working directory to the path specified in `path`. + +Returns: True on success, false on failure. + +Files +----- + + const open : (path : byte[:], opts : fdopt -> result(fd, errno)) + const openmode : (path : byte[:], opts : fdopt, mode : int64 -> result(fd, errno)) + +Open opens the file `path` for I/O according to the flags reqeusted in `opts`, +and returns a result containing the file descriptor or error. The mode is a +combination of the modes specified above: `Oread`, `Owrite`, `Ordwr`, +`Otrunc`, or `Ocreat`. + +Openmode is similar to open, however, if Ocreate is passed, it the file +requested will be created with the permissions passed in. + +Returns: either a valid file descriptor on success, or an error describing why +the open failed on failure. + + const mktemp : (base : byte[:], opts : fdopt, mode : int64 -> std.result((fd, byte[:]), errno) + +Mktemp is similar to openmode, however instead of taking a full path as +its first argument, it generates a unique name for a file in temporary +storage by appending a random string to the base name `base`. The mode +provided is in addition to the implicit Ocreat | Oexcl. + +Returns: Either a successful result containing the tuple of file descriptor +opened and path generated, or an error describing the failure. The path +is allocated with `std.slalloc`, and must be freed by the caller using +`std.slfree`. The file descriptor must be closed as ususal. + + + const close : (fd : fd -> void) + +Closes closes the file descriptor. If the file descriptor is valid, close +is guaranteed to close it. If it is not valid, this is a no-op. + + const read : (fd : fd, buf : byte[:] -> result(size, errno)) + +Reads up to the length of `buf` from the file descriptor `fd`, at the current +offset within the file, advancing the offset by the count of bytes read. The +buffer may not be filled entirely when the read completes. For example, when +reading from a console, often only one line will be returned at a time. + +Conventionally, `0` bytes are returned at the end of the file. + +Returns: Either the number of bytes read on success, or the error that caused +a failure reading on failure. + + const write : (fd : fd, buf : byte[:] -> result(size, errno)) + +Write writes up to the length of `buf` to the file descriptor, writing the +bytes at the current offset. The offset is advanced by the number of bytes +that were written, extending the file size if necessary. Write is not +guaranteed to write the full buffer. + +Returns: The number of bytes written on success, or the error that caused +the failure on error. + + const seek : (fd : fd, delta : off, whence : whence -> result(off, errno)) + +Seek changes the current offset within the file descriptor `fd` by `delta`. +This delta can be treated in three different ways, depending on the value of +`whence. + +If `whence` is Seekset, then `delta` is treated as an absolute value to seek +to, and the offset is set to `delta`. If `whence` is `Seekcur`, then `delta` +is added to the current offset. If `whence` is `Seekend`, then `delta` is +added to the size of the file. + +Returns: Either the new offset within the file on success, or the error that +occurred on failure. + + const pipe : (fds : fd[2]# -> errno) + +Pipe creates a unidirectional channel for communication between processes. +Two file descriptors are returned in the array fd. Data written to fd[1] is +available in fd[0]. The pipe may or may not be buffered. + +Returns: Enone on success, otherwise, returns the error that caused this +call to fail. + + const dup2 : (ofd : fd, nfd : fd -> result(fd, errno)) + +Dup2 copies the old fd `ofd` to the new fd `nfd`. If the file descriptor +`nfd` is already open, then it is implicitly closed by this call before +the fd is copied. This is done atomically. + +Returns: Either the new fd used, on success, or an error describing the +failure. + + const remove : (path : byte[:] -> errno) + +Remove removes the file specified from the directory in which it is contained. +The user must have write permissions for the directory in order to remove +files from it. If `path` is a directory, it must be empty. + +Returns: Enone on success, otherwise the error that caused the failure. + +Path Manipulation +----------------- + const basename : (p : byte[:] -> byte[:]) + const dirname : (p : byte[:] -> byte[:]) + +Given a string of the form "foo/bar/baz", `dirname()` returns the directory +component of it -- in other words, everything up to the final `/`. It ignores +trailing slashes. It + +The caller is responsible for freeing the path with `slfree`. + +For example, `dirname("foo/bar//")` will return `"foo/bar"`. + + const pathcat : (a : byte[:], b : byte[:] -> byte[:]) + +Pathcat joins two paths together, using '/' as a directory +separator. The paths are normalized before being returned. This +call is shorthand for `std.pathjoin([a, b][:])`. + +The caller is responsible for freeing the path with `slfree`. + +Returns: A concatenated path. + + const pathjoin : (p : byte[:][:] -> byte[:]) + +Pathcat joins a list of paths together, using '/' as a directory +separator. The paths are normalized before being returned. This +call is shorthand for `std.pathjoin([a, b][:])`. + +The caller is responsible for freeing the path with `slfree`. + +Returns: A concatenated path. + + const pathnorm : (p : byte[:] -> byte[:]) + +Pathnorm does a purely lexical normalization of the path. It removes +redundant components, doubled `/` characters, and similar. The returned +path is equivalent to the original input path. + +The caller is responsible for freeing the path with `slfree`. + +Returns: A new normalized path. + + const getcwd : (-> byte[:]) + +Returns the current working directory of the program. The caller is +responsible for freeing the path with `slfree`. + +Returns: A string representing the working directory. + +File Properties +--------------- + + const fmtime : (f : byte[:] -> result(time, errno)) + +Returns either the last modification time of the file `f`, or +the error that was encountered extracting this information. + + const fsize : (f : byte[:] -> result(off, errno)) + +Returns either the size in bytes of the file `f`, or +the error that was encountered extracting this information. + + const fexists : (f : byte[:] -> bool) + +Returns `true` if the file is able to be `stat`ed, or `false` +if this fails. + + const fisdir : (f : byte[:] -> bool) + +Returns `true` if the file is a directory that is able to be `stat`ed, or +`false` if this fails. + +Convenience Functions +--------------------- + + const slurp : (path : byte[:] -> result(byte[:], errno)) + +Reads all bytes from `path` until the end of file. + +Returns either the file data, or the failure encountered. + + const fslurp : (fd : fd -> result(byte[:], errno)) + +Reads all bytes from the file descriptor `fd` until the end of file. + +Returns either the file data, or the failure encountered. + + const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool) + +Creates the file `path` with permissions `perm`, and writes as much of +`buf` as it can into it. + +Returns Enone if no errors were encountered. Otherwise, the error is returned. + + const fblat : (f : fd, buf : byte[:] -> bool) + +Writes as much of `buf` as it can into the file descriptor `fd`. + +Returns Enone if no errors were encountered. Otherwise, the error is returned. + diff --git a/doc/api/libstd/fmt.txt b/doc/api/libstd/fmt.txt new file mode 100644 index 0000000..40f1b3f --- /dev/null +++ b/doc/api/libstd/fmt.txt @@ -0,0 +1,201 @@ +{ + title: Formatted I/O + description: libstd: Formatted I/O +} + + + +Formatted I/O +------- + + pkg std = + /* output to file descriptors */ + const put : (fmt : byte[:], args : ... -> size) + const fput : (fd : fd, fmt : byte[:], args : ... -> size) + const putv : (fmt : byte[:], ap : valist# -> size) + const fputv : (fd : fd, fmt : byte[:], ap : valist# -> size) + + /* formatting values */ + const fmt : (fmt : byte[:], args : ... -> byte[:]) + const fmtv : (fmt : byte[:], ap : valist# -> byte[:]) + const bfmt : (buf : byte[:], fmt : byte[:], args : ... -> byte[:]) + const bfmtv : (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:]) + const sbfmt : (buf : strbuf#, fmt : byte[:], args : ... -> size) + const sbfmtv : (buf : strbuf#, fmt : byte[:], ap : valist# -> size) + + /* custom formatting */ + const fmtinstall : (ty : byte[:], \ + fn : (sb : strbuf#, \ + ap : valist#, \ + opts : (byte[:],byte[:])[:] \ + -> void), \ + optdesc : (byte[:], bool)[:] \ + -> void) + ;; + + +Overview +-------- + +Formatting in Myrddin is done with format strings. These are effectively +dynamically typed at runtime, using introspection to decide the best way to +format a type. Custom formatters are allowed and encouraged. + +Formatting is specified with a `{}` pair, with any specifiers describing the +formatting passed in as a comma separated set of key value pairs. For example, +an integer can be padded with zeros and formatted in hex with the following +format specifier: `{p=0,x}`. If you want a literal '{' character, it can +be escaped by doubling it. + +None of the format specifiers print a newline character by default. + +Format Specifiers +-------------------------- + +The set of specifiers for the default types is sparse, and is fully +specified below. + +<dl> + <dt>w=WIDTH</dt> + <dd><p>Fill out to at least width WIDTH, filling with pad + characters.</p></dd> + + <dt>p=PAD</dt> + <dd> + <p>Fill spare width with this character. Defaults to a space + character.</p> </dd> + + <dt>x</dt> + <dd> + <p>Format in hex. This is only valid for integer types.</p> + </dd> + + <dt>j=joiner</dt> + <dd> + <p>Join slices with the joiner string. This leaves off the square + brackets from the ends, and replaces the default joiner string ", ". + </p> + </dd> +</dl> + +Specifiers can be installed by custom specifiers, and can be any +arbitrary set of strings. + +Functions +--------- + +All the format functions come in two variants: A variadic one, and one +that takes a variadic argument list. The latter is present for ease of +chaining from within a variadic function. + + const put : (fmt : byte[:], args : ... -> size) + const fput : (fd : fd, fmt : byte[:], args : ... -> size) + const putv : (fmt : byte[:], ap : valist# -> size) + const fputv : (fd : fd, fmt : byte[:], ap : valist# -> size) + +The `put` set of functions will format and output to a file descriptor. For +`put` and `putv`, the file descriptor is stdout. For `fput` and `fputv`, the +file descriptor is the one that is provided. + +These functions write immediately, and do not buffer, although they do attempt +to do their writing in a single system call, and will only split the call if +the kernel indicates short writes. + +The `v` variants will take a variadic argument list for printing. + +Returns: the number of bytes written to the file descriptor. + + const sbfmt : (buf : strbuf#, fmt : byte[:], args : ... -> size) + const sbfmtv : (buf : strbuf#, fmt : byte[:], ap : valist# -> size) + +The sbfmt functions will append to a string buffer, instead of writing to an +output stream, but are otherwise similar to the `fmt` functions. These +functions will return the number of bytes formatted. If the string buffer is +statically sized, and gets filled, the truncated size will be returned. + + const fmt : (fmt : byte[:], args : ... -> byte[:]) + const fmtv : (fmt : byte[:], ap : valist# -> byte[:]) + +These functions will format according to the format string, and return a +freshly allocated string containing the formatted string. This string should +be freed with `slfree`. + + const bfmt : (buf : byte[:], fmt : byte[:], args : ... -> byte[:]) + const bfmtv : (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:]) + +These functions will format according to the format string, putting the result +into `buf`. They return a slice into the buffer array. + + const fmtinstall : (ty : byte[:], \ + fn : (sb : strbuf#, + ap : valist#, \ + opts : (byte[:],byte[:])[:] \ + -> void), \ + optdesc : (byte[:], bool)[:] \ + -> void) + +Fmtinstall installs a custom formatter for a type. The type `ty` is a type +description that you would want to format. It can be obtained +using `std.typeof(var)`, `fn` is a function that handles custom formatting, +and `optdesc` is a list of options that this custom formater takes. It is +in the form a list of strings -- the argument names -- and booleans that +define whether these arguments take values. + + +The custom formatter takes a string buffer `sb` which you are expected to +format the custom input into, as well as a valist that you are expected to +pull the value from. Finally, it takes an option list. + +If a formatter is already installed for a type, it is replaced. + +Examples +-------- + +This example demonstrates a bunch of formatting using the std.format API. It +covers all of the various format specifiers, escaping, as well as showing the +formatting of complex types. + +```{runmyr fmtsimple} +use std + +const main = { + /* default formats */ + std.put("{} {}\n", "abcd", 123) + std.put("{}\n", [1,2,3][:]) + std.put("{}\n", (1,"foo")) + + /* mix in some format options */ + std.put("{w=10}\n", "abcd") + std.put("{p=0,w=10}\n", "abcdefghijkl") + std.put("{w=10,x}\n", 10) + std.put("{p=0,w=10}\n", 10) + + /* and now some escaping */ + std.put("{}bar{}\n", "foo\n", "baz") + std.put("{{}}bar{}\n", "baz") + std.put("{{bar{}}}\n", "baz") +} +``` + +This example shows how you would set up a + +```{runmyr customfmt} +use std + +const main = { + var x : int = 0 /* dummy: used for typeof */ + + std.fmtinstall(std.typeof(x), goaway, [][:]) + std.put("custom format: {}\n", 0x41) +} + +const goaway = {sb, ap, opts + var i : int64 + + i = std.vanext(ap) + std.sbfmt(sb, "go away! char val={}\n", i castto(char)) +} +``` + + + diff --git a/doc/api/libstd/index.txt b/doc/api/libstd/index.txt new file mode 100644 index 0000000..f154f09 --- /dev/null +++ b/doc/api/libstd/index.txt @@ -0,0 +1,711 @@ +{ + title: libstd + description: libstd: Summary +} + +Libstd Summary +--------------- + +This is a summary page listing all of the functions and types available +in libstd, sorted by category. The library is a bit of a grab bag of +functionality, but a good chunk of what is needed will be built in to +the library. + + +#### [Memory Allocation](alloc) + +Memory allocation is a function that nearly every program needs +to be able to do. Myrddin's generics allow for relatively easy +to use and typesafe functions for this to be written. + + pkg std = + generic mk : (val : @a -> @a#) + generic alloc : ( -> @a#) + generic zalloc : ( -> @a#) + generic free : (v:@a# -> void) + generic slalloc : (len : size -> @a[:]) + generic slzalloc : (len : size -> @a[:]) + generic slgrow : (sl : @a[:]#, len : size -> @a[:]) + generic slzgrow : (sl : @a[:]#, len : size -> @a[:]) + generic slfree : (sl : @a[:] -> void) + const bytealloc : (sz:size -> byte#) + const zbytealloc : (sz:size -> byte#) + const bytefree : (m:byte#, sz:size -> void) + ;; + +#### [Error Handling](err) + +Myrddin provides a number of types and operations for propagating errors +for later handling. + +It also provides operations for throwing up your hands, setting yourself on +fire, and screaming, if that's more appropriate. + + pkg std = + type option(@a) = union + `Some @a + `None + ;; + pkg std = + type result(@a, @b) = union + `Ok @a + `Fail @b + ;; + ;; + + $noret const fatalv : (fmt : byte[:], ap : valist# -> void) + $noret const fatal : (fmt : byte[:], args : ... -> void) + const assert : (cond : bool, fmt : byte[:], args : ... -> void) + const suicide : ( -> void) + + generic try : (v : result(@a, @b) -> @a) + generic tryv : (v : result(@a, @b), d : @a -> @a) + generic get : (v : option(@a) -> @a) + generic getv : (v : option(@a), d : @a -> @a) + ;; + +#### [OS Interfaces](os) + +The OS interfaces cover some portable primitives for handling processes +and OS errors. It restricts itself to a set of portable wrappers for OS +functionality. + +For complete interfaces, the `sys` library is your friend, providing +all OS functionality that can be provided. + + pkg std = + type sysinfo = struct + system : byte[:] + version : byte[:] + release : byte[:] + arch : byte[:] + uname : sys.utsname /* storage */ + ;; + + type waitstatus = union + `Wsuccess + `Wfailure + `Wsignalled + `Waiterror + ;; + + const Enone : errno + const Erange : errno + const Ebadf : errno + const Eexist : errno + const Einval : errno + const Efault : errno + const Eio : errno + const Emisc : errno + + const getsysinfo : (si : sysinfo# -> void) + const execvp : (cmd : byte[:], args : byte[:][:] -> int64) + const execvpe : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64) + const getenv : (name : byte[:] -> option(byte[:])) + const getenvv : (name : byte[:], default : byte[:] -> byte[:]) + const getpid : ( -> pid) + const fork : (-> pid) + const exec : (cmd : byte[:], args : byte[:][:] -> int64) + const execve : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64) + const waitpid : (pid:pid, loc:int32#, opt : int64 -> int64) + const spork : (cmd : byte[:][:] -> result((pid, fd, fd), int)) + const sporkfd : (cmd : byte[:][:], infd : fd, outfd : fd -> result(pid, int)) + const exit : (status:int -> void) + const wait : (pid : pid -> waitstatus) + ;; + +#### [File Handling](files) + +Many programs do file i/o by default. This package provides a portable +interface to the common subset that most programs need and most OSes provide. + + pkg std = + type dir = struct + ;; + + /* seek options */ + const Seekset : whence + const Seekcur : whence + const Seekend : whence + + /* open options */ + const Ordonly : fdopt + const Owronly : fdopt + const Ordwr : fdopt + const Otrunc : fdopt + const Ocreat : fdopt + const Oappend : fdopt + const Odir : fdopt + + /* directory handling */ + const diropen : (p : byte[:] -> std.result(dir#, byte[:])) + const dirread : (d : dir# -> std.option(byte[:])) + const dirclose : (d : dir# -> void) + const dirname : (p : byte[:] -> byte[:]) + const mkdir : (path : byte[:], mode : int64 -> int64) + const mkpath : (p : byte[:] -> bool) + const chdir : (path : byte[:] -> bool) + + /* file handling */ + const open : (path : byte[:], opts : fdopt -> fd) + const openmode : (path : byte[:], opts : fdopt, mode : int64 -> fd) + const close : (fd : fd -> int64) + const creat : (path : byte[:], mode : int64 -> fd) + const read : (fd : fd, buf : byte[:] -> size) + const write : (fd : fd, buf : byte[:] -> size) + const seek : (fd : fd, delta : off, whence : whence -> off) + const pipe : (fds : fd[2]# -> int64) + const dup2 : (ofd : fd, nfd : fd -> fd) + const remove : (path : byte[:] -> bool) + const unlink : (path : byte[:] -> int) + + /* path manipulation */ + const basename : (p : byte[:] -> byte[:]) + const pathcat : (a : byte[:], b : byte[:] -> byte[:]) + const pathjoin : (p : byte[:][:] -> byte[:]) + const pathnorm : (p : byte[:] -> byte[:]) + const getcwd : (-> byte[:]) + + /* file properties */ + const fmtime : (f : byte[:] -> option(time)) + const fsize : (f : byte[:] -> option(off)) + const fexists : (f : byte[:] -> bool) + const fisdir : (f : byte[:] -> bool) + + /* convenience functions */ + const slurp : (path : byte[:] -> result(byte[:], byte[:])) + const fslurp : (path : fd -> result(byte[:], byte[:])) + const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool) + const fblat : (f : fd, buf : byte[:] -> bool) + ;; + +#### [Networking](networking) + +The networking related functionality in libstd provides the ability to +quickly and easily open file descriptors to a server, as well as to +resolve servers and handle IP parsing. + +Currently, there is a large hole in functionality for announcing and +serving, where raw system specific network APIs neeed to be used +from the `sys` library. + + pkg std = + type rectype = union + `DnsA /* host address */ + `DnsNS /* authoritative name server */ + `DnsCNAME /* canonical name for an alias */ + `DnsSOA /* marks the start of a zone of authority */ + `DnsWKS /* well known service description */ + `DnsPTR /* domain name pointer */ + `DnsHINFO /* host information */ + `DnsMINFO /* mailbox or mail list information */ + `DnsMX /* mail exchange */ + `DnsTXT /* text strings */ + `DnsAAAA /* ipv6 host address */ + ;; + + type resolveerr = union + `Badhost + `Badsrv + `Badquery + `Badresp + ;; + + type hostinfo = struct + fam : sys.sockfam + stype : sys.socktype + ttl : uint32 + addr : ipaddr + ;; + + type ipaddr = union + `Ipv4 byte[4] + `Ipv6 byte[16] + ;; + + /* network connections */ + const dial : (dialstr : byte[:] -> result(fd, byte[:])) + const resolve : (host : byte[:] -> result(hostinfo[:], resolveerr)) + const resolvemx : (host : byte[:] -> result(hostinfo[:], resolveerr)) + const resolverec : (host : byte[:], t : rectype -> result(hostinfo[:], resolveerr)) + + /* ip parsing */ + const ipparse : (ip : byte[:] -> option(ipaddr)) + const ip4parse : (ip : byte[:] -> option(ipaddr)) + const ip6parse : (ip : byte[:] -> option(ipaddr)) + + generic hosttonet : (v : @a -> @a) + generic nettohost : (v : @a -> @a) + ;; + +#### [Command Line Parsing](cli) + +Simple command line parsing is offered, designed to meet the needs of most +programs quickly and easily. There isn't much to say here. + + pkg std = + type optdef = struct + argdesc : byte[:] /* the description for the usage */ + minargs : std.size /* the minimum number of positional args */ + maxargs : std.size /* the maximum number of positional args (0 = unlimited) */ + noargs : std.bool /* whether we accept args at all */ + opts : optdesc[:] /* the description of the options */ + ;; + type optdesc = struct + opt : char + arg : byte[:] + desc : byte[:] + optional : bool + ;; + type optparsed = struct + opts : (char, byte[:])[:] + args : byte[:][:] + ;; + + const optparse : (optargs : byte[:][:], def : optdef# -> optparsed) + const optusage : (prog : byte[:], def : optdef# -> void) + ;; + +#### [Formatted Output](fmt) + +libstd supports a number of simple, easy to use formatting functions, +which can provide a sane format for any type out of the box, but also +support custom formatters for specific types, so that they can be pretty +printed. Many of the builtin types, such as bigints, install custom +formatters by default. + + pkg std = + /* output to file descriptors */ + const put : (fmt : byte[:], args : ... -> size) + const fput : (fd : fd, fmt : byte[:], args : ... -> size) + const putv : (fmt : byte[:], ap : valist# -> size) + const fputv : (fd : fd, fmt : byte[:], ap : valist# -> size) + + /* formatting values */ + const fmt : (fmt : byte[:], args : ... -> byte[:]) + const fmtv : (fmt : byte[:], ap : valist# -> byte[:]) + const bfmt : (buf : byte[:], fmt : byte[:], args : ... -> byte[:]) + const bfmtv : (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:]) + const sbfmt : (buf : strbuf#, fmt : byte[:], args : ... -> size) + const sbfmtv : (buf : strbuf#, fmt : byte[:], ap : valist# -> size) + + /* custom formatting */ + const fmtinstall : (ty : byte[:], \ + fn : (sb : strbuf#, \ + ap : valist#, \ + opts : (byte[:],byte[:])[:] \ + -> void), \ + optdesc : (byte[:], bool)[:] \ + -> void) + ;; + +#### [Iteration Utilities](iterutil) + +Support for some common iteration patterns is provided. There are many kinds +of iteration that are done, and some of the most common ones are directly +supported by libstd. + +There are a few syntactic(!) issues in the language preventing these from +taking arbitrary iterators as parameters, but when this is resolved, that +restriction will be lifted. + + pkg std = + type zipiter(@a, @b) + type reverseiter(@a) + type enumiter(@a) + + impl iterable zipiter(@a, @b) -> (@a, @b) + impl iterable enumiter(@a) -> (size, @a) + impl iterable reverseiter(@a) -> @a + + generic byzip : (a : @a[:], b : @b[:] -> zipiter(@a, @b)) + generic byenum : (a : @a[:] -> enumiter(@a)) + generic byreverse : (sl : @a[:] -> reverseiter(@a)) + ;; + + +#### [Variadic Arguments](varargs) + +Myrddin supports variadic arguments for functions, and allows you +to walk over them, similar to the varargs functions in C, but safer. + +In addition, the Myrddin compiler generates type information for the types +that are compiled into a program. This code provides a rather awkward API +for iterating over them, and inspecting their values. + + pkg std = + type typedesc = union + `Tynone + + /* atomic types */ + `Tyvoid + `Tybool + `Tychar + + `Tyint8 + `Tyint16 + `Tyint + `Tyint32 + `Tyint64 + + `Tybyte + `Tyuint8 + `Tyuint16 + `Tyuint + `Tyuint32 + `Tyuint64 + `Tyflt32 + `Tyflt64 + `Tyvalist + + /* compound types */ + `Typtr byte[:] + `Tyfunc typecursor + `Tyslice byte[:] + `Tyarray (size, byte[:]) + + /* aggregate types */ + `Tytuple typecursor + `Tystruct typecursor + `Tyunion typecursor + /* name info */ + `Tyname (byte[:], byte[:]) + ;; + type typecursor = struct + nelt : size + rem : byte[:] + isnamed : bool + isiter : bool + ;; + type typeinfo = struct + size : size + align : size + ;; + generic typeof : (v : @a -> byte[:]) + const typeenc : (p : ...# -> typecursor) + const typeenccursor : (e : byte[:] -> typecursor) + const typedesc : (e : byte[:] -> typedesc) + const typeinfo : (e : byte[:] -> typeinfo) + const tcnext : (t : typecursor# -> byte[:]) + const tcpeek : (t : typecursor# -> byte[:]) + const ncpeek : (t : typecursor# -> (byte[:], byte[:])) + const ncnext : (t : typecursor# -> (byte[:], byte[:])) + + const vastart : (args : ...# -> valist) + const vatype : (ap : valist# -> byte[:]) + const vabytes : (ap : valist# -> byte[:]) + const vaenter : (ap : valist# -> valist) + generic vanext : (ap : valist# -> @a) + ;; + +#### [Slice manipulation](slices) + +Slices are used everywhere within Myrddin code, so clearly we have +some functions to manipulate them. They're listed here. Boopity boopity +boo. + + pkg std = + generic sleq : (a : @a[:], b : @a[:] -> bool) + generic slcp : (a : @a[:], b : @a[:] -> void) + generic slput : (sl : @a[:], idx : size, elt : @a -> @a[:]) + generic slpush : (sl : @a[:]#, elt : @a -> @a[:]) + generic sldup : (sl : @a[:] -> @a[:]) + generic slfill : (sl : @a[:], v : @a -> @a[:]) + generic sljoin : (dst : @a[:]#, src : @a[:] -> @a[:]) + ;; + +#### [String Manipulation](strings) + +String manipulation also tends to show up in code sometimes. Here are some +functions that do that. These are all unicode aware, and will not corrupt +utf8 data. + + pkg std = + /* string buffers */ + type strbuf = struct + ;; + + const mksb : (-> strbuf#) + const mkbufsb : (buf : byte[:] -> strbuf#) + const sbfin : (sb : strbuf# -> byte[:]) + const sbfree : (sb : strbuf# -> void) + const sbpeek : (sb : strbuf# -> byte[:]) + const sbputc : (sb : strbuf#, v : char -> bool) + const sbputs : (sb : strbuf#, v : byte[:] -> bool) + const sbputb : (sb : strbuf#, v : byte -> bool) + const sbtrim : (sb : strbuf#, len : size -> void) + + /* string searching */ + const strfind : (haystack : byte[:], needle : byte[:] -> option(size)) + const strrfind : (haystack : byte[:], needle : byte[:] -> option(size)) + const strhas : (haystack : byte[:], needle : byte[:] -> bool) + const hasprefix : (s : byte[:], pre : byte[:] -> bool) + const hassuffix : (s : byte[:], suff : byte[:] -> bool) + + /* C strings */ + const cstrlen : (buf : byte[:] -> size) + const cstrconv : (buf : byte[:] -> byte[:]) + const cstrconvp : (p : byte# -> byte[:]) + + /* tokenizing and splitting */ + const strsplit : (s : byte[:], delim : byte[:] -> byte[:][:]) + const strtok : (s : byte[:] -> byte[:][:]) + + /* string joining and stripping */ + const strcat : (a : byte[:], b : byte[:] -> byte[:]) + const strjoin : (strings : byte[:][:], delim : byte[:] -> byte[:]) + const strstrip : (str : byte[:] -> byte[:]) + const strfstrip : (str : byte[:] -> byte[:]) + const strrstrip : (str : byte[:] -> byte[:]) + + /* parsing numbers out of strings */ + generic intparsebase : (s : byte[:], base : int -> option(@a::(integral,numeric))) + generic intparse : (s : byte[:] -> option(@a::(integral,numeric))) + generic charval : (c : char, base : int -> @a::(integral,numeric)) + ;; + +#### [Unicode](unicode) + +A bunch of predicates and conversions to handle unicode. This only +provides simple functionality. For canonicalization, collation, and +all of the other UAX algorithms, go look in.. oh, who am I kidding. +I haven't had a chance to write them yet. + + pkg std = + const Badchar : char + const Maxcharlen : size + const Maxcharval : char + + /* utf8 information */ + const charlen : (chr : char -> size) + const encode : (buf : byte[:], chr : char -> size) + const decode : (buf : byte[:] -> char) + const striter : (str : byte[:] -> (char, byte[:])) + + /* character class predicates */ + const isalpha : (c : char -> bool) + const isdigit : (c : char -> bool) + const isxdigit : (c : char -> bool) + const isnum : (c : char -> bool) + const isalnum : (c : char -> bool) + const isspace : (c : char -> bool) + const isblank : (c : char -> bool) + const islower : (c : char -> bool) + const isupper : (c : char -> bool) + const istitle : (c : char -> bool) + + /* character class conversions */ + const tolower : (c : char -> char) + const toupper : (c : char -> char) + const totitle : (c : char -> char) + ;; + +#### [Pervasive Data Structures](datastruct) + +There are some data structures that basically every program seems to use: +Sets, and hash tables. Libstd includes them for that reason. + + pkg std = + type bitset = struct + ;; + + type htab(@k, @v) = struct + ;; + + type htkviter(@k, @v) + impl iterable htkviter + + type bsiter = struct + impl iterable bsiter + + /* bit sets */ + const mkbs : (-> bitset#) + const bsdup : (bs : bitset# -> bitset#) + const bsfree : (bs : bitset# -> void) + const bsmax : (a : bitset# -> size) + const bscount : (a : bitset# -> size) + generic bsput : (bs : bitset#, v : @a::(integral,numeric) -> bool) + generic bsdel : (bs : bitset#, v : @a::(integral,numeric) -> bool) + generic bshas : (bs : bitset#, v : @a::(integral,numeric) -> bool) + const bsdiff : (a : bitset#, b : bitset# -> void) + const bsintersect : (a : bitset#, b : bitset# -> void) + const bsunion : (a : bitset#, b : bitset# -> void) + const bseq : (a : bitset#, b : bitset# -> bool) + const bsissubset : (a : bitset#, b : bitset# -> bool) + const bsclear : (bs : bitset# -> bitset#) + const bybsvalue : (bs : bitset# -> bsiter) + + /* hash tables */ + generic mkht : (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#) + generic htfree : (ht : htab(@k, @v)# -> void) + generic htput : (ht : htab(@k, @v)#, k : @k, v : @v -> void) + generic htdel : (ht : htab(@k, @v)#, k : @k -> void) + generic htget : (ht : htab(@k, @v)#, k : @k -> option(@v)) + generic htgetv : (ht : htab(@k, @v)#, k : @k, fallback : @v-> @v) + generic hthas : (ht : htab(@k, @v)#, k : @k -> bool) + generic htkeys : (ht : htab(@k, @v)# -> @k[:]) + generic byhtkeyvals : (ht : htab(@k, @v)# -> htkviter(@k, @v)) + + /* prepackaged hashing and equality tests */ + const strhash : (s : byte[:] -> uint32) + const streq : (a : byte[:], b : byte[:] -> bool) + generic ptrhash : (p : @a# -> uint32) + generic ptreq : (a : @a#, b : @a# -> bool) + generic inthash : (v : @a::(integral,numeric) -> uint32) + generic inteq : (a : @a::(integral,numeric), b : @a::(integral,numeric) -> bool) + generic slhash : (sl : @a[:] -> uint32) + ;; + + +#### [Pervasive Algorithms](algorithms) + +Many programs also use sorting and searching, so this is also provided by +libstd. In addition, we package some useful comparison and hashing functions + + pkg std = + /* the result of a comparison */ + type order = union + `Before + `Equal + `After + ;; + + /* sorting and searching */ + generic sort : (sl:@a[:], cmp:(a:@a, b:@a -> order) -> @a[:]) + generic lsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric))) + generic bsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric))) + generic swap : (a : @a#, b : @a# -> void) + + /* prepackaged comparisons */ + generic numcmp : (a : @a, b : @a -> order) + const strcmp : (a : byte[:], b : byte[:] -> order) + const strncmp : (a : byte[:], b : byte[:], n : size -> order) + + /* extrema and absolute values */ + generic min : (a : @a::numeric, b : @a::numeric -> @a::numeric) + generic max : (a : @a::numeric, b : @a::numeric -> @a::numeric) + generic clamp : (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric) + generic abs : (a : @a::numeric -> @a::numeric) + ;; + +#### [Randomness](randomness) + +And of course, you can't go without being a little random at times. + + pkg std = + const mksrng : (seed : uint32 -> rng#) + const freerng : (rng : rng# -> void) + generic rand : (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral)) + generic rngrand : (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral)) + generic rngrandnum : (rng : rng# -> @a::(numeric,integral)) + const rngrandbytes : (rng : rng#, buf : byte[:] -> size) + ;; + +#### [Bigint Operations](bigint) + +While bigint usage in most programs is relatively rare, libstd needs them +internally for handling floats, and several other widely used pieces of +functionality also need them. + +As they are a significant amount of code, I decided it made sense to +expose them in the public API. + + pkg std = + type bigint = struct + ;; + + generic mkbigint : (v : @a::(numeric,integral) -> bigint#) + const bigfree : (a : bigint# -> void) + const bigdup : (a : bigint# -> bigint#) + const bigassign : (d : bigint#, s : bigint# -> bigint#) + const bigmove : (d : bigint#, s : bigint# -> bigint#) + const bigparse : (s : byte[:] -> option(bigint#)) + const bigclear : (a : bigint# -> bigint#) + const bigbfmt : (b : byte[:], a : bigint#, base : int -> size) + const bigtoint : (a : bigint# -> @a::(numeric,integral)) + const bigiszero : (a : bigint# -> bool) + const bigeq : (a : bigint#, b : bigint# -> bool) + const bigcmp : (a : bigint#, b : bigint# -> order) + const bigadd : (a : bigint#, b : bigint# -> bigint#) + const bigsub : (a : bigint#, b : bigint# -> bigint#) + const bigmul : (a : bigint#, b : bigint# -> bigint#) + const bigdiv : (a : bigint#, b : bigint# -> bigint#) + const bigmod : (a : bigint#, b : bigint# -> bigint#) + const bigdivmod : (a : bigint#, b : bigint# -> (bigint#, bigint#)) + const bigshl : (a : bigint#, b : bigint# -> bigint#) + const bigshr : (a : bigint#, b : bigint# -> bigint#) + const bigmodpow : (b : bigint#, e : bigint#, m : bigint# -> bigint#) + const bigpow : (a : bigint#, b : bigint# -> bigint#) + generic bigeqi : (a : bigint#, b : @a::(numeric,integral) -> bool) + generic bigaddi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigsubi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigmuli : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigdivi : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigshli : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + generic bigshri : (a : bigint#, b : @a::(integral,numeric) -> bigint#) + const bigpowi : (a : bigint#, b : uint64 -> bigint#) + ;; + + +#### [Closures](closures) + +There are functions for heapifying closures, too. + + pkg std = + generic fndup : (fn : @fn::function -> @fn::function) + generic fnfree : (fn : @fn::function -> void) + ;; + +#### [Misc](misc) + +Well, I said it was a grab bag. These don't really fit into any overarching +category. + + pkg std = + generic KiB : @a::(integral,numeric) + generic MiB : @a::(integral,numeric) + generic GiB : @a::(integral,numeric) + generic TiB : @a::(integral,numeric) + generic PiB : @a::(integral,numeric) + generic EiB : @a::(integral,numeric) + generic ZiB : @a::(integral,numeric) + generic YiB : @a::(integral,numeric) + + generic Sec : @a::(integral,numeric) + generic Msec : @a::(integral,numeric) + generic Usec : @a::(integral,numeric) + + /* time */ + const now : (-> time) + + /* packing integers */ + generic putle64 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe64 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle32 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe32 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle16 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe16 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle8 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe8 : (buf : byte[:], v : @a::(numeric,integral) -> size) + + /* unpacking integers */ + generic getle64 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe64 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle32 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe32 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle16 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe16 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle8 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe8 : (buf : byte[:] -> @a::(numeric,integral)) + + /* exploding and stitching floats */ + const flt64bits : (flt : flt64 -> int64) + const flt32bits : (flt : flt32 -> int32) + const flt64frombits : (bits : uint64 -> flt64) + const flt32frombits : (bits : uint32 -> flt32) + const flt64explode : (flt : flt64 -> (bool, int64, int64)) + const flt32explode : (flt : flt32 -> (bool, int32, int32)) + const flt64stitch : (flt : flt64 -> (bool, int64, int64)) + const flt32stitch : (flt : flt32 -> (bool, int32, int32)) + + ;; diff --git a/doc/api/libstd/iterutil.txt b/doc/api/libstd/iterutil.txt new file mode 100644 index 0000000..a023542 --- /dev/null +++ b/doc/api/libstd/iterutil.txt @@ -0,0 +1,100 @@ +{ + title: libstd + description: libstd: Summary +} + + +Iteration Utilities +---------------- + + pkg std = + type zipiter(@a, @b) + type reverseiter(@a) + type enumiter(@a) + + impl iterable zipiter(@a, @b) -> (@a, @b) + impl iterable enumiter(@a) -> (size, @a) + impl iterable reverseiter(@a) -> @a + + generic byzip : (a : @a[:], b : @b[:] -> zipiter(@a, @b)) + generic byenum : (a : @a[:] -> enumiter(@a)) + generic byreverse : (sl : @a[:] -> reverseiter(@a)) + ;; + +Summary +-------- + +Iteration over sequence is something that turns up regularly. The iteration +utilities provided here simplify a number of common instances of iteration +over collections. They allow for iterating over a zipped sequence, +enumerating a collection of elements, or going over a collection of elements +in reverse. + +All of these iterators hold a reference to the original data, and require that +it not be freed until they are finished consuming it. They do not copy the +slices that they iterate over, and all consume O(1) storage. + +Zip Iterators +------------- + + impl iterable zipiter(@a, @b) -> (@a, @b) + generic byzip : (a : @a[:], b : @b[:] -> zipiter(@a, @b)) + +The zipiter takes two slices, and returns an iterator that will walk over them +pair by pair. So, for example, if you were to call `std.byzip([1,2,3][:], +[4,5,6][:])`, you would iterate through the elements `(1,4), (2,5), (3, 6)`. + +Zip Iterators +------------- + impl iterable enumiter(@a) -> (size, @a) + generic byenum : (a : @a[:] -> enumiter(@a)) + +The enumiter takes a single sequence, and returns the pair of (index, element) +tuples. If you were to call `std.byenum(["hello", "there", "friend"][:])`, you +iterate through the elements `(1, "hello"), (2, "there"), (3, "friend")`. + +Reverse Iterators +----------------- + + impl iterable reverseiter(@a) -> @a + generic byreverse : (sl : @a[:] -> reverseiter(@a)) + + +The reverse takes a single slice, and returns the same elements back, but in +the reverse order. Calling `std.byenum(["hello", "there", "friend"][:])` +would iterate in the sequence `"friend", "there", "hello". + +Examples +-------- + +This is a simple zip iterator: + +```{runmyr zipiter} +use std +const main = { + for x in std.byzip([1,2,3][:], [4,5,6][:]) + std.put("{}\n", x) + ;; +} +``` + +This is a simple enum iterator: + +```{runmyr enumiter} +use std +const main = { + for x in std.byenum(["hello", "world"][:]) + std.put("{}\n", x) + ;; +} +``` + +```{runmyr reverseiter} +use std +const main = { + for x in std.byreverse(["hello", "world"][:]) + std.put("{}\n", x) + ;; +} +``` + diff --git a/doc/api/libstd/misc.txt b/doc/api/libstd/misc.txt new file mode 100644 index 0000000..13ab478 --- /dev/null +++ b/doc/api/libstd/misc.txt @@ -0,0 +1,107 @@ +{ + title: Misc + description: libstd: Misc +} + +Misc +----- + +The mongrels and mutts of libstd. + + pkg std = + generic KiB : @a::(integral,numeric) + generic MiB : @a::(integral,numeric) + generic GiB : @a::(integral,numeric) + generic TiB : @a::(integral,numeric) + generic PiB : @a::(integral,numeric) + generic EiB : @a::(integral,numeric) + generic ZiB : @a::(integral,numeric) + generic YiB : @a::(integral,numeric) + + /* time */ + const now : (-> time) + + /* packing integers */ + generic putle64 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe64 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle32 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe32 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle16 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe16 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle8 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe8 : (buf : byte[:], v : @a::(numeric,integral) -> size) + + /* unpacking integers */ + generic getle64 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe64 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle32 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe32 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle16 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe16 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle8 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe8 : (buf : byte[:] -> @a::(numeric,integral)) + + /* exploding and stitching floats */ + const flt64bits : (flt : flt64 -> int64) + const flt32bits : (flt : flt32 -> int32) + const flt64frombits : (bits : uint64 -> flt64) + const flt32frombits : (bits : uint32 -> flt32) + const flt64explode : (flt : flt64 -> (bool, int64, int64)) + const flt32explode : (flt : flt32 -> (bool, int32, int32)) + const flt64stitch : (flt : flt64 -> (bool, int64, int64)) + const flt32stitch : (flt : flt32 -> (bool, int32, int32)) + + ;; + +Constants +---------- + + generic KiB : @a::(integral,numeric) + generic MiB : @a::(integral,numeric) + generic GiB : @a::(integral,numeric) + generic TiB : @a::(integral,numeric) + generic PiB : @a::(integral,numeric) + generic EiB : @a::(integral,numeric) + generic ZiB : @a::(integral,numeric) + generic YiB : @a::(integral,numeric) + + generic Sec : time + generic Msec : time + generic Usec : time + +These are just constants that you can multiply things by in order to scale +units. If you want to get a + + const now : (-> time) + +Returns the current time in signed microseconds since the Unix epoch. Can +represent dates approximatelyl 70,000 years in either direction from the +present. + + generic putle64 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe64 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle32 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe32 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle16 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe16 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putle8 : (buf : byte[:], v : @a::(numeric,integral) -> size) + generic putbe8 : (buf : byte[:], v : @a::(numeric,integral) -> size) + +These functions pack integers into buffers. The suffix describes the number of +bits that will be packed -- the values will be implicitly converted to an +integer that is `nbits` long before packing into the buffer. Signed integers +will be sign extended, and unsigned ones will be zero extended. + + generic getle64 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe64 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle32 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe32 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle16 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe16 : (buf : byte[:] -> @a::(numeric,integral)) + generic getle8 : (buf : byte[:] -> @a::(numeric,integral)) + generic getbe8 : (buf : byte[:] -> @a::(numeric,integral)) + +These functions unpack integers from buffers. The numeric suffix describes how +many bits will be extracted from the buffer. The value will implicitly be +truncated or widened to the result returned by the specialization of this +function. diff --git a/doc/api/libstd/networking.txt b/doc/api/libstd/networking.txt new file mode 100644 index 0000000..0229573 --- /dev/null +++ b/doc/api/libstd/networking.txt @@ -0,0 +1,181 @@ +{ + title: Networking + description: libstd: Networking +} +Networking +---------- + + pkg std = + type netaddr = union + `Ipv4 byte[4] + `Ipv6 byte[16] + ;; + + + /* network connections */ + const dial : (dialstr : byte[:] -> result(fd, byte[:])) + const announce : (ds : byte[:] -> result(fd, byte[:])) + const listen : (sock : fd -> result(fd, byte[:])) + const accept : (lfd : fd -> result(fd, byte[:])) + + /* ip parsing */ + const ipparse : (ip : byte[:] -> option(netaddr)) + const ip4parse : (ip : byte[:] -> option(netaddr)) + const ip6parse : (ip : byte[:] -> option(netaddr)) + + generic hosttonet : (v : @a -> @a) + generic nettohost : (v : @a -> @a) + ;; + +Summary +------- + +This group of functions contains the basic, portable networking functionality +provided by libstd. There are other packages shipped which provide access +to the underlying functionality used to implement this code, and which may +provide more control. + +The bulk of the functionality is fairly low level. Most of the client side +networking should be done using nothing more than `dial` and `announce` + +Dial describes the endpoint to connect to in the form `proto!host!service`. +`proto` can be any supported protocol. The host specified can be an IP +address, hostname, or path to a local socket. The service ismay be either a +named service, or a protocol specific port. If the port is not a component of +the address (eg, Unix domain sockets) then it should be ommitted. + +On plan 9, the full dial(2) dial string syntax is suported. + +Data Types +---------- + +This contains the infomation that we extract by resolving a host. + + type ipaddr = union + `Ipv4 byte[4] + `Ipv6 byte[16] + ;; + +This contains an IP address. Either V4 or V6 is supported. + +Connections +---------- + + const dial : (dialstr : byte[:] -> result(fd, byte[:])) + +Dial connects to a dial string as described in the summary, returning either a +file descriptor on success, or an error description on failure. The FD +returned is a connection to the server. + + const announce : (ds : byte[:] -> result(fd, byte[:])) + +Announce sets up a file descriptor which is ready to listen for connections, +and binds it to an address. Wildcards can be specified with '*' within the +dial string. + + const listen : (sock : fd -> result(fd, byte[:])) + +Listen specifies that the socket created with `announce` is willing to accept +connections. + + const accept : (lfd : fd -> result(fd, byte[:])) + +Accept takes the returned file descriptor from listen, and returns a file +descriptor that is prepared for reading and writing. + +IP Parsing +---------- + + const ipparse : (ip : byte[:] -> option(netaddr)) + +Ipparse will parse an IP address. This will recognize either V4 or V6 +addresses, and `\`Some \`Ipv4 bits or `\`Some \`Ipv6 bits` as appropriate, or +`\`None` if the address can't be parsed. + + const ip4parse : (ip : byte[:] -> option(netaddr)) + +Parses an Ipv4 address from the string `ip`. The syntax expected is dotted +quad notation. Returns `\` Some \`Ipv4 bits` if the address parses successfully, or +`\`None` if parsing fails. + + const ip6parse : (ip : byte[:] -> option(netaddr)) + +Parses an Ipv6 address from the string `ip`. Returns `\` Some \`Ipv4 bits` if +the address parses successfully, or `\`None` if parsing fails. Zones are +currently not supported. This is a bug. + + +Endian flipping +-------------- + + generic hosttonet : (v : @a -> @a) + generic nettohost : (v : @a -> @a) + + +Flips the bits in an integer to match the expected. These functions should be +avoided in favor of explicit packing functions. + +Examples +-------- + +Some simple examples of how to use the Myrddin networking API + +#### Echo Server + + use std + + const Dialstr = "tcp!*!1234" + const main = { + var lfd, afd + var buf : byte[1024] + + match std.announce(Dialstr) + | `std.Ok f: lfd = f + | `std.Fail e: std.fatal("unable to announce on {}: {}\n", Dialstr, e) + ;; + + match std.listen(lfd) + | `std.Ok f: afd = f + | `std.Fail e: std.fatal("unable to listen on {}: {}\n", Dialstr, e) + ;; + + while true + match std.accept(afd) + | `std.Ok fd: + match std.read(fd, buf[:]) + | `std.Ok n: + std.writeall(fd, buf[:n]) + | `std.Fail e: + std.put("lost conection while reading: {}\n", e) + ;; + std.close(fd) + | `std.Fail e: + std.fatal("unable to accept connection on {}: {}\n", Dialstr, e) + ;; + ;; + } + + +#### Echo Client + + use std + + const Dialstr = "tcp!localhost!1234" + const main = {args : byte[:][:] + var req, resp + + match std.dial(Dialstr) + | `std.Ok fd: + req = std.strjoin(args[1:], " ") + std.writeall(fd, req) + resp = std.try(std.fslurp(fd)) + std.put("{}\n", resp) + | `std.Fail e: + std.fatal("unable to dial {}: {}\n", Dialstr, e) + ;; + } + +Bugs +---- +The errors returned are strings, when they should be unions with default +formatting functions. diff --git a/doc/api/libstd/os.txt b/doc/api/libstd/os.txt new file mode 100644 index 0000000..2fad271 --- /dev/null +++ b/doc/api/libstd/os.txt @@ -0,0 +1,228 @@ +{ + title: OS Interfaces + description: libstd: OS Interfaces +} + + +OS Interfaces +------------- + + pkg std = + type sysinfo = struct + system : byte[:] + version : byte[:] + release : byte[:] + arch : byte[:] + ;; + + type waitstatus = union + `Wsuccess + `Wfailure + `Wsignalled + `Waiterror + ;; + + const Enone : errno + const Eperm : errno + const Enoent : errno + const Esrch : errno + const Eintr : errno + const Eio : errno + const Enxio : errno + const E2big : errno + const Enoexec : errno + const Ebadf : errno + const Echild : errno + const Eagain : errno + const Enomem : errno + const Eacces : errno + const Efault : errno + const Enotblk : errno + const Ebusy : errno + const Eexist : errno + const Exdev : errno + const Enodev : errno + const Enotdir : errno + const Eisdir : errno + const Einval : errno + const Enfile : errno + const Emfile : errno + const Enotty : errno + const Etxtbsy : errno + const Efbig : errno + const Enospc : errno + const Espipe : errno + const Erofs : errno + const Emlink : errno + const Epipe : errno + const Edom : errno + const Erange : errno + const Emisc : errno + + const Failmem : byte# + + const getpid : ( -> pid) + const getsysinfo : (si : sysinfo# -> void) + const execvp : (cmd : byte[:], args : byte[:][:] -> int64) + const execvpe : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64) + const getenv : (name : byte[:] -> option(byte[:])) + const getenvv : (name : byte[:], default : byte[:] -> byte[:]) + const fork : (-> pid) + const execv : (cmd : byte[:], args : byte[:][:] -> int64) + const execve : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64) + const waitpid : (pid:pid, loc:int32#, opt : int64 -> int64) + const spork : (cmd : byte[:][:] -> result((pid, fd, fd), int)) + const sporkfd : (cmd : byte[:][:], infd : fd, outfd : fd -> result(pid, int)) + const exit : (status:int -> void) + const now : (-> time) + const wait : (pid : pid -> waitstatus) + + ;; + + type sysinfo = struct + system : byte[:] + version : byte[:] + release : byte[:] + arch : byte[:] + ;; + +The `sysinfo` struct is returned from the operating system, giving +some information about the sytem that this program is running on. It +is similar to the `uname` function in the standard C library, although +it is guaranteed to be portable. All the storage for the members is +within the private parts of the struct, and no freeing is needed to +relase them. + + type waitstatus = union + `Wsuccess + `Wfailure + `Wsignalled + `Waiterror + ;; + +This type indicates the exit status of a child process that was invoked +with one of the exec family of functions. It only returns a broad category +of values, and does not return the full details provided by the os -- this +is not portable. If the exact exit status is needed, the `sys` package +should cover this need. + + const Enone : errno + const Erange : errno + const Ebadf : errno + const Eexist : errno + const Einval : errno + const Efault : errno + const Eio : errno + const Emisc : errno + + +The errno results are used to signal OS errors. They are not going to remain +stable, and will probably be replaced with system call specific unions for +error handling in future API work. Use them, but parsimoniously. The code +that uses them will break. + +Emisc is used for any non-portable error codes. + + const getpid : ( -> pid) + +Returns the process id of the current process. + + const getsysinfo : (si : sysinfo# -> void) + +Fills a `sysinfo` struct with information about the platform that the program +is running on. + + const execv : (cmd : byte[:], args : byte[:][:] -> errno) + const execve : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno) + + const execvp : (cmd : byte[:], args : byte[:][:] -> errno) + const execvpe : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno) + +Executes a program. If the command `cmd` begins with a `/`, then it is +resolved as an absolute path. Otherwise, command is resolved relative to the +current directory. + +If the path in `cmd` is not an absolute path, the `execvp` variants of this +function will search the path for this program in each directory relative to +$PATH or $path, in addition to the current directory. + +The arguments in `args` are passed to the executed program as its argument +vector. By convention, the first argument in the `args` array should be the +filename of the program being executed. + +For the `execvp` exec variant, the current program's environment is inherited, +and is not modified. + +The `execvpe` variant of this function takes an additional argument `env`, +which is passed to the invoked binary, replacing alll the current environment +variables. It is in the form of a list of `"ENV_VAR=value"` key value pairs. + +Returns: Errno on failure. On success, the function does not return. + + const getenv : (name : byte[:] -> option(byte[:])) + +The `getenv` function looks up a variable from the process environment. + +Returns: `\`Some env\_val` for an environment variable that is present in the +environment, or `\`None` if it is not present. + + const getenvv : (name : byte[:], default : byte[:] -> byte[:]) + +The `getenvv` is the same as `getenv, with the exception that will return the +value of the environment variable if it is present, or `default` if there is +no such environment variable. + +Returns: The value of "name" if present, or "default" if not. + + const fork : (-> pid) + +This forks a new process. This function returns twice, once in the parent +and once in the child. + +On a successful fork, within the parent process `fork` returns a process ID +greater than zero, which is the process id of the child process. Within the +child process, `fork` returns zero. + +If the `fork` function returns a value less than zero, then creating a child +process failed. + +Returns: The pid of the child. + + const wait : (pid : pid -> waitstatus) + +`wait` waits for a process with the PID `pid` to exit, returning its final +status. This function blocks until the child process has exited. If the +process has already exited before this function is called, but has not yet +been called on the process id of the child process, then this function +will return a status immediately. + +If the child process has already been waited on, calling this function is +invalid, and it should return a `\`Waiterror`. + +Returns: A waitstatus, telling you if the process crashed, exited with +failure, exited with success, or whether the wait call was invalid. + + const spork : (cmd : byte[:][:] -> result((pid, fd, fd), errno)) + +Spork stand for `Speak to Process Fork`. It returns a process id and an +input and output file descriptor via which you can communicate to the process +over stdin and stdout. Stderr is inherited from the current process. + +Returns: Either a tuple of (pid, stdin, stdout) on success, or the error +that caused the failure. + + const sporkfd : (cmd : byte[:][:], infd : fd, outfd : fd -> result(pid, errno)) + +Sporkfd is identical to spork, however, instead of returning new file +descriptors, it uses the file descriptors passed in. + +Returns: Either the pid spawned, or the error that caused the spawn failure. + + + const exit : (status:int -> void) + +This exits a process with the status specified. On most Unixy systems, +this will return the value to the shell. On Plan 9, this will call +exits() with the number converted to a string. + +This function terminates the process. diff --git a/doc/api/libstd/randomness.txt b/doc/api/libstd/randomness.txt new file mode 100644 index 0000000..3c9934e --- /dev/null +++ b/doc/api/libstd/randomness.txt @@ -0,0 +1,88 @@ +{ + title: Randomness + description: libstd: Randomness +} + + +Randomness +---------- + + pkg std = + type rng = struct + ... + ;; + + generic rand : (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral)) + generic randnum : (rng : rng# -> @a::(numeric,integral)) + const randbytes : (buf : byte[:] -> size) + + const mksrng : (seed : uint32 -> rng#) + const freerng : (rng : rng# -> void) + generic rngrand : (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral)) + generic rngrandnum : (rng : rng# -> @a::(numeric,integral)) + const rngrandbytes : (rng : rng#, buf : byte[:] -> size) + ;; + + +Overview +-------- + +Currently, the random number generation interface is quite poor. It is not +cryptographically secure, although it should be. It exposes some functions +that it should not. + +Overall, deterministic random numbers should be removed from APIs that do not +define the specific generator. + +Types +----- + + type rng = struct + ... + ;; + +The `rng` type contains the state for the random number generator. + +Functions +--------- + + generic rand : (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral)) + +Generates a random integer in the range [lo, hi), returning the value. The +range [lo, hi) must be positive, nonempty, and the difference between hi and +lo must be less then 2^(type_bits - 1) + + generic randnum : (rng : rng# -> @a::(numeric,integral)) + +Generates a random integer of any magnitude the type may hold. The returned +value may be negative, if the type is signed. + + const randbytes : (buf : byte[:] -> size) + +Fills a buffer with random bytes. + + const mksrng : (seed : uint32 -> rng#) + +Allocates and initializes a random number generator. The seed `seed` is used +to seed the generator. The returned random number generator must be freed +using `freerng`. + + const freerng : (rng : rng# -> void) + +Frees all resources associated with the random number generator `rng`. + + generic rngrand : (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral)) + + +Generates a random integer from `rng` in the range [lo, hi), returning the +value. The range [lo, hi) must be positive, nonempty, and the difference +between hi and lo must be less then 2^(type_bits - 1) + + generic rngrandnum : (rng : rng# -> @a::(numeric,integral)) + +Generates a random integer of any size from the random number generator `rng`. +The returned value may be negative, if the type is signed. + + const rngrandbytes : (rng : rng#, buf : byte[:] -> size) + +Fills a buffer with random bytes from the random number generator `rng`. diff --git a/doc/api/libstd/slices.txt b/doc/api/libstd/slices.txt new file mode 100644 index 0000000..ca3379d --- /dev/null +++ b/doc/api/libstd/slices.txt @@ -0,0 +1,71 @@ +{ + title: Slice Manipulation + description: libstd: Slice Manipulation +} + + +Slice Manipulation +------------------ + + pkg std = + generic sleq : (a : @a[:], b : @a[:] -> bool) + generic slcp : (dst : @a[:], src : @a[:] -> void) + generic slput : (sl : @a[:], idx : size, elt : @a -> @a[:]) + generic slpush : (sl : @a[:], elt : @a -> @a[:]) + generic slpop : (sl : @a[:] -> (@a, @a[:])) + generic sldup : (sl : @a[:] -> @a[:]) + generic slfill : (sl : @a[:], v : @a -> @a[:]) + generic sljoin : (dst : @a[:]#, src : @a[:] -> @a[:]) + ;; + + +Functions +--------- + + generic sleq : (a : @a[:], b : @a[:] -> bool) + +Compares if two slices are equal, elementwise. Uses the '==' operator for +each value. Returns true if they are equal, false otherwise. + + generic slcp : (dst : @a[:], src : @a[:] -> void) + +Copies all the elements from `src` to `dst`. The copy made is shallow, +and done using the `=` operator. The two slices must be equal size. If they +are not equal, this will cause the program to abort. + + generic slput : (sl : @a[:], idx : size, elt : @a -> @a[:]) + +Inserts a value `elt` into the slice `sl` at index `idx`, moving all values +from `sl[idx:len]` to `sl[idx+1:len+1]`. This assumes that the slice is either +empty, or is allocated on the heap using `slalloc`. + +This may move the slice, invalidating the original input argument. + + generic slpush : (sl : @a[:], elt : @a -> @a[:]) + +Inserts a value `elt` into the slice `sl` at index the end of the slice. + +This may move the slice, invalidating the original input argument. + + + generic slpop : (sl : @a[:] -> (@a, @a[:])) + +Removes an element from the end of the slice, returning the element and the +new, truncated slice. + +This may move the slice, invalidating the original input argument. + + generic sldup : (sl : @a[:] -> @a[:]) + +Duplicates a slice. This function is equivalent to calling slalloc() followed +by slcp(). + + generic slfill : (sl : @a[:], v : @a -> @a[:]) + +Fills a slice with a value. + + generic sljoin : (dst : @a[:]#, src : @a[:] -> @a[:]) + +Concatenates `src` onto the end of `dst#`. Equivalent to iterating through +every element of `src` and `slpush()`ing it onto `dst`. + diff --git a/doc/api/libstd/strings.txt b/doc/api/libstd/strings.txt new file mode 100644 index 0000000..9da210a --- /dev/null +++ b/doc/api/libstd/strings.txt @@ -0,0 +1,205 @@ +{ + title: Strings + description: libstd: Strings +} + +Summary +------- + + pkg std = + /* string buffers */ + type strbuf = struct + ;; + + const mksb : (-> strbuf#) + const mkbufsb : (buf : byte[:] -> strbuf#) + const sbfin : (sb : strbuf# -> byte[:]) + const sbfree : (sb : strbuf# -> void) + const sbpeek : (sb : strbuf# -> byte[:]) + const sbputc : (sb : strbuf#, v : char -> bool) + const sbputs : (sb : strbuf#, v : byte[:] -> bool) + const sbputb : (sb : strbuf#, v : byte -> bool) + const sbtrim : (sb : strbuf#, len : size -> void) + + /* string searching */ + const strfind : (haystack : byte[:], needle : byte[:] -> option(size)) + const strrfind : (haystack : byte[:], needle : byte[:] -> option(size)) + const strhas : (haystack : byte[:], needle : byte[:] -> bool) + const hasprefix : (s : byte[:], pre : byte[:] -> bool) + const hassuffix : (s : byte[:], suff : byte[:] -> bool) + + /* C strings */ + const cstrlen : (buf : byte[:] -> size) + const cstrconv : (buf : byte[:] -> byte[:]) + const cstrconvp : (p : byte# -> byte[:]) + + /* tokenizing and splitting */ + const strsplit : (s : byte[:], delim : byte[:] -> byte[:][:]) + const bstrsplit : (sp : byte[:][:], s : byte[:], delim : byte[:] -> byte[:][:]) + const strtok : (s : byte[:] -> byte[:][:]) + const bstrtok : (sp : byte[:][:], s : byte[:] -> byte[:][:]) + + /* string joining and stripping */ + const strcat : (a : byte[:], b : byte[:] -> byte[:]) + const strjoin : (strings : byte[:][:], delim : byte[:] -> byte[:]) + const strstrip : (str : byte[:] -> byte[:]) + const strfstrip : (str : byte[:] -> byte[:]) + const strrstrip : (str : byte[:] -> byte[:]) + + /* parsing numbers out of strings */ + generic intparsebase : (s : byte[:], base : int -> option(@a::(integral,numeric))) + generic intparse : (s : byte[:] -> option(@a::(integral,numeric))) + generic charval : (c : char, base : int -> @a::(integral,numeric)) + ;; + + +Types +------ + + type strbuf = struct + ;; + +The `strbuf` type contains a string buffer under construction. It can operate +in two modes: Allocated, and static. The allocated mode keeps track +of buffer sizing, and grows it efficiently as the data is appended to it. + +The static mode, on the other hand, has a fixed size buffer that is provided +to it, and truncates values to fit the buffer if needed. This can be used when +allocations are undesirable. + +Functions: String buffers +-------------------------- + + const mksb : (-> strbuf#) + +Mksb creates an string buffer. The buffer returned is in allocated mode, and +starts off with an empty string. + + const mkbufsb : (buf : byte[:] -> strbuf#) + +Mkbufsb creates a fixed size string buffer, initialized with `buf`. The +initial length of the string is empty, regardless of the contents of the +buffer. Anything in it will be overwritten as appends happen. + + const sbfin : (sb : strbuf# -> byte[:]) + +Sbfin finishes the string buffer. Any auxiliary resources allocated by the +string buffer are released, and the final string that was constructed is +returned. In dynamic mode, the string is heap allocated, and must be freed +with `slfree`. Otherwise, it is simply a slice into the buffer passed in +the `mkbufsb` call. + + const sbfree : (sb : strbuf# -> void) + +Sbfree frees the string buffer `sb`, and all associated resources. The string +under construction is discarded if the buffer is dynamically allocated. + + const sbpeek : (sb : strbuf# -> byte[:]) + +Sbpeek returns the portion of the string that has already been constructed +by the string buffer, without freeing it. The returned string is only valid +as long as the buffer is not modified. + + const sbputc : (sb : strbuf#, v : char -> bool) + +Sbputc appends a single character to the string buffer, encoding it into +utf8 before appending it to the buffer. If the buffer is fixed and the +character will not fit, then it will be dropped in its entirety. + +Returns: True if there was sufficient space to append the character, false +otherwise. + + const sbputs : (sb : strbuf#, v : byte[:] -> bool) + +Sbputs appends a string to the string buffer. If the buffer is a static +buffer, and the string is too long to fit, as much of it as can possibly fit +will be copied. This may truncate characters mid-way through. + +Returns: True if there was sufficient space to append the character, false +otherwise. + + const sbputb : (sb : strbuf#, v : byte -> bool) + +Sbputs appends a single byte to the string buffer. If the buffer is a static +buffer and the character does not fit, the buffer will remain unmodified + +Returns: True if there was sufficient space to append the byte, false +otherwise. + + const sbtrim : (sb : strbuf#, len : size -> void) + +Truncates a string buffer to the length provided. If the length provided i +longer than the size of the buffer, the length of the buffer remains +unmodified. + + +Functions: Searching +-------------------- + + const strfind : (haystack : byte[:], needle : byte[:] -> option(size)) + const strrfind : (haystack : byte[:], needle : byte[:] -> option(size)) + +Strfind finds the first occurrence of the string `needle` within the string +`haystack`.Strrfind is similar, but it finds the last occurrence of `needle` +within `haystack`. + +Returns: `\`std.Some index` if needle is found within haystack, or `\`None` +otherwise. + + const strhas : (haystack : byte[:], needle : byte[:] -> bool) + +Strhas returns `true` if the string `needle` is found within haystack. + + const hasprefix : (s : byte[:], pre : byte[:] -> bool) + +hasprefix returns `true` if the string `pre` is found at the start of `s`. + + const hassuffix : (s : byte[:], suff : byte[:] -> bool) + +hassuffix returns `true` if the string `pre` is found at the end of `s`. + + +Functions: Splitting and joining +-------------------------------- + + const strsplit : (s : byte[:], delim : byte[:] -> byte[:][:]) + const strtok : (s : byte[:] -> byte[:][:]) + +Strsplit and strtok will split a string into its components. Strsplit uses a +string passed in as a delimiter, while strtok will use a variable amount of +whitespace to split the string. They dynamically allocate the split vector, +but not the elements within it. + +If there are repeated delimiters, `strsplit` will include zero length strings +between them. For example, `std.strsplit("a<><>b<>c", "<>")` will return +`["a", "", "b", "c"]`. + + const bstrsplit : (sp : byte[:][:], s : byte[:], delim : byte[:] -> byte[:][:]) + const strtok : (sp : byte[:][:], s : byte[:] -> byte[:][:]) + +The bstrsplit and bstrtok functions produce a split string similar to the +strsplit versions above, but will fill the `sp` vector passed in, instead of +allocating their own storage. If there are more splits to be made than the +vector can hold, then the last element will contain the tail of the string. + + + const strcat : (a : byte[:], b : byte[:] -> byte[:]) + +Strcat will concatenate two strings, returning a new buffer containing the +string that was created. + + const strjoin : (strings : byte[:][:], delim : byte[:] -> byte[:]) + + +Strcat will concatenate all strings in a list, returning a new buffer +containing the string that was created. It will interpose the delimiter +between them. + + const strstrip : (str : byte[:] -> byte[:]) + const strfstrip : (str : byte[:] -> byte[:]) + const strrstrip : (str : byte[:] -> byte[:]) + + +Strstrip will remove all whitespace characters from both ends of the string. +Strfstrip and strrstrip will strip all whitespace characters from the start or +end of the of the string, respectively. diff --git a/doc/api/libstd/unicode.txt b/doc/api/libstd/unicode.txt new file mode 100644 index 0000000..31ec714 --- /dev/null +++ b/doc/api/libstd/unicode.txt @@ -0,0 +1,133 @@ +{ + title: Unicode + description: libstd: Unicode +} + +Unicode +-------- + + pkg std = + const Badchar : char + const Maxcharlen : size + const Maxcharval : char + + /* iterators */ + impl iterable chariter -> char + + const chariter : (byte[:] -> chariter) + + /* utf8 information */ + const charlen : (chr : char -> size) + const encode : (buf : byte[:], chr : char -> size) + const decode : (buf : byte[:] -> char) + const strstep : (str : byte[:] -> (char, byte[:])) + + /* character class predicates */ + const isalpha : (c : char -> bool) + const isdigit : (c : char -> bool) + const isxdigit : (c : char -> bool) + const isnum : (c : char -> bool) + const isalnum : (c : char -> bool) + const isspace : (c : char -> bool) + const isblank : (c : char -> bool) + const islower : (c : char -> bool) + const isupper : (c : char -> bool) + const istitle : (c : char -> bool) + + /* character class conversions */ + const tolower : (c : char -> char) + const toupper : (c : char -> char) + const totitle : (c : char -> char) + ;; + +Summary +------- + +As a reminder, Myrddin characters hold a single Unicode codepoint, and all +strings are assumed to be encoded in UTF-8 by default. These functions are +designed to facilitate manipuating unicode strings and codepoints. + +The APIs are generally designed that strings will be streamed through, and +not encoded or decoded wholesale. + +Constants +--------- + const Badchar : char + +This is a character value that is not, and will never be, a valid unicode +codepoint. This is generally returned when we encounter an error fr + + const Maxcharlen : size + +This is a constant defining the maximum number of bytes that a character may +be decoded into. It's guaranteed that a buffer that is at least Maxcharlen +bytes long will be able to contain any character. + + const Maxcharval : char + +This is the maximum value that any valid future unicode codepoint may decode +into. Any character that is greater than this is an invalid character. + +Functions: Iterating over strings +-------------------------------- + + impl iterable chariter -> char + + const chariter : (byte[:] -> chariter) + +Chariter returns an iterator which steps through a string character by +character. + +Functions: Encoding and Decoding +-------------------------------- + + const charlen : (chr : char -> size) + +Charlen returns the length in bytes that decoding the character provided into +unicode would take. This can vary between 1 and Maxcharlen bytes. + + const encode : (buf : byte[:], chr : char -> size) + +Encode takes a single character, and encodes it to a utf8 string. The buffer +must be at least long enough to hold the character. + +Returns: The number of bytes written, or -1 if the character could not be +encoded. + + const decode : (buf : byte[:] -> char) + +Decode converts the head of the buffer `buf` to a single unicode codepoint, +returning the codepoint itself, or `Badchar` if the codepoint is invalid. + +The tail of the buffer is not considered, allowing this function to be used +to peek at the contents of a string. + + const strstep : (str : byte[:] -> (char, byte[:])) + +strstep is a function for stepping through unicode encoded strings. It +returns the tuple (`Badchar`, str[1:]) if the value cannot be decoded, +or `(charval, str[std.charlen(charval):])` therwise. + + +```{runmyr striter} + s = "abcd" + while s.len != 0 + (c, s) = std.striter(s) + std.put("next char is {}\n", s) + ;; +``` + +Character Classes +----------------- + + const isalpha : (c : char -> bool) + const isdigit : (c : char -> bool) + const isxdigit : (c : char -> bool) + const isnum : (c : char -> bool) + const isalnum : (c : char -> bool) + const isspace : (c : char -> bool) + const isblank : (c : char -> bool) + const islower : (c : char -> bool) + const isupper : (c : char -> bool) + const istitle : (c : char -> bool) + diff --git a/doc/api/libstd/varargs.txt b/doc/api/libstd/varargs.txt new file mode 100644 index 0000000..b0eaf3e --- /dev/null +++ b/doc/api/libstd/varargs.txt @@ -0,0 +1,189 @@ +{ + title: Varargs + description: libstd: Varargs +} + +Varargs +------- + + pkg std = + type typedesc = union + `Tynone + + /* atomic types */ + `Tyvoid + `Tybool + `Tychar + + `Tyint8 + `Tyint16 + `Tyint + `Tyint32 + `Tyint64 + + `Tybyte + `Tyuint8 + `Tyuint16 + `Tyuint + `Tyuint32 + `Tyuint64 + `Tyflt32 + `Tyflt64 + `Tyvalist + + /* compound types */ + `Typtr byte[:] + `Tyfunc typecursor + `Tyslice byte[:] + `Tyarray (size, byte[:]) + + /* aggregate types */ + `Tytuple typecursor + `Tystruct typecursor + `Tyunion typecursor + /* name info */ + `Tyname (byte[:], byte[:]) + ;; + + type typecursor = struct + nelt : size + ;; + + type typeinfo = struct + size : size + align : size + ;; + + generic typeof : (v : @a -> byte[:]) + const typeenc : (p : ...# -> typecursor) + const typeenccursor : (e : byte[:] -> typecursor) + const typedesc : (e : byte[:] -> typedesc) + const typeinfo : (e : byte[:] -> typeinfo) + const tcnext : (t : typecursor# -> byte[:]) + const tcpeek : (t : typecursor# -> byte[:]) + const ncpeek : (t : typecursor# -> (byte[:], byte[:])) + const ncnext : (t : typecursor# -> (byte[:], byte[:])) + + const vastart : (args : ...# -> valist) + const vatype : (ap : valist# -> byte[:]) + const vabytes : (ap : valist# -> byte[:]) + const vaenter : (ap : valist# -> valist) + generic vanext : (ap : valist# -> @a) + ;; + +Overview +-------- + +Type descriptions are encoded byte strings. + +Types +----- + + + type typedesc = union + ... + ;; + + +Typedesc provides a description of a type. It can be paired with a valist for +walking over the contents of a value, but this is ugly. + + + type typecursor = struct + nelt : size + ;; + +A type cursor allows for iterating over the subtypes of a type. It exposes the +number of elements in the subtype. + + type typeinfo = struct + size : size + align : size + ;; + +Typeinfo contains all of the attributes that we care about for the type. This +may expand in the future. + + +Type iteration +--------- + + generic typeof : (v : @a -> byte[:]) + +Typeof takes any arbitrary value, and returns an encoded type description for +the type of the value. It would be better to provide a first class interface +for finding type encodings, but this needs thought. + + const typeenc : (p : ...# -> typecursor) + +Typeenc returns a type cursor for an argument list, allowing for iteration +over the type of values within it. + + const typeenccursor : (e : byte[:] -> typecursor) + +Typeenccursor takes a type encoding, and converts it to a cursor with a single +type. Iterating the cursor will return only the one type encoding that was +passed to this function. + + const typedesc : (e : byte[:] -> typedesc) + +Typedesc extracts a typedesc from an encoded type. The type description +may contain other type cursors for iterating over subtypes. + + const typeinfo : (e : byte[:] -> typeinfo) + +Typeinfo extracts a typeinfo from an encoded type. The type description +contains attributes about the type, such as the size and alignment. + + const tcnext : (t : typecursor# -> byte[:]) + +Tcnext pulls an encoded subtype from a type cursor and advances it. +Calling this on a cursor that has a name is acceptable, and will +discard the name. + + const tcpeek : (t : typecursor# -> byte[:]) + +Tcnext pulls an encoded subtype from a type cursor and does not it. +Calling this on a cursor that has a name is acceptable, and will +discard the name. + + const ncnext : (t : typecursor# -> (byte[:], byte[:])) + +Ncnext pulls an encoded subtype from a type cursor for a type with named +subtypes, and advances the type cursor. such as a struct or union, and returns +the name and encoded type. + + const ncpeek : (t : typecursor# -> (byte[:], byte[:])) + +Ncpeek pulls an encoded subtype from a type cursor for a type with named +subtypes, such as a struct or union, and returns the name and encoded +type. This does not advance the cursor. + +Variadic Arguments +----------------- + + const vastart : (args : ...# -> valist) + +Vastart takes a pointer to a variadic argument list, and returns a valist, +which is basically an iterator for arguments. + + const vatype : (ap : valist# -> byte[:]) + +Vatype returns a type encoding for the current variadic argument that the +valist is pointing to. + + generic vanext : (ap : valist# -> @a) + +Vanext returns the next value for the variadic type, and advances the valist. + + const vabytes : (ap : valist# -> byte[:]) + +Vanext returns a slice to the bytes of the variadic argument, and advances the +valist. + + const vaenter : (ap : valist# -> valist) + +Vaenter does not advance the valist, but returns a new valist for the +argument, allowing iteration over the fields within the argument. For example, +if you had a struct passed as a variadic argument, calling 'vaenter' on it +would allow iterating over the members of the struct. diff --git a/doc/api/libtestr/index.txt b/doc/api/libtestr/index.txt new file mode 100644 index 0000000..774f364 --- /dev/null +++ b/doc/api/libtestr/index.txt @@ -0,0 +1,64 @@ +{ + title: libtestr + description: Myrddin Test Library +} + +Libtestr +--------- + + pkg testr = + type ctx + + type spec = struct + name : byte[:] + fn : (ctx : ctx# -> void) + ;; + + const run : (specs : spec[:] -> void) + const ok : (ctx : ctx# -> void) + const fail : (ctx : ctx#, msg : byte[:] -> void) + ;; + +Overview +-------- + +The testr library provides a simple library for running +unit tests. It outputs subtest results in a format that mbld +will be able to understand, log, and report on. + +Types +----- + + type ctx + +The context for the current test. Used to record the state +of the set of tests currently running. + + type spec = struct + name : byte[:] + fn : (ctx : ctx# -> void) + ;; + +The specification for a single test. Contains the name +of the test being run, and the code used to execute it. + +Mutex. + +Functions: Mutexes +------------------ + + const run : (specs : spec[:] -> void) + +Runs a sequence of tests, recording the state of the test +and outputting an appropriate log for mtest to consume. + + const ok : (ctx : ctx# -> void) + +Records a test success. It does not leave the current +scope. + + const fail : (ctx : ctx#, msg : byte[:] -> void) + +Records a test failure. It does not leave the current +scope. + diff --git a/doc/api/libthread/index.txt b/doc/api/libthread/index.txt new file mode 100644 index 0000000..6bbe28a --- /dev/null +++ b/doc/api/libthread/index.txt @@ -0,0 +1,115 @@ +{ + title: libthread + description: Myrddin Thread Library +} + +Libthread +--------- + + pkg thread = + trait atomic @a::(integral,numeric) = + xget : (p : @a# -> @a) + xset : (p : @a#, v : @a -> void) + xadd : (p : @a#, v : @a -> @a) + xsub : (p : @a#, v : @a -> @a) + xcas : (p : @a#, old : @a, new : @a -> @a) + xchg : (p : @a#, new : @a -> @a) + ;; + + type cond = struct + ... + ;; + + type mutex = struct + ... + ;; + + impl atomic int32 + impl atomic int64 + impl atomic uint32 + impl atomic uint64 + + /* mutexes */ + const mkmtx : (-> mutex) + const mtxlock : (mtx : mutex# -> void) + const mtxtrylock : (mtx : mutex# -> bool) + const mtxunlock : (mtx : mutex# -> void) + + /* condition variables */ + const mkcond : (mtx : mutex# -> cond) + const condwait : (cond : cond# -> void) + const condsignal : (cond : cond# -> void) + const condbroadcast : (cond : cond# -> void) + ;; + +Types +----- + + type cond = struct + ... + ;; + +Condition variable. + + type mutex = struct + ... + ;; + + trait atomic @a::(integral,numeric) = + xget : (p : @a# -> @a) + xset : (p : @a#, v : @a -> void) + xadd : (p : @a#, v : @a -> @a) + xsub : (p : @a#, v : @a -> @a) + xcas : (p : @a#, old : @a, new : @a -> @a) + xchg : (p : @a#, new : @a -> @a) + ;; + + +Mutex. + +Functions: Mutexes +------------------ + + const mkmtx : (-> mutex) + +Crates a new mutex, in the unlocked state. + + const mtxlock : (mtx : mutex# -> void) + +Locks a mutex. Blocks if the mutex is already locked. + + const mtxtrylock : (mtx : mutex# -> bool) + +Attempts to lock a mutex. Returns true if the lock was +taken successful. Returns false if the lock was not taken. + +This call does not block. + + const mtxunlock : (mtx : mutex# -> void) + +Unlocks a mutex that is taken. It is a bug to call this on a mutex that you +have not successfully locked. + +Functions: Condition Variables. +------------------------------ + + const mkcond : (mtx : mutex# -> cond) + +Creates a condition variable. Associates the mutex with the condition +variable. + + const condwait : (cond : cond# -> void) + +Waits on the condition to be notiifed on. Must be called with the associated +mutex locked. Unlocks the mutex that is associated with the condition variable +and sleeps until someone has notified on the condition variable. + + const condsignal : (cond : cond# -> void) + +Wakes at least one waiter on the condition variable, allowing them to take the +mutex. + + const condbroadcast : (cond : cond# -> void) + +Wakes all waiters on the condition variable. + |