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:
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: <a rel="next" accesskey="n" href="Encapsulations.html#Encapsulations">Encapsulations</a>,
+Previous: <a rel="previous" accesskey="p" href="Combiners.html#Combiners">Combiners</a>,
+Up: <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">
+— 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">
+— 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">
+— 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">
+— 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">
+— Applicative: <b>continuation->applicative</b> (<var>continuation->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">
+— 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">
+— 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">
+— 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->applicative</code>, and then
+applies it as usual.
+
+ <p>That is:
+ <pre class="example"> (apply-continuation continuation object) ==
+ (apply (continuation->applicative continuation) object)
+</pre>
+ </blockquote></div>
+
+<div class="defun">
+— Operative: <b>(</b><var>$let/cc <symbol> . <objects></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><symbol></code> to the continuation to which
+the result of the call to <code>$let/cc</code> should normally return; then,
+the subexpressions of <code><objects></code> are evaluated in <code>e</code> from
+left to right, with the last (if any) evaluated as a tail context, or
+if <code><objects></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">
+— 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">
+— 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: <a rel="next" accesskey="n" href="Encapsulations.html#Encapsulations">Encapsulations</a>,
-Previous: <a rel="previous" accesskey="p" href="Combiners.html#Combiners">Combiners</a>,
-Up: <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">
-— 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">
-— 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">
-— 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">
-— 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">
-— Applicative: <b>continuation->applicative</b> (<var>continuation->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">
-— 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">
-— 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">
-— 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->applicative</code>, and then
-applies it as usual.
-
- <p>That is:
- <pre class="example"> (apply-continuation continuation object) ==
- (apply (continuation->applicative continuation) object)
-</pre>
- </blockquote></div>
-
-<div class="defun">
-— Operative: <b>(</b><var>$let/cc <symbol> . <objects></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><symbol></code> to the continuation to which
-the result of the call to <code>$let/cc</code> should normally return; then,
-the subexpressions of <code><objects></code> are evaluated in <code>e</code> from
-left to right, with the last (if any) evaluated as a tail context, or
-if <code><objects></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">
-— 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">
-— 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, ©);
-
- /*
- ** 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, ©);
+ 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);