💾 Archived View for schinkel.bevuta.com › fleng › LIBRARY captured on 2024-08-18 at 19:24:11.

View Raw

More Information

⬅️ Previous capture (2024-05-12)

-=-=-=-=-=-=-


FLENG LIBRARY REFERENCE
=======================


### Table of contents:

 1. Syntactic Forms
 2. Toplevel declarations
 3. Guard expressions
 4. Builtin primitives
 5. "$rt" module: low-level primitives
 6. "lib" module: FGHC standard library
 7. "sys" module: Event-loop for thread-communication
 8. "fmt" module: Formatted output
 9. "sort" module: Sorting
 10. "map" module: Key-value maps
 11. "list" module: List operations
 12. "set" module: Lists as sets
 13. "proc" module: Subprocess invocation
 14. "lex" module: FGHC/FLENG lexical analyzer
 15. "parse" module: FGHC/FLENG parser
 16. "array" module: Mutable numeric arrays
 17. "app" module: Higher-order operations on lists
 18. "io" module: Extended I/O stream operations
 19. "scan" module: Simple parsers for various character sequences
 20. "match" module: Pattern matching
 21. "path" module: Pathname destructuring
 22. "find" module: Find files and directories
 23. "base64" module: Base64 encoding/decoding
 24. "binfmt" module: binary string formatting/scanning
 25. "9p" module - a client library for the 9P protocol
 26. JSON parsing
 27. "ucs" module: unicode character classification and conversion
 28. PCN syntax and primitive operations
 29. Security-relevant stuff
 30. "color" module: Access to named colors
 31. "sdl" module: basic SDL2 graphics and sound interface
 32. "ezd" module: Structured graphics
 33. "bb" module: EZD building blocks
 34. "eval" module - a simple FGHC evaluator
 35. Formal definition of PCN syntax


## 1. Syntactic Forms

        Block comment, may not be nested.

        [FGHC] Single-line comment.

    GOAL1, GOAL2
        [FGHC] Execute goals in parallel. The goals may not be variables.

    MODULE:GOAL
        [FGHC] Invokes GOAL, which must be a tuple or string and be defined in
        and exported from the module with the given name.

    GOAL@PEER
    MODULE:GOAL@PEER
        [FGHC] Invokes the specified non-variable GOAL in the thread designated
        by PEER, which may be a variable but must be bound.  All threads
        are ordered before execution in ring and torus topologies. PEER
        specifies what neighbouring thread in a topology should receive
        the call:

            fwd  bwd
                previous or next in the ring topology.

            north  south  east  west
                neighbours in the torus topology.

            all
                broadcast call to all threads.

        All threads are connected in the ring topology. Some threads
        may not be connected in the torus topology, depending on the
        number of threads.  Additionally PEER may be an integer thread
        number (starting at 1) addressing a specific thread in the set
        of all threads.

    GUARD -> GOAL1
    GUARD -> GOAL1; GOAL2
        [FGHC] Executes GOAL1 if the guard expression GUARD evaluates to true
        or executes GOAL2, otherwise. If GOAL2 is not given, it defaults
        to "true".

    GOAL1 & GOAL2
        [FGHC] Execute GOAL1 in a new task (see also "call/3") and then, once
        GOAL1 and all child processes created by GOAL1 have successfully
        executed, execute GOAL2. Note that "&/2" binds stronger than ",/2".
        Operationally, "X & Y" is equivalent to "(call(X, S), when(S, Y))".

    X = Y
        [FGHC] Unifies X with Y by recursively comparing the values in
        X and Y.  Unbound variables will be bound. In FLENG a failed
        unification will silently be ignored. Note tha variables in X
        or Y may be partially bound when the unification fails. In FGHC
        a failed unification will signal an error.

    X := Y
        [FGHC] Equivalent to "assign(Y, X, _)".

    S <= M
        [FGHC] Equivalent to "S0 = [M|S1]" where S is a paired argument.

    M => S
        [FGHC] Equivalent to "[M|S0] = S1" where S is a paired argument.

    S <== X
        [FGHC] Equivalent to "S1 = X" where S is a paired argument. The previous
        value is lost and the next occurrence of S will mean X instead.

    S += E
    S -= E
    S *= E
    S /= E
        [FGHC] Equivalent to "S1 is S0 + E" ("-" ...), where S is a paired
        argument.

    RESULT^ is EXPRESSION?
        [FGHC] Evaluates the numerical expression and unifies RESULT with
        the result of the computation. EXPRESSION must be an arithmetic
        expression and may not contain unbound variables. Available
        operations are:

            X + Y
            X - Y
            X * Y
            X / Y           Usual arithmetic operators
            X \\ Y          Integer remainder
            +X              Identity
            -X              Negation
            \X              Bitwise NOT
            sqrt(X)
            integer(X)      Truncate and convert to integer
            real(X)         Convert integer to float
            X /\ Y          Bitwise AND
            X \/ Y          Bitwise OR
            X >< Y          Bitwise XOR
            X << Y
            X >> Y          Shift X by Y
            X ** Y          Exponentiation of X by Y
            rnd             Pseudo random float betwwen 0 and 1
            rnd(X)          Random integer between 0 and X-1
            floor(X)
            ceiling(X)
            round(X)        Rounding operations
            sin(X)
            cos(X)
            tan(X)
            atan(X)         Trigonometry
            log(X)          Natural logarithm
            exp(X)          Exponential value
            abs(X)          Absolute value
            sign(X)         Sign
            real_integer_part(X)
            real_fractional_part(X)
                            Deconstruct floating-point value
            max(X, Y)
            min(X, Y)       Return greater or lesser argument

        Random numbers returned by "rnd/0" are uniformly distributed,
        "rnd/1" uses a slightly faster method and may not be uniformly
        distributed.
        Note that variables holding valid arithmetic expressions (as
        in ISO Prolog) are not supported.  Signals an error if any
        argument is not numeric.

    when(VAR?, GOAL)
        [FGHC] Executes GOAL, which must not be an unbounded variable, once
        VAR is bound.

    foreign_call(NAME(ARGUMENT, ...))
        Invokes an externally linked foreign function with the following
        signature:

            void <NAME>_<ARITY>(FL_TCB *tcb, FL_VAL argument1, ...)

        where ARITY is the number of arguments given. Arguments are
        dereferenced and passed on to the foreign function, using the C
        ABIs calling conventions. At most 4 arguments can be passed.
        The call does not block, you must ensure arguments are bound to
        something meaningful or are intended to be unbound.
        The "tcb" argument holds a pointer to a "thread control block"
        designating the thread context in which this foreign function is
        invoked.
        Execution of concurrent processes in the same thread will not
        commence, until the foreign function returns. See "fleng.h" and
        "fleng-util.h" for structure definitions, macros and functions to
        access and manipulate the TCB and FLENG runtime values.

## 2. Toplevel declarations

    -arguments(STRING)
        Adds additional run-time arguments to be used when running the
        compiled executable. This declaration is ignored in modules
        other than the main ('') module. The arguments can ge given as
        a string or character list and are effectively prepended to any
        arguments that are given when the executable is invoked. This
        declaration can be given multiple times, the argument strings
        will be appended in reverse order.

    -comment(ARGUMENT)
        Ignored. This is sometimes useful for adding metadata to source
        files generated or analyzed by tools.

    -fleng_library([MODULENAME, ...])
        [PCN] Declare the given modules as FGHC/Strand/FLENG code, so
        mutable variables are passed by value. As only PCN handles
        mutable (boxed) values transparently, this declaration is needed
        to seamlessly interoperate with libraries written in FGHC,
        Strand or FLENG and applies automatically to the library modules
        provided by the FLENG base system.  Meta-calls that refer to
        dynamically constructed modules will not be handled in this
        way, though. In that case, you must take care not to pass mutable
        variables directly in calls to separately compiled non-PCN
        modules, for example by passing their value via temporary
        definitional variables.

    -foreign(SPECLIST)
        Creates stubs and wrappers for external native code. SPECLIST should
        be a list of foreign-call specifications or strings and generates
        FLENG stubs that call generated C wrapper code which is produced in
        a file named "<module>.c", where "<module>" is the name of the currently
        compiled module. If no module is declared, the file will be named
        "foreign.c". The specifications can be of the following form:

            STRING
            NAME(TYPE, ...)
            struct(NAME(SLOT1:TYPE1, ...))
            const(NAME = STRING:TYPE)

        See the doc/MANUAL file for a full description of the foreign
        specification format.

        [PCN] Only the first variant for including verbatim C code is
        currently provided in PCN.

    -exports(EXPORTLIST)
        [FGHC] EXPORTLIST should be a list of "<Name>/<Arity>" specifications of
        predicates that should be visible to external modules. If this
        declaration is not given, then by default all predicates are exported.

        Note that there is no performance or space advantage in not exporting
        predicates. This declaration exists mostly for compatibility reasons
        with Strand.

    -include(FILENAMES)
        [FGHC] Includes the contents of the files given by the string
        or list of strings in FILENAME at the current toplevel position
        in the compiled file. The file-extension defaults to ".ghc",
        ".fghc", ".strand" or ".st" when compiling GHC or Strand and
        to ".fl" or ".fleng" otherwise.

    -initialization(PROCESSLIST)
        Declares that on startup, the processes given will be spawned.
        PROCESSLIST should be a string or a list of strings naming predicates
        with zero arity, which must be defined, but not necessarily exported.
        Only a single initialization declaration will be respected (later
        override earlier ones).

    -machine(TOPOLOGY)
        Provided for Strand compatibility. Only "ring" and "torus"
        topologies are allowed. This declaration has no effect.

    -mode(CLAUSE)
        [FGHC] Declares the predicate defined by CLAUSE to have a mode. CLAUSE
        should specify a predicate term "<name>(<mode>, ...)", where "<mode>" is
        either the symbol "?" or "^". The compiler will transform arguments
        to the predicate marked as "^" into an explicit output-argument
        unification, e.g.

            -mode(wheels(?, ^)).
            wheels(car, 4).

        is equivalent to

            wheels(car, X) :- X = 4.

        Output arguments (marked as "^") may not be used in guards.

    -module(NAME)
        Declares the name of the current module, unless the file was
        compiled with the "-m" command line option. If not given and
        no module name was specified during the invocation of the
        compiler, the module name defaults to the empty ("") module,
        which is the program's main module.

    -rewrite(FROM, TO)
        [FGHC] Transforms body terms matching FROM to TO and compile the resulting
        term instead. FROM and TO should both be strings or tuples. FROM and TO
        may be module-qualified.
        Tuple arguments in TO can refer to direct arguments in FROM and can be
        reordered. Other arguments in TO are taken verbatim:

            -rewrite(foo(X, Y), fmt:format(2, Y, X)).                 [FGHC]

            p(X) :- foo("arg: ~q\n", [X]).   % compiled as fmt:format(2, "...", [X])

        Rewrite-rules are applied after all built-in forms and so can not be used
        to change existing behaviour.

    -struct(TUPLE)
        [FGHC] Generates code to easily extract and modify tuple components.
        TUPLE should be a named tuple of length > 1. A struct declaration of the
        form

            -struct(point(x, y)).

        produces code similar to (but slightly more efficient than):

            point_x(point(X, _), Y) :- Y = X.
            point_y(point(_, X), Y) :- Y = X.
            point_x(X, point(_, B), Y) :- Y = point(X, B).
            point_y(X, point(A, _), Y) :- Y = point(A, X).

        Note that the update predicates take the new value as the first
        argument.

        [PCN] Declares a struct (record) with associated accessors, similar to
        FGHC. The "." (field reference) and "<--" (field update) can be used in
        the same module that contains this declaration to access structure fields.
        Additionally, a function call of the same syntax can be used to create
        new struct instances:

            -struct(point(x, y))
            :
            	p1 = point(123, 456),
            	:
            	x = p1.x,
            	:

        Note that field access and constructor are only available in the module
        that contains the declaration. Use "#include" to share struct declarations
        across multiple modules.

    -synthesized(NAME)
    -synthesized(NAME1/ARITY1, NAME2/ARITY2)
        [FLENG] Declares the the predicate NAME1/ARITY1 should be considered
        part of the implementation of NAME2/ARITY2 in profiling information. Also,
        NAME1/ARITY1 will not generate any entry-point information. This is
        mainly intended to hide internally generated clauses in compiled FGHC,
        Strand or PCN code. The simple form, where only a name is given
        declares that all predicates with that name (regardless of arity)
        should be considered hidden.

    -uses(MODULELIST)
        Declares that the modules should be loaded and process
        definitions be made available for use using the "MODULE:GOAL"
        notation. MODULELIST may be a string or a list of strings.
        In FGHC, declarations for modules called directly using the
        "MODULE:GOAL" notation are added automatically and so not
        required.

## 3. Guard expressions

    X == Y
        [FGHC] Succeeds if X matches Y. Note that matching never binds logic
        variables. If an argument variable in a clause head occurs
        several times, then subsequent occurrences imply an argument
        match equivalent to using "==/2", e.g.

        foo(X, [X]) :- ...

        is the same as

        foo(X, [Y]) :- X == Y | ...

    X =\= Y
        [FGHC] Succeeds if X does not match Y.

    X =:= Y
        [FGHC] Succeeds if X is numerically the same as Y, X and Y may be
        numerical expressions as in "is/2".

    X \=:= Y
        [FGHC] Succeeds if X is numerically different to Y. X and Y may be
        numerical expressions.

    X > Y
    X < Y
    X >= Y
    X =< Y
        [FGHC] Succeeds if X is numerically greater or less than Y. X and Y
        may be numerical expressions.

    X @> Y
    X @< Y
    X @>= Y
    X @=< Y
        Succeeds if X is ordered accordingly relative to Y. Implements a
        general ordering relation where

            integers < reals < strings < lists < tuples < ports < modules < arrays

        Integers and reals are compared numerically, lists element by
        element, strings lexicographically, tuples by size and, if
        equal, element by element. Arrays are sorted by element size, then
        length, then byte by byte.
        All other objects are sorted by some arbitrary but stable order.

        [PCN] For consistency, the "@=<" operator is named "@<=" in PCN.

    array(X)
        Succeeds if X is an array.

    atomic(X)
        [FGHC] Succeeds if X is a number or a string.

    data(X)
        [FGHC] Suspends if X is an unbound variable. This is identical to
        qualifying a head variable with "!".

    idle
        [FGHC] Suspends the clause until the current thread is "idle", that is,
        when no active processes are scheduled for execution. Once idle,
        the process will resume and subsequent matching of an "idle"
        guard will wait for the next idle cycle. Note that threads listening
        for input or other events like signals and timers are not considered idle.

    integer(X)
        [FGHC] Succeeds if X is an integer.

    known(X)
        Succeeds if X is a non-variable object or a bound variable, the
        guard does not suspend in the case that X is bound.

    list(X)
        Succeeds if X is a non-empty list.

    module(X)
        Succeeds if X is a module object.

    number(X)
        Succeeds if X is an integer or a floating point number.

    otherwise
        [FGHC] Always succeeds. A clause with this guard will only be matched
        if all textually previous clauses of the same process definition
        failed to match.

    port(X)
        Succeeds if X is a port object,

    real(X)
        Succeeds if X is a floating point number.

    remote(X)
        Succeeds if X is a variable or port object located in a different
        thread than the current one.

    string(X)
        Succeeds if X is a string. Note that this includes the empty
        list ("[]").

    tuple(X)
        Succeeds if X is a tuple.

    unknown(X)
        Succeeds if X is an unbound variable, the guard does not
        suspend in that case.

