FLENG LIBRARY REFERENCE ======================= ### Table of contents: 1. Syntactic Forms 2. Toplevel declarations 3. Guard expressions 4. Builtin primitives 5. "lib" module: FGHC standard library 6. "fmt" module: Formatted output 7. "sort" module: Sorting 8. "set" module: Lists as sets 9. "map" module: Key-value maps 10. "lex" module: FGHC/FLENG lexical analyzer 11. "parse" module: FGHC/FLENG parser 12. "sys" module: Event-loop for thread-communication 13. "proc" module: Subprocess invocation 14. "array" module: Mutable numeric arrays 15. "app" module: Higher-order operations on lists 16. "list" module: List operations 17. "io" module: Extended I/O stream operations 18. "scan" module: Simple parsers for various character sequences 19. "match" module: Pattern matching 20. "path" module: Pathname destructuring 21. "find" module: Find files and directories 22. "ucs" module: unicode character classification and conversion 23. Security-relevant stuff 24. "color" module: Access to named colors 25. "binfmt" module: binary string formatting/scanning 26. "9p" module - a client library for the 9P protocol 27. JSON parsing 28. "base64" module: Base64 encoding/decoding 29. PCN syntax and primitive operations 30. "kl1" module: KL1 syntax and primitive operations 31. "eval" module - a simple FGHC evaluator 32. "crc" module: CRC calculation 33. "vector" module: sparse functional arrays 34. "atom_table" module: operations on KL1 atoms 35. "generic" module: generic interface to KL1 objects 36. "timer" module: time-calculation and timers for KL1 37. "unix" module: stream-based UNIX interface 38. module "config": platform and configuration information 39. "sdl" module: basic SDL2 graphics and sound interface 40. "ezd" module: Structured graphics 41. "$rt" module: low-level primitives 42. "bb" module: EZD building blocks 43. 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. random a random thread, including the current one. unloaded the thread with the least amount of active goals. 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 _(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 ".c", where "" 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 "/" 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 "(, ...)", where "" 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. [KL1] For compatibility with KLIC, the name "main" is accepted as a substitute for the default ("") module. Also for compatibility reasons, the parentheses around NAME may be omitted in this declaration. -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 | ... [KL1] In KL1 this guard is called "=". X =\= Y [FGHC] Succeeds if X does not match Y. [KL1] In KL1 this guard is called "\=". 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. [KL1] In KL1 this guard is called "=\=" and expects integer expressions. X $=:= Y [KL1] Succeeds if X is numerically the same as Y, X and Y may be numerical expressions as in ":=/2" and must contain floating point numbers. X $=\= Y [KL1] Succeeds if X is numerically different to Y. X and Y may be numerical expressions and must contain floating point numbers. 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. [KL1] In KL1 these guards are only applicable to integer arguments. For floating-point numbers, use the "$..." variants. X $> Y X $< Y X $>= Y X $=< Y [KL1] Succeeds if X is numerically greater or less than Y. X and Y may be numerical expressions and must be floating point numbers. 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. GUARD1; GUARD2 [KL1] Guard disjunction, succeeds if either of the guards succeed. alternatively [KL1] A directive similar to "otherwise" and placed between a set of clauses. "Alternatively" directs the compiler to consider any preceding clauses before clauses that follow this directive when selecting a matching clause. Note that this implementation of KL1 does not support task priorities. arg(POSITION?, X, ARG^ [KL1] Unifies ARG with the argument at POSITION from the term X, where arguments are counted starting from 1. If the unification fails or if X is not a functor term or if POSITION exceeds the length of the term, the guard fails. array(X) Succeeds if X is an array. atom(X) [KL1] Succeeds if X is an atom. atomic(X) [FGHC] Succeeds if X is a number or a string. [KL1] In KL1 floating-point numbers are not considered atomic. compare(X, Y, ORDERING^) [KL1] Unify ORDERING with an integer less than, greater than or equal to 0, depending on whether X is ordered before Y, after Y or is equal to Y. data(X) [FGHC] Suspends if X is an unbound variable. This is identical to qualifying a head variable with "!". [KL1] In KL1 this guard is called "wait". functor(X, FUNCTOR^, ARITY^) [KL1] Unifies FUNCTOR and ARITY with the principal functor and arity of X. If X is an atomic value, FUNCTOR will be the same as X and ARITY will be 0. If any of the unifications fail, then the guard itself fails. Note that lists are considered functor terms of the form '.'(HEAD, TAIL). hash(X, HASH^) [KL1] Unifies HASH with a hash value for X, which can be of any value other than a variable. 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. [KL1] In KL1, this guard is a directive, inserted between two clauses: singleton([_], X) :- X = true. otherwise. singleton(_, X) :- X = false. 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) string(X, LEN^, SIZE^) [FGHC/PCN] Succeeds if X is a string. Note that this includes the empty list ("[]"). [KL1] in KL1 strings are of a different type than FGHC/PCN strings. KL1 strings are internally represented as arrays of type "char" holding UTF-8 encoded text. The "string" guard in KL1 takes two additional arguments, the length of the string and the size of each character in bytes. LEN will be unified with the number of codepoints and SIZE with the constant value 8 (eight). The latter is just for compatibility with KLIC and has no further meaning. If the unification of LEN and SIZE fails, the guard fails. string_element(X, INDEX^, ELEMENT^) [KL1] Succeeds if X is a string and INDEX and ELEMENT can be unified with the INDEXth code-point of the string. 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. vector(X) Succeeds if X is a vector. vector_element(X, INDEX^, ELEMENT^) [KL1] Succeeds if X is a vector and INDEX and ELEMENT can be unified with the INDEXth element of the vector. wait(X) [KL1] Suspends if X is an unbound variable. ## 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_pipe(IN^, OUT^) Assigns the file-descriptors of the read and write ends of a pipe to IN and OUT, using the pipe(2) system call. 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. thread_loads(LIST^) Unifies LIST with the number of active goals for each thread. [PCN] This operation may also be used as a 0-argument function in expressions 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. "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 "{, , ...}", "{':', , }" or "{':', , {, , ...}}". 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 or with a tuple of the form "error(ERRNO, STRING)" in case the operation failed. 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, vector, 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 "( ...)". 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. ## 6. "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. ## 7. "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. ## 8. "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 SET1 and SET2. The order of objects in SET2 will be preserved. set:union(SET1?, SET2?, RESULT^) Computes the union of the two lists SET1 and SET2. The order of objects in SET2 will be preserved (but not of SET1). 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. ## 9. "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 "@, }" or "{, }". 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 "{'-', , }". 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. ## 10. "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). ## 11. "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. ## 12. "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. ## 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. "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)". ## 15. "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 {"", , ...} Calls to specific modules should be encoded as tuples like this: {":", "", ""} {":", "", {"", , ...}} 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:times(GOAL?, END?, DONE^) app:times(GOAL?, START?, END?, DONE^) Invokes GOAL with integers from START (or 1 if not given) to END (inclusive) and assigns the empty list to DONE when finished. 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. ## 16. "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:butlast(LIST?, RESULT?) Unifies RESULT with the elements of LIST, except the last item. If LIST is the empty list, then so is RESULT. 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. ## 17. "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:write_buffered_bytes(FILE?, BLOCKSIZE?, STREAM?, DONE^) Write bytes in STREAM block-wise in chunks of BLOCKSIZE to FILE. If the stream ends DONE is assigned the empty list, if an error occurs during writing of a block, DONE is assigned the error result from the underlying "write_file/4" operation. io:write_buffered_chars(FILE?, BLOCKSIZE?, STREAM?, DONE^) Write characters in STREAM block-wise in chunks of BLOCKSIZE to FILE. If the stream ends DONE is assigned the empty list, if an error occurs during writing of a block, DONE is assigned the error result from the underlying "write_file/4" operation. 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)". ## 18. "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 "\" 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 "~" or "~*", 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. ## 19. "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 , 0'-, [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. ## 20. "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. ## 21. "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. ## 22. "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. ## 23. 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. ## 24. "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. ## 25. "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 "~" 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 "~" or "~*", 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". ## 26. "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". ## 27. 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 -> '{}'([:, ...]) [PCN] {"{}", [{":", , }, ...]} 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:" 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. any other string is queried as a list of its characters return list containing if equal or return the empty list. ## 28. "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. ## 29. PCN syntax and primitive operations PCN-specific operators and primitives. The "pcn" module is not explicitly used but provides additional functionality for compiled PCN modules. // [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, ...} {~ 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. "{~ ...}" represents a "fair" choice composition, where any successful guard has the same chance of executing. Fair compositions require multiple passes over the clause guards and thus have a certain performance overhead. Note that the separator between statement or choices may be either a comma (",") or a semicolon (";"). 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", "random", "unloaded", "all" 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. If IDENTIFIER refers to an argument pair then the left hand side of the definition refers to the new value. 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 -> } 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". ## 30. "kl1" module: KL1 syntax and primitive operations KL1-specific builtin operators and primitives. The "kl1" module is not explicitly used but provides additional functionality for compiled KL1 modules. FUNCTOR^ =.. LIST? Converts LIST to a functor term and unifies it with FUNCTOR. This operator can not be used to decompose a functor term into a list. arg(POSITION?, TERM?, ARG^) Unifies ARG with the argument at POSITION (counting from 1) of the functor term TERM. TERM must not be atomic. Lists are equivalent to the functor term '.'(HEAD, TAIL). main The main entry point, invoked for the main module on program startup. Access to the command-line arguments and providing an exit code on termination can be obtained by separate library functionality from the "unix" module. This predicate takes no arguments. current_node(ID^, NUM^) Unifies ID with the thread number of the thread that is executing the current clause, starting from 0. NUM is unified with the total number of available threads, as determined by the "+THREADS" runtime option. functor(TERM?, FUNCTOR^, ARITY^) Unifies FUNCTOR and ARITY with the principal functor of TERM. If TERM is an atomic, FUNCTOR is equal to TERM and ARITY is 0. Note that lists are considered functor terms of the form '.'(HEAD, TAIL). new_functor(FUNCTOR^, NAME?, ARITY?) Unifies FUNCTOR with a new functor term with the given NAME and ARITY arguments initialized to 0 (zero). If ARITY is zero, FUNCTOR is unified with NAME. new_string(STRING^, INIT?, SIZE?) Unifies STRING with a newly created string. INIT should be an integer giving the size of the allocated string (it will be filled with '\0' characters) or be a list of integer character codes. CALL@node(N?) Peer specification for remote calls. N should be an integer and designate a thread number, starting from 0. search_character(STRING?, INDEX1?, INDEX2?, CHAR?, WHERE^) Searches for the UNICODE character CHAR in STRING, starting at character position INDEX1 up to (but not inclusive INDEX2). Indexes start at 0. WHERE will be unified with the character index where CHAR was first found or -1 if not found. setarg(POSITION?, FUNCTOR?, VALUE?, NEWFUNCTOR^) setarg(POSITION?, FUNCTOR?, OLD^, VALUE?, NEWFUNCTOR^) Unifies NEWFUNCTOR with a copy of the functor term FUNCTOR but with the element at POSITION (counting from 1) replaced by VALUE. If OLD is given, it is unified with the previous element. string_element(STRING?, INDEX?, ELEMENT^) Unifies ELEMENT with the code of the INDEXth character in STRING. Indexes start at 0. Signals an error if the index is out of range. set_string_element(STRING?, INDEX?, ELEMENT?, NEWSTRING^) Unifies NEWSTRING with a copy of STRING where the INDEXth character is replaced by ELEMENT which should be an integer character code. The full UNICODE range is supported. Indexes start at 0. Signals an error if INDEX is out of range. ## 31. "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 (blocking) 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. Entering a variable on its own will print the current value of the variable if it has one (the operation will not block). 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)". ## 32. "crc" module: CRC calculation Computes 32-bit Cyclic Redundancy Codes. crc:input(DATA?, RESULT^) crc:input(DATA?, STATE?, RESULT^) Takes an array, a list of characters or a string and computes the 32-bit CRC, assigning it to RESULT. IF STATE is given and not the empty list, then it is taken as the current CRC from a previous invocation of "crc:input". On 32-bit platforms (currently only armv7) RESULT may be a floating-point value, if the value can not be expressed in 31 bits, which is the available range for integer values. ## 33. "vector" module: sparse functional arrays Vectors are sparse immutable arrays holding arbitrary values. Modification is non-destructive and relatively efficient and returns a new vector that shares as much information with the old one as possible. Vector indices begin at 0. Internally, vectors are implemented using a balanced tree (see also the "map" library module). vector:make(LENGTH?, INIT?, VECTOR^) Creates a new vector of LENGTH elements intitialized to INIT and unifies VECTOR with the newly created vector. Note that all elements share the same initialization value. vector:element(VECTOR?, INDEX?, VALUE^) Unifies VALUE with the element of VECTOR at the given INDEX. If INDEX is not an integer or exceeds the bounds of the vector, an error is signalled. vector:elements(VECTOR?, LIST^) vector:elements(VECTOR?, LIST^, TAIL?) Unifies LIST with the elements of VECTOR, optionally terminated by TAIL. vector:set_element(VECTOR?, INDEX?, VALUE?, NEWVECTOR^) vector:set_element(VECTOR?, INDEX?, OLD^, VALUE?, NEWVECTOR^) Unifies NEWVECTOR with a new vector holding the elements of VECTOR with VALUE replacing the element at INDEX. If INDEX is not an integer or exceeds the bounds of the vector, an error is signalled. If OLD is given, it is replaced with the original value. vector:new(VECTOR^, INIT?) Unifies VECTOR with a a new vector. If INIT is an integer, it specifies the size of the vector, with each element initialized to zero. If INIT is a list, the new vector holds the elements of the list in their natural order. vector:split(VECTOR?, AT?, LOW^, HIGH^) Splits VECTOR at index AT, unifying LOW and HIGH with new vectors containing the elements below AT and above or equal AT. vector:join(LOW?, HIGH?, VECTOR^) Unifies VECTOR with the a new vector created by concatenating the vectors LOW and HIGH. ## 34. "atom_table" module: operations on KL1 atoms This module contains various operations on "atoms" (called "strings" in Strand and FGHC) for use in KL1 code. Since KL1 strings have no easy to use equivalent FGHC or Strand, this module is only useful for KL1 programs. atom_table:make_atom(STRING?, ATOM^) When given a STRING, returns ATOM with that name. If such an atom does not exist, a new atom is registered. atom_table:atom_number(ATOM?, NUMBER^) Internal serial number for ATOM is returned to NUMBER as an integer value. atom_table:get_atom_string(ATOM?, STRING^) The name string of ATOM is returned to STRING. atom_table:intern(STRING?, RESULT^) The same as atom_table:make_atom, except that the returned value is a functor structure of the form ‘normal(ATOM)’. atom_table:get_atom_name(ATOM?, RESULT^) The same as atom_table:get_atom_string, except that the returned value is a functor structure of the form ‘normal(STRING)’. ## 35. "generic" module: generic interface to KL1 objects This module provides the "generic" interface provided by the KLIC KL1 system. Only the required classes are supported, specifically: float, merge, vector, string, module, predicate This is mostly a compatibility hack, for FGHC, Strand and PCN the use of this module may not make much sense. generic:new(float, FLOAT^, INTEGER?) generic:new(merge, IN^, OUT^) generic:new(vector, VECTOR^, INIT?) generic:new(string, STRING^, INIT?, INTEGER?) generic:new(module, MODULE^, MODULENAME?) generic:new(predicate, PREDICATE^, MODULE?, NAME?, ARITY?) Generic object creation methods. generic:generic(OBJECT?, FUNCTOR?) Invokes a predicate from the "generic" module as designated by FUNCTOR (an atom or a tuple of the form "NAME(ARGUMENT, ...)"). generic:add(X?, Y?, RESULT^) generic:subtract(X?, Y?, RESULT^) generic:multiply(X?, Y?, RESULT^) generic:divide(X?, Y?, RESULT^) generic:sin(X?, RESULT^) generic:cos(X?, RESULT^) generic:tan(X?, RESULT^) generic:asin(X?, RESULT^) generic:acos(X?, RESULT^) generic:atan(X?, RESULT^) generic:log(X?, RESULT^) generic:exp(X?, RESULT^) generic:sqrt(X?, RESULT^) generic:ceil(X?, RESULT^) generic:floor(X?, RESULT^) Generic methods on "float" objects (floating point numbers). generic:size(VECTOR?, LENGTH^) generic:size(STRING?, LENGTH^) Unifies LENGTH with the size of the vector or string, respectively. generic:element(VECTOR?, INDEX?, ELEMENT^) generic:element(STRING?, INDEX?, ELEMENT^) Unifies ELEMENT with the element in VECTOR or STRING and the gfiven INDEX and signals an error if the index is out of range. generic:element_size(STRING?, SIZE^) Unifies SIZE with 8. generic:set_element(VECTOR?, INDEX?, ELEMENT?, NEWVECTOR^) generic:set_element(VECTOR?, INDEX?, OLD^, ELEMENT?, NEWVECTOR^) generic:set_element(STRING?, INDEX?, ELEMENT?, NEWSTRING^) Returns a new vector or string with the contents of the given VECTOR or STRING but with the element at position INDEX replaced by ELEMENT. For vectors, OLDELEMENT can be given to hold the previous element that was replaced. generic:split(VECTOR?, AT?, LOWER^, UPPER^) generic:split(STRING?, AT?, LOWER^, UPPER^) Unifies LOWER and UPPER with new vectors or strings that hold the elements of VECTOR/STRING before index AT and including and after AT. generic:join(LOWER?, UPPER?, VECTOR^) generic:join(LOWER?, UPPER?, STRING^) Unifies VECTOR or STRING with the concatenated vectors or strings LOWER and UPPER, which must be of the same type. generic:search_character(STRING?, START?, END?, CHAR?, WHERE^) Searches for CHAR in STRING, starting at START and ending at the index before END. Unifies WHERE with the position (starting from 0) of the found character or -1 if the character could not be found. generic:name(MODULE?, NAME^) generic:name(PREDICATE?, NAME^) Unifies NAME with the name of the given predicate or module. generic:arity(PREDICATE?, ARITY^) Unifies ARITY with the arity of PREDICATE. generic:apply(PREDICATE?, ARGUMENTS?) Invokes PREDICATE with the given list of arguments. generic:call(PREDICATE?, ARGUMENT?, ...) Invokes PREDICATE with the given ARGUMENTS. At most 5 arguments are allowed. Use "generic:apply/2" if you want to pass more than 5. generic:module(PREDICATE?, MODULE^) Unifies MODULE with the module for which PREDICATE was created. ## 36. "timer" module: time-calculation and timers for KL1 This is a variant of the the "timer" module provided in the KLIC KL1 system. The module exists mainly for compatibility reasons, but may be useful for FGHC, Strand or PCN code. timer:get_time_of_day(TIME^) Unifies TIME with a functor of the form "time(DAYS, SECONDS, MICROSECONDS)", designating the current time as the difference to Jan 1., 1970. timer:add(TIME1?, TIME2?, RESULT^) Adds the time values and unifies RESULT with the sum. timer:sub(TIME1?, TIME2?, RESULT^) Subtracts the time value TIME2 from TIME1 and unifies RESULT with the difference. timer:compare(TIME1?, TIME2?, RESULT^) Compares TIME1 with TIME2 and unifies RESULT with the atom '<', '>' or '=', depending on whether TIME1 is later, before or equal to TIME2. timer:instantiate_at(TIME?, VAR^) Unifies VAR with the empty list when the current time has exceeded the point of time given in TIME. timer:instantiate_after(TIME?, VAR^) Unifies VAR with the empty list when the current time as exceeded the time interval given in TIME. timer:instantiate_every(TIME?, STOP?, VAR^) Instantiates the stream VAR with instances of the empty list ("[]") after the interval given in TIME has passed, repeatedly. Unify STOP with some arbitrary value to cancel the timer. ## 37. "unix" module: stream-based UNIX interface This module provides a stream-based interface to various system calls and library functions available on UNIX-like systems. The module is mainly provided for KLIC compatibility but may also be useful for FGHC, Strand or PCN code. The basic operation for using the provided functionality is the "unix" predicate. It takes a stream of commands that open files, standard input streams and some miscellaneous commands. Operations that accept argument strings, accept also FHGC strings ("atoms" in KL1 parlance) and character lists. Operations that return strings do so as KL1 strings. For use in other languages supported by the FLENG system alternatives are provided that return byte lists. Note that all I/O via this operations is byte-stream oriented. Use "utf_encode"/utf_decode" to perform any translation to Unicode manually. unix:unix(STREAM?) Accepts commands in STREAM until the stream is closed. Available commands are any of the following: stdin(R^) stdout(R^) stderr(R^) Unify R with the tuple "normal(S?)" holding a stream that receives I/O commands for one of the standard input-, output- and error- streams. read_open(FILENAME?, R^) write_open(FILENAME?, R^) append_open(FILENAME?, R^) update_open(FILENAME?, R^) Opens a file with the given name for reading, writing, appending or both reading and writing and unifies R with "normal(S?)" or the atom "abnormal", in case the opening failed. S holds an I/O stream. connect(SPEC?, R^) Opens a client socket specified by SPEC and unifies R with "normal(S?)" (where S is a bidirectional I/O stream) or "abnormal", depending on whether the opertion succeeded or failed. SPEC should be a tuple of one of the following shapes: unix(FILENAME?) Specifies a unix domain socket. inet(ADDR?, PORT?) Specifies an IP4 TCP socket with given address and port. ADDR may be the atom "*" (INADDR_ANY), a tuple of four IP address bytes or a host name as a string. bind(SPEC?, R^) Opens a server socket specified by SPEC and unifies R with "normal(SS?)" or "abnormal". SS is a stream that accepts only accept commands which are tuples of the form "accept(A?)", where A is "normal(S?)" with an I/O stream for communicating with the client and accepts both input and output commands. cd(FILENAME?, R^) Changes the current working directory to FILENAME and unifies R with zero or -1, in case the operation failed. unlink(FILENAME?, R^) Delete file and return status in R. mktemp(TEMPLATE?, FILENAME^) Unify FILENAME with a string holding the name of a temporary file based on TEMPLATE. Note that this operation has an unavoidable race condition as the name may be chosen by other processes before the file is created. Using "mkstemp/2" is prefererred. mktemp(TEMPLATE?, FILENAME^, TAIL?) The same as "mktemp/2", but unifies FILENAME with a character list terminated by TAIL. mkstemp(TEMPLATE?, FILE^, FILENAME^) Unifies FILE with a file-descriptor for a freshly created temporary file. TEMPLATE should be a string ending with at least 6 "X" characters. mkstemp(TEMPLATE?, FILE^, FILENAME^, TAIL?) Similar to "mkstemp/3" but unifies FILENAME with a character list terminated by TAIL. access(FILENAME?, MODE?, R^) Unifies R with 0 if the file with the given name can be accessed with the modes MODE. If the file is not accessible, unify R with -1. chmod(FILENAME?, MODE?, R^) Change the file mode of the given file to MODE and unify R with 0 ot -1. umask(UMASK^) Unify UMASK with the current umask of the process. umask(OLD^, NEW?) Change the umask of the current process to NEW and unify OLD with the previous one. signal_stream(SIGNAL?, R^) Unify R with "normal(S?)" where S is a stream that receives the atom "[]" the empty list for every occurrence of the signal given in SIGNAL which should be an integer. system(COMMAND?, R^) Invoke the given shell command and unify R with the exit status. getenv(NAME?, VALUE^) Unify VALUE with a string holding the value of the environment variable given by NAME or the integer 0 if the variable is currently not defined. putenv(STRING?, R^) Sets the environment variable given by STRING, which should be of the form "=". Unifies R with 0 or -1, depending on whether the operation siucceeded or not. kill(PID?, SIGNAL?, R^) Sends the given SIGNAL (an inteeger) to the process PID and unifies R with 0 or -1. fork(PID^) Forks the current process. In the parent process PID will be unified with the id of the child process, in the child process PID will be 0. fork_with_pipes(R^) Forks and unifies R with a tuple for communicating between parent and child process. In the parent R will be unified with "parent(PID^, IN?, OUT?)" and in the child with "child(IN?, OUT?)". Parent and child can communicate by sending I/O commands to IN and OUT, respectively. I/O streams understand the following commands: feof(R^) Unifies R with 1 or 0 depending on whether the end of file is reached. fseek(POS?, DIR?, R^) Sets the current file position to POS and unifies R with 0 or -1. DIR can be 0 (count POS from start of file), 1 (count from current position) or 2 (count from end). ftell(R^) Unifies R with the current file position. fclose(R^) Closes file and unifies R with 0. sync(R^) Synchronizes any outstanding read/write operations. getc(C^) Reads a byte and unifies C with the value or -1 if at end of file. ungetc(C?) Unread the byte for reading it on the next input operation. fwrite(STRING?, R^) Writes the string to the I/O stream and returns the number of bytes written in R. fwrite(STRING?) Writes the string to the I/O stream and waits until the operation is complete. format(FORMAT?, ARGUMENTS?) Writes the formatted string, as with using "fmt:format_chars/3". fread(COUNT?, STRING^) Reads at most COUNT bytes and unifies STRING with the received input. fread(COUNT?, LIST^, TAIL?) Read bytes as list, terminated with TAIL. linecount(COUNT^) Assigns the current line, starting at 0. Note that "fseek/3" will invalidate this counter. putc(C?) Write a byte. C If a number is stored in the stream it is interpreted identically to the corresponding "putc" operation. ## 38. module "config": platform and configuration information This module provides various information about how the system was configured at build time. config:fleng_version(VERSION^) Assigns the full version of the runtime and compiler to VERSION as a string. config:fleng_prefix(PREFIX^) Assigns a string containing the installation-prefix to PREFIX. config:os_type(OS^) Assigns the operating-system type to OS, which is one of the strings "linux" or "bsd". config:architecture(ARCHITECTURE^) Assigns the architecture id to ARCHITECTURE, being one of the strings "x64", "a32", "a64" or "r64". config:flavor(FLAVOR^) Assigns the operating system flavor to FLAVOR, which is one of the strings "m" (Mac), "b" (generated code requires BTI/IBT instructions) or the empty string. ## 39. "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?) fill_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?) warp_mouse(X?, Y?) FONT may be "[]" to specify the builtin 8*16 bitmap font. CURSOR may be one of the strings "default", "arrow", "ibeam", "wait", "crosshair", "waitarrow", "size_nwse", "size_nesw", "size_we", "size_ns", "size_all", "no", or "hand". FLAG is one of the strings "true" and "false". 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. ## 40. "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. Screen coordinates are converted to the coordinate system of a drawing by applying the following formula: DrawingX = (ScreenX - OriginX) / ScaleX DrawingY = (ScreenY - OriginY) / ScaleY 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. You can use the flengdraw program to interactively edit graphics and store them in a format suitable for use in FGHC/Strand code. Consult the "flengdraw(1)" manual page or enter "flengdoc flengdraw". As in the "sdl" module, all interfacing to the structured graphics system is done via a stream that receives messages, as obtained by the "ezd:init/{1,2,3}" predicate. Messages understood are any of the following: 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) filled_polygon(X, Y, SIDES, RADIUS, ANGLE) filled_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 is an pointer to an image file loaded via "sdl:load_image/2" or may be a string or character list naming an existing image file or a global variable containing the image pointer. FONT should be a pointer to a font loaded via "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. Polygons are always anchored at the center. If PRIMITIVES is empty, delete any object with this name. If it is not empty, the object retains any attributes, event handlers 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 and make it the current drawing. scale(NAME?, X?, Y?) Set scale of named drawing to X/Y and make it the current drawing. 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". Makes NAME the current drawing. 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. ACTION may also be a port - in that case the event is sent unchanged to that port. 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, with objects on top receiving the event before any object lower in the Z order. NAME may be "*" to match any object in the drawing. Event coordinates are always reported as screen coordinates. 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. order(LIST^) Unifies LIST with the names of all objects in the current drawing, sorted in increasing Z-order. window_to_drawing(XW?, YW?, XD^, YD^) Converts window coordinates XW/YW into the coordinate-system of the current drawing and assigns the new position to XD/YD. drawing_to_window(XD?, YD?, XW^, YW^) Converts the position XD/YD in the coordinate-system of the current drawing into window coordinates and assigns the new position to XW/YW. sdl(MESSAGE?) Pass MESSAGE on unchanged to the SDL command stream. 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. ## 41. "$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 asin x - Arc sine acos x - Arc cosine 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. ## 42. "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. ## 43. 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: = ... = | = "-" "(" "," ... ")" = [] "(" "," ... ")" [ ...] = [":"] = ["[" "]"] "," ... ";" = "int" | "char" | "long" | "short" | "double" = | = "," ... = "function" = | = "{" [";"] ... "}" | "{" "||" ... "}" | "{" "?" ... "}" | "{" "~" ... "}" = ";" | "," = "=" | ["[" "]"] ":=" | "=" | "++" {"++" } | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | "&=" | "|=" | "^=" | "<--" | | "if" "(" "," ... ")" ["else" ] | "let" | "with" "=" "," ... "->" | "foreign_call" "(" ")" | "return" "(" ")" | ["(" "," ... ")"] | ":" "(" "," ... ")" | = "over" ".." "::" | "over" "::" = | "`" "`" = | = ":" | " = "[" "," ... ["|" ] "]" | "{" "," ... "}" | | | | = "[" "," ... ["|" ] "]" | "{" "," ... "}" |