klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit 58aa1bb5f9a376eb6448f5249ffc12f377559641
parent 5a4381b470855c2038bea8c8f6de1f0b687671b3
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Tue,  6 Dec 2011 17:57:04 -0300

Merged (and closed) r7rs. All development will continue in default

Diffstat:
ATODO | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rmanual/html/A-Sample-Applicative-Description.html -> doc/html/A-Sample-Applicative-Description.html | 0
Rmanual/html/Acknowledgements.html -> doc/html/Acknowledgements.html | 0
Rmanual/html/Alphabetical-Index.html -> doc/html/Alphabetical-Index.html | 0
Rmanual/html/Booleans.html -> doc/html/Booleans.html | 0
Rmanual/html/Caveats.html -> doc/html/Caveats.html | 0
Rmanual/html/Characters.html -> doc/html/Characters.html | 0
Rmanual/html/Combiners.html -> doc/html/Combiners.html | 0
Adoc/html/Continuations.html | 238+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rmanual/html/Control.html -> doc/html/Control.html | 0
Rmanual/html/Conventions.html -> doc/html/Conventions.html | 0
Rmanual/html/Encapsulations.html -> doc/html/Encapsulations.html | 0
Rmanual/html/Environments.html -> doc/html/Environments.html | 0
Rmanual/html/Equivalence.html -> doc/html/Equivalence.html | 0
Rmanual/html/Error-Messages.html -> doc/html/Error-Messages.html | 0
Rmanual/html/Evaluation-Notation.html -> doc/html/Evaluation-Notation.html | 0
Rmanual/html/Format-of-Descriptions.html -> doc/html/Format-of-Descriptions.html | 0
Rmanual/html/Introduction.html -> doc/html/Introduction.html | 0
Rmanual/html/Kernel-History.html -> doc/html/Kernel-History.html | 0
Rmanual/html/Keyed-Variables.html -> doc/html/Keyed-Variables.html | 0
Rmanual/html/License.html -> doc/html/License.html | 0
Rmanual/html/Numbers.html -> doc/html/Numbers.html | 0
Rmanual/html/Pairs-and-lists.html -> doc/html/Pairs-and-lists.html | 0
Rmanual/html/Ports.html -> doc/html/Ports.html | 0
Rmanual/html/Printing-Notation.html -> doc/html/Printing-Notation.html | 0
Rmanual/html/Promises.html -> doc/html/Promises.html | 0
Rmanual/html/Some-Terms.html -> doc/html/Some-Terms.html | 0
Rmanual/html/Strings.html -> doc/html/Strings.html | 0
Rmanual/html/Symbols.html -> doc/html/Symbols.html | 0
Rmanual/html/index.html -> doc/html/index.html | 0
Adoc/klisp.1 | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/klisp.info | 2840+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rmanual/src/Makefile -> doc/src/Makefile | 0
Rmanual/src/booleans.texi -> doc/src/booleans.texi | 0
Rmanual/src/characters.texi -> doc/src/characters.texi | 0
Rmanual/src/combiners.texi -> doc/src/combiners.texi | 0
Adoc/src/continuations.texi | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rmanual/src/control.texi -> doc/src/control.texi | 0
Rmanual/src/encapsulations.texi -> doc/src/encapsulations.texi | 0
Rmanual/src/environments.texi -> doc/src/environments.texi | 0
Rmanual/src/equivalence.texi -> doc/src/equivalence.texi | 0
Rmanual/src/index.texi -> doc/src/index.texi | 0
Rmanual/src/intro.texi -> doc/src/intro.texi | 0
Rmanual/src/keyed_vars.texi -> doc/src/keyed_vars.texi | 0
Rmanual/src/klisp.texi -> doc/src/klisp.texi | 0
Rmanual/src/numbers.texi -> doc/src/numbers.texi | 0
Rmanual/src/pairs_lists.texi -> doc/src/pairs_lists.texi | 0
Rmanual/src/ports.texi -> doc/src/ports.texi | 0
Rmanual/src/promises.texi -> doc/src/promises.texi | 0
Rmanual/src/strings.texi -> doc/src/strings.texi | 0
Rmanual/src/symbols.texi -> doc/src/symbols.texi | 0
Dmanual/html/Continuations.html | 233-------------------------------------------------------------------------------
Dmanual/klisp.info | 2835-------------------------------------------------------------------------------
Dmanual/src/continuations.texi | 198-------------------------------------------------------------------------------
Msrc/Makefile | 145++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/examples/ffi-sdl.k | 6++----
Msrc/examples/ffi-signal.c | 15++++-----------
Msrc/imath.c | 4++--
Asrc/kchar.c | 40++++++++++++++++++++++++++++++++++++++++
Asrc/kchar.h | 34++++++++++++++++++++++++++++++++++
Msrc/kcontinuation.c | 2+-
Msrc/kencapsulation.c | 5+++++
Msrc/kencapsulation.h | 8+-------
Msrc/kenvironment.c | 9++++++---
Msrc/kenvironment.h | 2+-
Msrc/kerror.c | 6++----
Msrc/kerror.h | 2+-
Msrc/keval.c | 15+++++++++++++++
Msrc/keval.h | 6++----
Msrc/kgbooleans.c | 28+++++++++++++++++++---------
Msrc/kgbooleans.h | 36++----------------------------------
Msrc/kgbytevectors.c | 121++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/kgbytevectors.h | 39---------------------------------------
Msrc/kgc.c | 11++++++-----
Msrc/kgchars.c | 144++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/kgchars.h | 63---------------------------------------------------------------
Msrc/kgcombiners.c | 392+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/kgcombiners.h | 76++--------------------------------------------------------------------------
Msrc/kgcontinuations.c | 148+++++++++++--------------------------------------------------------------------
Msrc/kgcontinuations.h | 49++-----------------------------------------------
Msrc/kgcontrol.c | 293+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/kgcontrol.h | 37++-----------------------------------
Msrc/kgencapsulations.c | 34+---------------------------------
Msrc/kgencapsulations.h | 15---------------
Msrc/kgenv_mut.c | 44+++++++++++++++++++++++++++++---------------
Msrc/kgenv_mut.h | 244+------------------------------------------------------------------------------
Msrc/kgenvironments.c | 106++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/kgenvironments.h | 73++-----------------------------------------------------------------------
Msrc/kgeqp.c | 3++-
Msrc/kgeqp.h | 52----------------------------------------------------
Msrc/kgequalp.c | 166++-----------------------------------------------------------------------------
Msrc/kgequalp.h | 17-----------------
Dsrc/kgerror.c | 95-------------------------------------------------------------------------------
Dsrc/kgerror.h | 29-----------------------------
Asrc/kgerrors.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/kgerrors.h | 20++++++++++++++++++++
Msrc/kgffi.c | 50++++++++++++++++++++++++++------------------------
Msrc/kgffi.h | 12++----------
Msrc/kghelpers.c | 1599++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/kghelpers.h | 280+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/kgkd_vars.c | 167+------------------------------------------------------------------------------
Msrc/kgkd_vars.h | 18------------------
Msrc/kgks_vars.h | 12------------
Msrc/kgnumbers.c | 358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/kgnumbers.h | 202-------------------------------------------------------------------------------
Msrc/kgpair_mut.c | 157+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/kgpair_mut.h | 43-------------------------------------------
Msrc/kgpairs_lists.c | 448+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/kgpairs_lists.h | 87++-----------------------------------------------------------------------------
Msrc/kgports.c | 362+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/kgports.h | 107++-----------------------------------------------------------------------------
Msrc/kgpromises.c | 25+++++++++++++++++++++++--
Msrc/kgpromises.h | 25++-----------------------
Msrc/kground.c | 82+++++++++++++++++++++----------------------------------------------------------
Msrc/kground.h | 1+
Msrc/kgstrings.c | 264++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/kgstrings.h | 77-----------------------------------------------------------------------------
Msrc/kgsymbols.c | 2+-
Msrc/kgsymbols.h | 27---------------------------
Msrc/kgsystem.c | 214++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/kgsystem.h | 14--------------
Msrc/kgvectors.c | 335++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/kinteger.c | 22++++++++++++++++++++++
Msrc/kinteger.h | 4++++
Msrc/klimits.h | 10++++++++++
Msrc/klisp.c | 317++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/klispconf.h | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/kobject.c | 16+++++++++++++---
Msrc/kobject.h | 37+++++++++++++++++++++++++++++--------
Msrc/kpair.c | 2--
Msrc/kpair.h | 61-------------------------------------------------------------
Msrc/krational.c | 6++++--
Msrc/kread.c | 126++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/kread.h | 5++---
Msrc/kreal.c | 2++
Msrc/krepl.c | 44++++++++++++++++++++++++++------------------
Msrc/krepl.h | 9++-------
Dsrc/kscript.c | 254-------------------------------------------------------------------------------
Dsrc/kscript.h | 25-------------------------
Msrc/kstate.c | 55++++++++++++++++++++++++++++++++++++++-----------------
Msrc/kstate.h | 49+++++++++++++------------------------------------
Msrc/ksymbol.c | 69++++++++++++++-------------------------------------------------------
Msrc/ksymbol.h | 14++++++++------
Asrc/ksystem.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ksystem.h | 17+++++++++++++++++
Asrc/ksystem.posix.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ksystem.win32.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ktable.c | 2+-
Msrc/ktoken.c | 460++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/ktoken.h | 26++++++++++----------------
Msrc/kvector.c | 2++
Msrc/kvector.h | 6+++---
Msrc/kwrite.c | 269++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/kwrite.h | 1+
Dsrc/rep_op_c.sed | 78------------------------------------------------------------------------------
Dsrc/rep_op_h.sed | 32--------------------------------
Msrc/tests/booleans.k | 33++++++++++++++++++++++++++++++++-
Msrc/tests/bytevectors.k | 50++++++++++++++++++++++++++++++--------------------
Msrc/tests/characters.k | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/tests/combiners.k | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/tests/control.k | 262+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/tests/error.k | 5++++-
Msrc/tests/numbers.k | 101++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/tests/pair-mutation.k | 35+++++++++++++++++++++++++++++++++++
Msrc/tests/pairs-and-lists.k | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/tests/ports.k | 3++-
Msrc/tests/promises.k | 15++++++++++++++-
Msrc/tests/strings.k | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Asrc/tests/system.k | 27+++++++++++++++++++++++++++
Msrc/tests/test-all.k | 1+
Asrc/tests/test-interpreter.sh | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/tests/vectors.k | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
172 files changed, 10664 insertions(+), 7399 deletions(-)

diff --git a/TODO b/TODO @@ -0,0 +1,58 @@ +* refactor: +** double check combiner names to be verbs + (e.g. add get- where appropriate) +** split kghelpers in appropriate parts + (e.g. create knumber.h knumber.c and move there kfinitep, kintegerp, etc + from kgnumbers) +** use some convention for ground operative underlaying function names + maybe add "kgop_" +** use a better convention for continuation underlaying function names +** try to use krooted_vars_push more to save some lines and avoid + clutter (e.g. when creating continuations) +** Study differrent c interfaces (maybe a stack like in lua would be + better than dealing with gc push/pop) +** eliminate all remaining char * arguments where not needed +** remove most of inline declarations, we may then add some + back after proper profiling +** standarize either int32_t (now used in lists) or uint32_t (now used + in strings, vectors and bytevectors) for sizes (and maybe use a + typedef like lua) +* fix: +** fix char-ready? and u8-ready? (r7rs) +* documentation +** update the manual with the current features +** add a section to the manual with the interpreter usage +* reader/writer +** syntax support for complex numbers (Kernel report) +* library +** some simplified error guarding (r7rs) +** $case (r7rs) +** $case-lambda + $case-vau (r7rs) +** $named-let + $do (r7rs) +** $define-record-type (r7rs) +** eager comprehensions (at least for check.k) see SRFIs 42 and 78 + (srfi) +* other +** restarts (r7rs/common lisp) +** add restart support to the repl/interpreter (r7rs) +** simple modules (something inspired in r7rs) (r7rs) +** add modules support to the interpreter (r7rs) +** complex numbers (Kernel report) +** interval arithmetic (Kernel report) +* reduce binary size +** currently (2011/12/05) is 3megs... most of it from kg*.o +** 1st culprite klisp_assert: +** almost 1 meg comes from klisp_asserts, asserts also add + considerably to the compilation time +** add a flag to enable assertions (maybe debug) and disable + it by default +** fix warnings when assertions are turned off (probably unitialized + uses, unused variables, etc) +** 2nd culprite debugging symbols: +** 1 meg and a half comes from debugging symbols, they also add to + the compilation time +** add a flag (maybe the same as for asserts, maybe another one) to + include debug symbols and disable it by default +** After removing asserts & symbols the size is reduced to a more + manageable 500k, however it would be nice to bring that even + lower diff --git a/manual/html/A-Sample-Applicative-Description.html b/doc/html/A-Sample-Applicative-Description.html diff --git a/manual/html/Acknowledgements.html b/doc/html/Acknowledgements.html diff --git a/manual/html/Alphabetical-Index.html b/doc/html/Alphabetical-Index.html diff --git a/manual/html/Booleans.html b/doc/html/Booleans.html diff --git a/manual/html/Caveats.html b/doc/html/Caveats.html diff --git a/manual/html/Characters.html b/doc/html/Characters.html diff --git a/manual/html/Combiners.html b/doc/html/Combiners.html diff --git a/doc/html/Continuations.html b/doc/html/Continuations.html @@ -0,0 +1,238 @@ +<html lang="en"> +<head> +<title>Continuations - klisp Reference Manual</title> +<meta http-equiv="Content-Type" content="text/html"> +<meta name="description" content="klisp Reference Manual"> +<meta name="generator" content="makeinfo 4.13"> +<link title="Top" rel="start" href="index.html#Top"> +<link rel="prev" href="Combiners.html#Combiners" title="Combiners"> +<link rel="next" href="Encapsulations.html#Encapsulations" title="Encapsulations"> +<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage"> +<meta http-equiv="Content-Style-Type" content="text/css"> +<style type="text/css"><!-- + pre.display { font-family:inherit } + pre.format { font-family:inherit } + pre.smalldisplay { font-family:inherit; font-size:smaller } + pre.smallformat { font-family:inherit; font-size:smaller } + pre.smallexample { font-size:smaller } + pre.smalllisp { font-size:smaller } + span.sc { font-variant:small-caps } + span.roman { font-family:serif; font-weight:normal; } + span.sansserif { font-family:sans-serif; font-weight:normal; } +--></style> +</head> +<body> +<div class="node"> +<a name="Continuations"></a> +<p> +Next:&nbsp;<a rel="next" accesskey="n" href="Encapsulations.html#Encapsulations">Encapsulations</a>, +Previous:&nbsp;<a rel="previous" accesskey="p" href="Combiners.html#Combiners">Combiners</a>, +Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> +<hr> +</div> + +<!-- node-name, next, previous, up --> +<h2 class="chapter">9 Continuations</h2> + +<p><a name="index-continuations-126"></a> + A continuation is a plan for all future computation, parameterized +by a value to be provided, and contingent on the states of all mutable +data structures (which notably may include environments). When the +Kernel evaluator is invoked, the invoker provides a continuation to +which the result of the evaluation will normally be returned. + + <p>For example, when <code>$if</code> evaluates its test operand, the +continuation provided for the result expects to be given a boolean +value; and, depending on which boolean it gets, it will evaluate +either the consequent or the alternative operand as a tail context — +that is, the continuation provided for the result of evaluating the +selected operand is the same continuation that was provided for the +result of the call to <code>$if</code>. + + <p>A Kernel program may sometimes capture a continuation; that is, +acquire a reference to it as a first-class object. The basic means of +continuation capture is applicative <code>call/cc</code>. Given a +first-class continuation <code>c</code>, a combiner can be constructed that +will abnormally pass its operand tree to <code>c</code> (as opposed to the +<!-- TODO add xref to abnormal pass --> +normal return of values to continuations). In the simplest case, the +abnormally passed value arrives at <code>c</code> as if it had been normally +returned to <code>c</code>. In general, continuations bypassed by the +abnormal pass may have entry/exit guards attached to them, and these +guards can intercept the abnormal pass before it reaches <code>c</code>. +Each entry/exit guard consists of a selector continuation, which +designates which abnormal passes the guard will intercept, and an +interceptor applicative that performs the interception when selected. +<!-- TODO add xref to guard-continuation, continuation->applicative --> +<!-- and abnormal pass --> + + <p>Continuations are immutable, and are <code>equal?</code> iff <code>eq?</code>. +The continuation type is encapsulated. + +<!-- TODO add dynamic extent & guard selection/interception to the intro --> +<div class="defun"> +&mdash; Applicative: <b>continuation?</b> (<var>continuation? . objects</var>)<var><a name="index-continuation_003f-127"></a></var><br> +<blockquote><p> The primitive type predicate for type continuation. +<code>continuation?</code> returns true iff all the objects in +<code>objects</code> are of type continuation. +</p></blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>call/cc</b> (<var>call/cc combiner</var>)<var><a name="index-call_002fcc-128"></a></var><br> +<blockquote><p> Calls <code>combiner</code> in the dynamic environment as a tail context, +passing as sole operand to it the continuation to which <code>call/cc</code> +would normally return its result. (That is, constructs such a +combination and evaluates it in the dynamic environment.) +<!-- TODO add xref Cf. operative $let/cc , §7.3.2. --> +</p></blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>extend-continuation</b> (<var>extend-continuation continuation applicative </var>[<var>environment</var>])<var><a name="index-extend_002dcontinuation-129"></a></var><br> +<blockquote><p> The <code>extend-continuation</code> applicative constructs and returns a +new child of <code>continuation</code> that, when it normally receives a +value v, calls the underlying combiner of <code>applicative</code> with +dynamic environment <code>environment</code> (or an empty environment if +none was specified) and operand tree <code>v</code>, the result of the call +normally to be returned to <code>continuation</code>. + + <p>The following equivalnece defines the short version: + <pre class="example"> (extend-continuation c a) == + (extend-continuation c a (make-environment)) +</pre> + </blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>guard-continuation</b> (<var>guard-continuation entry-guards continuation exit-guards</var>)<var><a name="index-guard_002dcontinuation-130"></a></var><br> +<blockquote><p> <code>entry-guards</code> and <code>exit-guards</code> should each be a list of +clauses; each clause should be a list of length two, whose first +element is a continuation, and whose second element is an applicative +whose underlying combiner is operative. + + <p>Applicative <code>guard-continuation</code> constructs two continuations: +a child of continuation, called the <code>outer continuation</code>; and a +child of the <code>outer continuation</code>, called the <code>inner +continuation</code>. The <code>inner continuation</code> is returned as the +result of the call to <code>guard-continuation</code>. + + <p>When the <code>inner continuation</code> normally receives a value, it +passes the value normally to the <code>outer continuation</code>; and when +the <code>outer continuation</code> normally receives a value, it passes the +value normally to <code>continuation</code>. Thus, in the absence of +abnormal passing, the inner and outer continuations each have the same +behavior as <code>continuation</code>. + + <p>The two elements of each guard clause are called, respectively, the +<code>selector</code> and the <code>interceptor</code>. The <code>selector</code> +continuation is used in deciding whether to intercept a given abnormal +pass, and the <code>interceptor</code> applicative is called to perform +<!-- TODO add xref to selection and interception --> +customized action when interception occurs. + + <!-- TODO add xref to evaluation structure --> + <p>At the beginning of the call to <code>guard-continuation</code>, internal +copies are made of the evaluation structures of <code>entry-guards</code> +and <code>exit-guards</code>, so that the selectors and interceptors +contained in the arguments at that time remain fixed thereafter, +independent of any subsequent mutations to the arguments. +</p></blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>continuation-&gt;applicative</b> (<var>continuation-&gt;applicative continuation</var>)<var><a name="index-continuation_002d_003eapplicative-131"></a></var><br> +<blockquote><p> Returns an applicative whose underlying operative abnormally passes +its operand tree to <code>continuation</code>, thus: A series of +interceptors are selected to handle the abnormal pass, and a +continuation is derived that will normally perform all the +interceptions in sequence and pass some value to the destination of +the originally abnormal pass. The operand tree is then normally +passed to the derived continuation. +<!-- TODO add xref to selection and interception --> +</p></blockquote></div> + +<div class="defun"> +&mdash; Variable: <b>root-continuation</b><var><a name="index-root_002dcontinuation-132"></a></var><br> +<blockquote><p> This continuation is the ancestor of all other continuations. When +it normally receives a value, it terminates the Kernel session. (For +example, if the system is running a read-eval-print loop, it exits the +loop.) +<!-- TODO add xref Cf. applicative exit, §7.3.4. --> +</p></blockquote></div> + +<div class="defun"> +&mdash; Variable: <b>error-continuation</b><var><a name="index-error_002dcontinuation-133"></a></var><br> +<blockquote><p> The dynamic extent of this continuation is mutually disjoint from +the dynamic extent in which Kernel computation usually occurs (such as +the dynamic extent in which the Kernel system would run a +read-eval-print loop). + + <p>When this continuation normally receives a value, it provides a +diagnostic message to the user of the Kernel system, on the assumption +that the received value is an attempt to describe some error that +aborted a computation; and then resumes operation of the Kernel system +at some point that is outside of all user-defined computation. (For +example, if the system is running a read-eval-print loop, operation +may resume by continuing from the top of the loop.) + + <p>The diagnostic message is not made available to any Kernel +computation, and is therefore permitted to contain information that +violates abstractions within the system. + + <!-- TODO add details about klisp error messages --> + <p>When an error is signaled during a Kernel computation, the signaling +action consists of an abnormal pass to some continuation in the +dynamic extent of <code>error-continuation</code>. +</p></blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>apply-continuation</b> (<var>apply-continuation continuation object</var>)<var><a name="index-apply_002dcontinuation-134"></a></var><br> +<blockquote><p> Applicative <code>apply-continuation</code> converts its first argument to +an applicative as if by <code>continuation-&gt;applicative</code>, and then +applies it as usual. + + <p>That is: + <pre class="example"> (apply-continuation continuation object) == + (apply (continuation-&gt;applicative continuation) object) +</pre> + </blockquote></div> + +<div class="defun"> +&mdash; Operative: <b>(</b><var>$let/cc &lt;symbol&gt; . &lt;objects&gt;</var>)<var><a name="index-g_t_0028-135"></a></var><br> +<blockquote><p> A child environment <code>e</code> of the dynamic environment is created, +containing a binding of <code>&lt;symbol&gt;</code> to the continuation to which +the result of the call to <code>$let/cc</code> should normally return; then, +the subexpressions of <code>&lt;objects&gt;</code> are evaluated in <code>e</code> from +left to right, with the last (if any) evaluated as a tail context, or +if <code>&lt;objects&gt;</code> is empty the result is inert. + + <p>That is: + <pre class="example"> ($let/cc symbol . objects) == + (call/cc ($lambda (symbol) . objects)) +</pre> + </blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>guard-dynamic-extent</b> (<var>guard-dynamic-extent entry-guards combiner exit-guards</var>)<var><a name="index-guard_002ddynamic_002dextent-136"></a></var><br> +<blockquote><p> This applicative extends the current continuation with the specified +guards, and calls <code>combiner</code> in the dynamic extent of the new +continuation, with no operands and the dynamic environment of the call +to <code>guard-dynamic-extent</code>. +</p></blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>exit</b> (<var>exit </var>[<var>object</var>])<var><a name="index-exit-137"></a></var><br> +<blockquote><!-- TODO add xref --> + <p>Applicative <code>exit</code> initiates an abnormal transfer of +<code>object</code> (or <code>#inert</code> if <code>object</code> was not specified), +to <code>root-continuation</code>. + That is: + <pre class="example"> (exit) == (apply-continuation root-continuation #inert) + (exit obj) == (apply-continuation root-continuation obj) +</pre> + <p>SOURCE NOTE: This applicative doesn't have the optional argument in +the report. It was added to klisp to allow a simple way to terminate +the interpreter passing a value that is then tried to convert to an +exit status. +</p></blockquote></div> + +<!-- *-texinfo-*- --> + </body></html> + diff --git a/manual/html/Control.html b/doc/html/Control.html diff --git a/manual/html/Conventions.html b/doc/html/Conventions.html diff --git a/manual/html/Encapsulations.html b/doc/html/Encapsulations.html diff --git a/manual/html/Environments.html b/doc/html/Environments.html diff --git a/manual/html/Equivalence.html b/doc/html/Equivalence.html diff --git a/manual/html/Error-Messages.html b/doc/html/Error-Messages.html diff --git a/manual/html/Evaluation-Notation.html b/doc/html/Evaluation-Notation.html diff --git a/manual/html/Format-of-Descriptions.html b/doc/html/Format-of-Descriptions.html diff --git a/manual/html/Introduction.html b/doc/html/Introduction.html diff --git a/manual/html/Kernel-History.html b/doc/html/Kernel-History.html diff --git a/manual/html/Keyed-Variables.html b/doc/html/Keyed-Variables.html diff --git a/manual/html/License.html b/doc/html/License.html diff --git a/manual/html/Numbers.html b/doc/html/Numbers.html diff --git a/manual/html/Pairs-and-lists.html b/doc/html/Pairs-and-lists.html diff --git a/manual/html/Ports.html b/doc/html/Ports.html diff --git a/manual/html/Printing-Notation.html b/doc/html/Printing-Notation.html diff --git a/manual/html/Promises.html b/doc/html/Promises.html diff --git a/manual/html/Some-Terms.html b/doc/html/Some-Terms.html diff --git a/manual/html/Strings.html b/doc/html/Strings.html diff --git a/manual/html/Symbols.html b/doc/html/Symbols.html diff --git a/manual/html/index.html b/doc/html/index.html diff --git a/doc/klisp.1 b/doc/klisp.1 @@ -0,0 +1,198 @@ +.TH KLISP 1 "$Date: 2011/11/23 06:35:03 $" +.SH NAME +klisp \- Kernel Programming Language interpreter +.SH SYNOPSIS +.B klisp +[ +.I options +] +[ +.I script +[ +.I args +] +] +.SH DESCRIPTION +.B klisp +is a stand-alone klisp interpreter for +the Kernel Programming Language. +It loads and evaluates Kernel programs +in textual source form. +.B klisp +can be used as a batch interpreter and also interactively. +.LP +The given +.I options +(see below) +are evaluated and then +the klisp program in file +.I script +is loaded and evaluated. +All evaluations mentioned, including the initialization +that is described below, take place in the same +(initially) standard environment. All values that +result from these evaluation are discarded, but +if the root continuation or error continuation +are passed a value, the evaluation of options +is interrupted and the EXIT_STATUS is as described +in the corresponding section. +The string +.I script +together with all +.I args +are available as a list of strings +via the applicative +.RI ' get-script-arguments '. +If these arguments contain spaces or other characters special to the shell, +then they should be quoted +(but note that the quotes will be removed by the shell). +The complete command line +including the name of the interpreter, options, +the script, and its arguments +are available as a list of strings +via the applicative +.RI ' get-interpreter-arguments '. +.LP +At the very beginning, +before even handling the command line, +.B klisp +reads and evaluates the contents of the environment variable +.BR KLISP_INIT , +if it is defined. +To use an init file, just define +.B KLISP_INIT +to the following form +.RI '(load +"/path/to/init-file")'. +.LP +Options start with +.B '\-' +and are described below. +You can use +.B "'\--'" +to signal the end of options. +.LP +If no arguments are given, +then +.B "\-v \-i" +is assumed when the standard input is a terminal; +otherwise, +.B "\-" +is assumed. +.LP +In interactive mode, +.B klisp +prompts the user, +reads expressions from the standard input, +and evaluates them as they are read. +The default prompt is "klisp> ". +.SH OPTIONS +.TP +.B \- +load and execute the standard input as a file, +that is, +not interactively, +even when the standard input is a terminal. +.TP +.BI \-e " expr" +evaluate expression +.IR expr . +You need to quote +.I expr +if it contains spaces, quotes, +or other characters special to the shell. +.TP +.B \-i +enter interactive mode after +.I script +is executed. +.TP +.BI \-l " name" +evaluate +.BI (load " name") +before +.I script +is executed. +Typically used to do environment initialization. +.TP +.BI \-r " name" +evaluate +.BI (require " name") +before +.I script +is executed. +Typically used to load libraries. +.TP +.B \-v +show version information. +.SH EXIT STATUS +If the +.I script +or +.I stdin +reach EOF or if there is no script, +.B EXIT_SUCCESS +is returned. +If the root continuation is passed an object during +init, arguments or script evaluation +.B EXIT_FAILURE +is returned. +If the +.I root-continuation +is passed an object, +.B klisp +tries to convert the value passed to the +.I root-continuation +to an exit status as follows: +.TP +If the value is an integer it is used as exit status. +.TP +If the value is a boolean then +.B EXIT_SUCCESS +is returned for +.I #t +and +.B EXIT_FAILURE +for +.I #f. +.TP +If the value is inert, then +.B EXIT_SUCCESS +is returned. +.TP +In any other case +.B EXIT_FAILURE +is returned. +.SH ENVIRONMENT +.br +.TP +.BI KLISP_INIT +.br +A Kernel expression to be evaluated before +any arguments to the interpreter. +.br +To use an init file, just define +.B KLISP_INIT +to the following form +.RI '(load +"/path/to/init-file")'. +.br +.TP +.BI KLISP_PATH +.br +A colon separated list of templates for +controlling the search of required files. +Each template can use the char '?' to +be replaced by the required name at run-time. +.SH "SEE ALSO" +.br +http://klisp.org/ +.br +The klisp Manual (info & html versions available). +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +Andres Navarro +and +Oto Havle +.\" EOF diff --git a/doc/klisp.info b/doc/klisp.info @@ -0,0 +1,2840 @@ +This is ../klisp.info, produced by makeinfo version 4.13 from +klisp.texi. + +This file documents klisp. + + This is edition 0.2 of the klisp Reference Manual, for klisp version +0.2. + + Copyright (C) 2011 Andres Navarro + + Permission is granted to copy and distribute this manual, in whole or +in part, without fee. Please note that most text of this manual is +derived from `The Revised(-1) Report on the Kernel Programming +Language' by John N. Shutt. There's a clause in that reports, under +the header "Permission to copy this report", that reads: + + This report is intended to belong to the programming community, + and so permission is granted to copy it in whole or in part + without fee. + + +File: klisp.info, Node: Top, Next: License, Prev: (dir), Up: (dir) + + This Info file contains edition 0.2 of the klisp Reference Manual, +corresponding to klisp version 0.2. + + Copyright (C) 2011 Andres Navarro + + Permission is granted to copy and distribute this manual, in whole or +in part, without fee. Please note that most text of this manual is +derived from `The Revised(-1) Report on the Kernel Programming +Language' by John N. Shutt. There's a clause in that reports, under +the header "Permission to copy this report", that reads: + + This report is intended to belong to the programming community, + and so permission is granted to copy it in whole or in part + without fee. + +* Menu: + +* License:: Conditions for copying and changing klisp. +* Introduction:: Introduction and conventions used. +* Booleans:: Booleans module features. +* Equivalence:: Equivalence (under & up to) mutation modules features. +* Symbols:: Symbols module features. +* Control:: Control module features. +* Pairs and lists:: Pairs and lists and Pair mutation modules features. +* Environments:: Environments and Environment mutation modules features. +* Combiners:: Combiners module features. +* Continuations:: Continuations module features. +* Encapsulations:: Encapsulations module features. +* Promises:: Promises module features. +* Keyed Variables:: Keyed (dynamic & static) variables module features. +* Numbers:: Numbers module features. +* Strings:: Strings module features. +* Characters:: Characters module features. +* Ports:: Ports module features. +* Alphabetical Index:: Index including concepts, functions, variables, + and other terms. + + +File: klisp.info, Node: License, Next: Introduction, Prev: Top, Up: Top + + klisp is licensed under the terms of the MIT license reproduced +below. This means that klisp is free software and can be used for both +academic and commercial purposes at absolutely no cost. The two +projects whose code klisp uses, Lua & IMath, are also distributed under +the MIT license. + + * klisp Parts: Copyright (C) 2011 Andres Navarro, Oto Havle. + + * Lua Parts: Copyright (C) 1994-2010 Lua.org, PUC-Rio. + + * IMath Parts: Copyright (C) 2002-2007 Michael J. Fromberger. + + * srfi-78: Copyright (C) 2005-2006 Sebastian Egner. + +MIT/X11 License +*************** + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + + The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +File: klisp.info, Node: Introduction, Next: Booleans, Prev: License, Up: Top + +1 Introduction +************** + +klisp is an open source interpreter for the Kernel Programming +Language. It aims at being comprehensive and robust as specified in +the `Revised(-1) Report on the Kernel Programming Language', but that +probably won't happen for some time. It is written in C99 under the +MIT license. It draws heavily from the Lua interpreter source code & +file structure. It uses the IMath library for arbitrary sized integers +and rationals. + + The Kernel programming language is a statically scoped and properly +tail-recursive dialect of Lisp, descended from Scheme. It is designed +to be simpler and more general than Scheme, with an exceptionally +clear, simple, and versatile semantics, only one way to form compound +expressions, and no inessential restrictions on the power of that one +compound form. Imperative, functional, and message-passing programming +styles (to name a few) may be conveniently expressed in Kernel. + + An important property of Kernel is that all manipulable entities in +Kernel are first-class objects. In particular, Kernel has no +second-class combiners; instead, the roles of special forms and macros +are subsumed by operatives, which are first-class, statically scoped +combiners that act directly on their unevaluated operands. Kernel also +has a second type of combiners, applicatives, which act on their evalu- +ated arguments. Applicatives are roughly equivalent to Scheme +procedures. However, an applicative is nothing more than a wrapper to +induce operand evaluation, around an underlying operative (or, in +principle, around another applicative, though that isn’t usually done); +applicatives themselves are mere facilitators to computation. + + You can read more about Kernel at +`http://web.cs.wpi.edu/~jshutt/kernel.html'. + + klisp is freely available for both academic and commercial purposes. +See LICENSE for details. it can be downloaded at +`https://bitbucket.org/AndresNavarro/klisp' + + klisp is developed by Andres Navarro, a Computer Science +undergraduate at Buenos Aires University (UBA). You can reach him at +<canavarro82@gmail.com>. Significant contributions are being done by +Oto Havle, his fork is at `https://bitbucket.org/havleoto/klisp'. + + This manual describes klisp version 0.2, presuming some familiarity +with the Lisp family of languages in general, and with the Kernel +Programming Language in particular. There are frequent references to +the Kernel Programming Language Report. Unlike in the report, no +rationale is provided for any feature, only a description of the +implemented functionality. + + This is edition 0.2. + +* Menu: + +* Caveats:: Flaws and a request for help. +* Kernel History:: Kernel is descended from Scheme. +* Conventions:: How the manual is formatted. +* Acknowledgements:: Contributions to this manual. + + +File: klisp.info, Node: Caveats, Next: Kernel History, Prev: Introduction, Up: Introduction + +1.1 Caveats +=========== + +This is the first draft of this manual. It will be incomplete for some +time. It will also evolve, together with klisp and the Kernel +Programming Language, both of which, right now, are in a quite fluid +state. + + The main reference on Kernel is the preliminary report: `Revised(-1) +Report on the Kernel Programming Language'. Some sections of the +report are still incomplete, so both klisp and this manual will use +specifications from other languages in these sections, trying to follow +the Kernel spirit. These instances will be documented throughout the +manual. + + Please mail comments and corrections to <canavarro82@gmail.com>. + + + -Andres Navarro + + +File: klisp.info, Node: Kernel History, Next: Conventions, Prev: Caveats, Up: Introduction + +1.2 Kernel History +================== + +The Kernel Programming Language is a work in progress. It is being +developed by John N. Shutt, Ph.D, who created it while studying at the +Worcester Polytechnic Institute (I think about 2002, or so... ASK). It +is descended from scheme, with the idea that all objects should be +first class values. In particular, Kernel replaces macros with +operatives (kinda like statically scoped fexprs and fsubrs) and has +first class environments. Kernel also has the notion of encapsulated +objects which limits the ammount of information an implementation can +share with a Kernel program (e.g. There is no way in Kernel to get the +parents or a complete list of bindings of an environment object). + + The main reference on Kernel is the preliminary report: `Revised(-1) +Report on the Kernel Programming Language'. Some sections of the +report are still incomplete, so both klisp and this manual will use +specifications from other languages in these sections, trying to follow +the Kernel spirit. These instances will be documented throughout the +manual. + + You can read all about Kernel at John's homepage at WPI +`http://www.cs.wpi.edu/~jshutt/', including the preliminary report on +the language and his doctoral dissertation which gives a theorethical +frame for fexprs. You can contact him at <jshutt@cs.wpi.edu>. + + +File: klisp.info, Node: Conventions, Next: Acknowledgements, Prev: Kernel History, Up: Introduction + +1.3 Conventions +=============== + +This section explains the notational conventions that are used in this +manual. You may want to skip this section and refer back to it later. + +* Menu: + +* Some Terms:: Explanation of terms we use in this manual. +* Evaluation Notation:: The format we use for examples of evaluation. +* Printing Notation:: The format we use for examples that print output. +* Error Messages:: The format we use for examples of errors. +* Format of Descriptions:: Notation for describing functions, variables, etc. + + +File: klisp.info, Node: Some Terms, Next: Evaluation Notation, Prev: Conventions, Up: Conventions + +1.3.1 Some Terms +---------------- + +Throughout this manual, the phrases "the Kernel reader" and "the Kernel +printer" are used to refer to those routines in Lisp that convert +textual representations of Kernel objects into actual objects, and vice +versa. XXX Printed Representation XXX, for more details. You, the +person reading this manual, are assumed to be "the programmer" or "the +user". + + Examples of Kernel code appear in this font or form: `(list 1 2 3)'. +Names that represent arguments or metasyntactic variables appear in +this font or form: FIRST-NUMBER. + + +File: klisp.info, Node: Evaluation Notation, Next: Printing Notation, Prev: Some Terms, Up: Conventions + +1.3.2 Evaluation Notation +------------------------- + +When you evaluate a piece of Kernel code, it produces a result. In the +examples in this manual, this is indicated with `=>': + + (car (cons 1 2)) + => 1 + +You can read this as "`(car (cons 1 2))' evaluates to 1". + + The semantics of a language feature are sometimes clarified, or even +defined, in its entry by specifying that two expressions are +equivalent. This is notated with `=='. For example, the semantics of +applicative list* can be defined by following equivalences: + (list* arg1) == arg1 + (list* arg1 . more-args) == (cons arg1 (list* . more-args)) + Notice that in these kind of examples the applicatives or operatives +referred to are the first class values and not the symbols bound to +them in the ground environment. This definition would hold even if +`cons' or `list*' were redefined in the current dynamic environment. + + +File: klisp.info, Node: Printing Notation, Next: Error Messages, Prev: Evaluation Notation, Up: Conventions + +1.3.3 Printing Notation +----------------------- + +Many of the examples in this manual print text when they are evaluated. +In examples that print text, the printed text is indicated with `-|'. +The value returned by evaluating the form (here `#t') follows on a +separate line. + + ($sequence (write 1) (write 2) #t) + -| 1 + -| 2 + => #t + + +File: klisp.info, Node: Error Messages, Next: Format of Descriptions, Prev: Printing Notation, Up: Conventions + +1.3.4 Error Messages +-------------------- + +Some examples cause errors to be signaled. The report doesn't specify +what objects are passed to the error continuation, but in klisp, +objects passed to the error continuation are encapsulated error objects +that have at least a message and possibly some additional objects and +context informations (such as source code location). In the examples, +the error message is shown on a line starting with `error-->'. + + (+ 23 #t) + error--> Wrong type argument: (expected number) (#t) + + +File: klisp.info, Node: Format of Descriptions, Prev: Error Messages, Up: Conventions + +1.3.5 Format of Descriptions +---------------------------- + +Applicatives, operatives, and other objects are described in this manual +in a uniform format. The first line of a description contains the name +of the item followed by its operands or arguments, if any. The +category--operative, applicative, or whatever--appears at the beginning +of the line. The description follows on succeeding lines, sometimes +with examples. + +* Menu: + +* A Sample Applicative Description:: + + +File: klisp.info, Node: A Sample Applicative Description, Prev: Format of Descriptions, Up: Format of Descriptions + +1.3.5.1 A Sample Applicative Description +........................................ + +In an applicative description, the name of the applicative being +described appears first. It is followed on the same line by an +applicative combination that includes the name of the applicative and +the arguments, as would appear in a program. The names used for the +arguments are also used in the body of the description. + + Here is a description of an imaginary applicative `foo': + + -- Applicative: foo (foo integer1 integer2 . rest) + The applicative `foo' subtracts INTEGER1 from INTEGER2, then adds + all the rest of the arguments to the result. + + (foo 1 5 3 9) + => 16 + + More generally, + + (foo W X Y...) + == + (+ (- X W) Y...) + + Any parameter whose name contains the name of a type (e.g., INTEGER, +INTEGER1 or CONTINUATION) is expected to be of that type. A plural of +a type (such as NUMBERS) often means a list of objects of that type. +Parameters named OBJECT may be of any type. Additionally parameters +named K, or KN (for any value of N), should be exact, non-negative +integers. (XXX Types of Lisp Object XXX, for a list of Kernel object +types.) Parameters with other sorts of names are discussed +specifically in the description of the combiner. In some sections, +features common to parameters of several combiners are described at the +beginning. + + Operative descriptions have the same format, but the word +`Applicative' is replaced by `Operative', and `Argument' is replaced +by `Operand'. Also Operatives always have an environment parameter +(that can be #ignore or a symbol). + + +File: klisp.info, Node: Acknowledgements, Prev: Conventions, Up: Introduction + +1.4 Acknowledgements +==================== + +This manual was written by Andres Navarro. + + The structure and some text for this introductory section were +borrowed from the Elisp Manual by the Free Sofware Foundation. This +manual also borrows freely from both the Kernel Report and the Scheme +Reports. + + +File: klisp.info, Node: Booleans, Next: Equivalence, Prev: Introduction, Up: Top + +2 Booleans +********** + +The boolean data type consists of two values, which are called true and +false, and have respectively external representations `#t' and `#f'. +There are no possible mutations of either of these two values, and the +boolean type is encapsulated. + + -- Applicative: boolean? (boolean? . objects) + The primitive type predicate for type boolean. `boolean?' returns + true iff all the objects in `objects' are of type boolean. + + -- Applicative: not? (not? boolean) + Applicative `not?' is a predicate that returns the logical + negation of its argument. + + -- Applicative: and? (and? . booleans) + Applicative `and?' is a predicate that returns true unless one or + more of its arguments are false. + + -- Applicative: or? (or? . booleans) + Applicative `or?' is a predicate that returns false unless one or + more of its arguments are true. + + -- Operative: $and? ($and? . <list>) + The `$and?' operative performs a "short-circuit and" of its + operands. It evaluates them from left to right, until either an + operand evaluates to false, or the end of the list is reached. If + the end of the list is reached (which is immediate if `<list>' is + `nil'), the operative returns true. If an operand evaluates to + false, no further operand evaluations are performed, and the + operative returns false. If `<list>' is acyclic, and the last + operand is evaluated, it is evaluated as a tail context. If + `<list>' is cyclic, an unbounded number of operand evaluations may + be performed. If any of the operands evaluates to a non-boolean + value, an error is signaled (even if it's the last one). + + -- Operative: $or? ($or? . <list>) + The `$or?' operative performs a "short-circuit or" of its + operands. It evaluates them from left to right, until either an + operand evaluates to true, or the end of the list is reached. If + the end of the list is reached (which is immediate if `<list>' is + `nil'), the operative returns false. If an operand evaluates to + true, no further operand evaluations are performed, and the + operative returns true. If `<list>' is acyclic, and the last + operand is evaluated, it is evaluated as a tail context. If + `<list>' is cyclic, an unbounded number of operand evaluations may + be performed. If any of the operands evaluates to a non-boolean + value, an error is signaled (even if it's the last one). + + +File: klisp.info, Node: Equivalence, Next: Symbols, Prev: Booleans, Up: Top + +3 Equivalence +************* + +Kernel has two general-purpose equivalence predicates (whereas R5RS +Scheme has three). The two Kernel predicates correspond to the +abstract notions of equivalence up to mutation (`equal') and +equivalence in the presence of mutation (`eq?'). + + -- Applicative: eq? (eq? . objects) + Predicate `eq?' returns true iff all of `objects' are effectively + the same object, even in the presence of mutation. + + -- Applicative: equal? (equal? . objects) + Predicate `equal?' returns true iff all of `objects' "look" the + same as long as nothing is mutated. This is a weaker predicate + than `eq?'; that is, `equal?' must return true whenever `eq?' + would return true. + + +File: klisp.info, Node: Symbols, Next: Control, Prev: Equivalence, Up: Top + +4 Symbols +********* + +Two symbols are eq? iff they have the same external representation. +Symbols are immutable, and the symbol type is encapsulated. The +external representations of symbols are usually identifiers. However, +symbols with other external representations may be created. + + -- Applicative: symbol? (symbol? . objects) + The primitive type predicate for type symbol. `symbol?' returns + true iff all the objects in `objects' are of type symbol. + + -- Applicative: symbol->string (symbol->string symbol) + Applicative `symbol->string' returns the name of `symbol' as a + string. The string returned is immutable. + + -- Applicative: string->symbol (string->symbol string) + Applicative `string->symbol' returns the symbol with name + `string'. The symbol is always interned, which means, that it is + always the case that: + (eq? <symbol> (string->symbol (symbol->string <symbol>))) + => #t + `string->symbol' can create symbols whose external + representation aren't identifiers. Right now klisp uses an + output-only representation, but in the near future it will + probably include some kind of escaping mechanism to allow + arbitrary symbols to have readable external representations as in + R7RS Scheme. + + +File: klisp.info, Node: Control, Next: Pairs and lists, Prev: Symbols, Up: Top + +5 Control +********* + +The inert data type is provided for use with control combiners. It +consists of a single immutable value, having external representation +`#inert'. The inert type is encapsulated. + + -- Applicative: inert? (inert? . objects) + The primitive type predicate for type inert. `inert?' returns true + iff all the objects in `objects' are of type inert. + + -- Operative: $if ($if <test> <consequent> <alternative>) + The `$if' operative first evaluates `<test>' in the dynamic + environment. If the result is not of type boolean, an error is + signaled. If the result is true, `<consequent>' is then evaluated + in the dynamic environment as a tail context. Otherwise, + `<alternative>' is evaluated in the dynamic environment as a tail + context. + + -- Operative: $sequence ($sequence . <objects>) + The `$sequence' operative evaluates the elements of the list + `<objects>' in the dynamic environment, one at a time from left to + right. If `<objects>' is a cyclic list, element evaluation + continues indefinitely, with elements in the cycle being evaluated + repeatedly. If `<objects>' is a nonempty finite list, its last + element is evaluated as a tail context. If `<objects>' is the + empty list, the result is inert. + + -- Operative: $cond ($cond . <clauses>) + `<clauses>' should be a list of clause expressions, each of the + form `(<test> . <body>)', where body is a list of expressions. + + The following equivalences define the behaviour of the `$cond' + operative: + ($cond) == #inert + ($cond (<test> . <body>) . <clauses>) == + ($if <test> ($sequence . <body>) ($cond . <clauses>)) + + -- Applicative: for-each (for-each . lists) + `lists' must be a nonempty list of lists; if there are two or + more, they should all be the same length. If lists is empty, or if + all of its elements are not lists of the same length, an error is + signaled. + + `for-each' behaves identically to `map', except that instead of + accumulating and returning a list of the results of the + element-wise applications, the results of the applications are + discarded and the result returned by `for-each' is inert. + + +File: klisp.info, Node: Pairs and lists, Next: Environments, Prev: Control, Up: Top + +6 Pairs and lists +***************** + +A pair is an object that refers to two other objects, called its car +and cdr. The Kernel data type pair is encapsulated. + + The null data type consists of a single immutable value, called nil +or the empty list and having external representation `()', with or +without whitespace between the parentheses. It is immutable, and the +null type is encapsulated. + + If `a' and `d' are external representations of respectively the car +and cdr of a pair `p', then `(a . d)' is an external representation of +`p'. If the cdr of `p' is nil, then `(a)' is also an external +representation of `p'. If the cdr of `p' is a pair `p2', and `(r)' is +an external representation of `p2', then `(a r)' is an external +representation of `p'. When a pair is output (as by write), an +external representation with the fewest parentheses is used; in the +case of a finite list, only one set of parentheses is required beyond +those used in representing the elements of the list. For example, an +object with external representation `(1 . (2 . (3 . ())))' would be +output using, modulo whitespace, external representation `(1 2 3)'. + + -- Applicative: pair? (pair? . objects) + The primitive type predicate for type pair. `pair?' returns true + iff all the objects in `objects' are of type pair. + + -- Applicative: null? (null? . objects) + The primitive type predicate for type null. `null?' returns true + iff all the objects in `objects' are of type null. + + -- Applicative: cons (cons object1 object2) + A new mutable pair object is constructed and returned, whose car + and cdr referents are respectively `object1' and `object2'. No + two objects returned by different calls to cons are `eq?' to each + other. + + -- Applicative: set-car! (set-car! pair object) + -- Applicative: set-cdr! (set-cdr! pair object) + `pair' should be a mutable pair. + + These applicatives set the referent of, respectively, the car + reference or the cdr reference of `pair' to `object'. The result + of the expression is inert. + + -- Applicative: copy-es-immutable! (copy-es-immutable object) + The short description of this applicative is that it returns an + object `equal?' to `object' with an immutable evaluation + structure. The "-es-" in the name is short for "evaluation + structure". + + The evaluation structure of an object `o' is defined to be the set + of all pairs that can be reached by following chains of references + from `o' without ever passing through a non-pair object. The + evaluation structure of a non-pair object is empty. + + If `object' is not a pair, the applicative returns `object'. + Otherwise (if `object' is a pair), the applicative returns an + immutable pair whose car and cdr would be suitable results for + `(copy-es-immutable (car object))' and `(copy-es-immutable (cdr + object))', respectively. Further, the evaluation structure of the + returned value is isomorphic to that of `object' at the time of + copying, with corresponding non-pair referents being `eq?'. + + NOTE: In Kernel it's undefined whether immutable pairs are copied + or left "as is" in the result. klisp doesn't copy immutable + pairs, but that behaviour should not be depended upon. + + -- Applicative: list (list . objects) + The `list' applicative returns `objects'. + + The underlying operative of `list' returns its undifferentiated + operand tree, regardless of whether that tree is or is not a list. + + -- Applicative: list* (list* . objects) + `objects' should be a finite nonempty list of arguments. + + The following equivalences hold: + (list* arg1) == arg1 + (list* arg1 arg2 . args) == (cons arg1 (list* arg2 . args)) + + -- Applicative: car (car pair) + -- Applicative: cdr (cdr pair) + These applicatives return, respectively, the car and cdr of `pair'. + + -- Applicative: caar (caar pair) + -- Applicative: cadr (cadr pair) + -- Applicative: cdar (cdar pair) + -- Applicative: cddr (cddr pair) + -- Applicative: caaar (caaar pair) + -- Applicative: caadr (caadr pair) + -- Applicative: cadar (cadar pair) + -- Applicative: caddr (caddr pair) + -- Applicative: cdaar (cdaar pair) + -- Applicative: cdadr (cdadr pair) + -- Applicative: cddar (cddar pair) + -- Applicative: cdddr (cdddr pair) + -- Applicative: caaaar (caaaar pair) + -- Applicative: caaadr (caaadr pair) + -- Applicative: caadar (caadar pair) + -- Applicative: caaddr (caaddr pair) + -- Applicative: cadaar (cadaar pair) + -- Applicative: cadadr (cadadr pair) + -- Applicative: caddar (caddar pair) + -- Applicative: cadddr (cadddr pair) + -- Applicative: cdaaar (cdaaar pair) + -- Applicative: cdaadr (cdaadr pair) + -- Applicative: cdadar (cdadar pair) + -- Applicative: cdaddr (cdaddr pair) + -- Applicative: cddaar (cddaar pair) + -- Applicative: cddadr (cddadr pair) + -- Applicative: cdddar (cdddar pair) + -- Applicative: cddddr (cddddr pair) + These applicatives are compositions of `car' and `cdr', with the + "a’s" and "d’s" in the same order as they would appear if all the + individual "car’s" and "cdr’s" were written out in prefix order. + Arbitrary compositions up to four deep are provided. There are + twenty-eight of these applicatives in all. + + -- Applicative: get-list-metrics (get-list-metrics object) + By definition, an improper list is a data structure whose objects + are its start together with all objects reachable from the start by + following the cdr references of pairs, and whose internal + references are just the cdr references of its pairs. Every + object, of whatever type, is the start of an improper list. If + the start is not a pair, the improper list consists of just that + object. The acyclic prefix length of an improper list `L' is the + number of pairs of `L' that a naive traversal of `L' would visit + only once. The cycle length of `L' is the number of pairs of `L' + that a naive traversal would visit repeatedly. Two improper lists + are structurally isomorphic iff they have the same acyclic prefix + length and cycle length and, if they are terminated by non-pair + objects rather than by cycles, the non-pair objects have the same + type. Applicative `get-list-metrics' constructs and returns a + list of exact integers of the form `(p n a c)', where `p', `n', + `a', and `c' are, respectively, the number of pairs in, the number + of nil objects in, the acyclic prefix length of, and the cycle + length of, the improper list starting with `object'. `n' is either + `0' or `1', `a + c = p', and `n' and `c' cannot both be non-zero. + If `c = 0', the improper list is acyclic; if `n = 1', the improper + list is a finite list; if `n = c = 0', the improper list is not a + list; if `a = c = 0', `object' is not a pair. + + -- Applicative: list-tail (list-tail object k) + `object' must be the start of an improper list containing at least + `k' pairs. + + The `list-tail' applicative follows `k' cdr references starting + from `object'. + + The following equivalences hold: + (list-tail object 0) == object + (list-tail object (+ k 1)) == (list-tail (cdr object) k) + + -- Applicative: encycle! (encycle! object k1 k2) + The improper list starting at `object' must contain at least `k1 + + k2' pairs. + + If `k2 = 0', the applicative does nothing. If `k2 > 0', the + applicative mutates the improper list starting at `object' to have + acyclic prefix length `k1' and cycle length `k2', by setting the + cdr of the `(k1+k2)'th pair in the list to refer to the `(k1 + + 1)'th pair in the list. The result returned by `encycle!' is + inert. + + -- Applicative: map (map applicative . lists) + `lists' must be a nonempty list of lists; if there are two or + more, they must all have the same length. + + The map applicative applies `applicative' element-wise to the + elements of the lists in lists (i.e., applies it to a list of the + first elements of the lists, to a list of the second elements of + the lists, etc.), using the dynamic environment from which map was + called, and returns a list of the results, in order. The + applications may be performed in any order, as long as their + results occur in the resultant list in the order of their + arguments in the original lists. If `lists' is a cyclic list, + each argument list to which `applicative' is applied is + structurally isomorphic to `lists'. If any of the elements of + `lists' is a cyclic list, they all must be, or they wouldn’t all + have the same length. Let `a1...an' be their acyclic prefix + lengths, and `c1...cn' be their cycle lengths. The acyclic prefix + length `a' of the resultant list will be the maximum of the `ak', + while the cycle length `c' of the resultant list will be the least + common multiple of the `ck'. In the construction of the result, + `applicative' is called exactly `a + c' times. + + -- Applicative: length (length object) + Applicative `length' returns the (exact) improper-list length of + `object'. That is, it returns the number of consecutive cdr + references that can be followed starting from `object'. If + `object' is not a pair, it returns zero; if `object' is a cyclic + list, it returns positive infinity. + + -- Applicative: list-ref (list-ref object k) + The `list-ref' applicative returns the `car' of the object + obtained by following `k' cdr references starting from `object'. + + NOTE: In the current report, object is required to be a list. In + klisp, for now, we prefer the behaviour presented here, as it is + more in line with the applicative `list-tail'. That is, we define + `list-ref' by the following equivalence: + (list-ref object k) == (car (list-tail object k)) + + -- Applicative: append (append . lists) + Here, all the elements of `lists' except the last element (if any) + must be acyclic lists. The `append' applicative returns a freshly + allocated list of the elements of all the specified `lists', in + order, except that if there is a last specified element of + `lists', it is not copied, but is simply referenced by the cdr of + the preceding pair (if any) in the resultant list. If `lists' is + cyclic, the cycle of the result list consists of just the elements + of the lists specified in the cycle in `lists'. In this case, the + acyclic prefix length of the result is the sum of the lengths of + the lists specified in the acyclic prefix of `lists', and the + cycle length of the result is the sum of the lengths of the lists + specified in the cycle of `lists'. + + The following equivalences hold: + (append) == () + (append h) == h + (append () h . t) == (append h . t) + (append (cons a b) h . t) == (cons a (append b h . t)) + + -- Applicative: list-neighbors (list-neighbors list) + The `list-neighbors' applicative constructs and returns a list of + all the consecutive sublists of `list' of length 2, in order. If + `list' is nil, the result is nil. If `list' is non-nil, the + length of the result is one less than the length of `list'. If + `list' is cyclic, the result is structurally isomorphic to it + (i.e., has the same acyclic prefix length and cycle length). + + For example: + (list-neighbors (list 1 2 3 4)) => ((1 2) (2 3) (3 4)) + + -- Applicative: filter (filter applicative list) + Applicative `filter' passes each of the elements of `list' as an + argument to `applicative', one at a time in no particular order, + using a fresh empty environment for each call. The result of each + call to `applicative' must be boolean, otherwise an error is + signaled. `filter' constructs and returns a list of all elements + of `list' on which `applicative' returned true, in the same order + as in `list'. `applicative' is called exactly as many times as + there are pairs in `list'. The resultant list has a cycle + containing exactly those elements accepted by `applicative' that + were in the cycle of `list'; if there were no such elements, the + result is acyclic. + + -- Applicative: assoc (assoc object pairs) + Applicative `assoc' returns the first element of `pairs' whose car + is `equal?' to `object'. If there is no such element in `pairs', + nil is returned. + + -- Applicative: member? (member? object list) + Applicative `member?' is a predicate that returns true iff some + element of `list' is `equal?' to `object'. + + -- Applicative: finite-list? (finite-list? . objects) + This is the type predicate for type finite-list. `finite-list?' + returns true iff all the objects in `objects' are acyclic lists. + + -- Applicative: countable-list? (countable-list? . objects) + This is the type predicate for type list. `countable-list?' + returns true iff all the objects in `objects' are lists. + + -- Applicative: reduce (reduce list binary identity [precycle incycle + postcycle]) + `binary' should be an applicative. If the short form is used, + `list' should be an acyclic. If the long form is used, `precycle', + `incycle', and `postcycle' should be applicatives. + + If `list' is empty, applicative `reduce' returns `identity'. If + `list' is nonempty but acyclic, applicative `reduce' uses binary + operation `binary' to merge all the elements of `list' into a + single object, using any associative grouping of the elements. + That is, the sequence of objects initially found in `list' is + repeatedly decremented in length by applying `binary' to a list of + any two consecutive objects, replacing those two objects with the + result at the point in the sequence where they occurred; and when + the sequence contains only one object, that object is returned. + If `list' is cyclic, the long form must be used. The elements of + the cycle are passed, one at a time (but just once for each + position in the cycle), as arguments to unary applicative + `precycle'; the finite, cyclic sequence of results from `precycle' + is reduced using binary applicative `incycle'; and the result from + reducing the cycle is passed as an argument to unary applicative + `postcycle'. Binary operation `binary' is used to reduce the + sequence consisting of the elements of the acyclic prefix of + `list' followed by the result returned by `postcycle'. The only + constraint on the order of calls to the applicatives is that each + call must be made before its result is needed (thus, parts of the + reduction of the acyclic prefix may occur before the contribution + from the cycle has been completed). + + Each call to `binary', `precycle', `incycle', or `postcycle' uses + the dynamic environment of the call to `reduce'. + + If `list' is acyclic with length `n >= 1', `binary' is called `n - + 1' times. If `list' is cyclic with acyclic prefix length `a' and + cycle length `c', `binary' is called `a' times; `precycle', `c' + times; `incycle', `c - 1' times; and `postcycle', once. + + -- Applicative: append! (append! . lists) + `lists' must be a nonempty list; its first element must be an + acyclic nonempty list, and all of its elements except the last + element (if any) must be acyclic lists. + + The `append!' applicative sets the cdr of the last pair in each + nonempty list argument to refer to the next non-nil argument, + except that if there is a last non-nil argument, it isn’t mutated. + It is an error for any two of the list arguments to have the same + last pair. The result returned by this applicative is inert. + + The following equivalences hold: + (append! v) == #inert + (append! u v . w) == ($sequence (append! u v) (append! u . w)) + + -- Applicative: copy-es (copy-es object) + Briefly, applicative `copy-es' returns an object initially + `equal?' to `object' with a freshly constructed evaluation + structure made up of mutable pairs. If `object' is not a pair, + the applicative returns `object'. If `object' is a pair, the + applicative returns a freshly constructed pair whose car and cdr + would be suitable results for `(copy-es (car object))' and + `(copy-es (cdr object))', respectively. Further, the evaluation + structure of the returned value is structurally isomorphic to that + of `object' at the time of copying, with corresponding non-pair + referents being `eq?'. + + -- Applicative: assq (assq object pairs) + Applicative `assq' returns the first element of `pairs' whose car + is `eq?' to `object'. If there is no such element in `pairs', nil + is returned. + + -- Applicative: memq? (memq? object list) + Applicative `memq?' is a predicate that returns true iff some + element of `list' is `eq?' to `object'. + + +File: klisp.info, Node: Environments, Next: Combiners, Prev: Pairs and lists, Up: Top + +7 Environments +************** + +An environment consists of a set of bindings, and a list of zero or +more references to other environments called its parents. Changing the +set of bindings of an environment, or setting the referent of the +reference in a binding, is a mutation of the environment. (Changing the +parent list, or a referent in the list, would be a mutation of the +environment too, but there is no facility provided to do it.) The +Kernel data type environment is encapsulated. Among other things, +there is no facility provided for enumerating all the variables +exhibited by an environment (which is not required, after all, to be a +finite set), and no facility for identifying the parents of an +environment. Two environments are `equal?' iff they are `eq?'. + + An auxiliary data type used by combiners that perform binding is +ignore. The ignore type consists of a single immutable value, having +external representation `#ignore'. The ignore type is encapsulated. + + -- Applicative: environment? (environment? . objects) + The primitive type predicate for type environment. `environment?' + returns true iff all the objects in `objects' are of type + environment. + + -- Applicative: ignore? (ignore? . objects) + The primitive type predicate for type ignore. `ignore?' returns + true iff all the objects in `objects' are of type ignore. + + -- Applicative: eval (eval expression environment) + The `eval' applicative evaluates `expression' as a tail context in + `environment', and returns the resulting value. + + -- Applicative: make-environment (make-environment . environments) + The applicative constructs and returns a new environment, with + initially no local bindings, and parent environments the + environments listed in `environments'. The constructed environment + internally stores its list of parents independent of the + first-class list `environments', so that subsequent mutation of + `environments' will not change the parentage of the constructed + environment. If the provided list `environments' is cyclic, the + constructed environment will still check each of its parents at + most once, and signal an error if no binding is found locally or + in any of the parents. No two objects returned by different calls + to `make-environment' are `eq?' to each other. + + -- Operative: $define! ($define! <definiend> <expression>) + `<definiend>' should be a formal parameter tree, as described + below; otherwise, an error is signaled. + + The `$define!' operative evaluates `<expression>' in the dynamic + environment and matches `<definiend>' to the result in the dynamic + environment, binding each symbol in definiend in the dynamic + environment to the corresponding part of the result; the matching + process will be further described below. The ancestors of the + dynamic environment, if any, are unaffected by the matching + process, as are all bindings, local to the dynamic environment, of + symbols not in `<definiend>'. The result returned by `$define!' is + inert. + + A formal parameter tree has the following context-free structure: + ptree:: symbol | #ignore | () | (ptree . ptree) + + That is, a formal parameter tree is either a symbol, or ignore, or + nil, or a pair whose car and cdr referents are formal parameter + trees. A formal parameter tree must also be acyclic, and no one + symbol can occur more than once in it. It is not an error for a + pair in the tree to be reachable from the root by more than one + path, as long as there is no cycle; but if any particular symbol + were reachable from the root by more than one path, that would + count as occurring more than once. Thus, if a pair is reachable + by more than one path, there must be no symbols reachable from it. + + Matching of a formal parameter tree `t' to an object `o' in an + environment `e' proceeds recursively as follows. If the matching + process fails, an error is signaled. + * If `t' is a symbol, then `t' is bound to `o' in `e'. + + * If `t' is `#ignore', no action is taken. + + * If `t' is nil, then `o' must be nil (else matching fails). + + * If `t' is a pair, then `o' must be a pair (else matching + fails). The car of `t' is matched to the car of `o' in `e', + and the cdr of `t' is matched to the cdr of `o' in `e'. + + -- Operative: $let ($let <bindings> . <objects>) + `<bindings>' should be a finite list of + formal-parameter-tree/expression pairings, each of the form + `(formals expression)', where each `formals' is a formal + parameter, and no symbol occurs in more than one of the `formals'. + + The following equivalence holds: + + ($let ((form1 exp1) ... (formn expn)) . objects) == + (($lambda (form1 ... formn) . objects) exp1 ... expn) + + Thus, the `expk' are first evaluated in the dynamic environment, + in any order; then a child environment `e' of the dynamic + environment is created, with the `formk' matched in `e' to the + results of the evaluations of the `expk'; and finally the + subexpressions of `objects' are evaluated in `e' from left to + right, with the last (if any) evaluated as a tail context, or if + `objects' is empty the result is inert. + + -- Operative: $binds? ($binds? <exp> . <symbols>) + Operative `$binds' evaluates `<exp>' in the dynamic environment; + call the result `env'. `env' must be an environment. The + operative is a predicate that returns true iff all its later + operands, `<symbols>', are visibly bound in `env'. + + -- Applicative: get-current-environment (get-current-environment) + The `get-current-environment' applicative returns the dynamic + environment in which it is called. + + -- Applicative: make-kernel-standard-environment + (make-kernel-standard-environment) + The `make-kernel-standard-environment' applicative returns a + standard environment; that is, a child of the ground environment + with no local bindings. + + -- Operative: $let* ($let* <bindings> . <body>) + `<bindings>' should be a finite list of + formal-parameter-tree/expression pairings, each of the form + `(formals expression)', where each `formals' is a formal parameter + tree; `<body>' should be a list of expressions. + + The following equivalences hold: + + ($let* () . body) == ($let () . body) + + ($let* ((form exp) . bindings) . body) == + ($let ((form exp)) ($let* bindings . body)) + + -- Operative: $letrec ($letrec <bindings> . <body>) + `<bindings>' and `<body>' should be as described for `$let'. + + The following equivalence holds: + ($letrec ((form1 exp1) ... (formn expn)) . body) == + ($let () ($define! (form1 ... formn) (list exp1 ... expn)) . body) + + -- Operative: $letrec* ($letrec* <bindings> . <body>) + `<bindings>' and `<body>' should be as described for `$let*'. + + The following equivalences hold: + ($letrec* () . body) == ($letrec () . body) + + ($letrec* ((form exp) . bindings) . body) == + ($letrec ((form exp)) ($letrec* bindings . body)) + + -- Operative: $let-redirect ($let-redirect <exp> <bindings> . <body>) + `<bindings>' and `<body>' should be as described for `$let'. + + The following equivalence holds: + + ($let-redirect exp ((form1 exp1) ... (formn . body) expn)) == + ((eval (list $lambda (form1 ... formn) body) exp) expn ... expn) + + -- Operative: $let-safe ($let-safe <bindings> . <body>) + `<bindings>' and `<body>' should be as described for `$let'. + + The following equivalence holds: + + ($let-safe bindings . body) == + ($let-redirect (make-kernel-standard-environment) bindings . body) + + -- Operative: $remote-eval ($remote-eval <exp1> <exp2>) + Operative `$remote-eval' evaluates `<exp2>' in the dynamic + environment, then evaluates `<exp1>' as a tail context in the + environment that must result from the first evaluation. + + -- Operative: ($bindings-environment . <bindings>) + `<bindings>' should be as described for `$let'. + + The following equivalence holds: + + ($bindings->environment . bindings) == + ($let-redirect (make-environment) bindings (get-current-environment)) + + -- Operative: $set! ($set! <exp1> <formals> <exp2>) + `<formals>' should be as described for the `$define!' operative. + The `$set!' operative evaluates `<exp1>' and `<exp2>' in the + dynamic environment; call the results `env' and `obj'. If `env' + is not an environment, an error is signaled. Then the operative + matches `<formals>' to `obj' in environment `env'. Thus, the + symbols of `<formals>' are bound in `env' to the corresponding + parts of `obj'. The result returned by `$set!' is inert. + + -- Operative: $provide! ($provide! <symbols> . <body>) + `<symbols>' must be a finite list of symbols, containing no + duplicates. `<body>' must be a finite list. + + The `$provide!' operative constructs a child `e' of the dynamic + environment `d'; evaluates the elements of `<body>' in `e', from + left to right, discarding all of the results; and exports all of + the bindings of symbols in `<symbols>' from `e' to `d', i.e., + binds each symbol in `d' to the result of looking it up in `e'. + The result returned by `$provide!' is inert. + + The following equivalence holds: + + ($provide! symbols . body) == + ($define! symbols ($let () ($sequence . body) (list . symbols))) + + -- Operative: $import! ($import! <exp> . <symbols>) + `<symbols>' must be a list of symbols. + + The `$import!' operative evaluates `<exp>' in the dynamic + environment; call the result `env'. `env' must be an environment. + Each distinct symbol `s' in `<symbols>' is evaluated in `env', and + `s' is bound in the dynamic environment to the result of this + evaluation. + + The following equivalence holds: + + ($import! exp . symbols) == + ($define! symbols ($remote-eval (list symbols) exp)) + + +File: klisp.info, Node: Combiners, Next: Continuations, Prev: Environments, Up: Top + +8 Combiners +*********** + +There are two types of combiners in Kernel, operative and applicative. +Both types are encapsulated. All combiners are immutable. Two +applicatives are `eq?' iff their underlying combiners are `eq?'. +However, `eq?'-ness of operatives is only constrained by the general +rules for `eq?', which leave considerable leeway for variation between +implementations. klisp only considers `eq?' those operatives +constructed by the same call to a constructor (e.g. `$vau'). Two +combiners are `equal?' iff they are `eq?'. + + -- Applicative: operative? (operative? . objects) + The primitive type predicate for type operative. `operative?' + returns true iff all the objects in `objects' are of type + operative. + + -- Applicative: applicative? (applicative? . objects) + The primitive type predicate for type applicative. `applicative?' + returns true iff all the objects in `objects' are of type + applicative. + + -- Operative: $vau ($vau <formals> <eformal> . <objects>) + `<formals>' should be a formal parameter tree; `<eformal>' should + be either a symbol or `#ignore'. If `<formals>' does not have the + correct form for a formal parameter tree, or if `<eformal>' is a + symbol that also occurs in `<formals>', an error is signaled. + + A `vau' expression evaluates to an operative; an operative created + in this way is said to be compound. The environment in which the + `vau' expression was evaluated is remembered as part of the + compound operative, called the compound operative’s static + environment. `<formals>' and `<objects>' are copied as by + `copy-es-immutable' and the copies are stored as part of the + operative being constructed. This avoids problem if these + structures are later mutated. + + When the compound operative created by `$vau' is later called with + an object and an environment, here called respectively the operand + tree and the dynamic environment, the following happens: + + 1. A new, initially empty environment is created, with the static + environment as its parent. This will be called the local + environment. + + 2. A stored copy of the formal parameter tree formals is matched + in the local environment to the operand tree, locally binding + the symbols of formals to the corresponding parts of the + operand tree. eformal is matched to the dynamic environment; + that is, if eformal is a symbol then that symbol is bound in + the local environment to the dynamic environment. + + 3. A stored copy of the expressions is evaluated sequentially + from left to right, with the last (if any) evaluated as a + tail context, or if the list of expressions is empty, the + result is inert. + + NOTE: Because compound operatives are not a distinct type in + Kernel, they are covered by the encapsulation of type operative. + In particular, an implementation of Kernel cannot provide a + feature that supports extracting the static environment of any + given compound operative, nor that supports determining whether or + not a given operative is compound. + + -- Applicative: wrap (wrap combiner) + The `wrap' applicative returns an applicative whose underlying + combiner is `combiner'. + + -- Applicative: unwrap (unwrap applicative) + The `unwrap' applicative returns the underlying combiner of + `applicative'. + + -- Operative: $lambda ($lambda <formals> . <objects>) + `<formals>' should be a formal parameter tree. + + The `$lambda' operative is defined by the following equivalence: + ($lambda formals . objects) == + (wrap ($vau formals #ignore . objects)) + + -- Applicative: apply (apply applicative object [environment]) + Applicative `apply' combines the underlying combiner of + `applicative' with `object' in a tail context with dynamic + environment `environment' (if the long form is used) or in an + empty environment (if the short form is used). + + The following equivalences hold: + (apply applicative object environment) == + (eval (cons (unwrap applicative) object) environment) + + (apply applicative object) == + (apply applicative object (make-environment)) + + -- Applicative: map (map applicative . lists) + `lists' must be a nonempty list of lists; if there are two or + more, they must all have the same length. If `lists' is empty, or + if all of its elements are not lists of the same length, an error + is signaled. + + The `map' applicative applies `applicative' element-wise to the + elements of the lists in `lists' (i.e., applies it to a list of + the first elements of the `lists', to a list of the second + elements of the `lists', etc.), using the dynamic environment from + which `map' was called, and returns a list of the results, in + order. The applications may be performed in any order, as long as + their results occur in the resultant list in the order of their + arguments in the original `lists'. If `lists' is a cyclic list, + each argument list to which `applicative' is applied is + structurally isomorphic to `lists'. If any of the elements of + `lists' is a cyclic list, they all must be, or they wouldn’t all + have the same length. Let `a1...an' be their acyclic prefix + lengths, and `c1...cn' be their cycle lengths. The acyclic prefix + length `a' of the resultant list will be the maximum of the `ak', + while the cycle length `c' of the resultant list will be the least + common multiple of the `ck'. In the construction of the result, + applicative is called exactly `a + c' times. + + -- Applicative: combiner? (combiner? . objects) + The primitive type predicate for type combiner. `combiner?' + returns true iff all the objects in `objects' are of type combiner + (i.e. applicative or operative). + + +File: klisp.info, Node: Continuations, Next: Encapsulations, Prev: Combiners, Up: Top + +9 Continuations +*************** + +A continuation is a plan for all future computation, parameterized by a +value to be provided, and contingent on the states of all mutable data +structures (which notably may include environments). When the Kernel +evaluator is invoked, the invoker provides a continuation to which the +result of the evaluation will normally be returned. + + For example, when `$if' evaluates its test operand, the continuation +provided for the result expects to be given a boolean value; and, +depending on which boolean it gets, it will evaluate either the +consequent or the alternative operand as a tail context — that is, the +continuation provided for the result of evaluating the selected operand +is the same continuation that was provided for the result of the call +to `$if'. + + A Kernel program may sometimes capture a continuation; that is, +acquire a reference to it as a first-class object. The basic means of +continuation capture is applicative `call/cc'. Given a first-class +continuation `c', a combiner can be constructed that will abnormally +pass its operand tree to `c' (as opposed to the normal return of values +to continuations). In the simplest case, the abnormally passed value +arrives at `c' as if it had been normally returned to `c'. In general, +continuations bypassed by the abnormal pass may have entry/exit guards +attached to them, and these guards can intercept the abnormal pass +before it reaches `c'. Each entry/exit guard consists of a selector +continuation, which designates which abnormal passes the guard will +intercept, and an interceptor applicative that performs the +interception when selected. + + Continuations are immutable, and are `equal?' iff `eq?'. The +continuation type is encapsulated. + + -- Applicative: continuation? (continuation? . objects) + The primitive type predicate for type continuation. + `continuation?' returns true iff all the objects in `objects' are + of type continuation. + + -- Applicative: call/cc (call/cc combiner) + Calls `combiner' in the dynamic environment as a tail context, + passing as sole operand to it the continuation to which `call/cc' + would normally return its result. (That is, constructs such a + combination and evaluates it in the dynamic environment.) + + -- Applicative: extend-continuation (extend-continuation continuation + applicative [environment]) + The `extend-continuation' applicative constructs and returns a new + child of `continuation' that, when it normally receives a value v, + calls the underlying combiner of `applicative' with dynamic + environment `environment' (or an empty environment if none was + specified) and operand tree `v', the result of the call normally + to be returned to `continuation'. + + The following equivalnece defines the short version: + (extend-continuation c a) == + (extend-continuation c a (make-environment)) + + -- Applicative: guard-continuation (guard-continuation entry-guards + continuation exit-guards) + `entry-guards' and `exit-guards' should each be a list of clauses; + each clause should be a list of length two, whose first element is + a continuation, and whose second element is an applicative whose + underlying combiner is operative. + + Applicative `guard-continuation' constructs two continuations: a + child of continuation, called the `outer continuation'; and a + child of the `outer continuation', called the `inner + continuation'. The `inner continuation' is returned as the result + of the call to `guard-continuation'. + + When the `inner continuation' normally receives a value, it passes + the value normally to the `outer continuation'; and when the + `outer continuation' normally receives a value, it passes the + value normally to `continuation'. Thus, in the absence of abnormal + passing, the inner and outer continuations each have the same + behavior as `continuation'. + + The two elements of each guard clause are called, respectively, the + `selector' and the `interceptor'. The `selector' continuation is + used in deciding whether to intercept a given abnormal pass, and + the `interceptor' applicative is called to perform customized + action when interception occurs. + + At the beginning of the call to `guard-continuation', internal + copies are made of the evaluation structures of `entry-guards' and + `exit-guards', so that the selectors and interceptors contained in + the arguments at that time remain fixed thereafter, independent of + any subsequent mutations to the arguments. + + -- Applicative: continuation->applicative (continuation->applicative + continuation) + Returns an applicative whose underlying operative abnormally passes + its operand tree to `continuation', thus: A series of interceptors + are selected to handle the abnormal pass, and a continuation is + derived that will normally perform all the interceptions in + sequence and pass some value to the destination of the originally + abnormal pass. The operand tree is then normally passed to the + derived continuation. + + -- Variable: root-continuation + This continuation is the ancestor of all other continuations. When + it normally receives a value, it terminates the Kernel session. + (For example, if the system is running a read-eval-print loop, it + exits the loop.) + + -- Variable: error-continuation + The dynamic extent of this continuation is mutually disjoint from + the dynamic extent in which Kernel computation usually occurs + (such as the dynamic extent in which the Kernel system would run a + read-eval-print loop). + + When this continuation normally receives a value, it provides a + diagnostic message to the user of the Kernel system, on the + assumption that the received value is an attempt to describe some + error that aborted a computation; and then resumes operation of + the Kernel system at some point that is outside of all + user-defined computation. (For example, if the system is running a + read-eval-print loop, operation may resume by continuing from the + top of the loop.) + + The diagnostic message is not made available to any Kernel + computation, and is therefore permitted to contain information that + violates abstractions within the system. + + When an error is signaled during a Kernel computation, the + signaling action consists of an abnormal pass to some continuation + in the dynamic extent of `error-continuation'. + + -- Applicative: apply-continuation (apply-continuation continuation + object) + Applicative `apply-continuation' converts its first argument to an + applicative as if by `continuation->applicative', and then applies + it as usual. + + That is: + (apply-continuation continuation object) == + (apply (continuation->applicative continuation) object) + + -- Operative: ($let/cc <symbol> . <objects>) + A child environment `e' of the dynamic environment is created, + containing a binding of `<symbol>' to the continuation to which + the result of the call to `$let/cc' should normally return; then, + the subexpressions of `<objects>' are evaluated in `e' from left + to right, with the last (if any) evaluated as a tail context, or + if `<objects>' is empty the result is inert. + + That is: + ($let/cc symbol . objects) == + (call/cc ($lambda (symbol) . objects)) + + -- Applicative: guard-dynamic-extent (guard-dynamic-extent + entry-guards combiner exit-guards) + This applicative extends the current continuation with the + specified guards, and calls `combiner' in the dynamic extent of + the new continuation, with no operands and the dynamic environment + of the call to `guard-dynamic-extent'. + + -- Applicative: exit (exit [object]) + Applicative `exit' initiates an abnormal transfer of `object' (or + `#inert' if `object' was not specified), to `root-continuation'. + That is: + (exit) == (apply-continuation root-continuation #inert) + (exit obj) == (apply-continuation root-continuation obj) + + SOURCE NOTE: This applicative doesn't have the optional argument in + the report. It was added to klisp to allow a simple way to + terminate the interpreter passing a value that is then tried to + convert to an exit status. + + +File: klisp.info, Node: Encapsulations, Next: Promises, Prev: Continuations, Up: Top + +10 Encapsulations +***************** + +An encapsulation is an object that refers to another object, called its +content. The Kernel data type encapsulation is encapsulated. Two +encapsulations are `equal?' iff they are `eq?'. Encapsulations are +immutable. + + -- Applicative: make-encapsulation-type (make-encapsulation-type) + Returns a list of the form `(e p? d)', where `e', `p'?, and `d' + are applicatives, as follows. Each call to + `make-encapsulation-type' returns different applicatives `e', + `p?', and `d'. + + * `e' is an applicative that takes one argument, and returns a + fresh encapsulation with the argument as content. + Encapsulations returned on different occasions are not `eq?'. + + * `p?' is a primitive type predicate, that takes zero or more + arguments and returns true iff all of them are encapsulations + generated by `e'. + + * `d' is an applicative that takes one argument; if the + argument is not an encapsulation generated by `e', an error + is signaled, otherwise the content of the encapsulation is + returned. + + That is, the predicate `p?' only recognizes, and the decapsulator + `d' only extracts the content of, encapsulations created by the + encapsulator `e' that was returned by the same call to + `make-encapsulation-type'. + + +File: klisp.info, Node: Promises, Next: Keyed Variables, Prev: Encapsulations, Up: Top + +11 Promises +*********** + +A promise is an object that represents the potential to determine a +value. The value may be the result of an arbitrary computation that +will not be performed until the value must be determined (constructor +`$lazy'); or, in advanced usage, the value may be determined before the +promise is constructed (constructor `memoize'). + + The value determined by a promise is obtained by forcing it +(applicative `force'). A given promise cannot determine different +values on different occasions that it is forced. Also, if a promise +determines its value by computation, and that computation has already +been completed, forcing the promise again will produce the previously +determined result without re-initiating the computation to determine it. + + The Kernel data type promise is encapsulated. + + The general rules for predicate `eq?' only require it to distinguish +promises if they can exhibit different behavior; the resulting leeway +for variation between implementations is similar, in both cause and +effect, to that for `eq?'-ness of operatives. For example, if two +promises, constructed on different occasions, would perform the same +computation to determine their values, and that computation has no +side-effects and must always return the same value, the promises may or +may not be `eq?'. Two promises are `equal?' iff they are `eq?'. + + -- Applicative: promise? (promise? . objects) + The primitive type predicate for type promise. `promise?' returns + true iff all the objects in `objects' are of type promise. + + -- Applicative: force (force object) + If `object' is a promise, applicative `force' returns the value + determined by promise; otherwise, it returns `object'. + + The means used to force a promise depend on how the promise was + constructed. The description of each promise constructor specifies + how to force promises constructed by that constructor. + + -- Operative: $lazy ($lazy expression) + Operative `$lazy' constructs and returns a new object of type + promise, representing potential evaluation of expression in the + dynamic environment from which `$lazy' was called. + + When the promise is forced, if a value has not previously been + determined for it, `expression' is evaluated in the dynamic + environment of the constructing call to `$lazy'. If, when the + evaluation returns a result, a value is found to have been + determined for the promise during the evaluation, the result is + discarded in favor of the previously determined value; otherwise, + the result is forced, and the value returned by that forcing + becomes the value determined by the promise. + + Forcing an undetermined lazy promise (i.e., a promise constructed + by $lazy for which no value has yet been determined) may cause a + sequential series of evaluations, each of which returns a promise + that is forced and thus initiates the next evaluation in the + series. The implementation must support series of this kind with + unbounded length (i.e., unbounded number of sequential + evaluations). + + Note that forcing concerns the value determined by a given promise, + not the result of evaluating a given expression in a given + environment. Distinct promises (judged by `eq?' represent + different occasions of evaluation; so, even if they do represent + evaluation of the same expression in the same environment, forcing + one does not necessarily determine the value for the other, and + actual evaluation will take place the first time each of them is + forced. + + -- Applicative: memoize (memoize object) + Applicative `memoize' constructs and returns a new object of type + promise, representing memoization of `object'. Whenever the + promise is forced, it determines `object'. + + +File: klisp.info, Node: Keyed Variables, Next: Numbers, Prev: Promises, Up: Top + +12 Keyed Variables +****************** + +A keyed variable is a device that associates a non-symbolic key (in the +form of an accessor applicative) with a value depending on the context +in which lookup occurs. Kernel provides two types of keyed variables: +dynamic & static. Keyed Dynamic Variables use the dynamic extent as +context and Keyed Static Variables use the dynamic environment. + +12.1 Keyed Dynamic Variables +============================ + +A keyed dynamic variable is a device that associates a non-symbolic key +(in the form of an accessor applicative) with a value depending on the +dynamic extent in which lookup occurs. + + -- Applicative: make-keyed-dynamic-variable + (make-keyed-dynamic-variable) + Returns a list of the form `(b a)', where `b' and `a' are + applicatives, as follows. Each call to + `make-keyed-dynamic-variable' returns different `b' and `a'. + + * `b' is an applicative that takes two arguments, the second of + which must be a combiner. It calls its second argument with + no operands (nil operand tree) in a fresh empty environment, + and returns the result. + + * `a' is an applicative that takes zero arguments. If the call + to `a' occurs within the dynamic extent of a call to `b', then + `a' returns the value of the first argument passed to `b' in + the smallest enclosing dynamic extent of a call to `b'. If the + call to `a' is not within the dynamic extent of any call to + `b', an error is signaled. + +12.2 Keyed Static Variables +=========================== + +A keyed static variable is a device that binds data in an environment +by a non-symbolic key, where the key is an accessor applicative. + + -- Applicative: make-keyed-static-variable (make-keyed-static-variable) + Returns a list of the form `(b a)', where `b' and `a' are + applicatives, as follows. Each call to + `make-keyed-static-variable' returns different `b' and `a'. + + * `b' is an applicative that takes two arguments, the second of + which must be an environment. It constructs and returns a + child-environment of its second argument, with initially no + local bindings. + + * `a' is an applicative that takes zero arguments. If the + dynamic environment `e' of the call to a has an improper + ancestor that was constructed by a call to `b', then a + returns the value of the first argument passed to `b' in the + first such environment encountered by a depth-first traversal + of the improper ancestors of `e'. If `e' has no improper + ancestors constructed via `b', an error is signaled. + + +File: klisp.info, Node: Numbers, Next: Strings, Prev: Keyed Variables, Up: Top + +13 Numbers +********** + +All numbers are immutable, and `equal?' iff `eq?'. The number type is +encapsulated. + + The external representation of an undefined number is `#undefined'. +The external representation of a real with no primary value is `#real' +(but this may change in the future, the report is missing the output +representation for reals with no primary values). All other rules for +externally representing numbers pertain only to defined numbers with +primary values. + + An external representation of a real number consists of optional +radix and/or exactness prefixes, optional sign (`+' or `-'), and +magnitude. The radix prefixes are `#b' (binary), `#o' (octal), `#d' +(decimal), and `#x' (hexadecimal); the default is decimal. The +exactness prefixes are `#e' (exact) and `#i' (inexact); by default, the +number is inexact iff the magnitude representation uses floating point. +If both kinds of prefixes are used, they may occur in either order. The +magnitude is either `infinity'; an unsigned integer (nonempty sequence +of digits); a ratio of unsigned integers (two unsigned integers with a +`/' between, of which the second is non-zero); or a floating point +representation. If the magnitude is `infinity', there must be an +exactness prefix and a sign, and no radix prefix. Floating point +representation can only be used with decimal radix; it consists of +nonempty integer part, point (`.'), nonempty fraction part, and +optional exponent part. The optional exponent part consists of an +exponent letter, and an (optionally signed) integer indicating a power +of ten by which to multiply the magnitude. The choice of exponent +letter makes no difference in what mathematical number is indicated by +the external representation, but does indicate internal representation +precision. Exponent letters `s', `f', `d', `f' indicate preference for +successively higher internal precision - short, float, double, long. +When reading an inexact real number, exponent letter `e' accepts the +default internal precision, which must be at least double. When +writeing an inexact real number, exponent letter `e' may be used for +the default internal precision, and must be used for any internal +number format not indicated by any of the other exponent letters. +Float and double must provide, respectively, at least as much precision +as IEEE 32-bit and 64-bit floating point standards [IE85]. For +example, `#i#xa/c' represents an inexact number using hexadecimal +notation, with signed magnitude positive five sixths (ten over twelve). +`-3.5l-2' represents an inexact number using decimal notation, with +signed magnitude negative thirty five thousandths, and requested long +precision (which must be at least IEEE 64-bit floating point). When +reading an external representation of an inexact real, the bounds on +the resulting inexact number are chosen in accordance with the +narrow-arithmetic keyed dynamic variable. + + NOTE: in klisp, all inexact numbers are stored as IEEE 64-bit +floating point. No bounding or robustness info is kept. + + -- Applicative: number? (number? . objects) + The primitive type predicate for type number. `number?' returns + true iff all the objects in `objects' are of type number. + + -- Applicative: integer? (integer? . objects) + The primitive type predicate for number subtype integer. + `integer?' returns true iff all the objects in `objects' are of + type integer. + + -- Applicative: rational? (rational? . objects) + The primitive type predicate for number subtype rational. + `rational?' returns true iff all the objects in `objects' are of + type rational. + + -- Applicative: real? (real? . objects) + The primitive type predicate for number subtype real. `real?' + returns true iff all the objects in `objects' are of type real. + + -- Applicative: finite? (finite? . numbers) + Predicate `finite?' returns true iff all the numbers in `numbers' + are finite. + + -- Applicative: exact? (exact? . numbers) + Predicate `exact?' returns true iff all the numbers in `numbers' + are exact. + + -- Applicative: inexact? (inexact? . numbers) + Predicate `inexact?' returns true iff all the numbers in `numbers' + are inexact. + + -- Applicative: robust? (robust? . numbers) + Predicate `robust?' returns true iff all the numbers in `numbers' + are robust. + + -- Applicative: undefined? (undefined? . numbers) + Predicate `undefined?' returns true iff all the numbers in + `numbers' are undefined. + + -- Applicative: =? (=? . numbers) + Applicative `=?' is a predicate that returns true iff all its + arguments are numerically equal to each other. If any of its + arguments has no primary value, an error is signaled. + + -- Applicative: <? (<? . reals) + -- Applicative: <=? (<=? . reals) + -- Applicative: >? (>? . reals) + -- Applicative: >=? (>=? . reals) + Each of these applicatives is a predicate that returns true iff + every two consecutive elements of `reals' have primary values in + the order indicated by the name of the applicative. If any + element of `reals' has no primary value, an error is signaled. + + -- Applicative: + (+ . numbers) + Applicative `+' returns the sum of the elements of numbers. If + numbers is empty, the sum of its elements is exact zero. If a + positive infinity is added to a negative infinity, the result has + no primary value. If all the elements of a cycle are zero, the + sum of the cycle is zero. If the acyclic sum of the elements of a + cycle (i.e., the sum of an acyclic list containing just those + elements) is non-zero, the sum of the cycle is positive infinity + times the acyclic sum of the elements. If the acyclic sum of the + elements of a cycle is zero, but some of the elements of the cycle + are non-zero, the sum of the cycle has no primary value. + + -- Applicative: * (* . numbers) + Applicative `*' returns the product of the elements of numbers. + If numbers is empty, the product of its elements is exact one. If + an infinity is multiplied by zero, the result has no primary + value. If the acyclic product of the elements of a cycle is real + greater than one, the product of the cycle is positive infinity. + If all the elements of a cycle are positive one, the product of + the cycle is positive one. If the acyclic product of the elements + of a cycle is positive one, but some of the elements of the cycle + are not positive one, the product of the cycle has no primary + value. If the acyclic product of the elements of a cycle has + magnitude less than one, the product of the cycle is zero. If the + acyclic product of the elements of a cycle has magnitude greater + than or equal to one, and is not positive real, the product of the + cycle has no primary value. + + -- Applicative: - (- number . numbers) + `numbers' should be a nonempty list of numbers. + + Applicative `-' returns the sum of `number' with the negation of + the sum of `numbers'. + + -- Applicative: zero? (zero? . numbers) + Applicative `zero?' is a predicate that returns true iff every + element of `numbers' is zero. For this purpose, a real number is + zero if its primary value is zero. If any element of numbers has + no primary value an error is signaled. + + -- Applicative: div (div real1 real2) + -- Applicative: mod (mod real1 real2) + -- Applicative: div-and-mod (div-and-mod real1 real2) + For all three applicatives, if `real1' is infinite or `real2' is + zero, an error is signaled. + + Let `n' be the greatest integer such that `real2 * n <= real1'. + Applicative `div' returns `n'. Applicative `mod' returns `real1 - + (real2 * n)'. Applicative `div-and-mod' returns a freshly + allocated list of length two, whose first element is `n' and whose + second element is `real1 - (real2 * n)'. + + NOTE: I'm not really sure about this description... + + -- Applicative: div0 (div0 real1 real2) + -- Applicative: mod0 (mod0 real1 real2) + -- Applicative: div0-and-mod0 (div0-and-mod0 real1 real2) + For all three applicatives, if `real1' is infinite or `real2' is + zero, an error is signaled. + + Let `n' be the greatest integer such that `real2 * n <= real1 + + |real2/2|'. Applicative `div0' returns `n'. Applicative `mod0' + returns `real1 - (real2 * n)'. Applicative `div0-and-mod0' + returns a freshly allocated list of length two, whose first + element is `n' and whose second element is `real1 - (real2 * n)'. + + NOTE: I'm not really sure about this description... + + -- Applicative: positive? (positive? . reals) + -- Applicative: negative? (negative? . reals) + Applicative `positive?' is a predicate that returns true iff every + element of `reals' is greater than zero. Applicative `negative?' + is a predicate that returns true iff every element of `reals' is + less than zero. If any argument to either applicative has no + primary value an error is signaled. + + -- Applicative: odd? (odd? . integers) + -- Applicative: even? (even? . integers) + Applicative `odd?' is a predicate that returns true iff every + element of `integers' is odd. Applicative `even?' is a predicate + that returns true iff every element of `integers' is even. If any + argument to either applicative has no primary value an error is + signaled. + + -- Applicative: (abs real) + Applicative `abs' returns the nonnegative real number with the + same magnitude as `real'; that is, if `real' is nonnegative it + returns `real', otherwise it returns the negation of `real'. + + -- Applicative: max (max . reals) + -- Applicative: min (min . reals) + If `reals' is nil, applicative `max' returns exact negative + infinity, and applicative `min' returns exact positive infinity. + If `reals' is non-nil, applicative `max' returns the largest + number in `reals', and applicative `min' returns the smallest + number in `reals'. + + -- Applicative: lcm (lcm . impints) + -- Applicative: gcd (gcd . impints) + `impints' should be a list of improper integers, that is, real + numbers each of which is either an integer or an infinity. + + Applicative `lcm' returns the smallest positive improper integer + that is an improper0integer multiple of every element of `impints' + (that is, smallest `n >= 1' such that for every argument `nk' + there exists `n'k' with `nk * n'k = n'). If any of the arguments + is zero, the result of `lcm' has no primary value. According to + these rules, `lcm' with nil argument list returns `1', and `lcm' + with any infinite argument returns positive infinity. + + Applicative `gcd' returns the largest positive improper integer + such that every element of `impints' is an improper-integer + multiple of it (that is, largest `n >= 1' such that for every + argument `nk' there exists `n'k' with `n * n'k = nk'). `gcd' with + nil argument list returns exact positive infinity. If `gcd' is + called with one or more arguments, and at least one of the + arguments is zero, but none of the arguments is a non-zero finite + integer, its result has no primary value. According to these + rules, if `gcd' is called with at least one finite non-zero + argument, its result is the same as if all zero and infinite + arguments were deleted. + + -- Applicative: get-real-internal-bounds (get-real-internal-bounds + real) + -- Applicative: get-real-exact-bounds (get-real-exact-bounds real) + Applicative `get-real-internal-bounds' returns a freshly allocated + list of reals `(x1 x2)', where the primary value of `x1' is the + lower bound of `real', using the same internal representation as + the primary value of `real', and the primary value of `x2' is the + upper bound of `real', using the same internal representation as + the primary value of `real'. The `xk' are inexact iff real is + inexact. The `xk' are robust (i.e., tagged if the implementation + supports such), and the bounds of each `xk' are only required to + contain its primary value (i.e., the implementation is allowed to + make the bounds equal to the primary value). + + Applicative `get-real-exact-bounds' returns a freshly allocated + list of exact reals `(x1 x2)', where `x1' is not greater than the + lower bound of `real', and `x2' is not less than the upper bound + of `real'. + + -- Applicative: get-real-internal-primary (get-real-internal-primary + real) + -- Applicative: get-real-exact-primary (get-real-exact-primary real) + If `real' is exact, both applicatives return `real'. If `real' + has no primary value, both applicatives signal an error. + + If `real' is inexact with a primary value, applicative + `get-real-internal-primary' returns a real number `x0' whose + primary value is the same as, and has the same internal format as, + the primary value of `real'. `x0' is robust, and its bounds are + only required to contain its primary value. + + If `real' is inexact with a primary value, applicative + `get-real-exact-primary' returns an exact real number `x0' within + the exact bounds that would be returned for `real' by applicative + `get-real-exact-bounds'. Preferably, `x0' should be as close to + the primary value of `real' as the implementation can reasonably + arrange. If the implementation does not support any exact `real' + that reasonably approximates `real', an error may be signaled. + + -- Applicative: make-inexact (make-inexact real1 real2 real3) + Applicative `make-inexact' returns an inexact real number, as + follows. If `real2' is inexact, the result has the same primary + value as `real2'; and if `real2' has no primary value, the result + has no primary value. The result has the same robustness as + `real2'. If possible, the result uses the same internal + representation as `real2'. If `real2' is exact, the primary value + of the result is as close to `real2' as the implementation can + reasonably arrange; overflow and underflow are handled as + described in .... The lower bound of the result is no greater than + the lower bound of `real1', the primary value of `real2', and the + primary value of the result. The upper bound of the result is no + less than the upper bound of `real3', the primary value of + `real2', and the primary value of the result. + + -- Applicative: real->inexact (real->inexact real) + -- Applicative: real->exact (real->exact real) + Applicative `real->exact' behaves just as `get-real-exact-primary'. + + If `real' is inexact, applicative `real->inexact' returns `real'. + If `real' is exact, applicative `real->inexact' returns an inexact + real `x0' such that `real' would be a permissible result of + passing `x0' to `real->exact'. If the implementation does not + support any such `x0', an error may be signaled. Otherwise, `x0' + is robust, and its bounds are only required to contain its primary + value and `real'. + + -- Applicative: with-strict-arithmetic (with-strict-arithmetic boolean + combiner) + -- Applicative: get-string-arithmetic (get-strict-arithmetic?) + These applicatives are the binder and accessor of the + `strict-arithmetic' keyed dynamic variable. When this keyed + variable is true, various survivable but dubious arithmetic events + signal an error - notably, operation results with no primary value, + and over- and underflows. + + -- Applicative: / (/ number . numbers) + `numbers' should be a nonempty list of numbers. + + Applicative `/' returns `number' divided by the product of + `numbers'. If the product of `numbers' is zero, an error is + signaled. If `number' is infinite and the product of `numbers' is + infinite, an error is signaled. + + -- Applicative: numerator (numerator rational) + -- Applicative: denominator (denominator rational) + These applicatives return the numerator and denominator of + `rational', in least terms (i.e., chosen for the least positive + denominator). Note that if `rational' is inexact, and either of + its bounds is not its primary value, the denominator has upper + bound positive infinity, and the numerator must have at least one + infinite bound (two infinite bounds if the bounds of rational + allow values of both signs). + + -- Applicative: floor (floor real) + -- Applicative: ceiling (ceiling real) + -- Applicative: truncate (truncate real) + -- Applicative: round (round real) + Applicative `floor' returns the largest integer not greater than + `real'. + + Applicative `ceiling' returns the smallest integer not less than + `real'. + + Applicative `truncate' returns the integer closest to `real' whose + absolute value is not greater than that of `real'. + + Applicative `round' returns the closest integer to `real', + rounding to even when `real' is halfway between two integers. + + -- Applicative: rationalize (rationalize real1 real2) + -- Applicative: simplest-rational (simplest-rational real1 real2) + A rational number `r1' is simpler than another rational `r2' if + `r1 = p1 / q1' and `r2 = p2 / q2', both in lowest terms, and `|p1| + <= |p2|' and `|q1| <= |q2|'. Thus `3/5' is simpler than `4/7'. Not + all rationals are comparable in this ordering, as for example + `2/7' and `3/5'. However, any interval (that contains rational + numbers) contains a rational number that is simpler than every + other rational number in that interval. Note that `0 = 0/1' is + simpler than any other rational (so that one never has to choose + between `p/q' and `−p/q'). + + For applicative `simplest-rational', let `x0' be the simplest + rational mathematically not less than the primary value of `real1' + and not greater than the primary value of `real2'. If no such + `x0' exists (because the primary value of `real1' is greater, or + because the primary values of the arguments are equal and + irrational), or if either argument does not have a primary value, + an error is signaled. + + For applicative `rationalize', let `x0' be the simplest rational + mathematical number within the interval bounded by the primary + value of `real1' plus and minus the primary value of `real2'. If + no such `x0' exists (because the primary value of `real1' is + irrational and the primary value `real2' is zero), or if either + argument does not have a primary value, an error is signaled. + + If `real1' and `real2' are exact, the applicative (whichever it + is) returns exact `x0'. If one or both of `real1' and `real2' are + inexact, the applicative returns an inexact rational approximating + `x0' (as by `real->inexact'. Note that an inexact result returned + is not necessarily bounded by the primary values of the arguments; + but the result is an approximation of `x0', which is so bounded, + and the bounds of the result include `x0'. + + -- Applicative: exp (exp number) + -- Applicative: log (log number) + TODO + + -- Applicative: sin (sin number) + -- Applicative: cos (cos number) + -- Applicative: tan (tan number) + TODO + + -- Applicative: asin (asin number) + -- Applicative: acos (acos number) + -- Applicative: atan (atan number1 [number2]) + TODO + + -- Applicative: sqrt (sqrt number) + -- Applicative: expt (expt number1 number2) + TODO + + +File: klisp.info, Node: Strings, Next: Characters, Prev: Numbers, Up: Top + +14 Strings +********** + +A string is an object that represent a sequence of characters (for now, +only ASCII is supported in klisp, in the future, full UNICODE will be +supported). The external representation of strings consists of a +leading """, the characters of the string and a closing """. Some +characters should be escaped, by preceding them with a "\": in klisp +these are the double quote (""") and the backslash ("\"). In the +future more advanced escape mechanism may be added (like in r7rs-draft +scheme, for escping common ASCII control codes and arbitrary unicode +characters). A string has a length that is fixed at creation time, and +as many characters, indexed from `0' to `length-1'. + + Strings may be mutable or immutable. If an attempt is made to +mutate an immutable string, an error is signaled. Two immutable +strings are "eq?" iff they are "equal?". Two mutable strings are "eq?" +if they were created by the same constructor call. Two mutable strings +are "equal?" iff they are "string=?". For now it is undefined if a +mutable and an immutable strings that are "string=?" are "equal?" or +not. The only exception is the empty string. There is only one empty +string (all empty strings are "eq?" to each other) and it should be +considered immutable. Even if an attempt is made to return a new empty +string (like calling `(string)', the canonical immutable empty string +is returned. The string type is encapsulated. + + SOURCE NOTE: This section is still missing from the report. The +features defined here were taken mostly from r5rs scheme. It is +possible that in the future, klisp only admits immutable strings (like +lua and java), and that operations for contructing strings are moved to +a new type (like Java's StringBuilder/StringBuffer). But for now, +compatibility with r5rs was preferred/simpler. + + -- Applicative: string? (string? . objects) + The primitive type predicate for type string. `string?' returns + true iff all the objects in `objects' are of type string. + + -- Applicative: string=? (string=? . strings) + -- Applicative: string<? (string<? . strings) + -- Applicative: string<=? (string<=? . strings) + -- Applicative: string>? (string>? . strings) + -- Applicative: string>=? (string>=? . strings) + These predicates compare any number of strings by their + lexicographic order. + + -- Applicative: string-ci=? (string-ci=? . strings) + -- Applicative: string-ci<? (string-ci<? . strings) + -- Applicative: string-ci<=? (string-ci<=? . strings) + -- Applicative: string-ci>? (string-ci>? . strings) + -- Applicative: string-ci>=? (string-ci>=? . strings) + These predicates convert the strings to lowercase and then compare + them using their lexicographic order. + + -- Applicative: make-string (make-string k [char]) + Applicative `make-string' constructs and returns a new mutable + string of length `k'. If `char' is specified, then all characters + in the returned string are `char', otherwise the content of the + string is unspecified. + + -- Applicative: string (string . chars) + Applicative `string' contructs and return a new mutable string + composed of the character arguments. + + -- Applicative: string-length (string-length string) + Applicative `string-length' returns the length of `string'. + + -- Applicative: string-ref (string-ref string k) + Applicative `string-ref' returns the character of `string' at + position `k'. If `k' is out of bounds (i.e. less than `0' or + greater or equal than `(length string)') an error is signaled. + + -- Applicative: string-set! (string-set! string k char) + Applicative `string-set!' replaces the character with index `k' in + `string' with character `char'. If `k' is out of bounds, or + `string' is immutable, an error is signaled. + + -- Applicative: string-fill! (string-fill! string char) + Applicative `string-fill!' replaces all the characters in `string' + with character `char'. If `string' is an immutable string, an + error is signaled. + + -- Applicative: substring (substring string k1 k2) + Both `k1' & `k2' should be valid indexes in `string'. Also it + should be the case that `k1 <= k2'. + + Applicative `substring' constructs and returns a new immutable + string with length `k2 - k1', with the characters from `string', + starting at index `k1' (inclusive) and ending at index `k2' + (exclusive). + + -- Applicative: string-append (string-append . strings) + Applicative `string-append' constructs and returns a new mutable + string consisting of the concatenation of all its arguments. + + -- Applicative: string-copy (string-copy string) + Applicative `string-copy' constructs and returns a new mutable + string with the same length and characters as `string'. + + -- Applicative: string->immutable-string (string->immutable-string + string) + Applicative `string->immutable-string' constructs and returns a + new immutable string with the same length and characters as + `string'. + + -- Applicative: string->list (string->list string) + -- Applicative: list->string (list->string chars) + Applicatives `string->list' and `list->string' convert between + strings and list of characters. The strings returned by + `list->string' are mutable. + + +File: klisp.info, Node: Characters, Next: Ports, Prev: Strings, Up: Top + +15 Characters +************* + +A character is an object that represents an ASCII character (for now, +only ASCII is supported in klisp, in the future, full UNICODE will be +supported). The external representation of characters consists of a +leading "#\" and the character or character name. The only supported +names for now are "newline" and "space" (both from r5rs scheme). +Characters are immutable. The character type is encapsulated. + + SOURCE NOTE: This section is still missing from the report. The +features defined here were taken mostly from r5rs scheme. + + -- Applicative: char? (char? . objects) + The primitive type predicate for type character. `char?' returns + true iff all the objects in `objects' are of type character. + + -- Applicative: char=? (char=? . chars) + -- Applicative: char<? (char<? . chars) + -- Applicative: char<=? (char<=? . chars) + -- Applicative: char>? (char>? . chars) + -- Applicative: char>=? (char>=? . chars) + These predicates compare any number of characters using their + ASCII value for the comparison. + + -- Applicative: char-ci=? (char-ci=? . chars) + -- Applicative: char-ci<? (char-ci<? . chars) + -- Applicative: char-ci<=? (char-ci<=? . chars) + -- Applicative: char-ci>? (char-ci>? . chars) + -- Applicative: char-ci>=? (char-ci>=? . chars) + These predicates convert the chars to lowercase and then compare + their ASCII values. + + -- Applicative: char-alphabetic? (char-alphabetic? . chars) + -- Applicative: char-numeric? (char-numeric? . chars) + -- Applicative: char-whitespace? (char-whitespace? . chars) + These predicates return true iff all of their arguments are + respectively "alphabetic", "numeric", or "whitespace". + + -- Applicative: char-upper-case? (char-upper-case? . chars) + -- Applicative: char-lower-case? (char-lower-case? . chars) + These predicates return true iff all of their arguments are + respectively "upper case, or "lower case". + + -- Applicative: char-upcase (char-upcase char) + -- Applicative: char-downcase (char-downcase char) + These applicatives return a character `char2' so that: + (char-ci=? char char2) => #t + + If `char' is alphabetic then the following holds: + + (char-upper-case? (char-upcase char)) => #t + (char-lower-case? (char-downcase char)) => #t + + -- Applicative: char->integer (char->integer char) + -- Applicative: integer->char (integer->char k) + These applicatives convert between ASCII values (as exact integers + between 0 and 127) and characters. If an integer that is out of + range for ASCII characters is passed to `integer->char', an error + is signaled. + + +File: klisp.info, Node: Ports, Next: Alphabetical Index, Prev: Characters, Up: Top + +16 Ports +******** + +A port is an object that mediates data from an input or to a +destination. In the former case, the port is an input port, in the +latter case, an output port. The data itself can consist of either +characters or bytes. In the former case the port is a textual port and +in the latter case, a binary port. + + There are three textual ports open, binded by dynamic variables, one +for standard input, output, and error. + + Although ports are not considered immutable, none of the operations +on ports described in this section constitute mutation. Ports are +`equal?' iff `eq?'. The port type is encapsulated. + + An auxiliary data type used to signal the end of file was reached is +`eof'. The eof type consists of a single immutable value, having an +output only external representation (so that it can never be the normal +result of a call to read). The eof type is encapsulated. + + SOURCE NOTE: the eof type is not in the Kernel report, it is used in +klisp and was taken from Scheme. + + -- Applicative: port? (port? . objects) + The primitive type predicate for type port. `port?' returns true + iff all the objects in `objects' are of type port. + + -- Applicative: input-port? (input-port? . objects) + -- Applicative: output-port? (output-port? . objects) + Applicative `input-port?' is a predicate that returns true unless + one or more of its arguments is not an input port. Applicative + `output-port?' is a predicate that returns true unless one or more + of its arguments is not an output port. + + Every port must be admitted by at least one of these two + predicates. + + -- Applicative: textual-port? (textual-port? . objects) + -- Applicative: binary-port? (binary-port? . objects) + Applicative `textual-port?' is a predicate that returns true + unless one or more of its arguments is not a textual port. + Applicative `binary-port?' is a predicate that returns true unless + one or more of its arguments is not a binary port. + + Every port must be admitted by at least one of these two + predicates. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- with-input-from-file: (with-input-from-file string combiner) + -- with-output-to-file: (with-output-to-file string combiner) + -- with-error-to-file: (with-error-to-file string combiner) + These three applicatives open the file named in `string' for + textual input or output, an invoke the binder of either the + input-port, the output-port or the error-port keyed dynamic + variables respectively with the opened port & the passed + `combiner' (this means that the combiner is called in a fresh, + empty dynamic environment). When/if the binder normally returns, + the port is closed. The result of the applicatives + `with-input-from-file' and `with-output-from-file' is inert. + + SOURCE NOTE: The first two are enumerated in the Kernel report but + the text is still missing. The third applicative is from Scheme. + + -- get-current-input-port: (get-current-input-port) + -- get-current-output-port: (get-current-output-port) + -- get-current-error-port: (get-current-error-port) + These are the accessors for the input-port, output-port, and + error-port keyed dynamic variables repectively. + + SOURCE NOTE: The first two are enumerated in the Kernel report but + the text is still missing. The third applicative is from Scheme. + + -- Applicative: open-input-file (open-input-file string) + -- Applicative: open-binary-input-file (open-binary-input-file string) + `string' should be the name/path for an existing file. + + Applicative `open-input-file' creates and returns a textual input + port associated with the file represented with `string'. + Applicative `open-binary-input-file' creates and returns a binary + input port associated with the file represented with `string'. In + either case, if the file can't be opened (e.g. because it doesn't + exists, or there's a permissions problem), an error is signaled. + + SOURCE NOTE: open-input-file is enumerated in the Kernel report but + the text is still missing. open-binary-input-file is from Scheme. + + -- Applicative: open-output-file (open-output-file string) + -- Applicative: open-binary-output-file (open-binary-output-file + string) + `string' should be the name/path for an existing file. + + Applicative `open-output-file' creates and returns a textual + output port associated with the file represented with `string'. + Applicative `open-binary-output-file' creates and returns a binary + output port associated with the file represented with `string'. + In either case, if the file can't be opened (e.g. if there's a + permissions problem), an error is signaled. + + In klisp, for now, applicative `open-output-file' and + `open-binary-output-file' truncate the file if it already exists, + but that could change later (i.e. like in Scheme the behaviour + should be considered unspecified). + + SOURCE NOTE: open-output-file is enumerated in the Kernel report + but the text is still missing. open-binary-output-file is from + Scheme. + + -- close-input-file: (close-input-file input-port) + -- close-output-file: (close-output-file output-port) + These applicatives close the port argument, so that no more + input/output may be performed on them, and the resources can be + freed. If the port was already closed these applicatives have no + effect. + + The result returned by applicatives `close-input-file' and + `close-output-file' is inert. + + SOURCE NOTE: this is enumerated in the Kernel report but the text + is still missing. There's probably a name error here. These + should probably be called close-input-port & close-output-port. + + -- close-input-port: (close-input-port input-port) + -- close-output-port: (close-output-port output-port) + -- close-port: (close-port port) + These applicatives close the port argument, so that no more + input/output may be performed on them, and the resources can be + freed. If the port was already closed these applicatives have no + effect. If at some time klisp provided input/ouput ports these + could be used to selectively close only one direction of the port. + + The result returned by applicatives `close-input-port', + `close-output-port', and `close-port' is inert. + + SOURCE NOTE: this is from Scheme. The equivalent + `close-input-file' and `close-output-file' are probably name + errors and only retained here till the draft standard rectifies + them + + -- Applicative: read (read [textual-input-port]) + If the `port' optional argument is not specified, then the value + of the `input-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `read' reads & returns the next parseable object from + the given port, or the `eof' if no objects remain. If `read' + finds and unparseable object in the port, an error is signaled. + In that case, the remaining position in the port is unspecified. + + SOURCE NOTE: this is enumerated in the Kernel report but the text + is still missing. + + -- write: (write object [textual-output-port]) + If the `port' optional argument is not specified, then the value + of the `output-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `write' writes an external representation of `object' + to the specified port. This may be an output-only representation + that can't be read by applicative `read' in cases where the type + of `object' doen't have a parseable external representation (e.g. + combiners and environments). The result returned by `write' is + inert. + + SOURCE NOTE: this is enumerated in the Kernel report but the text + is still missing. + + -- Applicative: call-with-input-file (call-with-input-file string + combiner) + -- Applicative: call-with-output-file (call-with-output-file string + combiner) + These applicatives open file named in `string' for textual + input/output respectively and call their `combiner' argument in a + fresh empty environment passing it as a sole operand the opened + port. When/if the combiner normally returns a value the port is + closed and that value is returned as the result of the applicative. + + SOURCE NOTE: this is enumerated in the Kernel report but the text + is still missing. + + -- Applicative: load (load string) + Applicative `load' opens the file named `string' for textual + input; reads objects from the file until the end of the file is + reached; evaluates those objects consecutively in the created + environment. The result from applicative `load' is inert. + + SOURCE NOTE: load is enumerated in the Kernel report, but the + description is not there yet. This seems like a sane way to define + it, taking the description of `get-module' that there is in the + report. The one detail that I think is still open, is whether to + return `#inert' (as is the case with klisp currently) or rather + return the value of the last evaluation. + + -- Applicative: get-module (get-module string [environment]) + Applicative `get-module' creates a fresh standard environment; + opens the file named `string' for textual input; reads objects + from the file until the end of the file is reached; evaluates those + objects consecutively in the created environment; and, lastly, + returns the created environment. If the optional argument + `environment' is specified, the freshly created standard + environment is augmented, prior to evaluating read expressions, by + binding symbol `module-parameters' to the `environment' argument. + + -- Applicative: eof-object? (eof-object? . objects) + The primitive type predicate for type eof. `eof-object?' returns + true iff all the objects in `objects' are of type eof. + + SOURCE NOTE: This is not in the report, the idea is from Scheme. + The `eof-object?' name is also from Scheme, but this will probably + be changed to just `eof?', for consistency with the other + primitive type predicates. + + -- read-char: (read-char [textual-input-port]) + If the `port' optional argument is not specified, then the value + of the `input-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `read-char' reads and returns a character (not an + external representation of a character) from the specified port, or + an `eof' if the end of file was reached. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- peek-char: (peek-char [textual-input-port]) + If the `port' optional argument is not specified, then the value + of the `input-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `peek-char' reads and returns a character (not an + external representation of a character) from the specified port, or + an `eof' if the end of file was reached. The position of the port + remains unchanged so that new call to `peek-char' or `read-char' + on the same port return the same character. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- char-ready?: (char-ready? [textual-input-port]) + If the `port' optional argument is not specified, then the value + of the `input-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Predicate `char-ready?' checks to see if a character is available + in the specified port. If it returns true, then a `read-char' or + `peek-char' on that port is guaranteed not to block/hang. For now + in klisp this is hardcoded to `#t' because the code to do this is + non-portable. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- write-char: (write-char char [textual-output-port]) + If the `port' optional argument is not specified, then the value + of the `output-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `write-char' writes the `char' character (not an + external representation of the character) to the specified port. + The result returned by `write-char' is inert. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- newline: (newline [textal-ouput-port]) + If the `port' optional argument is not specified, then the value + of the `output-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `newline' writes a newline to the specified port. The + result returned by `newline' is inert. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- display: (display object [textual-output-port]) + If the `port' optional argument is not specified, then the value + of the `output-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `display' behaves like `write' except that strings are + not enclosed in double quotes and no character is escaped within + those strings and character objects are output as if by + `write-char' instead of `read'. The result returned by `display' + is inert. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- read-u8: (read-u8 [textual-input-port]) + If the `port' optional argument is not specified, then the value + of the `input-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `read-u8' reads and returns a byte as an exact + unsigned integer between 0 and 255 inclusive (not an external + representation of a byte) from the specified port, or an `eof' if + the end of file was reached. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- peek-u8: (peek-u8 [textual-input-port]) + If the `port' optional argument is not specified, then the value + of the `input-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `peek-u8' reads and returns a byte as an exact + unsigned integer between 0 and 255 inclusive (not an external + representation of a byte) from the specified port, or an `eof' if + the end of file was reached. The position of the port remains + unchanged so that new call to `peek-u8' or `read-u8' on the same + port return the same byte. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- u8-ready?: (u8-ready? [textual-input-port]) + If the `port' optional argument is not specified, then the value + of the `input-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Predicate `u8-ready?' checks to see if a byte is available in the + specified port. If it returns true, then a `read-u8' or `peek-u8' + on that port is guaranteed not to block/hang. For now in klisp + this is hardcoded to `#t' because the code to do this is + non-portable. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- write-u8: (write-u8 u8 [textual-output-port]) + If the `port' optional argument is not specified, then the value + of the `output-port' keyed dynamic variable is used. If the port + is closed, an error is signaled. + + Applicative `write-u8' writes the byte represented by the unsigned + integer `u8', that should be between 0 and 255 inclusive, (not an + external representation of byte) to the specified port. The + result returned by `write-u8' is inert. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. + + -- flush-output-port: (flush-output-port [output-port]) + If the `port' optional argument is not specified, then the value + of the `output-port' keyed dynamic variable is used. If the + `port' is closed or if it is not an output port, an error is + signaled. + + Applicative `flush-ouput-port' flushes any buffered data in the + output port to the underlying file or device. The result returned + by `flush-output-port' is inert. + + SOURCE NOTE: this is missing from Kernel, it is taken from r7rs + Scheme. + + -- file-exists?: (file-exists? string) + `string' should be the name/path for a file. + + Predicate `file-exists?' checks to see if a file named `string' + exists. + + SOURCE NOTE: this is missing from Kernel, it is taken from r7rs + Scheme. + + -- delete-file: (delete-file string) + `string' should be the name/path for an existing file. + + Applicative `delete-file' deletes the file named `string'. If it + doesn't exists or can't be deleted, an error is signaled. The + result returned by `delete-file' is inert. + + SOURCE NOTE: this is missing from Kernel, it is taken from r7rs + Scheme. + + -- rename-file: (rename-file string1 string2) + `string1' should be the name/path for an existing file, `string2' + should be the name/path for a non existing file. + + Applicative `rename-file' renames the file named `string1' to + `string2'. If the file doesn't exists or can't be renamed for any + reason, an error is signaled. The result returned by `rename-file' + is inert. + + SOURCE NOTE: this is missing from Kernel AND Scheme, it is taken + from C, being quite similar to `delete-file'. + + +File: klisp.info, Node: Alphabetical Index, Next: (dir), Prev: Ports, Up: Top + +Index +***** + + +* Menu: + +* $and?: Booleans. (line 28) +* $binds?: Environments. (line 108) +* $cond: Control. (line 32) +* $define!: Environments. (line 49) +* $if: Control. (line 15) +* $import!: Environments. (line 207) +* $lambda: Combiners. (line 76) +* $lazy: Promises. (line 43) +* $let: Environments. (line 89) +* $let*: Environments. (line 124) +* $let-redirect: Environments. (line 153) +* $let-safe: Environments. (line 161) +* $letrec: Environments. (line 137) +* $letrec*: Environments. (line 144) +* $or?: Booleans. (line 41) +* $provide!: Environments. (line 191) +* $remote-eval: Environments. (line 169) +* $sequence: Control. (line 23) +* $set!: Environments. (line 182) +* $vau: Combiners. (line 26) +* ( <1>: Ports. (line 54) +* ( <2>: Numbers. (line 193) +* ( <3>: Continuations. (line 143) +* (: Environments. (line 174) +* *: Numbers. (line 121) +* +: Numbers. (line 109) +* -: Numbers. (line 137) +* /: Numbers. (line 306) +* <=?: Numbers. (line 101) +* <?: Numbers. (line 100) +* =?: Numbers. (line 95) +* >=?: Numbers. (line 103) +* >?: Numbers. (line 102) +* acos: Numbers. (line 385) +* and?: Booleans. (line 20) +* append: Pairs and lists. (line 208) +* append!: Pairs and lists. (line 306) +* applicative descriptions: A Sample Applicative Description. + (line 6) +* applicative?: Combiners. (line 21) +* applicatives: Combiners. (line 6) +* apply: Combiners. (line 83) +* apply-continuation: Continuations. (line 134) +* asin: Numbers. (line 384) +* assoc: Pairs and lists. (line 252) +* assq: Pairs and lists. (line 333) +* atan: Numbers. (line 386) +* binary-port?: Ports. (line 43) +* boolean?: Booleans. (line 12) +* booleans: Booleans. (line 6) +* caaaar: Pairs and lists. (line 101) +* caaadr: Pairs and lists. (line 102) +* caaar: Pairs and lists. (line 93) +* caadar: Pairs and lists. (line 103) +* caaddr: Pairs and lists. (line 104) +* caadr: Pairs and lists. (line 94) +* caar: Pairs and lists. (line 89) +* cadaar: Pairs and lists. (line 105) +* cadadr: Pairs and lists. (line 106) +* cadar: Pairs and lists. (line 95) +* caddar: Pairs and lists. (line 107) +* cadddr: Pairs and lists. (line 108) +* caddr: Pairs and lists. (line 96) +* cadr: Pairs and lists. (line 90) +* call-with-input-file: Ports. (line 173) +* call-with-output-file: Ports. (line 175) +* call/cc: Continuations. (line 43) +* car: Pairs and lists. (line 85) +* cdaaar: Pairs and lists. (line 109) +* cdaadr: Pairs and lists. (line 110) +* cdaar: Pairs and lists. (line 97) +* cdadar: Pairs and lists. (line 111) +* cdaddr: Pairs and lists. (line 112) +* cdadr: Pairs and lists. (line 98) +* cdar: Pairs and lists. (line 91) +* cddaar: Pairs and lists. (line 113) +* cddadr: Pairs and lists. (line 114) +* cddar: Pairs and lists. (line 99) +* cdddar: Pairs and lists. (line 115) +* cddddr: Pairs and lists. (line 116) +* cdddr: Pairs and lists. (line 100) +* cddr: Pairs and lists. (line 92) +* cdr: Pairs and lists. (line 86) +* ceiling: Numbers. (line 325) +* char->integer: Characters. (line 58) +* char-alphabetic?: Characters. (line 37) +* char-ci<=?: Characters. (line 31) +* char-ci<?: Characters. (line 30) +* char-ci=?: Characters. (line 29) +* char-ci>=?: Characters. (line 33) +* char-ci>?: Characters. (line 32) +* char-downcase: Characters. (line 49) +* char-lower-case?: Characters. (line 44) +* char-numeric?: Characters. (line 38) +* char-upcase: Characters. (line 48) +* char-upper-case?: Characters. (line 43) +* char-whitespace?: Characters. (line 39) +* char<=?: Characters. (line 23) +* char<?: Characters. (line 22) +* char=?: Characters. (line 21) +* char>=?: Characters. (line 25) +* char>?: Characters. (line 24) +* char?: Characters. (line 17) +* characters: Characters. (line 6) +* combiner?: Combiners. (line 120) +* combiners: Combiners. (line 6) +* cons: Pairs and lists. (line 35) +* continuation->applicative: Continuations. (line 95) +* continuation?: Continuations. (line 38) +* continuations: Continuations. (line 6) +* control: Control. (line 6) +* copy-es: Pairs and lists. (line 321) +* copy-es-immutable!: Pairs and lists. (line 49) +* cos: Numbers. (line 380) +* countable-list?: Pairs and lists. (line 265) +* denominator: Numbers. (line 315) +* description format: Format of Descriptions. + (line 6) +* div: Numbers. (line 149) +* div-and-mod: Numbers. (line 151) +* div0: Numbers. (line 163) +* div0-and-mod0: Numbers. (line 165) +* documentation notation: Evaluation Notation. (line 6) +* empty list: Pairs and lists. (line 6) +* encapsulations: Encapsulations. (line 6) +* encycle!: Pairs and lists. (line 158) +* environment?: Environments. (line 23) +* environments: Environments. (line 6) +* eof-object?: Ports. (line 208) +* eq?: Equivalence. (line 12) +* equal?: Equivalence. (line 16) +* equivalence: Equivalence. (line 6) +* error message notation: Error Messages. (line 6) +* error-continuation: Continuations. (line 110) +* eval: Environments. (line 32) +* evaluation notation: Evaluation Notation. (line 6) +* even?: Numbers. (line 186) +* exact?: Numbers. (line 79) +* exit: Continuations. (line 162) +* exp: Numbers. (line 375) +* expt: Numbers. (line 390) +* extend-continuation: Continuations. (line 50) +* filter: Pairs and lists. (line 239) +* finite-list?: Pairs and lists. (line 261) +* finite?: Numbers. (line 75) +* floor: Numbers. (line 324) +* fonts: Some Terms. (line 13) +* foo: A Sample Applicative Description. + (line 15) +* for-each: Control. (line 42) +* force: Promises. (line 35) +* gcd: Numbers. (line 207) +* get-current-environment: Environments. (line 114) +* get-list-metrics: Pairs and lists. (line 123) +* get-module: Ports. (line 198) +* get-real-exact-bounds: Numbers. (line 233) +* get-real-exact-primary: Numbers. (line 252) +* get-real-internal-bounds: Numbers. (line 232) +* get-real-internal-primary: Numbers. (line 251) +* get-string-arithmetic: Numbers. (line 299) +* guard-continuation: Continuations. (line 63) +* guard-dynamic-extent: Continuations. (line 156) +* ignore: Environments. (line 6) +* ignore?: Environments. (line 28) +* inert: Control. (line 6) +* inert?: Control. (line 11) +* inexact?: Numbers. (line 83) +* input-port?: Ports. (line 32) +* integer->char: Characters. (line 59) +* integer?: Numbers. (line 61) +* Kernel history: Kernel History. (line 6) +* keyed dynamic variables: Keyed Variables. (line 15) +* keyed static variables: Keyed Variables. (line 40) +* keyed variables: Keyed Variables. (line 6) +* lcm: Numbers. (line 206) +* length: Pairs and lists. (line 191) +* list: Pairs and lists. (line 72) +* list*: Pairs and lists. (line 78) +* list->string: Strings. (line 109) +* list-neighbors: Pairs and lists. (line 228) +* list-ref: Pairs and lists. (line 198) +* list-tail: Pairs and lists. (line 147) +* lists: Pairs and lists. (line 6) +* load: Ports. (line 185) +* log: Numbers. (line 376) +* make-encapsulation-type: Encapsulations. (line 12) +* make-environment: Environments. (line 36) +* make-inexact: Numbers. (line 270) +* make-kernel-standard-environment: Environments. (line 119) +* make-keyed-dynamic-variable: Keyed Variables. (line 21) +* make-keyed-static-variable: Keyed Variables. (line 44) +* make-string: Strings. (line 57) +* map <1>: Combiners. (line 96) +* map: Pairs and lists. (line 169) +* max: Numbers. (line 198) +* member?: Pairs and lists. (line 257) +* memoize: Promises. (line 74) +* memq?: Pairs and lists. (line 338) +* min: Numbers. (line 199) +* mod: Numbers. (line 150) +* mod0: Numbers. (line 164) +* negative?: Numbers. (line 178) +* nil: Pairs and lists. (line 6) +* not?: Booleans. (line 16) +* null?: Pairs and lists. (line 31) +* number?: Numbers. (line 57) +* numbers: Numbers. (line 6) +* numerator: Numbers. (line 314) +* object descriptions: A Sample Applicative Description. + (line 6) +* odd?: Numbers. (line 185) +* open-binary-input-file: Ports. (line 79) +* open-binary-output-file: Ports. (line 94) +* open-input-file: Ports. (line 78) +* open-output-file: Ports. (line 92) +* operative descriptions: A Sample Applicative Description. + (line 6) +* operative?: Combiners. (line 16) +* operatives: Combiners. (line 6) +* or?: Booleans. (line 24) +* output-port?: Ports. (line 33) +* pair?: Pairs and lists. (line 27) +* pairs: Pairs and lists. (line 6) +* port?: Ports. (line 28) +* ports: Ports. (line 6) +* positive?: Numbers. (line 177) +* printing notation: Printing Notation. (line 6) +* promise?: Promises. (line 31) +* promises: Promises. (line 6) +* rational?: Numbers. (line 66) +* rationalize: Numbers. (line 340) +* read: Ports. (line 144) +* real->exact: Numbers. (line 286) +* real->inexact: Numbers. (line 285) +* real?: Numbers. (line 71) +* reduce: Pairs and lists. (line 270) +* robust?: Numbers. (line 87) +* root-continuation: Continuations. (line 104) +* round: Numbers. (line 327) +* set-car!: Pairs and lists. (line 41) +* set-cdr!: Pairs and lists. (line 42) +* simplest-rational: Numbers. (line 341) +* sin: Numbers. (line 379) +* sqrt: Numbers. (line 389) +* string: Strings. (line 63) +* string->immutable-string: Strings. (line 103) +* string->list: Strings. (line 108) +* string->symbol: Symbols. (line 20) +* string-append: Strings. (line 94) +* string-ci<=?: Strings. (line 51) +* string-ci<?: Strings. (line 50) +* string-ci=?: Strings. (line 49) +* string-ci>=?: Strings. (line 53) +* string-ci>?: Strings. (line 52) +* string-copy: Strings. (line 98) +* string-fill!: Strings. (line 80) +* string-length: Strings. (line 67) +* string-ref: Strings. (line 70) +* string-set!: Strings. (line 75) +* string<=?: Strings. (line 43) +* string<?: Strings. (line 42) +* string=?: Strings. (line 41) +* string>=?: Strings. (line 45) +* string>?: Strings. (line 44) +* string?: Strings. (line 37) +* strings: Strings. (line 6) +* substring: Strings. (line 85) +* symbol->string: Symbols. (line 16) +* symbol?: Symbols. (line 12) +* symbols: Symbols. (line 6) +* tan: Numbers. (line 381) +* textual-port?: Ports. (line 42) +* truncate: Numbers. (line 326) +* undefined?: Numbers. (line 91) +* unwrap: Combiners. (line 72) +* with-strict-arithmetic: Numbers. (line 298) +* wrap: Combiners. (line 68) +* zero?: Numbers. (line 143) + + + +Tag Table: +Node: Top703 +Node: License2601 +Node: Introduction4283 +Node: Caveats7213 +Node: Kernel History7999 +Node: Conventions9444 +Node: Some Terms10115 +Node: Evaluation Notation10786 +Node: Printing Notation11807 +Node: Error Messages12283 +Node: Format of Descriptions12931 +Node: A Sample Applicative Description13495 +Node: Acknowledgements15258 +Node: Booleans15644 +Node: Equivalence18186 +Node: Symbols18979 +Node: Control20345 +Node: Pairs and lists22662 +Node: Environments39685 +Node: Combiners49892 +Node: Continuations55928 +Node: Encapsulations64461 +Node: Promises65914 +Node: Keyed Variables69837 +Node: Numbers72608 +Node: Strings92107 +Node: Characters97454 +Node: Ports100164 +Node: Alphabetical Index117768 + +End Tag Table diff --git a/manual/src/Makefile b/doc/src/Makefile diff --git a/manual/src/booleans.texi b/doc/src/booleans.texi diff --git a/manual/src/characters.texi b/doc/src/characters.texi diff --git a/manual/src/combiners.texi b/doc/src/combiners.texi diff --git a/doc/src/continuations.texi b/doc/src/continuations.texi @@ -0,0 +1,204 @@ +@c -*-texinfo-*- +@setfilename ../src/continuations + +@node Continuations, Encapsulations, Combiners, Top +@comment node-name, next, previous, up + +@chapter Continuations +@cindex continuations + + A continuation is a plan for all future computation, parameterized +by a value to be provided, and contingent on the states of all mutable +data structures (which notably may include environments). When the +Kernel evaluator is invoked, the invoker provides a continuation to +which the result of the evaluation will normally be returned. + + For example, when @code{$if} evaluates its test operand, the +continuation provided for the result expects to be given a boolean +value; and, depending on which boolean it gets, it will evaluate +either the consequent or the alternative operand as a tail context — +that is, the continuation provided for the result of evaluating the +selected operand is the same continuation that was provided for the +result of the call to @code{$if}. + + A Kernel program may sometimes capture a continuation; that is, +acquire a reference to it as a first-class object. The basic means of +continuation capture is applicative @code{call/cc}. Given a +first-class continuation @code{c}, a combiner can be constructed that +will abnormally pass its operand tree to @code{c} (as opposed to the +@c TODO add xref to abnormal pass +normal return of values to continuations). In the simplest case, the +abnormally passed value arrives at @code{c} as if it had been normally +returned to @code{c}. In general, continuations bypassed by the +abnormal pass may have entry/exit guards attached to them, and these +guards can intercept the abnormal pass before it reaches @code{c}. +Each entry/exit guard consists of a selector continuation, which +designates which abnormal passes the guard will intercept, and an +interceptor applicative that performs the interception when selected. +@c TODO add xref to guard-continuation, continuation->applicative +@c and abnormal pass + + Continuations are immutable, and are @code{equal?} iff @code{eq?}. +The continuation type is encapsulated. + +@c TODO add dynamic extent & guard selection/interception to the intro +@deffn Applicative continuation? (continuation? . objects) + The primitive type predicate for type continuation. +@code{continuation?} returns true iff all the objects in +@code{objects} are of type continuation. +@end deffn + +@deffn Applicative call/cc (call/cc combiner) + Calls @code{combiner} in the dynamic environment as a tail context, +passing as sole operand to it the continuation to which @code{call/cc} +would normally return its result. (That is, constructs such a +combination and evaluates it in the dynamic environment.) +@c TODO add xref Cf. operative $let/cc , §7.3.2. +@end deffn + +@deffn Applicative extend-continuation (extend-continuation continuation applicative [environment]) + The @code{extend-continuation} applicative constructs and returns a +new child of @code{continuation} that, when it normally receives a +value v, calls the underlying combiner of @code{applicative} with +dynamic environment @code{environment} (or an empty environment if +none was specified) and operand tree @code{v}, the result of the call +normally to be returned to @code{continuation}. + + The following equivalnece defines the short version: +@example +(extend-continuation c a) @equiv{} + (extend-continuation c a (make-environment)) +@end example +@end deffn + +@deffn Applicative guard-continuation (guard-continuation entry-guards continuation exit-guards) + @code{entry-guards} and @code{exit-guards} should each be a list of +clauses; each clause should be a list of length two, whose first +element is a continuation, and whose second element is an applicative +whose underlying combiner is operative. + + Applicative @code{guard-continuation} constructs two continuations: +a child of continuation, called the @code{outer continuation}; and a +child of the @code{outer continuation}, called the @code{inner +continuation}. The @code{inner continuation} is returned as the +result of the call to @code{guard-continuation}. + + When the @code{inner continuation} normally receives a value, it +passes the value normally to the @code{outer continuation}; and when +the @code{outer continuation} normally receives a value, it passes the +value normally to @code{continuation}. Thus, in the absence of +abnormal passing, the inner and outer continuations each have the same +behavior as @code{continuation}. + + The two elements of each guard clause are called, respectively, the +@code{selector} and the @code{interceptor}. The @code{selector} +continuation is used in deciding whether to intercept a given abnormal +pass, and the @code{interceptor} applicative is called to perform +@c TODO add xref to selection and interception +customized action when interception occurs. + +@c TODO add xref to evaluation structure +At the beginning of the call to @code{guard-continuation}, internal +copies are made of the evaluation structures of @code{entry-guards} +and @code{exit-guards}, so that the selectors and interceptors +contained in the arguments at that time remain fixed thereafter, +independent of any subsequent mutations to the arguments. +@end deffn + +@deffn Applicative continuation->applicative (continuation->applicative continuation) + Returns an applicative whose underlying operative abnormally passes +its operand tree to @code{continuation}, thus: A series of +interceptors are selected to handle the abnormal pass, and a +continuation is derived that will normally perform all the +interceptions in sequence and pass some value to the destination of +the originally abnormal pass. The operand tree is then normally +passed to the derived continuation. +@c TODO add xref to selection and interception +@end deffn + +@defvar root-continuation + This continuation is the ancestor of all other continuations. When +it normally receives a value, it terminates the Kernel session. (For +example, if the system is running a read-eval-print loop, it exits the +loop.) +@c TODO add xref Cf. applicative exit, §7.3.4. +@end defvar + +@defvar error-continuation + The dynamic extent of this continuation is mutually disjoint from +the dynamic extent in which Kernel computation usually occurs (such as +the dynamic extent in which the Kernel system would run a +read-eval-print loop). + + When this continuation normally receives a value, it provides a +diagnostic message to the user of the Kernel system, on the assumption +that the received value is an attempt to describe some error that +aborted a computation; and then resumes operation of the Kernel system +at some point that is outside of all user-defined computation. (For +example, if the system is running a read-eval-print loop, operation +may resume by continuing from the top of the loop.) + + The diagnostic message is not made available to any Kernel +computation, and is therefore permitted to contain information that +violates abstractions within the system. + +@c TODO add details about klisp error messages + When an error is signaled during a Kernel computation, the signaling +action consists of an abnormal pass to some continuation in the +dynamic extent of @code{error-continuation}. +@end defvar + +@deffn Applicative apply-continuation (apply-continuation continuation object) + Applicative @code{apply-continuation} converts its first argument to +an applicative as if by @code{continuation->applicative}, and then +applies it as usual. + + That is: +@example +(apply-continuation continuation object) @equiv{} + (apply (continuation->applicative continuation) object) +@end example +@end deffn + +@deffn Operative ($let/cc <symbol> . <objects>) + A child environment @code{e} of the dynamic environment is created, +containing a binding of @code{<symbol>} to the continuation to which +the result of the call to @code{$let/cc} should normally return; then, +the subexpressions of @code{<objects>} are evaluated in @code{e} from +left to right, with the last (if any) evaluated as a tail context, or +if @code{<objects>} is empty the result is inert. + + That is: +@example +($let/cc symbol . objects) @equiv{} + (call/cc ($lambda (symbol) . objects)) +@end example +@end deffn + +@deffn Applicative guard-dynamic-extent (guard-dynamic-extent entry-guards combiner exit-guards) + This applicative extends the current continuation with the specified +guards, and calls @code{combiner} in the dynamic extent of the new +continuation, with no operands and the dynamic environment of the call +to @code{guard-dynamic-extent}. +@end deffn + +@deffn Applicative exit (exit [object]) +@c TODO add xref + Applicative @code{exit} initiates an abnormal transfer of +@code{object} (or @code{#inert} if @code{object} was not specified), +to @code{root-continuation}. + That is: +@example +(exit) @equiv{} (apply-continuation root-continuation #inert) +(exit obj) @equiv{} (apply-continuation root-continuation obj) +@end example + + SOURCE NOTE: This applicative doesn't have the optional argument in +the report. It was added to klisp to allow a simple way to terminate +the interpreter passing a value that is then tried to convert to an +exit status. +@end deffn + + + + diff --git a/manual/src/control.texi b/doc/src/control.texi diff --git a/manual/src/encapsulations.texi b/doc/src/encapsulations.texi diff --git a/manual/src/environments.texi b/doc/src/environments.texi diff --git a/manual/src/equivalence.texi b/doc/src/equivalence.texi diff --git a/manual/src/index.texi b/doc/src/index.texi diff --git a/manual/src/intro.texi b/doc/src/intro.texi diff --git a/manual/src/keyed_vars.texi b/doc/src/keyed_vars.texi diff --git a/manual/src/klisp.texi b/doc/src/klisp.texi diff --git a/manual/src/numbers.texi b/doc/src/numbers.texi diff --git a/manual/src/pairs_lists.texi b/doc/src/pairs_lists.texi diff --git a/manual/src/ports.texi b/doc/src/ports.texi diff --git a/manual/src/promises.texi b/doc/src/promises.texi diff --git a/manual/src/strings.texi b/doc/src/strings.texi diff --git a/manual/src/symbols.texi b/doc/src/symbols.texi diff --git a/manual/html/Continuations.html b/manual/html/Continuations.html @@ -1,233 +0,0 @@ -<html lang="en"> -<head> -<title>Continuations - klisp Reference Manual</title> -<meta http-equiv="Content-Type" content="text/html"> -<meta name="description" content="klisp Reference Manual"> -<meta name="generator" content="makeinfo 4.13"> -<link title="Top" rel="start" href="index.html#Top"> -<link rel="prev" href="Combiners.html#Combiners" title="Combiners"> -<link rel="next" href="Encapsulations.html#Encapsulations" title="Encapsulations"> -<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage"> -<meta http-equiv="Content-Style-Type" content="text/css"> -<style type="text/css"><!-- - pre.display { font-family:inherit } - pre.format { font-family:inherit } - pre.smalldisplay { font-family:inherit; font-size:smaller } - pre.smallformat { font-family:inherit; font-size:smaller } - pre.smallexample { font-size:smaller } - pre.smalllisp { font-size:smaller } - span.sc { font-variant:small-caps } - span.roman { font-family:serif; font-weight:normal; } - span.sansserif { font-family:sans-serif; font-weight:normal; } ---></style> -</head> -<body> -<div class="node"> -<a name="Continuations"></a> -<p> -Next:&nbsp;<a rel="next" accesskey="n" href="Encapsulations.html#Encapsulations">Encapsulations</a>, -Previous:&nbsp;<a rel="previous" accesskey="p" href="Combiners.html#Combiners">Combiners</a>, -Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> -<hr> -</div> - -<!-- node-name, next, previous, up --> -<h2 class="chapter">9 Continuations</h2> - -<p><a name="index-continuations-126"></a> - A continuation is a plan for all future computation, parameterized -by a value to be provided, and contingent on the states of all mutable -data structures (which notably may include environments). When the -Kernel evaluator is invoked, the invoker provides a continuation to -which the result of the evaluation will normally be returned. - - <p>For example, when <code>$if</code> evaluates its test operand, the -continuation provided for the result expects to be given a boolean -value; and, depending on which boolean it gets, it will evaluate -either the consequent or the alternative operand as a tail context — -that is, the continuation provided for the result of evaluating the -selected operand is the same continuation that was provided for the -result of the call to <code>$if</code>. - - <p>A Kernel program may sometimes capture a continuation; that is, -acquire a reference to it as a first-class object. The basic means of -continuation capture is applicative <code>call/cc</code>. Given a -first-class continuation <code>c</code>, a combiner can be constructed that -will abnormally pass its operand tree to <code>c</code> (as opposed to the -<!-- TODO add xref to abnormal pass --> -normal return of values to continuations). In the simplest case, the -abnormally passed value arrives at <code>c</code> as if it had been normally -returned to <code>c</code>. In general, continuations bypassed by the -abnormal pass may have entry/exit guards attached to them, and these -guards can intercept the abnormal pass before it reaches <code>c</code>. -Each entry/exit guard consists of a selector continuation, which -designates which abnormal passes the guard will intercept, and an -interceptor applicative that performs the interception when selected. -<!-- TODO add xref to guard-continuation, continuation->applicative --> -<!-- and abnormal pass --> - - <p>Continuations are immutable, and are <code>equal?</code> iff <code>eq?</code>. -The continuation type is encapsulated. - -<!-- TODO add dynamic extent & guard selection/interception to the intro --> -<div class="defun"> -&mdash; Applicative: <b>continuation?</b> (<var>continuation? . objects</var>)<var><a name="index-continuation_003f-127"></a></var><br> -<blockquote><p> The primitive type predicate for type continuation. -<code>continuation?</code> returns true iff all the objects in -<code>objects</code> are of type continuation. -</p></blockquote></div> - -<div class="defun"> -&mdash; Applicative: <b>call/cc</b> (<var>call/cc combiner</var>)<var><a name="index-call_002fcc-128"></a></var><br> -<blockquote><p> Calls <code>combiner</code> in the dynamic environment as a tail context, -passing as sole operand to it the continuation to which <code>call/cc</code> -would normally return its result. (That is, constructs such a -combination and evaluates it in the dynamic environment.) -<!-- TODO add xref Cf. operative $let/cc , §7.3.2. --> -</p></blockquote></div> - -<div class="defun"> -&mdash; Applicative: <b>extend-continuation</b> (<var>extend-continuation continuation applicative </var>[<var>environment</var>])<var><a name="index-extend_002dcontinuation-129"></a></var><br> -<blockquote><p> The <code>extend-continuation</code> applicative constructs and returns a -new child of <code>continuation</code> that, when it normally receives a -value v, calls the underlying combiner of <code>applicative</code> with -dynamic environment <code>environment</code> (or an empty environment if -none was specified) and operand tree <code>v</code>, the result of the call -normally to be returned to <code>continuation</code>. - - <p>The following equivalnece defines the short version: - <pre class="example"> (extend-continuation c a) == - (extend-continuation c a (make-environment)) -</pre> - </blockquote></div> - -<div class="defun"> -&mdash; Applicative: <b>guard-continuation</b> (<var>guard-continuation entry-guards continuation exit-guards</var>)<var><a name="index-guard_002dcontinuation-130"></a></var><br> -<blockquote><p> <code>entry-guards</code> and <code>exit-guards</code> should each be a list of -clauses; each clause should be a list of length two, whose first -element is a continuation, and whose second element is an applicative -whose underlying combiner is operative. - - <p>Applicative <code>guard-continuation</code> constructs two continuations: -a child of continuation, called the <code>outer continuation</code>; and a -child of the <code>outer continuation</code>, called the <code>inner -continuation</code>. The <code>inner continuation</code> is returned as the -result of the call to <code>guard-continuation</code>. - - <p>When the <code>inner continuation</code> normally receives a value, it -passes the value normally to the <code>outer continuation</code>; and when -the <code>outer continuation</code> normally receives a value, it passes the -value normally to <code>continuation</code>. Thus, in the absence of -abnormal passing, the inner and outer continuations each have the same -behavior as <code>continuation</code>. - - <p>The two elements of each guard clause are called, respectively, the -<code>selector</code> and the <code>interceptor</code>. The <code>selector</code> -continuation is used in deciding whether to intercept a given abnormal -pass, and the <code>interceptor</code> applicative is called to perform -<!-- TODO add xref to selection and interception --> -customized action when interception occurs. - - <!-- TODO add xref to evaluation structure --> - <p>At the beginning of the call to <code>guard-continuation</code>, internal -copies are made of the evaluation structures of <code>entry-guards</code> -and <code>exit-guards</code>, so that the selectors and interceptors -contained in the arguments at that time remain fixed thereafter, -independent of any subsequent mutations to the arguments. -</p></blockquote></div> - -<div class="defun"> -&mdash; Applicative: <b>continuation-&gt;applicative</b> (<var>continuation-&gt;applicative continuation</var>)<var><a name="index-continuation_002d_003eapplicative-131"></a></var><br> -<blockquote><p> Returns an applicative whose underlying operative abnormally passes -its operand tree to <code>continuation</code>, thus: A series of -interceptors are selected to handle the abnormal pass, and a -continuation is derived that will normally perform all the -interceptions in sequence and pass some value to the destination of -the originally abnormal pass. The operand tree is then normally -passed to the derived continuation. -<!-- TODO add xref to selection and interception --> -</p></blockquote></div> - -<div class="defun"> -&mdash; Variable: <b>root-continuation</b><var><a name="index-root_002dcontinuation-132"></a></var><br> -<blockquote><p> This continuation is the ancestor of all other continuations. When -it normally receives a value, it terminates the Kernel session. (For -example, if the system is running a read-eval-print loop, it exits the -loop.) -<!-- TODO add xref Cf. applicative exit, §7.3.4. --> -</p></blockquote></div> - -<div class="defun"> -&mdash; Variable: <b>error-continuation</b><var><a name="index-error_002dcontinuation-133"></a></var><br> -<blockquote><p> The dynamic extent of this continuation is mutually disjoint from -the dynamic extent in which Kernel computation usually occurs (such as -the dynamic extent in which the Kernel system would run a -read-eval-print loop). - - <p>When this continuation normally receives a value, it provides a -diagnostic message to the user of the Kernel system, on the assumption -that the received value is an attempt to describe some error that -aborted a computation; and then resumes operation of the Kernel system -at some point that is outside of all user-defined computation. (For -example, if the system is running a read-eval-print loop, operation -may resume by continuing from the top of the loop.) - - <p>The diagnostic message is not made available to any Kernel -computation, and is therefore permitted to contain information that -violates abstractions within the system. - - <!-- TODO add details about klisp error messages --> - <p>When an error is signaled during a Kernel computation, the signaling -action consists of an abnormal pass to some continuation in the -dynamic extent of <code>error-continuation</code>. -</p></blockquote></div> - -<div class="defun"> -&mdash; Applicative: <b>apply-continuation</b> (<var>apply-continuation continuation object</var>)<var><a name="index-apply_002dcontinuation-134"></a></var><br> -<blockquote><p> Applicative <code>apply-continuation</code> converts its first argument to -an applicative as if by <code>continuation-&gt;applicative</code>, and then -applies it as usual. - - <p>That is: - <pre class="example"> (apply-continuation continuation object) == - (apply (continuation-&gt;applicative continuation) object) -</pre> - </blockquote></div> - -<div class="defun"> -&mdash; Operative: <b>(</b><var>$let/cc &lt;symbol&gt; . &lt;objects&gt;</var>)<var><a name="index-g_t_0028-135"></a></var><br> -<blockquote><p> A child environment <code>e</code> of the dynamic environment is created, -containing a binding of <code>&lt;symbol&gt;</code> to the continuation to which -the result of the call to <code>$let/cc</code> should normally return; then, -the subexpressions of <code>&lt;objects&gt;</code> are evaluated in <code>e</code> from -left to right, with the last (if any) evaluated as a tail context, or -if <code>&lt;objects&gt;</code> is empty the result is inert. - - <p>That is: - <pre class="example"> ($let/cc symbol . objects) == - (call/cc ($lambda (symbol) . objects)) -</pre> - </blockquote></div> - -<div class="defun"> -&mdash; Applicative: <b>guard-dynamic-extent</b> (<var>guard-dynamic-extent entry-guards combiner exit-guards</var>)<var><a name="index-guard_002ddynamic_002dextent-136"></a></var><br> -<blockquote><p> This applicative extends the current continuation with the specified -guards, and calls <code>combiner</code> in the dynamic extent of the new -continuation, with no operands and the dynamic environment of the call -to <code>guard-dynamic-extent</code>. -</p></blockquote></div> - -<div class="defun"> -&mdash; Applicative: <b>exit</b> (<var>exit</var>)<var><a name="index-exit-137"></a></var><br> -<blockquote><!-- TODO add xref --> - <p>Applicative <code>exit</code> initiates an abnormal transfer of -<code>#inert</code> to <code>root-continuation</code>. - - <p>That is: - <pre class="example"> (exit ) == (apply-continuation root-continuation #inert) -</pre> - </blockquote></div> - -<!-- *-texinfo-*- --> - </body></html> - diff --git a/manual/klisp.info b/manual/klisp.info @@ -1,2835 +0,0 @@ -This is ../klisp.info, produced by makeinfo version 4.13 from -klisp.texi. - -This file documents klisp. - - This is edition 0.2 of the klisp Reference Manual, for klisp version -0.2. - - Copyright (C) 2011 Andres Navarro - - Permission is granted to copy and distribute this manual, in whole or -in part, without fee. Please note that most text of this manual is -derived from `The Revised(-1) Report on the Kernel Programming -Language' by John N. Shutt. There's a clause in that reports, under -the header "Permission to copy this report", that reads: - - This report is intended to belong to the programming community, - and so permission is granted to copy it in whole or in part - without fee. - - -File: klisp.info, Node: Top, Next: License, Prev: (dir), Up: (dir) - - This Info file contains edition 0.2 of the klisp Reference Manual, -corresponding to klisp version 0.2. - - Copyright (C) 2011 Andres Navarro - - Permission is granted to copy and distribute this manual, in whole or -in part, without fee. Please note that most text of this manual is -derived from `The Revised(-1) Report on the Kernel Programming -Language' by John N. Shutt. There's a clause in that reports, under -the header "Permission to copy this report", that reads: - - This report is intended to belong to the programming community, - and so permission is granted to copy it in whole or in part - without fee. - -* Menu: - -* License:: Conditions for copying and changing klisp. -* Introduction:: Introduction and conventions used. -* Booleans:: Booleans module features. -* Equivalence:: Equivalence (under & up to) mutation modules features. -* Symbols:: Symbols module features. -* Control:: Control module features. -* Pairs and lists:: Pairs and lists and Pair mutation modules features. -* Environments:: Environments and Environment mutation modules features. -* Combiners:: Combiners module features. -* Continuations:: Continuations module features. -* Encapsulations:: Encapsulations module features. -* Promises:: Promises module features. -* Keyed Variables:: Keyed (dynamic & static) variables module features. -* Numbers:: Numbers module features. -* Strings:: Strings module features. -* Characters:: Characters module features. -* Ports:: Ports module features. -* Alphabetical Index:: Index including concepts, functions, variables, - and other terms. - - -File: klisp.info, Node: License, Next: Introduction, Prev: Top, Up: Top - - klisp is licensed under the terms of the MIT license reproduced -below. This means that klisp is free software and can be used for both -academic and commercial purposes at absolutely no cost. The two -projects whose code klisp uses, Lua & IMath, are also distributed under -the MIT license. - - * klisp Parts: Copyright (C) 2011 Andres Navarro, Oto Havle. - - * Lua Parts: Copyright (C) 1994-2010 Lua.org, PUC-Rio. - - * IMath Parts: Copyright (C) 2002-2007 Michael J. Fromberger. - - * srfi-78: Copyright (C) 2005-2006 Sebastian Egner. - -MIT/X11 License -*************** - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - - The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -File: klisp.info, Node: Introduction, Next: Booleans, Prev: License, Up: Top - -1 Introduction -************** - -klisp is an open source interpreter for the Kernel Programming -Language. It aims at being comprehensive and robust as specified in -the `Revised(-1) Report on the Kernel Programming Language', but that -probably won't happen for some time. It is written in C99 under the -MIT license. It draws heavily from the Lua interpreter source code & -file structure. It uses the IMath library for arbitrary sized integers -and rationals. - - The Kernel programming language is a statically scoped and properly -tail-recursive dialect of Lisp, descended from Scheme. It is designed -to be simpler and more general than Scheme, with an exceptionally -clear, simple, and versatile semantics, only one way to form compound -expressions, and no inessential restrictions on the power of that one -compound form. Imperative, functional, and message-passing programming -styles (to name a few) may be conveniently expressed in Kernel. - - An important property of Kernel is that all manipulable entities in -Kernel are first-class objects. In particular, Kernel has no -second-class combiners; instead, the roles of special forms and macros -are subsumed by operatives, which are first-class, statically scoped -combiners that act directly on their unevaluated operands. Kernel also -has a second type of combiners, applicatives, which act on their evalu- -ated arguments. Applicatives are roughly equivalent to Scheme -procedures. However, an applicative is nothing more than a wrapper to -induce operand evaluation, around an underlying operative (or, in -principle, around another applicative, though that isn’t usually done); -applicatives themselves are mere facilitators to computation. - - You can read more about Kernel at -`http://web.cs.wpi.edu/~jshutt/kernel.html'. - - klisp is freely available for both academic and commercial purposes. -See LICENSE for details. it can be downloaded at -`https://bitbucket.org/AndresNavarro/klisp' - - klisp is developed by Andres Navarro, a Computer Science -undergraduate at Buenos Aires University (UBA). You can reach him at -<canavarro82@gmail.com>. Significant contributions are being done by -Oto Havle, his fork is at `https://bitbucket.org/havleoto/klisp'. - - This manual describes klisp version 0.2, presuming some familiarity -with the Lisp family of languages in general, and with the Kernel -Programming Language in particular. There are frequent references to -the Kernel Programming Language Report. Unlike in the report, no -rationale is provided for any feature, only a description of the -implemented functionality. - - This is edition 0.2. - -* Menu: - -* Caveats:: Flaws and a request for help. -* Kernel History:: Kernel is descended from Scheme. -* Conventions:: How the manual is formatted. -* Acknowledgements:: Contributions to this manual. - - -File: klisp.info, Node: Caveats, Next: Kernel History, Prev: Introduction, Up: Introduction - -1.1 Caveats -=========== - -This is the first draft of this manual. It will be incomplete for some -time. It will also evolve, together with klisp and the Kernel -Programming Language, both of which, right now, are in a quite fluid -state. - - The main reference on Kernel is the preliminary report: `Revised(-1) -Report on the Kernel Programming Language'. Some sections of the -report are still incomplete, so both klisp and this manual will use -specifications from other languages in these sections, trying to follow -the Kernel spirit. These instances will be documented throughout the -manual. - - Please mail comments and corrections to <canavarro82@gmail.com>. - - - -Andres Navarro - - -File: klisp.info, Node: Kernel History, Next: Conventions, Prev: Caveats, Up: Introduction - -1.2 Kernel History -================== - -The Kernel Programming Language is a work in progress. It is being -developed by John N. Shutt, Ph.D, who created it while studying at the -Worcester Polytechnic Institute (I think about 2002, or so... ASK). It -is descended from scheme, with the idea that all objects should be -first class values. In particular, Kernel replaces macros with -operatives (kinda like statically scoped fexprs and fsubrs) and has -first class environments. Kernel also has the notion of encapsulated -objects which limits the ammount of information an implementation can -share with a Kernel program (e.g. There is no way in Kernel to get the -parents or a complete list of bindings of an environment object). - - The main reference on Kernel is the preliminary report: `Revised(-1) -Report on the Kernel Programming Language'. Some sections of the -report are still incomplete, so both klisp and this manual will use -specifications from other languages in these sections, trying to follow -the Kernel spirit. These instances will be documented throughout the -manual. - - You can read all about Kernel at John's homepage at WPI -`http://www.cs.wpi.edu/~jshutt/', including the preliminary report on -the language and his doctoral dissertation which gives a theorethical -frame for fexprs. You can contact him at <jshutt@cs.wpi.edu>. - - -File: klisp.info, Node: Conventions, Next: Acknowledgements, Prev: Kernel History, Up: Introduction - -1.3 Conventions -=============== - -This section explains the notational conventions that are used in this -manual. You may want to skip this section and refer back to it later. - -* Menu: - -* Some Terms:: Explanation of terms we use in this manual. -* Evaluation Notation:: The format we use for examples of evaluation. -* Printing Notation:: The format we use for examples that print output. -* Error Messages:: The format we use for examples of errors. -* Format of Descriptions:: Notation for describing functions, variables, etc. - - -File: klisp.info, Node: Some Terms, Next: Evaluation Notation, Prev: Conventions, Up: Conventions - -1.3.1 Some Terms ----------------- - -Throughout this manual, the phrases "the Kernel reader" and "the Kernel -printer" are used to refer to those routines in Lisp that convert -textual representations of Kernel objects into actual objects, and vice -versa. XXX Printed Representation XXX, for more details. You, the -person reading this manual, are assumed to be "the programmer" or "the -user". - - Examples of Kernel code appear in this font or form: `(list 1 2 3)'. -Names that represent arguments or metasyntactic variables appear in -this font or form: FIRST-NUMBER. - - -File: klisp.info, Node: Evaluation Notation, Next: Printing Notation, Prev: Some Terms, Up: Conventions - -1.3.2 Evaluation Notation -------------------------- - -When you evaluate a piece of Kernel code, it produces a result. In the -examples in this manual, this is indicated with `=>': - - (car (cons 1 2)) - => 1 - -You can read this as "`(car (cons 1 2))' evaluates to 1". - - The semantics of a language feature are sometimes clarified, or even -defined, in its entry by specifying that two expressions are -equivalent. This is notated with `=='. For example, the semantics of -applicative list* can be defined by following equivalences: - (list* arg1) == arg1 - (list* arg1 . more-args) == (cons arg1 (list* . more-args)) - Notice that in these kind of examples the applicatives or operatives -referred to are the first class values and not the symbols bound to -them in the ground environment. This definition would hold even if -`cons' or `list*' were redefined in the current dynamic environment. - - -File: klisp.info, Node: Printing Notation, Next: Error Messages, Prev: Evaluation Notation, Up: Conventions - -1.3.3 Printing Notation ------------------------ - -Many of the examples in this manual print text when they are evaluated. -In examples that print text, the printed text is indicated with `-|'. -The value returned by evaluating the form (here `#t') follows on a -separate line. - - ($sequence (write 1) (write 2) #t) - -| 1 - -| 2 - => #t - - -File: klisp.info, Node: Error Messages, Next: Format of Descriptions, Prev: Printing Notation, Up: Conventions - -1.3.4 Error Messages --------------------- - -Some examples cause errors to be signaled. The report doesn't specify -what objects are passed to the error continuation, but in klisp, -objects passed to the error continuation are encapsulated error objects -that have at least a message and possibly some additional objects and -context informations (such as source code location). In the examples, -the error message is shown on a line starting with `error-->'. - - (+ 23 #t) - error--> Wrong type argument: (expected number) (#t) - - -File: klisp.info, Node: Format of Descriptions, Prev: Error Messages, Up: Conventions - -1.3.5 Format of Descriptions ----------------------------- - -Applicatives, operatives, and other objects are described in this manual -in a uniform format. The first line of a description contains the name -of the item followed by its operands or arguments, if any. The -category--operative, applicative, or whatever--appears at the beginning -of the line. The description follows on succeeding lines, sometimes -with examples. - -* Menu: - -* A Sample Applicative Description:: - - -File: klisp.info, Node: A Sample Applicative Description, Prev: Format of Descriptions, Up: Format of Descriptions - -1.3.5.1 A Sample Applicative Description -........................................ - -In an applicative description, the name of the applicative being -described appears first. It is followed on the same line by an -applicative combination that includes the name of the applicative and -the arguments, as would appear in a program. The names used for the -arguments are also used in the body of the description. - - Here is a description of an imaginary applicative `foo': - - -- Applicative: foo (foo integer1 integer2 . rest) - The applicative `foo' subtracts INTEGER1 from INTEGER2, then adds - all the rest of the arguments to the result. - - (foo 1 5 3 9) - => 16 - - More generally, - - (foo W X Y...) - == - (+ (- X W) Y...) - - Any parameter whose name contains the name of a type (e.g., INTEGER, -INTEGER1 or CONTINUATION) is expected to be of that type. A plural of -a type (such as NUMBERS) often means a list of objects of that type. -Parameters named OBJECT may be of any type. Additionally parameters -named K, or KN (for any value of N), should be exact, non-negative -integers. (XXX Types of Lisp Object XXX, for a list of Kernel object -types.) Parameters with other sorts of names are discussed -specifically in the description of the combiner. In some sections, -features common to parameters of several combiners are described at the -beginning. - - Operative descriptions have the same format, but the word -`Applicative' is replaced by `Operative', and `Argument' is replaced -by `Operand'. Also Operatives always have an environment parameter -(that can be #ignore or a symbol). - - -File: klisp.info, Node: Acknowledgements, Prev: Conventions, Up: Introduction - -1.4 Acknowledgements -==================== - -This manual was written by Andres Navarro. - - The structure and some text for this introductory section were -borrowed from the Elisp Manual by the Free Sofware Foundation. This -manual also borrows freely from both the Kernel Report and the Scheme -Reports. - - -File: klisp.info, Node: Booleans, Next: Equivalence, Prev: Introduction, Up: Top - -2 Booleans -********** - -The boolean data type consists of two values, which are called true and -false, and have respectively external representations `#t' and `#f'. -There are no possible mutations of either of these two values, and the -boolean type is encapsulated. - - -- Applicative: boolean? (boolean? . objects) - The primitive type predicate for type boolean. `boolean?' returns - true iff all the objects in `objects' are of type boolean. - - -- Applicative: not? (not? boolean) - Applicative `not?' is a predicate that returns the logical - negation of its argument. - - -- Applicative: and? (and? . booleans) - Applicative `and?' is a predicate that returns true unless one or - more of its arguments are false. - - -- Applicative: or? (or? . booleans) - Applicative `or?' is a predicate that returns false unless one or - more of its arguments are true. - - -- Operative: $and? ($and? . <list>) - The `$and?' operative performs a "short-circuit and" of its - operands. It evaluates them from left to right, until either an - operand evaluates to false, or the end of the list is reached. If - the end of the list is reached (which is immediate if `<list>' is - `nil'), the operative returns true. If an operand evaluates to - false, no further operand evaluations are performed, and the - operative returns false. If `<list>' is acyclic, and the last - operand is evaluated, it is evaluated as a tail context. If - `<list>' is cyclic, an unbounded number of operand evaluations may - be performed. If any of the operands evaluates to a non-boolean - value, an error is signaled (even if it's the last one). - - -- Operative: $or? ($or? . <list>) - The `$or?' operative performs a "short-circuit or" of its - operands. It evaluates them from left to right, until either an - operand evaluates to true, or the end of the list is reached. If - the end of the list is reached (which is immediate if `<list>' is - `nil'), the operative returns false. If an operand evaluates to - true, no further operand evaluations are performed, and the - operative returns true. If `<list>' is acyclic, and the last - operand is evaluated, it is evaluated as a tail context. If - `<list>' is cyclic, an unbounded number of operand evaluations may - be performed. If any of the operands evaluates to a non-boolean - value, an error is signaled (even if it's the last one). - - -File: klisp.info, Node: Equivalence, Next: Symbols, Prev: Booleans, Up: Top - -3 Equivalence -************* - -Kernel has two general-purpose equivalence predicates (whereas R5RS -Scheme has three). The two Kernel predicates correspond to the -abstract notions of equivalence up to mutation (`equal') and -equivalence in the presence of mutation (`eq?'). - - -- Applicative: eq? (eq? . objects) - Predicate `eq?' returns true iff all of `objects' are effectively - the same object, even in the presence of mutation. - - -- Applicative: equal? (equal? . objects) - Predicate `equal?' returns true iff all of `objects' "look" the - same as long as nothing is mutated. This is a weaker predicate - than `eq?'; that is, `equal?' must return true whenever `eq?' - would return true. - - -File: klisp.info, Node: Symbols, Next: Control, Prev: Equivalence, Up: Top - -4 Symbols -********* - -Two symbols are eq? iff they have the same external representation. -Symbols are immutable, and the symbol type is encapsulated. The -external representations of symbols are usually identifiers. However, -symbols with other external representations may be created. - - -- Applicative: symbol? (symbol? . objects) - The primitive type predicate for type symbol. `symbol?' returns - true iff all the objects in `objects' are of type symbol. - - -- Applicative: symbol->string (symbol->string symbol) - Applicative `symbol->string' returns the name of `symbol' as a - string. The string returned is immutable. - - -- Applicative: string->symbol (string->symbol string) - Applicative `string->symbol' returns the symbol with name - `string'. The symbol is always interned, which means, that it is - always the case that: - (eq? <symbol> (string->symbol (symbol->string <symbol>))) - => #t - `string->symbol' can create symbols whose external - representation aren't identifiers. Right now klisp uses an - output-only representation, but in the near future it will - probably include some kind of escaping mechanism to allow - arbitrary symbols to have readable external representations as in - R7RS Scheme. - - -File: klisp.info, Node: Control, Next: Pairs and lists, Prev: Symbols, Up: Top - -5 Control -********* - -The inert data type is provided for use with control combiners. It -consists of a single immutable value, having external representation -`#inert'. The inert type is encapsulated. - - -- Applicative: inert? (inert? . objects) - The primitive type predicate for type inert. `inert?' returns true - iff all the objects in `objects' are of type inert. - - -- Operative: $if ($if <test> <consequent> <alternative>) - The `$if' operative first evaluates `<test>' in the dynamic - environment. If the result is not of type boolean, an error is - signaled. If the result is true, `<consequent>' is then evaluated - in the dynamic environment as a tail context. Otherwise, - `<alternative>' is evaluated in the dynamic environment as a tail - context. - - -- Operative: $sequence ($sequence . <objects>) - The `$sequence' operative evaluates the elements of the list - `<objects>' in the dynamic environment, one at a time from left to - right. If `<objects>' is a cyclic list, element evaluation - continues indefinitely, with elements in the cycle being evaluated - repeatedly. If `<objects>' is a nonempty finite list, its last - element is evaluated as a tail context. If `<objects>' is the - empty list, the result is inert. - - -- Operative: $cond ($cond . <clauses>) - `<clauses>' should be a list of clause expressions, each of the - form `(<test> . <body>)', where body is a list of expressions. - - The following equivalences define the behaviour of the `$cond' - operative: - ($cond) == #inert - ($cond (<test> . <body>) . <clauses>) == - ($if <test> ($sequence . <body>) ($cond . <clauses>)) - - -- Applicative: for-each (for-each . lists) - `lists' must be a nonempty list of lists; if there are two or - more, they should all be the same length. If lists is empty, or if - all of its elements are not lists of the same length, an error is - signaled. - - `for-each' behaves identically to `map', except that instead of - accumulating and returning a list of the results of the - element-wise applications, the results of the applications are - discarded and the result returned by `for-each' is inert. - - -File: klisp.info, Node: Pairs and lists, Next: Environments, Prev: Control, Up: Top - -6 Pairs and lists -***************** - -A pair is an object that refers to two other objects, called its car -and cdr. The Kernel data type pair is encapsulated. - - The null data type consists of a single immutable value, called nil -or the empty list and having external representation `()', with or -without whitespace between the parentheses. It is immutable, and the -null type is encapsulated. - - If `a' and `d' are external representations of respectively the car -and cdr of a pair `p', then `(a . d)' is an external representation of -`p'. If the cdr of `p' is nil, then `(a)' is also an external -representation of `p'. If the cdr of `p' is a pair `p2', and `(r)' is -an external representation of `p2', then `(a r)' is an external -representation of `p'. When a pair is output (as by write), an -external representation with the fewest parentheses is used; in the -case of a finite list, only one set of parentheses is required beyond -those used in representing the elements of the list. For example, an -object with external representation `(1 . (2 . (3 . ())))' would be -output using, modulo whitespace, external representation `(1 2 3)'. - - -- Applicative: pair? (pair? . objects) - The primitive type predicate for type pair. `pair?' returns true - iff all the objects in `objects' are of type pair. - - -- Applicative: null? (null? . objects) - The primitive type predicate for type null. `null?' returns true - iff all the objects in `objects' are of type null. - - -- Applicative: cons (cons object1 object2) - A new mutable pair object is constructed and returned, whose car - and cdr referents are respectively `object1' and `object2'. No - two objects returned by different calls to cons are `eq?' to each - other. - - -- Applicative: set-car! (set-car! pair object) - -- Applicative: set-cdr! (set-cdr! pair object) - `pair' should be a mutable pair. - - These applicatives set the referent of, respectively, the car - reference or the cdr reference of `pair' to `object'. The result - of the expression is inert. - - -- Applicative: copy-es-immutable! (copy-es-immutable object) - The short description of this applicative is that it returns an - object `equal?' to `object' with an immutable evaluation - structure. The "-es-" in the name is short for "evaluation - structure". - - The evaluation structure of an object `o' is defined to be the set - of all pairs that can be reached by following chains of references - from `o' without ever passing through a non-pair object. The - evaluation structure of a non-pair object is empty. - - If `object' is not a pair, the applicative returns `object'. - Otherwise (if `object' is a pair), the applicative returns an - immutable pair whose car and cdr would be suitable results for - `(copy-es-immutable (car object))' and `(copy-es-immutable (cdr - object))', respectively. Further, the evaluation structure of the - returned value is isomorphic to that of `object' at the time of - copying, with corresponding non-pair referents being `eq?'. - - NOTE: In Kernel it's undefined whether immutable pairs are copied - or left "as is" in the result. klisp doesn't copy immutable - pairs, but that behaviour should not be depended upon. - - -- Applicative: list (list . objects) - The `list' applicative returns `objects'. - - The underlying operative of `list' returns its undifferentiated - operand tree, regardless of whether that tree is or is not a list. - - -- Applicative: list* (list* . objects) - `objects' should be a finite nonempty list of arguments. - - The following equivalences hold: - (list* arg1) == arg1 - (list* arg1 arg2 . args) == (cons arg1 (list* arg2 . args)) - - -- Applicative: car (car pair) - -- Applicative: cdr (cdr pair) - These applicatives return, respectively, the car and cdr of `pair'. - - -- Applicative: caar (caar pair) - -- Applicative: cadr (cadr pair) - -- Applicative: cdar (cdar pair) - -- Applicative: cddr (cddr pair) - -- Applicative: caaar (caaar pair) - -- Applicative: caadr (caadr pair) - -- Applicative: cadar (cadar pair) - -- Applicative: caddr (caddr pair) - -- Applicative: cdaar (cdaar pair) - -- Applicative: cdadr (cdadr pair) - -- Applicative: cddar (cddar pair) - -- Applicative: cdddr (cdddr pair) - -- Applicative: caaaar (caaaar pair) - -- Applicative: caaadr (caaadr pair) - -- Applicative: caadar (caadar pair) - -- Applicative: caaddr (caaddr pair) - -- Applicative: cadaar (cadaar pair) - -- Applicative: cadadr (cadadr pair) - -- Applicative: caddar (caddar pair) - -- Applicative: cadddr (cadddr pair) - -- Applicative: cdaaar (cdaaar pair) - -- Applicative: cdaadr (cdaadr pair) - -- Applicative: cdadar (cdadar pair) - -- Applicative: cdaddr (cdaddr pair) - -- Applicative: cddaar (cddaar pair) - -- Applicative: cddadr (cddadr pair) - -- Applicative: cdddar (cdddar pair) - -- Applicative: cddddr (cddddr pair) - These applicatives are compositions of `car' and `cdr', with the - "a’s" and "d’s" in the same order as they would appear if all the - individual "car’s" and "cdr’s" were written out in prefix order. - Arbitrary compositions up to four deep are provided. There are - twenty-eight of these applicatives in all. - - -- Applicative: get-list-metrics (get-list-metrics object) - By definition, an improper list is a data structure whose objects - are its start together with all objects reachable from the start by - following the cdr references of pairs, and whose internal - references are just the cdr references of its pairs. Every - object, of whatever type, is the start of an improper list. If - the start is not a pair, the improper list consists of just that - object. The acyclic prefix length of an improper list `L' is the - number of pairs of `L' that a naive traversal of `L' would visit - only once. The cycle length of `L' is the number of pairs of `L' - that a naive traversal would visit repeatedly. Two improper lists - are structurally isomorphic iff they have the same acyclic prefix - length and cycle length and, if they are terminated by non-pair - objects rather than by cycles, the non-pair objects have the same - type. Applicative `get-list-metrics' constructs and returns a - list of exact integers of the form `(p n a c)', where `p', `n', - `a', and `c' are, respectively, the number of pairs in, the number - of nil objects in, the acyclic prefix length of, and the cycle - length of, the improper list starting with `object'. `n' is either - `0' or `1', `a + c = p', and `n' and `c' cannot both be non-zero. - If `c = 0', the improper list is acyclic; if `n = 1', the improper - list is a finite list; if `n = c = 0', the improper list is not a - list; if `a = c = 0', `object' is not a pair. - - -- Applicative: list-tail (list-tail object k) - `object' must be the start of an improper list containing at least - `k' pairs. - - The `list-tail' applicative follows `k' cdr references starting - from `object'. - - The following equivalences hold: - (list-tail object 0) == object - (list-tail object (+ k 1)) == (list-tail (cdr object) k) - - -- Applicative: encycle! (encycle! object k1 k2) - The improper list starting at `object' must contain at least `k1 + - k2' pairs. - - If `k2 = 0', the applicative does nothing. If `k2 > 0', the - applicative mutates the improper list starting at `object' to have - acyclic prefix length `k1' and cycle length `k2', by setting the - cdr of the `(k1+k2)'th pair in the list to refer to the `(k1 + - 1)'th pair in the list. The result returned by `encycle!' is - inert. - - -- Applicative: map (map applicative . lists) - `lists' must be a nonempty list of lists; if there are two or - more, they must all have the same length. - - The map applicative applies `applicative' element-wise to the - elements of the lists in lists (i.e., applies it to a list of the - first elements of the lists, to a list of the second elements of - the lists, etc.), using the dynamic environment from which map was - called, and returns a list of the results, in order. The - applications may be performed in any order, as long as their - results occur in the resultant list in the order of their - arguments in the original lists. If `lists' is a cyclic list, - each argument list to which `applicative' is applied is - structurally isomorphic to `lists'. If any of the elements of - `lists' is a cyclic list, they all must be, or they wouldn’t all - have the same length. Let `a1...an' be their acyclic prefix - lengths, and `c1...cn' be their cycle lengths. The acyclic prefix - length `a' of the resultant list will be the maximum of the `ak', - while the cycle length `c' of the resultant list will be the least - common multiple of the `ck'. In the construction of the result, - `applicative' is called exactly `a + c' times. - - -- Applicative: length (length object) - Applicative `length' returns the (exact) improper-list length of - `object'. That is, it returns the number of consecutive cdr - references that can be followed starting from `object'. If - `object' is not a pair, it returns zero; if `object' is a cyclic - list, it returns positive infinity. - - -- Applicative: list-ref (list-ref object k) - The `list-ref' applicative returns the `car' of the object - obtained by following `k' cdr references starting from `object'. - - NOTE: In the current report, object is required to be a list. In - klisp, for now, we prefer the behaviour presented here, as it is - more in line with the applicative `list-tail'. That is, we define - `list-ref' by the following equivalence: - (list-ref object k) == (car (list-tail object k)) - - -- Applicative: append (append . lists) - Here, all the elements of `lists' except the last element (if any) - must be acyclic lists. The `append' applicative returns a freshly - allocated list of the elements of all the specified `lists', in - order, except that if there is a last specified element of - `lists', it is not copied, but is simply referenced by the cdr of - the preceding pair (if any) in the resultant list. If `lists' is - cyclic, the cycle of the result list consists of just the elements - of the lists specified in the cycle in `lists'. In this case, the - acyclic prefix length of the result is the sum of the lengths of - the lists specified in the acyclic prefix of `lists', and the - cycle length of the result is the sum of the lengths of the lists - specified in the cycle of `lists'. - - The following equivalences hold: - (append) == () - (append h) == h - (append () h . t) == (append h . t) - (append (cons a b) h . t) == (cons a (append b h . t)) - - -- Applicative: list-neighbors (list-neighbors list) - The `list-neighbors' applicative constructs and returns a list of - all the consecutive sublists of `list' of length 2, in order. If - `list' is nil, the result is nil. If `list' is non-nil, the - length of the result is one less than the length of `list'. If - `list' is cyclic, the result is structurally isomorphic to it - (i.e., has the same acyclic prefix length and cycle length). - - For example: - (list-neighbors (list 1 2 3 4)) => ((1 2) (2 3) (3 4)) - - -- Applicative: filter (filter applicative list) - Applicative `filter' passes each of the elements of `list' as an - argument to `applicative', one at a time in no particular order, - using a fresh empty environment for each call. The result of each - call to `applicative' must be boolean, otherwise an error is - signaled. `filter' constructs and returns a list of all elements - of `list' on which `applicative' returned true, in the same order - as in `list'. `applicative' is called exactly as many times as - there are pairs in `list'. The resultant list has a cycle - containing exactly those elements accepted by `applicative' that - were in the cycle of `list'; if there were no such elements, the - result is acyclic. - - -- Applicative: assoc (assoc object pairs) - Applicative `assoc' returns the first element of `pairs' whose car - is `equal?' to `object'. If there is no such element in `pairs', - nil is returned. - - -- Applicative: member? (member? object list) - Applicative `member?' is a predicate that returns true iff some - element of `list' is `equal?' to `object'. - - -- Applicative: finite-list? (finite-list? . objects) - This is the type predicate for type finite-list. `finite-list?' - returns true iff all the objects in `objects' are acyclic lists. - - -- Applicative: countable-list? (countable-list? . objects) - This is the type predicate for type list. `countable-list?' - returns true iff all the objects in `objects' are lists. - - -- Applicative: reduce (reduce list binary identity [precycle incycle - postcycle]) - `binary' should be an applicative. If the short form is used, - `list' should be an acyclic. If the long form is used, `precycle', - `incycle', and `postcycle' should be applicatives. - - If `list' is empty, applicative `reduce' returns `identity'. If - `list' is nonempty but acyclic, applicative `reduce' uses binary - operation `binary' to merge all the elements of `list' into a - single object, using any associative grouping of the elements. - That is, the sequence of objects initially found in `list' is - repeatedly decremented in length by applying `binary' to a list of - any two consecutive objects, replacing those two objects with the - result at the point in the sequence where they occurred; and when - the sequence contains only one object, that object is returned. - If `list' is cyclic, the long form must be used. The elements of - the cycle are passed, one at a time (but just once for each - position in the cycle), as arguments to unary applicative - `precycle'; the finite, cyclic sequence of results from `precycle' - is reduced using binary applicative `incycle'; and the result from - reducing the cycle is passed as an argument to unary applicative - `postcycle'. Binary operation `binary' is used to reduce the - sequence consisting of the elements of the acyclic prefix of - `list' followed by the result returned by `postcycle'. The only - constraint on the order of calls to the applicatives is that each - call must be made before its result is needed (thus, parts of the - reduction of the acyclic prefix may occur before the contribution - from the cycle has been completed). - - Each call to `binary', `precycle', `incycle', or `postcycle' uses - the dynamic environment of the call to `reduce'. - - If `list' is acyclic with length `n >= 1', `binary' is called `n - - 1' times. If `list' is cyclic with acyclic prefix length `a' and - cycle length `c', `binary' is called `a' times; `precycle', `c' - times; `incycle', `c - 1' times; and `postcycle', once. - - -- Applicative: append! (append! . lists) - `lists' must be a nonempty list; its first element must be an - acyclic nonempty list, and all of its elements except the last - element (if any) must be acyclic lists. - - The `append!' applicative sets the cdr of the last pair in each - nonempty list argument to refer to the next non-nil argument, - except that if there is a last non-nil argument, it isn’t mutated. - It is an error for any two of the list arguments to have the same - last pair. The result returned by this applicative is inert. - - The following equivalences hold: - (append! v) == #inert - (append! u v . w) == ($sequence (append! u v) (append! u . w)) - - -- Applicative: copy-es (copy-es object) - Briefly, applicative `copy-es' returns an object initially - `equal?' to `object' with a freshly constructed evaluation - structure made up of mutable pairs. If `object' is not a pair, - the applicative returns `object'. If `object' is a pair, the - applicative returns a freshly constructed pair whose car and cdr - would be suitable results for `(copy-es (car object))' and - `(copy-es (cdr object))', respectively. Further, the evaluation - structure of the returned value is structurally isomorphic to that - of `object' at the time of copying, with corresponding non-pair - referents being `eq?'. - - -- Applicative: assq (assq object pairs) - Applicative `assq' returns the first element of `pairs' whose car - is `eq?' to `object'. If there is no such element in `pairs', nil - is returned. - - -- Applicative: memq? (memq? object list) - Applicative `memq?' is a predicate that returns true iff some - element of `list' is `eq?' to `object'. - - -File: klisp.info, Node: Environments, Next: Combiners, Prev: Pairs and lists, Up: Top - -7 Environments -************** - -An environment consists of a set of bindings, and a list of zero or -more references to other environments called its parents. Changing the -set of bindings of an environment, or setting the referent of the -reference in a binding, is a mutation of the environment. (Changing the -parent list, or a referent in the list, would be a mutation of the -environment too, but there is no facility provided to do it.) The -Kernel data type environment is encapsulated. Among other things, -there is no facility provided for enumerating all the variables -exhibited by an environment (which is not required, after all, to be a -finite set), and no facility for identifying the parents of an -environment. Two environments are `equal?' iff they are `eq?'. - - An auxiliary data type used by combiners that perform binding is -ignore. The ignore type consists of a single immutable value, having -external representation `#ignore'. The ignore type is encapsulated. - - -- Applicative: environment? (environment? . objects) - The primitive type predicate for type environment. `environment?' - returns true iff all the objects in `objects' are of type - environment. - - -- Applicative: ignore? (ignore? . objects) - The primitive type predicate for type ignore. `ignore?' returns - true iff all the objects in `objects' are of type ignore. - - -- Applicative: eval (eval expression environment) - The `eval' applicative evaluates `expression' as a tail context in - `environment', and returns the resulting value. - - -- Applicative: make-environment (make-environment . environments) - The applicative constructs and returns a new environment, with - initially no local bindings, and parent environments the - environments listed in `environments'. The constructed environment - internally stores its list of parents independent of the - first-class list `environments', so that subsequent mutation of - `environments' will not change the parentage of the constructed - environment. If the provided list `environments' is cyclic, the - constructed environment will still check each of its parents at - most once, and signal an error if no binding is found locally or - in any of the parents. No two objects returned by different calls - to `make-environment' are `eq?' to each other. - - -- Operative: $define! ($define! <definiend> <expression>) - `<definiend>' should be a formal parameter tree, as described - below; otherwise, an error is signaled. - - The `$define!' operative evaluates `<expression>' in the dynamic - environment and matches `<definiend>' to the result in the dynamic - environment, binding each symbol in definiend in the dynamic - environment to the corresponding part of the result; the matching - process will be further described below. The ancestors of the - dynamic environment, if any, are unaffected by the matching - process, as are all bindings, local to the dynamic environment, of - symbols not in `<definiend>'. The result returned by `$define!' is - inert. - - A formal parameter tree has the following context-free structure: - ptree:: symbol | #ignore | () | (ptree . ptree) - - That is, a formal parameter tree is either a symbol, or ignore, or - nil, or a pair whose car and cdr referents are formal parameter - trees. A formal parameter tree must also be acyclic, and no one - symbol can occur more than once in it. It is not an error for a - pair in the tree to be reachable from the root by more than one - path, as long as there is no cycle; but if any particular symbol - were reachable from the root by more than one path, that would - count as occurring more than once. Thus, if a pair is reachable - by more than one path, there must be no symbols reachable from it. - - Matching of a formal parameter tree `t' to an object `o' in an - environment `e' proceeds recursively as follows. If the matching - process fails, an error is signaled. - * If `t' is a symbol, then `t' is bound to `o' in `e'. - - * If `t' is `#ignore', no action is taken. - - * If `t' is nil, then `o' must be nil (else matching fails). - - * If `t' is a pair, then `o' must be a pair (else matching - fails). The car of `t' is matched to the car of `o' in `e', - and the cdr of `t' is matched to the cdr of `o' in `e'. - - -- Operative: $let ($let <bindings> . <objects>) - `<bindings>' should be a finite list of - formal-parameter-tree/expression pairings, each of the form - `(formals expression)', where each `formals' is a formal - parameter, and no symbol occurs in more than one of the `formals'. - - The following equivalence holds: - - ($let ((form1 exp1) ... (formn expn)) . objects) == - (($lambda (form1 ... formn) . objects) exp1 ... expn) - - Thus, the `expk' are first evaluated in the dynamic environment, - in any order; then a child environment `e' of the dynamic - environment is created, with the `formk' matched in `e' to the - results of the evaluations of the `expk'; and finally the - subexpressions of `objects' are evaluated in `e' from left to - right, with the last (if any) evaluated as a tail context, or if - `objects' is empty the result is inert. - - -- Operative: $binds? ($binds? <exp> . <symbols>) - Operative `$binds' evaluates `<exp>' in the dynamic environment; - call the result `env'. `env' must be an environment. The - operative is a predicate that returns true iff all its later - operands, `<symbols>', are visibly bound in `env'. - - -- Applicative: get-current-environment (get-current-environment) - The `get-current-environment' applicative returns the dynamic - environment in which it is called. - - -- Applicative: make-kernel-standard-environment - (make-kernel-standard-environment) - The `make-kernel-standard-environment' applicative returns a - standard environment; that is, a child of the ground environment - with no local bindings. - - -- Operative: $let* ($let* <bindings> . <body>) - `<bindings>' should be a finite list of - formal-parameter-tree/expression pairings, each of the form - `(formals expression)', where each `formals' is a formal parameter - tree; `<body>' should be a list of expressions. - - The following equivalences hold: - - ($let* () . body) == ($let () . body) - - ($let* ((form exp) . bindings) . body) == - ($let ((form exp)) ($let* bindings . body)) - - -- Operative: $letrec ($letrec <bindings> . <body>) - `<bindings>' and `<body>' should be as described for `$let'. - - The following equivalence holds: - ($letrec ((form1 exp1) ... (formn expn)) . body) == - ($let () ($define! (form1 ... formn) (list exp1 ... expn)) . body) - - -- Operative: $letrec* ($letrec* <bindings> . <body>) - `<bindings>' and `<body>' should be as described for `$let*'. - - The following equivalences hold: - ($letrec* () . body) == ($letrec () . body) - - ($letrec* ((form exp) . bindings) . body) == - ($letrec ((form exp)) ($letrec* bindings . body)) - - -- Operative: $let-redirect ($let-redirect <exp> <bindings> . <body>) - `<bindings>' and `<body>' should be as described for `$let'. - - The following equivalence holds: - - ($let-redirect exp ((form1 exp1) ... (formn . body) expn)) == - ((eval (list $lambda (form1 ... formn) body) exp) expn ... expn) - - -- Operative: $let-safe ($let-safe <bindings> . <body>) - `<bindings>' and `<body>' should be as described for `$let'. - - The following equivalence holds: - - ($let-safe bindings . body) == - ($let-redirect (make-kernel-standard-environment) bindings . body) - - -- Operative: $remote-eval ($remote-eval <exp1> <exp2>) - Operative `$remote-eval' evaluates `<exp2>' in the dynamic - environment, then evaluates `<exp1>' as a tail context in the - environment that must result from the first evaluation. - - -- Operative: ($bindings-environment . <bindings>) - `<bindings>' should be as described for `$let'. - - The following equivalence holds: - - ($bindings->environment . bindings) == - ($let-redirect (make-environment) bindings (get-current-environment)) - - -- Operative: $set! ($set! <exp1> <formals> <exp2>) - `<formals>' should be as described for the `$define!' operative. - The `$set!' operative evaluates `<exp1>' and `<exp2>' in the - dynamic environment; call the results `env' and `obj'. If `env' - is not an environment, an error is signaled. Then the operative - matches `<formals>' to `obj' in environment `env'. Thus, the - symbols of `<formals>' are bound in `env' to the corresponding - parts of `obj'. The result returned by `$set!' is inert. - - -- Operative: $provide! ($provide! <symbols> . <body>) - `<symbols>' must be a finite list of symbols, containing no - duplicates. `<body>' must be a finite list. - - The `$provide!' operative constructs a child `e' of the dynamic - environment `d'; evaluates the elements of `<body>' in `e', from - left to right, discarding all of the results; and exports all of - the bindings of symbols in `<symbols>' from `e' to `d', i.e., - binds each symbol in `d' to the result of looking it up in `e'. - The result returned by `$provide!' is inert. - - The following equivalence holds: - - ($provide! symbols . body) == - ($define! symbols ($let () ($sequence . body) (list . symbols))) - - -- Operative: $import! ($import! <exp> . <symbols>) - `<symbols>' must be a list of symbols. - - The `$import!' operative evaluates `<exp>' in the dynamic - environment; call the result `env'. `env' must be an environment. - Each distinct symbol `s' in `<symbols>' is evaluated in `env', and - `s' is bound in the dynamic environment to the result of this - evaluation. - - The following equivalence holds: - - ($import! exp . symbols) == - ($define! symbols ($remote-eval (list symbols) exp)) - - -File: klisp.info, Node: Combiners, Next: Continuations, Prev: Environments, Up: Top - -8 Combiners -*********** - -There are two types of combiners in Kernel, operative and applicative. -Both types are encapsulated. All combiners are immutable. Two -applicatives are `eq?' iff their underlying combiners are `eq?'. -However, `eq?'-ness of operatives is only constrained by the general -rules for `eq?', which leave considerable leeway for variation between -implementations. klisp only considers `eq?' those operatives -constructed by the same call to a constructor (e.g. `$vau'). Two -combiners are `equal?' iff they are `eq?'. - - -- Applicative: operative? (operative? . objects) - The primitive type predicate for type operative. `operative?' - returns true iff all the objects in `objects' are of type - operative. - - -- Applicative: applicative? (applicative? . objects) - The primitive type predicate for type applicative. `applicative?' - returns true iff all the objects in `objects' are of type - applicative. - - -- Operative: $vau ($vau <formals> <eformal> . <objects>) - `<formals>' should be a formal parameter tree; `<eformal>' should - be either a symbol or `#ignore'. If `<formals>' does not have the - correct form for a formal parameter tree, or if `<eformal>' is a - symbol that also occurs in `<formals>', an error is signaled. - - A `vau' expression evaluates to an operative; an operative created - in this way is said to be compound. The environment in which the - `vau' expression was evaluated is remembered as part of the - compound operative, called the compound operative’s static - environment. `<formals>' and `<objects>' are copied as by - `copy-es-immutable' and the copies are stored as part of the - operative being constructed. This avoids problem if these - structures are later mutated. - - When the compound operative created by `$vau' is later called with - an object and an environment, here called respectively the operand - tree and the dynamic environment, the following happens: - - 1. A new, initially empty environment is created, with the static - environment as its parent. This will be called the local - environment. - - 2. A stored copy of the formal parameter tree formals is matched - in the local environment to the operand tree, locally binding - the symbols of formals to the corresponding parts of the - operand tree. eformal is matched to the dynamic environment; - that is, if eformal is a symbol then that symbol is bound in - the local environment to the dynamic environment. - - 3. A stored copy of the expressions is evaluated sequentially - from left to right, with the last (if any) evaluated as a - tail context, or if the list of expressions is empty, the - result is inert. - - NOTE: Because compound operatives are not a distinct type in - Kernel, they are covered by the encapsulation of type operative. - In particular, an implementation of Kernel cannot provide a - feature that supports extracting the static environment of any - given compound operative, nor that supports determining whether or - not a given operative is compound. - - -- Applicative: wrap (wrap combiner) - The `wrap' applicative returns an applicative whose underlying - combiner is `combiner'. - - -- Applicative: unwrap (unwrap applicative) - The `unwrap' applicative returns the underlying combiner of - `applicative'. - - -- Operative: $lambda ($lambda <formals> . <objects>) - `<formals>' should be a formal parameter tree. - - The `$lambda' operative is defined by the following equivalence: - ($lambda formals . objects) == - (wrap ($vau formals #ignore . objects)) - - -- Applicative: apply (apply applicative object [environment]) - Applicative `apply' combines the underlying combiner of - `applicative' with `object' in a tail context with dynamic - environment `environment' (if the long form is used) or in an - empty environment (if the short form is used). - - The following equivalences hold: - (apply applicative object environment) == - (eval (cons (unwrap applicative) object) environment) - - (apply applicative object) == - (apply applicative object (make-environment)) - - -- Applicative: map (map applicative . lists) - `lists' must be a nonempty list of lists; if there are two or - more, they must all have the same length. If `lists' is empty, or - if all of its elements are not lists of the same length, an error - is signaled. - - The `map' applicative applies `applicative' element-wise to the - elements of the lists in `lists' (i.e., applies it to a list of - the first elements of the `lists', to a list of the second - elements of the `lists', etc.), using the dynamic environment from - which `map' was called, and returns a list of the results, in - order. The applications may be performed in any order, as long as - their results occur in the resultant list in the order of their - arguments in the original `lists'. If `lists' is a cyclic list, - each argument list to which `applicative' is applied is - structurally isomorphic to `lists'. If any of the elements of - `lists' is a cyclic list, they all must be, or they wouldn’t all - have the same length. Let `a1...an' be their acyclic prefix - lengths, and `c1...cn' be their cycle lengths. The acyclic prefix - length `a' of the resultant list will be the maximum of the `ak', - while the cycle length `c' of the resultant list will be the least - common multiple of the `ck'. In the construction of the result, - applicative is called exactly `a + c' times. - - -- Applicative: combiner? (combiner? . objects) - The primitive type predicate for type combiner. `combiner?' - returns true iff all the objects in `objects' are of type combiner - (i.e. applicative or operative). - - -File: klisp.info, Node: Continuations, Next: Encapsulations, Prev: Combiners, Up: Top - -9 Continuations -*************** - -A continuation is a plan for all future computation, parameterized by a -value to be provided, and contingent on the states of all mutable data -structures (which notably may include environments). When the Kernel -evaluator is invoked, the invoker provides a continuation to which the -result of the evaluation will normally be returned. - - For example, when `$if' evaluates its test operand, the continuation -provided for the result expects to be given a boolean value; and, -depending on which boolean it gets, it will evaluate either the -consequent or the alternative operand as a tail context — that is, the -continuation provided for the result of evaluating the selected operand -is the same continuation that was provided for the result of the call -to `$if'. - - A Kernel program may sometimes capture a continuation; that is, -acquire a reference to it as a first-class object. The basic means of -continuation capture is applicative `call/cc'. Given a first-class -continuation `c', a combiner can be constructed that will abnormally -pass its operand tree to `c' (as opposed to the normal return of values -to continuations). In the simplest case, the abnormally passed value -arrives at `c' as if it had been normally returned to `c'. In general, -continuations bypassed by the abnormal pass may have entry/exit guards -attached to them, and these guards can intercept the abnormal pass -before it reaches `c'. Each entry/exit guard consists of a selector -continuation, which designates which abnormal passes the guard will -intercept, and an interceptor applicative that performs the -interception when selected. - - Continuations are immutable, and are `equal?' iff `eq?'. The -continuation type is encapsulated. - - -- Applicative: continuation? (continuation? . objects) - The primitive type predicate for type continuation. - `continuation?' returns true iff all the objects in `objects' are - of type continuation. - - -- Applicative: call/cc (call/cc combiner) - Calls `combiner' in the dynamic environment as a tail context, - passing as sole operand to it the continuation to which `call/cc' - would normally return its result. (That is, constructs such a - combination and evaluates it in the dynamic environment.) - - -- Applicative: extend-continuation (extend-continuation continuation - applicative [environment]) - The `extend-continuation' applicative constructs and returns a new - child of `continuation' that, when it normally receives a value v, - calls the underlying combiner of `applicative' with dynamic - environment `environment' (or an empty environment if none was - specified) and operand tree `v', the result of the call normally - to be returned to `continuation'. - - The following equivalnece defines the short version: - (extend-continuation c a) == - (extend-continuation c a (make-environment)) - - -- Applicative: guard-continuation (guard-continuation entry-guards - continuation exit-guards) - `entry-guards' and `exit-guards' should each be a list of clauses; - each clause should be a list of length two, whose first element is - a continuation, and whose second element is an applicative whose - underlying combiner is operative. - - Applicative `guard-continuation' constructs two continuations: a - child of continuation, called the `outer continuation'; and a - child of the `outer continuation', called the `inner - continuation'. The `inner continuation' is returned as the result - of the call to `guard-continuation'. - - When the `inner continuation' normally receives a value, it passes - the value normally to the `outer continuation'; and when the - `outer continuation' normally receives a value, it passes the - value normally to `continuation'. Thus, in the absence of abnormal - passing, the inner and outer continuations each have the same - behavior as `continuation'. - - The two elements of each guard clause are called, respectively, the - `selector' and the `interceptor'. The `selector' continuation is - used in deciding whether to intercept a given abnormal pass, and - the `interceptor' applicative is called to perform customized - action when interception occurs. - - At the beginning of the call to `guard-continuation', internal - copies are made of the evaluation structures of `entry-guards' and - `exit-guards', so that the selectors and interceptors contained in - the arguments at that time remain fixed thereafter, independent of - any subsequent mutations to the arguments. - - -- Applicative: continuation->applicative (continuation->applicative - continuation) - Returns an applicative whose underlying operative abnormally passes - its operand tree to `continuation', thus: A series of interceptors - are selected to handle the abnormal pass, and a continuation is - derived that will normally perform all the interceptions in - sequence and pass some value to the destination of the originally - abnormal pass. The operand tree is then normally passed to the - derived continuation. - - -- Variable: root-continuation - This continuation is the ancestor of all other continuations. When - it normally receives a value, it terminates the Kernel session. - (For example, if the system is running a read-eval-print loop, it - exits the loop.) - - -- Variable: error-continuation - The dynamic extent of this continuation is mutually disjoint from - the dynamic extent in which Kernel computation usually occurs - (such as the dynamic extent in which the Kernel system would run a - read-eval-print loop). - - When this continuation normally receives a value, it provides a - diagnostic message to the user of the Kernel system, on the - assumption that the received value is an attempt to describe some - error that aborted a computation; and then resumes operation of - the Kernel system at some point that is outside of all - user-defined computation. (For example, if the system is running a - read-eval-print loop, operation may resume by continuing from the - top of the loop.) - - The diagnostic message is not made available to any Kernel - computation, and is therefore permitted to contain information that - violates abstractions within the system. - - When an error is signaled during a Kernel computation, the - signaling action consists of an abnormal pass to some continuation - in the dynamic extent of `error-continuation'. - - -- Applicative: apply-continuation (apply-continuation continuation - object) - Applicative `apply-continuation' converts its first argument to an - applicative as if by `continuation->applicative', and then applies - it as usual. - - That is: - (apply-continuation continuation object) == - (apply (continuation->applicative continuation) object) - - -- Operative: ($let/cc <symbol> . <objects>) - A child environment `e' of the dynamic environment is created, - containing a binding of `<symbol>' to the continuation to which - the result of the call to `$let/cc' should normally return; then, - the subexpressions of `<objects>' are evaluated in `e' from left - to right, with the last (if any) evaluated as a tail context, or - if `<objects>' is empty the result is inert. - - That is: - ($let/cc symbol . objects) == - (call/cc ($lambda (symbol) . objects)) - - -- Applicative: guard-dynamic-extent (guard-dynamic-extent - entry-guards combiner exit-guards) - This applicative extends the current continuation with the - specified guards, and calls `combiner' in the dynamic extent of - the new continuation, with no operands and the dynamic environment - of the call to `guard-dynamic-extent'. - - -- Applicative: exit (exit) - Applicative `exit' initiates an abnormal transfer of `#inert' to - `root-continuation'. - - That is: - (exit ) == (apply-continuation root-continuation #inert) - - -File: klisp.info, Node: Encapsulations, Next: Promises, Prev: Continuations, Up: Top - -10 Encapsulations -***************** - -An encapsulation is an object that refers to another object, called its -content. The Kernel data type encapsulation is encapsulated. Two -encapsulations are `equal?' iff they are `eq?'. Encapsulations are -immutable. - - -- Applicative: make-encapsulation-type (make-encapsulation-type) - Returns a list of the form `(e p? d)', where `e', `p'?, and `d' - are applicatives, as follows. Each call to - `make-encapsulation-type' returns different applicatives `e', - `p?', and `d'. - - * `e' is an applicative that takes one argument, and returns a - fresh encapsulation with the argument as content. - Encapsulations returned on different occasions are not `eq?'. - - * `p?' is a primitive type predicate, that takes zero or more - arguments and returns true iff all of them are encapsulations - generated by `e'. - - * `d' is an applicative that takes one argument; if the - argument is not an encapsulation generated by `e', an error - is signaled, otherwise the content of the encapsulation is - returned. - - That is, the predicate `p?' only recognizes, and the decapsulator - `d' only extracts the content of, encapsulations created by the - encapsulator `e' that was returned by the same call to - `make-encapsulation-type'. - - -File: klisp.info, Node: Promises, Next: Keyed Variables, Prev: Encapsulations, Up: Top - -11 Promises -*********** - -A promise is an object that represents the potential to determine a -value. The value may be the result of an arbitrary computation that -will not be performed until the value must be determined (constructor -`$lazy'); or, in advanced usage, the value may be determined before the -promise is constructed (constructor `memoize'). - - The value determined by a promise is obtained by forcing it -(applicative `force'). A given promise cannot determine different -values on different occasions that it is forced. Also, if a promise -determines its value by computation, and that computation has already -been completed, forcing the promise again will produce the previously -determined result without re-initiating the computation to determine it. - - The Kernel data type promise is encapsulated. - - The general rules for predicate `eq?' only require it to distinguish -promises if they can exhibit different behavior; the resulting leeway -for variation between implementations is similar, in both cause and -effect, to that for `eq?'-ness of operatives. For example, if two -promises, constructed on different occasions, would perform the same -computation to determine their values, and that computation has no -side-effects and must always return the same value, the promises may or -may not be `eq?'. Two promises are `equal?' iff they are `eq?'. - - -- Applicative: promise? (promise? . objects) - The primitive type predicate for type promise. `promise?' returns - true iff all the objects in `objects' are of type promise. - - -- Applicative: force (force object) - If `object' is a promise, applicative `force' returns the value - determined by promise; otherwise, it returns `object'. - - The means used to force a promise depend on how the promise was - constructed. The description of each promise constructor specifies - how to force promises constructed by that constructor. - - -- Operative: $lazy ($lazy expression) - Operative `$lazy' constructs and returns a new object of type - promise, representing potential evaluation of expression in the - dynamic environment from which `$lazy' was called. - - When the promise is forced, if a value has not previously been - determined for it, `expression' is evaluated in the dynamic - environment of the constructing call to `$lazy'. If, when the - evaluation returns a result, a value is found to have been - determined for the promise during the evaluation, the result is - discarded in favor of the previously determined value; otherwise, - the result is forced, and the value returned by that forcing - becomes the value determined by the promise. - - Forcing an undetermined lazy promise (i.e., a promise constructed - by $lazy for which no value has yet been determined) may cause a - sequential series of evaluations, each of which returns a promise - that is forced and thus initiates the next evaluation in the - series. The implementation must support series of this kind with - unbounded length (i.e., unbounded number of sequential - evaluations). - - Note that forcing concerns the value determined by a given promise, - not the result of evaluating a given expression in a given - environment. Distinct promises (judged by `eq?' represent - different occasions of evaluation; so, even if they do represent - evaluation of the same expression in the same environment, forcing - one does not necessarily determine the value for the other, and - actual evaluation will take place the first time each of them is - forced. - - -- Applicative: memoize (memoize object) - Applicative `memoize' constructs and returns a new object of type - promise, representing memoization of `object'. Whenever the - promise is forced, it determines `object'. - - -File: klisp.info, Node: Keyed Variables, Next: Numbers, Prev: Promises, Up: Top - -12 Keyed Variables -****************** - -A keyed variable is a device that associates a non-symbolic key (in the -form of an accessor applicative) with a value depending on the context -in which lookup occurs. Kernel provides two types of keyed variables: -dynamic & static. Keyed Dynamic Variables use the dynamic extent as -context and Keyed Static Variables use the dynamic environment. - -12.1 Keyed Dynamic Variables -============================ - -A keyed dynamic variable is a device that associates a non-symbolic key -(in the form of an accessor applicative) with a value depending on the -dynamic extent in which lookup occurs. - - -- Applicative: make-keyed-dynamic-variable - (make-keyed-dynamic-variable) - Returns a list of the form `(b a)', where `b' and `a' are - applicatives, as follows. Each call to - `make-keyed-dynamic-variable' returns different `b' and `a'. - - * `b' is an applicative that takes two arguments, the second of - which must be a combiner. It calls its second argument with - no operands (nil operand tree) in a fresh empty environment, - and returns the result. - - * `a' is an applicative that takes zero arguments. If the call - to `a' occurs within the dynamic extent of a call to `b', then - `a' returns the value of the first argument passed to `b' in - the smallest enclosing dynamic extent of a call to `b'. If the - call to `a' is not within the dynamic extent of any call to - `b', an error is signaled. - -12.2 Keyed Static Variables -=========================== - -A keyed static variable is a device that binds data in an environment -by a non-symbolic key, where the key is an accessor applicative. - - -- Applicative: make-keyed-static-variable (make-keyed-static-variable) - Returns a list of the form `(b a)', where `b' and `a' are - applicatives, as follows. Each call to - `make-keyed-static-variable' returns different `b' and `a'. - - * `b' is an applicative that takes two arguments, the second of - which must be an environment. It constructs and returns a - child-environment of its second argument, with initially no - local bindings. - - * `a' is an applicative that takes zero arguments. If the - dynamic environment `e' of the call to a has an improper - ancestor that was constructed by a call to `b', then a - returns the value of the first argument passed to `b' in the - first such environment encountered by a depth-first traversal - of the improper ancestors of `e'. If `e' has no improper - ancestors constructed via `b', an error is signaled. - - -File: klisp.info, Node: Numbers, Next: Strings, Prev: Keyed Variables, Up: Top - -13 Numbers -********** - -All numbers are immutable, and `equal?' iff `eq?'. The number type is -encapsulated. - - The external representation of an undefined number is `#undefined'. -The external representation of a real with no primary value is `#real' -(but this may change in the future, the report is missing the output -representation for reals with no primary values). All other rules for -externally representing numbers pertain only to defined numbers with -primary values. - - An external representation of a real number consists of optional -radix and/or exactness prefixes, optional sign (`+' or `-'), and -magnitude. The radix prefixes are `#b' (binary), `#o' (octal), `#d' -(decimal), and `#x' (hexadecimal); the default is decimal. The -exactness prefixes are `#e' (exact) and `#i' (inexact); by default, the -number is inexact iff the magnitude representation uses floating point. -If both kinds of prefixes are used, they may occur in either order. The -magnitude is either `infinity'; an unsigned integer (nonempty sequence -of digits); a ratio of unsigned integers (two unsigned integers with a -`/' between, of which the second is non-zero); or a floating point -representation. If the magnitude is `infinity', there must be an -exactness prefix and a sign, and no radix prefix. Floating point -representation can only be used with decimal radix; it consists of -nonempty integer part, point (`.'), nonempty fraction part, and -optional exponent part. The optional exponent part consists of an -exponent letter, and an (optionally signed) integer indicating a power -of ten by which to multiply the magnitude. The choice of exponent -letter makes no difference in what mathematical number is indicated by -the external representation, but does indicate internal representation -precision. Exponent letters `s', `f', `d', `f' indicate preference for -successively higher internal precision - short, float, double, long. -When reading an inexact real number, exponent letter `e' accepts the -default internal precision, which must be at least double. When -writeing an inexact real number, exponent letter `e' may be used for -the default internal precision, and must be used for any internal -number format not indicated by any of the other exponent letters. -Float and double must provide, respectively, at least as much precision -as IEEE 32-bit and 64-bit floating point standards [IE85]. For -example, `#i#xa/c' represents an inexact number using hexadecimal -notation, with signed magnitude positive five sixths (ten over twelve). -`-3.5l-2' represents an inexact number using decimal notation, with -signed magnitude negative thirty five thousandths, and requested long -precision (which must be at least IEEE 64-bit floating point). When -reading an external representation of an inexact real, the bounds on -the resulting inexact number are chosen in accordance with the -narrow-arithmetic keyed dynamic variable. - - NOTE: in klisp, all inexact numbers are stored as IEEE 64-bit -floating point. No bounding or robustness info is kept. - - -- Applicative: number? (number? . objects) - The primitive type predicate for type number. `number?' returns - true iff all the objects in `objects' are of type number. - - -- Applicative: integer? (integer? . objects) - The primitive type predicate for number subtype integer. - `integer?' returns true iff all the objects in `objects' are of - type integer. - - -- Applicative: rational? (rational? . objects) - The primitive type predicate for number subtype rational. - `rational?' returns true iff all the objects in `objects' are of - type rational. - - -- Applicative: real? (real? . objects) - The primitive type predicate for number subtype real. `real?' - returns true iff all the objects in `objects' are of type real. - - -- Applicative: finite? (finite? . numbers) - Predicate `finite?' returns true iff all the numbers in `numbers' - are finite. - - -- Applicative: exact? (exact? . numbers) - Predicate `exact?' returns true iff all the numbers in `numbers' - are exact. - - -- Applicative: inexact? (inexact? . numbers) - Predicate `inexact?' returns true iff all the numbers in `numbers' - are inexact. - - -- Applicative: robust? (robust? . numbers) - Predicate `robust?' returns true iff all the numbers in `numbers' - are robust. - - -- Applicative: undefined? (undefined? . numbers) - Predicate `undefined?' returns true iff all the numbers in - `numbers' are undefined. - - -- Applicative: =? (=? . numbers) - Applicative `=?' is a predicate that returns true iff all its - arguments are numerically equal to each other. If any of its - arguments has no primary value, an error is signaled. - - -- Applicative: <? (<? . reals) - -- Applicative: <=? (<=? . reals) - -- Applicative: >? (>? . reals) - -- Applicative: >=? (>=? . reals) - Each of these applicatives is a predicate that returns true iff - every two consecutive elements of `reals' have primary values in - the order indicated by the name of the applicative. If any - element of `reals' has no primary value, an error is signaled. - - -- Applicative: + (+ . numbers) - Applicative `+' returns the sum of the elements of numbers. If - numbers is empty, the sum of its elements is exact zero. If a - positive infinity is added to a negative infinity, the result has - no primary value. If all the elements of a cycle are zero, the - sum of the cycle is zero. If the acyclic sum of the elements of a - cycle (i.e., the sum of an acyclic list containing just those - elements) is non-zero, the sum of the cycle is positive infinity - times the acyclic sum of the elements. If the acyclic sum of the - elements of a cycle is zero, but some of the elements of the cycle - are non-zero, the sum of the cycle has no primary value. - - -- Applicative: * (* . numbers) - Applicative `*' returns the product of the elements of numbers. - If numbers is empty, the product of its elements is exact one. If - an infinity is multiplied by zero, the result has no primary - value. If the acyclic product of the elements of a cycle is real - greater than one, the product of the cycle is positive infinity. - If all the elements of a cycle are positive one, the product of - the cycle is positive one. If the acyclic product of the elements - of a cycle is positive one, but some of the elements of the cycle - are not positive one, the product of the cycle has no primary - value. If the acyclic product of the elements of a cycle has - magnitude less than one, the product of the cycle is zero. If the - acyclic product of the elements of a cycle has magnitude greater - than or equal to one, and is not positive real, the product of the - cycle has no primary value. - - -- Applicative: - (- number . numbers) - `numbers' should be a nonempty list of numbers. - - Applicative `-' returns the sum of `number' with the negation of - the sum of `numbers'. - - -- Applicative: zero? (zero? . numbers) - Applicative `zero?' is a predicate that returns true iff every - element of `numbers' is zero. For this purpose, a real number is - zero if its primary value is zero. If any element of numbers has - no primary value an error is signaled. - - -- Applicative: div (div real1 real2) - -- Applicative: mod (mod real1 real2) - -- Applicative: div-and-mod (div-and-mod real1 real2) - For all three applicatives, if `real1' is infinite or `real2' is - zero, an error is signaled. - - Let `n' be the greatest integer such that `real2 * n <= real1'. - Applicative `div' returns `n'. Applicative `mod' returns `real1 - - (real2 * n)'. Applicative `div-and-mod' returns a freshly - allocated list of length two, whose first element is `n' and whose - second element is `real1 - (real2 * n)'. - - NOTE: I'm not really sure about this description... - - -- Applicative: div0 (div0 real1 real2) - -- Applicative: mod0 (mod0 real1 real2) - -- Applicative: div0-and-mod0 (div0-and-mod0 real1 real2) - For all three applicatives, if `real1' is infinite or `real2' is - zero, an error is signaled. - - Let `n' be the greatest integer such that `real2 * n <= real1 + - |real2/2|'. Applicative `div0' returns `n'. Applicative `mod0' - returns `real1 - (real2 * n)'. Applicative `div0-and-mod0' - returns a freshly allocated list of length two, whose first - element is `n' and whose second element is `real1 - (real2 * n)'. - - NOTE: I'm not really sure about this description... - - -- Applicative: positive? (positive? . reals) - -- Applicative: negative? (negative? . reals) - Applicative `positive?' is a predicate that returns true iff every - element of `reals' is greater than zero. Applicative `negative?' - is a predicate that returns true iff every element of `reals' is - less than zero. If any argument to either applicative has no - primary value an error is signaled. - - -- Applicative: odd? (odd? . integers) - -- Applicative: even? (even? . integers) - Applicative `odd?' is a predicate that returns true iff every - element of `integers' is odd. Applicative `even?' is a predicate - that returns true iff every element of `integers' is even. If any - argument to either applicative has no primary value an error is - signaled. - - -- Applicative: (abs real) - Applicative `abs' returns the nonnegative real number with the - same magnitude as `real'; that is, if `real' is nonnegative it - returns `real', otherwise it returns the negation of `real'. - - -- Applicative: max (max . reals) - -- Applicative: min (min . reals) - If `reals' is nil, applicative `max' returns exact negative - infinity, and applicative `min' returns exact positive infinity. - If `reals' is non-nil, applicative `max' returns the largest - number in `reals', and applicative `min' returns the smallest - number in `reals'. - - -- Applicative: lcm (lcm . impints) - -- Applicative: gcd (gcd . impints) - `impints' should be a list of improper integers, that is, real - numbers each of which is either an integer or an infinity. - - Applicative `lcm' returns the smallest positive improper integer - that is an improper0integer multiple of every element of `impints' - (that is, smallest `n >= 1' such that for every argument `nk' - there exists `n'k' with `nk * n'k = n'). If any of the arguments - is zero, the result of `lcm' has no primary value. According to - these rules, `lcm' with nil argument list returns `1', and `lcm' - with any infinite argument returns positive infinity. - - Applicative `gcd' returns the largest positive improper integer - such that every element of `impints' is an improper-integer - multiple of it (that is, largest `n >= 1' such that for every - argument `nk' there exists `n'k' with `n * n'k = nk'). `gcd' with - nil argument list returns exact positive infinity. If `gcd' is - called with one or more arguments, and at least one of the - arguments is zero, but none of the arguments is a non-zero finite - integer, its result has no primary value. According to these - rules, if `gcd' is called with at least one finite non-zero - argument, its result is the same as if all zero and infinite - arguments were deleted. - - -- Applicative: get-real-internal-bounds (get-real-internal-bounds - real) - -- Applicative: get-real-exact-bounds (get-real-exact-bounds real) - Applicative `get-real-internal-bounds' returns a freshly allocated - list of reals `(x1 x2)', where the primary value of `x1' is the - lower bound of `real', using the same internal representation as - the primary value of `real', and the primary value of `x2' is the - upper bound of `real', using the same internal representation as - the primary value of `real'. The `xk' are inexact iff real is - inexact. The `xk' are robust (i.e., tagged if the implementation - supports such), and the bounds of each `xk' are only required to - contain its primary value (i.e., the implementation is allowed to - make the bounds equal to the primary value). - - Applicative `get-real-exact-bounds' returns a freshly allocated - list of exact reals `(x1 x2)', where `x1' is not greater than the - lower bound of `real', and `x2' is not less than the upper bound - of `real'. - - -- Applicative: get-real-internal-primary (get-real-internal-primary - real) - -- Applicative: get-real-exact-primary (get-real-exact-primary real) - If `real' is exact, both applicatives return `real'. If `real' - has no primary value, both applicatives signal an error. - - If `real' is inexact with a primary value, applicative - `get-real-internal-primary' returns a real number `x0' whose - primary value is the same as, and has the same internal format as, - the primary value of `real'. `x0' is robust, and its bounds are - only required to contain its primary value. - - If `real' is inexact with a primary value, applicative - `get-real-exact-primary' returns an exact real number `x0' within - the exact bounds that would be returned for `real' by applicative - `get-real-exact-bounds'. Preferably, `x0' should be as close to - the primary value of `real' as the implementation can reasonably - arrange. If the implementation does not support any exact `real' - that reasonably approximates `real', an error may be signaled. - - -- Applicative: make-inexact (make-inexact real1 real2 real3) - Applicative `make-inexact' returns an inexact real number, as - follows. If `real2' is inexact, the result has the same primary - value as `real2'; and if `real2' has no primary value, the result - has no primary value. The result has the same robustness as - `real2'. If possible, the result uses the same internal - representation as `real2'. If `real2' is exact, the primary value - of the result is as close to `real2' as the implementation can - reasonably arrange; overflow and underflow are handled as - described in .... The lower bound of the result is no greater than - the lower bound of `real1', the primary value of `real2', and the - primary value of the result. The upper bound of the result is no - less than the upper bound of `real3', the primary value of - `real2', and the primary value of the result. - - -- Applicative: real->inexact (real->inexact real) - -- Applicative: real->exact (real->exact real) - Applicative `real->exact' behaves just as `get-real-exact-primary'. - - If `real' is inexact, applicative `real->inexact' returns `real'. - If `real' is exact, applicative `real->inexact' returns an inexact - real `x0' such that `real' would be a permissible result of - passing `x0' to `real->exact'. If the implementation does not - support any such `x0', an error may be signaled. Otherwise, `x0' - is robust, and its bounds are only required to contain its primary - value and `real'. - - -- Applicative: with-strict-arithmetic (with-strict-arithmetic boolean - combiner) - -- Applicative: get-string-arithmetic (get-strict-arithmetic?) - These applicatives are the binder and accessor of the - `strict-arithmetic' keyed dynamic variable. When this keyed - variable is true, various survivable but dubious arithmetic events - signal an error - notably, operation results with no primary value, - and over- and underflows. - - -- Applicative: / (/ number . numbers) - `numbers' should be a nonempty list of numbers. - - Applicative `/' returns `number' divided by the product of - `numbers'. If the product of `numbers' is zero, an error is - signaled. If `number' is infinite and the product of `numbers' is - infinite, an error is signaled. - - -- Applicative: numerator (numerator rational) - -- Applicative: denominator (denominator rational) - These applicatives return the numerator and denominator of - `rational', in least terms (i.e., chosen for the least positive - denominator). Note that if `rational' is inexact, and either of - its bounds is not its primary value, the denominator has upper - bound positive infinity, and the numerator must have at least one - infinite bound (two infinite bounds if the bounds of rational - allow values of both signs). - - -- Applicative: floor (floor real) - -- Applicative: ceiling (ceiling real) - -- Applicative: truncate (truncate real) - -- Applicative: round (round real) - Applicative `floor' returns the largest integer not greater than - `real'. - - Applicative `ceiling' returns the smallest integer not less than - `real'. - - Applicative `truncate' returns the integer closest to `real' whose - absolute value is not greater than that of `real'. - - Applicative `round' returns the closest integer to `real', - rounding to even when `real' is halfway between two integers. - - -- Applicative: rationalize (rationalize real1 real2) - -- Applicative: simplest-rational (simplest-rational real1 real2) - A rational number `r1' is simpler than another rational `r2' if - `r1 = p1 / q1' and `r2 = p2 / q2', both in lowest terms, and `|p1| - <= |p2|' and `|q1| <= |q2|'. Thus `3/5' is simpler than `4/7'. Not - all rationals are comparable in this ordering, as for example - `2/7' and `3/5'. However, any interval (that contains rational - numbers) contains a rational number that is simpler than every - other rational number in that interval. Note that `0 = 0/1' is - simpler than any other rational (so that one never has to choose - between `p/q' and `−p/q'). - - For applicative `simplest-rational', let `x0' be the simplest - rational mathematically not less than the primary value of `real1' - and not greater than the primary value of `real2'. If no such - `x0' exists (because the primary value of `real1' is greater, or - because the primary values of the arguments are equal and - irrational), or if either argument does not have a primary value, - an error is signaled. - - For applicative `rationalize', let `x0' be the simplest rational - mathematical number within the interval bounded by the primary - value of `real1' plus and minus the primary value of `real2'. If - no such `x0' exists (because the primary value of `real1' is - irrational and the primary value `real2' is zero), or if either - argument does not have a primary value, an error is signaled. - - If `real1' and `real2' are exact, the applicative (whichever it - is) returns exact `x0'. If one or both of `real1' and `real2' are - inexact, the applicative returns an inexact rational approximating - `x0' (as by `real->inexact'. Note that an inexact result returned - is not necessarily bounded by the primary values of the arguments; - but the result is an approximation of `x0', which is so bounded, - and the bounds of the result include `x0'. - - -- Applicative: exp (exp number) - -- Applicative: log (log number) - TODO - - -- Applicative: sin (sin number) - -- Applicative: cos (cos number) - -- Applicative: tan (tan number) - TODO - - -- Applicative: asin (asin number) - -- Applicative: acos (acos number) - -- Applicative: atan (atan number1 [number2]) - TODO - - -- Applicative: sqrt (sqrt number) - -- Applicative: expt (expt number1 number2) - TODO - - -File: klisp.info, Node: Strings, Next: Characters, Prev: Numbers, Up: Top - -14 Strings -********** - -A string is an object that represent a sequence of characters (for now, -only ASCII is supported in klisp, in the future, full UNICODE will be -supported). The external representation of strings consists of a -leading """, the characters of the string and a closing """. Some -characters should be escaped, by preceding them with a "\": in klisp -these are the double quote (""") and the backslash ("\"). In the -future more advanced escape mechanism may be added (like in r7rs-draft -scheme, for escping common ASCII control codes and arbitrary unicode -characters). A string has a length that is fixed at creation time, and -as many characters, indexed from `0' to `length-1'. - - Strings may be mutable or immutable. If an attempt is made to -mutate an immutable string, an error is signaled. Two immutable -strings are "eq?" iff they are "equal?". Two mutable strings are "eq?" -if they were created by the same constructor call. Two mutable strings -are "equal?" iff they are "string=?". For now it is undefined if a -mutable and an immutable strings that are "string=?" are "equal?" or -not. The only exception is the empty string. There is only one empty -string (all empty strings are "eq?" to each other) and it should be -considered immutable. Even if an attempt is made to return a new empty -string (like calling `(string)', the canonical immutable empty string -is returned. The string type is encapsulated. - - SOURCE NOTE: This section is still missing from the report. The -features defined here were taken mostly from r5rs scheme. It is -possible that in the future, klisp only admits immutable strings (like -lua and java), and that operations for contructing strings are moved to -a new type (like Java's StringBuilder/StringBuffer). But for now, -compatibility with r5rs was preferred/simpler. - - -- Applicative: string? (string? . objects) - The primitive type predicate for type string. `string?' returns - true iff all the objects in `objects' are of type string. - - -- Applicative: string=? (string=? . strings) - -- Applicative: string<? (string<? . strings) - -- Applicative: string<=? (string<=? . strings) - -- Applicative: string>? (string>? . strings) - -- Applicative: string>=? (string>=? . strings) - These predicates compare any number of strings by their - lexicographic order. - - -- Applicative: string-ci=? (string-ci=? . strings) - -- Applicative: string-ci<? (string-ci<? . strings) - -- Applicative: string-ci<=? (string-ci<=? . strings) - -- Applicative: string-ci>? (string-ci>? . strings) - -- Applicative: string-ci>=? (string-ci>=? . strings) - These predicates convert the strings to lowercase and then compare - them using their lexicographic order. - - -- Applicative: make-string (make-string k [char]) - Applicative `make-string' constructs and returns a new mutable - string of length `k'. If `char' is specified, then all characters - in the returned string are `char', otherwise the content of the - string is unspecified. - - -- Applicative: string (string . chars) - Applicative `string' contructs and return a new mutable string - composed of the character arguments. - - -- Applicative: string-length (string-length string) - Applicative `string-length' returns the length of `string'. - - -- Applicative: string-ref (string-ref string k) - Applicative `string-ref' returns the character of `string' at - position `k'. If `k' is out of bounds (i.e. less than `0' or - greater or equal than `(length string)') an error is signaled. - - -- Applicative: string-set! (string-set! string k char) - Applicative `string-set!' replaces the character with index `k' in - `string' with character `char'. If `k' is out of bounds, or - `string' is immutable, an error is signaled. - - -- Applicative: string-fill! (string-fill! string char) - Applicative `string-fill!' replaces all the characters in `string' - with character `char'. If `string' is an immutable string, an - error is signaled. - - -- Applicative: substring (substring string k1 k2) - Both `k1' & `k2' should be valid indexes in `string'. Also it - should be the case that `k1 <= k2'. - - Applicative `substring' constructs and returns a new immutable - string with length `k2 - k1', with the characters from `string', - starting at index `k1' (inclusive) and ending at index `k2' - (exclusive). - - -- Applicative: string-append (string-append . strings) - Applicative `string-append' constructs and returns a new mutable - string consisting of the concatenation of all its arguments. - - -- Applicative: string-copy (string-copy string) - Applicative `string-copy' constructs and returns a new mutable - string with the same length and characters as `string'. - - -- Applicative: string->immutable-string (string->immutable-string - string) - Applicative `string->immutable-string' constructs and returns a - new immutable string with the same length and characters as - `string'. - - -- Applicative: string->list (string->list string) - -- Applicative: list->string (list->string chars) - Applicatives `string->list' and `list->string' convert between - strings and list of characters. The strings returned by - `list->string' are mutable. - - -File: klisp.info, Node: Characters, Next: Ports, Prev: Strings, Up: Top - -15 Characters -************* - -A character is an object that represents an ASCII character (for now, -only ASCII is supported in klisp, in the future, full UNICODE will be -supported). The external representation of characters consists of a -leading "#\" and the character or character name. The only supported -names for now are "newline" and "space" (both from r5rs scheme). -Characters are immutable. The character type is encapsulated. - - SOURCE NOTE: This section is still missing from the report. The -features defined here were taken mostly from r5rs scheme. - - -- Applicative: char? (char? . objects) - The primitive type predicate for type character. `char?' returns - true iff all the objects in `objects' are of type character. - - -- Applicative: char=? (char=? . chars) - -- Applicative: char<? (char<? . chars) - -- Applicative: char<=? (char<=? . chars) - -- Applicative: char>? (char>? . chars) - -- Applicative: char>=? (char>=? . chars) - These predicates compare any number of characters using their - ASCII value for the comparison. - - -- Applicative: char-ci=? (char-ci=? . chars) - -- Applicative: char-ci<? (char-ci<? . chars) - -- Applicative: char-ci<=? (char-ci<=? . chars) - -- Applicative: char-ci>? (char-ci>? . chars) - -- Applicative: char-ci>=? (char-ci>=? . chars) - These predicates convert the chars to lowercase and then compare - their ASCII values. - - -- Applicative: char-alphabetic? (char-alphabetic? . chars) - -- Applicative: char-numeric? (char-numeric? . chars) - -- Applicative: char-whitespace? (char-whitespace? . chars) - These predicates return true iff all of their arguments are - respectively "alphabetic", "numeric", or "whitespace". - - -- Applicative: char-upper-case? (char-upper-case? . chars) - -- Applicative: char-lower-case? (char-lower-case? . chars) - These predicates return true iff all of their arguments are - respectively "upper case, or "lower case". - - -- Applicative: char-upcase (char-upcase char) - -- Applicative: char-downcase (char-downcase char) - These applicatives return a character `char2' so that: - (char-ci=? char char2) => #t - - If `char' is alphabetic then the following holds: - - (char-upper-case? (char-upcase char)) => #t - (char-lower-case? (char-downcase char)) => #t - - -- Applicative: char->integer (char->integer char) - -- Applicative: integer->char (integer->char k) - These applicatives convert between ASCII values (as exact integers - between 0 and 127) and characters. If an integer that is out of - range for ASCII characters is passed to `integer->char', an error - is signaled. - - -File: klisp.info, Node: Ports, Next: Alphabetical Index, Prev: Characters, Up: Top - -16 Ports -******** - -A port is an object that mediates data from an input or to a -destination. In the former case, the port is an input port, in the -latter case, an output port. The data itself can consist of either -characters or bytes. In the former case the port is a textual port and -in the latter case, a binary port. - - There are three textual ports open, binded by dynamic variables, one -for standard input, output, and error. - - Although ports are not considered immutable, none of the operations -on ports described in this section constitute mutation. Ports are -`equal?' iff `eq?'. The port type is encapsulated. - - An auxiliary data type used to signal the end of file was reached is -`eof'. The eof type consists of a single immutable value, having an -output only external representation (so that it can never be the normal -result of a call to read). The eof type is encapsulated. - - SOURCE NOTE: the eof type is not in the Kernel report, it is used in -klisp and was taken from Scheme. - - -- Applicative: port? (port? . objects) - The primitive type predicate for type port. `port?' returns true - iff all the objects in `objects' are of type port. - - -- Applicative: input-port? (input-port? . objects) - -- Applicative: output-port? (output-port? . objects) - Applicative `input-port?' is a predicate that returns true unless - one or more of its arguments is not an input port. Applicative - `output-port?' is a predicate that returns true unless one or more - of its arguments is not an output port. - - Every port must be admitted by at least one of these two - predicates. - - -- Applicative: textual-port? (textual-port? . objects) - -- Applicative: binary-port? (binary-port? . objects) - Applicative `textual-port?' is a predicate that returns true - unless one or more of its arguments is not a textual port. - Applicative `binary-port?' is a predicate that returns true unless - one or more of its arguments is not a binary port. - - Every port must be admitted by at least one of these two - predicates. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- with-input-from-file: (with-input-from-file string combiner) - -- with-output-to-file: (with-output-to-file string combiner) - -- with-error-to-file: (with-error-to-file string combiner) - These three applicatives open the file named in `string' for - textual input or output, an invoke the binder of either the - input-port, the output-port or the error-port keyed dynamic - variables respectively with the opened port & the passed - `combiner' (this means that the combiner is called in a fresh, - empty dynamic environment). When/if the binder normally returns, - the port is closed. The result of the applicatives - `with-input-from-file' and `with-output-from-file' is inert. - - SOURCE NOTE: The first two are enumerated in the Kernel report but - the text is still missing. The third applicative is from Scheme. - - -- get-current-input-port: (get-current-input-port) - -- get-current-output-port: (get-current-output-port) - -- get-current-error-port: (get-current-error-port) - These are the accessors for the input-port, output-port, and - error-port keyed dynamic variables repectively. - - SOURCE NOTE: The first two are enumerated in the Kernel report but - the text is still missing. The third applicative is from Scheme. - - -- Applicative: open-input-file (open-input-file string) - -- Applicative: open-binary-input-file (open-binary-input-file string) - `string' should be the name/path for an existing file. - - Applicative `open-input-file' creates and returns a textual input - port associated with the file represented with `string'. - Applicative `open-binary-input-file' creates and returns a binary - input port associated with the file represented with `string'. In - either case, if the file can't be opened (e.g. because it doesn't - exists, or there's a permissions problem), an error is signaled. - - SOURCE NOTE: open-input-file is enumerated in the Kernel report but - the text is still missing. open-binary-input-file is from Scheme. - - -- Applicative: open-output-file (open-output-file string) - -- Applicative: open-binary-output-file (open-binary-output-file - string) - `string' should be the name/path for an existing file. - - Applicative `open-output-file' creates and returns a textual - output port associated with the file represented with `string'. - Applicative `open-binary-output-file' creates and returns a binary - output port associated with the file represented with `string'. - In either case, if the file can't be opened (e.g. if there's a - permissions problem), an error is signaled. - - In klisp, for now, applicative `open-output-file' and - `open-binary-output-file' truncate the file if it already exists, - but that could change later (i.e. like in Scheme the behaviour - should be considered unspecified). - - SOURCE NOTE: open-output-file is enumerated in the Kernel report - but the text is still missing. open-binary-output-file is from - Scheme. - - -- close-input-file: (close-input-file input-port) - -- close-output-file: (close-output-file output-port) - These applicatives close the port argument, so that no more - input/output may be performed on them, and the resources can be - freed. If the port was already closed these applicatives have no - effect. - - The result returned by applicatives `close-input-file' and - `close-output-file' is inert. - - SOURCE NOTE: this is enumerated in the Kernel report but the text - is still missing. There's probably a name error here. These - should probably be called close-input-port & close-output-port. - - -- close-input-port: (close-input-port input-port) - -- close-output-port: (close-output-port output-port) - -- close-port: (close-port port) - These applicatives close the port argument, so that no more - input/output may be performed on them, and the resources can be - freed. If the port was already closed these applicatives have no - effect. If at some time klisp provided input/ouput ports these - could be used to selectively close only one direction of the port. - - The result returned by applicatives `close-input-port', - `close-output-port', and `close-port' is inert. - - SOURCE NOTE: this is from Scheme. The equivalent - `close-input-file' and `close-output-file' are probably name - errors and only retained here till the draft standard rectifies - them - - -- Applicative: read (read [textual-input-port]) - If the `port' optional argument is not specified, then the value - of the `input-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `read' reads & returns the next parseable object from - the given port, or the `eof' if no objects remain. If `read' - finds and unparseable object in the port, an error is signaled. - In that case, the remaining position in the port is unspecified. - - SOURCE NOTE: this is enumerated in the Kernel report but the text - is still missing. - - -- write: (write object [textual-output-port]) - If the `port' optional argument is not specified, then the value - of the `output-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `write' writes an external representation of `object' - to the specified port. This may be an output-only representation - that can't be read by applicative `read' in cases where the type - of `object' doen't have a parseable external representation (e.g. - combiners and environments). The result returned by `write' is - inert. - - SOURCE NOTE: this is enumerated in the Kernel report but the text - is still missing. - - -- Applicative: call-with-input-file (call-with-input-file string - combiner) - -- Applicative: call-with-output-file (call-with-output-file string - combiner) - These applicatives open file named in `string' for textual - input/output respectively and call their `combiner' argument in a - fresh empty environment passing it as a sole operand the opened - port. When/if the combiner normally returns a value the port is - closed and that value is returned as the result of the applicative. - - SOURCE NOTE: this is enumerated in the Kernel report but the text - is still missing. - - -- Applicative: load (load string) - Applicative `load' opens the file named `string' for textual - input; reads objects from the file until the end of the file is - reached; evaluates those objects consecutively in the created - environment. The result from applicative `load' is inert. - - SOURCE NOTE: load is enumerated in the Kernel report, but the - description is not there yet. This seems like a sane way to define - it, taking the description of `get-module' that there is in the - report. The one detail that I think is still open, is whether to - return `#inert' (as is the case with klisp currently) or rather - return the value of the last evaluation. - - -- Applicative: get-module (get-module string [environment]) - Applicative `get-module' creates a fresh standard environment; - opens the file named `string' for textual input; reads objects - from the file until the end of the file is reached; evaluates those - objects consecutively in the created environment; and, lastly, - returns the created environment. If the optional argument - `environment' is specified, the freshly created standard - environment is augmented, prior to evaluating read expressions, by - binding symbol `module-parameters' to the `environment' argument. - - -- Applicative: eof-object? (eof-object? . objects) - The primitive type predicate for type eof. `eof-object?' returns - true iff all the objects in `objects' are of type eof. - - SOURCE NOTE: This is not in the report, the idea is from Scheme. - The `eof-object?' name is also from Scheme, but this will probably - be changed to just `eof?', for consistency with the other - primitive type predicates. - - -- read-char: (read-char [textual-input-port]) - If the `port' optional argument is not specified, then the value - of the `input-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `read-char' reads and returns a character (not an - external representation of a character) from the specified port, or - an `eof' if the end of file was reached. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- peek-char: (peek-char [textual-input-port]) - If the `port' optional argument is not specified, then the value - of the `input-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `peek-char' reads and returns a character (not an - external representation of a character) from the specified port, or - an `eof' if the end of file was reached. The position of the port - remains unchanged so that new call to `peek-char' or `read-char' - on the same port return the same character. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- char-ready?: (char-ready? [textual-input-port]) - If the `port' optional argument is not specified, then the value - of the `input-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Predicate `char-ready?' checks to see if a character is available - in the specified port. If it returns true, then a `read-char' or - `peek-char' on that port is guaranteed not to block/hang. For now - in klisp this is hardcoded to `#t' because the code to do this is - non-portable. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- write-char: (write-char char [textual-output-port]) - If the `port' optional argument is not specified, then the value - of the `output-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `write-char' writes the `char' character (not an - external representation of the character) to the specified port. - The result returned by `write-char' is inert. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- newline: (newline [textal-ouput-port]) - If the `port' optional argument is not specified, then the value - of the `output-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `newline' writes a newline to the specified port. The - result returned by `newline' is inert. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- display: (display object [textual-output-port]) - If the `port' optional argument is not specified, then the value - of the `output-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `display' behaves like `write' except that strings are - not enclosed in double quotes and no character is escaped within - those strings and character objects are output as if by - `write-char' instead of `read'. The result returned by `display' - is inert. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- read-u8: (read-u8 [textual-input-port]) - If the `port' optional argument is not specified, then the value - of the `input-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `read-u8' reads and returns a byte as an exact - unsigned integer between 0 and 255 inclusive (not an external - representation of a byte) from the specified port, or an `eof' if - the end of file was reached. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- peek-u8: (peek-u8 [textual-input-port]) - If the `port' optional argument is not specified, then the value - of the `input-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `peek-u8' reads and returns a byte as an exact - unsigned integer between 0 and 255 inclusive (not an external - representation of a byte) from the specified port, or an `eof' if - the end of file was reached. The position of the port remains - unchanged so that new call to `peek-u8' or `read-u8' on the same - port return the same byte. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- u8-ready?: (u8-ready? [textual-input-port]) - If the `port' optional argument is not specified, then the value - of the `input-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Predicate `u8-ready?' checks to see if a byte is available in the - specified port. If it returns true, then a `read-u8' or `peek-u8' - on that port is guaranteed not to block/hang. For now in klisp - this is hardcoded to `#t' because the code to do this is - non-portable. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- write-u8: (write-u8 u8 [textual-output-port]) - If the `port' optional argument is not specified, then the value - of the `output-port' keyed dynamic variable is used. If the port - is closed, an error is signaled. - - Applicative `write-u8' writes the byte represented by the unsigned - integer `u8', that should be between 0 and 255 inclusive, (not an - external representation of byte) to the specified port. The - result returned by `write-u8' is inert. - - SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - - -- flush-output-port: (flush-output-port [output-port]) - If the `port' optional argument is not specified, then the value - of the `output-port' keyed dynamic variable is used. If the - `port' is closed or if it is not an output port, an error is - signaled. - - Applicative `flush-ouput-port' flushes any buffered data in the - output port to the underlying file or device. The result returned - by `flush-output-port' is inert. - - SOURCE NOTE: this is missing from Kernel, it is taken from r7rs - Scheme. - - -- file-exists?: (file-exists? string) - `string' should be the name/path for a file. - - Predicate `file-exists?' checks to see if a file named `string' - exists. - - SOURCE NOTE: this is missing from Kernel, it is taken from r7rs - Scheme. - - -- delete-file: (delete-file string) - `string' should be the name/path for an existing file. - - Applicative `delete-file' deletes the file named `string'. If it - doesn't exists or can't be deleted, an error is signaled. The - result returned by `delete-file' is inert. - - SOURCE NOTE: this is missing from Kernel, it is taken from r7rs - Scheme. - - -- rename-file: (rename-file string1 string2) - `string1' should be the name/path for an existing file, `string2' - should be the name/path for a non existing file. - - Applicative `rename-file' renames the file named `string1' to - `string2'. If the file doesn't exists or can't be renamed for any - reason, an error is signaled. The result returned by `rename-file' - is inert. - - SOURCE NOTE: this is missing from Kernel AND Scheme, it is taken - from C, being quite similar to `delete-file'. - - -File: klisp.info, Node: Alphabetical Index, Next: (dir), Prev: Ports, Up: Top - -Index -***** - - -* Menu: - -* $and?: Booleans. (line 28) -* $binds?: Environments. (line 108) -* $cond: Control. (line 32) -* $define!: Environments. (line 49) -* $if: Control. (line 15) -* $import!: Environments. (line 207) -* $lambda: Combiners. (line 76) -* $lazy: Promises. (line 43) -* $let: Environments. (line 89) -* $let*: Environments. (line 124) -* $let-redirect: Environments. (line 153) -* $let-safe: Environments. (line 161) -* $letrec: Environments. (line 137) -* $letrec*: Environments. (line 144) -* $or?: Booleans. (line 41) -* $provide!: Environments. (line 191) -* $remote-eval: Environments. (line 169) -* $sequence: Control. (line 23) -* $set!: Environments. (line 182) -* $vau: Combiners. (line 26) -* ( <1>: Ports. (line 54) -* ( <2>: Numbers. (line 193) -* ( <3>: Continuations. (line 143) -* (: Environments. (line 174) -* *: Numbers. (line 121) -* +: Numbers. (line 109) -* -: Numbers. (line 137) -* /: Numbers. (line 306) -* <=?: Numbers. (line 101) -* <?: Numbers. (line 100) -* =?: Numbers. (line 95) -* >=?: Numbers. (line 103) -* >?: Numbers. (line 102) -* acos: Numbers. (line 385) -* and?: Booleans. (line 20) -* append: Pairs and lists. (line 208) -* append!: Pairs and lists. (line 306) -* applicative descriptions: A Sample Applicative Description. - (line 6) -* applicative?: Combiners. (line 21) -* applicatives: Combiners. (line 6) -* apply: Combiners. (line 83) -* apply-continuation: Continuations. (line 134) -* asin: Numbers. (line 384) -* assoc: Pairs and lists. (line 252) -* assq: Pairs and lists. (line 333) -* atan: Numbers. (line 386) -* binary-port?: Ports. (line 43) -* boolean?: Booleans. (line 12) -* booleans: Booleans. (line 6) -* caaaar: Pairs and lists. (line 101) -* caaadr: Pairs and lists. (line 102) -* caaar: Pairs and lists. (line 93) -* caadar: Pairs and lists. (line 103) -* caaddr: Pairs and lists. (line 104) -* caadr: Pairs and lists. (line 94) -* caar: Pairs and lists. (line 89) -* cadaar: Pairs and lists. (line 105) -* cadadr: Pairs and lists. (line 106) -* cadar: Pairs and lists. (line 95) -* caddar: Pairs and lists. (line 107) -* cadddr: Pairs and lists. (line 108) -* caddr: Pairs and lists. (line 96) -* cadr: Pairs and lists. (line 90) -* call-with-input-file: Ports. (line 173) -* call-with-output-file: Ports. (line 175) -* call/cc: Continuations. (line 43) -* car: Pairs and lists. (line 85) -* cdaaar: Pairs and lists. (line 109) -* cdaadr: Pairs and lists. (line 110) -* cdaar: Pairs and lists. (line 97) -* cdadar: Pairs and lists. (line 111) -* cdaddr: Pairs and lists. (line 112) -* cdadr: Pairs and lists. (line 98) -* cdar: Pairs and lists. (line 91) -* cddaar: Pairs and lists. (line 113) -* cddadr: Pairs and lists. (line 114) -* cddar: Pairs and lists. (line 99) -* cdddar: Pairs and lists. (line 115) -* cddddr: Pairs and lists. (line 116) -* cdddr: Pairs and lists. (line 100) -* cddr: Pairs and lists. (line 92) -* cdr: Pairs and lists. (line 86) -* ceiling: Numbers. (line 325) -* char->integer: Characters. (line 58) -* char-alphabetic?: Characters. (line 37) -* char-ci<=?: Characters. (line 31) -* char-ci<?: Characters. (line 30) -* char-ci=?: Characters. (line 29) -* char-ci>=?: Characters. (line 33) -* char-ci>?: Characters. (line 32) -* char-downcase: Characters. (line 49) -* char-lower-case?: Characters. (line 44) -* char-numeric?: Characters. (line 38) -* char-upcase: Characters. (line 48) -* char-upper-case?: Characters. (line 43) -* char-whitespace?: Characters. (line 39) -* char<=?: Characters. (line 23) -* char<?: Characters. (line 22) -* char=?: Characters. (line 21) -* char>=?: Characters. (line 25) -* char>?: Characters. (line 24) -* char?: Characters. (line 17) -* characters: Characters. (line 6) -* combiner?: Combiners. (line 120) -* combiners: Combiners. (line 6) -* cons: Pairs and lists. (line 35) -* continuation->applicative: Continuations. (line 95) -* continuation?: Continuations. (line 38) -* continuations: Continuations. (line 6) -* control: Control. (line 6) -* copy-es: Pairs and lists. (line 321) -* copy-es-immutable!: Pairs and lists. (line 49) -* cos: Numbers. (line 380) -* countable-list?: Pairs and lists. (line 265) -* denominator: Numbers. (line 315) -* description format: Format of Descriptions. - (line 6) -* div: Numbers. (line 149) -* div-and-mod: Numbers. (line 151) -* div0: Numbers. (line 163) -* div0-and-mod0: Numbers. (line 165) -* documentation notation: Evaluation Notation. (line 6) -* empty list: Pairs and lists. (line 6) -* encapsulations: Encapsulations. (line 6) -* encycle!: Pairs and lists. (line 158) -* environment?: Environments. (line 23) -* environments: Environments. (line 6) -* eof-object?: Ports. (line 208) -* eq?: Equivalence. (line 12) -* equal?: Equivalence. (line 16) -* equivalence: Equivalence. (line 6) -* error message notation: Error Messages. (line 6) -* error-continuation: Continuations. (line 110) -* eval: Environments. (line 32) -* evaluation notation: Evaluation Notation. (line 6) -* even?: Numbers. (line 186) -* exact?: Numbers. (line 79) -* exit: Continuations. (line 162) -* exp: Numbers. (line 375) -* expt: Numbers. (line 390) -* extend-continuation: Continuations. (line 50) -* filter: Pairs and lists. (line 239) -* finite-list?: Pairs and lists. (line 261) -* finite?: Numbers. (line 75) -* floor: Numbers. (line 324) -* fonts: Some Terms. (line 13) -* foo: A Sample Applicative Description. - (line 15) -* for-each: Control. (line 42) -* force: Promises. (line 35) -* gcd: Numbers. (line 207) -* get-current-environment: Environments. (line 114) -* get-list-metrics: Pairs and lists. (line 123) -* get-module: Ports. (line 198) -* get-real-exact-bounds: Numbers. (line 233) -* get-real-exact-primary: Numbers. (line 252) -* get-real-internal-bounds: Numbers. (line 232) -* get-real-internal-primary: Numbers. (line 251) -* get-string-arithmetic: Numbers. (line 299) -* guard-continuation: Continuations. (line 63) -* guard-dynamic-extent: Continuations. (line 156) -* ignore: Environments. (line 6) -* ignore?: Environments. (line 28) -* inert: Control. (line 6) -* inert?: Control. (line 11) -* inexact?: Numbers. (line 83) -* input-port?: Ports. (line 32) -* integer->char: Characters. (line 59) -* integer?: Numbers. (line 61) -* Kernel history: Kernel History. (line 6) -* keyed dynamic variables: Keyed Variables. (line 15) -* keyed static variables: Keyed Variables. (line 40) -* keyed variables: Keyed Variables. (line 6) -* lcm: Numbers. (line 206) -* length: Pairs and lists. (line 191) -* list: Pairs and lists. (line 72) -* list*: Pairs and lists. (line 78) -* list->string: Strings. (line 109) -* list-neighbors: Pairs and lists. (line 228) -* list-ref: Pairs and lists. (line 198) -* list-tail: Pairs and lists. (line 147) -* lists: Pairs and lists. (line 6) -* load: Ports. (line 185) -* log: Numbers. (line 376) -* make-encapsulation-type: Encapsulations. (line 12) -* make-environment: Environments. (line 36) -* make-inexact: Numbers. (line 270) -* make-kernel-standard-environment: Environments. (line 119) -* make-keyed-dynamic-variable: Keyed Variables. (line 21) -* make-keyed-static-variable: Keyed Variables. (line 44) -* make-string: Strings. (line 57) -* map <1>: Combiners. (line 96) -* map: Pairs and lists. (line 169) -* max: Numbers. (line 198) -* member?: Pairs and lists. (line 257) -* memoize: Promises. (line 74) -* memq?: Pairs and lists. (line 338) -* min: Numbers. (line 199) -* mod: Numbers. (line 150) -* mod0: Numbers. (line 164) -* negative?: Numbers. (line 178) -* nil: Pairs and lists. (line 6) -* not?: Booleans. (line 16) -* null?: Pairs and lists. (line 31) -* number?: Numbers. (line 57) -* numbers: Numbers. (line 6) -* numerator: Numbers. (line 314) -* object descriptions: A Sample Applicative Description. - (line 6) -* odd?: Numbers. (line 185) -* open-binary-input-file: Ports. (line 79) -* open-binary-output-file: Ports. (line 94) -* open-input-file: Ports. (line 78) -* open-output-file: Ports. (line 92) -* operative descriptions: A Sample Applicative Description. - (line 6) -* operative?: Combiners. (line 16) -* operatives: Combiners. (line 6) -* or?: Booleans. (line 24) -* output-port?: Ports. (line 33) -* pair?: Pairs and lists. (line 27) -* pairs: Pairs and lists. (line 6) -* port?: Ports. (line 28) -* ports: Ports. (line 6) -* positive?: Numbers. (line 177) -* printing notation: Printing Notation. (line 6) -* promise?: Promises. (line 31) -* promises: Promises. (line 6) -* rational?: Numbers. (line 66) -* rationalize: Numbers. (line 340) -* read: Ports. (line 144) -* real->exact: Numbers. (line 286) -* real->inexact: Numbers. (line 285) -* real?: Numbers. (line 71) -* reduce: Pairs and lists. (line 270) -* robust?: Numbers. (line 87) -* root-continuation: Continuations. (line 104) -* round: Numbers. (line 327) -* set-car!: Pairs and lists. (line 41) -* set-cdr!: Pairs and lists. (line 42) -* simplest-rational: Numbers. (line 341) -* sin: Numbers. (line 379) -* sqrt: Numbers. (line 389) -* string: Strings. (line 63) -* string->immutable-string: Strings. (line 103) -* string->list: Strings. (line 108) -* string->symbol: Symbols. (line 20) -* string-append: Strings. (line 94) -* string-ci<=?: Strings. (line 51) -* string-ci<?: Strings. (line 50) -* string-ci=?: Strings. (line 49) -* string-ci>=?: Strings. (line 53) -* string-ci>?: Strings. (line 52) -* string-copy: Strings. (line 98) -* string-fill!: Strings. (line 80) -* string-length: Strings. (line 67) -* string-ref: Strings. (line 70) -* string-set!: Strings. (line 75) -* string<=?: Strings. (line 43) -* string<?: Strings. (line 42) -* string=?: Strings. (line 41) -* string>=?: Strings. (line 45) -* string>?: Strings. (line 44) -* string?: Strings. (line 37) -* strings: Strings. (line 6) -* substring: Strings. (line 85) -* symbol->string: Symbols. (line 16) -* symbol?: Symbols. (line 12) -* symbols: Symbols. (line 6) -* tan: Numbers. (line 381) -* textual-port?: Ports. (line 42) -* truncate: Numbers. (line 326) -* undefined?: Numbers. (line 91) -* unwrap: Combiners. (line 72) -* with-strict-arithmetic: Numbers. (line 298) -* wrap: Combiners. (line 68) -* zero?: Numbers. (line 143) - - - -Tag Table: -Node: Top703 -Node: License2601 -Node: Introduction4283 -Node: Caveats7213 -Node: Kernel History7999 -Node: Conventions9444 -Node: Some Terms10115 -Node: Evaluation Notation10786 -Node: Printing Notation11807 -Node: Error Messages12283 -Node: Format of Descriptions12931 -Node: A Sample Applicative Description13495 -Node: Acknowledgements15258 -Node: Booleans15644 -Node: Equivalence18186 -Node: Symbols18979 -Node: Control20345 -Node: Pairs and lists22662 -Node: Environments39685 -Node: Combiners49892 -Node: Continuations55928 -Node: Encapsulations64102 -Node: Promises65555 -Node: Keyed Variables69478 -Node: Numbers72249 -Node: Strings91748 -Node: Characters97095 -Node: Ports99805 -Node: Alphabetical Index117409 - -End Tag Table diff --git a/manual/src/continuations.texi b/manual/src/continuations.texi @@ -1,198 +0,0 @@ -@c -*-texinfo-*- -@setfilename ../src/continuations - -@node Continuations, Encapsulations, Combiners, Top -@comment node-name, next, previous, up - -@chapter Continuations -@cindex continuations - - A continuation is a plan for all future computation, parameterized -by a value to be provided, and contingent on the states of all mutable -data structures (which notably may include environments). When the -Kernel evaluator is invoked, the invoker provides a continuation to -which the result of the evaluation will normally be returned. - - For example, when @code{$if} evaluates its test operand, the -continuation provided for the result expects to be given a boolean -value; and, depending on which boolean it gets, it will evaluate -either the consequent or the alternative operand as a tail context — -that is, the continuation provided for the result of evaluating the -selected operand is the same continuation that was provided for the -result of the call to @code{$if}. - - A Kernel program may sometimes capture a continuation; that is, -acquire a reference to it as a first-class object. The basic means of -continuation capture is applicative @code{call/cc}. Given a -first-class continuation @code{c}, a combiner can be constructed that -will abnormally pass its operand tree to @code{c} (as opposed to the -@c TODO add xref to abnormal pass -normal return of values to continuations). In the simplest case, the -abnormally passed value arrives at @code{c} as if it had been normally -returned to @code{c}. In general, continuations bypassed by the -abnormal pass may have entry/exit guards attached to them, and these -guards can intercept the abnormal pass before it reaches @code{c}. -Each entry/exit guard consists of a selector continuation, which -designates which abnormal passes the guard will intercept, and an -interceptor applicative that performs the interception when selected. -@c TODO add xref to guard-continuation, continuation->applicative -@c and abnormal pass - - Continuations are immutable, and are @code{equal?} iff @code{eq?}. -The continuation type is encapsulated. - -@c TODO add dynamic extent & guard selection/interception to the intro -@deffn Applicative continuation? (continuation? . objects) - The primitive type predicate for type continuation. -@code{continuation?} returns true iff all the objects in -@code{objects} are of type continuation. -@end deffn - -@deffn Applicative call/cc (call/cc combiner) - Calls @code{combiner} in the dynamic environment as a tail context, -passing as sole operand to it the continuation to which @code{call/cc} -would normally return its result. (That is, constructs such a -combination and evaluates it in the dynamic environment.) -@c TODO add xref Cf. operative $let/cc , §7.3.2. -@end deffn - -@deffn Applicative extend-continuation (extend-continuation continuation applicative [environment]) - The @code{extend-continuation} applicative constructs and returns a -new child of @code{continuation} that, when it normally receives a -value v, calls the underlying combiner of @code{applicative} with -dynamic environment @code{environment} (or an empty environment if -none was specified) and operand tree @code{v}, the result of the call -normally to be returned to @code{continuation}. - - The following equivalnece defines the short version: -@example -(extend-continuation c a) @equiv{} - (extend-continuation c a (make-environment)) -@end example -@end deffn - -@deffn Applicative guard-continuation (guard-continuation entry-guards continuation exit-guards) - @code{entry-guards} and @code{exit-guards} should each be a list of -clauses; each clause should be a list of length two, whose first -element is a continuation, and whose second element is an applicative -whose underlying combiner is operative. - - Applicative @code{guard-continuation} constructs two continuations: -a child of continuation, called the @code{outer continuation}; and a -child of the @code{outer continuation}, called the @code{inner -continuation}. The @code{inner continuation} is returned as the -result of the call to @code{guard-continuation}. - - When the @code{inner continuation} normally receives a value, it -passes the value normally to the @code{outer continuation}; and when -the @code{outer continuation} normally receives a value, it passes the -value normally to @code{continuation}. Thus, in the absence of -abnormal passing, the inner and outer continuations each have the same -behavior as @code{continuation}. - - The two elements of each guard clause are called, respectively, the -@code{selector} and the @code{interceptor}. The @code{selector} -continuation is used in deciding whether to intercept a given abnormal -pass, and the @code{interceptor} applicative is called to perform -@c TODO add xref to selection and interception -customized action when interception occurs. - -@c TODO add xref to evaluation structure -At the beginning of the call to @code{guard-continuation}, internal -copies are made of the evaluation structures of @code{entry-guards} -and @code{exit-guards}, so that the selectors and interceptors -contained in the arguments at that time remain fixed thereafter, -independent of any subsequent mutations to the arguments. -@end deffn - -@deffn Applicative continuation->applicative (continuation->applicative continuation) - Returns an applicative whose underlying operative abnormally passes -its operand tree to @code{continuation}, thus: A series of -interceptors are selected to handle the abnormal pass, and a -continuation is derived that will normally perform all the -interceptions in sequence and pass some value to the destination of -the originally abnormal pass. The operand tree is then normally -passed to the derived continuation. -@c TODO add xref to selection and interception -@end deffn - -@defvar root-continuation - This continuation is the ancestor of all other continuations. When -it normally receives a value, it terminates the Kernel session. (For -example, if the system is running a read-eval-print loop, it exits the -loop.) -@c TODO add xref Cf. applicative exit, §7.3.4. -@end defvar - -@defvar error-continuation - The dynamic extent of this continuation is mutually disjoint from -the dynamic extent in which Kernel computation usually occurs (such as -the dynamic extent in which the Kernel system would run a -read-eval-print loop). - - When this continuation normally receives a value, it provides a -diagnostic message to the user of the Kernel system, on the assumption -that the received value is an attempt to describe some error that -aborted a computation; and then resumes operation of the Kernel system -at some point that is outside of all user-defined computation. (For -example, if the system is running a read-eval-print loop, operation -may resume by continuing from the top of the loop.) - - The diagnostic message is not made available to any Kernel -computation, and is therefore permitted to contain information that -violates abstractions within the system. - -@c TODO add details about klisp error messages - When an error is signaled during a Kernel computation, the signaling -action consists of an abnormal pass to some continuation in the -dynamic extent of @code{error-continuation}. -@end defvar - -@deffn Applicative apply-continuation (apply-continuation continuation object) - Applicative @code{apply-continuation} converts its first argument to -an applicative as if by @code{continuation->applicative}, and then -applies it as usual. - - That is: -@example -(apply-continuation continuation object) @equiv{} - (apply (continuation->applicative continuation) object) -@end example -@end deffn - -@deffn Operative ($let/cc <symbol> . <objects>) - A child environment @code{e} of the dynamic environment is created, -containing a binding of @code{<symbol>} to the continuation to which -the result of the call to @code{$let/cc} should normally return; then, -the subexpressions of @code{<objects>} are evaluated in @code{e} from -left to right, with the last (if any) evaluated as a tail context, or -if @code{<objects>} is empty the result is inert. - - That is: -@example -($let/cc symbol . objects) @equiv{} - (call/cc ($lambda (symbol) . objects)) -@end example -@end deffn - -@deffn Applicative guard-dynamic-extent (guard-dynamic-extent entry-guards combiner exit-guards) - This applicative extends the current continuation with the specified -guards, and calls @code{combiner} in the dynamic extent of the new -continuation, with no operands and the dynamic environment of the call -to @code{guard-dynamic-extent}. -@end deffn - -@deffn Applicative exit (exit) -@c TODO add xref - Applicative @code{exit} initiates an abnormal transfer of -@code{#inert} to @code{root-continuation}. - - That is: -@example -(exit ) @equiv{} (apply-continuation root-continuation #inert) -@end example -@end deffn - - - - diff --git a/src/Makefile b/src/Makefile @@ -33,14 +33,14 @@ PLATS= generic mingw posix KRN_A= libklisp.a CORE_O= kobject.o ktoken.o kpair.o kstring.o ksymbol.o kread.o \ kwrite.o kstate.o kmem.o kerror.o kauxlib.o kenvironment.o \ - kcontinuation.o koperative.o kapplicative.o keval.o krepl.o kscript.o \ - kencapsulation.o kpromise.o kport.o kinteger.o krational.o \ + kcontinuation.o koperative.o kapplicative.o keval.o krepl.o \ + kencapsulation.o kpromise.o kport.o kinteger.o krational.o ksystem.o \ kreal.o ktable.o kgc.o imath.o imrat.o kbytevector.o kvector.o \ - kground.o kghelpers.o kgbooleans.o kgeqp.o kgequalp.o \ + kchar.o kground.o kghelpers.o kgbooleans.o kgeqp.o kgequalp.o \ kgsymbols.o kgcontrol.o kgpairs_lists.o kgpair_mut.o kgenvironments.o \ kgenv_mut.o kgcombiners.o kgcontinuations.o kgencapsulations.o \ kgpromises.o kgkd_vars.o kgks_vars.o kgports.o kgchars.o kgnumbers.o \ - kgstrings.o kgbytevectors.o kgvectors.o kgsystem.o kgerror.o \ + kgstrings.o kgbytevectors.o kgvectors.o kgsystem.o kgerrors.o \ $(if $(USE_LIBFFI),kgffi.o) # TEMP: in klisp there is no distinction between core & lib @@ -104,10 +104,9 @@ mingw: "MINGW_LDFLAGS=$(if $(USE_LIBFFI), $(MINGW_LIBFFI_LDFLAGS) -lffi.dll)" \ "MYLDFLAGS=-s" klisp.exe #lisp_use_posix isn't used right now... -# TEMP: rename read() and write() here to avoid name conflicts with foreign code posix: $(MAKE) all \ - "MYCFLAGS=-DKLISP_USE_POSIX $(if $(USE_LIBFFI),-DKUSE_LIBFFI=1 -Dread=klisp_read -Dwrite=klisp_write)" \ + "MYCFLAGS=-DKLISP_USE_POSIX -D_POSIX_SOURCE $(if $(USE_LIBFFI),-DKUSE_LIBFFI=1)" \ "MYLIBS=$(if $(USE_LIBFFI), -rdynamic -ldl -lffi)" # list targets that do not create files (but not all makes understand .PHONY) @@ -119,6 +118,7 @@ kauxlib.o: kauxlib.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ ktoken.h kmem.h kbytevector.o: kbytevector.c kbytevector.h kobject.h klimits.h klisp.h \ klispconf.h kstate.h ktoken.h kmem.h kgc.h kstring.h +kchar.o: kchar.c kobject.h klimits.h klisp.h klispconf.h kcontinuation.o: kcontinuation.c kcontinuation.h kobject.h klimits.h \ klisp.h klispconf.h kstate.h ktoken.h kmem.h kgc.h kencapsulation.o: kencapsulation.c kobject.h klimits.h klisp.h \ @@ -129,127 +129,127 @@ kenvironment.o: kenvironment.c kenvironment.h kobject.h klimits.h klisp.h \ kerror.o: kerror.c klisp.h kobject.h klimits.h klispconf.h kpair.h \ kstate.h ktoken.h kmem.h kgc.h kstring.h kerror.h keval.o: keval.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ - ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h kerror.h + ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h kerror.h \ + kghelpers.h kapplicative.h koperative.h ksymbol.h kstring.h ktable.h kgbooleans.o: kgbooleans.c kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h kpair.h kgc.h ksymbol.h kstring.h \ kcontinuation.h kerror.h kghelpers.h kapplicative.h koperative.h \ - kenvironment.h + kenvironment.h ktable.h kgbooleans.h kgbytevectors.o: kgbytevectors.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h \ kerror.h kpair.h kgc.h kbytevector.h kghelpers.h kenvironment.h \ - ksymbol.h kstring.h kgbytevectors.h kgnumbers.h + ksymbol.h kstring.h ktable.h kgbytevectors.h kgc.o: kgc.c kgc.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kport.h imath.h imrat.h ktable.h kstring.h kbytevector.h \ kvector.h kerror.h kpair.h +kgchars.o: kgchars.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ + ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ + kpair.h kgc.h kchar.h kghelpers.h kenvironment.h ksymbol.h kstring.h \ + ktable.h kgchars.h kgcombiners.o: kgcombiners.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h \ ksymbol.h kstring.h koperative.h kapplicative.h kerror.h kghelpers.h \ - kgpair_mut.h kgenv_mut.h kgcontrol.h kgcombiners.h + ktable.h kgcombiners.h kgcontinuations.o: kgcontinuations.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h \ kapplicative.h koperative.h ksymbol.h kstring.h kerror.h kghelpers.h \ - kgcontinuations.h kgcontrol.h + ktable.h kgcontinuations.h kgcontrol.o: kgcontrol.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kpair.h kgc.h kcontinuation.h kerror.h kghelpers.h \ - kapplicative.h koperative.h kenvironment.h ksymbol.h kstring.h \ - kgcontrol.h kgcombiners.h + kapplicative.h koperative.h kenvironment.h ksymbol.h kstring.h ktable.h \ + kgcontrol.h kgencapsulations.o: kgencapsulations.c kstate.h klimits.h klisp.h \ kobject.h klispconf.h ktoken.h kmem.h kencapsulation.h kapplicative.h \ koperative.h kerror.h kpair.h kgc.h kghelpers.h kcontinuation.h \ - kenvironment.h ksymbol.h kstring.h kgencapsulations.h + kenvironment.h ksymbol.h kstring.h ktable.h kgencapsulations.h +kgenv_mut.o: kgenv_mut.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ + ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h ksymbol.h \ + kstring.h kerror.h kghelpers.h kapplicative.h koperative.h ktable.h \ + kgenv_mut.h kgenvironments.o: kgenvironments.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h \ ksymbol.h kstring.h kerror.h kghelpers.h kapplicative.h koperative.h \ - kgenvironments.h kgenv_mut.h kgpair_mut.h kgcontrol.h -kgenv_mut.o: kgenv_mut.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h ksymbol.h \ - kstring.h kerror.h kghelpers.h kapplicative.h koperative.h kgenv_mut.h \ - kgcontrol.h + ktable.h kgenvironments.h kgeqp.o: kgeqp.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kpair.h kgc.h kcontinuation.h kerror.h kghelpers.h \ - kapplicative.h koperative.h kenvironment.h ksymbol.h kstring.h kgeqp.h \ - kinteger.h imath.h krational.h imrat.h + kapplicative.h koperative.h kenvironment.h ksymbol.h kstring.h ktable.h \ + kgeqp.h kgequalp.o: kgequalp.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kpair.h kgc.h kstring.h kbytevector.h kcontinuation.h \ - kerror.h kghelpers.h kapplicative.h koperative.h kenvironment.h \ - ksymbol.h kgeqp.h kinteger.h imath.h krational.h imrat.h kgequalp.h -kgerror.o: kgerror.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ + ktoken.h kmem.h kpair.h kgc.h kvector.h kstring.h kbytevector.h \ + kcontinuation.h kerror.h kghelpers.h kapplicative.h koperative.h \ + kenvironment.h ksymbol.h ktable.h kgequalp.h +kgerrors.o: kgerrors.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kstring.h kpair.h kgc.h kerror.h kghelpers.h \ kapplicative.h koperative.h kcontinuation.h kenvironment.h ksymbol.h \ - kgerror.h + ktable.h kgerrors.h kgffi.o: kgffi.c imath.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kinteger.h kpair.h kgc.h kerror.h kbytevector.h \ kencapsulation.h ktable.h kghelpers.h kapplicative.h koperative.h \ - kcontinuation.h kenvironment.h ksymbol.h kstring.h kgencapsulations.h \ - kgcombiners.h kgcontinuations.h kgffi.h + kcontinuation.h kenvironment.h ksymbol.h kstring.h kgffi.h kghelpers.o: kghelpers.c kghelpers.h kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kerror.h kpair.h kgc.h kapplicative.h \ - koperative.h kcontinuation.h kenvironment.h ksymbol.h kstring.h -kgchars.o: kgchars.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ - kpair.h kgc.h kghelpers.h kenvironment.h ksymbol.h kstring.h kgchars.h + koperative.h kcontinuation.h kenvironment.h ksymbol.h kstring.h ktable.h \ + kinteger.h imath.h krational.h imrat.h kbytevector.h kvector.h \ + kencapsulation.h kpromise.h kgkd_vars.o: kgkd_vars.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kpair.h kgc.h kcontinuation.h koperative.h \ kapplicative.h kenvironment.h kerror.h kghelpers.h ksymbol.h kstring.h \ - kgcontinuations.h kgkd_vars.h + ktable.h kgkd_vars.h kgks_vars.o: kgks_vars.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kpair.h kgc.h kcontinuation.h koperative.h \ kapplicative.h kenvironment.h kerror.h kghelpers.h ksymbol.h kstring.h \ - kgks_vars.h + ktable.h kgks_vars.h kgnumbers.o: kgnumbers.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ kpair.h kgc.h ksymbol.h kstring.h kinteger.h imath.h krational.h imrat.h \ - kreal.h kghelpers.h kenvironment.h kgnumbers.h kgkd_vars.h + kreal.h kghelpers.h kenvironment.h ktable.h kgnumbers.h kgpair_mut.o: kgpair_mut.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kcontinuation.h ksymbol.h \ kstring.h kerror.h kghelpers.h kapplicative.h koperative.h \ - kenvironment.h kgpair_mut.h kgeqp.h kinteger.h imath.h krational.h \ - imrat.h kgnumbers.h + kenvironment.h ktable.h kgpair_mut.h kgpairs_lists.o: kgpairs_lists.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kstring.h kcontinuation.h \ kenvironment.h ksymbol.h kerror.h kghelpers.h kapplicative.h \ - koperative.h kgequalp.h kgpairs_lists.h kgnumbers.h kinteger.h imath.h + koperative.h ktable.h kgpairs_lists.h kgports.o: kgports.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kport.h kstring.h kbytevector.h kenvironment.h \ kapplicative.h koperative.h kcontinuation.h kpair.h kgc.h kerror.h \ - ksymbol.h kread.h kwrite.h kscript.h kghelpers.h kgports.h \ - kgcontinuations.h kgcontrol.h kgkd_vars.h + ksymbol.h kread.h kwrite.h kghelpers.h ktable.h kgports.h ktable.h kgpromises.o: kgpromises.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpromise.h kpair.h kgc.h kapplicative.h \ koperative.h kcontinuation.h kerror.h kghelpers.h kenvironment.h \ - ksymbol.h kstring.h kgpromises.h + ksymbol.h kstring.h ktable.h kgpromises.h kground.o: kground.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kground.h kghelpers.h kerror.h kpair.h kgc.h \ kapplicative.h koperative.h kcontinuation.h kenvironment.h ksymbol.h \ - kstring.h kgbooleans.h kgeqp.h kinteger.h imath.h krational.h imrat.h \ - kgequalp.h kgsymbols.h kgcontrol.h kgpairs_lists.h kgpair_mut.h \ - kgenvironments.h kgenv_mut.h kgcombiners.h kgcontinuations.h \ - kgencapsulations.h kgpromises.h kgkd_vars.h kgks_vars.h kgnumbers.h \ - kgstrings.h kgchars.h kgports.h kgbytevectors.h kgvectors.h kgsystem.h \ - kgerror.h kgffi.h ktable.h keval.h krepl.h kscript.h + kstring.h ktable.h kgbooleans.h kgeqp.h kgequalp.h kgsymbols.h \ + kgcontrol.h kgpairs_lists.h kgpair_mut.h kgenvironments.h kgenv_mut.h \ + kgcombiners.h kgcontinuations.h kgencapsulations.h kgpromises.h \ + kgkd_vars.h kgks_vars.h kgnumbers.h kgstrings.h kgchars.h kgports.h \ + kgbytevectors.h kgvectors.h kgsystem.h kgerrors.h \ + kgffi.h keval.h krepl.h kgstrings.o: kgstrings.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ - kpair.h kgc.h ksymbol.h kstring.h kghelpers.h kenvironment.h kgchars.h \ - kgstrings.h kgnumbers.h + kpair.h kgc.h ksymbol.h kstring.h kchar.h kvector.h kbytevector.h \ + kghelpers.h kenvironment.h ktable.h kgstrings.h kgsymbols.o: kgsymbols.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kcontinuation.h kpair.h kgc.h kstring.h ksymbol.h \ - kerror.h kghelpers.h kapplicative.h koperative.h kenvironment.h \ + kerror.h kghelpers.h kapplicative.h koperative.h kenvironment.h ktable.h \ kgsymbols.h kgsystem.o: kgsystem.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kpair.h kgc.h kerror.h kghelpers.h kapplicative.h \ - koperative.h kcontinuation.h kenvironment.h ksymbol.h kstring.h \ - kgsystem.h + ktoken.h kmem.h kpair.h kgc.h kerror.h ksystem.h kghelpers.h \ + kapplicative.h koperative.h kcontinuation.h kenvironment.h ksymbol.h \ + kstring.h ktable.h kgsystem.h kinteger.h kmem.h imath.h kgc.h kgvectors.o: kgvectors.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ - kpair.h kgc.h kvector.h kghelpers.h kenvironment.h ksymbol.h kstring.h \ - kgvectors.h kgnumbers.h + kpair.h kgc.h kvector.h kbytevector.h kghelpers.h kenvironment.h \ + ksymbol.h kstring.h ktable.h kgvectors.h kinteger.o: kinteger.c kinteger.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h imath.h kgc.h klisp.o: klisp.c klimits.h klisp.h kobject.h klispconf.h kstate.h \ ktoken.h kmem.h kauxlib.h kstring.h kcontinuation.h koperative.h \ - kenvironment.h kport.h kread.h kwrite.h kerror.h kpair.h kgc.h \ - kgcontinuations.h kghelpers.h kapplicative.h ksymbol.h kgcontrol.h \ - kscript.h krepl.h + kapplicative.h ksymbol.h kenvironment.h kport.h kread.h kwrite.h \ + kerror.h kpair.h kgc.h krepl.h kghelpers.h ktable.h kmem.o: kmem.c klisp.h kobject.h klimits.h klispconf.h kstate.h ktoken.h \ kmem.h kerror.h kpair.h kgc.h kobject.o: kobject.c kobject.h klimits.h klisp.h klispconf.h @@ -264,31 +264,32 @@ kpromise.o: kpromise.c kobject.h klimits.h klisp.h klispconf.h kstate.h \ krational.o: krational.c krational.h kobject.h klimits.h klisp.h \ klispconf.h kstate.h ktoken.h kmem.h kinteger.h imath.h imrat.h kgc.h kread.o: kread.c kread.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ - ktoken.h kmem.h kpair.h kgc.h kerror.h ktable.h kport.h + ktoken.h kmem.h kpair.h kgc.h kerror.h ktable.h kport.h kstring.h kreal.o: kreal.c kreal.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kinteger.h imath.h krational.h imrat.h kgc.h kpair.h \ kerror.h krepl.o: krepl.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ ktoken.h kmem.h kcontinuation.h kenvironment.h kerror.h kpair.h kgc.h \ - kread.h kwrite.h kstring.h krepl.h ksymbol.h kport.h kgerror.h \ - kghelpers.h kapplicative.h koperative.h ktable.h kgcontinuations.h -kscript.o: kscript.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ - ktoken.h kmem.h kcontinuation.h kenvironment.h kerror.h kpair.h kgc.h \ - kread.h kwrite.h kstring.h krepl.h kscript.h ksymbol.h kport.h \ - kgcontrol.h kghelpers.h kapplicative.h koperative.h kgerror.h ktable.h + kread.h kwrite.h kstring.h krepl.h ksymbol.h kport.h ktable.h \ + kghelpers.h kapplicative.h koperative.h kstate.o: kstate.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ ktoken.h kmem.h kstring.h kpair.h kgc.h keval.h koperative.h \ kapplicative.h kcontinuation.h kenvironment.h kground.h krepl.h \ - kscript.h ksymbol.h kport.h ktable.h kbytevector.h kvector.h \ - kgpairs_lists.h kghelpers.h kerror.h kgerror.h + ksymbol.h kport.h ktable.h kbytevector.h kvector.h kghelpers.h kerror.h \ + kgerrors.h kstring.o: kstring.c kstring.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h kgc.h ksymbol.o: ksymbol.c ksymbol.h kobject.h klimits.h klisp.h klispconf.h \ - kstate.h ktoken.h kmem.h kstring.h kgc.h + kstate.h kmem.h kstring.h kgc.h +ksystem.o: ksystem.c kobject.h klimits.h klisp.h klispconf.h kstate.h \ + ktoken.h kmem.h kerror.h kpair.h kgc.h ksystem.h +ksystem.posix.o: ksystem.posix.c kobject.h klimits.h klisp.h klispconf.h \ + kstate.h ktoken.h kmem.h kinteger.h imath.h ksystem.h +ksystem.win32.o: ksystem.win32.c kobject.h klimits.h klisp.h klispconf.h \ + kstate.h ktoken.h kmem.h kinteger.h imath.h ksystem.h ktable.o: ktable.c klisp.h kobject.h klimits.h klispconf.h kgc.h kstate.h \ - ktoken.h kmem.h ktable.h kapplicative.h koperative.h kgeqp.h kinteger.h \ - imath.h krational.h imrat.h kghelpers.h kerror.h kpair.h kcontinuation.h \ - kenvironment.h ksymbol.h kstring.h + ktoken.h kmem.h ktable.h kapplicative.h koperative.h kghelpers.h \ + kerror.h kpair.h kcontinuation.h kenvironment.h ksymbol.h kstring.h ktoken.o: ktoken.c ktoken.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h kmem.h kinteger.h imath.h krational.h imrat.h kreal.h kpair.h \ kgc.h kstring.h kbytevector.h ksymbol.h kerror.h kport.h @@ -297,7 +298,7 @@ kvector.o: kvector.c kvector.h kobject.h klimits.h klisp.h klispconf.h \ kwrite.o: kwrite.c kwrite.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h kinteger.h imath.h krational.h imrat.h kreal.h \ kpair.h kgc.h kstring.h ksymbol.h kerror.h ktable.h kport.h \ - kenvironment.h kbytevector.h + kenvironment.h kbytevector.h kvector.h ktoken.h imath.o: imath.c imath.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kerror.h kpair.h kgc.h imrat.o: imrat.c imrat.h imath.h kobject.h klimits.h klisp.h klispconf.h \ diff --git a/src/examples/ffi-sdl.k b/src/examples/ffi-sdl.k @@ -198,8 +198,6 @@ (#t (event-loop screen drawing)))))) -($define! main - ($lambda (argv) - (with-sdl "klisp ffi demo" - ($lambda (screen) (event-loop screen #f))))) +(with-sdl "klisp ffi demo" + ($lambda (screen) (event-loop screen #f))) diff --git a/src/examples/ffi-signal.c b/src/examples/ffi-signal.c @@ -29,12 +29,9 @@ static void handler(int signo) write(self_pipe[1], &message, 1); } -static void install_signal_handler(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +static void install_signal_handler(klisp_State *K) { - UNUSED(xparams); - UNUSED(denv); - bind_1tp(K, ptree, "string", ttisstring, signame); + bind_1tp(K, K->next_value, "string", ttisstring, signame); int signo; if (!strcmp(kstring_buf(signame), "SIGINT")) { @@ -49,12 +46,8 @@ static void install_signal_handler(klisp_State *K, TValue *xparams, kapply_cc(K, KINERT); } -static void open_signal_port(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +static void open_signal_port(klisp_State *K) { - UNUSED(xparams); - UNUSED(denv); - FILE *fw = fdopen(self_pipe[0], "r"); TValue filename = kstring_new_b_imm(K, "**SIGNAL**"); krooted_tvs_push(K, filename); @@ -65,7 +58,7 @@ static void open_signal_port(klisp_State *K, TValue *xparams, static void safe_add_applicative(klisp_State *K, TValue env, const char *name, - klisp_Ofunc fn) + klisp_CFunction fn) { TValue symbol = ksymbol_new(K, name, KNIL); krooted_tvs_push(K, symbol); diff --git a/src/imath.c b/src/imath.c @@ -1866,7 +1866,7 @@ mp_result mp_int_to_string(klisp_State *K, mp_int z, mp_size radix, return MP_RANGE; if(CMPZ(z) == 0) { - *str++ = s_val2ch(0, 1); + *str++ = s_val2ch(0, 0); /* changed to lowercase, Andres Navarro */ } else { mpz_t tmp; @@ -1889,7 +1889,7 @@ mp_result mp_int_to_string(klisp_State *K, mp_int z, mp_size radix, break; d = s_ddiv(&tmp, (mp_digit)radix); - *str++ = s_val2ch(d, 1); + *str++ = s_val2ch(d, 0); /* changed to lowercase, Andres Navarro */ } t = str - 1; diff --git a/src/kchar.c b/src/kchar.c @@ -0,0 +1,40 @@ +/* +** kchar.c +** Kernel Characters +** See Copyright Notice in klisp.h +*/ + +#include <ctype.h> +#include <stdbool.h> + +#include "kobject.h" + +bool kcharp(TValue tv) { return ttischar(tv); } +bool kchar_alphabeticp(TValue ch) { return isalpha(chvalue(ch)) != 0; } +bool kchar_numericp(TValue ch) { return isdigit(chvalue(ch)) != 0; } +bool kchar_whitespacep(TValue ch) { return isspace(chvalue(ch)) != 0; } +bool kchar_upper_casep(TValue ch) { return isupper(chvalue(ch)) != 0; } +bool kchar_lower_casep(TValue ch) { return islower(chvalue(ch)) != 0; } + +/* Helpers for binary typed predicates */ +bool kchar_eqp(TValue ch1, TValue ch2) { return chvalue(ch1) == chvalue(ch2); } +bool kchar_ltp(TValue ch1, TValue ch2) { return chvalue(ch1) < chvalue(ch2); } +bool kchar_lep(TValue ch1, TValue ch2) { return chvalue(ch1) <= chvalue(ch2); } +bool kchar_gtp(TValue ch1, TValue ch2) { return chvalue(ch1) > chvalue(ch2); } +bool kchar_gep(TValue ch1, TValue ch2) { return chvalue(ch1) >= chvalue(ch2); } + +bool kchar_ci_eqp(TValue ch1, TValue ch2) +{ return tolower(chvalue(ch1)) == tolower(chvalue(ch2)); } + +bool kchar_ci_ltp(TValue ch1, TValue ch2) +{ return tolower(chvalue(ch1)) < tolower(chvalue(ch2)); } + +bool kchar_ci_lep(TValue ch1, TValue ch2) +{ return tolower(chvalue(ch1)) <= tolower(chvalue(ch2)); } + +bool kchar_ci_gtp(TValue ch1, TValue ch2) +{ return tolower(chvalue(ch1)) > tolower(chvalue(ch2)); } + +bool kchar_ci_gep(TValue ch1, TValue ch2) +{ return tolower(chvalue(ch1)) >= tolower(chvalue(ch2)); } + diff --git a/src/kchar.h b/src/kchar.h @@ -0,0 +1,34 @@ +/* +** kchar.h +** Kernel Characters +** See Copyright Notice in klisp.h +*/ + +#ifndef kchar_h +#define kchar_h + +#include <stdbool.h> + +#include "kobject.h" +#include "kstate.h" + +bool kcharp(TValue tv); +bool kchar_alphabeticp(TValue ch); +bool kchar_numericp(TValue ch); +bool kchar_whitespacep(TValue ch); +bool kchar_upper_casep(TValue ch); +bool kchar_lower_casep(TValue ch); +/* Helpers for binary typed predicates */ +bool kchar_eqp(TValue ch1, TValue ch2); +bool kchar_ltp(TValue ch1, TValue ch2); +bool kchar_lep(TValue ch1, TValue ch2); +bool kchar_gtp(TValue ch1, TValue ch2); +bool kchar_gep(TValue ch1, TValue ch2); + +bool kchar_ci_eqp(TValue ch1, TValue ch2); +bool kchar_ci_ltp(TValue ch1, TValue ch2); +bool kchar_ci_lep(TValue ch1, TValue ch2); +bool kchar_ci_gtp(TValue ch1, TValue ch2); +bool kchar_ci_gep(TValue ch1, TValue ch2); + +#endif diff --git a/src/kcontinuation.c b/src/kcontinuation.c @@ -46,7 +46,7 @@ TValue kmake_continuation(klisp_State *K, TValue parent, klisp_CFunction fn, TValue res = gc2cont(new_cont); /* Add the current source info as source info (may be changed later) */ /* TODO: find all the places where this should be changed (like $and?, - $sequence, and change it */ + $sequence), and change it */ kset_source_info(K, res, kget_csi(K)); return res; } diff --git a/src/kencapsulation.c b/src/kencapsulation.c @@ -11,6 +11,11 @@ #include "kpair.h" #include "kgc.h" +bool kis_encapsulation_type(TValue enc, TValue key) +{ + return ttisencapsulation(enc) && tv_equal(kget_enc_key(enc), key); +} + /* GC: Assumes that key & val are rooted */ TValue kmake_encapsulation(klisp_State *K, TValue key, TValue val) { diff --git a/src/kencapsulation.h b/src/kencapsulation.h @@ -14,15 +14,9 @@ TValue kmake_encapsulation(klisp_State *K, TValue key, TValue val); TValue kmake_encapsulation_key(klisp_State *K); -inline bool kis_encapsulation_type(TValue enc, TValue key); +bool kis_encapsulation_type(TValue enc, TValue key); #define kget_enc_val(e_)(tv2enc(e_)->value) #define kget_enc_key(e_)(tv2enc(e_)->key) -inline bool kis_encapsulation_type(TValue enc, TValue key) -{ - return ttisencapsulation(enc) && tv_equal(kget_enc_key(enc), key); -} - - #endif diff --git a/src/kenvironment.c b/src/kenvironment.c @@ -55,7 +55,9 @@ TValue kmake_environment(klisp_State *K, TValue parents) } else { /* list of parents, for now, just append them */ krooted_tvs_push(K, gc2env(new_env)); /* keep the new env rooted */ - TValue tail = kget_dummy1(K); /* keep the list rooted */ + TValue plist = kcons(K, KNIL, KNIL); /* keep the list rooted */ + krooted_vars_push(K, &plist); + TValue tail = plist; while(!ttisnil(parents)) { TValue parent = kcar(parents); TValue pkparents = env_keyed_parents(parent); @@ -74,8 +76,9 @@ TValue kmake_environment(klisp_State *K, TValue parents) } parents = kcdr(parents); } - /* all alocation done */ - kparents = kcutoff_dummy1(K); + /* all alocation done */ + kparents = kcdr(plist); + krooted_vars_pop(K); krooted_tvs_pop(K); /* if it's just one env switch from (env) to env. */ if (ttispair(kparents) && ttisnil(kcdr(kparents))) diff --git a/src/kenvironment.h b/src/kenvironment.h @@ -23,7 +23,7 @@ TValue kmake_keyed_static_env(klisp_State *K, TValue parent, TValue key, TValue kget_keyed_static_var(klisp_State *K, TValue env, TValue key); /* environments with hashtable bindings */ -/* TEMP: for now only for ground environment +/* TEMP: for now only for ground & std environments TODO: Should profile too see when it makes sense & should add code to all operatives creating environments to see when it's appropriate or should add code to add binding to at certain point move over to diff --git a/src/kerror.c b/src/kerror.c @@ -63,10 +63,6 @@ void clear_buffers(klisp_State *K) ks_tbclear(K); K->shared_dict = KNIL; - UNUSED(kcutoff_dummy1(K)); - UNUSED(kcutoff_dummy2(K)); - UNUSED(kcutoff_dummy3(K)); - krooted_tvs_clear(K); krooted_vars_clear(K); } @@ -106,6 +102,8 @@ void klispE_throw_simple(klisp_State *K, char *msg) /* GC: assumes all objs passed are rooted */ void klispE_throw_with_irritants(klisp_State *K, char *msg, TValue irritants) { + /* it's important that this is immutable, because it's user + accessible */ TValue error_msg = kstring_new_b_imm(K, msg); krooted_tvs_push(K, error_msg); TValue error_obj = diff --git a/src/kerror.h b/src/kerror.h @@ -55,7 +55,7 @@ void klispE_throw_system_error_with_irritants( TValue ls__ = klist(K__, __VA_ARGS__); \ krooted_tvs_push(K__, ls__); \ klispE_throw_system_error_with_irritants(K__, service__, errnum__, ls__); \ - } + } #define klispE_throw_errno_simple(K__, service__) \ klispE_throw_system_error_with_irritants(K__, service__, errno, KNIL); diff --git a/src/keval.c b/src/keval.c @@ -12,6 +12,14 @@ #include "kcontinuation.h" #include "kerror.h" +/* for continuation name setting */ +#include "kghelpers.h" + +/* Continuations */ +void do_eval_ls(klisp_State *K); +void do_combine(klisp_State *K); + + /* ** Eval helpers */ @@ -173,4 +181,11 @@ void keval_ofn(klisp_State *K) } } +/* init continuation names */ +void kinit_eval_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + add_cont_name(K, t, do_eval_ls, "eval-list"); + add_cont_name(K, t, do_combine, "eval-combine"); +} diff --git a/src/keval.h b/src/keval.h @@ -7,12 +7,10 @@ #ifndef keval_h #define keval_h -#include "klisp.h" #include "kstate.h" -#include "kobject.h" void keval_ofn(klisp_State *K); -void do_eval_ls(klisp_State *K); -void do_combine(klisp_State *K); +/* init continuation names */ +void kinit_eval_cont_names(klisp_State *K); #endif diff --git a/src/kgbooleans.c b/src/kgbooleans.c @@ -17,7 +17,12 @@ #include "ksymbol.h" #include "kcontinuation.h" #include "kerror.h" + #include "kghelpers.h" +#include "kgbooleans.h" + +/* Continuations */ +void do_Sandp_Sorp(klisp_State *K); /* 4.1.1 boolean? */ /* uses typep */ @@ -38,9 +43,6 @@ void notp(klisp_State *K) kapply_cc(K, res); } -/* Helper for type checking booleans */ -bool kbooleanp(TValue obj) { return ttisboolean(obj); } - /* 6.1.2 and? */ void andp(klisp_State *K) { @@ -50,9 +52,9 @@ void andp(klisp_State *K) klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); UNUSED(denv); + int32_t pairs; /* don't care about cycle pairs */ - int32_t pairs = check_typed_list(K, "and?", "boolean", kbooleanp, - true, ptree, NULL); + check_typed_list(K, kbooleanp, true, ptree, &pairs, NULL); TValue res = KTRUE; TValue tail = ptree; while(pairs--) { @@ -75,9 +77,9 @@ void orp(klisp_State *K) klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); UNUSED(denv); + int32_t pairs; /* don't care about cycle pairs */ - int32_t pairs = check_typed_list(K, "or?", "boolean", kbooleanp, - true, ptree, NULL); + check_typed_list(K, kbooleanp,true, ptree, &pairs, NULL); TValue res = KFALSE; TValue tail = ptree; while(pairs--) { @@ -119,7 +121,8 @@ void do_Sandp_Sorp(klisp_State *K) TValue denv = xparams[3]; if (!ttisboolean(obj)) { - klispE_throw_simple(K, "expected boolean"); + klispE_throw_simple_with_irritants(K, "expected boolean", 1, + obj); return; } else if (ttisnil(ls) || tv_equal(obj, term_bool)) { /* in both cases the value to be returned is obj: @@ -169,7 +172,7 @@ void Sandp_Sorp(klisp_State *K) TValue sname = xparams[0]; TValue term_bool = xparams[1]; - TValue ls = check_copy_list(K, ksymbol_buf(sname), ptree, false); + TValue ls = check_copy_list(K, ptree, false, NULL, NULL); /* This will work even if ls is empty */ krooted_tvs_push(K, ls); TValue new_cont = kmake_continuation(K, kget_cc(K), do_Sandp_Sorp, 4, @@ -208,3 +211,10 @@ void kinit_booleans_ground_env(klisp_State *K) /* 6.1.5 $or? */ add_operative(K, ground_env, "$or?", Sandp_Sorp, 2, symbol, KTRUE); } + +/* init continuation names */ +void kinit_booleans_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + add_cont_name(K, t, do_Sandp_Sorp, "eval-booleans"); +} diff --git a/src/kgbooleans.h b/src/kgbooleans.h @@ -7,43 +7,11 @@ #ifndef kgbooleans_h #define kgbooleans_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* 4.1.1 boolean? */ -/* uses typep */ - -/* 6.1.1 not? */ -void notp(klisp_State *K); - -/* 6.1.2 and? */ -void andp(klisp_State *K); - -/* 6.1.3 or? */ -void orp(klisp_State *K); - -/* Helpers for $and? & $or? */ -void do_Sandp_Sorp(klisp_State *K); -void Sandp_Sorp(klisp_State *K); - -/* 6.1.4 $and? */ -/* uses Sandp_Sorp */ - -/* 6.1.5 $or? */ -/* uses Sandp_Sorp */ - -/* Helper */ -bool kbooleanp(TValue obj); /* init ground */ void kinit_booleans_ground_env(klisp_State *K); +/* init continuation names */ +void kinit_booleans_cont_names(klisp_State *K); #endif diff --git a/src/kgbytevectors.c b/src/kgbytevectors.c @@ -21,15 +21,67 @@ #include "kghelpers.h" #include "kgbytevectors.h" -#include "kgnumbers.h" /* for keintegerp & knegativep */ -/* 13.1.1? bytevector? */ +/* ?.? bytevector? */ /* uses typep */ -/* 13.? immutable-bytevector?, mutable-bytevector? */ +/* ?.? immutable-bytevector?, mutable-bytevector? */ /* use ftypep */ -/* 13.1.2? make-bytevector */ +/* ?.? bytevector */ +void bytevector(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + + /* don't allow cycles */ + int32_t pairs; + check_typed_list(K, ku8p, false, ptree, &pairs, NULL); + TValue new_bb = list_to_bytevector_h(K, ptree, pairs); + kapply_cc(K, new_bb); +} + +/* ?.? bytevector->list */ +void bytevector_to_list(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + + bind_1tp(K, ptree, "bytevector", ttisbytevector, bb); + + TValue res = bytevector_to_list_h(K, bb, NULL); + kapply_cc(K, res); +} + +/* ?.? list->bytevector */ +void list_to_bytevector(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + + /* check later in list_to_bytevector_h */ + bind_1p(K, ptree, ls); + + /* don't allow cycles */ + int32_t pairs; + check_typed_list(K, ku8p, false, ls, &pairs, NULL); + TValue new_bb = list_to_bytevector_h(K, ls, pairs); + kapply_cc(K, new_bb); +} + +/* ?.? make-bytevector */ void make_bytevector(klisp_State *K) { TValue *xparams = K->next_xparams; @@ -57,7 +109,7 @@ void make_bytevector(klisp_State *K) kapply_cc(K, new_bytevector); } -/* 13.1.3? bytevector-length */ +/* ?.? bytevector-length */ void bytevector_length(klisp_State *K) { TValue *xparams = K->next_xparams; @@ -72,7 +124,7 @@ void bytevector_length(klisp_State *K) kapply_cc(K, res); } -/* 13.1.4? bytevector-u8-ref */ +/* ?.? bytevector-u8-ref */ void bytevector_u8_ref(klisp_State *K) { TValue *xparams = K->next_xparams; @@ -101,8 +153,8 @@ void bytevector_u8_ref(klisp_State *K) kapply_cc(K, res); } -/* 13.1.5? bytevector-u8-set! */ -void bytevector_u8_setS(klisp_State *K) +/* ?.? bytevector-u8-set! */ +void bytevector_u8_setB(klisp_State *K) { TValue *xparams = K->next_xparams; TValue ptree = K->next_value; @@ -134,7 +186,7 @@ void bytevector_u8_setS(klisp_State *K) kapply_cc(K, KINERT); } -/* 13.2.8? bytevector-copy */ +/* ?.? bytevector-copy */ /* TEMP: at least for now this always returns mutable bytevectors */ void bytevector_copy(klisp_State *K) { @@ -158,7 +210,7 @@ void bytevector_copy(klisp_State *K) } /* 13.2.9? bytevector-copy! */ -void bytevector_copyS(klisp_State *K) +void bytevector_copyB(klisp_State *K) { TValue *xparams = K->next_xparams; TValue ptree = K->next_value; @@ -186,7 +238,7 @@ void bytevector_copyS(klisp_State *K) kapply_cc(K, KINERT); } -/* 13.2.10? bytevector-copy-partial */ +/* ?.? bytevector-copy-partial */ /* TEMP: at least for now this always returns mutable bytevectors */ void bytevector_copy_partial(klisp_State *K) { @@ -235,8 +287,8 @@ void bytevector_copy_partial(klisp_State *K) kapply_cc(K, new_bytevector); } -/* 13.2.11? bytevector-copy-partial! */ -void bytevector_copy_partialS(klisp_State *K) +/* ?.? bytevector-copy-partial! */ +void bytevector_copy_partialB(klisp_State *K) { TValue *xparams = K->next_xparams; TValue ptree = K->next_value; @@ -307,7 +359,32 @@ void bytevector_copy_partialS(klisp_State *K) kapply_cc(K, KINERT); } -/* 13.2.12? bytevector->immutable-bytevector */ +/* ?.? bytevector-u8-fill! */ +void bytevector_u8_fillB(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + bind_2tp(K, ptree, "bytevector", ttisbytevector, bytevector, + "u8", ttisu8, tv_byte); + + if (kbytevector_immutablep(bytevector)) { + klispE_throw_simple(K, "immutable bytevector"); + return; + } + + uint32_t size = kbytevector_size(bytevector); + uint8_t *buf = kbytevector_buf(bytevector); + while(size-- > 0) { + *buf++ = (uint8_t) ivalue(tv_byte); + } + kapply_cc(K, KINERT); +} + +/* ?.? bytevector->immutable-bytevector */ void bytevector_to_immutable_bytevector(klisp_State *K) { TValue *xparams = K->next_xparams; @@ -349,6 +426,12 @@ void kinit_bytevectors_ground_env(klisp_State *K) p2tv(kimmutable_bytevectorp)); add_applicative(K, ground_env, "mutable-bytevector?", ftypep, 2, symbol, p2tv(kmutable_bytevectorp)); + /* ??.1.? bytevector */ + add_applicative(K, ground_env, "bytevector", bytevector, 0); + /* ??.1.? list->bytevector */ + add_applicative(K, ground_env, "list->bytevector", list_to_bytevector, 0); + /* ??.1.? bytevector->list */ + add_applicative(K, ground_env, "bytevector->list", bytevector_to_list, 0); /* ??.1.2? make-bytevector */ add_applicative(K, ground_env, "make-bytevector", make_bytevector, 0); /* ??.1.3? bytevector-length */ @@ -357,21 +440,25 @@ void kinit_bytevectors_ground_env(klisp_State *K) /* ??.1.4? bytevector-u8-ref */ add_applicative(K, ground_env, "bytevector-u8-ref", bytevector_u8_ref, 0); /* ??.1.5? bytevector-u8-set! */ - add_applicative(K, ground_env, "bytevector-u8-set!", bytevector_u8_setS, + add_applicative(K, ground_env, "bytevector-u8-set!", bytevector_u8_setB, 0); /* ??.1.?? bytevector-copy */ add_applicative(K, ground_env, "bytevector-copy", bytevector_copy, 0); /* ??.1.?? bytevector-copy! */ - add_applicative(K, ground_env, "bytevector-copy!", bytevector_copyS, 0); + add_applicative(K, ground_env, "bytevector-copy!", bytevector_copyB, 0); /* ??.1.?? bytevector-copy-partial */ add_applicative(K, ground_env, "bytevector-copy-partial", bytevector_copy_partial, 0); /* ??.1.?? bytevector-copy-partial! */ add_applicative(K, ground_env, "bytevector-copy-partial!", - bytevector_copy_partialS, 0); + bytevector_copy_partialB, 0); + /* ??.?? bytevector-u8-fill! */ + add_applicative(K, ground_env, "bytevector-u8-fill!", + bytevector_u8_fillB, 0); + /* ??.1.?? bytevector->immutable-bytevector */ add_applicative(K, ground_env, "bytevector->immutable-bytevector", bytevector_to_immutable_bytevector, 0); diff --git a/src/kgbytevectors.h b/src/kgbytevectors.h @@ -7,46 +7,7 @@ #ifndef kgbytevectors_h #define kgbytevectors_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* ??.1.1? bytevector? */ -/* uses typep */ - -/* ??.1.2? make-bytevector */ -void make_bytevector(klisp_State *K); - -/* ??.1.3? bytevector-length */ -void bytevector_length(klisp_State *K); - -/* ??.1.4? bytevector-u8-ref */ -void bytevector_u8_ref(klisp_State *K); - -/* ??.1.5? bytevector-u8-set! */ -void bytevector_u8_setS(klisp_State *K); - -/* ??.2.?? bytevector-copy */ -void bytevector_copy(klisp_State *K); - -/* ??.2.?? bytevector-copy! */ -void bytevector_copyS(klisp_State *K); - -/* ??.2.?? bytevector-copy-partial */ -void bytevector_copy_partial(klisp_State *K); - -/* ??.2.?? bytevector-copy-partial! */ -void bytevector_copy_partialS(klisp_State *K); - -/* ??.2.?? bytevector->immutable-bytevector */ -void bytevector_to_immutable_bytevector(klisp_State *K); /* init ground */ void kinit_bytevectors_ground_env(klisp_State *K); diff --git a/src/kgc.c b/src/kgc.c @@ -604,6 +604,7 @@ static void markroot (klisp_State *K) { /* NOTE: next_x_params is protected by next_obj */ markvalue(K, K->eval_op); markvalue(K, K->list_app); + markvalue(K, K->memoize_app); markvalue(K, K->ground_env); markvalue(K, K->module_params_sym); markvalue(K, K->root_cont); @@ -626,9 +627,12 @@ static void markroot (klisp_State *K) { markvalue(K, K->curr_port); + markvalue(K, K->require_path); + markvalue(K, K->require_table); + /* Mark all objects in the auxiliary stack, - (all valid indexes are below top), all the objects in - the two protected areas, and the three dummy pairs */ + (all valid indexes are below top) and all the objects in + the two protected areas */ markvaluearray(K, K->sbuf, K->stop); markvaluearray(K, K->rooted_tvs_buf, K->rooted_tvs_top); /* the area protecting variables is an array of type TValue *[] */ @@ -637,9 +641,6 @@ static void markroot (klisp_State *K) { markvalue(K, **ptr); } - markvalue(K, K->dummy_pair1); - markvalue(K, K->dummy_pair2); - markvalue(K, K->dummy_pair3); K->gcstate = GCSpropagate; } diff --git a/src/kgchars.c b/src/kgchars.c @@ -17,6 +17,7 @@ #include "koperative.h" #include "kcontinuation.h" #include "kerror.h" +#include "kchar.h" #include "kghelpers.h" #include "kgchars.h" @@ -30,14 +31,6 @@ /* 14.1.3? char-upper-case?, char-lower-case? */ /* use ftyped_predp */ -/* Helpers for typed predicates */ -bool kcharp(TValue tv) { return ttischar(tv); } -bool kchar_alphabeticp(TValue ch) { return isalpha(chvalue(ch)) != 0; } -bool kchar_numericp(TValue ch) { return isdigit(chvalue(ch)) != 0; } -bool kchar_whitespacep(TValue ch) { return isspace(chvalue(ch)) != 0; } -bool kchar_upper_casep(TValue ch) { return isupper(chvalue(ch)) != 0; } -bool kchar_lower_casep(TValue ch) { return islower(chvalue(ch)) != 0; } - /* 14.1.4? char->integer, integer->char */ void kchar_to_integer(klisp_State *K) { @@ -76,32 +69,21 @@ void kinteger_to_char(klisp_State *K) kapply_cc(K, ch2tv((char) i)); } -/* 14.1.4? char-upcase, char-downcase */ -void kchar_upcase(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue ptree = K->next_value; - TValue denv = K->next_env; - klisp_assert(ttisenvironment(K->next_env)); - UNUSED(xparams); - UNUSED(denv); - bind_1tp(K, ptree, "character", ttischar, chtv); - char ch = chvalue(chtv); - ch = toupper(ch); - kapply_cc(K, ch2tv(ch)); -} - -void kchar_downcase(klisp_State *K) +/* 14.1.4? char-upcase, char-downcase, char-titlecase, char-foldcase */ +void kchar_change_case(klisp_State *K) { TValue *xparams = K->next_xparams; TValue ptree = K->next_value; TValue denv = K->next_env; klisp_assert(ttisenvironment(K->next_env)); - UNUSED(xparams); + /* + ** xparams[0]: conversion fn + */ UNUSED(denv); bind_1tp(K, ptree, "character", ttischar, chtv); char ch = chvalue(chtv); - ch = tolower(ch); + char (*fn)(char) = pvalue(xparams[0]); + ch = fn(ch); kapply_cc(K, ch2tv(ch)); } @@ -117,27 +99,89 @@ void kchar_downcase(klisp_State *K) /* 14.2.4? char-ci<?, char-ci<=?, char-ci>?, char-ci>=? */ /* use ftyped_bpredp */ -/* Helpers for binary typed predicates */ -bool kchar_eqp(TValue ch1, TValue ch2) { return chvalue(ch1) == chvalue(ch2); } -bool kchar_ltp(TValue ch1, TValue ch2) { return chvalue(ch1) < chvalue(ch2); } -bool kchar_lep(TValue ch1, TValue ch2) { return chvalue(ch1) <= chvalue(ch2); } -bool kchar_gtp(TValue ch1, TValue ch2) { return chvalue(ch1) > chvalue(ch2); } -bool kchar_gep(TValue ch1, TValue ch2) { return chvalue(ch1) >= chvalue(ch2); } +/* 14.2.? char-digit?, char->digit, digit->char */ +void char_digitp(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + UNUSED(denv); + UNUSED(xparams); + bind_al1tp(K, ptree, "character", ttischar, chtv, basetv); + + int base = 10; /* default */ + + if (get_opt_tpar(K, basetv, "base [2-36]", ttisbase)) { + base = ivalue(basetv); + } + char ch = tolower(chvalue(chtv)); + bool b = (isdigit(ch) && (ch - '0') < base) || + (isalpha(ch) && (ch - 'a' + 10) < base); + kapply_cc(K, b2tv(b)); +} + +void char_to_digit(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + UNUSED(denv); + UNUSED(xparams); + bind_al1tp(K, ptree, "character", ttischar, chtv, basetv); + + int base = 10; /* default */ + + if (get_opt_tpar(K, basetv, "base [2-36]", ttisbase)) { + base = ivalue(basetv); + } + char ch = tolower(chvalue(chtv)); + int digit = 0; + + if (isdigit(ch) && (ch - '0') < base) + digit = ch - '0'; + else if (isalpha(ch) && (ch - 'a' + 10) < base) + digit = ch - 'a' + 10; + else { + klispE_throw_simple_with_irritants(K, "Not a digit in this base", + 2, ch2tv(ch), i2tv(base)); + return; + } + kapply_cc(K, i2tv(digit)); +} -bool kchar_ci_eqp(TValue ch1, TValue ch2) -{ return tolower(chvalue(ch1)) == tolower(chvalue(ch2)); } +void digit_to_char(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); -bool kchar_ci_ltp(TValue ch1, TValue ch2) -{ return tolower(chvalue(ch1)) < tolower(chvalue(ch2)); } + UNUSED(denv); + UNUSED(xparams); + bind_al1tp(K, ptree, "exact integer", ttiseinteger, digittv, basetv); -bool kchar_ci_lep(TValue ch1, TValue ch2) -{ return tolower(chvalue(ch1)) <= tolower(chvalue(ch2)); } + int base = 10; /* default */ -bool kchar_ci_gtp(TValue ch1, TValue ch2) -{ return tolower(chvalue(ch1)) > tolower(chvalue(ch2)); } + if (get_opt_tpar(K, basetv, "base [2-36]", ttisbase)) { + base = ivalue(basetv); + } -bool kchar_ci_gep(TValue ch1, TValue ch2) -{ return tolower(chvalue(ch1)) >= tolower(chvalue(ch2)); } + if (ttisbigint(digittv) || ivalue(digittv) < 0 || + ivalue(digittv) >= base) { + klispE_throw_simple_with_irritants(K, "Not a digit in this base", + 2, digittv, i2tv(base)); + return; + } + int digit = ivalue(digittv); + char ch = digit <= 9? + '0' + digit : + 'a' + (digit - 10); + kapply_cc(K, ch2tv(ch)); +} /* init ground */ void kinit_chars_ground_env(klisp_State *K) @@ -174,9 +218,15 @@ void kinit_chars_ground_env(klisp_State *K) /* 14.1.4? char->integer, integer->char */ add_applicative(K, ground_env, "char->integer", kchar_to_integer, 0); add_applicative(K, ground_env, "integer->char", kinteger_to_char, 0); - /* 14.1.4? char-upcase, char-downcase */ - add_applicative(K, ground_env, "char-upcase", kchar_upcase, 0); - add_applicative(K, ground_env, "char-downcase", kchar_downcase, 0); + /* 14.1.4? char-upcase, char-downcase, char-titlecase, char-foldcase */ + add_applicative(K, ground_env, "char-upcase", kchar_change_case, 1, + p2tv(toupper)); + add_applicative(K, ground_env, "char-downcase", kchar_change_case, 1, + p2tv(tolower)); + add_applicative(K, ground_env, "char-titlecase", kchar_change_case, 1, + p2tv(toupper)); + add_applicative(K, ground_env, "char-foldcase", kchar_change_case, 1, + p2tv(tolower)); /* 14.2.1? char=? */ add_applicative(K, ground_env, "char=?", ftyped_bpredp, 3, symbol, p2tv(kcharp), p2tv(kchar_eqp)); @@ -201,4 +251,8 @@ void kinit_chars_ground_env(klisp_State *K) symbol, p2tv(kcharp), p2tv(kchar_ci_gtp)); add_applicative(K, ground_env, "char-ci>=?", ftyped_bpredp, 3, symbol, p2tv(kcharp), p2tv(kchar_ci_gep)); + /* 14.2.? char-digit?, char->digit, digit->char */ + add_applicative(K, ground_env, "char-digit?", char_digitp, 0); + add_applicative(K, ground_env, "char->digit", char_to_digit, 0); + add_applicative(K, ground_env, "digit->char", digit_to_char, 0); } diff --git a/src/kgchars.h b/src/kgchars.h @@ -7,70 +7,7 @@ #ifndef kgchars_h #define kgchars_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* 14.1.1? char? */ -/* uses typep */ - -/* 14.1.2? char-alphabetic?, char-numeric?, char-whitespace? */ -/* use ftyped_predp */ - -/* 14.1.3? char-upper-case?, char-lower-case? */ -/* use ftyped_predp */ - -/* Helpers for typed predicates */ -/* XXX: this should probably be in a file kchar.h but there is no real need for - that file yet */ -bool kcharp(TValue tv); -bool kchar_alphabeticp(TValue ch); -bool kchar_numericp(TValue ch); -bool kchar_whitespacep(TValue ch); -bool kchar_upper_casep(TValue ch); -bool kchar_lower_casep(TValue ch); - -/* 14.1.4? char->integer, integer->char */ -void kchar_to_integer(klisp_State *K); -void kinteger_to_char(klisp_State *K); - -/* 14.1.4? char-upcase, char-downcase */ -void kchar_upcase(klisp_State *K); -void kchar_downcase(klisp_State *K); - -/* 14.2.1? char=? */ -/* uses ftyped_bpredp */ - -/* 14.2.2? char<?, char<=?, char>?, char>=? */ -/* use ftyped_bpredp */ - -/* 14.2.3? char-ci=? */ -/* uses ftyped_bpredp */ - -/* 14.2.4? char-ci<?, char-ci<=?, char-ci>?, char-ci>=? */ -/* use ftyped_bpredp */ - -/* Helpers for typed binary predicates */ -/* XXX: this should probably be in a file kchar.h but there is no real need for - that file yet */ -bool kchar_eqp(TValue ch1, TValue ch2); -bool kchar_ltp(TValue ch1, TValue ch2); -bool kchar_lep(TValue ch1, TValue ch2); -bool kchar_gtp(TValue ch1, TValue ch2); -bool kchar_gep(TValue ch1, TValue ch2); - -bool kchar_ci_eqp(TValue ch1, TValue ch2); -bool kchar_ci_ltp(TValue ch1, TValue ch2); -bool kchar_ci_lep(TValue ch1, TValue ch2); -bool kchar_ci_gtp(TValue ch1, TValue ch2); -bool kchar_ci_gep(TValue ch1, TValue ch2); /* init ground */ void kinit_chars_ground_env(klisp_State *K); diff --git a/src/kgcombiners.c b/src/kgcombiners.c @@ -21,14 +21,18 @@ #include "kerror.h" #include "kghelpers.h" -#include "kgpair_mut.h" /* for copy_es_immutable_h */ -#include "kgenv_mut.h" /* for match */ -#include "kgcontrol.h" /* for do_seq */ #include "kgcombiners.h" -/* Helper (used by $vau & $lambda) */ +/* continuations */ void do_vau(klisp_State *K); +void do_map(klisp_State *K); +void do_map_ret(klisp_State *K); +void do_map_encycle(klisp_State *K); +void do_map_cycle(klisp_State *K); + +void do_array_map_ret(klisp_State *K); + /* 4.10.1 operative? */ /* uses typep */ @@ -47,13 +51,13 @@ void Svau(klisp_State *K) bind_al2p(K, ptree, vptree, vpenv, vbody); /* The ptree & body are copied to avoid mutation */ - vptree = check_copy_ptree(K, "$vau", vptree, vpenv); + vptree = check_copy_ptree(K, vptree, vpenv); krooted_tvs_push(K, vptree); /* the body should be a list */ - UNUSED(check_list(K, "$vau", true, vbody, NULL)); - vbody = copy_es_immutable_h(K, "$vau", vbody, false); + check_list(K, true, vbody, NULL, NULL); + vbody = copy_es_immutable_h(K, vbody, false); krooted_tvs_push(K, vbody); @@ -101,8 +105,7 @@ void do_vau(klisp_State *K) /* protect env */ krooted_tvs_push(K, env); - /* TODO use name from operative */ - match(K, "[user-operative]", env, op_ptree, ptree); + match(K, env, op_ptree, ptree); if (!ttisignore(penv)) kadd_binding(K, env, penv, denv); @@ -182,11 +185,11 @@ void Slambda(klisp_State *K) bind_al1p(K, ptree, vptree, vbody); /* The ptree & body are copied to avoid mutation */ - vptree = check_copy_ptree(K, "$lambda", vptree, KIGNORE); + vptree = check_copy_ptree(K, vptree, KIGNORE); krooted_tvs_push(K, vptree); /* the body should be a list */ - UNUSED(check_list(K, "$lambda", true, vbody, NULL)); - vbody = copy_es_immutable_h(K, "$lambda", vbody, false); + check_list(K, true, vbody, NULL, NULL); + vbody = copy_es_immutable_h(K, vbody, false); krooted_tvs_push(K, vbody); @@ -235,205 +238,6 @@ void apply(klisp_State *K) ktail_eval(K, expr, env); } -/* Helpers for map (also used by for each) */ -void map_for_each_get_metrics(klisp_State *K, char *name, TValue lss, - int32_t *app_apairs_out, int32_t *app_cpairs_out, - int32_t *res_apairs_out, int32_t *res_cpairs_out) -{ - /* avoid warnings (shouldn't happen if _No_return was used in throw) */ - *app_apairs_out = 0; - *app_cpairs_out = 0; - *res_apairs_out = 0; - *res_cpairs_out = 0; - - /* get the metrics of the ptree of each call to app */ - int32_t app_cpairs; - int32_t app_pairs = check_list(K, name, true, lss, &app_cpairs); - int32_t app_apairs = app_pairs - app_cpairs; - - /* get the metrics of the result list */ - int32_t res_cpairs; - /* We now that lss has at least one elem */ - int32_t res_pairs = check_list(K, name, true, kcar(lss), &res_cpairs); - int32_t res_apairs = res_pairs - res_cpairs; - - if (res_cpairs == 0) { - /* finite list of length res_pairs (all lists should - have the same structure: acyclic with same length) */ - int32_t pairs = app_pairs - 1; - TValue tail = kcdr(lss); - while(pairs--) { - int32_t first_cpairs; - int32_t first_pairs = check_list(K, name, true, kcar(tail), - &first_cpairs); - tail = kcdr(tail); - - if (first_cpairs != 0) { - klispE_throw_simple(K, "mixed finite and infinite lists"); - return; - } else if (first_pairs != res_pairs) { - klispE_throw_simple(K, "lists of different length"); - return; - } - } - } else { - /* cyclic list: all lists should be cyclic. - result will have acyclic length equal to the - max of all the lists and cyclic length equal to the lcm - of all the lists. res_pairs may be broken but will be - restored by after the loop */ - int32_t pairs = app_pairs - 1; - TValue tail = kcdr(lss); - while(pairs--) { - int32_t first_cpairs; - int32_t first_pairs = check_list(K, name, true, kcar(tail), - &first_cpairs); - int32_t first_apairs = first_pairs - first_cpairs; - tail = kcdr(tail); - - if (first_cpairs == 0) { - klispE_throw_simple(K, "mixed finite and infinite lists"); - return; - } - res_apairs = kmax32(res_apairs, first_apairs); - /* this can throw an error if res_cpairs doesn't - fit in 32 bits, which is a reasonable implementation - restriction because the list wouldn't fit in memory - anyways */ - res_cpairs = kcheck32(K, "map/for-each: result list is too big", - klcm32_64(res_cpairs, first_cpairs)); - } - res_pairs = kcheck32(K, "map/for-each: result list is too big", - (int64_t) res_cpairs + (int64_t) res_apairs); - UNUSED(res_pairs); - } - - *app_apairs_out = app_apairs; - *app_cpairs_out = app_cpairs; - *res_apairs_out = res_apairs; - *res_cpairs_out = res_cpairs; -} - -/* Return two lists, isomorphic to lss: one list of cars and one list - of cdrs (replacing the value of lss) */ - -/* GC: assumes lss is rooted, and dummy1 & 2 are free in K */ -TValue map_for_each_get_cars_cdrs(klisp_State *K, TValue *lss, - int32_t apairs, int32_t cpairs) -{ - TValue tail = *lss; - - TValue lp_cars = kget_dummy1(K); - TValue lap_cars = lp_cars; - - TValue lp_cdrs = kget_dummy2(K); - TValue lap_cdrs = lp_cdrs; - - while(apairs != 0 || cpairs != 0) { - int32_t pairs; - if (apairs != 0) { - pairs = apairs; - } else { - /* remember last acyclic pair of both lists to to encycle! later */ - lap_cars = lp_cars; - lap_cdrs = lp_cdrs; - pairs = cpairs; - } - - while(pairs--) { - TValue first = kcar(tail); - tail = kcdr(tail); - - /* accumulate both cars and cdrs */ - TValue np; - np = kcons(K, kcar(first), KNIL); - kset_cdr(lp_cars, np); - lp_cars = np; - - np = kcons(K, kcdr(first), KNIL); - kset_cdr(lp_cdrs, np); - lp_cdrs = np; - } - - if (apairs != 0) { - apairs = 0; - } else { - cpairs = 0; - /* encycle! the list of cars and the list of cdrs */ - TValue fcp, lcp; - fcp = kcdr(lap_cars); - lcp = lp_cars; - kset_cdr(lcp, fcp); - - fcp = kcdr(lap_cdrs); - lcp = lp_cdrs; - kset_cdr(lcp, fcp); - } - } - - *lss = kcutoff_dummy2(K); - return kcutoff_dummy1(K); -} - -/* Transpose lss so that the result is a list of lists, each one having - metrics (app_apairs, app_cpairs). The metrics of the returned list - should be (res_apairs, res_cpairs) */ - -/* GC: assumes lss is rooted */ -TValue map_for_each_transpose(klisp_State *K, TValue lss, - int32_t app_apairs, int32_t app_cpairs, - int32_t res_apairs, int32_t res_cpairs) -{ - /* reserve dummy1 & 2 to get_cars_cdrs */ - TValue lp = kget_dummy3(K); - TValue lap = lp; - - TValue cars = KNIL; /* put something for GC */ - TValue tail = lss; - - /* GC: both cars & tail vary in each loop, to protect them we need - the vars stack */ - krooted_vars_push(K, &cars); - krooted_vars_push(K, &tail); - - /* Loop over list of lists, creating a list of cars and - a list of cdrs, accumulate the list of cars and loop - with the list of cdrs as the new list of lists (lss) */ - while(res_apairs != 0 || res_cpairs != 0) { - int32_t pairs; - - if (res_apairs != 0) { - pairs = res_apairs; - } else { - pairs = res_cpairs; - /* remember last acyclic pair to encycle! later */ - lap = lp; - } - - while(pairs--) { - /* accumulate cars and replace tail with cdrs */ - cars = map_for_each_get_cars_cdrs(K, &tail, app_apairs, app_cpairs); - TValue np = kcons(K, cars, KNIL); - kset_cdr(lp, np); - lp = np; - } - - if (res_apairs != 0) { - res_apairs = 0; - } else { - res_cpairs = 0; - /* encycle! the list of list of cars */ - TValue fcp = kcdr(lap); - TValue lcp = lp; - kset_cdr(lcp, fcp); - } - } - - krooted_vars_pop(K); - krooted_vars_pop(K); - return kcutoff_dummy3(K); -} - /* Continuation helpers for map */ /* For acyclic input lists: Return the mapped list */ @@ -451,7 +255,7 @@ void do_map_ret(klisp_State *K) and later mutation of the result */ /* XXX: the check isn't necessary really, but there is no list_copy */ - TValue copy = check_copy_list(K, "map", kcdr(xparams[0]), false); + TValue copy = check_copy_list(K, kcdr(xparams[0]), false, NULL, NULL); kapply_cc(K, copy); } @@ -478,7 +282,7 @@ void do_map_encycle(klisp_State *K) and later mutation of the result */ /* XXX: the check isn't necessary really, but there is no list_copy */ - TValue copy = check_copy_list(K, "map", kcdr(xparams[0]), false); + TValue copy = check_copy_list(K, kcdr(xparams[0]), false, NULL, NULL); kapply_cc(K, copy); } @@ -517,7 +321,7 @@ void do_map(klisp_State *K) /* copy the ptree to avoid problems with mutation */ /* XXX: no check necessary, could just use copy_list if there was such a procedure */ - TValue first_ptree = check_copy_list(K, "map", kcar(ls), false); + TValue first_ptree = check_copy_list(K, kcar(ls), false, NULL, NULL); ls = kcdr(ls); n = n-1; krooted_tvs_push(K, first_ptree); @@ -596,7 +400,7 @@ void map(klisp_State *K) int32_t app_pairs, app_apairs, app_cpairs; int32_t res_pairs, res_apairs, res_cpairs; - map_for_each_get_metrics(K, "map", lss, &app_apairs, &app_cpairs, + map_for_each_get_metrics(K, lss, &app_apairs, &app_cpairs, &res_apairs, &res_cpairs); app_pairs = app_apairs + app_cpairs; res_pairs = res_apairs + res_cpairs; @@ -640,12 +444,142 @@ void map(klisp_State *K) kapply_cc(K, KINERT); } +/* +** These are from r7rs (except bytevector). For now just follow +** Kernel version of (list) map. That means that the objects should +** all have the same size, and that the dynamic environment is passed +** to the applicatives. Continuation capturing interaction is still +** an open issue (see comment in map). +*/ + +/* NOTE: the type error on the result of app are only checked after + all values are collected. This could be changed if necessary, by + having map continuations take an additional typecheck param */ +/* Helpers for array_map */ + +/* copy the resulting list to a new vector */ +void do_array_map_ret(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + /* + ** xparams[0]: (dummy . complete-ls) + ** xparams[1]: list->array + ** xparams[2]: length + */ + UNUSED(obj); + + TValue ls = kcdr(xparams[0]); + TValue (*list_to_array)(klisp_State *K, TValue array, int32_t size) = + pvalue(xparams[1]); + int32_t length = ivalue(xparams[2]); + + /* This will also avoid some problems with continuations + captured from within the dynamic extent to map + and later mutation of the result */ + TValue copy = list_to_array(K, ls, length); + kapply_cc(K, copy); +} + +/* 5.9.? string-map */ +/* 5.9.? vector-map */ +/* 5.9.? bytevector-map */ +void array_map(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + /* + ** xparams[0]: list->array fn + ** xparams[1]: array->list fn (with type check and size ret) + */ + + TValue list_to_array_tv = xparams[0]; + TValue (*array_to_list)(klisp_State *K, TValue array, int32_t *size) = + pvalue(xparams[1]); + + bind_al1tp(K, ptree, "applicative", ttisapplicative, app, lss); + + /* check that lss is a non empty list, and copy it */ + if (ttisnil(lss)) { + klispE_throw_simple(K, "no arguments after applicative"); + return; + } + + int32_t app_pairs, app_apairs, app_cpairs; + /* the copied list should be protected from gc, and will host + the lists resulting from the conversion */ + lss = check_copy_list(K, lss, true, &app_pairs, &app_cpairs); + app_apairs = app_pairs - app_cpairs; + krooted_tvs_push(K, lss); + + /* check that all elements have the correct type and same size, + and convert them to lists */ + int32_t res_pairs; + TValue head = kcar(lss); + TValue tail = kcdr(lss); + TValue ls = array_to_list(K, head, &res_pairs); + kset_car(lss, ls); /* save the first */ + /* all array will produce acyclic lists */ + + for(int32_t i = 1 /* jump over first */; i < app_pairs; ++i) { + head = kcar(tail); + int32_t pairs; + ls = array_to_list(K, head, &pairs); + /* in klisp all arrays should have the same length */ + if (pairs != res_pairs) { + klispE_throw_simple(K, "arguments of different length"); + return; + } + kset_car(tail, ls); + tail = kcdr(tail); + } + + /* create the list of parameters to app */ + lss = map_for_each_transpose(K, lss, app_apairs, app_cpairs, + res_pairs, 0); /* cycle pairs is always 0 */ + + /* ASK John: the semantics when this is mixed with continuations, + isn't all that great..., but what are the expectations considering + there is no prescribed order? */ + + krooted_tvs_pop(K); + krooted_tvs_push(K, lss); + /* This will be the list to be returned, but it will be transformed + to an array before returning (making it also play a little nicer + with continuations) */ + TValue dummy = kcons(K, KINERT, KNIL); + + krooted_tvs_push(K, dummy); + + TValue ret_cont = + kmake_continuation(K, kget_cc(K), do_array_map_ret, 3, dummy, + list_to_array_tv, i2tv(res_pairs)); + krooted_tvs_push(K, ret_cont); + + /* schedule the mapping of the elements of the acyclic part. + signal dummyp = true to avoid creating a pair for + the inert value passed to the first continuation */ + TValue new_cont = + kmake_continuation(K, ret_cont, do_map, 6, app, lss, dummy, + i2tv(res_pairs), denv, KTRUE); + + krooted_tvs_pop(K); + krooted_tvs_pop(K); + krooted_tvs_pop(K); + + kset_cc(K, new_cont); + + /* this will be a nop, and will continue with do_map */ + kapply_cc(K, KINERT); +} + /* 6.2.1 combiner? */ /* uses ftypedp */ -/* Helper for combiner? */ -bool kcombinerp(TValue obj) { return ttiscombiner(obj); } - /* init ground */ void kinit_combiners_ground_env(klisp_State *K) { @@ -671,7 +605,29 @@ void kinit_combiners_ground_env(klisp_State *K) add_applicative(K, ground_env, "apply", apply, 0); /* 5.9.1 map */ add_applicative(K, ground_env, "map", map, 0); + /* 5.9.? string-map, vector-map, bytevector-map */ + add_applicative(K, ground_env, "string-map", array_map, 2, + p2tv(list_to_string_h), p2tv(string_to_list_h)); + add_applicative(K, ground_env, "vector-map", array_map, 2, + p2tv(list_to_vector_h), p2tv(vector_to_list_h)); + add_applicative(K, ground_env, "bytevector-map", array_map, 2, + p2tv(list_to_bytevector_h), p2tv(bytevector_to_list_h)); /* 6.2.1 combiner? */ add_applicative(K, ground_env, "combiner?", ftypep, 2, symbol, p2tv(kcombinerp)); } + +/* init continuation names */ +void kinit_combiners_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + + add_cont_name(K, t, do_vau, "$vau-bind!-eval"); + + add_cont_name(K, t, do_map, "map-acyclic-part"); + add_cont_name(K, t, do_map_encycle, "map-encycle!"); + add_cont_name(K, t, do_map_ret, "map-ret"); + add_cont_name(K, t, do_map_cycle, "map-cyclic-part"); + + add_cont_name(K, t, do_array_map_ret, "array-map-ret"); +} diff --git a/src/kgcombiners.h b/src/kgcombiners.h @@ -7,83 +7,11 @@ #ifndef kgcombiners_h #define kgcombiners_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* 4.10.1 operative? */ -/* uses typep */ - -/* 4.10.2 applicative? */ -/* uses typep */ - -/* 4.10.3 $vau */ -/* 5.3.1 $vau */ -void Svau(klisp_State *K); - -/* 4.10.4 wrap */ -void wrap(klisp_State *K); - -/* 4.10.5 unwrap */ -void unwrap(klisp_State *K); - -/* 5.3.1 $vau */ -/* DONE: above, together with 4.10.4 */ - -/* 5.3.2 $lambda */ -void Slambda(klisp_State *K); - -/* 5.5.1 apply */ -void apply(klisp_State *K); - -/* Helpers for map (also used by for each) */ - -/* Calculate the metrics for both the result list and the ptree - passed to the applicative */ -void map_for_each_get_metrics( - klisp_State *K, char *name, TValue lss, int32_t *app_apairs_out, - int32_t *app_cpairs_out, int32_t *res_apairs_out, int32_t *res_cpairs_out); - -/* Return two lists, isomorphic to lss: one list of cars and one list - of cdrs (replacing the value of lss) */ -/* GC: Assumes lss is rooted, uses dummys 2 & 3 */ -TValue map_for_each_get_cars_cdrs(klisp_State *K, TValue *lss, - int32_t apairs, int32_t cpairs); - -/* Transpose lss so that the result is a list of lists, each one having - metrics (app_apairs, app_cpairs). The metrics of the returned list - should be (res_apairs, res_cpairs) */ - -/* GC: Assumes lss is rooted, uses dummys 1, & - (through get_cars_cdrs, 2, 3) */ -TValue map_for_each_transpose(klisp_State *K, TValue lss, - int32_t app_apairs, int32_t app_cpairs, - int32_t res_apairs, int32_t res_cpairs); - -/* 5.9.1 map */ -void map(klisp_State *K); - -/* 6.2.1 combiner? */ -/* uses ftypedp */ - -/* Helper for combiner? */ -bool kcombinerp(TValue obj); - - -void do_vau(klisp_State *K); -void do_map_ret(klisp_State *K); -void do_map_encycle(klisp_State *K); -void do_map(klisp_State *K); -void do_map_cycle(klisp_State *K); /* init ground */ void kinit_combiners_ground_env(klisp_State *K); +/* init continuation names */ +void kinit_combiners_cont_names(klisp_State *K); #endif diff --git a/src/kgcontinuations.c b/src/kgcontinuations.c @@ -22,7 +22,9 @@ #include "kghelpers.h" #include "kgcontinuations.h" -#include "kgcontrol.h" /* for seq helpers in $let/cc */ + +/* Continuations */ +void do_extended_cont(klisp_State *K); /* 7.1.1 continuation? */ /* uses typep */ @@ -84,92 +86,6 @@ void extend_continuation(klisp_State *K) kapply_cc(K, new_cont); } -/* Helpers for guard-continuation (& guard-dynamic-extent) */ - -/* this is used for inner & outer continuations, it just - passes the value. xparams is not actually empty, it contains - the entry/exit guards, but they are used only in - continuation->applicative (that is during abnormal passes) */ -void do_pass_value(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - UNUSED(xparams); - kapply_cc(K, obj); -} - -#define singly_wrapped(obj_) (ttisapplicative(obj_) && \ - ttisoperative(kunwrap(obj_))) - -/* this unmarks root before throwing any error */ -/* TODO: this isn't very clean, refactor */ - -/* GC: assumes obj & root are rooted, dummy1 is in use */ -inline TValue check_copy_single_entry(klisp_State *K, char *name, - TValue obj, TValue root) -{ - if (!ttispair(obj) || !ttispair(kcdr(obj)) || - !ttisnil(kcddr(obj))) { - unmark_list(K, root); - klispE_throw_simple(K, "Bad entry (expected list of length 2)"); - return KINERT; - } - TValue cont = kcar(obj); - TValue app = kcadr(obj); - - if (!ttiscontinuation(cont)) { - unmark_list(K, root); - klispE_throw_simple(K, "Bad type on first element (expected " - "continuation)"); - return KINERT; - } else if (!singly_wrapped(app)) { - unmark_list(K, root); - klispE_throw_simple(K, "Bad type on second element (expected " - "singly wrapped applicative)"); - return KINERT; - } - - /* save the operative directly, don't waste space/time - with a list, use just a pair */ - return kcons(K, cont, kunwrap(app)); -} - -/* the guards are probably generated on the spot so we don't check - for immutability and copy it anyways */ -/* GC: Assumes obj is rooted */ -TValue check_copy_guards(klisp_State *K, char *name, TValue obj) -{ - if (ttisnil(obj)) { - return obj; - } else { - TValue last_pair = kget_dummy1(K); - TValue tail = obj; - - while(ttispair(tail) && !kis_marked(tail)) { - /* this will clear the marks and throw an error if the structure - is incorrect */ - TValue entry = check_copy_single_entry(K, name, kcar(tail), obj); - krooted_tvs_push(K, entry); - TValue new_pair = kcons(K, entry, KNIL); - krooted_tvs_pop(K); - kmark(tail); - kset_cdr(last_pair, new_pair); - last_pair = new_pair; - tail = kcdr(tail); - } - - /* dont close the cycle (if there is one) */ - unmark_list(K, obj); - TValue ret = kcutoff_dummy1(K); - if (!ttispair(tail) && !ttisnil(tail)) { - klispE_throw_simple(K, "expected list"); - return KINERT; - } - return ret; - } -} - /* 7.2.4 guard-continuation */ void guard_continuation(klisp_State *K) { @@ -280,7 +196,7 @@ void Slet_cc(klisp_State *K) /* the list of instructions is copied to avoid mutation */ /* MAYBE: copy the evaluation structure, ASK John */ - TValue ls = check_copy_list(K, "$let/cc", objs, false); + TValue ls = check_copy_list(K, objs, false, NULL, NULL); krooted_tvs_push(K, ls); /* this is needed because seq continuation doesn't check for @@ -300,47 +216,11 @@ void Slet_cc(klisp_State *K) } /* 7.3.3 guard-dynamic-extent */ -void guard_dynamic_extent(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue ptree = K->next_value; - TValue denv = K->next_env; - klisp_assert(ttisenvironment(K->next_env)); - UNUSED(xparams); - - bind_3tp(K, ptree, "any", anytype, entry_guards, - "combiner", ttiscombiner, comb, - "any", anytype, exit_guards); - - entry_guards = check_copy_guards(K, "guard-dynamic-extent: entry guards", - entry_guards); - krooted_tvs_push(K, entry_guards); - exit_guards = check_copy_guards(K, "guard-dynamic-extent: exit guards", - exit_guards); - krooted_tvs_push(K, exit_guards); - /* GC: root continuations */ - /* The current continuation is guarded */ - TValue outer_cont = kmake_continuation(K, kget_cc(K), do_pass_value, - 2, entry_guards, denv); - kset_outer_cont(outer_cont); - kset_cc(K, outer_cont); /* this implicitly roots outer_cont */ - - TValue inner_cont = kmake_continuation(K, outer_cont, do_pass_value, 2, - exit_guards, denv); - kset_inner_cont(inner_cont); - - /* call combiner with no operands in the dynamic extent of inner, - with the dynamic env of this call */ - kset_cc(K, inner_cont); /* this implicitly roots inner_cont */ - TValue expr = kcons(K, comb, KNIL); - - krooted_tvs_pop(K); - krooted_tvs_pop(K); - - ktail_eval(K, expr, denv); -} +/* in kghelpers */ /* 7.3.4 exit */ +/* Unlike in the report, in klisp this takes an optional argument + to be passed to the root continuation (defaults to #inert) */ void kgexit(klisp_State *K) { TValue *xparams = K->next_xparams; @@ -350,11 +230,13 @@ void kgexit(klisp_State *K) UNUSED(denv); UNUSED(xparams); - check_0p(K, ptree); + TValue obj = ptree; + if (!get_opt_tpar(K, obj, "any", anytype)) + obj = KINERT; /* TODO: look out for guards and dynamic variables */ /* should be probably handled in kcall_cont() */ - kcall_cont(K, K->root_cont, KINERT); + kcall_cont(K, K->root_cont, obj); } /* init ground */ @@ -398,3 +280,11 @@ void kinit_continuations_ground_env(klisp_State *K) add_applicative(K, ground_env, "exit", kgexit, 0); } + +/* init continuation names */ +void kinit_continuations_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + + add_cont_name(K, t, do_extended_cont, "extended-cont"); +} diff --git a/src/kgcontinuations.h b/src/kgcontinuations.h @@ -7,56 +7,11 @@ #ifndef kgcontinuations_h #define kgcontinuations_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* Helpers (also used in keyed dynamic code) */ -void do_pass_value(klisp_State *K); - -/* 7.1.1 continuation? */ -/* uses typep */ - -/* 7.2.2 call/cc */ -void call_cc(klisp_State *K); - -/* 7.2.3 extend-continuation */ -void extend_continuation(klisp_State *K); - -/* 7.2.4 guard-continuation */ -void guard_continuation(klisp_State *K); - -/* 7.2.5 continuation->applicative */ -void continuation_applicative(klisp_State *K); - -/* 7.2.6 root-continuation */ -/* done in kground.c/krepl.c */ - -/* 7.2.7 error-continuation */ -/* done in kground.c/krepl.c */ - -/* 7.3.1 apply-continuation */ -void apply_continuation(klisp_State *K); - -/* 7.3.2 $let/cc */ -void Slet_cc(klisp_State *K); - -/* 7.3.3 guard-dynamic-extent */ -void guard_dynamic_extent(klisp_State *K); - -/* 7.3.4 exit */ -void kgexit(klisp_State *K); - -void do_extended_cont(klisp_State *K); /* init ground */ void kinit_continuations_ground_env(klisp_State *K); +/* init continuation names */ +void kinit_continuations_cont_names(klisp_State *K); #endif diff --git a/src/kgcontrol.c b/src/kgcontrol.c @@ -18,16 +18,18 @@ #include "kghelpers.h" #include "kgcontrol.h" -#include "kgcombiners.h" /* for map/for-each helpers */ + +/* Continuations */ +void do_select_clause(klisp_State *K); +void do_cond(klisp_State *K); +void do_for_each(klisp_State *K); +void do_Swhen_Sunless(klisp_State *K); /* 4.5.1 inert? */ /* uses typep */ /* 4.5.2 $if */ -/* helpers */ -void do_select_clause(klisp_State *K); - /* ASK JOHN: both clauses should probably be copied (copy-es-immutable) */ void Sif(klisp_State *K) { @@ -35,8 +37,8 @@ void Sif(klisp_State *K) TValue ptree = K->next_value; TValue denv = K->next_env; klisp_assert(ttisenvironment(K->next_env)); - (void) denv; - (void) xparams; + UNUSED(denv); + UNUSED(xparams); bind_3p(K, ptree, test, cons_c, alt_c); @@ -86,7 +88,7 @@ void Ssequence(klisp_State *K) } else { /* the list of instructions is copied to avoid mutation */ /* MAYBE: copy the evaluation structure, ASK John */ - TValue ls = check_copy_list(K, "$sequence", ptree, false); + TValue ls = check_copy_list(K, ptree, false, NULL, NULL); /* this is needed because seq continuation doesn't check for nil sequence */ /* TODO this could be at least in an inlineable function to @@ -108,37 +110,6 @@ void Ssequence(klisp_State *K) } } -/* Helper (also used by $vau and $lambda) */ -/* the remaining list can't be null, that case is managed before */ -void do_seq(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - - UNUSED(obj); - - /* - ** xparams[0]: remaining list - ** xparams[1]: dynamic environment - */ - TValue ls = xparams[0]; - TValue first = kcar(ls); - TValue tail = kcdr(ls); - TValue denv = xparams[1]; - - if (ttispair(tail)) { - TValue new_cont = kmake_continuation(K, kget_cc(K), do_seq, 2, tail, - denv); - kset_cc(K, new_cont); -#if KTRACK_SI - /* put the source info of the list including the element - that we are about to evaluate */ - kset_source_info(K, new_cont, ktry_get_si(K, ls)); -#endif - } - ktail_eval(K, first, denv); -} /* Helpers for cond */ @@ -154,14 +125,19 @@ void do_seq(klisp_State *K) TValue split_check_cond_clauses(klisp_State *K, TValue clauses, TValue *bodies) { - TValue last_car_pair = kget_dummy1(K); - TValue last_cdr_pair = kget_dummy2(K); + TValue cars = kcons(K, KNIL, KNIL); + krooted_vars_push(K, &cars); + TValue last_car_pair = cars; + + TValue cdrs = kcons(K, KNIL, KNIL); + krooted_vars_push(K, &cdrs); + TValue last_cdr_pair = cdrs; TValue tail = clauses; int32_t count = 0; while(ttispair(tail) && !kis_marked(tail)) { - count++; + ++count; TValue first = kcar(tail); if (!ttispair(first)) { unmark_list(K, clauses); @@ -193,25 +169,26 @@ TValue split_check_cond_clauses(klisp_State *K, TValue clauses, if (!ttispair(tail) && !ttisnil(tail)) { klispE_throw_simple(K, "expected list (clauses)"); return KNIL; - } else { - /* - check all the bodies (should be lists), and - make a copy of the list structure. - couldn't be done before because this uses - marks, count is used because it may be a cyclic list - */ - tail = kget_dummy2_tail(K); - while(count--) { - TValue first = kcar(tail); - /* this uses dummy3 */ - TValue copy = check_copy_list(K, "$cond", first, false); - kset_car(tail, copy); - tail = kcdr(tail); - } + } - *bodies = kcutoff_dummy2(K); - return kcutoff_dummy1(K); + /* + check all the bodies (should be lists), and + make a copy of the list structure. + couldn't be done before because this uses + marks, count is used because it may be a cyclic list + */ + tail = kcdr(cdrs); + while(count--) { + TValue first = kcar(tail); + TValue copy = check_copy_list(K, first, false, NULL, NULL); + kset_car(tail, copy); + tail = kcdr(tail); } + + *bodies = kcdr(cdrs); + krooted_vars_pop(K); + krooted_vars_pop(K); + return kcdr(cars); } /* Helper for the $cond continuation */ @@ -339,7 +316,7 @@ void do_for_each(klisp_State *K) /* copy the ptree to avoid problems with mutation */ /* XXX: no check necessary, could just use copy_list if there was such a procedure */ - TValue first_ptree = check_copy_list(K, "for-each", kcar(ls), false); + TValue first_ptree = check_copy_list(K, kcar(ls), false, NULL, NULL); krooted_tvs_push(K, first_ptree); ls = kcdr(ls); n = n-1; @@ -376,7 +353,7 @@ void for_each(klisp_State *K) int32_t app_pairs, app_apairs, app_cpairs; int32_t res_pairs, res_apairs, res_cpairs; - map_for_each_get_metrics(K, "for-each", lss, &app_apairs, &app_cpairs, + map_for_each_get_metrics(K, lss, &app_apairs, &app_cpairs, &res_apairs, &res_cpairs); app_pairs = app_apairs + app_cpairs; res_pairs = res_apairs + res_cpairs; @@ -398,6 +375,178 @@ void for_each(klisp_State *K) kapply_cc(K, KINERT); } +/* 6.9.? string-for-each, vector-for-each, bytevector-for-each */ +void array_for_each(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + /* + ** xparams[1]: array->list fn (with type check and size ret) + */ + + TValue (*array_to_list)(klisp_State *K, TValue array, int32_t *size) = + pvalue(xparams[0]); + + bind_al1tp(K, ptree, "applicative", ttisapplicative, app, lss); + + /* check that lss is a non empty list, and copy it */ + if (ttisnil(lss)) { + klispE_throw_simple(K, "no arguments after applicative"); + return; + } + + int32_t app_pairs, app_apairs, app_cpairs; + /* the copied list should be protected from gc, and will host + the lists resulting from the conversion */ + lss = check_copy_list(K, lss, true, &app_pairs, &app_cpairs); + app_apairs = app_pairs - app_cpairs; + krooted_tvs_push(K, lss); + + /* check that all elements have the correct type and same size, + and convert them to lists */ + int32_t res_pairs; + TValue head = kcar(lss); + TValue tail = kcdr(lss); + TValue ls = array_to_list(K, head, &res_pairs); + kset_car(lss, ls); /* save the first */ + /* all array will produce acyclic lists */ + for(int32_t i = 1 /* jump over first */; i < app_pairs; ++i) { + head = kcar(tail); + int32_t pairs; + ls = array_to_list(K, head, &pairs); + /* in klisp all arrays should have the same length */ + if (pairs != res_pairs) { + klispE_throw_simple(K, "arguments of different length"); + return; + } + kset_car(tail, ls); + tail = kcdr(tail); + } + + /* create the list of parameters to app */ + lss = map_for_each_transpose(K, lss, app_apairs, app_cpairs, + res_pairs, 0); /* cycle pairs is always 0 */ + + /* ASK John: the semantics when this is mixed with continuations, + isn't all that great..., but what are the expectations considering + there is no prescribed order? */ + + krooted_tvs_pop(K); + krooted_tvs_push(K, lss); + + /* schedule all elements at once, this will also return #inert once + done. */ + TValue new_cont = + kmake_continuation(K, kget_cc(K), do_for_each, 4, app, lss, + i2tv(res_pairs), denv); + kset_cc(K, new_cont); + krooted_tvs_pop(K); + /* this will be a nop */ + kapply_cc(K, KINERT); +} + +/* Helper for $when and $unless */ +void do_Swhen_Sunless(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + + /* + ** xparams[0]: bool condition + ** xparams[1]: body + ** xparams[2]: denv + ** xparams[3]: si for whole form + */ + bool cond = bvalue(xparams[0]); + TValue ls = xparams[1]; + TValue denv = xparams[2]; +#if KTRACK_SI + TValue si = xparams[3]; +#endif + + if (!ttisboolean(obj)) { + klispE_throw_simple(K, "test is not a boolean"); + return; + } + + if (bvalue(obj) == cond && !ttisnil(ls)) { + /* only contruct the #inert returning continuation if the + current continuation is not of the same type */ + if (!kis_inert_ret_cont(kget_cc(K))) { + TValue new_cont = + kmake_continuation(K, kget_cc(K), do_return_value, 1, KINERT); + /* mark it, so that it can be detected as inert throwing cont */ + kset_inert_ret_cont(new_cont); + kset_cc(K, new_cont); +#if KTRACK_SI + /* put the source info of the whole form */ + kset_source_info(K, new_cont, si); +#endif + } + /* this is needed because seq continuation doesn't check for + nil sequence */ + /* TODO this could be at least in an inlineable function to + allow used from $lambda, $vau, $let family, load, etc */ + TValue tail = kcdr(ls); + if (ttispair(tail)) { + krooted_tvs_push(K, ls); + TValue new_cont = kmake_continuation(K, kget_cc(K), do_seq, 2, + tail, denv); + kset_cc(K, new_cont); +#if KTRACK_SI + /* put the source info of the list including the element + that we are about to evaluate */ + kset_source_info(K, new_cont, ktry_get_si(K, ls)); +#endif + krooted_tvs_pop(K); + } + ktail_eval(K, kcar(ls), denv); + } else { + /* either the test failed or the body was nil */ + kapply_cc(K, KINERT); + } +} + +/* ASK JOHN: list is copied here (like in $sequence) */ +void Swhen_Sunless(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + bind_al1p(K, ptree, test, body); + + /* + ** xparams[0]: bool condition + */ + TValue tv_cond = xparams[0]; + + /* the list of instructions is copied to avoid mutation */ + /* MAYBE: copy the evaluation structure, ASK John */ + TValue ls = check_copy_list(K, body, false, NULL, NULL); + krooted_tvs_push(K, ls); + /* prepare the continuation that will check the test result + and do the evaluation */ + TValue si = K->next_si; /* this is the source info of the whole + $when/$unless form */ + TValue new_cont = kmake_continuation(K, kget_cc(K), do_Swhen_Sunless, + 4, tv_cond, ls, denv, si); + krooted_tvs_pop(K); + /* + ** Mark as a bool checking cont, not necessary but avoids a continuation + ** in the last evaluation in the common use of + ** ($when/$unless ($or?/$and? ...) ...) + */ + kset_bool_check_cont(new_cont); + kset_cc(K, new_cont); + ktail_eval(K, test, denv); +} + /* init ground */ void kinit_control_ground_env(klisp_State *K) { @@ -415,4 +564,28 @@ void kinit_control_ground_env(klisp_State *K) add_operative(K, ground_env, "$cond", Scond, 0); /* 6.9.1 for-each */ add_applicative(K, ground_env, "for-each", for_each, 0); + /* 6.9.? string-for-each, vector-for-each, bytevector-for-each */ + add_applicative(K, ground_env, "string-for-each", array_for_each, 1, + p2tv(string_to_list_h)); + add_applicative(K, ground_env, "vector-for-each", array_for_each, 1, + p2tv(vector_to_list_h)); + add_applicative(K, ground_env, "bytevector-for-each", array_for_each, 1, + p2tv(bytevector_to_list_h)); + /* ?.? */ + add_operative(K, ground_env, "$when", Swhen_Sunless, 1, + b2tv(true)); + add_operative(K, ground_env, "$unless", Swhen_Sunless, 1, + b2tv(false)); +} + +/* init continuation names */ +void kinit_control_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + + add_cont_name(K, t, do_select_clause, "select-clause"); + add_cont_name(K, t, do_Swhen_Sunless, "conditional-eval-sequence"); + + add_cont_name(K, t, do_cond, "eval-cond-list"); + add_cont_name(K, t, do_for_each, "for-each"); } diff --git a/src/kgcontrol.h b/src/kgcontrol.h @@ -7,44 +7,11 @@ #ifndef kgcontrol_h #define kgcontrol_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* 4.5.1 inert? */ -/* uses typep */ - -/* 4.5.2 $if */ - -void Sif(klisp_State *K); - -/* 5.1.1 $sequence */ -void Ssequence(klisp_State *K); - -/* Helpers for $cond */ -TValue split_check_cond_clauses(klisp_State *K, TValue clauses, - TValue *bodies); - - -/* 5.6.1 $cond */ -void Scond(klisp_State *K); - -/* 6.9.1 for-each */ -void for_each(klisp_State *K); - -void do_seq(klisp_State *K); -void do_cond(klisp_State *K); -void do_select_clause(klisp_State *K); -void do_for_each(klisp_State *K); /* init ground */ void kinit_control_ground_env(klisp_State *K); +/* init continuation names */ +void kinit_control_cont_names(klisp_State *K); #endif diff --git a/src/kgencapsulations.c b/src/kgencapsulations.c @@ -23,39 +23,7 @@ /* Helpers for make-encapsulation-type */ /* Type predicate for encapsulations */ -void enc_typep(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue ptree = K->next_value; - TValue denv = K->next_env; - klisp_assert(ttisenvironment(K->next_env)); - UNUSED(denv); - /* - ** xparams[0]: encapsulation key - */ - TValue key = xparams[0]; - - /* check the ptree is a list while checking the predicate. - Keep going even if the result is false to catch errors in - ptree structure */ - bool res = true; - - TValue tail = ptree; - while(ttispair(tail) && kis_unmarked(tail)) { - kmark(tail); - res &= kis_encapsulation_type(kcar(tail), key); - tail = kcdr(tail); - } - unmark_list(K, ptree); - - if (ttispair(tail) || ttisnil(tail)) { - kapply_cc(K, b2tv(res)); - } else { - /* try to get name from encapsulation */ - klispE_throw_simple(K, "expected list"); - return; - } -} +/* enc_typep(klisp_State *K), in kghelpers */ /* Constructor for encapsulations */ void enc_wrap(klisp_State *K) diff --git a/src/kgencapsulations.h b/src/kgencapsulations.h @@ -7,22 +7,7 @@ #ifndef kgencapsulations_h #define kgencapsulations_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* needed by kgffi.c */ -void enc_typep(klisp_State *K); - -/* 8.1.1 make-encapsulation-type */ -void make_encapsulation_type(klisp_State *K); /* init ground */ void kinit_encapsulations_ground_env(klisp_State *K); diff --git a/src/kgenv_mut.c b/src/kgenv_mut.c @@ -20,7 +20,11 @@ #include "kghelpers.h" #include "kgenv_mut.h" -#include "kgcontrol.h" /* for do_seq */ + +/* Continuations */ +void do_match(klisp_State *K); +void do_set_eval_obj(klisp_State *K); +void do_import(klisp_State *K); /* 4.9.1 $define! */ void SdefineB(klisp_State *K) @@ -36,7 +40,7 @@ void SdefineB(klisp_State *K) TValue def_sym = xparams[0]; - dptree = check_copy_ptree(K, "$define!", dptree, KIGNORE); + dptree = check_copy_ptree(K, dptree, KIGNORE); krooted_tvs_push(K, dptree); @@ -61,9 +65,8 @@ void do_match(klisp_State *K) */ TValue ptree = xparams[0]; TValue env = xparams[1]; - char *name = ksymbol_buf(xparams[2]); - match(K, name, env, ptree, obj); + match(K, env, ptree, obj); kapply_cc(K, KINERT); } @@ -80,7 +83,7 @@ void SsetB(klisp_State *K) bind_3p(K, ptree, env_exp, raw_formals, eval_exp); - TValue formals = check_copy_ptree(K, "$set!", raw_formals, KIGNORE); + TValue formals = check_copy_ptree(K, raw_formals, KIGNORE); krooted_tvs_push(K, formals); TValue new_cont = @@ -142,13 +145,15 @@ inline void unmark_maybe_symbol_list(klisp_State *K, TValue ls) ** Check that obj is a finite list of symbols with no duplicates and ** returns a copy of the list (cf. check_copy_ptree) */ -/* GC: Assumes obj is rooted, uses dummy1 */ -TValue check_copy_symbol_list(klisp_State *K, char *name, TValue obj) +/* GC: Assumes obj is rooted */ +TValue check_copy_symbol_list(klisp_State *K, TValue obj) { TValue tail = obj; bool type_errorp = false; bool repeated_errorp = false; - TValue last_pair = kget_dummy1(K); + TValue slist = kcons(K, KNIL, KNIL); + krooted_vars_push(K, &slist); + TValue last_pair = slist; while(ttispair(tail) && !kis_marked(tail)) { /* even if there is a type error continue checking the structure */ @@ -173,14 +178,14 @@ TValue check_copy_symbol_list(klisp_State *K, char *name, TValue obj) klispE_throw_simple(K, "expected finite list"); return KNIL; } else if (type_errorp) { - /* TODO put type name too */ klispE_throw_simple(K, "bad operand type (expected list of " "symbols)"); return KNIL; } else if (repeated_errorp) { klispE_throw_simple(K, "repeated symbols"); } - return kcutoff_dummy1(K); + krooted_vars_pop(K); + return kcdr(slist); } void do_import(klisp_State *K) @@ -222,13 +227,12 @@ void SprovideB(klisp_State *K) ** xparams[0]: name as symbol */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al1p(K, ptree, symbols, body); - symbols = check_copy_symbol_list(K, name, symbols); + symbols = check_copy_symbol_list(K, symbols); krooted_tvs_push(K, symbols); - body = check_copy_list(K, name, body, false); + body = check_copy_list(K, body, false, NULL, NULL); krooted_tvs_push(K, body); TValue new_env = kmake_environment(K, denv); @@ -293,11 +297,10 @@ void SimportB(klisp_State *K) ** xparams[0]: name as symbol */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al1p(K, ptree, env_expr, symbols); - symbols = check_copy_symbol_list(K, name, symbols); + symbols = check_copy_symbol_list(K, symbols); /* REFACTOR/ASK John: another way for this kind of operative would be to first eval the env expression and only then check the type @@ -328,3 +331,14 @@ void kinit_env_mut_ground_env(klisp_State *K) /* 6.8.3 $import! */ add_operative(K, ground_env, "$import!", SimportB, 1, symbol); } + +/* init continuation names */ +void kinit_env_mut_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + + add_cont_name(K, t, do_match, "match-ptree"); + add_cont_name(K, t, do_set_eval_obj, "set-eval-obj"); + add_cont_name(K, t, do_import, "import-bindings"); +} + diff --git a/src/kgenv_mut.h b/src/kgenv_mut.h @@ -7,250 +7,12 @@ #ifndef kgenv_mut_h #define kgenv_mut_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* helpers */ -inline void match(klisp_State *K, char *name, TValue env, TValue ptree, - TValue obj); -void do_match(klisp_State *K); -inline void ptree_clear_all(klisp_State *K, TValue sym_ls); -inline TValue check_copy_ptree(klisp_State *K, char *name, TValue ptree, - TValue penv); -/* 4.9.1 $define! */ -void SdefineB(klisp_State *K); - -/* MAYBE: don't make these inline */ -/* -** Clear all the marks (symbols + pairs) & stacks. -** The stack should contain only pairs, sym_ls should be -** as above -*/ -inline void ptree_clear_all(klisp_State *K, TValue sym_ls) -{ - while(!ttisnil(sym_ls)) { - TValue first = sym_ls; - sym_ls = kget_symbol_mark(first); - kunmark_symbol(first); - } - - while(!ks_sisempty(K)) { - kunmark(ks_sget(K)); - ks_sdpop(K); - } - - ks_tbclear(K); -} - -/* GC: assumes env, ptree & obj are rooted */ -inline void match(klisp_State *K, char *name, TValue env, TValue ptree, - TValue obj) -{ - assert(ks_sisempty(K)); - ks_spush(K, obj); - ks_spush(K, ptree); - - while(!ks_sisempty(K)) { - ptree = ks_spop(K); - obj = ks_spop(K); - - switch(ttype(ptree)) { - case K_TNIL: - if (!ttisnil(obj)) { - /* TODO show ptree and arguments */ - ks_sclear(K); - klispE_throw_simple(K, "ptree doesn't match arguments"); - return; - } - break; - case K_TIGNORE: - /* do nothing */ - break; - case K_TSYMBOL: - kadd_binding(K, env, ptree, obj); - break; - case K_TPAIR: - if (ttispair(obj)) { - ks_spush(K, kcdr(obj)); - ks_spush(K, kcdr(ptree)); - ks_spush(K, kcar(obj)); - ks_spush(K, kcar(ptree)); - } else { - /* TODO show ptree and arguments */ - ks_sclear(K); - klispE_throw_simple(K, "ptree doesn't match arguments"); - return; - } - break; - default: - /* can't really happen */ - break; - } - } -} - -/* GC: assumes ptree & penv are rooted */ -inline TValue check_copy_ptree(klisp_State *K, char *name, TValue ptree, - TValue penv) -{ - /* copy is only valid if the state isn't ST_PUSH */ - /* but init anyways for gc (and avoiding warnings) */ - TValue copy = ptree; - krooted_vars_push(K, &copy); - - /* - ** NIL terminated singly linked list of symbols - ** (using the mark as next pointer) - */ - TValue sym_ls = KNIL; - - assert(ks_sisempty(K)); - assert(ks_tbisempty(K)); - - ks_tbpush(K, ST_PUSH); - ks_spush(K, ptree); - - while(!ks_sisempty(K)) { - char state = ks_tbpop(K); - TValue top = ks_spop(K); - - if (state == ST_PUSH) { - switch(ttype(top)) { - case K_TIGNORE: - case K_TNIL: - copy = top; - break; - case K_TSYMBOL: { - if (kis_symbol_marked(top)) { - ptree_clear_all(K, sym_ls); - klispE_throw_simple_with_irritants(K, "repeated symbol " - "in ptree", 1, top); - return KNIL; - } else { - copy = top; - /* add it to the symbol list */ - kset_symbol_mark(top, sym_ls); - sym_ls = top; - } - break; - } - case K_TPAIR: { - if (kis_unmarked(top)) { - if (kis_immutable(top)) { - /* don't copy mutable pairs, just use them */ - /* NOTE: immutable pairs can't have mutable - car or cdr */ - /* we have to continue thou, because there could be a - cycle */ - kset_mark(top, top); - } else { - /* create a new pair as copy, save it in the mark */ - TValue new_pair = kimm_cons(K, KNIL, KNIL); - kset_mark(top, new_pair); - /* copy the source code info */ - TValue si = ktry_get_si(K, top); - if (!ttisnil(si)) - kset_source_info(K, new_pair, si); - } - /* keep the old pair and continue with the car */ - ks_tbpush(K, ST_CAR); - ks_spush(K, top); - - ks_tbpush(K, ST_PUSH); - ks_spush(K, kcar(top)); - } else { - /* marked pair means a cycle was found */ - /* NOTE: the pair should be in the stack already so - it isn't necessary to push it again to clear the mark */ - ptree_clear_all(K, sym_ls); - klispE_throw_simple(K, "cycle detected in ptree"); - /* avoid warning */ - return KNIL; - } - break; - } - default: - ptree_clear_all(K, sym_ls); - klispE_throw_simple(K, "bad object type in ptree"); - /* avoid warning */ - return KNIL; - } - } else { - /* last operation was a pop */ - /* top is a marked pair, the mark is the copied obj */ - /* NOTE: if top is immutable the mark is also top - we could still do the set-car/set-cdr because the - copy would be the same as the car/cdr, but why bother */ - if (state == ST_CAR) { - /* only car was checked (not yet copied) */ - if (kis_mutable(top)) { - TValue copied_pair = kget_mark(top); - /* copied_pair may be immutable */ - kset_car_unsafe(K, copied_pair, copy); - } - /* put the copied pair again, continue with the cdr */ - ks_tbpush(K, ST_CDR); - ks_spush(K, top); - - ks_tbpush(K, ST_PUSH); - ks_spush(K, kcdr(top)); - } else { - /* both car & cdr were checked (cdr not yet copied) */ - TValue copied_pair = kget_mark(top); - /* the unmark is needed to allow diamonds */ - kunmark(top); - - if (kis_mutable(top)) { - /* copied_pair may be immutable */ - kset_cdr_unsafe(K, copied_pair, copy); - } - copy = copied_pair; - } - } - } - - if (ttissymbol(penv)) { - if (kis_symbol_marked(penv)) { - ptree_clear_all(K, sym_ls); - klispE_throw_simple_with_irritants(K, "same symbol in both ptree " - "and environment parameter", - 1, sym_ls); - } - } else if (!ttisignore(penv)) { - ptree_clear_all(K, sym_ls); - klispE_throw_simple(K, "symbol or #ignore expected as " - "environment parmameter"); - } - ptree_clear_all(K, sym_ls); - krooted_vars_pop(K); - return copy; -} - -/* 6.8.1 $set! */ -void SsetB(klisp_State *K); - -/* Helper for $set! */ -void do_set_eval_obj(klisp_State *K); - -/* Helpers for $provide & $import! */ -TValue check_copy_symbol_list(klisp_State *K, char *name, TValue obj); -void do_import(klisp_State *K); - -/* 6.8.2 $provide! */ -void SprovideB(klisp_State *K); - -/* 6.8.3 $import! */ -void SimportB(klisp_State *K); /* init ground */ void kinit_env_mut_ground_env(klisp_State *K); +/* init continuation names */ +void kinit_env_mut_cont_names(klisp_State *K); + #endif diff --git a/src/kgenvironments.c b/src/kgenvironments.c @@ -20,10 +20,13 @@ #include "kghelpers.h" #include "kgenvironments.h" -#include "kgenv_mut.h" /* for check_ptree */ -#include "kgpair_mut.h" /* for copy_es_immutable_h */ -#include "kgcontrol.h" /* for do_seq */ -/* MAYBE: move the above to kghelpers.h */ + +/* Continuations */ +void do_let(klisp_State *K); +void do_let_redirect(klisp_State *K); +void do_bindsp(klisp_State *K); +void do_remote_eval(klisp_State *K); +void do_b_to_env(klisp_State *K); /* 4.8.1 environment? */ /* uses typep */ @@ -75,7 +78,7 @@ void make_environment(klisp_State *K) } else { /* this is the general case, copy the list but without the cycle if there is any */ - TValue parents = check_copy_env_list(K, "make-environment", ptree); + TValue parents = check_copy_env_list(K, ptree); krooted_tvs_push(K, parents); new_env = kmake_environment(K, parents); krooted_tvs_pop(K); @@ -97,12 +100,16 @@ void make_environment(klisp_State *K) ** If bindings is not finite (or not a list) an error is signaled. */ -/* GC: assume bindings is rooted, uses dummys 1 & 2 */ -TValue split_check_let_bindings(klisp_State *K, char *name, TValue bindings, +/* GC: assume bindings is rooted */ +TValue split_check_let_bindings(klisp_State *K, TValue bindings, TValue *exprs, bool starp) { - TValue last_car_pair = kget_dummy1(K); - TValue last_cadr_pair = kget_dummy2(K); + TValue cars = kcons(K, KNIL, KNIL); + krooted_vars_push(K, &cars); + TValue last_car_pair = cars; + TValue cadrs = kcons(K, KNIL, KNIL); + krooted_vars_push(K, &cadrs); + TValue last_cadr_pair = cadrs; TValue tail = bindings; @@ -139,20 +146,21 @@ TValue split_check_let_bindings(klisp_State *K, char *name, TValue bindings, if (starp) { /* all bindings are consider individual ptrees in these 'let's, replace each ptree with its copy (after checking of course) */ - tail = kget_dummy1_tail(K); + tail = kcdr(cars); while(!ttisnil(tail)) { TValue first = kcar(tail); - TValue copy = check_copy_ptree(K, name, first, KIGNORE); + TValue copy = check_copy_ptree(K, first, KIGNORE); kset_car(tail, copy); tail = kcdr(tail); } - res = kget_dummy1_tail(K); + res = kcdr(cars); } else { /* all bindings are consider one ptree in these 'let's */ - res = check_copy_ptree(K, name, kget_dummy1_tail(K), KIGNORE); + res = check_copy_ptree(K, kcdr(cars), KIGNORE); } - *exprs = kcutoff_dummy2(K); - UNUSED(kcutoff_dummy1(K)); + *exprs = kcdr(cadrs); + krooted_vars_pop(K); + krooted_vars_pop(K); return res; } } @@ -177,7 +185,6 @@ void do_let(klisp_State *K) ** xparams[6]: body */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); TValue ptree = xparams[1]; TValue bindings = xparams[2]; TValue exprs = xparams[3]; @@ -185,7 +192,7 @@ void do_let(klisp_State *K) bool recp = bvalue(xparams[5]); TValue body = xparams[6]; - match(K, name, env, ptree, obj); + match(K, env, ptree, obj); if (ttisnil(bindings)) { if (ttisnil(body)) { @@ -231,16 +238,15 @@ void Slet(klisp_State *K) ** xparams[0]: symbol name */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al1p(K, ptree, bindings, body); TValue exprs; - TValue bptree = split_check_let_bindings(K, name, bindings, &exprs, false); + TValue bptree = split_check_let_bindings(K, bindings, &exprs, false); krooted_tvs_push(K, bptree); krooted_tvs_push(K, exprs); - UNUSED(check_list(K, name, true, body, NULL)); - body = copy_es_immutable_h(K, name, body, false); + check_list(K, true, body, NULL, NULL); + body = copy_es_immutable_h(K, body, false); krooted_tvs_push(K, body); TValue new_env = kmake_environment(K, denv); @@ -304,9 +310,9 @@ void Sbindsp(klisp_State *K) bind_al1p(K, ptree, env_expr, symbols); /* REFACTOR replace with single function check_copy_typed_list */ - int32_t count = check_typed_list(K, "$binds?", "symbol", ksymbolp, - true, symbols, NULL); - symbols = check_copy_list(K, "$binds?", symbols, false); + int32_t count; + check_typed_list(K, ksymbolp, true, symbols, &count, NULL); + symbols = check_copy_list(K, symbols, false, NULL, NULL); krooted_tvs_push(K, symbols); TValue new_cont = kmake_continuation(K, kget_cc(K), do_bindsp, @@ -356,15 +362,14 @@ void SletS(klisp_State *K) ** xparams[0]: symbol name */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al1p(K, ptree, bindings, body); TValue exprs; - TValue bptree = split_check_let_bindings(K, name, bindings, &exprs, true); + TValue bptree = split_check_let_bindings(K, bindings, &exprs, true); krooted_tvs_push(K, exprs); krooted_tvs_push(K, bptree); - UNUSED(check_list(K, name, true, body, NULL)); - body = copy_es_immutable_h(K, name, body, false); + check_list(K, true, body, NULL, NULL); + body = copy_es_immutable_h(K, body, false); krooted_tvs_push(K, body); TValue new_env = kmake_environment(K, denv); @@ -409,16 +414,15 @@ void Sletrec(klisp_State *K) ** xparams[0]: symbol name */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al1p(K, ptree, bindings, body); TValue exprs; - TValue bptree = split_check_let_bindings(K, name, bindings, &exprs, false); + TValue bptree = split_check_let_bindings(K, bindings, &exprs, false); krooted_tvs_push(K, exprs); krooted_tvs_push(K, bptree); - UNUSED(check_list(K, name, true, body, NULL)); - body = copy_es_immutable_h(K, name, body, false); + check_list(K, true, body, NULL, NULL); + body = copy_es_immutable_h(K, body, false); krooted_tvs_push(K, body); TValue new_env = kmake_environment(K, denv); @@ -450,15 +454,14 @@ void SletrecS(klisp_State *K) ** xparams[0]: symbol name */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al1p(K, ptree, bindings, body); TValue exprs; - TValue bptree = split_check_let_bindings(K, name, bindings, &exprs, true); + TValue bptree = split_check_let_bindings(K, bindings, &exprs, true); krooted_tvs_push(K, exprs); krooted_tvs_push(K, bptree); - UNUSED(check_list(K, name, true, body, NULL)); - body = copy_es_immutable_h(K, name, body, false); + check_list(K, true, body, NULL, NULL); + body = copy_es_immutable_h(K, body, false); krooted_tvs_push(K, body); TValue new_env = kmake_environment(K, denv); @@ -538,16 +541,15 @@ void Slet_redirect(klisp_State *K) ** xparams[0]: symbol name */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al2p(K, ptree, env_exp, bindings, body); TValue exprs; - TValue bptree = split_check_let_bindings(K, name, bindings, &exprs, false); + TValue bptree = split_check_let_bindings(K, bindings, &exprs, false); krooted_tvs_push(K, exprs); krooted_tvs_push(K, bptree); - UNUSED(check_list(K, name, true, body, NULL)); - body = copy_es_immutable_h(K, name, body, false); + check_list(K, true, body, NULL, NULL); + body = copy_es_immutable_h(K, body, false); krooted_tvs_push(K, body); TValue eexpr = kcons(K, K->list_app, exprs); @@ -577,17 +579,16 @@ void Slet_safe(klisp_State *K) ** xparams[0]: symbol name */ TValue sname = xparams[0]; - char *name = ksymbol_buf(sname); bind_al1p(K, ptree, bindings, body); TValue exprs; - TValue bptree = split_check_let_bindings(K, name, bindings, &exprs, false); + TValue bptree = split_check_let_bindings(K, bindings, &exprs, false); krooted_tvs_push(K, exprs); krooted_tvs_push(K, bptree); - UNUSED(check_list(K, name, true, body, NULL)); + check_list(K, true, body, NULL, NULL); - body = copy_es_immutable_h(K, name, body, false); + body = copy_es_immutable_h(K, body, false); krooted_tvs_push(K, body); /* according to the definition of the report it should be a child @@ -657,7 +658,7 @@ void do_b_to_env(klisp_State *K) TValue ptree = xparams[0]; TValue env = xparams[1]; - match(K, "$bindings->environment", env, ptree, obj); + match(K, env, ptree, obj); kapply_cc(K, env); } @@ -670,8 +671,7 @@ void Sbindings_to_environment(klisp_State *K) klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); TValue exprs; - TValue bptree = split_check_let_bindings(K, "$bindings->environment", - ptree, &exprs, false); + TValue bptree = split_check_let_bindings(K, ptree, &exprs, false); krooted_tvs_push(K, exprs); krooted_tvs_push(K, bptree); @@ -732,3 +732,15 @@ void kinit_environments_ground_env(klisp_State *K) add_operative(K, ground_env, "$bindings->environment", Sbindings_to_environment, 1, symbol); } + +/* init continuation names */ +void kinit_environments_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + + add_cont_name(K, t, do_let, "eval-let"); + add_cont_name(K, t, do_let_redirect, "eval-let-redirect"); + add_cont_name(K, t, do_bindsp, "eval-$binds?-env"); + add_cont_name(K, t, do_remote_eval, "eval-remote-eval-env"); + add_cont_name(K, t, do_b_to_env, "bindings-to-env"); +} diff --git a/src/kgenvironments.h b/src/kgenvironments.h @@ -7,80 +7,11 @@ #ifndef kgenvironments_h #define kgenvironments_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -/* 4.8.1 environment? */ -/* uses typep */ - -/* 4.8.2 ignore? */ -/* uses typep */ - -/* 4.8.3 eval */ -void eval(klisp_State *K); - -/* 4.8.4 make-environment */ -void make_environment(klisp_State *K); - -/* Helpers for all $let family */ -TValue split_check_let_bindings(klisp_State *K, char *name, TValue bindings, - TValue *exprs, bool starp); -/* 5.10.1 $let */ -void Slet(klisp_State *K); - -/* Helper for $binds? */ -void do_bindsp(klisp_State *K); - -/* 6.7.1 $binds? */ -void Sbindsp(klisp_State *K); - -/* 6.7.2 get-current-environment */ -void get_current_environment(klisp_State *K); - -/* 6.7.3 make-kernel-standard-environment */ -void make_kernel_standard_environment(klisp_State *K); - -/* 6.7.4 $let* */ -void SletS(klisp_State *K); - -/* 6.7.5 $letrec */ -void Sletrec(klisp_State *K); - -/* 6.7.6 $letrec* */ -void SletrecS(klisp_State *K); - -/* Helper for $let-redirect */ -void do_let_redirect(klisp_State *K); - -/* 6.7.7 $let-redirect */ -void Slet_redirect(klisp_State *K); - -/* 6.7.8 $let-safe */ -void Slet_safe(klisp_State *K); - -/* 6.7.9 $remote-eval */ -void Sremote_eval(klisp_State *K); - -/* Helper for $remote-eval */ -void do_remote_eval(klisp_State *K); - -/* Helper for $bindings->environment */ -void do_b_to_env(klisp_State *K); - -/* 6.7.10 $bindings->environment */ -void Sbindings_to_environment(klisp_State *K); - -void do_let(klisp_State *K); /* init ground */ void kinit_environments_ground_env(klisp_State *K); +/* init continuation names */ +void kinit_environments_cont_names(klisp_State *K); #endif diff --git a/src/kgeqp.c b/src/kgeqp.c @@ -31,7 +31,8 @@ void eqp(klisp_State *K) UNUSED(denv); UNUSED(xparams); - int32_t pairs = check_list(K, "eq?", true, ptree, NULL); + int32_t pairs; + check_list(K, true, ptree, &pairs, NULL); /* In this case we can get away without comparing the first and last element on a cycle because eq? is diff --git a/src/kgeqp.h b/src/kgeqp.h @@ -7,59 +7,7 @@ #ifndef kgeqp_h #define kgeqp_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - #include "kstate.h" -#include "kobject.h" -#include "kapplicative.h" /* for unwrap */ -#include "kinteger.h" /* for kbigint_eqp */ -#include "krational.h" /* for kbigrat_eqp */ -#include "klisp.h" -#include "kghelpers.h" - -/* 4.2.1 eq? */ -/* 6.5.1 eq? */ -void eqp(klisp_State *K); - -/* Helper (also used in equal?) */ -inline bool eq2p(klisp_State *K, TValue obj1, TValue obj2) -{ - bool res = (tv_equal(obj1, obj2)); - if (!res && (ttype(obj1) == ttype(obj2))) { - switch (ttype(obj1)) { - case K_TSYMBOL: - /* symbols can't be compared with tv_equal! */ - res = tv_sym_equal(obj1, obj2); - break; - case K_TAPPLICATIVE: - while(ttisapplicative(obj1) && ttisapplicative(obj2)) { - obj1 = kunwrap(obj1); - obj2 = kunwrap(obj2); - } - res = (tv_equal(obj1, obj2)); - break; - case K_TBIGINT: - /* it's important to know that it can't be the case - that obj1 is bigint and obj is some other type and - (eq? obj1 obj2) */ - res = kbigint_eqp(obj1, obj2); - break; - case K_TBIGRAT: - /* it's important to know that it can't be the case - that obj1 is bigrat and obj is some other type and - (eq? obj1 obj2) */ - res = kbigrat_eqp(K, obj1, obj2); - break; - } /* immutable strings & bytevectors are interned so they are - covered already by tv_equalp */ - - } - return res; -} /* init ground */ void kinit_eqp_ground_env(klisp_State *K); diff --git a/src/kgequalp.c b/src/kgequalp.c @@ -13,13 +13,13 @@ #include "kstate.h" #include "kobject.h" #include "kpair.h" +#include "kvector.h" #include "kstring.h" /* for kstring_equalp */ #include "kbytevector.h" /* for kbytevector_equalp */ #include "kcontinuation.h" #include "kerror.h" #include "kghelpers.h" -#include "kgeqp.h" /* for eq2p */ #include "kgequalp.h" /* 4.3.1 equal? */ @@ -43,7 +43,8 @@ void equalp(klisp_State *K) UNUSED(denv); UNUSED(xparams); - int32_t pairs = check_list(K, "equal?", true, ptree, NULL); + int32_t pairs; + check_list(K, true, ptree, &pairs, NULL); /* In this case we can get away without comparing the first and last element on a cycle because equal? is @@ -65,167 +66,6 @@ void equalp(klisp_State *K) kapply_cc(K, res); } - -/* -** Helpers -** -** See [2] for details of the list merging algorithm. -** Here are the implementation details: -** The marks of the pairs are used to store the nodes of the trees -** that represent the set of previous comparations of each pair. -** They serve the function of the array in [2]. -** If a pair is unmarked, it was never compared (empty comparison set). -** If a pair is marked, the mark object is either (#f . parent-node) -** if the node is not the root, and (#t . n) where n is the number -** of elements in the set, if the node is the root. -** This pair also doubles as the "name" of the set in [2]. -** -** GC: all of these assume that arguments are rooted. -*/ - -/* find "name" of the set of this obj, if there isn't one create it, - if there is one, flatten its branch */ -inline TValue equal_find(klisp_State *K, TValue obj) -{ - /* GC: should root obj */ - if (kis_unmarked(obj)) { - /* object wasn't compared before, create new set */ - TValue new_node = kcons(K, KTRUE, i2tv(1)); - kset_mark(obj, new_node); - return new_node; - } else { - TValue node = kget_mark(obj); - - /* First obtain the root and a list of all the other objects in this - branch, as said above the root is the one with #t in its car */ - /* NOTE: the stack is being used, so we must remember how many pairs we - push, we can't just pop 'till is empty */ - int np = 0; - while(kis_false(kcar(node))) { - ks_spush(K, node); - node = kcdr(node); - ++np; - } - TValue root = node; - - /* set all parents to root, to flatten the branch */ - while(np--) { - node = ks_spop(K); - kset_cdr(node, root); - } - return root; - } -} - -/* merge the smaller set into the big one, if both are equal just pick one */ -inline void equal_merge(klisp_State *K, TValue root1, TValue root2) -{ - /* K isn't needed but added for consistency */ - (void)K; - int32_t size1 = ivalue(kcdr(root1)); - int32_t size2 = ivalue(kcdr(root2)); - TValue new_size = i2tv(size1 + size2); - - if (size1 < size2) { - /* add root1 set (the smaller one) to root2 */ - kset_cdr(root2, new_size); - kset_car(root1, KFALSE); - kset_cdr(root1, root2); - } else { - /* add root2 set (the smaller one) to root1 */ - kset_cdr(root1, new_size); - kset_car(root2, KFALSE); - kset_cdr(root2, root1); - } -} - -/* check to see if two objects were already compared, and return that. If they - weren't compared yet, merge their sets (and flatten their branches) */ -inline bool equal_find2_mergep(klisp_State *K, TValue obj1, TValue obj2) -{ - /* GC: should root root1 and root2 */ - TValue root1 = equal_find(K, obj1); - TValue root2 = equal_find(K, obj2); - if (tv_equal(root1, root2)) { - /* they are in the same set => they were already compared */ - return true; - } else { - equal_merge(K, root1, root2); - return false; - } -} - -/* -** See [1] for details, in this case the pairs form a possibly infinite "tree" -** structure, and that can be seen as a finite automata, where each node is a -** state, the car and the cdr are the transitions from that state to others, -** and the leaves (the non-pair objects) are the final states. -** Other way to see it is that, the key for determining equalness of two pairs -** is: Check to see if they were already compared to each other. -** If so, return #t, otherwise, mark them as compared to each other and -** recurse on both cars and both cdrs. -** The idea is that if assuming obj1 and obj2 are equal their components are -** equal then they are effectively equal to each other. -*/ -bool equal2p(klisp_State *K, TValue obj1, TValue obj2) -{ - assert(ks_sisempty(K)); - - /* the stack has the elements to be compaired, always in pairs. - So the top should be compared with the one below, the third with - the fourth and so on */ - ks_spush(K, obj1); - ks_spush(K, obj2); - - /* if the stacks becomes empty, all pairs of elements were equal */ - bool result = true; - TValue saved_obj1 = obj1; - TValue saved_obj2 = obj2; - - while(!ks_sisempty(K)) { - obj2 = ks_spop(K); - obj1 = ks_spop(K); -/* REFACTOR these ifs: compare both types first, then switch on type */ - if (!eq2p(K, obj1, obj2)) { - if (ttispair(obj1) && ttispair(obj2)) { - /* if they were already compaired, consider equal for now - otherwise they are equal if both their cars and cdrs are */ - if (!equal_find2_mergep(K, obj1, obj2)) { - ks_spush(K, kcdr(obj1)); - ks_spush(K, kcdr(obj2)); - ks_spush(K, kcar(obj1)); - ks_spush(K, kcar(obj2)); - } - } else if (ttisstring(obj1) && ttisstring(obj2)) { - if (!kstring_equalp(obj1, obj2)) { - result = false; - break; - } - } else if (ttisbytevector(obj1) && ttisbytevector(obj2)) { - if (!kbytevector_equalp(obj1, obj2)) { - result = false; - break; - } - } else if (ttisvector(obj1) && ttisvector(obj2)) { - fprintf(stderr, "TODO: equal? for vectors not implemented!\n"); - result = false; - } else { - result = false; - break; - } - } - } - - /* if result is false, the stack may not be empty */ - ks_sclear(K); - - unmark_tree(K, saved_obj1); - unmark_tree(K, saved_obj2); - - return result; -} - - /* init ground */ void kinit_equalp_ground_env(klisp_State *K) { diff --git a/src/kgequalp.h b/src/kgequalp.h @@ -7,24 +7,7 @@ #ifndef kgequalp_h #define kgequalp_h -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - #include "kstate.h" -#include "kobject.h" -#include "klisp.h" -#include "kghelpers.h" - -/* 4.3.1 equal? */ -/* 6.6.1 equal? */ -void equalp(klisp_State *K); - -/* Helper (may be used in assoc and member) */ -/* compare two objects and check to see if they are "equal?". */ -bool equal2p(klisp_State *K, TValue obj1, TValue obj2); /* init ground */ void kinit_equalp_ground_env(klisp_State *K); diff --git a/src/kgerror.c b/src/kgerror.c @@ -1,95 +0,0 @@ -/* -** kgerror.c -** Error handling features for the ground environment -** See Copyright Notice in klisp.h -*/ - -#include <stdbool.h> -#include <stdint.h> - -#include "kstate.h" -#include "kobject.h" -#include "kstring.h" -#include "kpair.h" -#include "kerror.h" - -#include "kghelpers.h" -#include "kgerror.h" - -void r7rs_error(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue ptree = K->next_value; - TValue denv = K->next_env; - klisp_assert(ttisenvironment(K->next_env)); - UNUSED(xparams); - UNUSED(denv); - if (ttispair(ptree) && ttisstring(kcar(ptree))) { - klispE_throw_with_irritants(K, kstring_buf(kcar(ptree)), kcdr(ptree)); - } else { - klispE_throw_with_irritants(K, "Unknown error in user code", ptree); - } -} - -void error_object_message(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue ptree = K->next_value; - TValue denv = K->next_env; - klisp_assert(ttisenvironment(K->next_env)); - UNUSED(xparams); - UNUSED(denv); - bind_1tp(K, ptree, "error object", ttiserror, error_tv); - Error *err_obj = tv2error(error_tv); - klisp_assert(ttisstring(err_obj->msg)); - kapply_cc(K, err_obj->msg); -} - -void error_object_irritants(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue ptree = K->next_value; - TValue denv = K->next_env; - klisp_assert(ttisenvironment(K->next_env)); - UNUSED(xparams); - UNUSED(denv); - bind_1tp(K, ptree, "error object", ttiserror, error_tv); - Error *err_obj = tv2error(error_tv); - kapply_cc(K, err_obj->irritants); -} -/* REFACTOR this is the same as do_pass_value */ -void do_exception_cont(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - UNUSED(xparams); - /* Just pass error object to general error continuation. */ - kapply_cc(K, obj); -} - -/* REFACTOR maybe this should be in kerror.c */ -/* Create system-error-continuation. */ -void kinit_error_hierarchy(klisp_State *K) -{ - klisp_assert(ttiscontinuation(K->error_cont)); - klisp_assert(ttisinert(K->system_error_cont)); - - K->system_error_cont = kmake_continuation(K, K->error_cont, - do_exception_cont, 0); -} - -/* init ground */ -void kinit_error_ground_env(klisp_State *K) -{ - TValue ground_env = K->ground_env; - TValue symbol, value; - - add_applicative(K, ground_env, "error-object?", typep, 2, symbol, i2tv(K_TERROR)); - add_applicative(K, ground_env, "error", r7rs_error, 0); - add_applicative(K, ground_env, "error-object-message", error_object_message, 0); - add_applicative(K, ground_env, "error-object-irritants", error_object_irritants, 0); - - klisp_assert(ttiscontinuation(K->system_error_cont)); - add_value(K, ground_env, "system-error-continuation", K->system_error_cont); -} diff --git a/src/kgerror.h b/src/kgerror.h @@ -1,29 +0,0 @@ -/* -** kgerror.h -** Error handling features for the ground environment -** See Copyright Notice in klisp.h -*/ - -#ifndef kgerror_h -#define kgerror_h - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kobject.h" -#include "klisp.h" -#include "kstate.h" -#include "kghelpers.h" - -/* init ground */ -void kinit_error_ground_env(klisp_State *K); - -/* Second stage of itialization of ground environment. Must be - * called after initializing general error continuation - * K->error_cont. */ -void kinit_error_hierarchy(klisp_State *K); - -#endif diff --git a/src/kgerrors.c b/src/kgerrors.c @@ -0,0 +1,127 @@ +/* +** kgerrors.c +** Error handling features for the ground environment +** See Copyright Notice in klisp.h +*/ + +#include <stdbool.h> +#include <stdint.h> + +#include "kstate.h" +#include "kobject.h" +#include "kstring.h" +#include "kpair.h" +#include "kerror.h" + +#include "kghelpers.h" +#include "kgerrors.h" + +void kgerror(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + + bind_al1tp(K, ptree, "string", ttisstring, str, rest); + /* copy the list of irritants, to avoid modification later */ + /* also check that is a list! */ + TValue irritants = check_copy_list(K, rest, false, NULL, NULL); + krooted_tvs_push(K, irritants); + /* the msg is implicitly copied here */ + klispE_throw_with_irritants(K, kstring_buf(str), irritants); +} + +void kgraise(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + + bind_1p(K, ptree, obj); + kcall_cont(K, K->error_cont, obj); +} + +void error_object_message(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + bind_1tp(K, ptree, "error object", ttiserror, error_tv); + Error *err_obj = tv2error(error_tv); + /* the string is immutable, no need to copy it */ + klisp_assert(ttisstring(err_obj->msg)); + kapply_cc(K, err_obj->msg); +} + +void error_object_irritants(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + bind_1tp(K, ptree, "error object", ttiserror, error_tv); + Error *err_obj = tv2error(error_tv); + kapply_cc(K, err_obj->irritants); +} + +/* REFACTOR this is the same as do_pass_value */ +void do_exception_cont(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + UNUSED(xparams); + /* Just pass error object to general error continuation. */ + kapply_cc(K, obj); +} + +/* REFACTOR maybe this should be in kerror.c */ +/* Create system-error-continuation. */ +void kinit_error_hierarchy(klisp_State *K) +{ + klisp_assert(ttiscontinuation(K->error_cont)); + klisp_assert(ttisinert(K->system_error_cont)); + + K->system_error_cont = kmake_continuation(K, K->error_cont, + do_exception_cont, 0); +} + +/* init ground */ +void kinit_error_ground_env(klisp_State *K) +{ + TValue ground_env = K->ground_env; + TValue symbol, value; + + add_applicative(K, ground_env, "error-object?", typep, 2, symbol, + i2tv(K_TERROR)); + add_applicative(K, ground_env, "error", kgerror, 0); + add_applicative(K, ground_env, "raise", kgraise, 0); + /* MAYBE add get- and remove object from these names */ + add_applicative(K, ground_env, "error-object-message", + error_object_message, 0); + add_applicative(K, ground_env, "error-object-irritants", + error_object_irritants, 0); + /* TODO raise-continuable from r7rs doesn't make sense in the Kernel + system of handling continuations. + What we could have is a more sofisticated system + of restarts, which would be added to an error object + and would encapsulate continuations and descriptions of them. + It would be accessible with + error-object-restarts or something like that. + See Common Lisp and mit scheme for examples + */ + + klisp_assert(ttiscontinuation(K->system_error_cont)); + add_value(K, ground_env, "system-error-continuation", K->system_error_cont); +} diff --git a/src/kgerrors.h b/src/kgerrors.h @@ -0,0 +1,20 @@ +/* +** kgerror.h +** Error handling features for the ground environment +** See Copyright Notice in klisp.h +*/ + +#ifndef kgerrors_h +#define kgerrors_h + +#include "kstate.h" + +/* init ground */ +void kinit_error_ground_env(klisp_State *K); + +/* Second stage of itialization of ground environment. Must be + * called after initializing general error continuation + * K->error_cont. */ +void kinit_error_hierarchy(klisp_State *K); + +#endif diff --git a/src/kgffi.c b/src/kgffi.c @@ -41,9 +41,6 @@ #include "ktable.h" #include "kghelpers.h" -#include "kgencapsulations.h" -#include "kgcombiners.h" -#include "kgcontinuations.h" #include "kgffi.h" /* Set to 0 to ignore aligment errors during direct @@ -79,6 +76,10 @@ typedef struct { #define CB_INDEX_STACK 1 #define CB_INDEX_FIRST_CALLBACK 2 +/* Continuations */ +void do_ffi_callback_encode_result(klisp_State *K); +void do_ffi_callback_return(klisp_State *K); + static TValue ffi_decode_void(ffi_codec_t *self, klisp_State *K, const void *buf) { UNUSED(self); @@ -279,25 +280,8 @@ static void ffi_encode_sint32(ffi_codec_t *self, klisp_State *K, TValue v, void static TValue ffi_decode_uint64(ffi_codec_t *self, klisp_State *K, const void *buf) { - /* TODO */ UNUSED(self); - uint64_t x = *(uint64_t *)buf; - if (x <= INT32_MAX) { - return i2tv((int32_t) x); - } else { - TValue res = kbigint_make_simple(K); - krooted_tvs_push(K, res); - - uint8_t d[8]; - for (int i = 7; i >= 0; i--) { - d[i] = (x & 0xFF); - x >>= 8; - } - - mp_int_read_unsigned(K, tv2bigint(res), d, 8); - krooted_tvs_pop(K); - return res; - } + return kinteger_new_uint64(K, *(uint64_t *)buf); } static void ffi_encode_uint64(ffi_codec_t *self, klisp_State *K, TValue v, void *buf) @@ -499,8 +483,9 @@ void ffi_make_call_interface(klisp_State *K) "argtypes string list", ttislist, argtypes_tv); #undef ttislist - size_t nargs = check_typed_list(K, "ffi-make-call-interface", "argtype string", - kstringp, false, argtypes_tv, NULL); + size_t nargs; + check_typed_list(K, kstringp, false, argtypes_tv, (int32_t *) &nargs, + NULL); /* Allocate C structure ffi_call_interface_t inside a mutable bytevector. The structure contains C pointers @@ -868,15 +853,21 @@ static void ffi_callback_entry(ffi_cif *cif, void *ret, void **args, void *user_ TValue exit_guard = ffi_callback_guard(cb, do_ffi_callback_exit_guard); krooted_tvs_push(K, exit_guard); + /* Construct fresh dynamic environment for the callback applicative. */ + TValue denv = kmake_empty_environment(K); + krooted_tvs_push(K, denv); + TValue ptree = kimm_list(K, 3, entry_guard, app, exit_guard); krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K); + krooted_tvs_pop(K); K->next_xparams = NULL; K->next_value = ptree; - /* K->next_env already has the correct value */ + K->next_env = denv; + guard_dynamic_extent(K); /* Enter new "inner" trampoline loop. */ @@ -1191,3 +1182,14 @@ void kinit_ffi_ground_env(klisp_State *K) add_applicative(K, ground_env, "ffi-library?", enc_typep, 1, dll_key); add_applicative(K, ground_env, "ffi-call-interface?", enc_typep, 1, cif_key); } + +/* init continuation names */ +void kinit_ffi_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + + add_cont_name(K, t, do_ffi_callback_encode_result, + "ffi-callback-encode-result"); + add_cont_name(K, t, do_ffi_callback_return, + "ffi-callback-ret"); +} diff --git a/src/kgffi.h b/src/kgffi.h @@ -10,20 +10,12 @@ #if (KUSE_LIBFFI != 1) # error "Compiling FFI code, but KUSE_LIBFFI != 1." #endif -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> -#include "kobject.h" -#include "klisp.h" #include "kstate.h" -#include "kghelpers.h" - -void ffi_load_library(klisp_State *K); /* init ground */ void kinit_ffi_ground_env(klisp_State *K); +/* init continuation names */ +void kinit_ffi_cont_names(klisp_State *K); #endif diff --git a/src/kghelpers.c b/src/kghelpers.c @@ -4,7 +4,6 @@ ** See Copyright Notice in klisp.h */ -#include <assert.h> #include <stdlib.h> #include <stdio.h> #include <stdbool.h> @@ -16,6 +15,144 @@ #include "klisp.h" #include "kerror.h" #include "ksymbol.h" +#include "kenvironment.h" +#include "kinteger.h" +#include "krational.h" +#include "kapplicative.h" +#include "kbytevector.h" +#include "kvector.h" +#include "kstring.h" +#include "kpair.h" +#include "kcontinuation.h" +#include "kencapsulation.h" +#include "kpromise.h" + +/* Initialization of continuation names */ +void kinit_kghelpers_cont_names(klisp_State *K) +{ + Table *t = tv2table(K->cont_name_table); + add_cont_name(K, t, do_seq, "eval-sequence"); + add_cont_name(K, t, do_pass_value, "pass-value"); + add_cont_name(K, t, do_return_value, "return-value"); + add_cont_name(K, t, do_bind, "dynamic-bind"); + add_cont_name(K, t, do_bind, "dynamic-access"); + add_cont_name(K, t, do_bind, "dynamic-unbind"); + add_cont_name(K, t, do_bind, "dynamic-set!-pass"); +} + +/* Type predicates */ +/* TODO these should be moved to either kobject.h or the corresponding + files (e.g. kbooleanp to kboolean.h */ +bool kbooleanp(TValue obj) { return ttisboolean(obj); } +bool kcombinerp(TValue obj) { return ttiscombiner(obj); } +bool knumberp(TValue obj) { return ttisnumber(obj); } +/* TEMP used (as a type predicate) in all predicates that need a primary value + (XXX it's not actually a type error, but it's close enough and otherwise + should define new predp & bpredp for numeric predicates...) */ +bool knumber_wpvp(TValue obj) +{ + return ttisnumber(obj) && !ttisrwnpv(obj) && !ttisundef(obj); +} +/* This is used in gcd & lcm */ +bool kimp_intp(TValue obj) { return ttisinteger(obj) || ttisinf(obj); } +/* obj is known to be a number */ +bool kfinitep(TValue obj) { return !ttisinf(obj); } +/* fixint, bigints & inexact integers */ +bool kintegerp(TValue obj) { return ttisinteger(obj); } +/* only exact integers (like for indices), bigints & fixints */ +bool keintegerp(TValue obj) { return ttiseinteger(obj); } +/* exact integers between 0 and 255 inclusive */ +bool ku8p(TValue obj) { return ttisu8(obj); } +bool krationalp(TValue obj) { return ttisrational(obj); } +bool krealp(TValue obj) { return ttisreal(obj); } +/* TEMP used (as a type predicate) in all predicates that need a real with + primary value (XXX it's not actually a type error, but it's close enough + and otherwise should define new predp & bpredp for numeric predicates...) */ +bool kreal_wpvp(TValue obj) { return ttisreal(obj) && !ttisrwnpv(obj); } + +bool kexactp(TValue obj) { return ttisexact(obj); } +bool kinexactp(TValue obj) { return ttisinexact(obj); } +bool kundefinedp(TValue obj) { return ttisundef(obj); } +bool krobustp(TValue obj) { return ttisrobust(obj); } + +void enc_typep(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(denv); + /* + ** xparams[0]: encapsulation key + */ + TValue key = xparams[0]; + + /* check the ptree is a list while checking the predicate. + Keep going even if the result is false to catch errors in + ptree structure */ + bool res = true; + + TValue tail = ptree; + while(ttispair(tail) && kis_unmarked(tail)) { + kmark(tail); + res &= kis_encapsulation_type(kcar(tail), key); + tail = kcdr(tail); + } + unmark_list(K, ptree); + + if (ttispair(tail) || ttisnil(tail)) { + kapply_cc(K, b2tv(res)); + } else { + /* try to get name from encapsulation */ + klispE_throw_simple(K, "expected list"); + return; + } +} +/* /Type predicates */ + +/* some number functions */ +bool kpositivep(TValue n) +{ + switch (ttype(n)) { + case K_TFIXINT: + case K_TEINF: + case K_TIINF: + return ivalue(n) > 0; + case K_TBIGINT: + return kbigint_positivep(n); + case K_TBIGRAT: + return kbigrat_positivep(n); + case K_TDOUBLE: + return dvalue(n) > 0.0; + /* real with no prim value, complex and undefined should be captured by + type predicate */ + default: + klisp_assert(0); + return false; + } +} + +bool knegativep(TValue n) +{ + switch (ttype(n)) { + case K_TFIXINT: + case K_TEINF: + case K_TIINF: + return ivalue(n) < 0; + case K_TBIGINT: + return kbigint_negativep(n); + case K_TBIGRAT: + return kbigrat_negativep(n); + case K_TDOUBLE: + return dvalue(n) < 0.0; + /* real with no prim value, complex and undefined should be captured by + type predicate */ + default: + klisp_assert(0); + return false; + } +} +/* /some number functions */ void typep(klisp_State *K) { @@ -100,14 +237,13 @@ void ftyped_predp(klisp_State *K) ** xparams[1]: type fn pointer (as a void * in a user TValue) ** xparams[2]: fn pointer (as a void * in a user TValue) */ - char *name = ksymbol_buf(xparams[0]); bool (*typep)(TValue obj) = pvalue(xparams[1]); bool (*predp)(TValue obj) = pvalue(xparams[2]); /* check the ptree is a list first to allow the structure errors to take precedence over the type errors. */ - int32_t cpairs; - int32_t pairs = check_list(K, name, true, ptree, &cpairs); + int32_t pairs, cpairs; + check_list(K, true, ptree, &pairs, &cpairs); TValue tail = ptree; bool res = true; @@ -144,14 +280,13 @@ void ftyped_bpredp(klisp_State *K) ** xparams[1]: type fn pointer (as a void * in a user TValue) ** xparams[2]: fn pointer (as a void * in a user TValue) */ - char *name = ksymbol_buf(xparams[0]); bool (*typep)(TValue obj) = pvalue(xparams[1]); bool (*predp)(TValue obj1, TValue obj2) = pvalue(xparams[2]); /* check the ptree is a list first to allow the structure errors to take precedence over the type errors. */ - int32_t cpairs; - int32_t pairs = check_list(K, name, true, ptree, &cpairs); + int32_t pairs, cpairs; + check_list(K, true, ptree, &pairs, &cpairs); /* cyclical list require an extra comparison of the last & first element of the cycle */ @@ -204,15 +339,14 @@ void ftyped_kbpredp(klisp_State *K) ** xparams[1]: type fn pointer (as a void * in a user TValue) ** xparams[2]: fn pointer (as a void * in a user TValue) */ - char *name = ksymbol_buf(xparams[0]); bool (*typep)(TValue obj) = pvalue(xparams[1]); bool (*predp)(klisp_State *K, TValue obj1, TValue obj2) = pvalue(xparams[2]); /* check the ptree is a list first to allow the structure errors to take precedence over the type errors. */ - int32_t cpairs; - int32_t pairs = check_list(K, name, true, ptree, &cpairs); + int32_t pairs, cpairs; + check_list(K, true, ptree, &pairs, &cpairs); /* cyclical list require an extra comparison of the last & first element of the cycle */ @@ -252,86 +386,299 @@ void ftyped_kbpredp(klisp_State *K) } /* typed finite list. Structure error should be throw before type errors */ -int32_t check_typed_list(klisp_State *K, char *name, char *typename, - bool (*typep)(TValue), bool allow_infp, TValue obj, - int32_t *cpairs) +void check_typed_list(klisp_State *K, bool (*typep)(TValue), bool allow_infp, + TValue obj, int32_t *pairs, int32_t *cpairs) { TValue tail = obj; - int32_t pairs = 0; + int32_t p = 0; bool type_errorp = false; while(ttispair(tail) && !kis_marked(tail)) { /* even if there is a type error continue checking the structure */ type_errorp |= !(*typep)(kcar(tail)); - kset_mark(tail, i2tv(pairs)); + kset_mark(tail, i2tv(p)); tail = kcdr(tail); - ++pairs; + ++p; } + if (pairs != NULL) *pairs = p; if (cpairs != NULL) - *cpairs = ttispair(tail)? (pairs - ivalue(kget_mark(tail))) : 0; + *cpairs = ttispair(tail)? (p - ivalue(kget_mark(tail))) : 0; unmark_list(K, obj); if (!ttispair(tail) && !ttisnil(tail)) { klispE_throw_simple(K, allow_infp? "expected list" : "expected finite list"); - return 0; + return; } else if(ttispair(tail) && !allow_infp) { klispE_throw_simple(K, "expected finite list"); - return 0; + return; } else if (type_errorp) { - /* TODO put type name too */ + /* TODO put type name too, should be extracted from a + table of type names */ klispE_throw_simple(K, "bad operand type"); - return 0; + return; } - return pairs; } -int32_t check_list(klisp_State *K, const char *name, bool allow_infp, - TValue obj, int32_t *cpairs) +void check_list(klisp_State *K, bool allow_infp, TValue obj, + int32_t *pairs, int32_t *cpairs) { TValue tail = obj; - int pairs = 0; + int32_t p = 0; + while(ttispair(tail) && !kis_marked(tail)) { - kset_mark(tail, i2tv(pairs)); + kset_mark(tail, i2tv(p)); tail = kcdr(tail); - ++pairs; + ++p; } + if (pairs != NULL) *pairs = p; if (cpairs != NULL) - *cpairs = ttispair(tail)? (pairs - ivalue(kget_mark(tail))) : 0; + *cpairs = ttispair(tail)? (p - ivalue(kget_mark(tail))) : 0; unmark_list(K, obj); if (!ttispair(tail) && !ttisnil(tail)) { klispE_throw_simple(K, allow_infp? "expected list" : "expected finite list"); - return 0; + return; } else if(ttispair(tail) && !allow_infp) { klispE_throw_simple(K, "expected finite list"); - return 0; + return; + } +} + + +TValue check_copy_list(klisp_State *K, TValue obj, bool force_copy, + int32_t *pairs, int32_t *cpairs) +{ + int32_t p = 0; + if (ttisnil(obj)) { + if (pairs != NULL) *pairs = 0; + if (cpairs != NULL) *cpairs = 0; + return obj; + } + + if (ttispair(obj) && kis_immutable(obj) && !force_copy) { + /* this will properly set pairs and cpairs */ + check_list(K, true, obj, pairs, cpairs); + return obj; } else { - return pairs; + TValue copy = kcons(K, KNIL, KNIL); + krooted_vars_push(K, &copy); + TValue last_pair = copy; + TValue tail = obj; + + while(ttispair(tail) && !kis_marked(tail)) { + TValue new_pair = kcons(K, kcar(tail), KNIL); + /* record the corresponding pair to simplify cycle handling */ + kset_mark(tail, new_pair); + /* record the pair number in the new pair, to set cpairs */ + kset_mark(new_pair, i2tv(p)); + /* copy the source code info */ + TValue si = ktry_get_si(K, tail); + if (!ttisnil(si)) + kset_source_info(K, new_pair, si); + kset_cdr(last_pair, new_pair);