## 4. Builtin primitives

    all_modules(LIST^)
        Unifies LIST with a list of all linked modules.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    assign(VAR^, VAL?)
    assign(VAR^, VAL?, DONE^)
        Assigns VAL to the variable VAR, which must be unbound and
        unifies DONE with the empty list, when the assignment is
        completed. VAR must be currently unbound or contain a value
        identical to VAL or an error is signalled.

    cancel_timer(ID?)
    cancel_timer(ID?, RESULT^)
        Cancels and removes the timer identifier by ID, previously
        created by calling "timer/3" or "clock/3" and unifies RESULT with the
        "true" when the operation is complete. The variable associated
        with the timer is assigned the string "false" or an empty list,
        depending on whether the timer is single-shot or periodic.
        If no timer with the given ID is currently active, then this
        operation does nothing and unifies RESULT with "false" (if given).

    clock(MS?, VAR^, ID^)
        Establishes a periodic timer and assigns an integer identifier
        to ID that can be used to cancel the timer. Every MS milliseconds
        an integer or float indicating the number of expirations since the
        last will be assigned to the stream in VAR.

    close_file(FILE?)
    close_file(FILE?, DONE^)
        Closes the open file with the descriptor FILE and unifies DONE
        with the empty list when the operation is completed. FILE may be
        an integer or one of the strings "stdin", "stdout" or "stderr".

    command_line(LIST^)
        Unifies LIST with a list of strings holding the command line
        arguments to the currently executing program, not including the
        program name and any run-time options.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    counter(NUM^)
        Unifies NUM with the current value of a thread-specific counter
        and increases the counter.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    current_seconds(SECONDS^)
        Unifies SECONDS with the current UNIX timestamp in seconds
        since 00:00, Jan. 1, 1970.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    dbgwrite(OBJECT?)
    dbgwrite(OBJECT?, DONE^)
        Writes OBJECT to stderr, followed by a newline, including
        uninstantiated variables and with maximum output limited. If DONE
        is given, it is assigned the empty list after the operation
        completes.

    environment(ENV^)
        Unifies ENV with the environment slot of the current task, or the
        empty list, if the current process does not belong to an explicitly
        created task.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    fdup(FILE1?, FILE2?)
    fdup(FILE1?, FILE2?, DONE^)
        Duplicates file descriptor FILE1 to FILE2. In the error case
        "fdup/2" will signal an error and abort. After the operation,
        DONE will be unified with the empty list. FILE1 and FILE2 may be
        integers or one of the strings "stdin", "stdout" or "stderr".

    get_arg(INDEX?, TUPLE?, ITEM^)
    get_arg(INDEX?, TUPLE?, ITEM^, DONE^)
        Unifies ITEM with the INDEXth element of TUPLE, assigning the
        empty list to DONE, if given. Indexing starts at 1. Signals an
        error if INDEX is out of range.

        [PCN] This operation may also be used as a 2-argument function
        in expressions.

    get_global(NAME?, VAL^)
    get_global(NAME?, VAL^, DEFAULT^)
        Retrieves the global variable named by the string NAME and unifies
        its value with VAL. If no global variable under this name is defined,
        an error is signaled if DEFAULT is not given. If DEFAULT is given and
        the global variable has not yet been set, VAL is unified with DEFAULT.
        Global variables are thread-local.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    get_module(NAME?, MODULE^)
        Assigns the module  with the given name to MODULE. If no module
        with this name is linked, MODULE is unified with the empty list.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    getcwd(DIR^)
        Unifies DIR with a character list holding the name of the current
        directory.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    getpid(PID^)
        Unifies PID with the UNIX process ID of the currently executing
        program.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    global(NAME?, VAL?)
        If a global variable with the given name exists, its current value
        is unified with VAL. Otherwise the global variable will be created,
        set to a fresh unbound variable which will then be unified with
        VAL.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    halt(EXITCODE?)
        Terminates the program with the given exit code, which must be
        an integer.

    heap_statistics(TUPLE^)
        Unifies TUPLE with a tuple of 5 elements containing the number of
        bytes currently used in the threads's heap holding variables, tuples,
        list, floats and port objects.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    idle_thread(PEER^)
        Unifies PEER with the number of a random idle thread (other than
        the current). If no other thread is currently idle, PEER is unified
        with "false". Note that threads listening for input or other events
        like signals are not considered idle.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    isatty(FILE?, FLAG^)
        Assigns "true" or "false" to FLAG, depending on whether the file
        descriptor FILE is connected to a terminal or not. FILE may b
        e
        an integer or one of the strings "stdin", "stdout" or "stderr".
        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    kill(SIGNAL?, PID?)
    kill(SIGNAL?, PID?, DONE^)
        Sends SIGNAL (which should be an integer or a string containing the
        Linux/BSD uppercase signal name) to the process with the ID PID using the
        kill(2) system call and unifies DONE with the empty list when the
        operation is completed. If the system call fails, DONE will be unified
        with a tuple of the form "error(ERRNO, STRING)" where ERRNO designates
        the error code and STRING a textual representation.

    listen(FILE?, VAR^)
        Registers the file descriptor FILE with the internal polling
        loop and unifies VAR with the empty list once data can be read
        from the file. To listen again, invoke "listen" again for
        the same file. If an error occurs, then VAR will be unified with
        a tuple of the form "error(ERRNO, STRING)", where ERRNO is the UNIX
        error code and STRING a textual representation of the same. FILE may be
        an integer or one of the strings "stdin", "stdout" or "stderr".

    lseek(FILE?, OFFSET?, DONE^)
    lseek(FILE?, OFFSET?, WHENCE?, DONE^)
        Reposition file-pointer for the file-descriptor FILE to OFFSET.
        WHENCE, when given, designates the start location and can
        be "set" (the default), "current" or "end", indicating that OFFSET
        should be counted from the start, current location or the end.
        DONE is assigned the empty list when the operation is completed.
        If an error occurs, DONE will be unified with a tuple of the form
        "error(ERRNO, STRING)", where ERRNO is the UNIX
        error code and STRING a textual representation of the same.
        FILE may be an integer or one of the strings "stdin", "stdout" or "stderr".

    make_tuple(LENGTH?, TUPLE^)
        Unifies TUPLE with a fresh tuple of the specified length, the
        resulting tuple is populated with unbound variables. Signals
        an error if LENGTH is not between 0 and 127. Creating a tuple
        of length 0 will unify TUPLE with the empty list.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    module_exports(MODULE?, LIST^)
        Unifies LIST with the list of exported process definitions
        contained in MODULE. Each element of the list will be a tuple of
        the form '/'(NAME, ARITY).

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    module_name(MODULE?, NAME^)
        Assigns astring holding the name of MODULE to NAME.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    number_to_list(NUMBER?, LIST^, TAIL?)
    number_to_list(NUMBER?, BASE?, LIST^, TAIL?)
        Converts the integer or real NUMBER into a list of character
        codes terminated by TAIL and unifies it with LIST.

    open_port(PORT^, LIST^)
        Creates a "port" object and unifies it with PORT. LIST is
        unified with a "stream" receiving objects send to PORT using
        the "send" primitive. When the port is not referenced anymore,
        the stream is closed by assigning the empty list to its tail.

    program_name(NAME^)
        Assign the name of the current executable to NAME as a string.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    put_arg(INDEX?, TUPLE?, ITEM?)
    put_arg(INDEX?, TUPLE?, ITEM?, DONE^)
        Unifies the INDEXth element of TUPLE with ITEM, assigning the
        empty list to DONE, if given. Indexing starts at 1. Signals an
        error if INDEX is out of range.

    put_global(NAME?, VAL^)
    put_global(NAME?, VAL^, DONE^)
        Assigns VAL to the global variable named by the string NAME and
        unifies DONE with the empty list when the assignment is completed.
        Global variables are thread-local.

    restart_timer(ID?, MS?)
    restart_timer(ID?, MS?, RESULT^)
        Modifies the timeout for the timer identified by ID and previously
        created by calling "timer/3" or "clock/3" and unifies RESULT with
        "true" when the operation is complete. MS specifies the new
        timeout (possibly periodic when ID designates a periodic timer).
        If no timer with the given ID is currently active, then this
        operation does nothing and unifies RESULT with "false" (if given).

    self(ID^)
        Unifies ID with the thread number of the thread that is executing
        the current clause.
        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    send(PORT?, OBJECT?)
    send(PORT?, OBJECT?, DONE^)
        Sends OBJECT (which may be any data objecv whatsoever) to
        PORT and unifies DONE with the empty list, when given.

    signal(SIGNAL?, VAR^)
    signal(SIGNAL?, VAR^, DONE^)
        Installs a signal handler for the signal with the name given
        by the string SIGNAL, which should be an integer or a valid uppercase
        Linux/BSD signal name. If the signal is raised, or was raised since the
        program started, the number of times the signal was raised since
        is added as an integer to the stream in VAR.
        Handling of the signal can not be disabled, once the signal
        handler was installed.

    statistics(TUPLE^)
        Unifies TUPLE with a tuple of 6 elements containing the number of
        goals, active goals, suspended goals and used, peak and average
        heap-cells.

        The peak and average number of cells is computed only at sample
        points. Sample points are when this primitive is called and when
        statistics are written to the log output file, enabled via the "+STATS"
        runtime option.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    string_to_byte_list(STRING?, LIST^, TAIL?)
        Converts STRING to a list of bytes, terminated by TAIL.

    string_to_integer(STRING?, INTEGER^)
    string_to_integer(STRING?, BASE?, INTEGER^)
        Converts the atom STRING to an integer, interpreting the
        characters in STRING in BASE. BASE defaults to 10. If STRING
        can not be converted, then INTEGER is assigned the string
        "error".

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    string_to_list(STRING?, LIST^)
    string_to_list(STRING?, LIST^, TAIL?)
        Converts STRING to a list of UNICODE code points, terminated by
        TAIL.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    string_to_real(STRING?, REAL^)
        Converts the atom STRING to a floating-point number.  If STRING
        can not be converted, then an error is signaled.
        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    thread_resource_usage(UTIME^, STIME^, MAXRSS^)
        Assigns the current thread's time spend in user- and system-mode
        to UTIME and STIME as seconds in floating point format and
        assigns the maximum resident set size in kilobytes to MAXRSS.

    threads(NUMBER^)
        Unifies NUMBER with the number of threads, as given to the
        "+THREADS" run-time option on startup.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    ticks(TICKS^)
        Unifies TICKS with an integer counter, corresponding to "ticks"
        of the internal process scheduler.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    timer(MS?, VAR^, ID^)
        Establishes a single-shot timer that unifies VAR with the empty
        list after MS milliseconds have passed. ID is unified immediately
        with an integer identifying this timer and can be used to cancel
        the timer before it has expired.

    true
        [FGHC] Does nothing.

    tuple_to_list(TUPLE?, LIST)
    tuple_to_list(TUPLE?, LIST^, TAIL?)
        Unifies LIST with the elements of TUPLE, terminated by TAIL. If
        TUPLE is the empty list, the result is the empty list.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    unify(X?, Y?, RESULT^)
        Unifies X with Y and finally unifies RESULT with the string "true" or
        "false", depending on whether the unification succeeded or
        failed. Variables bound during the unification will be restored to
        their unbound state if the full unification should fail.
        Note that this primitive receives the result variable in the third
        argument position, which differs from the description given in [1].
        Also note that "remote" variable bindings in other threads are
        not restored on failure and still trigger inter-thread messages
        that negotiate the final value.

        [1] "FLENG Prolog - The Language which turns Supercomputers into
            Parallel Prolog Machines"
            Martin Nilsson and Hidehiko Tanaka

    unify_with_occurs_check(X?, Y?, RESULT^)
        Similar to "unify/3", but fails in case a binding would make a variable
        directly or indirectly refer to itself. This primitive always performs
        the check, regardless of the "+OCCURS_CHECK" runtime option.

## 5. "$rt" module: low-level primitives

    The definitions in this module are available directly, without using
    any module prefix and provide some higher-order operations for
    invoking dynamically computed goals ("call", "trace", "run") and
    for FLENG's built-in "compute" operation.

    call(GOAL?)
    call(GOAL?, STATUS^)
    call(GOAL?, ENVIRONMENT?, STATUS^)
        Invokes the process specified by GOAL which must be a tuple
        or string. If GOAL is not a variable, then it may refer to a
        primitive operation (a suitable user-defined wrapper clause is
        synthesized by the compiler), but if it is a variable, then it
        must refer to a user defined process.
        GOAL may refer to a module-qualified term and must be exported
        from the module in which it is defined.

        "call/2" and "call/3" execute GOAL in a new group of processes
        called a "task". Every process created in GOAL belongs to the
        same task and once all processes in that group have terminated
        (including child tasks), STATUS is unified with the empty list.
        IF ENVIRONMENT is given, it is provided as a parameter associated
        with the task group and can be accessed by the "environment/1"
        primitive, otherwise the new task inherits the same environment
        as the current task (if any).

        Tasks may span multiple threads, a task is considered completed
        when all processes of the task and it's child tasks in all threads
        have terminated.

    call_detached(GOAL?, STATUS^)
        Invokes GOAL in a new task, similar to "call/2", but does not
        Link the new task to the current one. Executuion of said new
        task will be independent and allow the current task to complete
        without waiting for the new task.

    trace(GOAL?)
    trace(GOAL?, STATUS^)
        Similar to "call/2", but enabled logging for the newly created
        task to show entered predicates along with their arguments.
        Tracing is inherited, so child tasks will be logged as well,
        even in other threads. Note that tracing only produces logging
        output for code that was compiled with the "-d" option.

    compute(OP?, ARG?, RESULT^)
    compute(OP?, ARG1?, ARG2?, RESULT^)
        Performs a unary or binary numeric computation. OP must be a
        string and may be one of the following:

                    Unary      Binary   Result
            +         -          x      Sum
            -         -          x      Difference
            *         -          x      Product
            /         -          x      Quotient
            mod       -          x      Remainder
            and       -          x      Bitwise AND
            or        -          x      Bitwise OR
            xor       -          x      Bitwise XOR
            shl       -          x      Shift bits left
            shr       -          x      Arithmetic shift bits right
            =         -          x      Equality comparison
            >         -          x      Is ARG1 numerically greater than ARG2
            <         -          x      Is ARG1 numerically less than ARG2
            min       -          x      Return lesser of the two arguments
            max       -          x      Return greater of the two arguments
            sametype  -          x      Have ARG1 an ARG2 the same type
            **        -          x      Exponentiation
            sqrt      x          -      Square root
            sin       x          -      Sine (radians)
            cos       x          -      Cosine (radians)
            tan       x          -      Tangent
            atan      x          -      Arc tangent
            exp       x          -      Exponential value
            abs       x          -      Absolute value
            sign      x          -      Sign (returns integer)
            rnd       x          -      Returns random integer
            real_integer_part
                      x          -      Extract integer part of float
            real_fractional_part
                      x          -      Extract fractional part of float
            integer   x          -      Convert float to integer
            real      x          -      Convert integer to float
            truncate  x          -      Truncate float
            floor     x          -      Round float to next lower integer
            round     x          -      Round float
            ceiling   x          -      Round float to next higher integer

        +, -, * and / produce real results if one of the arguments is
        a real number. "abs" returns a result of the same type as the argument.
        "**" always produces a real result. "and", "or", "xor", "rnd",
        "shl" and "shr" require integer arguments. With the exception of
        "=", "sametype" the arguments must be bound to numbers.

        Note that arguments to "compute" are not forced if unbound.
        Note that integer over- and underflow is not detected and will
        result in significant bits being silently truncated. "sametype"
        will not force unbound arguments (the type of the argument is
        considered "var" in that case).

        See "is/2" for a more convenient way to perform arithmetic
        computations.

    current_module(MODULE^)
        Assigns the module containing this expression to MODULE.

    run(MODULE?, TERM?)
        Invokes TERM similar to "call/1" in the module represented by MODULE,
        which may be a module object or a name referring to a linked
        module.


