commit 3781ff253913e65e96e65e84dd545b463b6b90e4 parent 97d10f6e860b77903dbfe79efa24ff1f3921edd4 Author: Oto Havle <havleoto@gmail.com> Date: Sat, 26 Nov 2011 11:26:04 +0100 Merged recent changes from the original repo Diffstat:
97 files changed, 4651 insertions(+), 4285 deletions(-)
diff --git a/TODO b/TODO @@ -0,0 +1,65 @@ +* refactor: +** double check combiner names to be verbs + (e.g. add get- where appropriate) +** remove function prototypes from kg*.h, move the + ones that are used in more than one place to kghelpers.h +** 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 char * arguments where not needed (like list check/copy + functions in kghelpers +** check if all inline functions need to be inline +* fix: +** current-jiffy (r7rs) +** jiffies-per-second (r7rs) +* operatives: +** $when (r7rs) +** $unless (r7rs) +** $string-for-each (r7rs) +** $vector-for-each (r7rs) +** $bytevector-for-each +** $case (r7rs) +** $case-lambda (r7rs) +** $case-vau (r7rs) +** $named-let (r7rs) +** $do (r7rs) +** $define-record-type (r7rs) +* applicatives: +** vector-map (r7rs) +** bytevector-map (r7rs) +** string-map (r7rs) +** vector->bytevector +** bytevector->vector +** vector->string (r7rs) +** string->vector (r7rs) +** vector-copy! (r7rs) +** vector-copy-partial (r7rs) +** vector-copy-partial! (r7rs) +** read-line (r7rs) +** number->string (r7rs) +** string->number (r7rs) +** char-digit? +** digit->char +** char->digit +* reader +** symbol escapes (r7rs) +** string escapes (r7rs) +** char escapes (r7rs) +* other +** optional argument to member? (r7rs) +** optional argument to assoc (r7rs) +** some simplified error guarding (r7rs) +** restarts (r7rs) +** add restart support to the repl/interpreter (r7rs) +** simple modules (something inspired in r7rs) (r7rs) +** add modules support to the interpreter (r7rs) +** eager comprehensions (at least for check.k) see SRFIs 42 and 78 + (srfi) + + 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,163 @@ +.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, including the initialization +that is described below, take place in the same +(initially) standard environment. +The given +.I args +are available to +.I script +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 arguments in the returned string start with the string +.RI ' script '. +The arguments given in the command line before +.IR script , +including the name of the interpreter, +are available 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" +.\" call +.\" .BI require(' name ') +.\" before executing +.\" .IR script . +.\" 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 there is an error during the evaluation of +the options, +.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 "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 \ + kcontinuation.o koperative.o kapplicative.o keval.o krepl.o \ kencapsulation.o kpromise.o kport.o kinteger.o krational.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 @@ -121,6 +121,7 @@ kbytevector.o: kbytevector.c kbytevector.h kobject.h klimits.h klisp.h \ klispconf.h kstate.h ktoken.h kmem.h kgc.h kstring.h kcontinuation.o: kcontinuation.c kcontinuation.h kobject.h klimits.h \ klisp.h klispconf.h kstate.h ktoken.h kmem.h kgc.h +kchar.o: kchar.c kchar.h kobject.h klimits.h klisp.h klispconf.h kstate.h kencapsulation.o: kencapsulation.c kobject.h klimits.h klisp.h \ klispconf.h kmem.h kstate.h ktoken.h kencapsulation.h kpair.h kgc.h kenvironment.o: kenvironment.c kenvironment.h kobject.h klimits.h klisp.h \ @@ -174,10 +175,10 @@ kgequalp.o: kgequalp.c kstate.h klimits.h klisp.h kobject.h klispconf.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 \ +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 + 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 \ @@ -185,10 +186,12 @@ kgffi.o: kgffi.c imath.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ kgcombiners.h kgcontinuations.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 + koperative.h kcontinuation.h kenvironment.h ksymbol.h kstring.h kinteger.h \ + imath.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 + kpair.h kgc.h kchar.h kghelpers.h kenvironment.h ksymbol.h kstring.h \ + kgchars.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 \ @@ -209,11 +212,11 @@ kgpair_mut.o: kgpair_mut.c kstate.h klimits.h klisp.h kobject.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 kgequalp.h kgpairs_lists.h kgnumbers.h imath.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 \ + ksymbol.h kread.h kwrite.h kghelpers.h kgports.h \ kgcontinuations.h kgcontrol.h kgkd_vars.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 \ @@ -227,10 +230,10 @@ kground.o: kground.c kstate.h klimits.h klisp.h kobject.h klispconf.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 + kgerrors.h kgffi.h ktable.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 \ + kpair.h kgc.h ksymbol.h kstring.h kghelpers.h kenvironment.h \ kgstrings.h kgnumbers.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 \ @@ -250,7 +253,7 @@ 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 + krepl.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 @@ -271,17 +274,13 @@ kreal.o: kreal.c kreal.h kobject.h klimits.h klisp.h klispconf.h kstate.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 \ + kread.h kwrite.h kstring.h krepl.h ksymbol.h kport.h kgerrors.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 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 \ + kgpairs_lists.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 \ diff --git a/src/kchar.c b/src/kchar.c @@ -0,0 +1,17 @@ +/* +** 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; } diff --git a/src/kchar.h b/src/kchar.h @@ -0,0 +1,22 @@ +/* +** 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); + +#endif diff --git a/src/kerror.c b/src/kerror.c @@ -106,6 +106,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/kgbytevectors.c b/src/kgbytevectors.c @@ -23,13 +23,94 @@ #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 */ +/* Helper for bytevector and list->bytevector */ +/* GC: Assumes ls is rooted */ +TValue list_to_bytevector_h(klisp_State *K, char *name, TValue ls) +{ + int32_t dummy; + /* don't allow cycles */ + int32_t pairs = check_typed_list(K, name, "u8", ku8p, false, + ls, &dummy); + + TValue new_bb; + /* the if isn't strictly necessary but it's clearer this way */ + if (pairs == 0) { + return K->empty_bytevector; + } else { + new_bb = kbytevector_new_s(K, pairs); + uint8_t *buf = kbytevector_buf(new_bb); + TValue tail = ls; + while(pairs--) { + *buf++ = ivalue(kcar(tail)); + tail = kcdr(tail); + } + return new_bb; + } +} + +/* ?.? 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); + + TValue new_bb = list_to_bytevector_h(K, "bytevector", ptree); + 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); + int32_t pairs = kbytevector_size(bb); + uint8_t *buf = kbytevector_buf(bb); + + TValue tail = kget_dummy1(K); + + while(pairs--) { + TValue new_pair = kcons(K, i2tv(*buf), KNIL); + buf++; + kset_cdr(tail, new_pair); + tail = new_pair; + } + kapply_cc(K, kcutoff_dummy1(K)); +} + +/* ?.? 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); + + TValue new_bb = list_to_bytevector_h(K, "list->bytevector", ls); + kapply_cc(K, new_bb); +} + +/* ?.? make-bytevector */ void make_bytevector(klisp_State *K) { TValue *xparams = K->next_xparams; @@ -57,7 +138,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 +153,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 +182,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 +215,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 +239,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 +267,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 +316,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 +388,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 +455,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 +469,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/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)); } @@ -174,9 +156,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)); 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/kgcontinuations.c b/src/kgcontinuations.c @@ -341,6 +341,8 @@ void guard_dynamic_extent(klisp_State *K) } /* 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 +352,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 */ 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, "error", rest, false); + 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,29 @@ +/* +** kgerror.h +** Error handling features for the ground environment +** See Copyright Notice in klisp.h +*/ + +#ifndef kgerrors_h +#define kgerrors_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/kghelpers.c b/src/kghelpers.c @@ -16,6 +16,7 @@ #include "klisp.h" #include "kerror.h" #include "ksymbol.h" +#include "kinteger.h" void typep(klisp_State *K) { @@ -383,3 +384,76 @@ int64_t klcm32_64(int32_t a_, int32_t b_) /* divide first to avoid possible overflow */ return (a / gcd) * b; } + +/* Helper for get-list-metrics, and list-tail, list-ref and list-set! + when receiving bigint indexes */ +void get_list_metrics_aux(klisp_State *K, TValue obj, int32_t *p, int32_t *n, + int32_t *a, int32_t *c) +{ + TValue tail = obj; + int32_t pairs = 0; + + while(ttispair(tail) && !kis_marked(tail)) { + /* record the pair number to simplify cycle pair counting */ + kset_mark(tail, i2tv(pairs)); + ++pairs; + tail = kcdr(tail); + } + int32_t apairs, cpairs, nils; + if (ttisnil(tail)) { + /* simple (possibly empty) list */ + apairs = pairs; + nils = 1; + cpairs = 0; + } else if (ttispair(tail)) { + /* cyclic (maybe circular) list */ + apairs = ivalue(kget_mark(tail)); + cpairs = pairs - apairs; + nils = 0; + } else { + apairs = pairs; + cpairs = 0; + nils = 0; + } + + unmark_list(K, obj); + + if (p != NULL) *p = pairs; + if (n != NULL) *n = nils; + if (a != NULL) *a = apairs; + if (c != NULL) *c = cpairs; +} + +/* Helper for list-tail, list-ref and list-set! */ +/* Calculate the smallest i such that + (eq? (list-tail obj i) (list-tail obj tk)) + tk is a bigint and all lists have fixint range number of pairs, + so the list should cyclic and we should calculate an index that + doesn't go through the complete cycle not even once */ +int32_t ksmallest_index(klisp_State *K, char *name, TValue obj, + TValue tk) +{ + int32_t apairs, cpairs; + get_list_metrics_aux(K, obj, NULL, NULL, &apairs, &cpairs); + if (cpairs == 0) { + klispE_throw_simple(K, "non pair found while traversing " + "object"); + return 0; + } + TValue tv_apairs = i2tv(apairs); + TValue tv_cpairs = i2tv(cpairs); + + /* all calculations will be done with bigints */ + kensure_bigint(tv_apairs); + kensure_bigint(tv_cpairs); + + TValue idx = kbigint_minus(K, tk, tv_apairs); + krooted_tvs_push(K, idx); /* root idx if it is a bigint */ + /* idx may have become a fixint */ + kensure_bigint(idx); + UNUSED(kbigint_div_mod(K, idx, tv_cpairs, &idx)); + krooted_tvs_pop(K); + /* now idx is less than cpairs so it fits in a fixint */ + assert(ttisfixint(idx)); + return ivalue(idx) + apairs; +} diff --git a/src/kghelpers.h b/src/kghelpers.h @@ -265,12 +265,14 @@ inline void unmark_tree(klisp_State *K, TValue obj) /* TODO: move all bools to a flag parameter (with constants like KCHK_LS_FORCE_COPY, KCHK_ALLOW_CYCLE, KCHK_AVOID_ENCYCLE, etc) */ +/* REFACTOR: remove the name argument */ /* 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); +/* REFACTOR: remove the name argument */ /* check that obj is a list, returns the number of pairs */ /* TODO change the return to void and add int32_t pairs obj */ int32_t check_list(klisp_State *K, const char *name, bool allow_infp, @@ -280,7 +282,7 @@ int32_t check_list(klisp_State *K, const char *name, bool allow_infp, ** MAYBE: These shouldn't be inline really. */ - +/* REFACTOR: remove the name argument */ /* REFACTOR: return the number of pairs and cycle pairs in two extra params */ /* TODO: add check_copy_typed_list */ /* TODO: remove inline */ @@ -328,6 +330,7 @@ inline TValue check_copy_list(klisp_State *K, char *name, TValue obj, } } +/* REFACTOR: remove the name argument */ /* check that obj is a list of environments and make a copy but don't keep the cycles */ /* GC: assume obj is rooted, uses dummy3 */ @@ -427,6 +430,18 @@ inline int32_t kcheck32(klisp_State *K, char *msg, int64_t i) int64_t kgcd32_64(int32_t a, int32_t b); int64_t klcm32_64(int32_t a, int32_t b); +/* +** Other +*/ + +/* Helper for list-tail, list-ref and list-set! */ +int32_t ksmallest_index(klisp_State *K, char *name, TValue obj, + TValue tk); + +/* Helper for get-list-metrics, and list-tail, list-ref and list-set! + when receiving bigint indexes */ +void get_list_metrics_aux(klisp_State *K, TValue obj, int32_t *p, int32_t *n, + int32_t *a, int32_t *c); /* ** Macros for ground environment initialization diff --git a/src/kgnumbers.c b/src/kgnumbers.c @@ -2358,6 +2358,9 @@ void kinit_numbers_ground_env(klisp_State *K) p2tv(knumber_wpvp), p2tv(kfinitep)); add_applicative(K, ground_env, "integer?", ftypep, 2, symbol, p2tv(kintegerp)); + /* 12.5.? exact-integer? */ + add_applicative(K, ground_env, "exact-integer?", ftypep, 2, symbol, + p2tv(keintegerp)); /* 12.5.2 =? */ add_applicative(K, ground_env, "=?", ftyped_kbpredp, 3, symbol, p2tv(knumber_wpvp), p2tv(knum_eqp)); diff --git a/src/kgpair_mut.c b/src/kgpair_mut.c @@ -264,9 +264,53 @@ void encycleB(klisp_State *K) kapply_cc(K, KINERT); } -/* Helpers for append! */ +/* 6.?? list-set! */ +void list_setB(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); +/* ASK John: can the object be an improper list? + We foolow list-tail here and allow it */ + UNUSED(denv); + UNUSED(xparams); + + bind_3tp(K, ptree, "any", anytype, obj, + "exact integer", keintegerp, tk, + "any", anytype, val); + + if (knegativep(tk)) { + klispE_throw_simple(K, "negative index"); + return; + } + + int32_t k = (ttisfixint(tk))? ivalue(tk) + : ksmallest_index(K, "list-set!", obj, tk); + while(k) { + if (!ttispair(obj)) { + klispE_throw_simple(K, "non pair found while traversing " + "object"); + return; + } + obj = kcdr(obj); + --k; + } + if (!ttispair(obj)) { + klispE_throw_simple(K, "non pair found while traversing " + "object"); + } else if (kis_immutable(obj)) { + /* this could be checked before, but the error here seems better */ + klispE_throw_simple(K, "immutable pair"); + } else { + kset_car(obj, val); + kapply_cc(K, KINERT); + } +} + +/* Helpers for append! */ inline void appendB_clear_last_pairs(klisp_State *K, TValue ls) { UNUSED(K); @@ -536,6 +580,8 @@ void kinit_pair_mut_ground_env(klisp_State *K) b2tv(false)); /* 5.8.1 encycle! */ add_applicative(K, ground_env, "encycle!", encycleB, 0); + /* 6.?? list-set! */ + add_applicative(K, ground_env, "list-set!", list_setB, 0); /* 6.4.1 append! */ add_applicative(K, ground_env, "append!", appendB, 0); /* 6.4.2 copy-es */ diff --git a/src/kgpairs_lists.c b/src/kgpairs_lists.c @@ -23,7 +23,6 @@ #include "kgequalp.h" #include "kgpairs_lists.h" #include "kgnumbers.h" -#include "kinteger.h" /* 4.6.1 pair? */ /* uses typep */ @@ -46,7 +45,6 @@ void cons(klisp_State *K) kapply_cc(K, new_pair); } - /* 5.2.1 list */ void list(klisp_State *K) { @@ -114,7 +112,6 @@ void listS(klisp_State *K) /* 5.4.1 car, cdr */ /* 5.4.2 caar, cadr, ... cddddr */ - void c_ad_r(klisp_State *K) { TValue *xparams = K->next_xparams; @@ -155,43 +152,86 @@ void c_ad_r(klisp_State *K) kapply_cc(K, obj); } -/* also used in list-tail and list-ref when receiving - bigint indexes */ -void get_list_metrics_aux(klisp_State *K, TValue obj, int32_t *p, int32_t *n, - int32_t *a, int32_t *c) +/* 5.4.? make-list */ +void make_list(klisp_State *K) { - TValue tail = obj; - int32_t pairs = 0; + 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, "exact integer", keintegerp, tv_s, fill); + + if (!get_opt_tpar(K, fill, "any", anytype)) + fill = KINERT; + + if (knegativep(tv_s)) { + klispE_throw_simple(K, "negative list length"); + return; + } else if (!ttisfixint(tv_s)) { + klispE_throw_simple(K, "list length is too big"); + return; + } + TValue tail = KNIL; + int i = ivalue(tv_s); + krooted_vars_push(K, &tail); + while(i-- > 0) { + tail = kcons(K, fill, tail); + } + krooted_vars_pop(K); + + kapply_cc(K, tail); +} + +/* 5.4.? list-copy */ +void list_copy(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, ls); + TValue copy = check_copy_list(K, "list-copy", ls, true); + kapply_cc(K, copy); +} + +/* 5.4.? reverse */ +void reverse(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, ls); + TValue tail = ls; + TValue res = KNIL; + krooted_vars_push(K, &res); while(ttispair(tail) && !kis_marked(tail)) { - /* record the pair number to simplify cycle pair counting */ - kset_mark(tail, i2tv(pairs)); - ++pairs; + kmark(tail); + res = kcons(K, kcar(tail), res); tail = kcdr(tail); } - int32_t apairs, cpairs, nils; - if (ttisnil(tail)) { - /* simple (possibly empty) list */ - apairs = pairs; - nils = 1; - cpairs = 0; - } else if (ttispair(tail)) { - /* cyclic (maybe circular) list */ - apairs = ivalue(kget_mark(tail)); - cpairs = pairs - apairs; - nils = 0; + unmark_list(K, ls); + krooted_vars_pop(K); + + if (ttispair(tail)) { + klispE_throw_simple(K, "expected acyclic list"); + } else if (!ttisnil(tail)) { + klispE_throw_simple(K, "expected list"); } else { - apairs = pairs; - cpairs = 0; - nils = 0; + kapply_cc(K, res); } - - unmark_list(K, obj); - - if (p != NULL) *p = pairs; - if (n != NULL) *n = nils; - if (a != NULL) *a = apairs; - if (c != NULL) *c = cpairs; } /* 5.7.1 get-list-metrics */ @@ -214,42 +254,6 @@ void get_list_metrics(klisp_State *K) kapply_cc(K, res); } -/* Helper for list-tail and list-ref */ - -/* Calculate the smallest i such that - (eq? (list-tail obj i) (list-tail obj tk)) - tk is a bigint and all lists have fixint range number of pairs, - so the list should cyclic and we should calculate an index that - doesn't go through the complete cycle not even once */ -int32_t ksmallest_index(klisp_State *K, char *name, TValue obj, - TValue tk) -{ - int32_t apairs, cpairs; - get_list_metrics_aux(K, obj, NULL, NULL, &apairs, &cpairs); - if (cpairs == 0) { - klispE_throw_simple(K, "non pair found while traversing " - "object"); - return 0; - } - TValue tv_apairs = i2tv(apairs); - TValue tv_cpairs = i2tv(cpairs); - - /* all calculations will be done with bigints */ - kensure_bigint(tv_apairs); - kensure_bigint(tv_cpairs); - - TValue idx = kbigint_minus(K, tk, tv_apairs); - krooted_tvs_push(K, idx); /* root idx if it is a bigint */ - /* idx may have become a fixint */ - kensure_bigint(idx); - UNUSED(kbigint_div_mod(K, idx, tv_cpairs, &idx)); - krooted_tvs_pop(K); - /* now idx is less than cpairs so it fits in a fixint */ - assert(ttisfixint(idx)); - return ivalue(idx) + apairs; -} - - /* 5.7.2 list-tail */ void list_tail(klisp_State *K) { @@ -1166,6 +1170,12 @@ void kinit_pairs_lists_ground_env(klisp_State *K) C_AD_R_PARAM(4, 0x1110)); add_applicative(K, ground_env, "cddddr", c_ad_r, 2, symbol, C_AD_R_PARAM(4, 0x1111)); + /* 5.?.? make-list */ + add_applicative(K, ground_env, "make-list", make_list, 0); + /* 5.?.? list-copy */ + add_applicative(K, ground_env, "list-copy", list_copy, 0); + /* 5.?.? reverse */ + add_applicative(K, ground_env, "reverse", reverse, 0); /* 5.7.1 get-list-metrics */ add_applicative(K, ground_env, "get-list-metrics", get_list_metrics, 0); /* 5.7.2 list-tail */ diff --git a/src/kgports.c b/src/kgports.c @@ -27,8 +27,6 @@ #include "kwrite.h" #include "kpair.h" -#include "kscript.h" - #include "kghelpers.h" #include "kgports.h" #include "kgcontinuations.h" /* for guards */ @@ -866,80 +864,6 @@ void flush(klisp_State *K) kapply_cc(K, KINERT); } -/* 15.1.? file-exists? */ -void file_existsp(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, "string", ttisstring, filename); - - /* TEMP: this should probably be done in a operating system specific - manner, but this will do for now */ - TValue res = KFALSE; - FILE *file = fopen(kstring_buf(filename), "r"); - if (file) { - res = KTRUE; - UNUSED(fclose(file)); - } - kapply_cc(K, res); -} - -/* 15.1.? delete-file */ -void delete_file(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, "string", ttisstring, filename); - - /* TEMP: this should probably be done in a operating system specific - manner, but this will do for now */ - /* XXX: this could fail if there's a dead (in the gc sense) port still - open, should probably retry once after doing a complete GC */ - if (remove(kstring_buf(filename))) { - klispE_throw_errno_with_irritants(K, "remove", 1, filename); - return; - } else { - kapply_cc(K, KINERT); - return; - } -} - -/* 15.1.? rename-file */ -void rename_file(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, "string", ttisstring, old_filename, - "string", ttisstring, new_filename); - - /* TEMP: this should probably be done in a operating system specific - manner, but this will do for now */ - /* XXX: this could fail if there's a dead (in the gc sense) port still - open, should probably retry once after doing a complete GC */ - if (rename(kstring_buf(old_filename), kstring_buf(new_filename))) { - klispE_throw_errno_with_irritants(K, "rename", 2, old_filename, new_filename); - return; - } else { - kapply_cc(K, KINERT); - return; - } -} - /* init ground */ void kinit_ports_ground_env(klisp_State *K) { @@ -1085,19 +1009,6 @@ void kinit_ports_ground_env(klisp_State *K) /* 15.1.? flush-output-port */ add_applicative(K, ground_env, "flush-output-port", flush, 0); - /* REFACTOR move to system module */ - - /* 15.1.? file-exists? */ - add_applicative(K, ground_env, "file-exists?", file_existsp, 0); - - /* 15.1.? delete-file */ - add_applicative(K, ground_env, "delete-file", delete_file, 0); - - /* this isn't in r7rs but it's in ansi c and quite easy to implement */ - - /* 15.1.? rename-file */ - add_applicative(K, ground_env, "rename-file", rename_file, 0); - /* * That's all there is in the report combined with r5rs and r7rs scheme. * TODO diff --git a/src/kgports.h b/src/kgports.h @@ -105,15 +105,6 @@ void do_close_file_ret(klisp_State *K); /* 15.1.? flush-output-port */ void flush(klisp_State *K); -/* 15.1.? file-exists? */ -void file_existsp(klisp_State *K); - -/* 15.1.? delete-file */ -void delete_file(klisp_State *K); - -/* 15.1.? rename-file */ -void rename_file(klisp_State *K); - /* init ground */ void kinit_ports_ground_env(klisp_State *K); diff --git a/src/kground.c b/src/kground.c @@ -38,7 +38,7 @@ #include "kgbytevectors.h" #include "kgvectors.h" #include "kgsystem.h" -#include "kgerror.h" +#include "kgerrors.h" #if KUSE_LIBFFI # include "kgffi.h" @@ -49,7 +49,6 @@ #include "kstring.h" #include "keval.h" #include "krepl.h" -#include "kscript.h" /* for init_cont_names */ #define add_cont_name(K_, t_, c_, n_) \ @@ -74,10 +73,6 @@ void kinit_cont_names(klisp_State *K) add_cont_name(K, t, do_repl_eval, "repl-eval"); add_cont_name(K, t, do_repl_loop, "repl-loop"); - /* SCRIPT, root-continuation & error-continuation */ - add_cont_name(K, t, do_script_exit, "script-exit"); - add_cont_name(K, t, do_script_error, "script-report-error"); - /* GROUND ENV */ add_cont_name(K, t, do_eval_ls, "eval-list"); add_cont_name(K, t, do_combine, "eval-combine"); diff --git a/src/kgstrings.c b/src/kgstrings.c @@ -19,10 +19,10 @@ #include "kcontinuation.h" #include "kerror.h" #include "ksymbol.h" +#include "kchar.h" #include "kstring.h" #include "kghelpers.h" -#include "kgchars.h" /* for kcharp */ #include "kgstrings.h" #include "kgnumbers.h" /* for keintegerp & knegativep */ @@ -105,7 +105,7 @@ void string_ref(klisp_State *K) } /* 13.1.5? string-set! */ -void string_setS(klisp_State *K) +void string_setB(klisp_State *K) { TValue *xparams = K->next_xparams; TValue ptree = K->next_value; @@ -139,7 +139,7 @@ void string_setS(klisp_State *K) /* Helper for string and list->string */ /* GC: Assumes ls is rooted */ -inline TValue list_to_string_h(klisp_State *K, char *name, TValue ls) +TValue list_to_string_h(klisp_State *K, char *name, TValue ls) { int32_t dummy; /* don't allow cycles */ @@ -176,6 +176,58 @@ void string(klisp_State *K) kapply_cc(K, new_str); } +/* 13.?? string-upcase, string-downcase, string-titlecase, string-foldcase */ +/* this will work for upcase, downcase and foldcase (in ASCII) */ +void kstring_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)); + /* + ** xparams[0]: conversion fn + */ + UNUSED(denv); + bind_1tp(K, ptree, "string", ttisstring, str); + char (*fn)(char) = pvalue(xparams[0]); + int32_t size = kstring_size(str); + TValue res = kstring_new_bs(K, kstring_buf(str), size); + char *buf = kstring_buf(res); + for(int32_t i = 0; i < size; ++i, buf++) { + *buf = fn(*buf); + } + kapply_cc(K, res); +} + +void kstring_title_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); + UNUSED(denv); + bind_1tp(K, ptree, "string", ttisstring, str); + uint32_t size = kstring_size(str); + TValue res = kstring_new_bs(K, kstring_buf(str), size); + char *buf = kstring_buf(res); + bool first = true; + while(size-- > 0) { + char ch = *buf; + if (ch == ' ') + first = true; + else if (!first) + *buf = tolower(ch); + else if (isalpha(ch)) { + /* only count as first letter something that can be capitalized */ + *buf = toupper(ch); + first = false; + } + ++buf; + } + kapply_cc(K, res); +} + /* 13.2.2? string=?, string-ci=? */ /* use ftyped_bpredp */ @@ -449,7 +501,7 @@ void string_to_immutable_string(klisp_State *K) } /* 13.2.10? string-fill! */ -void string_fillS(klisp_State *K) +void string_fillB(klisp_State *K) { TValue *xparams = K->next_xparams; TValue ptree = K->next_value; @@ -497,9 +549,18 @@ void kinit_strings_ground_env(klisp_State *K) /* 13.1.4? string-ref */ add_applicative(K, ground_env, "string-ref", string_ref, 0); /* 13.1.5? string-set! */ - add_applicative(K, ground_env, "string-set!", string_setS, 0); + add_applicative(K, ground_env, "string-set!", string_setB, 0); /* 13.2.1? string */ add_applicative(K, ground_env, "string", string, 0); + /* 13.?? string-upcase, string-downcase, string-titlecase, + string-foldcase */ + add_applicative(K, ground_env, "string-upcase", kstring_change_case, 1, + p2tv(toupper)); + add_applicative(K, ground_env, "string-downcase", kstring_change_case, 1, + p2tv(tolower)); + add_applicative(K, ground_env, "string-titlecase", kstring_title_case, 0); + add_applicative(K, ground_env, "string-foldcase", kstring_change_case, 1, + p2tv(tolower)); /* 13.2.2? string=?, string-ci=? */ add_applicative(K, ground_env, "string=?", ftyped_bpredp, 3, symbol, p2tv(kstringp), p2tv(kstring_eqp)); @@ -536,8 +597,6 @@ void kinit_strings_ground_env(klisp_State *K) add_applicative(K, ground_env, "string->immutable-string", string_to_immutable_string, 0); - /* TODO: add string-upcase and string-downcase like in r7rs-draft */ - /* 13.2.10? string-fill! */ - add_applicative(K, ground_env, "string-fill!", string_fillS, 0); + add_applicative(K, ground_env, "string-fill!", string_fillB, 0); } diff --git a/src/kgstrings.h b/src/kgstrings.h @@ -7,84 +7,7 @@ #ifndef kgstrings_h #define kgstrings_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" - -/* 13.1.1? string? */ -/* uses typep */ - -/* 13.1.? immutable-string?, mutable-string? */ -/* use ftypep */ - -/* 13.1.2? make-string */ -void make_string(klisp_State *K); - -/* 13.1.3? string-length */ -void string_length(klisp_State *K); - -/* 13.1.4? string-ref */ -void string_ref (klisp_State *K); - -/* 13.1.5? string-set! */ -void string_setS (klisp_State *K); - -/* 13.2.1? string */ -void string(klisp_State *K); - -/* 13.2.2? string=?, string-ci=? */ -/* use ftyped_bpredp */ - -/* 13.2.3? string<?, string<=?, string>?, string>=? */ -/* use ftyped_bpredp */ - -/* 13.2.4? string-ci<?, string-ci<=?, string-ci>?, string-ci>=? */ -/* use ftyped_bpredp */ - -/* Helpers for binary predicates */ -/* XXX: this should probably be in file kstring.h */ -bool kstring_eqp(TValue str1, TValue str2); -bool kstring_ci_eqp(TValue str1, TValue str2); - -bool kstring_ltp(TValue str1, TValue str2); -bool kstring_lep(TValue str1, TValue str2); -bool kstring_gtp(TValue str1, TValue str2); -bool kstring_gep(TValue str1, TValue str2); - -bool kstring_ci_ltp(TValue str1, TValue str2); -bool kstring_ci_lep(TValue str1, TValue str2); -bool kstring_ci_gtp(TValue str1, TValue str2); -bool kstring_ci_gep(TValue str1, TValue str2); - - -/* 13.2.5? substring */ -void substring(klisp_State *K); - -/* 13.2.6? string-append */ -void string_append(klisp_State *K); - -/* 13.2.7? string->list, list->string */ -void list_to_string(klisp_State *K); -void string_to_list(klisp_State *K); - -/* 13.2.8? string-copy */ -void string_copy(klisp_State *K); - -/* 13.2.9? string->immutable-string */ -void string_to_immutable_string(klisp_State *K); - -/* 13.2.10? string-fill! */ -void string_fillS(klisp_State *K); - -/* Helpers */ -bool kstringp(TValue obj); /* init ground */ void kinit_strings_ground_env(klisp_State *K); diff --git a/src/kgsystem.c b/src/kgsystem.c @@ -5,8 +5,10 @@ */ #include <assert.h> +#include <string.h> #include <stdlib.h> #include <stdbool.h> +#include <stdio.h> #include <stdint.h> #include <time.h> @@ -100,6 +102,167 @@ void jiffies_per_second(klisp_State *K) } } +/* 15.1.? file-exists? */ +void file_existsp(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, "string", ttisstring, filename); + + /* TEMP: this should probably be done in a operating system specific + manner, but this will do for now */ + TValue res = KFALSE; + FILE *file = fopen(kstring_buf(filename), "r"); + if (file) { + res = KTRUE; + UNUSED(fclose(file)); + } + kapply_cc(K, res); +} + +/* 15.1.? delete-file */ +void delete_file(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, "string", ttisstring, filename); + + /* TEMP: this should probably be done in a operating system specific + manner, but this will do for now */ + /* XXX: this could fail if there's a dead (in the gc sense) port still + open, should probably retry once after doing a complete GC */ + if (remove(kstring_buf(filename))) { + klispE_throw_errno_with_irritants(K, "remove", 1, filename); + return; + } else { + kapply_cc(K, KINERT); + return; + } +} + +/* 15.1.? rename-file */ +void rename_file(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, "string", ttisstring, old_filename, + "string", ttisstring, new_filename); + + /* TEMP: this should probably be done in a operating system specific + manner, but this will do for now */ + /* XXX: this could fail if there's a dead (in the gc sense) port still + open, should probably retry once after doing a complete GC */ + if (rename(kstring_buf(old_filename), kstring_buf(new_filename))) { + klispE_throw_errno_with_irritants(K, "rename", 2, old_filename, new_filename); + return; + } else { + kapply_cc(K, KINERT); + return; + } +} + +/* ?.? get-script-arguments, get-interpreter-arguments */ +void get_arguments(klisp_State *K) +{ + /* + ** xparams[0]: immutable argument list + */ + TValue ptree = K->next_value; + TValue *xparams = K->next_xparams; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(denv); + + check_0p(K, ptree); + TValue res = xparams[0]; + kapply_cc(K, res); +} + +/* ?.? get-environment-variable, get-environment-variables */ +void get_environment_variable(klisp_State *K) +{ + TValue ptree = K->next_value; + TValue *xparams = K->next_xparams; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + UNUSED(denv); + + bind_1tp(K, ptree, "string", ttisstring, name); + char *str = getenv(kstring_buf(name)); + /* I follow r7rs here, but should probably throw error */ + TValue res; + if (str == NULL) { + res = KFALSE; + } else { + res = kstring_new_b_imm(K, str); + } + kapply_cc(K, res); +} + +void get_environment_variables(klisp_State *K) +{ + /* + ** xparams[0]: immutable variable list + */ + TValue ptree = K->next_value; + TValue *xparams = K->next_xparams; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(denv); + + check_0p(K, ptree); + kapply_cc(K, xparams[0]); +} + +/* This should work in mingw as well as gcc */ +/* TODO test, if that doesn't work, try to find a way + avoiding taking extra params in main */ +/* I think it's defined in unistd, but it needs to have __USE_GNU + defined. The correct way to do that would be to define _GNU_SOURCE + before including any system files... That's not so good for an + embeddable interpreter, but it could be done in the makefile I guess */ +extern char **environ; + +/* Helper for get-environment-variables */ +TValue create_env_var_list(klisp_State *K) +{ + /* no need for gc guarding in this context */ + TValue var_name, var_value; + TValue tail = KNIL; + + /* This should work in mingw as well as gcc */ + /* TODO test, if that doesn't work, try to find a way + avoiding taking extra params in main */ + for(char **env = environ; *env != NULL; ++env) { + /* *env is of the form: "<name>=<value>", presumably, name can't have + an equal sign! */ + char *eq = strchr(*env, '='); + int name_len = eq - *env; + klisp_assert(eq != NULL); /* shouldn't happen */ + var_name = kstring_new_bs_imm(K, *env, name_len); + var_value = kstring_new_b_imm(K, *env + name_len + 1); + TValue new_entry = kimm_cons(K, var_name, var_value); + tail = kimm_cons(K, new_entry, tail); + } + return tail; +} + /* init ground */ void kinit_system_ground_env(klisp_State *K) { @@ -113,4 +276,22 @@ void kinit_system_ground_env(klisp_State *K) /* ??.?.? jiffies-per-second */ add_applicative(K, ground_env, "jiffies-per-second", jiffies_per_second, 0); + /* ?.? file-exists? */ + add_applicative(K, ground_env, "file-exists?", file_existsp, 0); + /* ?.? delete-file */ + add_applicative(K, ground_env, "delete-file", delete_file, 0); + /* this isn't in r7rs but it's in ansi c and quite easy to implement */ + /* ?.? rename-file */ + add_applicative(K, ground_env, "rename-file", rename_file, 0); + /* The value for these two will get set later by the interpreter */ + /* ?.? get-script-arguments, get-interpreter-arguments */ + add_applicative(K, ground_env, "get-script-arguments", get_arguments, + 1, KNIL); + add_applicative(K, ground_env, "get-interpreter-arguments", get_arguments, + 1, KNIL); + /* ?.? get-environment-variable, get-environment-variables */ + add_applicative(K, ground_env, "get-environment-variable", + get_environment_variable, 0); + add_applicative(K, ground_env, "get-environment-variables", + get_environment_variables, 1, create_env_var_list(K)); } diff --git a/src/kgvectors.c b/src/kgvectors.c @@ -89,7 +89,7 @@ void vector_ref(klisp_State *K) } /* (R7RS 3rd draft 6.3.6) vector-set! */ -void vector_setS(klisp_State *K) +void vector_setB(klisp_State *K) { klisp_assert(ttisenvironment(K->next_env)); @@ -187,6 +187,31 @@ void vector_to_list(klisp_State *K) kapply_cc(K, tail); } +/* ?.? vector-fill! */ +void vector_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, "vector", ttisvector, vector, + "any", anytype, fill); + + if (kvector_immutablep(vector)) { + klispE_throw_simple(K, "immutable vector"); + return; + } + + uint32_t size = kvector_length(vector); + TValue *buf = kvector_array(vector); + while(size-- > 0) { + *buf++ = fill; + } + kapply_cc(K, KINERT); +} + /* ??.?.? vector->immutable-vector */ void vector_to_immutable_vector(klisp_State *K) { @@ -228,7 +253,7 @@ void kinit_vectors_ground_env(klisp_State *K) /* (R7RS 3rd draft 6.3.6) vector-ref vector-set! */ add_applicative(K, ground_env, "vector-ref", vector_ref, 0); - add_applicative(K, ground_env, "vector-set!", vector_setS, 0); + add_applicative(K, ground_env, "vector-set!", vector_setB, 0); /* (R7RS 3rd draft 6.3.6) vector, vector->list, list->vector */ add_applicative(K, ground_env, "vector", vector, 0); @@ -238,9 +263,11 @@ void kinit_vectors_ground_env(klisp_State *K) /* ??.1.?? vector-copy */ add_applicative(K, ground_env, "vector-copy", vector_copy, 0); - /* TODO: vector->string, string->vector, vector-fill */ + /* TODO: vector->string, string->vector */ /* TODO: vector-copy! vector-copy-partial vector-copy-partial! */ + add_applicative(K, ground_env, "vector-fill!", vector_fillB, 0); + /* ??.1.?? vector->immutable-vector */ add_applicative(K, ground_env, "vector->immutable-vector", vector_to_immutable_vector, 0); diff --git a/src/klisp.c b/src/klisp.c @@ -25,14 +25,16 @@ #include "kstring.h" #include "kcontinuation.h" #include "koperative.h" +#include "kapplicative.h" +#include "ksymbol.h" #include "kenvironment.h" #include "kport.h" #include "kread.h" #include "kwrite.h" #include "kerror.h" +#include "kghelpers.h" /* for do_return_value */ #include "kgcontinuations.h" /* for do_pass_value */ #include "kgcontrol.h" /* for do_seq */ -#include "kscript.h" #include "krepl.h" /* TODO update dependencies in makefile */ @@ -139,7 +141,7 @@ static void show_error(klisp_State *K, TValue obj) { static int report (klisp_State *K, int status) { - if (status != 0) { + if (status != EXIT_SUCCESS) { const char *msg = "Error!"; k_message(progname, msg); show_error(K, K->next_value); @@ -253,12 +255,22 @@ static int dostring (klisp_State *K, const char *s, const char *name) /* only port remains in the root stack */ krooted_tvs_push(K, inner_cont); + /* This continuation will discard the result of the evaluation + and pass the root continuation #inert instead. This has to do with + the way the exit value of the interpreter is calculated (see man page) + */ + TValue discard_cont = kmake_continuation(K, inner_cont, do_return_value, + 1, KINERT); + + krooted_tvs_pop(K); /* pop inner cont */ + krooted_tvs_push(K, discard_cont); + /* XXX This should probably be an extra param to the function */ env = K->next_env; /* this is the standard env that should be used for evaluation */ - TValue eval_cont = kmake_continuation(K, inner_cont, do_str_eval, + TValue eval_cont = kmake_continuation(K, discard_cont, do_str_eval, 1, env); - krooted_tvs_pop(K); /* pop inner cont */ + krooted_tvs_pop(K); /* pop discard cont */ krooted_tvs_push(K, eval_cont); TValue read_cont = kmake_continuation(K, eval_cont, do_str_read, 1, port); @@ -269,8 +281,7 @@ static int dostring (klisp_State *K, const char *s, const char *name) klispS_run(K); - int status = errorp? 1 : 0; - + int status = errorp? EXIT_FAILURE : EXIT_SUCCESS; /* get the standard environment again in K->next_env */ K->next_env = env; return report(K, status); @@ -330,7 +341,7 @@ static int dofile(klisp_State *K, const char *name) krooted_tvs_pop(K); krooted_tvs_pop(K); K->next_value = error_obj; - return report(K, 1); + return report(K, EXIT_FAILURE); } TValue name_str = kstring_new_b(K, name); @@ -369,12 +380,23 @@ static int dofile(klisp_State *K, const char *name) /* only port remains in the root stack */ krooted_tvs_push(K, inner_cont); + + /* This continuation will discard the result of the evaluation + and pass the root continuation #inert instead. This has to do with + the way the exit value of the interpreter is calculated (see man page) + */ + TValue discard_cont = kmake_continuation(K, inner_cont, do_return_value, + 1, KINERT); + + krooted_tvs_pop(K); /* pop inner cont */ + krooted_tvs_push(K, discard_cont); + /* XXX This should probably be an extra param to the function */ env = K->next_env; /* this is the standard env that should be used for evaluation */ - TValue eval_cont = kmake_continuation(K, inner_cont, do_file_eval, + TValue eval_cont = kmake_continuation(K, discard_cont, do_file_eval, 1, env); - krooted_tvs_pop(K); /* pop inner cont */ + krooted_tvs_pop(K); /* pop discard cont */ krooted_tvs_push(K, eval_cont); TValue read_cont = kmake_continuation(K, eval_cont, do_file_read, 1, port); @@ -385,7 +407,7 @@ static int dofile(klisp_State *K, const char *name) klispS_run(K); - int status = errorp? 1 : 0; + int status = errorp? EXIT_FAILURE : EXIT_SUCCESS; /* get the standard environment again in K->next_env */ K->next_env = env; @@ -459,6 +481,8 @@ static int runargs (klisp_State *K, char **argv, int n) TValue env = K->next_env; UNUSED(env); + /* TEMP All passes to root cont and all resulting values will be ignored, + the only way to interrupt the running of arguments is to throw an error */ for (int i = 1; i < n; i++) { if (argv[i] == NULL) continue; @@ -473,7 +497,7 @@ static int runargs (klisp_State *K, char **argv, int n) klisp_assert(chunk != NULL); if (dostring(K, chunk, "=(command line)") != 0) - return 1; + return EXIT_FAILURE; break; } // case 'l': /* no libraries for now */ @@ -481,14 +505,48 @@ static int runargs (klisp_State *K, char **argv, int n) break; } } - return 0; + return EXIT_SUCCESS; +} + +static void populate_argument_lists(klisp_State *K, char **argv, int argc, + int script) +{ + /* first create the script list */ + TValue tail = KNIL; + TValue obj = KINERT; + krooted_vars_push(K, &tail); + krooted_vars_push(K, &obj); + while(argc > script) { + char *arg = argv[--argc]; + obj = kstring_new_b_imm(K, arg); + tail = kimm_cons(K, obj, tail); + } + /* Store the script argument list */ + obj = ksymbol_new(K, "get-script-arguments", KNIL); + klisp_assert(kbinds(K, K->ground_env, obj)); + obj = kunwrap(kget_binding(K, K->ground_env, obj)); + tv2op(obj)->extra[0] = tail; + + while(argc > 0) { + char *arg = argv[--argc]; + obj = kstring_new_b_imm(K, arg); + tail = kimm_cons(K, obj, tail); + } + /* Store the interpreter argument list */ + obj = ksymbol_new(K, "get-interpreter-arguments", KNIL); + klisp_assert(kbinds(K, K->ground_env, obj)); + obj = kunwrap(kget_binding(K, K->ground_env, obj)); + tv2op(obj)->extra[0] = tail; + + krooted_vars_pop(K); + krooted_vars_pop(K); } static int handle_klispinit(klisp_State *K) { const char *init = getenv(KLISP_INIT); if (init == NULL) - return 0; /* status OK */ + return EXIT_SUCCESS; else return dostring(K, init, "=" KLISP_INIT); } @@ -500,12 +558,12 @@ struct Smain { int status; }; -static int pmain(klisp_State *K) +static void pmain(klisp_State *K) { /* This is weird but was done to follow lua scheme */ struct Smain *s = (struct Smain *) pvalue(K->next_value); char **argv = s->argv; - s->status = 0; + s->status = EXIT_SUCCESS; /* There is a standard env in K->next_env, a common one is used for all evaluations (init, expression args, script/repl) */ @@ -524,32 +582,36 @@ static int pmain(klisp_State *K) /* init (eval KLISP_INIT env variable contents) */ s->status = handle_klispinit(K); - if (s->status != 0) - return 0; + if (s->status != EXIT_SUCCESS) + return; bool has_i = false, has_v = false, has_e = false; int script = collectargs(argv, &has_i, &has_v, &has_e); if (script < 0) { /* invalid args? */ print_usage(); - s->status = 1; - return 0; + s->status = EXIT_FAILURE; + return; } if (has_v) print_version(); + /* TEMP this could be either set before or after running the arguments, + we'll do it before for now */ + populate_argument_lists(K, argv, s->argc, (script > 0) ? script : s->argc); + s->status = runargs(K, argv, (script > 0) ? script : s->argc); - if (s->status != 0) - return 0; + if (s->status != EXIT_SUCCESS) + return; if (script > 0) { s->status = handle_script(K, argv, script); } - if (s->status != 0) - return 0; + if (s->status != EXIT_SUCCESS) + return; if (has_i) { dotty(K); @@ -561,13 +623,10 @@ static int pmain(klisp_State *K) s->status = dofile(K, NULL); } } - - return 0; } int main(int argc, char *argv[]) { - int status; struct Smain s; klisp_State *K = klispL_newstate(); @@ -580,9 +639,24 @@ int main(int argc, char *argv[]) s.argc = argc; s.argv = argv; K->next_value = p2tv(&s); - status = pmain(K); + + pmain(K); + + if (s.status == EXIT_SUCCESS) { + /* must check value passed to the root continuation to + return proper exit status */ + if (ttisinert(K->next_value)) { + s.status = EXIT_SUCCESS; + } else if (ttisboolean(K->next_value)) { + s.status = kis_true(K->next_value)? EXIT_SUCCESS : EXIT_FAILURE; + } else if (ttisfixint(K->next_value)) { + s.status = ivalue(K->next_value); + } else { + s.status = EXIT_FAILURE; + } + } klisp_close(K); - return (status || s.status)? EXIT_FAILURE : EXIT_SUCCESS; + return s.status; } diff --git a/src/kpair.h b/src/kpair.h @@ -61,7 +61,6 @@ inline TValue kcdr(TValue p) #define kcdddar(p_) (kcdr(kcdr(kcdr(kcar(p_))))) #define kcddddr(p_) (kcdr(kcdr(kcdr(kcdr(p_))))) -/* these will also work with immutable pairs */ inline void kset_car(TValue p, TValue v) { klisp_assert(kmutable_pairp(p)); diff --git a/src/krepl.c b/src/krepl.c @@ -19,7 +19,7 @@ #include "ksymbol.h" #include "kport.h" #include "kpair.h" -#include "kgerror.h" +#include "kgerrors.h" /* for names */ #include "ktable.h" /* for do_pass_value */ @@ -237,7 +237,7 @@ void do_int_repl_error(klisp_State *K) krooted_tvs_pop(K); } else { fprintf(stderr, "\n*ERROR*: not an error object passed to " - "error continuation"); + "error continuation\n\n"); } UNUSED(divert); diff --git a/src/kscript.c b/src/kscript.c @@ -1,254 +0,0 @@ -/* -** kscript.c -** klisp noninteractive script execution -** See Copyright Notice in klisp.h -*/ -#include <stdio.h> -#include <setjmp.h> - -#include "klisp.h" -#include "kstate.h" -#include "kobject.h" -#include "kcontinuation.h" -#include "kenvironment.h" -#include "kerror.h" -#include "kread.h" -#include "kwrite.h" -#include "kstring.h" -#include "krepl.h" -#include "kscript.h" -#include "ksymbol.h" -#include "kport.h" -#include "kpair.h" -#include "kgcontrol.h" -#include "kgerror.h" -/* for names */ -#include "ktable.h" - -/* Push (v) in GC roots and return (v). */ -static inline TValue krooted_tvs_pass(klisp_State *K, TValue v) -{ - krooted_tvs_push(K, v); - return v; -} - -#if KTRACK_SI -static inline TValue krooted_tvs_pass_si(klisp_State *K, TValue v, TValue si) -{ - krooted_tvs_push(K, v); - kset_source_info(K, v, si); - return v; -} -#endif - -/* the exit continuation, it exits the loop */ -void do_script_exit(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - UNUSED(xparams); - - /* save exit code */ - - switch(ttype(obj)) { - case K_TINERT: - K->script_exit_code = 0; - break; - case K_TFIXINT: - K->script_exit_code = (int) ivalue(obj); - break; - default: - K->script_exit_code = KSCRIPT_DEFAULT_ERROR_EXIT_CODE; - /* TODO: print error message here ? */ - break; - } - - /* force the loop to terminate */ - K->next_func = NULL; - return; -} - - -/* the underlying function of the error cont */ -void do_script_error(klisp_State *K) -{ - TValue *xparams = K->next_xparams; - TValue obj = K->next_value; - klisp_assert(ttisnil(K->next_env)); - /* - ** xparams[0]: dynamic environment - */ - UNUSED(xparams); - /* FOR NOW used only for irritant list */ - TValue port = kcdr(K->kd_error_port_key); - klisp_assert(kfport_file(port) == stderr); - - /* TEMP: obj should be an error obj */ - if (ttiserror(obj)) { - Error *err_obj = tv2error(obj); - TValue who = err_obj->who; - char *who_str; - /* TEMP? */ - if (ttiscontinuation(who)) - who = tv2cont(who)->comb; - - if (ttisstring(who)) { - who_str = kstring_buf(who); -#if KTRACK_NAMES - } else if (khas_name(who)) { - TValue name = kget_name(K, who); - who_str = ksymbol_buf(name); -#endif - } else { - who_str = "?"; - } - char *msg = kstring_buf(err_obj->msg); - fprintf(stderr, "\n*ERROR*: \n"); - fprintf(stderr, "%s: %s", who_str, msg); - - krooted_tvs_push(K, obj); - - /* Msg + irritants */ - /* TODO move to a new function */ - if (!ttisnil(err_obj->irritants)) { - fprintf(stderr, ": "); - kwrite_display_to_port(K, port, err_obj->irritants, false); - } - kwrite_newline_to_port(K, port); - -#if KTRACK_NAMES -#if KTRACK_SI - /* Location */ - /* TODO move to a new function */ - /* MAYBE: remove */ - if (khas_name(who) || khas_si(who)) { - fprintf(stderr, "Location: "); - kwrite_display_to_port(K, port, who, false); - kwrite_newline_to_port(K, port); - } - - /* Backtrace */ - /* TODO move to a new function */ - TValue tv_cont = err_obj->cont; - fprintf(stderr, "Backtrace: \n"); - while(ttiscontinuation(tv_cont)) { - kwrite_display_to_port(K, port, tv_cont, false); - kwrite_newline_to_port(K, port); - Continuation *cont = tv2cont(tv_cont); - tv_cont = cont->parent; - } - /* add extra newline at the end */ - kwrite_newline_to_port(K, port); -#endif -#endif - krooted_tvs_pop(K); - } else { - fprintf(stderr, "\n*ERROR*: not an error object passed to " - "error continuation"); - } - - /* Save the exit code to be returned from interpreter - main(). Terminate the interpreter loop. */ - - K->script_exit_code = KSCRIPT_DEFAULT_ERROR_EXIT_CODE; - K->next_func = NULL; -} - -/* convert C style argc-argv pair to list of strings */ -static TValue argv2value(klisp_State *K, int argc, char *argv[]) -{ - TValue dummy = kcons_g(K, false, KINERT, KNIL); - krooted_tvs_push(K, dummy); - TValue tail = dummy; - for (int i = 0; i < argc; i++) { - TValue next_car = kstring_new_b_imm(K, argv[i]); - krooted_tvs_push(K, next_car); - TValue np = kcons_g(K, false, next_car, KNIL); - krooted_tvs_pop(K); - kset_cdr_unsafe(K, tail, np); - tail = np; - } - krooted_tvs_pop(K); - return kcdr(dummy); -} - -/* loader_body(K, ARGV, DENV) returns the value - * - * ((load (car ARGV)) - * ($if ($binds? DENV main) (main ARGV) #inert) - * - */ -static TValue loader_body(klisp_State *K, TValue argv, TValue denv) -{ - int32_t rooted_tvs_mark = K->rooted_tvs_top; -# define S(z) (krooted_tvs_pass(K, ksymbol_new(K, (z), KNIL))) -# define C(car, cdr) (krooted_tvs_pass(K, kcons_g(K, false, (car), (cdr)))) -# define L(n, ...) (krooted_tvs_pass(K, klist_g(K, false, (n), __VA_ARGS__))) - TValue main_sym = S("main"); - TValue script_name = krooted_tvs_pass(K, kcar(argv)); - TValue body = - L(2, L(2, S("load"), script_name), - L(4, S("$if"), L(3, S("$binds?"), denv, main_sym), - L(2, main_sym, C(S("list"), argv)), - KINERT)); -# undef S -# undef L - K->rooted_tvs_top = rooted_tvs_mark; - return body; -} - -/* call this to init the noninteractive mode */ - -void kinit_script(klisp_State *K, int argc, char *argv[]) -{ -# define R(z) (krooted_tvs_pass(K, (z))) -# define G(z, sym) \ - do { TValue symbol = ksymbol_new(K, (sym), KNIL); \ - krooted_tvs_push(K, symbol); \ - kadd_binding(K, K->ground_env, symbol, (z)); \ - krooted_tvs_pop(K); \ - } while (0) - -#if KTRACK_SI - TValue str = R(kstring_new_b_imm(K, __FILE__)); - TValue tail = R(kcons(K, i2tv(__LINE__), i2tv(0))); - TValue si = kcons(K, str, tail); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_push(K, si); -# define RSI(z) (krooted_tvs_pass_si(K, (z), si)) -#else -# define RSI(z) R(z) -#endif - - TValue std_env = RSI(kmake_environment(K, K->ground_env)); - TValue root_cont = RSI(kmake_continuation(K, KNIL, do_script_exit, 0)); - TValue error_cont = RSI(kmake_continuation(K, root_cont, do_script_error, 1, std_env)); - G(root_cont, "root-continuation"); - G(error_cont, "error-continuation"); - K->root_cont = root_cont; - K->error_cont = error_cont; - krooted_tvs_pop(K); - krooted_tvs_pop(K); - - /* Create error continuation hierarchy. */ - kinit_error_hierarchy(K); - - TValue argv_value = RSI(argv2value(K, argc, argv)); - TValue loader = RSI(loader_body(K, argv_value, std_env)); - TValue loader_cont = RSI(kmake_continuation(K, root_cont, do_seq, 2, loader, std_env)); - kset_cc(K, loader_cont); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); -#if KTRACK_SI - krooted_tvs_pop(K); -#endif - kapply_cc(K, KINERT); - -#undef R -#undef RSI -#undef G -} diff --git a/src/kscript.h b/src/kscript.h @@ -1,25 +0,0 @@ -/* -** krepl.h -** klisp noninteractive script execution -** See Copyright Notice in klisp.h -*/ - -#ifndef kscript_h -#define kscript_h - -#include <stdio.h> -#include "klisp.h" -#include "kstate.h" -#include "kobject.h" - -void kinit_script(klisp_State *K, int argc, char *argv[]); - -/* continuation functions */ -void do_script_exit(klisp_State *K); -void do_script_error(klisp_State *K); - -/* default exit code in case of error according to SRFI-22 */ - -#define KSCRIPT_DEFAULT_ERROR_EXIT_CODE 70 - -#endif diff --git a/src/kstate.c b/src/kstate.c @@ -30,7 +30,6 @@ #include "kenvironment.h" #include "kground.h" #include "krepl.h" -#include "kscript.h" #include "ksymbol.h" #include "kstring.h" #include "kport.h" @@ -39,7 +38,7 @@ #include "kvector.h" #include "kgpairs_lists.h" /* for creating list_app */ -#include "kgerror.h" /* for creating error hierarchy */ +#include "kgerrors.h" /* for creating error hierarchy */ #include "kgc.h" /* for memory freeing & gc init */ @@ -196,9 +195,6 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { /* initialize writer */ K->write_displayp = false; /* set on each call to write */ - /* initialize script */ - K->script_exit_code = KSCRIPT_DEFAULT_ERROR_EXIT_CODE; - /* initialize temp stack */ K->ssize = KS_ISSIZE; K->stop = 0; /* stack is empty */ diff --git a/src/kstate.h b/src/kstate.h @@ -151,10 +151,6 @@ struct klisp_State { /* writer */ bool write_displayp; - /* script */ - /* REFACTOR rename to exit_code */ - int script_exit_code; - /* auxiliary stack */ int32_t ssize; /* total size of array */ int32_t stop; /* top of the stack (all elements are below this index) */ diff --git a/src/rep_op_c.sed b/src/rep_op_c.sed @@ -1,78 +0,0 @@ -# This is a collection of sed commands to refactor operatives underlying -# functions to just take a kernel state pointer (instead of also taking extra -# params, ptree and denv). - -# All these tests are run one at a time with sed -n - -# This is a collection of sed commands to refactor operatives underlying -# functions to just take a kernel state pointer (instead of also taking extra -# params, ptree and denv). - -# All these tests are run one at a time with sed -n - -# detect single line function definition -# There are 0 -#/^void \(.*\)[(]klisp_State \*K, TValue \*xparams, TValue ptree, TValue denv[)];/P - -# All the single line definitions done - -# try to detect multi line function definition -# There are 1, do_int_repl_error -#/^void \(.*\)[(]klisp_State \*K,/{ -#N -#/^void \(.*\)[(]klisp_State \*K,[[:space:]]*TValue \*xparams,[[:space:]]*TValue ptree,[[:space:]]*TValue denv);/P -#} - -# replace it -#/^void \(.*\)[(]klisp_State \*K,/{ -#N -#s/^void \(.*\)[(]klisp_State \*K,[[:space:]]*TValue \*xparams,[[:space:]]*TValue ptree,[[:space:]]*#TValue denv);/void \1(klisp_State *K);/ -#} - -# done! - -# Detect all with simple brace -# There are 101 -#/^void \(.*\)[(]klisp_State \*K, TValue \*xparams, TValue ptree, TValue denv[)]/{ -#N -#/^void \(.*\)[(]klisp_State \*K, TValue \*xparams, TValue ptree, TValue denv[)].*\n[{]/P -#} - -# replace them -# This is used to modify in place with sed -i -f <this-file> *.c -#/^void \(.*\)[(]klisp_State \*K, TValue \*xparams, TValue ptree, TValue denv[)]/{ -#N -#s/^void \(.*\)[(]klisp_State \*K, TValue \*xparams, TValue ptree, TValue denv[)].*\n[{]/void \1(klisp_State *K)\ -#\{\ -# TValue *xparams = K->next_xparams;\ -# TValue ptree = K->next_value;\ -# TValue denv = K->next_env;\ -# klisp_assert(ttisenvironment(K->next_env));/ -#} - -# Detect the ones in two lines (with braces) -# There are 84 -#/^void \(.*\)[(]klisp_State \*K,/{ -#N -#N -#/^void \(.*\)[(]klisp_State \*K,[[:space:]]*TValue \*xparams,[[:space:]]*TValue ptree,[[:space:]]*TValue denv[)][[:space:]]*[{]/P -#} - -# replace them -# This is used to modify in place with sed -i -f <this-file> *.c -/^void \(.*\)[(]klisp_State \*K,/{ -N -N -s/^void \(.*\)[(]klisp_State \*K,[[:space:]]*TValue \*xparams,[[:space:]]*TValue ptree,[[:space:]]*TValue denv[)][[:space:]]*[{]/void \1(klisp_State *K)\ -\{\ - TValue *xparams = K->next_xparams;\ - TValue ptree = K->next_value;\ - TValue denv = K->next_env;\ - klisp_assert(ttisenvironment(K->next_env));/ -} - -# keval_ofn was changed manually because the name of denv was env -# (denv was reserved for the den param in ptree) -# do_vau was changed manually because the name of ptree was obj -# (ptree was reserved for the ptree param) -# ffi_type_ref and ffi_type_ref were changed manually (were static) diff --git a/src/rep_op_h.sed b/src/rep_op_h.sed @@ -1,31 +0,0 @@ -# This is a collection of sed commands to refactor operatives underlying -# functions to just take a kernel state pointer (instead of also taking extra -# params, ptree and denv). - -# All these tests are run one at a time with sed -n - -# detect single line function definition -# There are 97 -/^void \(.*\)[(]klisp_State \*K, TValue \*xparams, TValue ptree, TValue denv[)];/P - -# Replace them in place with sed -i -f <this-file> *.h -#s/^void \(.*\)[(]klisp_State \*K, TValue \*xparams, TValue ptree, TValue denv[)];/void \1(klisp_State *K);/ - -# All the single line definitions done - -# try to detect multi line function definition -# There are 62 -#/^void \(.*\)[(]klisp_State \*K,/{ -#N -#/^void \(.*\)[(]klisp_State \*K,[[:space:]]*TValue \*xparams,[[:space:]]*TValue ptree,[[:space:]]*TValue denv);/P -#} - -# replace them -# equalp had a type (was xparas instead of xparams), correct first -s/xparas/xparams/ -/^void \(.*\)[(]klisp_State \*K,/{ -N -s/^void \(.*\)[(]klisp_State \*K,[[:space:]]*TValue \*xparams,[[:space:]]*TValue ptree,[[:space:]]*TValue denv);/void \1(klisp_State *K);/ -} - -# Done! -\ No newline at end of file diff --git a/src/tests/bytevectors.k b/src/tests/bytevectors.k @@ -5,9 +5,6 @@ ;; helper functions ;; -;; (list->bytevector INTEGERS) converts list of integers to bytevector -;; The elements of INTEGERS must be in the range 0...255. -;; ;; (u8 X_0 X_1 ... X_{N-1}) returns a bytevector B of length N, ;; such that B[k] = X_k ;; @@ -19,23 +16,8 @@ ;; such that the bytes B[4k] ... B[4k+3], combined into 32-bit ;; unsigned integer, represent the number X_k ;; -($define! list->bytevector - ($lambda (bytes) - ($let* - ( (n (length bytes)) - (v (make-bytevector n)) ) - ($letrec - ((loop ($lambda (i xs) - ($if (<? i n) - ($sequence - (bytevector-u8-set! v i (car xs)) - (loop (+ i 1) (cdr xs))) - #inert)))) - (loop 0 bytes) - v)))) - -($define! u8 - ($lambda bytes (list->bytevector bytes))) + +($define! u8 bytevector) ;; TODO: endianess ($define! u16 @@ -73,6 +55,27 @@ ($check-predicate (mutable-bytevector?)) ($check-predicate (mutable-bytevector? (make-bytevector 1))) +;; XXX bytevector +($check-predicate (bytevector? (bytevector 1 2 3))) +($check-predicate (mutable-bytevector? (bytevector 1 2 3))) +($check equal? (bytevector 1 2 3) (list->bytevector (list 1 2 3))) + +;; XXX list->bytevector +($check equal? (make-bytevector 0) (list->bytevector ())) +($check equal? (make-bytevector 3 1) (list->bytevector (list 1 1 1))) +($check equal? (list->bytevector (list 1 2 3 4)) (u8 1 2 3 4)) +($check-predicate (mutable-bytevector? (list->bytevector (list 1 2 3)))) +($check-predicate (mutable-bytevector? (list->bytevector + (copy-es-immutable (list 1 2 3))))) + +;; XXX bytevector->list +($check-predicate (null? (bytevector->list (u8)))) +($check equal? (bytevector->list (u8 1 2 3 4)) (list 1 2 3 4)) +($check-predicate (mutable-pair? (bytevector->list (u8 1 2)))) +($check-predicate (mutable-pair? (bytevector->list + (bytevector->immutable-bytevector + (u8 1 2))))) + ;; (R7RS 3rd draft, section 6.3.7) make-bytevector bytevector-length ($check equal? (bytevector-length (make-bytevector 0)) 0) @@ -162,6 +165,13 @@ ($check-error (bytevector-copy-partial! (u8 1 2) -1 0 v 0)) ($check-error (bytevector-copy-partial! (u8 1 2) 0 2 w 0))) +;; XXX bytevector-u8-fill! +($check-predicate (inert? (bytevector-u8-fill! (u8 1 2) 0))) +($check equal? ($let ((b (u8 1 2 3))) + (bytevector-u8-fill! b 0) + b) + (u8 0 0 0)) + ;; XXX bytevector->immutable-bytevector ($check-predicate diff --git a/src/tests/characters.k b/src/tests/characters.k @@ -73,8 +73,7 @@ ($check-predicate (char-lower-case? #\a #\b #\j #\y #\z)) ($check-predicate ($false-for-all? char-lower-case? #\0 #\A #\Z #\' #\@ #\{ #\[ #\~)) -;; XXX char-upcase char-downcase - +;; XXX char-upcase char-downcase char-titlecase char-foldcase ($check equal? (char-upcase #\a) #\A) ($check equal? (char-upcase #\z) #\Z) ($check equal? (char-upcase #\R) #\R) @@ -85,6 +84,16 @@ ($check equal? (char-downcase #\r) #\r) ($check equal? (char-downcase #\9) #\9) +($check equal? (char-titlecase #\a) #\A) +($check equal? (char-titlecase #\z) #\Z) +($check equal? (char-titlecase #\R) #\R) +($check equal? (char-titlecase #\2) #\2) + +($check equal? (char-foldcase #\A) #\a) +($check equal? (char-foldcase #\Z) #\z) +($check equal? (char-foldcase #\r) #\r) +($check equal? (char-foldcase #\9) #\9) + ;; XXX char->integer integer->char ($check equal? (char->integer #\space) #x20) diff --git a/src/tests/error.k b/src/tests/error.k @@ -39,7 +39,10 @@ ($check equal? (error-object-irritants e1) ()) ($check equal? (error-object-irritants e2) (list 1 2 3)) ($check equal? (error-object-irritants e3) ()) - ($check equal? (error-object-irritants e4) (list 1)) +;; error now uses the standard binding constructs from kghelper +;; for now they don't encapsulate any data in the error, but +;; they will in the future +;; ($check equal? (error-object-irritants e4) (list 1)) ($check-error (error-object-irritants)) ($check-error (error-object-irritants e1 e2)) diff --git a/src/tests/numbers.k b/src/tests/numbers.k @@ -60,7 +60,6 @@ ($check equal? #i+infinity #i+infinity) ;; 12.5.1 number? finite? integer? - ($check-predicate (number? 0 1 3/5 -3.14e0 #real)) ($check-not-predicate (number? 5 "6" 7)) @@ -77,6 +76,15 @@ ($check-not-predicate (integer? #real)) ($check-not-predicate (integer? "0")) +;; 12.?? exact-integer? +($check-predicate (exact-integer? 0 8/2 -12/6)) +($check-not-predicate (exact-integer? 1.0)) +($check-not-predicate (exact-integer? #e+infinity)) +($check-not-predicate (exact-integer? #e-infinity)) +($check-not-predicate (exact-integer? #real)) +($check-not-predicate (exact-integer? "0")) + + ;; 12.5.2 =? ($check-predicate (=?)) diff --git a/src/tests/pair-mutation.k b/src/tests/pair-mutation.k @@ -35,7 +35,29 @@ ($check equal? ($let ((l (list* 1 2 3 4 5))) (encycle! l 0 3) l) (list . #0=(1 2 3 . #0#))) +;; list-set! +($check-predicate (inert? (list-set! (list 0 1 2 3) 0 10))) +($check equal? ($let ((l (list 0 1 2 3))) + (list-set! l 1 10) + (list-set! l 3 30) + l) + (list 0 10 2 30)) +($check equal? ($let ((l (list 0 . #1=(1 2 . #1#)))) + (list-set! l 1 10) + (list-set! l 4 20) + l) + (list 0 . #2=(10 20 . #2#))) +;; see kgpair_mut.c for rationale on allowing +;; improper lists as argument to list-set! +($check equal? ($let ((l (list* 0 1 2 3))) + (list-set! l 1 10) + (list-set! l 2 20) + l) + (list* 0 10 20 3)) + ;; append! +($check-predicate (inert? (append! (list 1) (list 2)))) + ($let () ($define! l1 (list 1 2)) ($define! l2 (list 3 4)) @@ -159,6 +181,19 @@ ($check-error (encycle! (list 1 2 3) 0 -2)) ($check-error (encycle! (list 1 2 3) 0 #e+infinity)) +;; list-set! +;; set-car! & set-cdr! +($check-error (list-set!)) +($check-error (list-set! (list 1))) +($check-error (list-set! (list 1) 0)) +($check-error (list-set! (list 1) 0 1 1)) + +($check-error (list-set! #inert 0 0)) +($check-error (list-set! () 0 0)) +($check-error (list-set! (list 1 2) 2 0)) +($check-error (list-set! (list 1 2) -1 0)) +($check-error (list-set! (list* 1 2 3) 2 0)) + ;; append! ;; ASK does the report assert that the lists remains unmodified?? ;; probably should for robust implementations diff --git a/src/tests/pairs-and-lists.k b/src/tests/pairs-and-lists.k @@ -31,11 +31,11 @@ (enc #inert)))) ($check-not-predicate (null? (memoize #inert))) ($check-not-predicate (null? 1)) -;($check-not-predicate (null? 1.0)) +($check-not-predicate (null? 1.0)) ($check-not-predicate (null? #e+infinity)) -;($check-not-predicate (null? #i+infinity)) -;($check-not-predicate (null? #undefined)) -;($check-not-predicate (null? #real-with-no-primary-value)) +($check-not-predicate (null? #i+infinity)) +($check-not-predicate (null? #undefined)) +($check-not-predicate (null? #real)) ($check-not-predicate (null? "string")) ($check-not-predicate (null? #\a)) ($check-not-predicate (null? (get-current-input-port))) @@ -54,11 +54,11 @@ (enc #inert)))) ($check-not-predicate (pair? (memoize #inert))) ($check-not-predicate (pair? 1)) -;($check-not-predicate (pair? 1.0)) +($check-not-predicate (pair? 1.0)) ($check-not-predicate (pair? #e+infinity)) -;($check-not-predicate (pair? #i+infinity)) -;($check-not-predicate (pair? #undefined)) -;($check-not-predicate (pair? #real-with-no-primary-value)) +($check-not-predicate (pair? #i+infinity)) +($check-not-predicate (pair? #undefined)) +($check-not-predicate (pair? #real)) ($check-not-predicate (pair? "string")) ($check-not-predicate (pair? #\a)) ($check-not-predicate (pair? (get-current-input-port))) @@ -128,6 +128,26 @@ ($check eq? (cadddr tree16) 15) ($check eq? (cddddr tree16) 16)) +;; make-list +($check-predicate (null? (make-list 0))) +($check-predicate (mutable-pair? (make-list 1))) +($check equal? (make-list 2) (list #inert #inert)) +($check equal? (make-list 3 "val") (list "val" "val" "val")) + +;; list-copy +($check-predicate (null? (list-copy ()))) +($check-predicate (mutable-pair? (list-copy (list 1)))) +($check-predicate (mutable-pair? (list-copy (copy-es-immutable (list 1))))) +($check equal? (list-copy (list 1 2 3)) (list 1 2 3)) +($check equal? (list-copy (list . #1=(1 2 . #1#))) (list . #2=(1 2 . #2#))) + +;; reverse +($check-predicate (null? (reverse ()))) +($check-predicate (mutable-pair? (reverse (list 1)))) +($check-predicate (mutable-pair? (reverse (copy-es-immutable (list 1))))) +($check equal? (reverse (list 1)) (list 1)) +($check equal? (reverse (list 1 2 3)) (list 3 2 1)) + ;; get-list-metrics ($check equal? (get-list-metrics ()) (list 0 1 0 0)) ($check equal? (get-list-metrics #inert) (list 0 0 0 0)) @@ -152,7 +172,7 @@ ;; list-ref ($check =? (list-ref (list 1 2 3 4 5) 0) 1) ($check =? (list-ref (list 1 2 3 4 5) 1) 2) -;; see ground/pairs-and-lists.scm for rationale on allowing +;; see kgpairs_lists.c for rationale on allowing ;; improper lists as argument to list-ref ($check =? (list-ref (list* 1 2 3 4) 2) 3) ($check =? (list-ref (list . #0=(1 2 3 4 5 . #0#)) 10) 1) @@ -353,6 +373,27 @@ ($check-error (cadddr tree8)) ($check-error (cddddr tree8))) +;; make-list +($check-error (make-list)) +($check-error (make-list "str")) +($check-error (make-list 1 "str" "str2")) +($check-error (make-list -2)) +($check-error (make-list 3/4)) +($check-error (make-list #e+infinity)) + +;; list-copy +($check-error (list-copy)) +($check-error (list-copy () ())) +($check-error (list-copy #inert)) +($check-error (list-copy (list* 1 2 3))) + +;; reverse +($check-error (reverse)) +($check-error (reverse () ())) +($check-error (reverse #inert)) +($check-error (reverse (list* 1 2 3))) +($check-error (reverse (list 1 . #1=(2 . #1#)))) + ;; get-list-metrics ($check-error (get-list-metrics)) ($check-error (get-list-metrics () ())) diff --git a/src/tests/strings.k b/src/tests/strings.k @@ -4,7 +4,9 @@ ;; ;; XXX immutability of string constants - +;; this works because this file is loaded and the strings +;; are immutable, but just reading the file wouldn't make them +;; immutable ($check-predicate (immutable-string? "")) ($check-predicate (immutable-string? "abcd")) @@ -84,6 +86,24 @@ ($check equal? (string #\a #\b #\c) "abc") ($check-not-predicate ($let ((x (string #\a)) (y (string #\a))) (eq? x y))) +;; XXX string-upcase string-downcase string-titlecase string-foldcase +($check equal? (string-upcase "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrstuvwxyz") + "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ") +($check equal? (string-titlecase "this is a regular sentence. this 1 2!") + "This Is A Regular Sentence. This 1 2!") +($check equal? (string-downcase "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrstuvwxyz") + "abcdefghijklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz") +($check equal? (string-foldcase "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrstuvwxyz") + "abcdefghijklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz") +($check-predicate (mutable-string? (string-upcase (string-copy "A0a")))) +($check-predicate (mutable-string? (string-upcase "A0a"))) +($check-predicate (mutable-string? (string-downcase (string-copy "A0a")))) +($check-predicate (mutable-string? (string-downcase "A0a"))) +($check-predicate (mutable-string? (string-titlecase (string-copy "A0a")))) +($check-predicate (mutable-string? (string-titlecase "A0a"))) +($check-predicate (mutable-string? (string-foldcase (string-copy "A0a")))) +($check-predicate (mutable-string? (string-foldcase "A0a"))) + ;; XXX string-length ($check equal? (string-length "") 0) diff --git a/src/tests/vectors.k b/src/tests/vectors.k @@ -95,6 +95,13 @@ (mutable-vector? (vector-copy (vector->immutable-vector (vector 1 2 3))))) +;; XXX vector-fill! +($check-predicate (inert? (vector-fill! (vector 1 2) 0))) +($check equal? ($let ((v (vector 1 2 3))) + (vector-fill! v "str") + v) + (vector "str" "str" "str")) + ;; XXX vector->immutable-vector ($check-predicate (applicative? vector->immutable-vector))