## 6. "lib" module: FGHC standard library

    The definitions in this module are all available by default and
    are used without the module prefix.

    apply(GOAL?, LIST?)
        [FGHC] Invokes GOAL with a list of arguments in LIST. GOAL may be a
        string or tuples of the form "{<string>, <argument>, ...}",
        "{':', <modulename>, <string>}" or "{':', <modulename>, {<string>,
        <argument>, ...}}". GOAL may be seen as a "closure", holding state
        in a given list of values that is passed along with additional
        arguments when called.

        [PCN] This operation may also be used as a 2-argument function in
        expressions, GOAL must specify a function in that case.

    binding(NAME?, VALUE^)
    binding(NAME?, DEFAULT?, VALUE^)
   	Look up the dynamic task variable NAME (established using "with/2")
   	in the current task's environment and unify VALUE with the associated
   	value or, if not found, with DEFAULT.
   	If DEFAULT is not given and the binding could not be found, signal an error.

        [PCN] This operation may also be used as a 1 or 2-argument function
   	in expressions.

    call_handler(NAME?)
    call_handler(NAME?, STATUS^)
   	Look up task variable NAME in the dynamic environment and invoke
   	it using "call/3", with the same task environment but with the found handler
   	removed, so earlier bindings for the same variable are visible in later
   	look-ups using "binding/{2,3}" or "call_handler". STATUS, if given is
   	unified with the empty list once the handler finishes executing.

    chdir(DIRECTORY?)
    chdir(DIRECTORY?, DONE^)
        Changes the current directory to DIRECTORY, which should be a
        string or a character list. When the operation is complete,
        DONE is unified with the empty list.

    chmod(FILENAME?, MODE?)
    chmod(FILENAME?, MODE?, DONE^)
        Changes file permission bits of the file with the given name to
        MODE, which must be an integer and unifies DONE with the empty
        list when the operation is completed. In case of an error, DONE
        is unified with a tuple of the form "error(ERRNO, STRING)", where
        ERRNO is the UNIX error code and STRING is a textual representation
        of the same.

    compare(X?, Y?, RESULT^)
        Unifies RESULT with -1, 0 or 1, depending on whether X is ordered
        below, equal or above Y, as compared with '@>'/2 and '@<'/2.

        [PCN] This operation may also be used as a 2-argument function
   	in expressions.

    cpu_time(TIME^)
        Assigns the current CPU time for the executing thread to TIME,
        in microseconds, starting at zero.

        [PCN] This operation may also be used as a 0-argument function
   	in expressions.

    delete_file(FILENAME?)
    delete_file(FILENAME?, DONE^)
        Deletes the file with the name FILENAME and unifies DONE with the
        empty list when the operation is completed. Note that no error
        is signaled if FILENAME does not exist.

    deref(OBJECT?)
    deref(OBJECT?, DONE^)
        Recursively derefences variables in OBJECT until the term
        is fully ground, possibly suspending. Once all variables inside
        OBJECT are bound, DONE is unified with the empty list.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    directory(NAME?, ITEMS^)
    directory(NAME?, ITEMS^, TAIL^)
        Reads the directory specified by the string or character list NAME
        into the list ITEMS, containing the names of included files as
        character lists and terminated by TAIL (or the empty list).
        If reading the directory should fail, then ITEMS will be unified
        with a tuple of the form "error(ERRNO, STR)", holding the error
        code and a textual description of the error as a string. The
        entries for "." and ".." are not included.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    error(MESSAGE?)
        Writes MESSAGE to standard error and terminates the program
        with exit code 1.

    file_exists(FILENAME?, FLAG^)
    file_exists(FILE?, FLAG^)
        If FILENAME (a string or character list) or FILE (a file descriptor)
        designates an existing file or directory, assign
        "true" to FLAG, otherwise "false". Signals an error if the
        system call fails due to other causes.

        [PCN] This operation may also be used as a 1-argument function
    	 in expressions.

    file_modification_time(FILENAME?, TIME^)
    file_modification_time(FILE?, TIME^)
        Unifies TIME with the UNIX timestamp of the last modification of the
        file FILENAME (which should be a string or character list) or FILE (a
        fiule descriptor). If an error occurs, TIME is unified with a term of the
   	 form "error(ERRNO, STRING)" where ERRNO designates the error
   	 code and STRING is a textual representation of the same. FILE
   	may be an integer or one of the strings "stdin", "stdout" or "stderr".

        [PCN] This operation may also be used as a 1-argument function
    	 in expressions.

    file_size(FILENAME?, BYTES^)
    file_size(FILE?, BYTES^)
        Unifies BYTES with the number of bytes in the file named by the
        string or character list FILENAME pr the file descriptor FILE. If an error
        occurs, BYTES is unified with a term of the form "error(ERRNO, STRING)"
        where ERRNO designates the error code and STRING is a textual representation of
        the same. FILE may be an integer or one of the strings "stdin", "stdout"
    	 or "stderr".

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    file_type(FILENAME?, TYPE^)
        Unifies TYPE with the string "file", "directory", "link", "fifo"
        or "socket" depending on what type of file FILENAME refers to.
        If an error occurs, TYPE is unified with a term of the form
        "error(ERRNO, STRING)" where ERRNO designates the error code
        and STRING is a textual representation of the same. FILENAME may
        be a string or a character list.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    getenv(NAME?, VAL^)
        Unifies VAL with a character list holding the value of the environment
        variable of the given name, which should be a string or character list.
        If no variable with that name is defined, VAL is unified with the
        empty list.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    halt
        Terminates the program with exit code 0.

    length(OBJECT?, LEN^)
        Unifies LEN with the length of OBJECT, which may be a string, array,
        a list or a tuple.

    list_to_number(LIST?, NUMBER^)
        Unifies NUMBER with the number consisting of the characters
        in LIST, which must specify a valid integer or floating point
        number. If the conversion fails, NUMBER is assigned the string
        "error".

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    list_to_real(LIST?, REAL^)
        Similar to "list_to_number/2", but implicitly converts the
        result into a floating-point number. If the conversion fails, REAL
        is assigned the string "error".

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    list_to_integer(LIST?, NUMBER^)
    list_to_integer(LIST?, BASE?, NUMBER^)
        Similar to "list_to_number/2", but implicitly converts the
        result into an integer. BASE should be an integer
        and defaults to 10. If the conversion fails, NUMBER is assigned
        the string "error".

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    list_to_string(LIST?, STRING^)
        Unifies STRING with the string holding the UNICODE code points
        in LIST.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    list_to_tuple(LIST?, TUPLE^)
        Unifies TUPLE with the string holding the elements of LIST.
        If LIST is the empty list, TUPLE will be unified with the empty
        list as well (there are no empty tuples).

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    log(MESSAGE?)
    log(MESSAGE?, DONE^)
        Dereferences MESSAGE fully and writes it into the log file.
        After the message is written, DONE is unified with the empty list.

    merger(INSTREAM?, OUTSTREAM^)
        Takes elements from INSTREAM and writes them to OUTSTREAM.
        Element of the form "merge(STREAM?)" in INSTREAM result in
        merging the elements from STREAM into OUTSTREAM. Items are added
        to the output stream in an arbitrary order, but retain the
        order from the respectively merged streams. Merged streams
        may again receive "merge(STREAM)" messages. Once all streams
        are terminated with the empty list, OUTSTREAM is terminated
        as well.

    mkdir(NAME?)
    mkdir(NAME?, DONE^)
        Create a directory with given name. NAME should be a string
        or character list. Signals an error if the operation fails and
        unifies DONE with the empty list on success. It is not an error
        if the directory already exists.

    nl
    nl(DONE^)
        Write a single newline, unify DONE with the empty list when the
        operation is complete.

    open_file(NAME?, MODE?, FILE^)
        Creates or opens a file with the name NAME in the given MODE,
        which should be a string or character list containing one or more
        of the characters "r" (read), "w"(write) and "a" (append). The
        file descriptor will be unified with FILE.  If the system call fails,
        FILE will be unified with a tuple of the form "error(ERRNO, STRING)",
        where ERRNO is the UNIX error code and STRING is a textual
        representation of the same.

        [PCN] This operation may also be used as a 2-argument function
        in expressions.

    randomize(SEED?)
    randomize(SEED?, DONE^)
        Initializes the internal pseudo random number generator. SEED
        should be a string or a byte list. The buffer holding the random
        state has a size of 16 machine words. If the byte sequence given
        by SEED has a smaller size, then initialization "wraps around"
        to the start of SEED again. Once the random number generator
        has been initialized, DONE is unified with the empty list.
        On startup the random number generator is seeded with the
        system time.

        [PCN] This operation may also be used as a 0-argument function
        in expressions.

    read_file(FILE?, COUNT?, LIST^, TAIL?)
        Reads at most COUNT bytes from the file designated by the file descriptor
        FILE and unifies LIST with the read data, terminated by TAIL.
        If an error occurs, then LIST will be unified with a tuple of the
        form "error(ERRNO, STRING)", where ERRNO is the UNIX error code
        and STRING is a textual representation of the same. This call may
        block the current thread if no input is currently available.
        FILE may be an integer or one of the strings "stdin", "stdout" or "stderr".

    readlink(FILENAME?, VAL^)
        Unifies VAL with a character list holding the contents of the
        symbolic link FILENAME. If an error occurs, VAL is
        unified with a term of the form "error(ERRNO, STRING)" where ERRNO
        designates the error code and STRING is a textual representation of
        the same.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    real_to_list(REAL?, LIST^)
    real_to_list(REAL?, LIST^, TAIL?)
        Converts the floating-point number REAL to a list of character codes,
   	 optionally terminated by TAIL.

        [PCN] This operation may also be used as a 1-argument function
        in expressions.

    rmdir(FILENAME?)
    rmdir(FILENAME?, DONE^)
        Deletes the directory with the name FILENAME and unifies DONE with the
        empty list when the operation is completed. Note that no error
        is signaled if FILENAME does not exist. In case the operation
        fails DONE is unified with a tuple of the form "error(ERRNO, STRING)",
        where ERRNO is the UNIX error code and STRING is a textual
        representation of the same.

    setenv(VAR?, VAL?)
    setenv(VAR?, VAL?, DONE^)
       Sets the environment-variable named by the string or character list
       VAR to VAL, which should also be a string or character list.
       After the operation is completed, assigns the empty list to DONE,
       if given.

    utf_decode(LIST?, OUTLIST^)
    utf_decode(CHAR^, LIST?, REST^)
        Converts bytes in LIST to UNICODE code points. The former
        primitive writes characters into the stream OUTLIST until
        LIST is exhausted and closes OUTLIST by unifying it with the
        empty list. The latter primitive converts a single character
        and unifies REST with the remaining elements of LIST.

    utf_encode(INLIST?, OUTLIST^)
    utf_encode(CHAR?, LIST^, TAIL?)
        Convert UNICODE code points into a stream of bytes or encode
        a single codepoint into LIST, terminated by TAIL.
        The former receives a stream of code points and produces a stream
        of bytes until the end of INLIST is reached, after which OUTLIST is
        terminated with the empty list.

    with(BINDINGS?, GOAL?)
       Extend the environment of the current task with BINDINGS, which
       should be a term of the form "NAME = VALUE" or a list of such terms
       and invokes the given GOAL. Dynamic task bindings can be accessed
       using "binding/{2,3}". Note that BINDINGS may contain any value, even
       though "binding" only recognizes "NAME = VALUE" pairs.

    write(OBJECT?)
    write(OBJECT?, DONE^)
        Fully dereferences OBJECT and writes it to standard output.
        Objects are written in their "canonical" representation, specifically:
        character lists are written as a bracketed list of integers.
        After writing, DONE is unified with the empty list, if given.

    write_file(FILE?, DATA?, REST^)
    write_file(FILE?, DATA?, COUNT?, REST^)
        Writes COUNT bytes of DATA to the file designated by the file
        descriptor FILE and unifies REST with the empty list or any
        yet unwritten data. DATA may be a string or a byte list
        If COUNT is not given, writes DATA completely. When an error
        occurs, REST will be unified with a tuple of the form
        "error(ERRNO, STRING)", where ERRNO is the UNIX error code
        and STRING is a textual representation of the same.
        [PCN] Data will be written in FGHC "term" notation so tuples with
        a string as first element are printed as "<string>(<elements> ...)".
        FILE may be an integer or one of the strings "stdin", "stdout" or "stderr".

    writeln(OBJECT?)
    writeln(OBJECT?, DONE^)
        Fully dereferences OBJECT and writes it to standard output,
        followed by a newline character. After writing, DONE is unified
        with the empty list, if given.


## 7. "sys" module: Event-loop for thread-communication

      This module starts the internal event system for inter-thread 
      communication and is used automatically. Additionally, some library
      predicates are available to communicate with external FLENG processes.

    sys:attach(FILENAME?, FILE^, ADDR^)
          Access detached message port at FILENAME and unify ADDR with an 
          address to the mapped memory area and FILE with the file 
          representing FILENAME.

    sys:detach(FILE?, ADDR?)
    sys:detach(FILE?, ADDR?, DONE^)
          Release the attached message port designated by FILE and ADDR.

    sys:detach_message_port(FILENAME?)
    sys:detach_message_port(FILENAME?, DONE^)
          Detach message port to external file given and unify DONE with 
          the empty list when the operation is complete. The thread will 
          wait continuously for messages to arrive on the detached port 
          and so will not terminate by itself. Messages forwarded to
          the port will invoke "'':forwarded(MESSAGE?)".

    sys:transmit(ADDR?, MESSAGE?)
    sys:transmit(ADDR?, MESSAGE?, DONE^)
          Dereference MESSAGE completely and transmit it to the detached 
          message port identified by ADDR, then unify DONE with the empty 
          list. MESSAGE may not contain unbound variables, references to 
          modules or ports. The receiver is expected to define a clause 
          named '':forwarded(MESSAGE?) that will be called with the
          transmitted message object.


## 8. "fmt" module: Formatted output

    Support for formatted output and string construction. These
    operations take a string describing a format and a list of
    arguments to be displayed, depending on the formatting instructions
    encoded in the string.

    Character sequences in the format string are interpreted in the
    following manner:

            ~~  Output the "~" (tilde) character.

            ~a  Output the unquoted characters of the next argument
                which must be a string.

            ~s  Output the string, character list, char or int array given in the
                next argument.

            ~d  Output the next argument, which must be a number, in
                decimal notation.

            ~x  Output the next argument, which must be a number, in
                hexadecimal notation.

            ~w  Output the next argument term in FGHC term syntax.

            ~q  Output the next argument term in FGHC term syntax and with
                strings quoted, if necessary.

            ~c  Output the next argument which must be an integer as
                a single character.

            ~n  Output a newline character.

            ~?  Take a format-string and argument-list, format recursively.

    Use "format_chars" to format into a character list instead of writing
    the result to an output file.

    fmt:format(STRING?, ARGS?)
    fmt:format(FILE?, STRING?, ARGS?)
    fmt:format(FILE?, STRING?, ARGS?, DONE^)
          Writes the values in the list ARGS in a manner described by
          the format string STRING to FILE or to standard output.
          STRING may be a string or a list of character codes and may
          contain special characters describing how to output the next
          item in ARGS. Assigns [] to DONE when finished.

    fmt:format_chars(STRING?, ARGS?, OUT^)
    fmt:format_chars(STRING?, ARGS?, OUT^, TAIL?)
          Format to list of character codes and assign to OUT,
          optionally with a list tail, which defaults to the empty_list.
          STRING may be a string or a list of characters.

    fmt:format_chunked(FILE?, CHUNKS?)
    fmt:format_chunked(FILE?, CHUNKS?, DONE^)
          Format elements of the "chunk" list CHUNKS and write the output
          to file. CHUNKS is a list of output-specifications, as produced
          by "fmt:parse_format/3".

    fmt:format_chars_chunked(CHUNKS?, OUT^, TAIL?)
          Format elements of the "chunk" list CHUNKS and create the character
          list OUT, terminated by TAIL.
          CHUNKS is a list of output-specifications, as produce by
          "fmt:parse_format/3".

    fmt:parse_format(LIST?, ARGUMENTS^, CHUNKS^)
          Parses the format-specifications in the character list LIST with
          arguments taken from the list ARGUMENTS and produces a "chunk" list
          in CHUNKS, terminated by TAIL. If LIST contains invalid formatting
          specifications, or if arguments are missing, the operation aborts
          with an error.


## 9. "sort" module: Sorting

    Sorting of lists, using the total ordering of values provided by the
    "compare" primitive. "sort" sorts a list in ascending order,
    "keysort" sorts a list holding key-value tuples and "merge" merges
    two sorted lists into one.

     Originally from the Edinburgh DEC-10 Prolog utility Library
     Author : R.A.O'Keefe
     this code is in the public domain

    sort:sort(LIST?, RESULT^)
          Sorts the terms in LIST in term order, ascending and assign
          the result to RESULT. Duplicate keys are removed.

    sort:keysort(LIST?, RESULT^)
          Sorts LIST by keys, where each element of LIST is a 3-tuple
          of the form "KEY-VALUE", and assigns the sorted list to RESULT.
          Duplicate keys are removed.
    
    sort:merge(LIST1?, LIST2?, RESULT^)
          Merge the sorted lists and assign the sorted result to
          RESULT.


## 10. "map" module: Key-value maps

    Maps based on AVL trees. The maps allow random-access and are fully
    functional: inserting, deleting or replacing a value will create a
    new map that will share contents with the old one, but both new and old
    map are fully independent. The empty map is equivalent to the empty
    list ("[]").

    Keys may be of any type and are ordered according to the total order
    of values as defined by "compare/3" and "@</2".

    Use "insert" and "replace" to add values, "lookup" to search the map for
    a key and "delete" to delete entries. "keys" and "values" retrieve
    lists of all keys and values of a map, respectively. "list_to_map" and"
    "map_to_list" convert maps to and from lists.

    The implementation of this module was inspired by:
    https://two-wrongs.com/purely-functional-avl-trees-in-common-lisp.html

    map:node(KEY?, VAL?, TREE^)
          Create a new TREE with a single entry.

    map:insert(KEY?, VAL?, TREE?, RTREE^)
          Insert new entry into TREE, assigning the new tree to RTREE.
          If KEY already exists, the existing node is replaced.

    map:delete(KEY?, TREE?, RTREE^)
    map:delete(KEY?, VAL^, TREE?, RTREE^)
          Delete entry from TREE and assign new tree to RTREE, optionally
          assigning old existing value (or []) to VAL.

    map:replace(KEY?, VAL?, TREE?, RTREE)
    map:replace(KEY?, VAL?, OLDVAL^, TREE?, RTREE^)
          Replace existing entry in TREE with new value, optionally assigning
          the old value (or []) to OLDVAL. RTREE holds the final result tree.
          If the entry does not yet exist, create a new one.

    map:lookup(KEY?, TREE?, VAL^)
    map:lookup(KEY?, TREE?, VAL^, DEFAULT?)
          Unifies the value for the entry with the given KEY in TREE to VAL,
          unifies [] (or DEFAULT) if no such entry exists.

    map:keys(TREE?, KEYS^)
    map:keys(TREE?, KEYS^, TAIL?)
          Collects the keys of all entries and assigns the list of keys to KEYS.
          The returned list holds the keys in ascending order.

    map:values(TREE?, VALS^)
    map:values(TREE?, VALS^, TAIL?)
          Collect the values of all entries and assigns the list to VALS.
          The returned list holds the values in the ascendng order of the map's keys.

    map:list_to_map(LIST?, MAP^)
    map:list_to_map(LIST?, MAP1?, MAP^)
          Insert elements from LIST into MAP1 (or into a new map) and
          unifies MAP with the new map, LIST should have elements of the
          form "{'-', <KEY>, <VALUE>}" or "{<KEY>, <VALUE>}".

    map:map_to_list(MAP?, LIST^)
    map:map_to_list(MAP?, LIST^, TAIL?)
          Collects keys and values into a list with elements of the form
          "{'-', <KEY>, <VALUE>}". The list will be in sorted key order,
          ascending.

    map:root(MAP?, KEY^, VALUE^)
          Assigns KEY and VALUE the key and value of the root node of MAP.
          If the map is empty, the predicate fails.

    map:above(MAP?, RMAP^)
    map:below(MAP?, RMAP^)
          Unifies RMAP with the submap holding the elements above or
          below the root node of MAP.


## 11. "list" module: List operations

    This module provides various types of operations on lists, like
    extraction ("take", "drop", "cut", "slice", "split"), appending ("append",
    "join"), searching ("member", "search", "scan") and deleting elements
    ("trim", "delete").

    list:take(NUM?, LIST?, RESULT^, TAIL?)
          Copy the first NUM elements of LIST into RESULT, terminated by TAIL.

    list:drop(NUM?, LIST?, RESULT^)
          Remove the first NUM elements from LIST and unify RESULT with the
          remaining list.

    list:cut(NUM?, LIST?, TAIL?, RESULT^, REST^)
          Copy the first NUM elements of LIST into RESULT, terminated by TAIL
          and unify REST with the remaining list.

    list:make(NUM?, LIST^, TAIL?)
    list:make(NUM?, VALUE?, LIST^, TAIL?)
          Create a list of NUM elements, initialized to VALUE and terminated by
          TAIL. If VALUE is not given, initialize each element to a fresh
          variable.

    list:split(LIST?, SEP?, RESULT^)
    list:split(LIST?, SEP?, RESULT^, TAIL?)
          Splits the list into sublists, separated by SEP.

    list:scan(LIST?, X?, RLIST^, TAIL^)
    list:scan(LIST?, X?, RLIST^, RTAIL^, TAIL^)
          Collect elements of LIST in RLIST until the end of LIST or element
          occurs X and assign remaining elements to TAIL. If given, the end
          of RLIST is terminated with RTAIL or the empty list otherwise.

    list:iota(N?, LIST^, TAIL?)
    list:iota(N?, START?, LIST^, TAIL?)
    list:iota(N?, START?, STEP?, LIST^, TAIL?)
          Creates a sequence of N integers START, START + STEP, ... .
          START and STEP default to 1. The result list is terminated with TAIL
          and unified with LIST.

    list:slice(INDEX?, NUM?, LIST?, RESULT^, TAIL?)
          Returns a list of NUM elements, starting at index INDEX in LIST,
          terminating the extracted list with TAIL. Indexing starts at 1.

    list:search(NEEDLE?, HAYSTACK?, POSITION^)
    list:search(NEEDLE?, HAYSTACK?, PREFIX^, TAIL?, REST^)
          Searches for the list NEEDLE in HAYSTACK and either assigns the
          index of the sublist to POSITION (or 0 if not found) or unifies
          PREFIX with the list of elements in HAYSTACK preceeding NEEDLE
          (terminated by TAIL) and REST with all remaining elements.

    list:trim(SET?, LIST?, RESULT^)
    list:trim_left(SET?, LIST?, RESULT^)
    list:trim_right(SET?, LIST?, RESULT^)
          Remove elements from LIST found in SET from start (left), end
          (right) or both end and unify the result list with RESULT.

    list:delete(ITEM?, LIST?, RESULT^)
          Remove all elements equal to ITEM from LIST and unify the resulting
          list with RESULT.

    list:reverse(LIST?, RESULT^)
    list:reverse(LIST?, RESULT^, TAIL?)
          Reverse list and unify with RESULT, optionally terminated by TAIL.

    list:append(LISTS?, LIST^)
    list:append(LIST1?, LIST2?, LIST^)
          Concatenates all lists in LISTS (or both LIST1 and LIST2) and
          unifies the result with LIST.

    list:member(VALUE?, LIST?, BOOL^)
          Unifies BOOL with the string "true" or "false", depending on
          whether LIST contains a toplevel element that matches VALUE.

    list:last(LIST?, RESULT^)
          Unifies RESULT with the last element of LIST (or the empty list
          if LIST is empty).

    list:prefix(PREFIX?, LIST?, RESULT^)
          Unifies RESULT with the string "true" or "false", depending
          on whether LIST begins with the list PREFIX or not.

    list:suffix(SUFFIX?, LIST?, RESULT^)
          Unifies RESULT with the string "true" or "false", depending
          on whether LIST ends with the list SUFFIX or not.

    list:join(LIST?, SEP?, RESULT^)
    list:join(LIST?, SEP?, RESULT^, TAIL?)
          Unifies RESULT with all elements of the list of lists LIST,
          separated by SEP. The final result is terminated with TAIL,
   	   or the empty list if TAIL is not given.

    list:characters(THING?, LIST^)
    list:characters(THING?, LIST^, TAIL?)
       Converts THING, which should be a string or number, into a list of
       characters and unifies the result with LIST, optionally terminated
       by TAIL, which defaults to the empty list. If THING is already a
       list, it is not changed.

    list:assoc(PROP?, LIST?, VALUE^)
    list:assoc(PROP?, LIST?, VALUE^, DEFAULT?)
      Searches for a tuple or list whose first element is PROP in LIST and
      unifies VALUE with the corresponding list element, if found, or with
      DEFAULT, otherwise. If DEFAULT is not given, "false" is used.

    list:zip(LIST1?, LIST2?, RESULT^)
      Unifies RESULT with a list of 2-element tuples containing the
      elements of LIST1 and LIST2.

    list:nth(INDEX?, LIST?, RESULT^)
      Unify RESULT with the INDEXth item of LIST, starting from index 1.
      Signals an error if the list is too short.

    list:replace(OLD?, NEW?, LIST?, RESULT^)
   	Replace the sequence in the list OLD with the sequence in NEW in
   	LIST and unify the result with RESULT. OLD and NEW may also be
   	atomic and represent the respective single-element list.

    list:index(X?, LIST?, INDEX^)
   	Assign the first position of X in LIST to INDEX, or assign the string "false"
   	if X can not be found in LIST.


## 12. "set" module: Lists as sets

    This module provides operations that treat lists as sets, i.e.
    collections of unique items. "union", "intersection" and "difference" 
    perform the corresponding set operations. "Subset" tests for one
    set being a subset of another, "equal" compares sets, regardless of
    the order of elements.

    set:difference(SET1?, SET2?, RESULT^)
          Computes the set-difference of removing SET2 from SET1.
    
    set:intersection(SET1?, SET2?, RESULT^)
          Computes the intersection of the two lists.
    
    set:union(SET1?, SET2?, RESULT^)
          Computes the union of the two lists.

    set:equal(SET1?, SET2?, RESULT^)
          Unifies RESULT with "true" or "false", depending in whether
          SET1 is the same as SET2.

    set:adjoin(ITEM?, SET?, RESULT^)
          Add element to SET.

    set:subset(SET1?, SET2?, RESULT^)
          Assigs the string true or false to RESULT, depending on whether
          SET1 is a subset of SET2.


## 13. "proc" module: Subprocess invocation

    This module allows invoking sub-processes. The main operation is
    "execute", which takes a program name with optional arguments and
    starts a child process. A status variable will be bound once the
    child process terminates. Further options allow redirecting input
    and output for the child process to and from files or file streams.

    The convenience procedures "shell", "capture", "submit" and "pipe"
    all build on "execute" to simplify running processes without
    redirection or for directly providing data for in- or output of
    the child process.

    proc:execute(STRLIST?, STATUS^)
    proc:execute(STRLIST?, OPTIONS?, PID^, STATUS^)
      Execute command in STRLIST, which may be a string or a list
      of strings or character lists, with I/O channels connected to the
      child process.
      OPTIONS is a list of one ore more forms of the following kind:
        open(CH?, STR?)     open file named STR and redirect from/to
                            channel
        close(CH?)          close channel
        pipe(CH?, FILE^)    open bi-directional pipe for channel
        CH may be one of the strings in, out or err. PID and STATUS are
        unified with the process-identifier of the sub-process and the
        exit status (once it has terminated).

    proc:shell(STRING?)
    proc:shell(STRING?, STATUS^)
      Execute the command in "[sh, '-c', STRING]" (as in execute/3) and assign
      the exit status to STATUS.

    proc:capture(STRLIST?, RESULT^)
    proc:capture(STRLIST?, RESULT^, STATUS^)
      Execute the command in STRLIST (as in execute/3) with
      the output of the command captured in a byte stream and
      assigned to RESULT. The result string will have trailing whitespace
      removed. STATUS, if given is assigned the exit status of the call.

    proc:submit(STRLIST?, INPUT?)
    proc:submit(STRLIST?, INPUT?, STATUS^)
      Execute the command in STRLIST (as in execute/3) with
      the INPUT holding a byte stream that should be sent as the
      subprocess' input. STATUS, if given is assigned the exit status of
      the call.

    proc:pipe(STRLIST?, INPUT?, OUTPUT^)
    proc:pipe(STRLIST?, INPUT?, OUTPUT^, STATUS^)
      Execute the command in STRLIST (as in execute/3) taking the
      byte stream INPUT as input. OUTPUT is a byte stream holding
      the  output of the command. Execution of the subprocess continues until
      INPUT is closed. STATUS, if given is assigned the exit status of
      the call.


## 14. "lex" module: FGHC/FLENG lexical analyzer

    Support lexical analysis and tokenization of FGHC, Strand and FLENG
    source code. Only one operation is exposed, namely "lex_file".

    lex:lex_file(FILENAME?, OUT^, ERRORS?)
      Performs lexical analysis of the given list or file and writes a stream of
      tokens to OUT. Errors are send to the port ERRORS in the form
      error(LINE, FMT, ARGS, EXITCODE).


## 15. "parse" module: FGHC/FLENG parser

    A parser for FGHC, Strand and FLENG source code. This module is used
    internally by the FGHC and FLENG compilers and expose a few procedures
    for taking a stream of tokens (as produced by the "lex" module) and
    producing another stream of terms.

    "parse_terms" takes a token stream or a file and produces a term
    stream. Additionally, a port is expected that receives error messages
    that can then be presented to the user. If a file is the source of
    tokens, a lexical analyzer is implicitly started.

    parse:parse_terms(FILE?, FORMS^, ERRS?)
    parse:parse_terms(TOKENS?, FORMS^, ERRS?)
    parse:parse_terms(FILE?, VTAG?, FORMS^, ERRS?)
    parse:parse_terms(TOKENS?, VTAG?, FORMS^, ERRS?)
          Parses period-terminated toplevel terms from the token stream
          TOKENS or a token-stream read from FILE, with VTAG being a unique
          integer used for tagging variable placeholders (of the form
          "'$VAR'(VTAG, INDEX, NAME)") and writes each toplevel form into the
          stream FORMS. ERRS is a port receiving error messages in the form
          "error(LINENUM, FMT, ARGS, CODE)".

    parse:parse_term(TOKENS?, VTAG?, RTOKENS^, EXP^, ERRS?)
          Parses a single term, terminated by period and assigns it to
          EXP. ERRS is a port receiving error messages.

    parse:parse_term_list(LIST?, FORMS^, ERRS?)
    parse:parse_term_list(LIST?, VTAG?, FORMS^, ERRS?)
          Parses period-terminated expressions from LIST.


## 16. "array" module: Mutable numeric arrays

    This module provides random access numeric arrays. Arrays are
    allocated dynamically and automatically freed after all
    references are dropped. Elements of arrays are stored in native
    format. Indexing starts at zero.

    Note that arrays represent shared mutable data, no provisison is
    made to avoid the problems caused by concurrent read/write access
    to shared memory. It is the responsibility of the user of these
    arrays to ensure correctness in the presence of multiple processes.

    Element types match the respective C types:

      char            unsigned octet ("unsigned char")
      short           16 bit integer ("short")
      int             32-bit integer ("int" or "long")
      long            machine-word sized integer ("long")
      double          double precision floating point ("double")

    Arrays are created with "make", and accessed with "put" and "get".
    Use "length/2" to obtain the size of an array in elements.
    Operations for reading and writing arrays in native format to
    file streams are provided. Arrays are by default mutable, unless
    created by "array:clone/2".

    Note that on 32-bit platforms, "int" and "long" arrays have identical
    element sizes.

    It is also possible to create "views", which are array slices
    refering to another array. Any change to the underlying array
    will be visible in the slice.

    array:make(TYPE?, LENGTH?, ARRAY^)
      Creates an array of the given type, with LENGTH elements.
      TYPE may be one of the strings 'int', 'long', 'char', 'double' or 'short'.
      The array has initially random contents.

    array:list_to_array(TYPE?, LIST?, ARRAY^)
      Creates an array from the elements in LIST with the given TYPE,
      and assigns the result to ARRAY.

    array:put(INDEX?, DATA?, ARRAY?)
    array:put(INDEX?, DATA?, ARRAY?, DONE^)
      Store the values from the list DATA in ARRAY at the given index.
      DATA may also be a single numeric value or a string. After the operation
      is complete, the index of the element following the stored data is
      assigned to DONE. If the data list  exceeds the array range, the
      remaining elements are ignored.
      Data elements may be floating point values if ARRAY is of type
      "double". In all other cases they must be a integers.

    array:get(INDEX?, LENGTH?, ARRAY?, DATA^)
    array:get(INDEX?, LENGTH?, ARRAY?, DATA^, TAIL?)
      Extract LENGTH elements at INDEX from ARRAY and store them in the
      list DATA, optionally terminated by TAIL (which defaults to the
      empty list). Only elements up to the size of the array are extracted.

    array:write(INDEX?, LENGTH?, ARRAY?, FILE?)
    array:write(INDEX?, LENGTH?, ARRAY?, FILE?, DONE^)
      Write LENGTH elements at INDEX in ARRAY in native format to the
      given file descriptor and unify DONE with the number of written bytes
      when the operation is complete. Writing stops when the array length
      is exceeded.

    array:write_utf(INDEX?, LENGTH?, ARRAY?, FILE?)
    array:write_utf(INDEX?, LENGTH?, ARRAY?, FILE?, DONE^)
      Write LENGTH elements at INDEX in the int array ARRAY UTF8 encodded to the
      given file descriptor and unify DONE with the number of written bytes
      when the operation is complete. Writing stops when the array length
      is exceeded.

    array:read(FILE?, INDEX?, LENGTH?, ARRAY?)
    array:read(FILE?, INDEX?, LENGTH?, ARRAY?, DONE^)
      Read LENGTH elements in native format from FILE and store them in
      ARRAY, starting at INDEX. When the operation is complete DONE is
      unified with the number of elements read. Reading stops when the array
      length is exceeded.

    array:fill(VALUE?, ARRAY?)
    array:fill(VALUE?, ARRAY?, DONE^)
    array:fill(VALUE?, INDEX?, LENGTH?, ARRAY?)
    array:fill(VALUE?, INDEX?, LENGTH?, ARRAY?, DONE^)
      Fills ARRAY at INDEX with LENGTH elements of the given VALUE.
      INDEX defaults to 0, LENGTH to the length of the array. When
      the operation is complete, DONE is unified with the empty list.
      VALUE may be a floating point value if ARRAY is of type "double".
      In all other cases it must be an integer.

    array:copy(FROMARRAY?, TOARRAY?, FROMINDEX?, TOINDEX?, COUNT?)
    array:copy(FROMARRAY?, TOARRAY?, FROMINDEX?, TOINDEX?, COUNT?, DONE^)
      Copies COUNT elements from FROMARRAY to TOARRAY at the given
      indices and unifies DONE with the first index in TOARRAY after the copied
      section when the operation is complete. The arrays may be identitical
      and may overlap.

    array:type(ARRAY?, TYPE^)
      Unifies TYPE with the element type of ARRAY, which is one of the
      strings "short", "int", "long", "char" or "double".

    array:view(INDEX?, LENGTH?, ARRAY?, VIEWARRAY^)
    array:view(TYPE, INDEX?, LENGTH?, ARRAY?, VIEWARRAY^)
      Creates a "view", a slice of ARRAY at the given index and length
      and assigns it to VIEWARRAY. The two arrays share the same storage.
      The underlying memory of an array is released when the array and
      all views of it are not longer accessible. TYPE may be given
      explicitly to determine the type as which the shared elements
      are exposed and defaults to the type of the original array.

    array:clone(ARRAY?, CLONED^)
      Creates a read-only copy of ARRAY and assigns it to CLONED.

    array:resize(ARRAY?, SIZE?, NEWARRAY^)
    array:resize(ARRAY?, SIZE?, FILL?, NEWARRAY^)
      Lengthens or shortens ARRAY to the new size. If FILL is given and the
      new size is larger than the old one, added elements are set to FILL.
      NEWARRAY is assigned the new array. FILL defaults to zero. If the
      reallocation should fail, "false" is assigned to NEWARRAY.
      If SIZE equals the current size of ARRAY, NEWARRAY will be
      the identical array.

    array:search(NEEDLE?, HAYSTACK?, FOUND^)
    array:search(NEEDLE?, INDEX?, HAYSTACK?, FOUND^)
    array:search(NEEDLE?, INDEX?, LENGTH?, HAYSTACK?, FOUND^)
      Searches for NEEDLE in the array HAYSTACK, starting at INDEX for at most
      LENGTH elements of HAYSTACK. NEEDLE may be a number, a list of numbers or
      another array. FOUND is assigned the index of the first location of NEEDLE
      in HAYSTACK, or "false", if not found. Searching an array in another array
      performs a direct memory comparison, searching for a numeric value or
      a list of numbers performs element-by-element comparison.

    array:hex_to_binary(ARRAY^, LIST?, RLIST^)
      Convert the hexadecimal digits in the character list LIST into a "char"
      array and unify RLIST with any characters remaining after the last
      valid hex digit ([0-9a-fA-F]). The conversion stops at the first non-hex
      digit. If the number of digits is uneven, "0" is added.

    array:binary_to_hex(ARRAY?, LIST^)
    array:binary_to_hex(ARRAY?, LIST^, TAIL?)
       Convert the "char" array ARRAY into a list of hexadecimal characters
       and assign the list to LIST, optionally terminated by TAIL.

    array:pack(OBJECT?, ARRAY?, INDEX?, RINDEX^)
      Writes a binary representation of OBJECT into the long integer array
      ARRAY at position INDEX and assigns the index of the first unused
      item after the stored object in the array to RINDEX. Note that
      arrays, ports, modules and variables can not be serialized using
      this operation. If the array is not large enough to contain the
      serialization, the empty list will be assigned to RINDEX. If OBJECT
      contains unserializable data, the string "error" will be assigned
      to RINDEX.

    array:unpack(ARRAY?, INDEX?, RINDEX^, OBJECT^)
      Reads the binary representation of a serialized object from the
      long integer array ARRAY at position INDEX and unifies the object and
      the position of the rest of the array to OBJECT and RINDEX,
      respectively.

    array:map(FILE?, FLAGS?, TYPE?, LENGTH?, ARRAY^)
    array:map(FILE?, FLAGS?, TYPE?, LENGTH?, OFFSET?, ARRAY^)
      Maps the file designated by the file descriptor FILE into memory using
      the mmap(2) system call and assigns an array representation of the mapped
      memory to ARRAY. LENGTH and OFFSET limit the portion of the mapped
      contents of the file. FLAGS may be a string or a list of strings, from the set
      'PROT_EXEC', 'PROT_READ', 'PROT_WRITE', 'MAP_PRIVATE',
      'MAP_SHARED' and 'MAP_ANON'. TYPE should be a string and specify
      the type, as in "array:make".
      OFFSET defaults to zero. If an error occurs, ARRAY will be assigned the
      string "error", in case some of the arguments are invalid, or the tuple
      "error(ERRNO, STRING)" in case the system call failed.

      Memory mapped arrays must be manually unmapped using "array:unmap"
      for releasing the associated operating system resources.

    array:unmap(ARRAY?)
    array:unmap(ARRAY?, DONE^)
      Unmaps the memory-mapped array ARRAY from memory using the munmap(2)
      system call and assigns the empty list to DONE, when the operation has
      completed or the tuple "error(ERRNO, STRING)" on error.

    array:synchronize(ARRAY?, INDEX?, LENGTH?)
    array:synchronize(ARRAY?, INDEX?, LENGTH?, DONE^)
      Synchronizes any non-written pages from the memory mapped ARRAY to disk,
      from elements starting at INDEX up to INDEX + LENGTH and assigns "true"
      to DONE when the operation is completed. Should an error occur, DONE
      will be assign a tuple "error(ERRNO, STRING)".


## 17. "app" module: Higher-order operations on lists

    This module provides operations to invoke user-specifcied goals
    over lists, like fold, mapp, filter and partition.

    All goals default to the empty module ('':...) when no module prefix
    in given. Goals are invoked using "apply/2".

    The FGHC->FLENG compiler will detect and wrap primitive operations in GOAL
    position, but if GOAL is a variable, then it must refer to a
    user-defined process.

    [PCN] For PCN programs, the goals must be user-defined and given either
    in the "``...``" syntax or as strings or tuples of the form

      {"<name>", <argument>, ...}

    Calls to specific modules should be encoded as tuples like this:

      {":", "<module>", "<name>"}
      {":", "<module>", {"<name>", <arguments>, ...}}

    app:maplist(GOAL?, LIST?, RESULTLIST^)
    app:maplist(GOAL?, LIST?, RESULTLIST^, TAIL?)
          Invoke "apply(GOAL?, [ELEMENT?, RESULT^])" for each element of LIST and
          unify the list of results with RESULTLIST, optionally terminated by
          TAIL.
    app:mapappend(GOAL?, LIST?, RESULT^, TAIL?)
          Invoke "apply(GOAL?, [ELEMENT?, ARESULT^, ATAIL?])" for each
          element of LIST, where ARESULT + ATAIL represent a list of results
          which are combined into a final list. ARESULT always equals the
          ATAIL of the goal-invocation of the previous element. The final list
          is terminated by TAIL.

    app:foreach(GOAL?, LIST?)
    app:foreach(GOAL?, LIST?, DONE^)
          Invoke "apply(GOAL?, [ELEMENT?])" for each element of LIST and unifies DONE
          with the empty list when the last application is invoked.
          The applications of GOAL are performed as a separate task and
          each application only takes place after the previous one completed.

    app:filter(GOAL?, LIST?, RESULTLIST^)
    app:filter(GOAL?, LIST?, RESULTLIST^, TAIL?)
          Invoke "apply(GOAL?, [ELEMENT?, RESULT^])" for each element of LIST and
          unify the list of elements for which RESULT was "true" with RESULTLIST,
          optionally terminated with TAIL.

    app:partition(GOAL?, LIST?, TRUERESULTS^, FALSERESULTS^)
          Invoke "apply(GOAL?, [ELEMENT?, RESULT^])" for each element of LIST and
          unify the list of elements for which RESULT was "true" with TRUERESULTS and
          those for which RESULT was "false" with FALSERESULTS.

    app:foldl(GOAL?, LIST?, INITIAL?, FINAL^)
          Invoke "apply(GOAL, [ELEMENT?, PREVIOUS?, RESULT^])" for
   	   each element of LIST, where PREVIOUS holds the result of the previous
          application (INITIAL if this is the first one) and unifies FINAL with the final result.

    app:mapreduce(GOAL?, LIST?, INITIAL?, FINAL^)
          Similar to app:foldl, but invokes GOAL over as many threads as LIST has
          elements.

    app:take(GOAL?, LIST?, RESULT^, TAIL^)
    app:take(GOAL?, LIST?, RESULT^, TAIL^, MORE^)
          Unify RESULT with the elements of LIST until "apply(ELEMENT, FLAG)"
          assigns "false" to FLAG. The result list is terminated with TAIL.
          if MORE is given, it will be unified with the remaining list in case
          GOAL returns false.

    app:drop(GOAL?, LIST?, RESULT^)
          Unify RESULT with the elements of LIST starting from the location
          at which "apply(ELEMENT, FLAG)" first assigns "false" to FLAG.

    app:any(GOAL?, LIST?, RESULT^)
          Unifies RESULT with "true" if "apply(GOAL, [ELEMENT?, FLAG^])"
          assigs a value other than "false" to FLAG for at least one of the
          elements of LIST.

    app:every(GOAL?, LIST?, RESULT^)
          Unifies RESULT with "true" if "apply(GOAL, [ELEMENT?, FLAG^])"
          assigns a value other than "false" to FLAG for all elements of LIST.

    app:sequence(GOAL?, COUNT?, RESULT^, TAIL?)
    app:sequence(GOAL?, START?, COUNT?, RESULT^, TAIL?)
          Call GOAL with additional arguments [N, R], where N increases from
          START (or 1) to COUNT (inclusive) and unify RESULT with the list of
          results R, terminated by TAIL.

    app:compose(GOALS?, INITIAL?, RESULT^)
          Invokes each goal in the list GOALS with "apply(GOAL?, VALUE?,
          NEXT^)", taking the result of the previous application (INITIAL,
          in the first GOAL and the previous NEXT in all subsequent goals)
          and unifies RESULT with the final value.

    app:index(GOAL?, LIST?, INDEX^)
          Invokes "apply(GOAL, [ELEMENT?, FLAG^])" and assigns the index
          (starting from 1) to INDEX where FLAG returns a non-false value.
          If no element succeeds, assigns the string "false" to INDEX.


## 18. "io" module: Extended I/O stream operations

    This module contains several procedures to read and write from
    byte and character-streams. Character-handling is assuming UTF-8
    encoding. Use "read_byte_stream" and "write_byte_stream" for
    raw binary access and "read_char_stream" and "write_char_stream"
    for automatic decoding and encoding from and to UTF-8.

    "read_lines", "parse_lines" and "write_lines" access whole lines
    of in- or output.

    To have better control over the speed at which data is consumed,
    use "read_byte_stream_chunked", "read_lines_bounded" or
    "rate_limited_stream".

    io:read_byte_stream(FILE?, LIST^)
        Reads bytes from the file designated by the file descriptor FILE
        and writes them into the stream given by LIST until the end of
        file is reached.

    io:read_byte_stream_chunked(FILE?, LIST^, CHUNKS^)
        Reads bytes from the file designated by the file descriptor FILE
        and writes them as separate lists into LIST. The length of each
        sublist is taken from the stream CHUNKS. When the end of file is
        reached then LIST is terminated with an empty list as its
        remaining element (or an error indicator in case of a read-error).
        This library primitive allows control over the amount of bytes
        read, something that is not possible with "read_byte_stream", the
        latter always reading as many bytes as quickly as possible, which
        may exhaust available memory when the consumer of the output
        stream is too slow.

    io:read_char_stream(FILE?, LIST^)
        Reads UNICODE characters from the file designated by the file
        descriptor FILE and writes them into the stream given by LIST
        until the end of file is reached.

    io:write_byte_stream(IN?, FILE?)
    io:write_byte_stream(IN?, FILE?, DONE^)
        Writes the bytes in the integer stream IN blockwise into FILE
        until IN is empty. The operation may block the current thread.
        This predicate fails if the underlying file-system operation
        should result in an error. DONE, when given, is unified with the
        empty list when the operation is complete.

    io:write_char_stream(IN?, FILE?)
    io:write_char_stream(IN?, FILE?, DONE^)
        Writes the UNICODE code points in the integer stream IN blockwise
        into FILE until IN is empty. The operation may block the current
        thread. This predicate fails if the underlying file-system
        operation should result in an error. DONE, when given, is unified
        with the  empty list when the operation is complete.

    io:read_lines(FILE?, LINES^)
      Read lines from FILE and store each line as a character list in the
      stream LINES. This operation will read lines "eagerly", so reading from
      a large file may consume memory unless the lines are processed quick
      enough.

    io:parse_lines(IN?, LINES^)
      Parses data from the byte stream IN into a list of byte/character lists
      and unify the result with LINES.

    io:write_lines(LINES?, FILE?, DONE^)
      Writes elements from the list LINES to FILE and unifies DONE with the empty
      list when finished. LINES may contain numbers, strings or character lists
      and each line is terminated by "\n".

    io:read_lines_bounded(FILE?, IN?, LINES^)
      Read lines from FILE, but fills LINES with variables holding input lines
      as supplied by the stream IN. It provides a "bounded buffer", producing
      lines only on demand and not filling up memory with still unprocessed input.
      If IN is terminated by the empty list, reading will stop.

    io:transfer(FROM?, TO?, DONE^)
    io:transfer(FROM?, TO?, COUNT?, DONE^)
      Copy data from the file descriptor FROM to TO, at most COUNT bytes,
      or all if COUNT is not given. Unifies DONE with the empty list when the
      operation is complete.

    io:rate_limited_stream(RATE?, STREAM^, ID^)
      Starts a timer producing a stream of unbound variables at RATE per
      second. ID holds the timer ID and can be used to terminate the
      stream by calling "cancel_timer(ID)".


## 19. "scan" module: Simple parsers for various character sequences

    This module provides "scanners", operations that take a character
    list and parse it according to certain criteria. "identifier", "number",
    "word", "integer" and "whitespace" scan the prefix of a character
    list as long as it falls into the required character class.
    "delimited", "from_set" and "not_from_set" give a bit more control
    over the characters pass and whose that do not.

    scan:integer(NUM^, LIST?, REST^)
           Unify NUM with integer digits from LIST and unify REST with the
           remaining list. The integer may start with the "-" character.

    scan:number(NUM^, LIST?, REST^)
           Unify NUM with numeric characters representing a valid number
           from LIST and unify REST with the remaining list, or unify N with
           the empty list if no number is found. The number may start with
           the "-" character.

    scan:word(WORD^, LIST?, REST^)
           Unify WORD with non-whitespace characters from LIST
           and unify REST with the remaining list, or unify WORD with
           the empty list if no word is found.

    scan:delimited(DELIM?, STRING^, LIST?, REST^)
           Unify STRING with characters from LIST until the character code DELIM
           is found and unify REST with the remaining list.

    scan:delimited_with_escape(DELIM?, STRING^, LIST?, REST^)
           Unify STRING with characters from LIST until the character code DELIM
           is found and unify REST with the remaining list.
           The escape sequences  "\n", "\r", "\t", "\b", "\f", "\xXX", "\uXXXX" and
   	    "\<c>" are handled properly.

    scan:identifier(IDENT^, LIST?, REST^)
           Unify IDENT with characters from LIST representing a valid identifier,
           which starts with a letter or "_" and is followed by digits,
           letters or "_", unify REST with the remaining list. If no
           identifier can be scanned, unify IDENT with the empty list.

    scan:from_set(CHARS?, RESULT^, LIST?, REST^)
           Unify RESULT with characters from LIST that can be found in the list CHARS
           and unify REST with the remaining list.

    scan:not_from_set(CHARS?, RESULT^, LIST?, REST^)
           Unify RESULT with characters from LIST that are not in the list CHARS
           and unify REST with the remaining list.

    scan:whitespace(LIST?, REST^)
           Skip whitespace characters in LIST and unify REST with the remaining list.

    scan:format(FORMAT?, RESULTS?, LIST?, REST^)
   	Scans LIST according to FORMAT, which should be a string or character list.
   	REST will be unified with any remaining data in LIST.
   	FORMAT may contain characters, which are matched with elements from
   	LIST or a sequence of the form "~C", where C specifies what type of
   	subsequence should be extracted. Valid format specifiers are:

   	~u	Scan a single character
   	~d	Scan a decimal number (as with "scan:number/3")
   	~i	Scan an integer number (as with "scan:integer/3")
   	~n	Scan an identfiier (as with "scan:identifier/3")
   	~w	Scan a word (as with "scan:word/3")
   	~s	Scan any number of whitespace (as with "scan:whitespace/2")
   	~~   Expect the character "~"

   	Results of scanning each "~"-preceded format are unified with elements
   	of the list RESULTS, with the exception of "~~".
   	If scanning fails, REST will be unified with the string "false".

   	A format sequence may also be of the form "~<N><F>"
   	or "~*<F>", giving the number of items to be decoded. "*" takes an additional
   	argument specifying the count before the one representing the decoded value.

    scan:decode(CHUNKS?, LIST?, REST^)
   	Equivalent to "format", but uses pre-parsed chunks. Consult the "fmt" and "binfmt"
   	library units for more information about how pre-parsed chunk-lists correspond
   	to formatting strings.


## 20. "match" module: Pattern matching

    This module allows matching sequences with patterns. Patterns may be
    strings or lists and are matched according to the following rules:
    Each element of the pattern is matched with zero or more elements of
    the subject list

      0'*     matches zero or more elements
      0'?     matches any element
      0'[, ..., 0']       matches any element between the brackets
      0'[, 0'^, ..., 0']  matches an element that different from the sequence
                          given between the brackets
          Bracket-sequences may contain ranges of the form
          <element1>, 0'-, <element2>

      [X, ...]  matches any X (like brackets above)
      {X}     matches the arbitrary value X
      call(X) matches if "apply(X, [SUBJECT?, R^])" assigns anything but the
                string "false" to R.

    Note that patterns and subjects need not necessarily be character
    lists.

    "all" matches a full subject sequence, "begins" only a prefix. "find"
    searches a sequence for a match, and "extract" will produce the
    matched part after searching a sequence.

    match:all(PATTERN?, SUBJECT?, RESULT^)
      Unifies RESULT with "true" or "false", depending on whether PATTERN
      matches the complete sequence SUBJECT.

    match:begins(PATTERN?, SUBJECT?, REST^)
      Unifies REST with the portion of SUBJECT that follows the part matching
      PATTERN, or "false", if SUBJECT does not begin with a matching sequence.

    match:find(PATTERN?, SUBJECT?, REST^)
    match:find(PATTERN?, SUBJECT?, PREFIX^, REST^)
    match:find(PATTERN?, SUBJECT?, PREFIX^, PREFIXTAIL?, REST^)
      Searches SUBJECT for a sequence matching PATTERN and unifies PREFIX
      with the part before the match (terminated by PREFIXTAIL, which defaults to
      the empty list) and REST with the remaining part. If no match can be
      found, REST is unified with the string "false".

    match:extract(PATTERN?, SUBJECT?, MATCH^)
    match:extract(PATTERN?, SUBJECT?, MATCH^, TAIL?)
    match:extract(PATTERN?, SUBJECT?, MATCH^, TAIL?, REST^)
    match:extract(PATTERN?, SUBJECT?, PREFIX^, PREFIXTAIL?, MATCH^, TAIL?, REST^)
      Like "find", but unifies MATCH with the found sequence, optionally
      terminated by TAIL (which defaults to the empty list). PREFIX and
      PREFIXTAIL designate the part before the match (if found).

    match:fields(PATTERN?, SUBJECT?, LIST^)
    match:fields(PATTERN?, SUBJECT?, LIST^, TAIL?)
       Unifies LIST with a list of sub-lists in SUBJECT separated by PATTERN,
       optionally terminated by TAIL.


## 21. "path" module: Pathname destructuring

    This module provides basic operations to extract parts of filenames.
    All predicates accepts strings or character lists as input filenames
    and always produce character lists.

    Use "basename", "tail", "dirname" and "extension" to extract parts of
    a filename. "canonical" normalizes a path as much as possible by
    eliminating redundant "." and ".." parts. "join" creates a new filename
    by joining directory components.

    path:basename(NAME?, BASENAME^)
      Unify the last non-directory part of NAME without the file-
      extension with BASENAME.

    path:tail(NAME?, TAIL^)
      Unify the last non-directory part of NAME with TAIL.

    path:dirname(NAME?, DIR^)
      Unify the directory part of NAME with DIR.

    path:extension(NAME?, DIR^)
      Unify the part of NAME after the last "." (if any) with DIR. If
      the file has no extension, then unify DIR with the empty list.

    path:normalize(NAME?, NNAME^)
      Unifies NNAME with a character list of the normalized representation of
      NAME with redundant "." and ".." parts removed.

    path:canonical(NAME?, CNAME^)
    path:canonical(NAME?, ROOT?, CNAME^)
      Unifies CNAME with a character list of the normalized representation of
      NAME as an absolute path based on ROOT (or the current working
      directory), with redundant "." and ".." parts removed.

    path:join(PARTS?, JOINED^)
      Join directory and filenames, separated by the 0'/ character and
      unify JOINED with the result. The parts may be strings or character
      lists.

    path:with_root(DIRECTORY?, PATH?, RPATH^)
   	If PATH is an absolute path, assign its value to RPATH, otherwise
   	prepend DIRECTORY to PATH and assign the result to RPATH.

    path:with_extension(EXTENSION?, PATH?, RPATH^)
   	Replace the last element separated by "." in PATH with EXTENSION
   	and unify the result with RPATH. PATH and EXTENSION may be
   	strings or character lists.


## 22. "find" module: Find files and directories

    Collect lists of files in a given directory matching certain
    criteria.

    Use "files" and "leaves" to collect files for which a given goal
    succeeds, or "matching" to collect files that match a particular
    pattern. Consult the documentation for the "match" library module
    for further information regarding matching.

    find:files(GOAL?, FILES^)
    find:files(GOAL?, ROOT?, FILES^)
    find:files(GOAL?, ROOT?, FILES^, TAIL?)
    find:files(GOAL?, ROOT?, TEST?, FILES^, TAIL?)
      Traverses ROOT (or the current directory) recursively and unifies
      FILES with the list of all files that pass the test represented by
      GOAL. The file-list is terminated by TAIL or the empty list, if TAIL
      is not given. Sub-directories are ignored if the goal TEST answers
      "false" when passed the directory name.

      GOAL is invoked by calling "apply(GOAL, [FILENAME?, RESULT^])",
      TEST by calling "apply(TEST?, [DIRECTORY?, RESULT^])". Note that
      if GOAL or TEST have no module prefixes, then they default to
      the main ('') module. TEST may also be the empty list, meaning
      to descend into any subdirectory not detected by GOAL.

    find:matching(PATTERN?, FILES^)
    find:matching(PATTERN?, ROOT?, FILES^)
    find:matching(PATTERN?, ROOT?, FILES^, TAIL?)
      Unify FILES with a list of files and directories found in ROOT
      (or the current directory) that have names matching PATTERN,
      as with "match:all". Directories are traversed recursively.
      The list is terminated by TAIL or the empty list, if TAIL is not
      given.

    find:leaves(ROOT?, FILES^)
    find:leaves(GOAL?, ROOT?, FILES^)
    find:leaves(GOAL?, ROOT?, FILES^, TAIL?)
      Unifies FILES with all non-directory entities for which GOAL, when
      applied to the entity-name returns true. GOAL is invoked by calling
      "apply(GOAL, [FILENAME?, RESULT^])". If no module prefix is given
      in GOAL, it defaults to the main ('') module.

      The 2-argument variant returns all non-directory files in ROOT.


## 23. "base64" module: Base64 encoding/decoding

    Operations to create or decode Base64 representation of a stream of bytes.

    base64:encode(IN?, OUT^)
    base64:encode(IN?, OUT^, TAIL?)
          Encode bytes in stream IN as a base64 encoded list of bytes to stream OUT,
          terminated by TAIL or the empty list, if not given.

    base64:decode(IN?, OUT^)
    base64:decode(IN?, OUT^, TAIL?)
          Decode the base64 encoded data bytes in stream IN to the byte stream OUT,
          terminated by TAIL which defaults to the empty list.


## 24. "binfmt" module: binary string formatting/scanning

    This module provides operations to encode or decode binary data.

    Formats for encoding and decoding can be specified either
    as a string, similar to "fmt:format", or as a "chunk" list of 2-tuples
    holding a format-specifier and a value (or variable for decoding).
    Integers or strings in chunk lists are treated as unsigned bytes and
    encoded as is.

    Format strings are written as UTF-8 encoded strings, with sequences
    of the form "~<F>" being replaced by an associated argument value.
    "~~" is equivalent to "~", as with textual formatting ("fmt").

    Valid formats are:

   	b		an unsigned 8 bit integer
   	s		a signed 16-bit integer
   	i		a signed 32-bit integer
   	q		a signed 64-bit integer
   	f		a 32-bit float value in the machines native format (usually IEEE)
   	d		a 64-bit float value in the machines native format
   	u		a UTF-8 byte sequence
   	+		skip number of bytes given as argument

    When encoding, values formatted may be lists of values, each element will
    then be formatted as specified.

    For scanning, a format sequence may also be of the form "~<N><F>"
    or "~*<F>", giving the number of items to be decoded. "*" takes an additional
    argument specifying the count before the one representing the decoded value.

   	binfmt:format(FMT?, ARGS?)
   	binfmt:format(FILE?, FMT?, ARGS?)
   	binfmt:format(FILE?, FMT?, ARGS?, DONE^)
   	binfmt:format(FILE?, FMT?, ARGS?, ENDIAN?, DONE^)
   		Parses the format FMT, which may be a string or a character list
   		and encodes the values in the list ARGS according to the format
   		specifications to the file descriptor FILE. FILE defaults to 1 (stdout),
   		ENDIAN defaults to "little" and may also be "big" to force big-endian
   		output. When the operation is completed DONE will be assigned the
   		empty list.

   	binfmt:format_chunked(CHUNKS?)
   	binfmt:format_chunked(FILE?, CHUNKS?)
   	binfmt:format_chunked(FILE?, CHUNKS?, DONE^)
   	binfmt:format_chunked(FILE?, CHUNKS?, ENDIAN?, DONE^)
   		Encodes preformatted chunks in FILE using "encode", optionally with
   		endianness (defaults to "little") and confirmation variable DONE.

   	binfmt:format_bytes(FMT?, ARGS?, LIST^)
   	binfmt:format_bytes(FMT?, ARGS?, LIST^, TAIL?)
   	binfmt:format_bytes(FMT?, ARGS?, ENDIAN?, LIST^, TAIL?)
   		Format according to FMT and create a list of bytes, unified with LIST
   		and terminated by TAIL (which defaults to the empty list). ENDIAN
   		defaults to "little".

   	binfmt:scan_bytes(FMT?, ARGS?, LIST?, TAIL^)
   	binfmt:scan_bytes(FMT?, ARGS?, ENDIAN?, LIST?, TAIL^)
   		Decodes according to FMT and unifies each element of the list ARGS
   		with the decoded values. TAIL defaults to the empty list, ENDIAN to
   		"little".

   	binfmt:encode(CHUNKS?, LIST^, TAIL?)
   	binfmt:encode(CHUNKS?, ENDIAN?, LIST^, TAIL?)
   		Encodes the "chunk" list CHUNKS and unifies the result with LIST,
   		optionally terminated by TAIL which defaults to the empty list.

   	binfmt:decode(CHUNKS?, LIST?)
   	binfmt:decode(CHUNKS?, LIST?, TAIL^)
   	binfmt:decode(CHUNKS?, ENDIAN?, LIST?, TAIL^)
   		Decodes the bytes in LIST according to the "chunk" list CHUNKS
   		and unifies TAIL with the remaining elements. ENDIAN defaults to
   		"little".


## 25. "9p" module - a client library for the 9P protocol

    This module provides an interface for writing 9P[1] clients.
    Use "9p:client" to speak 9P via a pair of file descriptors by passing
    requests as tuples into a "request stream".

    [1] https://en.wikipedia.org/wiki/9P_(protocol)

    '9p':client(IN?, OUT?, ANAME?, UNAME?, S^, ROOT^, DONE^)
          Runs a 9P client, writing requests to the file IN and reading responses from
          OUT. ANAME is the attach point, UNAME is the user name that is trying to attach
          and ROOT is a variable which will be assigned the root fid. S is a stream
          of request tuples, described below. Version requests are handled by
          the client internally on establishing the communication. Authentification is
          currently not supported. When the server closes the connection, DONE
          is assigned the empty list.

       Valid request tuples are the following:

          clunk(FID?)
           Drops the FID.

          flush(TAG^)
           Drops response handling of the given TAG.

          open(TAG^, FID?, MODE?, QID^, IOUNIT^ )
           Open file given by FID in MODE and unifies QID and IOUNIT with
           the results given by the servers response. If the request fails,
           QID will be unified with a tuple of the form "error(MESSAGE)".
           Assigns an "error(MESSAGE)" tuple to QID on error.
           MODE may be an integer, a string or a list of strings specifying
           flags like "OEXCL", "ORDWR", etc.

         create(TAG^, FID?, NAME?, PERM?, MODE?, QID^, IOUNIT^)
           Create a file given by FID with PERM and MODE. If the request fails,
           QID will be unified with a tuple of the form "error(MESSAGE)".
           Assigns an "error(MESSAGE)" tuple to QID on error.
           MODE may be an integer, a string or a list of strings specifying
           flags like "OEXCL", "ORDWR", etc.

          read(TAG^, FID?, OFFSET?, COUNT?, RCOUNT^, READ^, TAIL?)
           Reads COUNT bytes at OFFSET from the given file and unifies
           READ with the list of bytes received, terminated by TAIL which
           defaults to the empty list. RCOUNT will be unified with the number
           of bytes actually read.
           If the request fails, READ will be unified with a tuple of the form
           "error(MESSAGE)".

          write(TAG^, FID?, OFFSET?, DATA?, COUNT^)
           Writes the bytes in the list DATA to the given file at OFFSET and
           unifies COUNT with the actual number of bytes written.
            If the request fails, COUNT will be unified with a tuple of the form
           "error(MESSAGE)". No check is made whether the data exceeds
           the I/O unit size.

          remove(TAG^, FID?, DONE^)
           Remove the given file and assign the empty list to DONE when
           the operation is completed. If the request fails,
           DONE will be unified with a tuple of the form "error(MESSAGE)".
           Assigns an "error(MESSAGE)" tuple to DONE on error.

          stat(TAG^, FID?, STAT^)
           Read a "stat" structure for the given FILE and unify it with STAT.
           If the request fails, STAT will be unified with a tuple of the form
           "error(MESSAGE)".
           Assigns an "error(MESSAGE)" tuple to STAT on error.

          wstat(TAG^, FID, STAT?, DONE^)
           Write the "stat" structure in STAT for the given file and assign the
           empty list to DONE when the operation is completed. If the request fails,
           DONE will be unified with a tuple of the form "error(MESSAGE)".
           Assigns an "error(MESSAGE)" tuple to DONE on error.

          walk(TAG^, FID?, PATH?, NFID^, QIDS^)
           Walk the file system at the root given by FID, for the path in the
           string, character list, list of strings or list of character lists in PATH.
           If a character list or string, embedded slashes ("/") separate path
           components. The path should always be relative. NFID will be the assigned
           a fresh fid representing the result (if valid). QIDS will be unified with
           a list of "qid" structures corresponding to the path walked and may
           be shorter than the requested depth in PATH if an element could not
           be found. If the request fails, QIDS will be unified with a tuple of the
           form "error(MESSAGE)".
           Assigns an "error(MESSAGE)" tuple to QIDS on error.

       In the requests above TAG is unified with an integer specifying the request.

        STAT records have the form

              stat(QID, MODE, ATIME, MTIME, LEN, NAME, UID, GID, MUID)

        QID records have the form

           qid(TYPE, VERSION, PATH)

       where TYPE specifies whether the file represents a directory or append-only
       file, etc. VERSION is an integer version number and PATH is a list of 8
       bytes, uniquely identifying the file.

       A slightly higher-level interface is also available with the "open", "create",
       "remove", "stat", "fread" and "fwrite" predicates, described below.

    '9p':connect(SOCKET?, IN^, OUT^, STATUS^)
       Connect to the UNIX socket with the filename SOCKET and return the
       input- and output file descriptors IN and OUT. STATUS holds the exit
       status of the process handling the connection, which is established via
       socat(1).

    '9p':permissions(PERM?, BITS^)
       Converts a string or character list PERM into a 32-bit permissions bitmask
       and assigns it to BITS. PERM may begin with 'd' to specify a directory.
       the remaining characters should be 3 triples of characters holding
       'r', 'w', 'x' or '-' to specify access permissions for user, group and others,
       e.g. "rwxr--r-" would specify user read/write/exec access but only
       read access for group and others. If PERM is an integer, it is assigned
       unchanged to BITS.

    '9p':parse_stat(STAT^, DATA?, TAIL^)
       Parse a "stat" structure from the byte-stream DATA, unify it with STAT
       and assign the remaining data to TAIL.

    '9p':parse_stat_list(DATA?, STATLIST^)
       Uses "parse_stat" and unify STATLIST with a list of "stat" structures
       contained in the byte-stream DATA. This operation is useful for
       parsing directory information previously read from the server.

    '9p':bits(BITS?, MASK^)
       Assigns an 8-bit integer to MASK representing the bitmask specified by the
       BITS argument, which can be a string or a list of strings of any of the
       following:

           DMDIR, DMAPPEND, DMEXCL, DMMOUNT, DMAUTH, DMTMP,
           DMREAD, DMWRITE, DMEXEC, QTDIR, QTAPPEND, QTEXCL,
           QTMOUNT, QTAUTH, QTTMP, QTSYMLINK, QTFILE,

    '9p':open(PATH?, ROOT?, FID^, RS1^, RS2?)
    '9p':open(PATH?, ROOT?, MODE, FID^, RS1^, RS2?)
    '9p':create(PATH?, ROOT?, MODE?, FID^, RS1^, RS2?)
    '9p':remove(PATH?, DONE^, RS1^, RS2?)
    '9p':stat(PATH?, ROOT?, STAT^, RS1^, RS2?)
         Perform "walk" requests to locate the files named by PATH in the directory tree
         ROOT and open, create or remove the file, or obtain stat information using the
         appropriate 9P requests. RS1 and RS2 are the 9P request stream as obtained from
         "'9p':client". On error FID, DONE or STAT will be unified with a tuple of the
         form "error(MESSAGE)".

    '9p':fstat(FID?, STAT^, RS1^, RS2?)
         Requests stat information on the file represented by FID (and previously
         opened via "open") and unifies STAT with the result. RS1 and RS2 are the 9P
         request stream as obtained from "'9p':client".

    '9p':fwstat(FID?, STAT?, DONE^, RS1^, RS2?)
         Writes stat information on the file represented by FID (and previously
         opened via "open" pr "create") and unifies DONE with the empty list, when
         done. RS1 and RS2 are the 9P request stream as obtained from "'9p':client".

    '9p':close(FID?, RS1^, RS2?)
         Closes the file represented by FID. RS1 and RS2 are the 9P request stream
         as obtained from "client".

    '9p':fread(FID?, DATA^, TAIL?, RS1^, RS2?)
    '9p':fread(FID?, COUNT?, DATA^, TAIL?, RS1^, RS2?)
    '9p':fread(FID?, OFFSET?, COUNT?, DATA^, TAIL?, RS1^, RS2?)
         Reads bytes from the file previously opened via "open" and represented by FID
         into DATA, terminated by TAIL. Optionally, offset and count can be given.
         RS1 and RS2 are the 9P request stream as obtained from "client".
         If the request fails, DATA will be unified with a tuple of the form
         "error(MESSAGE)".

    '9p':fwrite(FID?, DATA?, RCOUNT^, RS1^, RS2?)
    '9p':fwrite(FID?, COUNT?, DATA?, TAIL^, RCOUNT^, RS1^, RS2?)
    '9p':fwrite(FID?, OFFSET?, COUNT?, DATA?, TAIL^, RCOUNT^, RS1^, RS2?)
         Writes bytes in the list or string DATA to the file previously opened via "open" or
         "create" and represented by FID. Optionally, offset and count can be given.
         TAIL will be unified with remaining data if COUNT is given. RS1 and RS2 are
         the 9P request stream as obtained from "client".
        If the request fails, RCOUNT will be unified with a tuple of the form
         "error(MESSAGE)".

    '9p':readdir(PATH?, ROOT?, STATS^, RS1^, RS2?)
    '9p':freaddir(FID?, STATS^, RS1^, RS2?)
         Read directory from FID or opened at PATH. RS1 and RS2 are
         the 9P request stream as obtained from "client".


## 26. JSON parsing

    A parser and printer for JSON objects. JSON data is mapped to FLENG terms
    in the following manner:

               null, true, false   -> string
               object              -> '{}'([<charlist>:<value>, ...])
                           [PCN] {"{}", [{":", <charlist>, <value>}, ...]}
               array               -> array([...])  [PCN] {"array", [...]}
               string              -> character code list
               number              -> number

    Use "json:read" to read JSON expressions and "json:to_string" and "json:print" to
    convert parsed JSON expressions to character lists or write them to a file,
    respectively. "json:query" provides a simple querying mechanism for JSON
    expressions.
    json:read(IN?, OUT^)
    json:read(X^, IN?, OUT^)
       Unifies X with a JSON term scanned from the character stream IN, with
       the remaining input in OUT or reads successive terms from IN and writes
       them to the stream OUT.
       Errors will insert "error(MSG)" tuples into the output. The parser
       attempts to be permissive, especially with the placement of ","
       characters.

    json:print(TERM?)
    json:print(FILE?, TERM?)
    json:print(FILE?, TERM?, DONE^)
       Writes TERM in JSON representation to FILE (or standard output),
       optionally assigning the empty list to DONE when the operation is
       complete.

    json:to_string(TERM?, LIST^)
    json:to_string(TERM?, LIST^, TAIL?)
       Unifies LIST with a string containing the JSON representation
       of TERM, optionally with tail TAIL.
   	For convenience, this operation detects numeric arrays and
   	converts them into JSON arrays. Strings that are not one of "true",
   	"false" and "null" are written as quoted strings. "error" tuples
   	creating during parsing will trigger an error when an attempt is
   	made to convert it to a string.

    json:query(QUERY?, OBJECT?, RESULT^)
    json:query(QUERY?, OBJECT?, RESULT^, TAIL?)
       Extracts elements from the parsed JSON object OBJECT and unifies
       RESULT with the list of results, optionally terminated by TAIL.

           Queries may be any of the following:

              index(I)        returns a list of the Ith element of the
                              object, which must be an array. Indexing
                              starts at 1.
              range(I, J)     returns a list of the Ith to Jth elements
                              (inclusive) of the object, which must be
                              an array. Indexing starts at 1.
              key(K)          returns a list of the value of element
                              "K:<value>" of the object, which must
                              be a tuple of K:V elements. If no such
                              key exists, returns the empty list.
              id              returns a list containing the object.
              (QUERY1, QUERY2) returns the results of both queries,
                               concatenated together.
                               [PCN] {",", QUERY1, QUERY2}
              QUERY1+QUERY2   returns the second query applied to all
                              results of the first query.
                              [PCN] {"+", QUERY1, QUERY2}
              null
              true
              false           return a list holding the object, if
                              it is equal to the given string or
                              returns the empty list.
              <string>        any other string is queried as a list of its characters
              <charlist>      return list containing <charlist> if
                              equal or return the empty list.


## 27. "ucs" module: unicode character classification and conversion

    Provides character classification (uppercase, lowercase, letter, digit,
    whitespace, alphanumeric), case conversion and folding. The operations
    in this module are all UNICODE aware (in the Basic Multlingual Plane).

    ucs:upper(CODE?, FLAG^)
    ucs:lower(CODE?, FLAG^)
    ucs:alpha(CODE?, FLAG^)
    ucs:space(CODE?, FLAG^)
    ucs:digit(CODE?, FLAG^)
      Unify FLAG with the string "true" or "false", depending on whether
      the character code is of the given class.

    ucs:tolower(CODE?, RESULT^)
    ucs:toupper(CODE?, RESULT^)
      Unify RESULT with the lower or uppercase conversion of the character
      code given by CODE.

    ucs:foldcase(CODE?, RESULT^)
    ucs:foldcase(CODE?, RESULT^, TAIL?)
      Unify RESULT with the list of character codes resulting from the
      case-folding of CODE, optionally terminated by TAIL.


## 28. PCN syntax and primitive operations

    PCN-specific operators and primitives. The "pcn" module is not
    explicitly used and serves here only to group PCN-specific syntax.

    //
      [PCN] Single-line comment.

    pcn:main(ARGC?, ARGV?, EXIT_CODE^)
    pcn:main()
      The main entry point. ARGC contains the number of arguments in the
      list ARGV, including the program name, as a list of strings.
      EXIT_CODE should be bound to the exit status of the program. If
      the execution of "main" completes and EXIT_CODE is not bound, the
      program terminates with exit status 0.

      A program may optionally just define a "main" procedure with zero
      arguments, if access to the command-line and exit code is not
      needed.

    X + Y
    X - Y
    X * Y
    X / Y
    X % Y
    X & Y
    X | Y
    X ^ Y
    X >> Y
    X << Y
    ~ X
    - X
      [PCN] (Expression) Arithmetic and binary logic operators in
      expressions, with precedence as follows:

          -  ~                (highest)
          *  /  %
          +  -
          <<  >>
          &  |  ^             (lowest)

      For arithmetic operators, if both arguments of an operation are
      integer, then the result will be an integer as well. Otherwise the
      result will be a floating-point number.

    sin(X)
    cos(X)
    tan(X)
    atan(X)
    sqrt(X)
    log(X)
    exp(X)
      [PCN] (Expression) Trigonometric and transcendental functions.

    truncate(X)
    ceiling(X)
    floor(X)
    round(X)
      [PCN] (Expression) Rounding operations.

    max(X, Y)
    min(X, Y)
      [PCN] (Expression) Return the maximum or minimum of two numbers.

    real(X)
    integer(X)
      [PCN] (Expression) Convert integer to real or vice versa.

    real_fractional_part(X)
    real_integer_part(X)
      [PCN] (Expression) Extract the fractional or integer part of a real
      number.

    rnd()
    rnd(X)
      [PCN] (Expression) Return a uniformly distributed real number between 0
      and 1, or a random integer between 0 and X-1.

    IDENTIFIER over EXPRESSION .. EXPRESSION :: STATEMENT
    IDENTIFIER over TERM :: STATEMENT
      [PCN] (Statement) Executes STATEMENT with IDENTIFIER bound to the values
      in the range EXPRESSION .. EXPRESSION (inclusive) or in the list
      TERM. Depending on the enclosing composition the iteration takes
      place sequentially or in parallel.
      In a sequential composition IDENTIFIER may be a mutable variable.
      If IDENTIFIER is a definitional variable, then it is rebound during the
      execution of STATEMENT, but remains unbound in subsequent statements.

    MODULE:IDENTIFIER(...)
      [PCN] Designates a call of the external procedure IDENTIFIER defined
      in MODULE, the procedure must be exported.

    {; STATEMENT, ...}
    {|| STATEMENT, ...}
    {? CHOICE, ...}
      [PCN] (Statement) Composition blocks. STATEMENTS are executed
      sequentially in a "{; ...}" block, in parallel in a "{|| ...}"
      block. "{? ...}" contains a list of choices and executes the
      body of the first choice of which all guard-expressions succeed.

    GUARD, ... -> STATEMENT
      [PCN] Defines a choice that executes STATEMENT when all guards succeed.

    return(TERM)
      [PCN] (Statement) Sets the result of the function that contains this
      statement. Execution continues normally, this operation does not in
      any way change the flow of control.

    default -> STATEMENT
      [PCN] (Guard) Always succeeds after all other choices failed.
      Should other choices in the same composition suspend, then this
      guard also suspends until all other choices still fail after
      resumption.

    CALL @ TERM
      [PCN] (Statement/Expression) Invokes the procedure or function call
      in the  peer thread defined by TERM. TERM may be one of the strings
      "fwd", "bwd", "north", "east", "south", "west" or an integer designating
      a thread number from 1 to the number of threads.

    IDENTIFIER = TERM
    IDENTIFIER . IDENTIFIER = EXPRESSION
    IDENTIFIER [ EXPRESSION ] = EXPRESSION
      [PCN] (Statement) Binds a definitional variable and resumes any
      code currently suspended and waiting for this variable. If IDENTIFIER
      is already bound and not identical to TERM, then an error is signalled.
      If IDENTIFIER refers to a tuple or a list, then the referenced element
      must contain an unassigned variable.

    IDENTIFIER1.IDENTIFIER2
    IDENTIFIER1(.IDENTIFIER2 = EXPRESSION, ...)
      [PCN] Field-reference of structs (see "struct" declaration for details)
      and functional field-update. The latter returns a new struct that
      is a copy of the struct in IDENTIFIER1 with the given field values
      replaced by the values of the EXPRESSIONs.

    IDENTIFIER := EXPRESSION
    IDENTIFIER [ EXPRESSION ] := EXPRESSION
      [PCN] (Statement) Assigns the value of the right-hand side expression to
      the mutable variable or array element specified on the left-hand side.

    IDENTIFIER ++ TERM ++ ...
      [PCN] (Statement) Assigns a list [X, ...|Y] to the old value of the variable pair
      IDENTIFIER, where X, ... are the values of TERMs and Y is the new value of
      the pair. IDENTIFIER must be a definition variable. So

          build(:s) {          // same as: build(s_1, s_2)
          :
              s ++ 123,        // same as: "s_1 = [123|s_3]"
          :
          // in further operations "s" will refer to s_3
          :
          }   // implicitly unifies s_2 and s_3

    IDENTIFIER1.IDENTIFIER2 <-- TERM
    IDENTIFIER1 [ EXPRESSION ] <-- TERM
      [PCN] [Statement] Functional update of struct-fields (see "struct" declaration)
      and indexed list/tuple-fields. For lists, only part up to the indexed element
      is copied.
      IDENTIFIER1 must refer to an argument pair.

    DESTINATION += EXPRESSION
    DESTINATION -= EXPRESSION
    DESTINATION *= EXPRESSION
    DESTINATION /= EXPRESSION
    DESTINATION %= EXPRESSION
    DESTINATION >>= EXPRESSION
    DESTINATION <<= EXPRESSION
    DESTINATION &= EXPRESSION
    DESTINATION |= EXPRESSION
    DESTINATION ^= EXPRESSION
      [PCN] [Statement] Equivalent to

          DESTINATION = DESTINATION OP EXPRESSION

      where DESTINATION may be a variable designating an argument pair
      or a struct field reference "IDENTIFIER1.IDENTIFIER1") with
      IDENTIFIER1 naming a variable designating an argument pair and
      IDENTIFIER2 names a structure field.

    length(TERM)
      [PCN] (Function) Returns the length of the array, string, list or tuple
      designated by TERM. If TERM is any other type, 1 is returned.

    length(TERM)
      [PCN] (Function) Returns the tail part of a list TERM. If TERM is any
      other type, an error is signalled.

    `IDENTIFIER`
    `IDENTIFIER`(TERM, ...)
    IDENTIFIER:`IDENTIFIER`(TERM, ...)
    `IDENTIFIER`:`IDENTIFIER`(TERM, ...)
    `(IDENTIFIER, ...) -> STATEMENT
      [PCN] (Statement/Expression) Meta calls. in the first form, IDENTIFIER
      should hold a tuple with name and arguments of a call, or a tuple
      of the form

          {":", MODULE, CALL}

      where MODULE is a string naming an existing module and CALL is
      itself a tuple.
      In the second form the identfier should contain a string naming
      the procedure. In the third form, the call is qualified in a
      given or dynamically computed module.

      The final form is a general "lambda" expression representing a
      callable function with a number of arguments and a single statement
      that should be evaluated when the call takes place. This form may be
      a term element. Argument pairs are not supported for lambda parameter
      lists.

    ``IDENTFIER``
    ``IDENTIFIER(TERM, ...)``
   	[PCN] Represents a callable procedure with TERM, ... as implicit
   	arguments, prefixing any arguments additionally passed when the
   	call is performed. These forms may be term elements.

    IDENTIFIER ?= PATTERN
      [PCN] (Guard) Matches a pattern in a choice. Succeeds if IDENTIFIER
      contains a structure that matches PATTERN. If unbound
      definitional variables are embedded in PATTERN, then the match
      will suspend until the variables have been bound.

    TERM == TERM
    TERM != TERM
      [PCN] (Guard) Equality guards. If one of the terms is an expression, the
      comparison is numerical, otherwise the it is a structural comparison.
      Any unbound definitional variables in the terms/expressions will
      suspend execution until bound.

    EXPRESSION > EXPRESSION
    EXPRESSION < EXPRESSION
    EXPRESSION >= EXPRESSION
    EXPRESSION <= EXPRESSION
      [PCN] (Guard) Numerical comparison guards. Unbound definitional variables
      in one of the expressions will suspend execution until bound.

    int(TERM)
    byte(TERM)
    char(TERM)
    double(TERM)
    long(TERM)
    int DECLARATOR, ...;
    long DECLARATOR, ...;
    char DECLARATOR, ...;
    short DECLARATOR, ...;
    double DECLARATOR, ...;
      [PCN] (Guard/Declaration) These are both used as guards, testing the types
      of its arguments and as mutable variable declarations. In guards,
      "int", "short", "long" and "char" all simply test the argument for being
      an integer.

      DECLARATOR may be one of:

          IDENTIFIER                  defines a mutable variable
          IDENTIFIER[INTEGER]         allocates a numeric array
          IDENTIFIER[IDENTIFIER]      allocates a numeric array with dynamic length[*]
          IDENTIFIER[]                declares an argument to be a numeric
                                        array

      DECLARATOR may refer to procedure arguments and marks such arguments
      as being mutable.

      [*] IDENTIFIER must refer to a mutable argument variable

    if(GUARD, ...) STATEMENT
    if(GUARD, ...) STATEMENT else STATEMENT
      [PCN] (Statement) A convenience syntax for

          {? GUARD, ... -> STATEMENT }

      and

          {? GUARD, ... -> STATEMENT, default -> STATEMENT }

    let GUARD, ...
      [PCN] (Statement) A convenience syntax for

          {? GUARD, ... -> STATEMENTS, default -> <fail with error> }

      where STATEMENTS represents all statements following the "let"
      form in the same composition. Note that this form does not introduce
      scope: all variables used inside a procedure are visible throughout
      the full definition. Whether the STATEMENTS are executed in parallel
      or sequential depends on the enclosing composition.

      Previous versions of FLENG supported a "let GUARDS -> STATEMENT"
      form, which is deprecated and support for it will be removed in the
      future.

    with IDENTIFIER = TERM, ... -> STATEMENT
      [PCN] binds the given identifiers to terms in the dynamic environment
      of a task that executes STATEMENT.

    function PROCEDURE_DEFINITION
      [PCN] (Program modifier) Marks the following procedure as being a
      function. The procedure has a hidden definition variable has
      argument and may use the "return" statement to define the result
      value.

    true
    false
      [PCN] Preprocessor macros standing for the strings "true" and "false",
      respectively.

    nodes()
      [PCN] [Expression) Function that returns the number of threads.
      Equivalent to "threads/1".


## 29. Security-relevant stuff

    sec:drop_privileges(USERNAME?)
    sec:drop_privileges(USERNAME?, DONE^)
          Assumes process is root and drops privileges to those of the user given by the
          string, character list or integer USERNAME and unifies DONE with the empty 
          list when the operation is complete. Signals an error when the operation 
          failed for some reason or USERNAME does not identify a known user.

    sec:unveil(PATH?, PERMISSIONS?)
    sec:unveil(PATH?, PERMISSIONS?, DONE^)
          Performs the unveil(2) system call with the strings or character lists
          in PATH and PERMISSIONS as arguments and unifies DONE with the empty list
          when the operation is complete. If the operation fails for some reason,
          DONE will be unified with the tuple "error(ERRNO, STRING)".
          On platforms other than OpenBSD this operation does nothing and binds
          DONE. PATH + PERMISSIONS may be empty lists to disable future calls
          to unveil(2).

    sec:pledge(PROMISES?, XPROMISES?)
    sec:pledge(PROMISES?, XPROMISES?, DONE^)
          Performs the pledge(2) system call with the strings or character lists
          in PROMISES and XPROMISES as arguments and unifies DONE to the 
          empty list when the operation is complete. If the operation fails for 
          some reason, DONE will be unified with the tuple "error(ERRNO, STRING)".
          On platforms other than OpenBSD this operation does nothing and binds
          DONE. (X)PROMISES may be the empty list to indicate keeping the current
          settings.


## 30. "color" module: Access to named colors

    This module provides RGB values for all named X11 colors as normally found
    in "rgb.txt".

    color:get(NAME?, RGB^)
           Unifies RGB with a 3-tuple holding the red/green/blue components
           of the color named NAME. If no color with that name exists, RGB
           will be unified with "false".

    color:get_indexed(INDEX?, NAME^)
           Retrieve color by numeric index from 0-N, or the empty list of
           INDEX is out of range.

    color:all(COLORS^)
           Unifies COLORS with a list of all color known names.


## 31. "sdl" module: basic SDL2 graphics and sound interface

    This module provides a stream-based interface to libSDL2 for displaying
    graphics, render fonts and perform basic audio operations.

    Use "sdl:init/{1,2,3}" to initialize the SDL subsystem and obtain a
    port which accepts messages to show graphics and perform other tasks.
    Messages interpreted in the SDL stream are any of the following:

      listen(EVENT?, PORT^)     (EVENT may also be a list)
      ignore(EVENT?)
      close
      draw_image(X?, Y?, IMAGE?)
      draw_image(X?, Y?, IMAGE?, FLIP?)
      draw_image(X?, Y?, IMAGE?, ANGLE?, CX?, CY?)
      draw_image(X?, Y?, IMAGE?, ANGLE?, CX?, CY?, FLIP?)
      draw_text(X?, Y?, TEXT?)
      draw_text(X?, Y?, TEXT?, FONT?)
      draw_text(X?, Y?, TEXT?, FONT?, WIDTH?)
      redraw
      clear
      clear(R?, G?, B?)
      draw_line(X1?, Y1?, X2?, Y2?)
      draw_polygon(X?, Y?, SIDES?, RADIUS?, ANGLE?)
      draw_box(X?, Y?, X2?, Y2?)
      fill_box(X?, Y?, X2?, Y2?)
      clip(off)
      clip(X1?, Y1?, X2?, Y2?)
      color(R?, G?, B?)
      volume(CHANNEL?, VOL?)  (Channel: 0-7, Volume: 0-128)
      play(CHAN?, SAMPLE?)
      play(CHAN?, SAMPLE?, LOOPS?)
      play(CHAN?, SAMPLE?, LOOPS?, TICKS?)
      fade_in(CHAN?, SAMPLE?, MS?)
      fade_in(CHAN?, SAMPLE?, MS?, TICKS?)
      fade_in(CHAN?, SAMPLE?, LOOPS?, MS?, TICKS?)
      fade_out(CHAN?, MS?)
      pause(CHAN?)
      resume(CHAN?)
      set_mouse(FLAG?)
      mouse_cursor(CURSOR?)

      FONT may be "[]" to specify the builtin 8*16 bitmap font.

    Event types reported by the "listen" message:

      Type:                   Event sent to port:

      mouse                   mouse(X, Y)                 (mouse movement)
      keyup                   keyup(K)
      keydown                 keydown(K)
      buttonup(B)             buttonup(B, X, Y)           (mouse button press/release)
      buttondown(B)           buttondown(B, X, Y)
      joybuttonup             joybuttonup(B, JOYSTICK)    (joystick)
      joybuttondown           joybuttondown(B, JOYSTICK)
      joymotion               joymotion(JOYSTICK, AXIS, VALUE)
      controllerbuttonup      controllerbuttonup(B, JOYSTICK) (game controller)
      controllerbuttondown    controllerbuttondown(B, JOYSTICK)
      controllermotion        controllermotion(JOYSTICK, AXIS, VALUE)
      resize                  resize(W, H)                (window resizing)
      quit                    quit                        (window close)
      expose                  expose                      (window exposed/shown)
      textinput               textinput(CODE)             (textual input from keyboard)

      "K": keycode (ASCII character or control key
      "JOYSTICK": joystick indicator
      "B": button number
      "CODE": UNICODE code point

    With the exception of "sdl:wake_up/1", all predicates in this module _must_
    be called from the main thread.

    sdl:init(STREAM^)
    sdl:init(PARAMS?, STREAM^)
    sdl:init(PARAMS?, STREAM^, DONE^)
          Creates a resizable window of given size and returns a stream
          for communicating with SDL. PARAMS may be a list of the following
          elements:

          size(WIDTH?, HEIGHT?)
          fixed
          fullscreen
          handle(PORT^)       expects events are read via "next_event/1" and
                              sent to PORT

          Unless "handle(PORT)" is passed, an event loop will be started
          and run in the background, processing events as they are delivered
          from input devices. Events are processing once the thread is idle,
          so it is advisable to react to I/O events, signals and timers in a
          different thread to avoid blocking the SDL event loop processing
          user-events.

          DONE is assigned the empty list once initialization is complete.

    sdl:next_event(EVENT^)
          Unify EVENT with the next available SDL event or the empty list if
          no event is pending.

    sdl:image_size(IMAGE?, W^, H^)
          Unify W and H with the width and height of IMAGE.

    sdl:text_size(TEXT?, W^, H^)
    sdl:text_size(TEXT?, FONT?, W^, H^)
          Unify W and H with the width and height of TEXT (which can be a string
          or a character list) rendered using FONT. FONT defaults to the built-in
          bitmap font.

    sdl:load_image(NAME?, IMAGE^)
    sdl:load_sample(NAME?, SAMPLE^)
    sdl:load_font(NAME?, SIZE?, FONT^)
          Load external asset, unifies result with the empty list if loading fails.

    sdl:load_image_from_bundle(ARRAY?,  IMAGE^)
    sdl:load_sample_from_bundle(ARRAY?,  SAMPLE^)
    sdl:load_font_from_bundle(ARRAY?,  SIZE?, FONT^)
          Load external asset from memory, unifies result with the empty list if
          loading fails.

    sdl:release_image(IMAGE?, DONE^)
    sdl:release_sample(SAMPLE?, DONE^)
    sdl:release_font(FONT?, DONE^)
          Release loaded resource and unify DONE with the empty list.

    sdl:window_size(W^, H^)
          Returns the current window size.

    sdl:resize_window(W?, H?, DONE^)
          Resize window to given size.

    sdl:wake_up(DONE^)
          If the SDL event loop is currently blocked by waiting for events, then
          invoking this operation from another thread will trigger re-entry of the
          loop and give other processes in the thread the chance to run.

    sdl:window_title(STRING?, DONE^)
          Set the title of the window to STRING, which should be a string or a
          character list. DONE is unified with the empty list when the operation
          is completed.

    sdl:font_metrics(FONT?, METRICS^)
          Unifies metrics with a tuple of the form {HEIGHT, ASCENT, DESCENT, LINESKIP}
          for the given font.

    sdl:mouse_position(X^, Y^)
          Unifies X and Y with the current mouse position.

    sdl:mouse_buttons(B^)
          Unifies B with a bit-mask where bits #0 to #2 are set when the
          mouse buttons 1 to 3 are pressed.

    sdl:shift_state(STATE^)
    sdl:shift_state(EVENT^, STATE1?, STATE2^)
          The first form initializes a new, unset shift state object. The
          second form updates the current shift state according to the
          passed event object. If the event does not designate a keyboard
          event, the state is unchanged.

    sdl:get_shift_state(SHIFT?, STATE?, FLAG^)
          Unifies FLAG with the string "true" or "false", if the shift
          state STATE represenents the keys given in SHIFT, which may
          be one of the strings "shift", "control" or "alt", or a binary
          operator tuple like "control+shift".

    sdl:message_box(MESSAGE?, ITEMS?, RESPONSE^)
    sdl:message_box(TITLE?, MESSAGE?, ITEMS?, RESPONSE^)
          Shows a message box. Title may begin with the characters "!" or "?"
          to mark the message as a warning or an error. ITEMS should hold a list
          of strings or character lists with button texts. Each item may be
          preceded by the characters "*" or "^" to mark a button that should
          be selected when RETURN or ESCAPE is pressed, respectively.
          After the box is confirmed, RESPONSE will be assigned the index
          of the selected button (starting from 1). During display of the
          message box execution in the current thread is suspended.


## 32. "ezd" module: Structured graphics

    A structured graphics package inspired by the "EZDraw" by Joel Bartlett,
    based on libSDL2. Named graphical objects can be defined, consisting of
    one or more graphical primitives, where further operations allow grouping
    objects in "drawings" (layers). An object can be re-defined at any time
    and redrawing the canvas happens automatically.

    Currently the graphical primitives supported are lines, recangles, filled
    rectangles, polygons and text. Depending on whether a number of extension
    libraries for libSDL2 are available, TrueType font rendering and loading
    of extended image types is provided.

    As in the "sdl" module, all interfacing to the structured graphics system
    is done via a port that receives messages, as obtained by the
    "ezd:init/{1,2,3}" predicate.

    ezd:init(STREAM^)
    ezd:init(SDLINIT?, STREAM^)
    ezd:init(SDLINIT?, STREAM^, DONE^)
          Initialize SDL and EZD and accept commands in STREAM.
          DONE is assigned the empty list once initialization is complete.

          Note that invoking any of the "sdl:..." operations will only
          work once SDL is properly initialized.

         Commands:

         drawing(NAME?)
          Select or create drawing. Initially a default drawing named "ezd"
          is active.

         object(NAME?, PRIMITIVES?)
          Create or recreate object with given name and containing a list of
          graphics primmitives, which may be one or more of the following:

          line(X1, Y1, X2, Y2)
          line(X1, Y1, X2, Y2, COLOR)
          rectangle(X1, Y1, X2, Y2)
          rectangle(X1, Y1, X2, Y2, COLOR)
          polygon(X, Y, SIDES, RADIUS, ANGLE)
          polygon(X, Y, SIDES, RADIUS, ANGLE, COLOR)
          box(X1, Y1, X2, Y2)
          box(X1, Y1, X2, Y2, COLOR)
          text(X, Y, TEXT)
          text(X, Y, TEXT, PROPERTIES)            [font(FONT), color(COLOR),
                                                   anchor(ANCHOR), width(W)]
          image(X, Y, IMAGE)
          image(X, Y, IMAGE, PROPERTIES)          [angle(A), anchor(ANCHOR), flip(FLIP)]

              COLOR is a 3-tuple of 8 bit unsigned integers {R, G, B},
              a string naming a standard X11 color, or the string "clear",
              the default is "black".
              IMAGE and FONT are entities loaded via "sdl:load_image/2" or
              "sdl:load_font/3".
              ANGLE is the rotation in degrees
              FLIP is "none" or a string holding "h" and/or "v".
              ANCHOR specifies point of origin ("center", "n", nw", ...),
              "center" is the default.

          If PRIMITIVES is empty, delete any object with this name. If it is not
          empty, the object retains any attributes and its drawing order. Primitives
          are drawn in the order in which they are given in the PRIMITIVES list.

         raise(NAME?)
          Raise object to top.

         sink(NAME?)
          Sink object to bottom.

         clear
          Clear current drawing, including all event handlers.

         background(COLOR)
          Set background color.

         draw_now
          Redraw everything without waiting for next idle cycle.
          Note that EZD redraws when the thread is idle and any changes
          where made. If "ezd:init" was called with a polling event handler
          and other processes (e.g. timers) are running, then it may be
          necessary to trigger redraw explicitly using this message.

         delete_view(NAME?)
          Delete drawing.

         overlay(NAME?)
          Raise drawing with name to top.

         underlay(NAME?)
          Sink drawing with name to bottom.

         origin(NAME?, X?, Y?)
          Set origin of named drawing to X/Y.

         scale(NAME?, X?, Y?)
          Set scale of named drawing to X/Y.

         clip(NAME?, CLIP?)
          Define clipping region for drawing with given name. CLIP should be
          a tuple of the form {X1, Y1, X2, Y2} in window coordinates or the string
          "off".

         when(NAME?, EVENT?, ACTION?)
          Define event handler for named object in the current drawing. ACTION is
          invoked with "apply/2", with a string or tuple representing the event when
          the event occurs. The first matching handler in all drawings is invoked,
          starting at the topmost drawing, for which the event is defined and which
          is below the mouse cursor in case of mouse and button events.
          Once an object handles the event, the event is not further propagated.

          EVENT may be one of the following:

          buttonup(BUTTON?)               BUTTON: button number
          buttondown(BUTTON?)
          joybuttonup
          joybuttondown
          controllerbuttonup
          controllerbuttondown
          mouse
          joymotion
          controllermotion
          quit
          resize
          keyup
          keydown
          textinput

          Events of type mouse and button trigger an action only if they occur
          with the mouse being inside any of the primitives of the object.
          NAME may be "*" to match any object in the drawing.

          Specifying an event with action "[]" disables the handler.

         get(NAME?, ATTR?, VAL^)
          Retrieve attribute ATTR from object NAME and unify with VAL. If the
          attribute is not defined, unify with the empty list. The object must exist.

         put(NAME?, ATTR?, VAL?)
          Set attribute ATTR of object NAME to VAL, replace any existing atribute.
          The object must exist. Redefining an object will retain any defined
          attributes.

         set_mouse(FLAG?)
          Enable or disable mouse cursor.

         mouse_cursor(NAME?)
          Set mouse cursor to one of a set of predefined system cursors,
          NAME should be one of the following strings:

          default, arrow, ibeam, wait, crosshair, waitarrow, size_nwse,
          size_nesw, size_we, size_ns, size_all, no, hand

         drawings(LIST^)
           Unifies LIST with a list of drawing names, ordered from lowest to
           highest.

         drawing_info(NAME?, INFO^)
           Unifies INFO with a tuple of the form
             {ORIGINX/ORIGINY, SCALEX/SCALEY, CLIP, OBJECTS}
           for the drawing with the given name. If no such drawing exists, INFO
           be unified with the empty list. OBJECTS is a list of object names, CLIP
           a clipping tuple as used by the "clip" command.

         sdl(MESSAGE?)
          Pass MESSAGE on unchanged to the SDL command stream.


## 33. "bb" module: EZD building blocks

    This module provides simple UI components built using EZD objects.
    To use the facilities in this module, your application should adhere
    to a structure demonstrated in this example:

    In FGHC/Strand:

      -initialization(main).                                      [FGHC]

      main :-
          ezd:init(EZD),              % initialize EZD
          open_port(Events, S),       % create event port
          bb:std_events(Events, EZD, EZD2), % prepare some standard event handling
          build(Events, EZD2, EZD3),  % create static objects with EZD (tail is EZD3)
          loop(S, Events, EZD3).

      build(Events)-EZD :-
          % create dynamic objects with EZD pair, pushing objects and
          % event handlers via '<='/2, pass "events" to event-handlers
          % established with "when"which will forward messages to the event
          % stream "s", handled in "loop"
          ...

      loop([buttondown(1, X, Y)|S2], Events, EZD) :- % event loop
          % process button press...
          % invoke "build" to re-create dynamic
          % objects with EZD (tail is EZD2)
          build(Events, EZD, EZD2),
          loop(S2, Events, EZD3).
      loop([...|S2], Events, EZD) :-
          % handle further events
          ...
      loop([_|S2], Events, EZD) :-
          otherwise |
          loop(S2, Events, EZD).  % ignore other events

    In PCN:

      main() {||                                                  [PCN]
          ezd:init(ezd),
          open_port(events, s),
          bb:std_events(events, ezd, ezd2),
          build(events, ezd2, ezd3),
          loop(s, events, ezd3)
      }

      build(events, :ezd) {||
          ...
      }

      loop(s, events, ezd) {?
          s ?= [{"buttondown", 1, x, y}|s2] -> {
              // process button press...
              build(events, ezd, ezd2);
              loop(s2, events, ezd3)
          };
          ...
          default -> {
              let s ?= [_|s2]; loop(s2, events, ezd)
          }
      }

    In the following descriptions POSITION and SIZE refer to two-element tuples
    holding the X and Y position and the width and height of the created object,
    respectively. All object constructors accept an EZD input and output stream
    pair that is used to communicate with the EZD subsystem. If a PORT is specified
    as argument, then it should refer to the event-handling port created above.
    Events triggered by objects created by the operations in this module will
    be forwarded to this port and can be intercepted by the user or passed
    on to component-specific handlers.

    bb:std_events(PORT?, EZD1^, EZD?)
      Handles "quit" event + termination on pressing the ESCAPE key.
      Key events are sent as {"textinput", KEY} tuples.

    bb:label(ID?, POSITION?, TEXT?, EZD1^, EZD?)
    bb:label(ID?, POSITION?, TEXT?, FONT?, EZD1^, EZD?)
      A passive text label with the text anchored at the left center border of
      POSITION.

    bb:entry(ID?, POSITION?, SIZE?, TEXT?, FOCUS?, PORT?, EZD1^, EZD?)
    bb:entry(ID?, POSITION?, SIZE?, TEXT?, FONT?, FOCUS?, PORT?, EZD1^, EZD?)
    bb:entry(ID?, POSITION?, SIZE?, TEXT?, FONT?, STATUS?, FOCUS?, PORT?, EZD1^, EZD?)
      An active entry field containing TEXT. FOCUS determines whether field is ready
      for input: if equal to ID then this object is marked as receiving input.
      Pressing button 1 sends the tuple {"focus", id} as a message to PORT.
      STATUS may be one of the strings "disabled", "normal" or "invalid".

    bb:entry_update(OLDTEXT?, CHARCODE?, NEWTEXT^)
    bb:entry_update(OLDTEXT?, CHARCODE?, VALIDATOR?, NEWTEXT^)
      Update entry field text with the key represented by CHARCODE, handling BACKSPACE.
      If VALIDATOR is given, it should be an object suitable for "apply/2" and is
      called as "apply(VALIDATOR, [UPDATED?, OLDTEXT?, NEWTEXT^])". The validator should
      assign the new value to NEWTEXT, if UPDATED is valid, or OLDTEXT otherwise.
      CHARCODE may also be a "keydown" or "textinput" event tuple.

    bb:button(ID?, POSITION?, SIZE?, TEXT?, CLICK?, EZD1^, EZD?)
    bb:button(ID?, POSITION?, SIZE?, TEXT?, FONT?, CLICK?, EZD1^, EZD?)
    bb:button(ID?, POSITION?, SIZE?, TEXT?, FONT?, STATUS?, CLICK?, EZD1^, EZD?)
      A push button. The callable object CLICK is invoked using "apply/2" as
      "apply(CLICK)" when B1 is pressed over the button.
      STATUS may be one of the strings "disabled" or "normal".

    bb:menu(ID?, POSITION?, SIZE?, LIST?, SEL?, PORT?, EZD1^, EZD?)
    bb:menu(ID?, POSITION?, SIZE?, LIST?, FONT?, SEL?, PORT?, EZD1^, EZD?)
      Creates a menu of items given by LIST, where each element should be a string
      or character list. SEL holds the index of the currently selected item
      (starting from 1). When a menu item is clicked, a tuple of the form
      {"menu_select", ID, INFO} is sent to PORT.

    bb:menu_select(INFO?, STREAM^, PORT?, EZD^, K)
      Take over event-handling for managing a menu selection. INFO should be the
      value received via the "menu_select" message. STREAM is the event stream
      for PORT that usually is processed by application logic ("loop" in the
      example in the instroduction). The normal event handling should be suspended
      until K is invoked via "apply/2" as "apply(K, [SEL?, STREAM^, EZD^])",
      K can then continue processing events from STREAM and communicate with ezd
      using EZD. SEL will hold the index of the selected item.

    bb:gauge(ID?, POSITION?, SIZE?, VALUE?, EZD1^, EZD?)
    bb:gauge(ID?, POSITION?, SIZE?, VALUE?, COLOR?, EZD1^, EZD?)
      Draws a progress bar. VALUE is a floating-point value from 0 to 1 indicating
      the "fullness" of the bar.

    bb:slider(ID?, POSITION?, SIZE?, VALUE?, PORT?, EZD1^, EZD?)
      A slider object that can be adjusted via mouse buttons. When the value changes
      a tuple of the form {"adjust", ID, VALUE} is sent as a message to PORT, where
      VALUE indicates the new value.

    bb:delete_slider(ID?, EZD1^, EZD?)
      Delete a slider object and associated helper objects.

    bb:listbox(ID?, POSITION?, SIZE?, LIST?, SEL?, PORT?, COUNT^, EZD1^, EZD?)
    bb:listbox(ID?, POSITION?, SIZE?, LIST?, FONT?, SEL?, PORT?, COUNT^, EZD1^, EZD?)
      A "listbox" showing a list of text elements given by LIST. SEL specifies the
      index of the currently selected entry, starting from 1. COUNT will hold the
      number of items shown. When an item is clicked, the tuple
      {"list_select", INDEX, ITEM} is sent as a message to PORT, where INDEX is the
      index and ITEM the text of the selected item.

    bb:delete_listbox(ID?, COUNT?, EZD1^, EZD?)
      Delete a listbox and associated objects.

    bb:scrollbar(ID?, POSITION?, SIZE?, ORIENTATION?, RANGE?, PORT?, EZD1^, EZD?)
    bb:scrollbar(ID?, POSITION?, SIZE?, ORIENTATION?, RANGE?, FG?, BG?, PORT?, EZD1^, EZD?)
      A horizontal or vertical scroll bar. ORIENTATION should be one of the strings
      "h" or "v". RANGE is a a 2-element tuple holding the start and end value of the
      "thumb" as floating-point values of 0 to 1. When clicked, a tuple of the form
      {"scroll", ID, INFO} is sent to PORT as a message, which should be passed
      on to "bb:scrollbar_move/6".

    bb:scrollbar_move(ID?, INFO?, RNG^, EZD1^, EZD?)
      Adjusts the scroll bar range from INFO, as received previously via the "scroll"
      message. RNG will be assigned a new tuple holding the adjusted range.

    bb:delete_scrollbar(ID?, EZD1^, EZD?)
      Deletes a scrollbar and the associated objects.

    bb:dialog(ID?, POSITION?, SIZE?, EZD1^, EZD?)
      Creates a "dialog" box at the given position, containing a white background.
      A drawing of the same name as ID is created with its origin moved and a clipping
      rectangle set up to constrain any drawing to the dimensions of the dialog.
      The drawing will be active after this procedure is invoked, so any subsequent
      objects created will be inside the dialog. Make sure to always have the correct
      drawing active ("ezd" being the default drawing) when using dialogs.


## 34. "eval" module - a simple FGHC evaluator

    An evaluator for a restricted subset of FGHC, usable for testing compiled
    code and interactive experiments.

    Parsing and evaluation errors (if detected) are reported to stderr. Run-time
    errors drop the current process and schedule the next available one.
    This means that processes currently suspended and waiting for the
    process that triggered the error will never be resumed, resulting in memory
    leaks. Also note that when processes are waiting for suspended variables
    the interactive input-loop may not always be able to continue - in this
    case it will be necessary to terminate the session with Control-C and
    to restart.

    This is not a full fledged FGHC interpreter, it just evaluates basic terms.
    Definition of processes is not supported (":-"), neither are declarations
    or argument pair notation.

    The supported language includes calls to all documented primitives,
    and library goals and the core forms "(,)/2", "(&)/2", "true/0", "when/2",
    "(=)/2", "is/2", "(->)/2", "(;)/2" and "(@)/2".

    For convenience, some helper terms are provided:

   	p(X?)		prints X, showing unbound variables
   	q(X?)		prints X, which must be fully bound
   	t(G?)		prints "OK" or "FAILED" depending on whether the
   				guard G succeeds or fails
   	t(MSG?, G?)	as "t/1" but prefixes the result with the string MSG
   	q			terminates the process
    repl
   	Reads lines from stdin and evaluates terms contained in the code line
   	until the end of line is reached. Separate terms with full stop ("."), the
   	final full stop is optional. Terminates once stdin is at EOF.

    load(FNAME?)
    load(FNAME?, DONE^)
   	Loads terms from the file named FNAME and evaluates them. Unifies
   	DONE with the empty list when all terms have been evaluated or with
       the string "error" in case errors occurred during evaluation.
       If any "t/{2,3}" form failed, exits with a non-zero status.
       If FNAME is the string "-", terms are read from standard input.

    goal(GOAL?, RESULT^)
   	Evaluates GOAL and assigns "true" or "false" to RESULT, depending
       on whether errors where detected. In the latter case, they are reported
   	to stderr.

    expr(EXPR?, RESULT^)
   	Evaluates the expression EXPR and assigns the result to RESULT,
   	or, in the case of an error, with a tuple "error(INFORMATION)".

    guard(GUARD?, RESULT^)
   	Evaluates GUARD and assigns "true" or "false" to RESULT, depending
   	on whether the guard succeeded or not. In case an error is detected,
   	RESULT is assigned a tuple of the form "error(INFORMATION)".


## 35. Formal definition of PCN syntax


    * Block comments are of the form "/* ... */" any may not be nested.

    * Line comments are of the form "// ..."

    * The following keywords are reserved and may not be used as variables
      or procedure names:

        char, int, double, default, over, return, _asm,
        foreign_call, short, long, idle, if, else, function, let, with

    * Syntax in BNF:

    <program> = <toplevel> ...

    <toplevel> = <procedure>
               | <declaration>

    <declaration> = "-" <identifier> "(" <element> "," ... ")"

    <procedure> = [<modifiers>] <identifier> "(" <parameter> "," ... ")"
                  [<mutable-declaration> ...] <body>

    <parameter> = [":"] <identifier>

    <mutable-declaration> = <type> <identifier> ["[" <size> "]"] "," ... ";"

    <type> = "int" | "char" | "long" | "short" | "double"

    <size> = <integer> | <identifier>

    <modifiers> = <modifier> "," ...

    <modifier> = "function"

    <body> = <composition>
           | <choice>
           | "let" <guard> "," ... "->" <statement>

    <composition> = "{" [";"] <statement> <delimiter> ... "}"
                  | "{" "||" <statement> <delimiter> ... "}"
                  | "{" "?" <choice> <delimiter> ... "}"

    <delimiter> = ";" | ","

    <statement> = <destination> "=" <term>
                | <identifier> ["[" <expression> "]"] ":=" <expression>
                | <identifier> "=" <expression>
                | <identifier> "++" <term> {"++" <term>}
                | <fdestination> "+=" <expression>
                | <fdestination> "-=" <expression>
                | <fdestination> "*=" <expression>
                | <fdestination> "/=" <expression>
                | <fdestination> "%=" <expression>
                | <fdestination> "<<=" <expression>
                | <fdestination> ">>=" <expression>
                | <fdestination> "&=" <expression>
                | <fdestination> "|=" <expression>
                | <fdestination> "^=" <expression>
                | <fdestination> "<--" <term>
                | <composition>
                | "if" "(" <guard> "," ... ")" <statement> ["else" <statement>]
                | "let" <guard> "," ... "->" <statement>
                | "with" <identifier> "=" <term> "," ... "->" <statement>
                | "foreign_call" "(" <element> ")"
                | "return" "(" <term> ")"
                | <call> ["(" <argument> "," ... ")"]
                | <callprefix> ":" <call> "(" <argument> "," ... ")"
                | <quantification>

    <quantification> = <identifier> "over" <expression> ".." <expression> "::"
                       <statement>
                     | <identifier> "over" <term> "::" <statement>

    <call> = <identifier>
           | "`" <identifier> "`"

    <callprefix> = <string>
    			 | <call>

    <argument> = ":" <identifier>
               | "<term>

    <term> = "[" <element> "," ... ["|" <element>] "]"
           | "{" <element> "," ... "}"
           | <identifier>
           | <number>
           | <string>
           | <expression>

    <element> = "[" <element> "," ... ["|" <element>] "]"
              | "{" <element> "," ... "}"
              | <template>
              | <identifier> ["(" <element> "," ... ")"]
              | <number>
              | <charlist>
              | <string>

    <string> = "\"" <character> ... "\""

    <charlist> = "L\"" <character> ... "\""

    <number> = "'" <character "'"
             | <integer>
             | <float>

    <expression> = <expr2> "&" <expression>
                 | <expr2> "|" <expression>
                 | <expr2> "^" <expression>
                 | <expr2>

    <expr2> = <expr3> ">>" <expr3>
            | <expr3> "<<" <expr3>
            | <expr3>

    <expr3> = <expr4> "+" <expr3>
            | <expr4> "-" <expr3>
            | <expr4>

    <expr4> = <expr5> "*" <expr4>
            | <expr5> "/" <expr4>
            | <expr5> "%" <expr4>
            | <expr5>

    <expr5> = "-" <expr5>
            | "~" <expr5>
            | <destination>
            | <number>
            | <call> "(" <term> "," ... ")"
            | <callprefix> ":" <call> "(" <term> "," ... ")"
            | <template>
            | "`" "(" <identifier> "," ... ")" "->" <statement>*

    <template> = "``" <identifier> [":" <identifier>] ["(" <term>, ... ")"] "``"*

    <destination> = <identifier> {"." <identifier> | "[" <expression> "]"}

    <fdestination> = <identifier> ["." <identifier>]

    <choice> = <guard> "," ... "->" <statement>

    <guard> = <identifier> "?=" <element>
            | <test> "(" <term> ")"
            | "!" <term>
            | <term>* ["==" <term>*]
            | <term>* "!=" <term>*
            | <expression>* ">" <expression>*
            | <expression>* "<" <expression>*
            | <expression>* ">=" <expression>*
            | <expression>* "<=" <expression>*
            | "default"

      *: expression may use arithmetic functions but no user function calls