klisp

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

commit 5a4381b470855c2038bea8c8f6de1f0b687671b3
parent 513920b834538a72776b9ce6932d9f74567a39d6
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Wed, 23 Nov 2011 05:27:44 -0300

Merged last batch of changes from r7rs/refactor

Diffstat:
Mmanual/html/Alphabetical-Index.html | 22+++++++++++++---------
Mmanual/html/Ports.html | 265++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mmanual/klisp.info | 255++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mmanual/src/ports.texi | 227++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/Makefile | 115+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/examples/ffi-gsl.k | 6+++---
Msrc/examples/ffi-sdl.k | 10+++++-----
Msrc/examples/ffi-signal.c | 2+-
Msrc/examples/ffi-signal.k | 6+++---
Msrc/examples/ffi.k | 28++++++++++++++--------------
Dsrc/kblob.c | 66------------------------------------------------------------------
Dsrc/kblob.h | 34----------------------------------
Asrc/kbytevector.c | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/kbytevector.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kcontinuation.c | 2+-
Msrc/kcontinuation.h | 2+-
Msrc/kenvironment.c | 2+-
Msrc/kerror.c | 30+++++++++++++++++++++---------
Msrc/kerror.h | 20+++++++++++++++++++-
Msrc/keval.c | 25+++++++++++++++++++------
Msrc/keval.h | 6+++---
Dsrc/kgblobs.c | 250-------------------------------------------------------------------------------
Dsrc/kgblobs.h | 48------------------------------------------------
Msrc/kgbooleans.c | 29++++++++++++++++++++++++-----
Msrc/kgbooleans.h | 10+++++-----
Asrc/kgbytevectors.c | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/kgbytevectors.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kgc.c | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/kgchars.c | 28++++++++++++++++++++--------
Msrc/kgchars.h | 12++++--------
Msrc/kgcombiners.c | 82++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/kgcombiners.h | 23+++++++++++------------
Msrc/kgcontinuations.c | 74+++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/kgcontinuations.h | 28++++++++++------------------
Msrc/kgcontrol.c | 51+++++++++++++++++++++++++++++++++++++++++----------
Msrc/kgcontrol.h | 16++++++++--------
Msrc/kgencapsulations.c | 25++++++++++++++++++++-----
Msrc/kgencapsulations.h | 5++---
Msrc/kgenv_mut.c | 39++++++++++++++++++++++++++++++++-------
Msrc/kgenv_mut.h | 14+++++++-------
Msrc/kgenvironments.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/kgenvironments.h | 41++++++++++++++++++-----------------------
Msrc/kgeqp.c | 6+++++-
Msrc/kgeqp.h | 8++++----
Msrc/kgequalp.c | 15+++++++++++----
Msrc/kgequalp.h | 2+-
Msrc/kgerror.c | 46+++++++++++++++++++++++++++++-----------------
Msrc/kgffi.c | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/kgffi.h | 3+--
Msrc/kghelpers.c | 37++++++++++++++++++++++++++++++-------
Msrc/kghelpers.h | 61++++++++++++++++++++++++++++++-------------------------------
Msrc/kgkd_vars.c | 33++++++++++++++++++++++++---------
Msrc/kgkd_vars.h | 11++++-------
Msrc/kgks_vars.c | 21+++++++++++++++------
Msrc/kgks_vars.h | 3+--
Msrc/kgnumbers.c | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/kgnumbers.h | 72+++++++++++++++++++++++++++++++-----------------------------------------
Msrc/kgpair_mut.c | 56++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/kgpair_mut.h | 19++++++++++---------
Msrc/kgpairs_lists.c | 151+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/kgpairs_lists.h | 57+++++++++++++++++++++++++++------------------------------
Msrc/kgports.c | 611+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/kgports.h | 61++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/kgpromises.c | 23+++++++++++++++++++----
Msrc/kgpromises.h | 8++++----
Msrc/kground.c | 10++++++----
Msrc/kgstrings.c | 97++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/kgstrings.h | 32+++++++++++++++-----------------
Msrc/kgsymbols.c | 14++++++++++----
Msrc/kgsymbols.h | 6++----
Msrc/kgsystem.c | 33+++++++++++++++++++++++++++------
Msrc/kgsystem.h | 6++----
Asrc/kgvectors.c | 245+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/kgvectors.h | 15+++++++++++++++
Msrc/klimits.h | 10++++++++++
Msrc/klisp.c | 578+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/klisp.h | 6++++++
Msrc/klispconf.h | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kobject.c | 22+++++++++-------------
Msrc/kobject.h | 102++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/koperative.c | 2+-
Msrc/koperative.h | 3++-
Msrc/kpair.c | 8++++++++
Msrc/kpair.h | 7++-----
Msrc/kport.c | 169++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/kport.h | 36+++++++++++++++++++++++++++++-------
Msrc/kread.c | 269++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/kread.h | 2++
Msrc/krepl.c | 160++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/krepl.h | 10+++++-----
Msrc/kscript.c | 14++++++++++----
Msrc/kscript.h | 4++--
Msrc/kstate.c | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/kstate.h | 47++++++++++++++++++++++++++++-------------------
Msrc/kstring.c | 24++++++++++++++++++------
Msrc/kstring.h | 23++---------------------
Msrc/ksymbol.c | 7+++++--
Msrc/ktoken.c | 253++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/ktoken.h | 8+++++---
Asrc/kvector.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/kvector.h | 34++++++++++++++++++++++++++++++++++
Msrc/kwrite.c | 206++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/kwrite.h | 2++
Asrc/rep_op_c.sed | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/rep_op_h.sed | 32++++++++++++++++++++++++++++++++
Asrc/tests/bytevectors.k | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/tests/environments.k | 397++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Asrc/tests/memory-ports.k | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/tests/ports.k | 2++
Msrc/tests/strings.k | 6++++--
Msrc/tests/test-all.k | 7+++++--
Msrc/tests/test-helpers.k | 6++++++
Asrc/tests/vectors.k | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
113 files changed, 6263 insertions(+), 1858 deletions(-)

diff --git a/manual/html/Alphabetical-Index.html b/manual/html/Alphabetical-Index.html @@ -55,7 +55,7 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Control.html#index-g_t_0024sequence-30"><code>$sequence</code></a>: <a href="Control.html#Control">Control</a></li> <li><a href="Environments.html#index-g_t_0024set_0021-111"><code>$set!</code></a>: <a href="Environments.html#Environments">Environments</a></li> <li><a href="Combiners.html#index-g_t_0024vau-119"><code>$vau</code></a>: <a href="Combiners.html#Combiners">Combiners</a></li> -<li><a href="Ports.html#index-g_t_0028-261"><code>(</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-g_t_0028-263"><code>(</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Numbers.html#index-g_t_0028-179"><code>(</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Continuations.html#index-g_t_0028-135"><code>(</code></a>: <a href="Continuations.html#Continuations">Continuations</a></li> <li><a href="Environments.html#index-g_t_0028-110"><code>(</code></a>: <a href="Environments.html#Environments">Environments</a></li> @@ -81,6 +81,7 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Pairs-and-lists.html#index-assoc-84"><code>assoc</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Pairs-and-lists.html#index-assq-91"><code>assq</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Numbers.html#index-atan-209"><code>atan</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> +<li><a href="Ports.html#index-binary_002dport_003f-262"><code>binary-port?</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Booleans.html#index-boolean_003f-13"><code>boolean?</code></a>: <a href="Booleans.html#Booleans">Booleans</a></li> <li><a href="Booleans.html#index-booleans-12">booleans</a>: <a href="Booleans.html#Booleans">Booleans</a></li> <li><a href="Pairs-and-lists.html#index-caaaar-59"><code>caaaar</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> @@ -97,8 +98,8 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Pairs-and-lists.html#index-cadddr-66"><code>cadddr</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Pairs-and-lists.html#index-caddr-54"><code>caddr</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Pairs-and-lists.html#index-cadr-48"><code>cadr</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> -<li><a href="Ports.html#index-call_002dwith_002dinput_002dfile-271"><code>call-with-input-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> -<li><a href="Ports.html#index-call_002dwith_002doutput_002dfile-272"><code>call-with-output-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-call_002dwith_002dinput_002dfile-280"><code>call-with-input-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-call_002dwith_002doutput_002dfile-281"><code>call-with-output-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Continuations.html#index-call_002fcc-128"><code>call/cc</code></a>: <a href="Continuations.html#Continuations">Continuations</a></li> <li><a href="Pairs-and-lists.html#index-car-45"><code>car</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Pairs-and-lists.html#index-cdaaar-67"><code>cdaaar</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> @@ -160,7 +161,7 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Pairs-and-lists.html#index-encycle_0021-77"><code>encycle!</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Environments.html#index-environment_003f-95"><code>environment?</code></a>: <a href="Environments.html#Environments">Environments</a></li> <li><a href="Environments.html#index-environments-93">environments</a>: <a href="Environments.html#Environments">Environments</a></li> -<li><a href="Ports.html#index-eof_002dobject_003f-275"><code>eof-object?</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-eof_002dobject_003f-284"><code>eof-object?</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Equivalence.html#index-eq_003f-20"><code>eq?</code></a>: <a href="Equivalence.html#Equivalence">Equivalence</a></li> <li><a href="Equivalence.html#index-equal_003f-21"><code>equal?</code></a>: <a href="Equivalence.html#Equivalence">Equivalence</a></li> <li><a href="Equivalence.html#index-equivalence-19">equivalence</a>: <a href="Equivalence.html#Equivalence">Equivalence</a></li> @@ -185,7 +186,7 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Numbers.html#index-gcd-183"><code>gcd</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Environments.html#index-get_002dcurrent_002denvironment-102"><code>get-current-environment</code></a>: <a href="Environments.html#Environments">Environments</a></li> <li><a href="Pairs-and-lists.html#index-get_002dlist_002dmetrics-75"><code>get-list-metrics</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> -<li><a href="Ports.html#index-get_002dmodule-274"><code>get-module</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-get_002dmodule-283"><code>get-module</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Numbers.html#index-get_002dreal_002dexact_002dbounds-185"><code>get-real-exact-bounds</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Numbers.html#index-get_002dreal_002dexact_002dprimary-187"><code>get-real-exact-primary</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Numbers.html#index-get_002dreal_002dinternal_002dbounds-184"><code>get-real-internal-bounds</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> @@ -214,7 +215,7 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Pairs-and-lists.html#index-list_002dref-80"><code>list-ref</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Pairs-and-lists.html#index-list_002dtail-76"><code>list-tail</code></a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> <li><a href="Pairs-and-lists.html#index-lists-36">lists</a>: <a href="Pairs-and-lists.html#Pairs-and-lists">Pairs and lists</a></li> -<li><a href="Ports.html#index-load-273"><code>load</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-load-282"><code>load</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Numbers.html#index-log-203"><code>log</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Encapsulations.html#index-make_002dencapsulation_002dtype-139"><code>make-encapsulation-type</code></a>: <a href="Encapsulations.html#Encapsulations">Encapsulations</a></li> <li><a href="Environments.html#index-make_002denvironment-98"><code>make-environment</code></a>: <a href="Environments.html#Environments">Environments</a></li> @@ -241,8 +242,10 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Numbers.html#index-numerator-194"><code>numerator</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="A-Sample-Applicative-Description.html#index-object-descriptions-10">object descriptions</a>: <a href="A-Sample-Applicative-Description.html#A-Sample-Applicative-Description">A Sample Applicative Description</a></li> <li><a href="Numbers.html#index-odd_003f-177"><code>odd?</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> -<li><a href="Ports.html#index-open_002dinput_002dfile-265"><code>open-input-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> -<li><a href="Ports.html#index-open_002doutput_002dfile-266"><code>open-output-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-open_002dbinary_002dinput_002dfile-270"><code>open-binary-input-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-open_002dbinary_002doutput_002dfile-272"><code>open-binary-output-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-open_002dinput_002dfile-269"><code>open-input-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-open_002doutput_002dfile-271"><code>open-output-file</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="A-Sample-Applicative-Description.html#index-operative-descriptions-9">operative descriptions</a>: <a href="A-Sample-Applicative-Description.html#A-Sample-Applicative-Description">A Sample Applicative Description</a></li> <li><a href="Combiners.html#index-operative_003f-117"><code>operative?</code></a>: <a href="Combiners.html#Combiners">Combiners</a></li> <li><a href="Combiners.html#index-operatives-116">operatives</a>: <a href="Combiners.html#Combiners">Combiners</a></li> @@ -258,7 +261,7 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Promises.html#index-promises-140">promises</a>: <a href="Promises.html#Promises">Promises</a></li> <li><a href="Numbers.html#index-rational_003f-153"><code>rational?</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Numbers.html#index-rationalize-200"><code>rationalize</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> -<li><a href="Ports.html#index-read-269"><code>read</code></a>: <a href="Ports.html#Ports">Ports</a></li> +<li><a href="Ports.html#index-read-278"><code>read</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Numbers.html#index-real_002d_003eexact-190"><code>real-&gt;exact</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Numbers.html#index-real_002d_003einexact-189"><code>real-&gt;inexact</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Numbers.html#index-real_003f-154"><code>real?</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> @@ -298,6 +301,7 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <li><a href="Symbols.html#index-symbol_003f-23"><code>symbol?</code></a>: <a href="Symbols.html#Symbols">Symbols</a></li> <li><a href="Symbols.html#index-symbols-22">symbols</a>: <a href="Symbols.html#Symbols">Symbols</a></li> <li><a href="Numbers.html#index-tan-206"><code>tan</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> +<li><a href="Ports.html#index-textual_002dport_003f-261"><code>textual-port?</code></a>: <a href="Ports.html#Ports">Ports</a></li> <li><a href="Numbers.html#index-truncate-198"><code>truncate</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Numbers.html#index-undefined_003f-159"><code>undefined?</code></a>: <a href="Numbers.html#Numbers">Numbers</a></li> <li><a href="Combiners.html#index-unwrap-121"><code>unwrap</code></a>: <a href="Combiners.html#Combiners">Combiners</a></li> diff --git a/manual/html/Ports.html b/manual/html/Ports.html @@ -35,9 +35,14 @@ Up:&nbsp;<a rel="up" accesskey="u" href="index.html#Top">Top</a> <h2 class="chapter">16 Ports</h2> <p><a name="index-ports-257"></a> - A port is an object that mediates character-based input from a -source or character-based output to a destination. In the former case, -the port is an input port, in the latter case, an output port. + 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. + + <p>There are three textual ports open, binded by dynamic variables, one +for standard input, output, and error. <!-- TODO add xref to equal? & eq? --> <p>Although ports are not considered immutable, none of the operations @@ -45,7 +50,7 @@ on ports described in this section constitute mutation. Ports are <code>equal?</code> iff <code>eq?</code>. The port type is encapsulated. <p>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 +<code>eof</code>. 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. @@ -63,77 +68,96 @@ returns true iff all the objects in <code>objects</code> are of type port. &mdash; Applicative: <b>output-port?</b> (<var>output-port? . objects</var>)<var><a name="index-output_002dport_003f-260"></a></var><br> <blockquote><p> Applicative <code>input-port?</code> 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. +<code>output-port?</code> is a predicate that returns true unless one or +more of its arguments is not an output port. <p>Every port must be admitted by at least one of these two predicates. </p></blockquote></div> <div class="defun"> -&mdash; with-input-from-file: <b>(</b><var>with-input-from-file string combiner</var>)<var><a name="index-g_t_0028-261"></a></var><br> -&mdash; with-output-to-file: <b>(</b><var>with-output-to-file string combiner</var>)<var><a name="index-g_t_0028-262"></a></var><br> -<blockquote><!-- add xref get-current-input-port/get-current-output-port --> - <p>These two applicatives open the file named in <code>string</code> for -input or output, an invoke the binder of the input-port &amp; output-port -keyed dynamic variables respectively with the opened port &amp; the passed -<code>combiner</code> (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 <code>with-input-from-file</code> and -<code>with-output-from-file</code> is inert. +&mdash; Applicative: <b>textual-port?</b> (<var>textual-port? . objects</var>)<var><a name="index-textual_002dport_003f-261"></a></var><br> +&mdash; Applicative: <b>binary-port?</b> (<var>binary-port? . objects</var>)<var><a name="index-binary_002dport_003f-262"></a></var><br> +<blockquote><p> Applicative <code>textual-port?</code> is a predicate that returns true +unless one or more of its arguments is not a textual port. Applicative +<code>binary-port?</code> is a predicate that returns true unless one or more of +its arguments is not a binary port. - <p>SOURCE NOTE: this is enumerated in the Kernel report but the text is -still missing. In the new scheme report there's also a third -error-port variable. It is very likely that that will be added to the -klisp implementation in the near future. + <p>Every port must be admitted by at least one of these two predicates. + + <p>SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +</p></blockquote></div> + +<div class="defun"> +&mdash; with-input-from-file: <b>(</b><var>with-input-from-file string combiner</var>)<var><a name="index-g_t_0028-263"></a></var><br> +&mdash; with-output-to-file: <b>(</b><var>with-output-to-file string combiner</var>)<var><a name="index-g_t_0028-264"></a></var><br> +&mdash; with-error-to-file: <b>(</b><var>with-error-to-file string combiner</var>)<var><a name="index-g_t_0028-265"></a></var><br> +<blockquote><!-- add xref get-current-input-port/get-current-output-port --> + <p>These three applicatives open the file named in <code>string</code> 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 &amp; the passed <code>combiner</code> (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 <code>with-input-from-file</code> +and <code>with-output-from-file</code> is inert. + + <p>SOURCE NOTE: The first two are enumerated in the Kernel report but +the text is still missing. The third applicative is from Scheme. </p></blockquote></div> <div class="defun"> -&mdash; get-current-input-port: <b>(</b><var>get-current-input-port</var>)<var><a name="index-g_t_0028-263"></a></var><br> -&mdash; get-current-output-port: <b>(</b><var>get-current-output-port</var>)<var><a name="index-g_t_0028-264"></a></var><br> -<blockquote><p> These are the accessors for the input-port and output-port keyed -dynamic variables repectively. +&mdash; get-current-input-port: <b>(</b><var>get-current-input-port</var>)<var><a name="index-g_t_0028-266"></a></var><br> +&mdash; get-current-output-port: <b>(</b><var>get-current-output-port</var>)<var><a name="index-g_t_0028-267"></a></var><br> +&mdash; get-current-error-port: <b>(</b><var>get-current-error-port</var>)<var><a name="index-g_t_0028-268"></a></var><br> +<blockquote><p> These are the accessors for the input-port, output-port, and +error-port keyed dynamic variables repectively. <!-- add xref to with-input-from-file, etc --> <!-- add xref and text for these dynamic vars --> - <p>SOURCE NOTE: this is enumerated in the Kernel report but the text is -still missing. In the new scheme report there's also a third -error-port variable. It is very likely that that will be added to the -klisp implementation in the near future. + <p>SOURCE NOTE: The first two are enumerated in the Kernel report but +the text is still missing. The third applicative is from Scheme. </p></blockquote></div> <div class="defun"> -&mdash; Applicative: <b>open-input-file</b> (<var>open-input-file string</var>)<var><a name="index-open_002dinput_002dfile-265"></a></var><br> +&mdash; Applicative: <b>open-input-file</b> (<var>open-input-file string</var>)<var><a name="index-open_002dinput_002dfile-269"></a></var><br> +&mdash; Applicative: <b>open-binary-input-file</b> (<var>open-binary-input-file string</var>)<var><a name="index-open_002dbinary_002dinput_002dfile-270"></a></var><br> <blockquote><p> <code>string</code> should be the name/path for an existing file. - <p>Applicative <code>open-input-file</code> creates and returns an input port -associated with the file represented with <code>string</code>. If the file -can't be opened (e.g. because it doesn't exists, or there's a -permissions problem), an error is signaled. + <p>Applicative <code>open-input-file</code> creates and returns a textual +input port associated with the file represented with <code>string</code>. +Applicative <code>open-binary-input-file</code> creates and returns a binary +input port associated with the file represented with <code>string</code>. +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. - <p>SOURCE NOTE: this is enumerated in the Kernel report but the text is -still missing. + <p>SOURCE NOTE: open-input-file is enumerated in the Kernel report but +the text is still missing. open-binary-input-file is from Scheme. </p></blockquote></div> <div class="defun"> -&mdash; Applicative: <b>open-output-file</b> (<var>open-output-file string</var>)<var><a name="index-open_002doutput_002dfile-266"></a></var><br> +&mdash; Applicative: <b>open-output-file</b> (<var>open-output-file string</var>)<var><a name="index-open_002doutput_002dfile-271"></a></var><br> +&mdash; Applicative: <b>open-binary-output-file</b> (<var>open-binary-output-file string</var>)<var><a name="index-open_002dbinary_002doutput_002dfile-272"></a></var><br> <blockquote><p> <code>string</code> should be the name/path for an existing file. - <p>Applicative <code>open-output-file</code> creates and returns an output -port associated with the file represented with <code>string</code>. If the -file can't be opened (e.g. if there's a permissions problem), an error -is signaled. + <p>Applicative <code>open-output-file</code> creates and returns a textual +output port associated with the file represented with <code>string</code>. +Applicative <code>open-binary-output-file</code> creates and returns a +binary output port associated with the file represented with +<code>string</code>. In either case, if the file can't be opened (e.g. if +there's a permissions problem), an error is signaled. - <p>In klisp, for now, applicative <code>open-output-file</code> truncates the -file if it already exists, but that could change later (i.e. like in -scheme the behaviour should be considered unspecified). + <p>In klisp, for now, applicative <code>open-output-file</code> and +<code>open-binary-output-file</code> truncate the file if it already exists, +but that could change later (i.e. like in Scheme the behaviour should +be considered unspecified). - <p>SOURCE NOTE: this is enumerated in the Kernel report but the text is -still missing. + <p>SOURCE NOTE: open-output-file is enumerated in the Kernel report but +the text is still missing. open-binary-output-file is from Scheme. </p></blockquote></div> <div class="defun"> -&mdash; close-input-file: <b>(</b><var>close-input-file input-port</var>)<var><a name="index-g_t_0028-267"></a></var><br> -&mdash; close-output-file: <b>(</b><var>close-output-file output-port</var>)<var><a name="index-g_t_0028-268"></a></var><br> +&mdash; close-input-file: <b>(</b><var>close-input-file input-port</var>)<var><a name="index-g_t_0028-273"></a></var><br> +&mdash; close-output-file: <b>(</b><var>close-output-file output-port</var>)<var><a name="index-g_t_0028-274"></a></var><br> <blockquote><p> 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 @@ -148,13 +172,31 @@ probably be called close-input-port &amp; close-output-port. </p></blockquote></div> <div class="defun"> -&mdash; Applicative: <b>read</b> (<var>read </var>[<var>input-port</var>])<var><a name="index-read-269"></a></var><br> +&mdash; close-input-port: <b>(</b><var>close-input-port input-port</var>)<var><a name="index-g_t_0028-275"></a></var><br> +&mdash; close-output-port: <b>(</b><var>close-output-port output-port</var>)<var><a name="index-g_t_0028-276"></a></var><br> +&mdash; close-port: <b>(</b><var>close-port port</var>)<var><a name="index-g_t_0028-277"></a></var><br> +<blockquote><p> 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. + + <p>The result returned by applicatives <code>close-input-port</code>, +<code>close-output-port</code>, and <code>close-port</code> is inert. + + <p>SOURCE NOTE: this is from Scheme. The equivalent +<code>close-input-file</code> and <code>close-output-file</code> are probably name +errors and only retained here till the draft standard rectifies them +</p></blockquote></div> + +<div class="defun"> +&mdash; Applicative: <b>read</b> (<var>read </var>[<var>textual-input-port</var>])<var><a name="index-read-278"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>input-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. <p>Applicative <code>read</code> reads &amp; returns the next parseable object -from the given port, or the eof object if no objects remain. If +from the given port, or the <code>eof</code> if no objects remain. If <code>read</code> finds and unparseable object in the port, an error is signaled. In that case, the remaining position in the port is unspecified. @@ -164,7 +206,7 @@ still missing. </p></blockquote></div> <div class="defun"> -&mdash; write: <b>(</b><var>write object </var>[<var>port</var>])<var><a name="index-g_t_0028-270"></a></var><br> +&mdash; write: <b>(</b><var>write object </var>[<var>textual-output-port</var>])<var><a name="index-g_t_0028-279"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>output-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -182,25 +224,25 @@ still missing. </p></blockquote></div> <div class="defun"> -&mdash; Applicative: <b>call-with-input-file</b> (<var>call-with-input-file string combiner</var>)<var><a name="index-call_002dwith_002dinput_002dfile-271"></a></var><br> -&mdash; Applicative: <b>call-with-output-file</b> (<var>call-with-output-file string combiner</var>)<var><a name="index-call_002dwith_002doutput_002dfile-272"></a></var><br> -<blockquote><p> These applicatives open file named in <code>string</code> and call their -<code>combiner</code> 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. +&mdash; Applicative: <b>call-with-input-file</b> (<var>call-with-input-file string combiner</var>)<var><a name="index-call_002dwith_002dinput_002dfile-280"></a></var><br> +&mdash; Applicative: <b>call-with-output-file</b> (<var>call-with-output-file string combiner</var>)<var><a name="index-call_002dwith_002doutput_002dfile-281"></a></var><br> +<blockquote><p> These applicatives open file named in <code>string</code> for textual +input/output respectively and call their <code>combiner</code> 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. <p>SOURCE NOTE: this is enumerated in the Kernel report but the text is still missing. </p></blockquote></div> <div class="defun"> -&mdash; Applicative: <b>load</b> (<var>load string</var>)<var><a name="index-load-273"></a></var><br> +&mdash; Applicative: <b>load</b> (<var>load string</var>)<var><a name="index-load-282"></a></var><br> <blockquote><!-- TODO add xref, open/input, read --> - <p>Applicative <code>load</code> opens for input a file named <code>string</code>; -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 <code>load</code> is inert. + <p>Applicative <code>load</code> opens the file named <code>string</code> 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 <code>load</code> is inert. <p>SOURCE NOTE: load is enumerated in the Kernel report, but the description is not there yet. This seems like a sane way to define @@ -211,51 +253,51 @@ return the value of the last evaluation. </p></blockquote></div> <div class="defun"> -&mdash; Applicative: <b>get-module</b> (<var>get-module string </var>[<var>environment</var>])<var><a name="index-get_002dmodule-274"></a></var><br> +&mdash; Applicative: <b>get-module</b> (<var>get-module string </var>[<var>environment</var>])<var><a name="index-get_002dmodule-283"></a></var><br> <blockquote><!-- TODO add xref standard-environment, open/input, read --> <p>Applicative <code>get-module</code> creates a fresh standard environment; -opens for input a file named <code>string</code>; 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 <code>environment</code> is -specified, the freshly created standard environment is augmented, +opens the file named <code>string</code> 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 <code>environment</code> +is specified, the freshly created standard environment is augmented, prior to evaluating read expressions, by binding symbol <code>module-parameters</code> to the <code>environment</code> argument. </p></blockquote></div> <div class="defun"> -&mdash; Applicative: <b>eof-object?</b> (<var>eof-object? . objects</var>)<var><a name="index-eof_002dobject_003f-275"></a></var><br> +&mdash; Applicative: <b>eof-object?</b> (<var>eof-object? . objects</var>)<var><a name="index-eof_002dobject_003f-284"></a></var><br> <blockquote><p> The primitive type predicate for type eof. <code>eof-object?</code> returns true iff all the objects in <code>objects</code> are of type eof. <p>SOURCE NOTE: This is not in the report, the idea is from Scheme. -The <code>eof-object?</code> name is also from scheme, but this will +The <code>eof-object?</code> name is also from Scheme, but this will probably be changed to just <code>eof?</code>, for consistency with the other primitive type predicates. </p></blockquote></div> <div class="defun"> -&mdash; read-char: <b>(</b><var>read-char </var>[<var>port</var>])<var><a name="index-g_t_0028-276"></a></var><br> +&mdash; read-char: <b>(</b><var>read-char </var>[<var>textual-input-port</var>])<var><a name="index-g_t_0028-285"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>input-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. <p>Applicative <code>read-char</code> 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. +an <code>eof</code> if the end of file was reached. <p>SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. </p></blockquote></div> <div class="defun"> -&mdash; peek-char: <b>(</b><var>peek-char </var>[<var>port</var>])<var><a name="index-g_t_0028-277"></a></var><br> +&mdash; peek-char: <b>(</b><var>peek-char </var>[<var>textual-input-port</var>])<var><a name="index-g_t_0028-286"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>input-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. <p>Applicative <code>peek-char</code> 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 +an <code>eof</code> if the end of file was reached. The position of the port remains unchanged so that new call to <code>peek-char</code> or <code>read-char</code> on the same port return the same character. @@ -263,7 +305,7 @@ remains unchanged so that new call to <code>peek-char</code> or </p></blockquote></div> <div class="defun"> -&mdash; char-ready?: <b>(</b><var>char-ready? </var>[<var>port</var>])<var><a name="index-g_t_0028-278"></a></var><br> +&mdash; char-ready?: <b>(</b><var>char-ready? </var>[<var>textual-input-port</var>])<var><a name="index-g_t_0028-287"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>input-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -278,7 +320,7 @@ the code to do this is non-portable. </p></blockquote></div> <div class="defun"> -&mdash; write-char: <b>(</b><var>write-char char </var>[<var>port</var>])<var><a name="index-g_t_0028-279"></a></var><br> +&mdash; write-char: <b>(</b><var>write-char char </var>[<var>textual-output-port</var>])<var><a name="index-g_t_0028-288"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>output-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -291,7 +333,7 @@ The result returned by <code>write-char</code> is inert. </p></blockquote></div> <div class="defun"> -&mdash; newline: <b>(</b><var>newline </var>[<var>port</var>])<var><a name="index-g_t_0028-280"></a></var><br> +&mdash; newline: <b>(</b><var>newline </var>[<var>textal-ouput-port</var>])<var><a name="index-g_t_0028-289"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>output-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -303,7 +345,7 @@ The result returned by <code>newline</code> is inert. </p></blockquote></div> <div class="defun"> -&mdash; display: <b>(</b><var>display object </var>[<var>port</var>])<var><a name="index-g_t_0028-281"></a></var><br> +&mdash; display: <b>(</b><var>display object </var>[<var>textual-output-port</var>])<var><a name="index-g_t_0028-290"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>output-port</code> keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -318,7 +360,66 @@ within those strings and character objects are output as if by </p></blockquote></div> <div class="defun"> -&mdash; flush-output-port: <b>(</b><var>flush-output-port </var>[<var>port</var>])<var><a name="index-g_t_0028-282"></a></var><br> +&mdash; read-u8: <b>(</b><var>read-u8 </var>[<var>textual-input-port</var>])<var><a name="index-g_t_0028-291"></a></var><br> +<blockquote><p> If the <code>port</code> optional argument is not specified, then the +value of the <code>input-port</code> keyed dynamic variable is used. If the +port is closed, an error is signaled. + + <p>Applicative <code>read-u8</code> 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 <code>eof</code> if +the end of file was reached. + + <p>SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +</p></blockquote></div> + +<div class="defun"> +&mdash; peek-u8: <b>(</b><var>peek-u8 </var>[<var>textual-input-port</var>])<var><a name="index-g_t_0028-292"></a></var><br> +<blockquote><p> If the <code>port</code> optional argument is not specified, then the +value of the <code>input-port</code> keyed dynamic variable is used. If the +port is closed, an error is signaled. + + <p>Applicative <code>peek-u8</code> 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 <code>eof</code> if +the end of file was reached. The position of the port remains +unchanged so that new call to <code>peek-u8</code> or <code>read-u8</code> on the +same port return the same byte. + + <p>SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +</p></blockquote></div> + +<div class="defun"> +&mdash; u8-ready?: <b>(</b><var>u8-ready? </var>[<var>textual-input-port</var>])<var><a name="index-g_t_0028-293"></a></var><br> +<blockquote><p> If the <code>port</code> optional argument is not specified, then the +value of the <code>input-port</code> keyed dynamic variable is used. If the +port is closed, an error is signaled. + + <p>Predicate <code>u8-ready?</code> checks to see if a byte is +available in the specified port. If it returns true, then a +<code>read-u8</code> or <code>peek-u8</code> on that port is guaranteed not to +block/hang. For now in klisp this is hardcoded to <code>#t</code> because +the code to do this is non-portable. + + <p>SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +</p></blockquote></div> + +<div class="defun"> +&mdash; write-u8: <b>(</b><var>write-u8 u8 </var>[<var>textual-output-port</var>])<var><a name="index-g_t_0028-294"></a></var><br> +<blockquote><p> If the <code>port</code> optional argument is not specified, then the +value of the <code>output-port</code> keyed dynamic variable is used. If the +port is closed, an error is signaled. + + <p>Applicative <code>write-u8</code> writes the byte represented by the +unsigned integer <code>u8</code>, that should be between 0 and 255 inclusive, +(not an external representation of byte) to the specified port. The +result returned by <code>write-u8</code> is inert. + + <p>SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +</p></blockquote></div> + +<div class="defun"> +&mdash; flush-output-port: <b>(</b><var>flush-output-port </var>[<var>output-port</var>])<var><a name="index-g_t_0028-295"></a></var><br> <blockquote><p> If the <code>port</code> optional argument is not specified, then the value of the <code>output-port</code> keyed dynamic variable is used. If the <code>port</code> is closed or if it is not an output port, an error is @@ -332,7 +433,7 @@ output port to the underlying file or device. The result returned by </p></blockquote></div> <div class="defun"> -&mdash; file-exists?: <b>(</b><var>file-exists? string</var>)<var><a name="index-g_t_0028-283"></a></var><br> +&mdash; file-exists?: <b>(</b><var>file-exists? string</var>)<var><a name="index-g_t_0028-296"></a></var><br> <blockquote><p> <code>string</code> should be the name/path for a file. <p>Predicate <code>file-exists?</code> checks to see if a file named @@ -342,7 +443,7 @@ output port to the underlying file or device. The result returned by </p></blockquote></div> <div class="defun"> -&mdash; delete-file: <b>(</b><var>delete-file string</var>)<var><a name="index-g_t_0028-284"></a></var><br> +&mdash; delete-file: <b>(</b><var>delete-file string</var>)<var><a name="index-g_t_0028-297"></a></var><br> <blockquote><p> <code>string</code> should be the name/path for an existing file. <p>Applicative <code>delete-file</code> deletes the file named <code>string</code>. @@ -353,7 +454,7 @@ result returned by <code>delete-file</code> is inert. </p></blockquote></div> <div class="defun"> -&mdash; rename-file: <b>(</b><var>rename-file string1 string2</var>)<var><a name="index-g_t_0028-285"></a></var><br> +&mdash; rename-file: <b>(</b><var>rename-file string1 string2</var>)<var><a name="index-g_t_0028-298"></a></var><br> <blockquote><p> <code>string1</code> should be the name/path for an existing file, <code>string2</code> should be the name/path for a non existing file. diff --git a/manual/klisp.info b/manual/klisp.info @@ -2135,16 +2135,21 @@ File: klisp.info, Node: Ports, Next: Alphabetical Index, Prev: Characters, U 16 Ports ******** -A port is an object that mediates character-based input from a source -or character-based output to a destination. In the former case, the -port is an input port, in the latter case, an output port. +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 +`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. @@ -2159,62 +2164,82 @@ klisp and was taken from Scheme. -- 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. + `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) - These two applicatives open the file named in `string' for input - or output, an invoke the binder of the input-port & output-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-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: this is enumerated in the Kernel report but the text - is still missing. In the new scheme report there's also a third - error-port variable. It is very likely that that will be added to - the klisp implementation in the near future. + 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) - These are the accessors for the input-port and output-port keyed - dynamic variables repectively. + -- 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: this is enumerated in the Kernel report but the text - is still missing. In the new scheme report there's also a third - error-port variable. It is very likely that that will be added to - the klisp implementation in the near future. + 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 an input port - associated with the file represented with `string'. If the file - can't be opened (e.g. because it doesn't exists, or there's a - permissions problem), an error is signaled. + 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: this is enumerated in the Kernel report but the text - is still missing. + 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 an output port - associated with the file represented with `string'. If the file - can't be opened (e.g. if there's a permissions problem), an error - is signaled. + 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' truncates the - file if it already exists, but that could change later (i.e. like - in scheme the behaviour should be considered unspecified). + 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: this is enumerated in the Kernel report but the text - is still missing. + 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) @@ -2230,20 +2255,37 @@ klisp and was taken from Scheme. is still missing. There's probably a name error here. These should probably be called close-input-port & close-output-port. - -- Applicative: read (read [input-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 object if no objects remain. If `read' + 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 [port]) + -- 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. @@ -2262,20 +2304,20 @@ klisp and was taken from Scheme. combiner) -- Applicative: call-with-output-file (call-with-output-file string combiner) - These applicatives open file named in `string' 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. + 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 for input a file named `string'; 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. + 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 @@ -2286,48 +2328,48 @@ klisp and was taken from Scheme. -- Applicative: get-module (get-module string [environment]) Applicative `get-module' creates a fresh standard environment; - opens for input a file named `string'; 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. + 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 + 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 [port]) + -- 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. + 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 [port]) + -- 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 + 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? [port]) + -- 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. @@ -2340,7 +2382,7 @@ klisp and was taken from Scheme. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - -- write-char: (write-char char [port]) + -- 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. @@ -2351,7 +2393,7 @@ klisp and was taken from Scheme. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - -- newline: (newline [port]) + -- 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. @@ -2361,7 +2403,7 @@ klisp and was taken from Scheme. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - -- display: (display object [port]) + -- 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. @@ -2374,7 +2416,58 @@ klisp and was taken from Scheme. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. - -- flush-output-port: (flush-output-port [port]) + -- 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 @@ -2447,7 +2540,7 @@ Index * $sequence: Control. (line 23) * $set!: Environments. (line 182) * $vau: Combiners. (line 26) -* ( <1>: Ports. (line 37) +* ( <1>: Ports. (line 54) * ( <2>: Numbers. (line 193) * ( <3>: Continuations. (line 143) * (: Environments. (line 174) @@ -2474,6 +2567,7 @@ Index * 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) @@ -2490,8 +2584,8 @@ Index * cadddr: Pairs and lists. (line 108) * caddr: Pairs and lists. (line 96) * cadr: Pairs and lists. (line 90) -* call-with-input-file: Ports. (line 131) -* call-with-output-file: Ports. (line 133) +* 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) @@ -2554,7 +2648,7 @@ Index * encycle!: Pairs and lists. (line 158) * environment?: Environments. (line 23) * environments: Environments. (line 6) -* eof-object?: Ports. (line 166) +* eof-object?: Ports. (line 208) * eq?: Equivalence. (line 12) * equal?: Equivalence. (line 16) * equivalence: Equivalence. (line 6) @@ -2580,7 +2674,7 @@ Index * gcd: Numbers. (line 207) * get-current-environment: Environments. (line 114) * get-list-metrics: Pairs and lists. (line 123) -* get-module: Ports. (line 156) +* 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) @@ -2593,7 +2687,7 @@ Index * inert: Control. (line 6) * inert?: Control. (line 11) * inexact?: Numbers. (line 83) -* input-port?: Ports. (line 27) +* input-port?: Ports. (line 32) * integer->char: Characters. (line 59) * integer?: Numbers. (line 61) * Kernel history: Kernel History. (line 6) @@ -2609,7 +2703,7 @@ Index * list-ref: Pairs and lists. (line 198) * list-tail: Pairs and lists. (line 147) * lists: Pairs and lists. (line 6) -* load: Ports. (line 143) +* load: Ports. (line 185) * log: Numbers. (line 376) * make-encapsulation-type: Encapsulations. (line 12) * make-environment: Environments. (line 36) @@ -2637,17 +2731,19 @@ Index * object descriptions: A Sample Applicative Description. (line 6) * odd?: Numbers. (line 185) -* open-input-file: Ports. (line 62) -* open-output-file: Ports. (line 73) +* 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 28) +* output-port?: Ports. (line 33) * pair?: Pairs and lists. (line 27) * pairs: Pairs and lists. (line 6) -* port?: Ports. (line 23) +* port?: Ports. (line 28) * ports: Ports. (line 6) * positive?: Numbers. (line 177) * printing notation: Printing Notation. (line 6) @@ -2655,7 +2751,7 @@ Index * promises: Promises. (line 6) * rational?: Numbers. (line 66) * rationalize: Numbers. (line 340) -* read: Ports. (line 102) +* read: Ports. (line 144) * real->exact: Numbers. (line 286) * real->inexact: Numbers. (line 285) * real?: Numbers. (line 71) @@ -2695,6 +2791,7 @@ Index * 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) @@ -2733,6 +2830,6 @@ Node: Numbers72249 Node: Strings91748 Node: Characters97095 Node: Ports99805 -Node: Alphabetical Index112780 +Node: Alphabetical Index117409  End Tag Table diff --git a/manual/src/ports.texi b/manual/src/ports.texi @@ -7,9 +7,14 @@ @chapter Ports @cindex ports - A port is an object that mediates character-based input from a -source or character-based output to a destination. In the former case, -the port is an input port, in the latter case, an output port. + 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. @c TODO add xref to equal? & eq? Although ports are not considered immutable, none of the operations @@ -17,7 +22,7 @@ on ports described in this section constitute mutation. Ports are @code{equal?} iff @code{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 +@code{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. @@ -33,68 +38,86 @@ returns true iff all the objects in @code{objects} are of type port. @deffnx Applicative output-port? (output-port? . objects) Applicative @code{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. +@code{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. @end deffn +@deffn Applicative textual-port? (textual-port? . objects) +@deffnx Applicative binary-port? (binary-port? . objects) + Applicative @code{textual-port?} is a predicate that returns true +unless one or more of its arguments is not a textual port. Applicative +@code{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. +@end deffn + @deffn with-input-from-file (with-input-from-file string combiner) @deffnx with-output-to-file (with-output-to-file string combiner) +@deffnx with-error-to-file (with-error-to-file string combiner) @c add xref get-current-input-port/get-current-output-port - These two applicatives open the file named in @code{string} for -input or output, an invoke the binder of the input-port & output-port -keyed dynamic variables respectively with the opened port & the passed -@code{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 @code{with-input-from-file} and -@code{with-output-from-file} is inert. - - SOURCE NOTE: this is enumerated in the Kernel report but the text is -still missing. In the new scheme report there's also a third -error-port variable. It is very likely that that will be added to the -klisp implementation in the near future. + These three applicatives open the file named in @code{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 @code{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 @code{with-input-from-file} +and @code{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. @end deffn @deffn get-current-input-port (get-current-input-port) @deffnx get-current-output-port (get-current-output-port) - These are the accessors for the input-port and output-port keyed -dynamic variables repectively. +@deffnx 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. @c add xref to with-input-from-file, etc @c add xref and text for these dynamic vars - SOURCE NOTE: this is enumerated in the Kernel report but the text is -still missing. In the new scheme report there's also a third -error-port variable. It is very likely that that will be added to the -klisp implementation in the near future. + SOURCE NOTE: The first two are enumerated in the Kernel report but +the text is still missing. The third applicative is from Scheme. @end deffn @deffn Applicative open-input-file (open-input-file string) +@deffnx Applicative open-binary-input-file (open-binary-input-file string) @code{string} should be the name/path for an existing file. - Applicative @code{open-input-file} creates and returns an input port -associated with the file represented with @code{string}. If the file -can't be opened (e.g. because it doesn't exists, or there's a -permissions problem), an error is signaled. + Applicative @code{open-input-file} creates and returns a textual +input port associated with the file represented with @code{string}. +Applicative @code{open-binary-input-file} creates and returns a binary +input port associated with the file represented with @code{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: this is enumerated in the Kernel report but the text is -still missing. + SOURCE NOTE: open-input-file is enumerated in the Kernel report but +the text is still missing. open-binary-input-file is from Scheme. @end deffn @deffn Applicative open-output-file (open-output-file string) +@deffnx Applicative open-binary-output-file (open-binary-output-file string) @code{string} should be the name/path for an existing file. - Applicative @code{open-output-file} creates and returns an output -port associated with the file represented with @code{string}. If the -file can't be opened (e.g. if there's a permissions problem), an error -is signaled. + Applicative @code{open-output-file} creates and returns a textual +output port associated with the file represented with @code{string}. +Applicative @code{open-binary-output-file} creates and returns a +binary output port associated with the file represented with +@code{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 @code{open-output-file} truncates the -file if it already exists, but that could change later (i.e. like in -scheme the behaviour should be considered unspecified). + In klisp, for now, applicative @code{open-output-file} and +@code{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: this is enumerated in the Kernel report but the text is -still missing. + SOURCE NOTE: open-output-file is enumerated in the Kernel report but +the text is still missing. open-binary-output-file is from Scheme. @end deffn @deffn close-input-file (close-input-file input-port) @@ -112,13 +135,30 @@ still missing. There's probably a name error here. These should probably be called close-input-port & close-output-port. @end deffn -@deffn Applicative read (read [input-port]) +@deffn close-input-port (close-input-port input-port) +@deffnx close-output-port (close-output-port output-port) +@deffnx 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 @code{close-input-port}, +@code{close-output-port}, and @code{close-port} is inert. + + SOURCE NOTE: this is from Scheme. The equivalent +@code{close-input-file} and @code{close-output-file} are probably name +errors and only retained here till the draft standard rectifies them +@end deffn + +@deffn Applicative read (read [textual-input-port]) If the @code{port} optional argument is not specified, then the value of the @code{input-port} keyed dynamic variable is used. If the port is closed, an error is signaled. Applicative @code{read} reads & returns the next parseable object -from the given port, or the eof object if no objects remain. If +from the given port, or the @code{eof} if no objects remain. If @code{read} finds and unparseable object in the port, an error is signaled. In that case, the remaining position in the port is unspecified. @@ -127,7 +167,7 @@ unspecified. still missing. @end deffn -@deffn write (write object [port]) +@deffn write (write object [textual-output-port]) If the @code{port} optional argument is not specified, then the value of the @code{output-port} keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -147,11 +187,11 @@ still missing. @deffn Applicative call-with-input-file (call-with-input-file string combiner) @deffnx Applicative call-with-output-file (call-with-output-file string combiner) - These applicatives open file named in @code{string} and call their -@code{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. + These applicatives open file named in @code{string} for textual +input/output respectively and call their @code{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. @@ -159,10 +199,10 @@ still missing. @deffn Applicative load (load string) @c TODO add xref, open/input, read - Applicative @code{load} opens for input a file named @code{string}; -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 @code{load} is inert. + Applicative @code{load} opens the file named @code{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 @code{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 @@ -175,11 +215,11 @@ return the value of the last evaluation. @deffn Applicative get-module (get-module string [environment]) @c TODO add xref standard-environment, open/input, read Applicative @code{get-module} creates a fresh standard environment; -opens for input a file named @code{string}; 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 @code{environment} is -specified, the freshly created standard environment is augmented, +opens the file named @code{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 @code{environment} +is specified, the freshly created standard environment is augmented, prior to evaluating read expressions, by binding symbol @code{module-parameters} to the @code{environment} argument. @end deffn @@ -189,38 +229,38 @@ prior to evaluating read expressions, by binding symbol returns true iff all the objects in @code{objects} are of type eof. SOURCE NOTE: This is not in the report, the idea is from Scheme. -The @code{eof-object?} name is also from scheme, but this will +The @code{eof-object?} name is also from Scheme, but this will probably be changed to just @code{eof?}, for consistency with the other primitive type predicates. @end deffn -@deffn read-char (read-char [port]) +@deffn read-char (read-char [textual-input-port]) If the @code{port} optional argument is not specified, then the value of the @code{input-port} keyed dynamic variable is used. If the port is closed, an error is signaled. Applicative @code{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. +an @code{eof} if the end of file was reached. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. @end deffn -@deffn peek-char (peek-char [port]) +@deffn peek-char (peek-char [textual-input-port]) If the @code{port} optional argument is not specified, then the value of the @code{input-port} keyed dynamic variable is used. If the port is closed, an error is signaled. Applicative @code{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 +an @code{eof} if the end of file was reached. The position of the port remains unchanged so that new call to @code{peek-char} or @code{read-char} on the same port return the same character. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. @end deffn -@deffn char-ready? (char-ready? [port]) +@deffn char-ready? (char-ready? [textual-input-port]) If the @code{port} optional argument is not specified, then the value of the @code{input-port} keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -234,7 +274,7 @@ the code to do this is non-portable. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. @end deffn -@deffn write-char (write-char char [port]) +@deffn write-char (write-char char [textual-output-port]) If the @code{port} optional argument is not specified, then the value of the @code{output-port} keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -246,7 +286,7 @@ The result returned by @code{write-char} is inert. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. @end deffn -@deffn newline (newline [port]) +@deffn newline (newline [textal-ouput-port]) If the @code{port} optional argument is not specified, then the value of the @code{output-port} keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -257,7 +297,7 @@ The result returned by @code{newline} is inert. SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. @end deffn -@deffn display (display object [port]) +@deffn display (display object [textual-output-port]) If the @code{port} optional argument is not specified, then the value of the @code{output-port} keyed dynamic variable is used. If the port is closed, an error is signaled. @@ -271,7 +311,62 @@ within those strings and character objects are output as if by SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. @end deffn -@deffn flush-output-port (flush-output-port [port]) +@deffn read-u8 (read-u8 [textual-input-port]) + If the @code{port} optional argument is not specified, then the +value of the @code{input-port} keyed dynamic variable is used. If the +port is closed, an error is signaled. + + Applicative @code{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 @code{eof} if +the end of file was reached. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +@end deffn + +@deffn peek-u8 (peek-u8 [textual-input-port]) + If the @code{port} optional argument is not specified, then the +value of the @code{input-port} keyed dynamic variable is used. If the +port is closed, an error is signaled. + + Applicative @code{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 @code{eof} if +the end of file was reached. The position of the port remains +unchanged so that new call to @code{peek-u8} or @code{read-u8} on the +same port return the same byte. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +@end deffn + +@deffn u8-ready? (u8-ready? [textual-input-port]) + If the @code{port} optional argument is not specified, then the +value of the @code{input-port} keyed dynamic variable is used. If the +port is closed, an error is signaled. + + Predicate @code{u8-ready?} checks to see if a byte is +available in the specified port. If it returns true, then a +@code{read-u8} or @code{peek-u8} on that port is guaranteed not to +block/hang. For now in klisp this is hardcoded to @code{#t} because +the code to do this is non-portable. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +@end deffn + +@deffn write-u8 (write-u8 u8 [textual-output-port]) + If the @code{port} optional argument is not specified, then the +value of the @code{output-port} keyed dynamic variable is used. If the +port is closed, an error is signaled. + + Applicative @code{write-u8} writes the byte represented by the +unsigned integer @code{u8}, that should be between 0 and 255 inclusive, +(not an external representation of byte) to the specified port. The +result returned by @code{write-u8} is inert. + + SOURCE NOTE: this is missing from Kernel, it is taken from Scheme. +@end deffn + +@deffn flush-output-port (flush-output-port [output-port]) If the @code{port} optional argument is not specified, then the value of the @code{output-port} keyed dynamic variable is used. If the @code{port} is closed or if it is not an output port, an error is diff --git a/src/Makefile b/src/Makefile @@ -35,12 +35,12 @@ CORE_O= kobject.o ktoken.o kpair.o kstring.o ksymbol.o kread.o \ kwrite.o kstate.o kmem.o kerror.o kauxlib.o kenvironment.o \ kcontinuation.o koperative.o kapplicative.o keval.o krepl.o kscript.o \ kencapsulation.o kpromise.o kport.o kinteger.o krational.o \ - kreal.o ktable.o kgc.o imath.o imrat.o kblob.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 \ 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 kgblobs.o kgsystem.o kgerror.o \ + kgstrings.o kgbytevectors.o kgvectors.o kgsystem.o kgerror.o \ $(if $(USE_LIBFFI),kgffi.o) # TEMP: in klisp there is no distinction between core & lib @@ -69,10 +69,11 @@ $(KRN_T): $(KRN_O) $(KRN_A) $(CC) -o $@ $(MYLDFLAGS) $(KRN_O) $(KRN_A) $(LIBS) clean: - $(RM) $(ALL_T) $(ALL_O) + $(RM) $(ALL_T) $(ALL_O) kgffi.o +# XXX this fails if USE_LIBFFI is not defined depend: - @$(CC) $(CFLAGS) -MM k*.c imath.c imrat.c + @$(CC) $(CFLAGS) -DKUSE_LIBFFI=1 -MM k*.c imath.c imrat.c echo: @echo "PLAT = $(PLAT)" @@ -116,8 +117,8 @@ kapplicative.o: kapplicative.c kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h kapplicative.h koperative.h kgc.h kauxlib.o: kauxlib.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ ktoken.h kmem.h -kblob.o: kblob.c kblob.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ - ktoken.h kmem.h kgc.h +kbytevector.o: kbytevector.c kbytevector.h kobject.h klimits.h klisp.h \ + klispconf.h kstate.h ktoken.h kmem.h kgc.h kstring.h kcontinuation.o: kcontinuation.c kcontinuation.h kobject.h klimits.h \ klisp.h klispconf.h kstate.h ktoken.h kmem.h kgc.h kencapsulation.o: kencapsulation.c kobject.h klimits.h klisp.h \ @@ -126,23 +127,20 @@ kenvironment.o: kenvironment.c kenvironment.h kobject.h klimits.h klisp.h \ klispconf.h kstate.h ktoken.h kmem.h kpair.h kgc.h ksymbol.h kstring.h \ kerror.h ktable.h kapplicative.h koperative.h kerror.o: kerror.c klisp.h kobject.h klimits.h klispconf.h kpair.h \ - kstate.h ktoken.h kmem.h kgc.h kstring.h + kstate.h ktoken.h kmem.h kgc.h kstring.h kerror.h keval.o: keval.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h kerror.h -kgblobs.o: kgblobs.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ - kblob.h kghelpers.h kpair.h kgc.h kenvironment.h ksymbol.h kstring.h \ - kgblobs.h kgnumbers.h kgbooleans.o: kgbooleans.c kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h kpair.h kgc.h ksymbol.h kstring.h \ kcontinuation.h kerror.h kghelpers.h kapplicative.h koperative.h \ kenvironment.h +kgbytevectors.o: kgbytevectors.c kstate.h klimits.h klisp.h kobject.h \ + klispconf.h ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h \ + kerror.h kpair.h kgc.h kbytevector.h kghelpers.h kenvironment.h \ + ksymbol.h kstring.h kgbytevectors.h kgnumbers.h kgc.o: kgc.c kgc.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ - ktoken.h kmem.h kport.h imath.h imrat.h ktable.h kstring.h kblob.h \ - kerror.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 \ - kghelpers.h kpair.h kgc.h kenvironment.h ksymbol.h kstring.h kgchars.h + ktoken.h kmem.h kport.h imath.h imrat.h ktable.h kstring.h kbytevector.h \ + kvector.h kerror.h kpair.h kgcombiners.o: kgcombiners.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h \ ksymbol.h kstring.h koperative.h kapplicative.h kerror.h kghelpers.h \ @@ -157,31 +155,39 @@ kgcontrol.o: kgcontrol.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ kgcontrol.h kgcombiners.h kgencapsulations.o: kgencapsulations.c kstate.h klimits.h klisp.h \ kobject.h klispconf.h ktoken.h kmem.h kencapsulation.h kapplicative.h \ - koperative.h kerror.h kghelpers.h kpair.h kgc.h kcontinuation.h \ + koperative.h kerror.h kpair.h kgc.h kghelpers.h kcontinuation.h \ kenvironment.h ksymbol.h kstring.h kgencapsulations.h -kgenv_mut.o: kgenv_mut.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h ksymbol.h \ - kstring.h kerror.h kghelpers.h kapplicative.h koperative.h kgenv_mut.h \ - kgcontrol.h kgenvironments.o: kgenvironments.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h \ ksymbol.h kstring.h kerror.h kghelpers.h kapplicative.h koperative.h \ kgenvironments.h kgenv_mut.h kgpair_mut.h kgcontrol.h +kgenv_mut.o: kgenv_mut.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ + ktoken.h kmem.h kpair.h kgc.h kenvironment.h kcontinuation.h ksymbol.h \ + kstring.h kerror.h kghelpers.h kapplicative.h koperative.h kgenv_mut.h \ + kgcontrol.h kgeqp.o: kgeqp.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kpair.h kgc.h kcontinuation.h kerror.h kghelpers.h \ kapplicative.h koperative.h kenvironment.h ksymbol.h kstring.h kgeqp.h \ kinteger.h imath.h krational.h imrat.h kgequalp.o: kgequalp.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kpair.h kgc.h kstring.h kblob.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 + ktoken.h kmem.h kpair.h kgc.h kstring.h kbytevector.h kcontinuation.h \ + kerror.h kghelpers.h kapplicative.h koperative.h kenvironment.h \ + ksymbol.h kgeqp.h kinteger.h imath.h krational.h imrat.h kgequalp.h kgerror.o: kgerror.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kstring.h kpair.h kgc.h kerror.h kghelpers.h \ kapplicative.h koperative.h kcontinuation.h kenvironment.h ksymbol.h \ - kgerror.h + kgerror.h +kgffi.o: kgffi.c imath.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ + ktoken.h kmem.h kinteger.h kpair.h kgc.h kerror.h kbytevector.h \ + kencapsulation.h ktable.h kghelpers.h kapplicative.h koperative.h \ + kcontinuation.h kenvironment.h ksymbol.h kstring.h kgencapsulations.h \ + kgcombiners.h kgcontinuations.h kgffi.h kghelpers.o: kghelpers.c kghelpers.h kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kerror.h kpair.h kgc.h kapplicative.h \ koperative.h kcontinuation.h kenvironment.h ksymbol.h kstring.h +kgchars.o: kgchars.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ + ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ + kpair.h kgc.h kghelpers.h kenvironment.h ksymbol.h kstring.h kgchars.h 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 \ @@ -192,8 +198,8 @@ kgks_vars.o: kgks_vars.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ kgks_vars.h kgnumbers.o: kgnumbers.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ - ksymbol.h kstring.h kinteger.h imath.h krational.h imrat.h kreal.h \ - kghelpers.h kpair.h kgc.h kenvironment.h kgnumbers.h kgkd_vars.h + kpair.h kgc.h ksymbol.h kstring.h kinteger.h imath.h krational.h imrat.h \ + kreal.h kghelpers.h kenvironment.h kgnumbers.h kgkd_vars.h kgpair_mut.o: kgpair_mut.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpair.h kgc.h kcontinuation.h ksymbol.h \ kstring.h kerror.h kghelpers.h kapplicative.h koperative.h \ @@ -204,9 +210,10 @@ kgpairs_lists.o: kgpairs_lists.c kstate.h klimits.h klisp.h kobject.h \ kenvironment.h ksymbol.h kerror.h kghelpers.h kapplicative.h \ koperative.h kgequalp.h kgpairs_lists.h kgnumbers.h kinteger.h imath.h kgports.o: kgports.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kport.h kenvironment.h kapplicative.h koperative.h \ - kcontinuation.h kpair.h kgc.h kerror.h ksymbol.h kstring.h kread.h \ - kwrite.h kghelpers.h kgports.h kgcontinuations.h kgcontrol.h kgkd_vars.h kscript.h + ktoken.h kmem.h kport.h kstring.h kbytevector.h kenvironment.h \ + kapplicative.h koperative.h kcontinuation.h kpair.h kgc.h kerror.h \ + ksymbol.h kread.h kwrite.h kscript.h kghelpers.h kgports.h \ + kgcontinuations.h kgcontrol.h kgkd_vars.h kgpromises.o: kgpromises.c kstate.h klimits.h klisp.h kobject.h \ klispconf.h ktoken.h kmem.h kpromise.h kpair.h kgc.h kapplicative.h \ koperative.h kcontinuation.h kerror.h kghelpers.h kenvironment.h \ @@ -218,11 +225,11 @@ kground.o: kground.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ kgequalp.h kgsymbols.h kgcontrol.h kgpairs_lists.h kgpair_mut.h \ kgenvironments.h kgenv_mut.h kgcombiners.h kgcontinuations.h \ kgencapsulations.h kgpromises.h kgkd_vars.h kgks_vars.h kgnumbers.h \ - kgstrings.h kgchars.h kgports.h kgblobs.h ktable.h keval.h krepl.h \ - kscript.h kgsystem.h kgerror.h kgffi.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 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 \ - ksymbol.h kstring.h kghelpers.h kpair.h kgc.h kenvironment.h kgchars.h \ + kpair.h kgc.h ksymbol.h kstring.h kghelpers.h kenvironment.h kgchars.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 \ @@ -232,23 +239,26 @@ kgsystem.o: kgsystem.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ ktoken.h kmem.h kpair.h kgc.h kerror.h kghelpers.h kapplicative.h \ koperative.h kcontinuation.h kenvironment.h ksymbol.h kstring.h \ kgsystem.h -kgffi.o: kgsystem.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ - ktoken.h kmem.h kpair.h kgc.h kerror.h kghelpers.h kapplicative.h \ - koperative.h kcontinuation.h kenvironment.h ksymbol.h kstring.h \ - kblob.h kencapsulation.h kgencapsulations.h kgffi.h +kgvectors.o: kgvectors.c kstate.h klimits.h klisp.h kobject.h klispconf.h \ + ktoken.h kmem.h kapplicative.h koperative.h kcontinuation.h kerror.h \ + kpair.h kgc.h kvector.h kghelpers.h kenvironment.h ksymbol.h kstring.h \ + kgvectors.h kgnumbers.h kinteger.o: kinteger.c kinteger.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h imath.h kgc.h klisp.o: klisp.c klimits.h klisp.h kobject.h klispconf.h kstate.h \ - ktoken.h kmem.h kauxlib.h + 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 kmem.o: kmem.c klisp.h kobject.h klimits.h klispconf.h kstate.h ktoken.h \ - kmem.h kerror.h kgc.h + kmem.h kerror.h kpair.h kgc.h kobject.o: kobject.c kobject.h klimits.h klisp.h klispconf.h koperative.o: koperative.c koperative.h kobject.h klimits.h klisp.h \ klispconf.h kstate.h ktoken.h kmem.h kgc.h kpair.o: kpair.c kpair.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kgc.h kport.o: kport.c kport.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ - ktoken.h kmem.h kerror.h kstring.h kgc.h + ktoken.h kmem.h kerror.h kpair.h kgc.h kstring.h kbytevector.h kpromise.o: kpromise.c kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kpromise.h kpair.h kgc.h krational.o: krational.c krational.h kobject.h klimits.h klisp.h \ @@ -259,15 +269,18 @@ kreal.o: kreal.c kreal.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kinteger.h imath.h krational.h imrat.h kgc.h kpair.h \ kerror.h krepl.o: krepl.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ - ktoken.h kmem.h kcontinuation.h kenvironment.h kerror.h kread.h kwrite.h \ - kstring.h krepl.h ksymbol.h kport.h kpair.h kgc.h ktable.h + ktoken.h kmem.h kcontinuation.h kenvironment.h kerror.h kpair.h kgc.h \ + kread.h kwrite.h kstring.h krepl.h ksymbol.h kport.h kgerror.h \ + kghelpers.h kapplicative.h koperative.h ktable.h kgcontinuations.h kscript.o: kscript.c klisp.h kobject.h klimits.h klispconf.h kstate.h \ - ktoken.h kmem.h kcontinuation.h kenvironment.h kerror.h kread.h kwrite.h \ - kstring.h krepl.h kscript.h ksymbol.h kport.h kpair.h kgc.h ktable.h kgcontrol.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 kblob.h kgpairs_lists.h kghelpers.h kerror.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 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 \ @@ -278,12 +291,14 @@ ktable.o: ktable.c klisp.h kobject.h klimits.h klispconf.h kgc.h kstate.h \ kenvironment.h ksymbol.h kstring.h ktoken.o: ktoken.c ktoken.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h kmem.h kinteger.h imath.h krational.h imrat.h kreal.h kpair.h \ - kgc.h kstring.h ksymbol.h kerror.h kport.h + kgc.h kstring.h kbytevector.h ksymbol.h kerror.h kport.h +kvector.o: kvector.c kvector.h kobject.h klimits.h klisp.h klispconf.h \ + kstate.h ktoken.h kmem.h kgc.h kwrite.o: kwrite.c kwrite.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h kinteger.h imath.h krational.h imrat.h kreal.h \ kpair.h kgc.h kstring.h ksymbol.h kerror.h ktable.h kport.h \ - kenvironment.h kblob.h + kenvironment.h kbytevector.h imath.o: imath.c imath.h kobject.h klimits.h klisp.h klispconf.h kstate.h \ - ktoken.h kmem.h kerror.h + ktoken.h kmem.h kerror.h kpair.h kgc.h imrat.o: imrat.c imrat.h imath.h kobject.h klimits.h klisp.h klispconf.h \ - kstate.h ktoken.h kmem.h kerror.h + kstate.h ktoken.h kmem.h kerror.h kpair.h kgc.h diff --git a/src/examples/ffi-gsl.k b/src/examples/ffi-gsl.k @@ -24,7 +24,7 @@ (cif (ffi-make-call-interface abi "double" (list "double" "pointer"))) ) ($lambda (f) ($let - ( (gslf (make-blob (* 2 pointer-size)) ) + ( (gslf (make-bytevector (* 2 pointer-size)) ) (aux ($lambda (x params) (f x)))) (set! (list gslf 0) (ffi-make-callback aux cif)) gslf)))) @@ -39,8 +39,8 @@ ((gslf (make-gsl-function f))) ($lambda (x h) ($let - ( (result (make-blob double-size)) - (abserr (make-blob double-size))) + ( (result (make-bytevector double-size)) + (abserr (make-bytevector double-size))) (gsl_deriv_central gslf x h result abserr) (list (ref result) (ref abserr)))))))) diff --git a/src/examples/ffi-sdl.k b/src/examples/ffi-sdl.k @@ -45,10 +45,10 @@ ((SDL_WaitEvent (sdl-import "sint" "SDL_WaitEvent" "pointer"))) ($lambda () ($let* - ( (buffer (make-blob 512)) + ( (buffer (make-bytevector 512)) (ok (SDL_WaitEvent buffer))) ($if (zero? ok) - (apply-continuation error-continuation "SDL_WaitEvent signalled error") + (error "SDL_WaitEvent signalled error") buffer))))) ($define! align @@ -113,14 +113,14 @@ (write status) (newline) ($if (<? status 0) - (apply error-continuation "error initializing SDL") + (error "error initializing SDL") ($sequence (guard-dynamic-extent () ($lambda () ($let* ((screen (sdl-set-video-mode 640 480 32 SDL_HWSURFACE))) ($if (null? screen) - (apply-continuation error-contination "unable to set video mode") + (error "unable to set video mode") ($sequence (sdl-wm-set-caption window-title ()) (worker screen))))) @@ -156,7 +156,7 @@ (SDL_Flip (sdl-import "sint" "SDL_Flip" "pointer"))) ($lambda (screen (x y) (r g b)) ($if (<? (SDL_LockSurface screen) 0) - (apply error-continuation "SDL_LockSurface failed") + (error "SDL_LockSurface failed") ()) ($let ( (pixels (SDL_Surface.pixels screen)) diff --git a/src/examples/ffi-signal.c b/src/examples/ffi-signal.c @@ -58,7 +58,7 @@ static void open_signal_port(klisp_State *K, TValue *xparams, FILE *fw = fdopen(self_pipe[0], "r"); TValue filename = kstring_new_b_imm(K, "**SIGNAL**"); krooted_tvs_push(K, filename); - TValue port = kmake_std_port(K, filename, false, fw); + TValue port = kmake_std_fport(K, filename, false, true, fw); krooted_tvs_pop(K); kapply_cc(K, port); } diff --git a/src/examples/ffi-signal.k b/src/examples/ffi-signal.k @@ -39,7 +39,7 @@ ;; an internal pipe. ;; ;; (open-signal-port) opens the read-end of the internal pipe -;; as a port. +;; as a binary input port. ;; ;; The following code demonstrates the signal handling (it is not ;; possible to install arbitrary klisp procedure as a signal handler, @@ -48,10 +48,10 @@ (install-signal-handler "SIGINT") ($define! signal-port (open-signal-port)) (display "Installed signal handler for SIGINT. Press Ctrl-C to continue...") -(read-char signal-port) +(read-u8 signal-port) (newline) (display "Signal detected. Press Ctrl-C again...") -(read-char signal-port) +(read-u8 signal-port) (newline) (display "Done.") (newline) diff --git a/src/examples/ffi.k b/src/examples/ffi.k @@ -41,7 +41,7 @@ ;; "uint64" uint64_t fixint, bigint ;; "float" float double ;; "double" double double -;; "pointer" (void *) blob (only for arguments) +;; "pointer" (void *) bytevector (only for arguments) ;; string (only for arguments) ;; nil ;; pointer (TAG_USER) @@ -122,7 +122,7 @@ ;; (REF MEMORY-LOCATION) ;; (SET! MEMORY-LOCATION VALUE) ;; -;; MEMORY-LOCATION is either blob, string, pointer, +;; MEMORY-LOCATION is either bytevector, string, pointer, ;; or a two-element list (MEMORY-LOCATION OFFSET). ;; The offset specification can not be nested, i.e. ;; ((blob 1) 2) is not valid memory location. @@ -136,7 +136,7 @@ (newline) ;; Using ffi-type-suite, one can define means to convert -;; C structs (stored in blobs or arbitrary memory locations) +;; C structs (stored in bytevectors or arbitrary memory locations) ;; to lists. ;; ($define! align @@ -184,7 +184,7 @@ (ffi-make-call-interface abi "sint" (list "pointer" "pointer"))))) ($lambda () - ($let* ((buffer (make-blob (* 2 sint-size)))) + ($let* ((buffer (make-bytevector (* 2 sint-size)))) (unix-gettimeofday buffer ()) ($let (((tv_sec tv_usec) (struct-timeval-ref buffer))) (list tv_sec (/ tv_usec 1000000))))))) @@ -203,8 +203,8 @@ (decode-struct "sint" "sint" "sint" "sint" "sint" "sint" "sint" "sint"))) ($lambda (t) ($let* - ( (t-buf (make-blob sint-size)) - (tm-buf (make-blob 128)) ) + ( (t-buf (make-bytevector sint-size)) + (tm-buf (make-bytevector 128)) ) (sint-set! t-buf t) (localtime-r t-buf tm-buf) ($let @@ -236,21 +236,21 @@ ;; (ffi-memmove DESTINATION SOURCE SIZE) copies ;; SIZE bytes from SOURCE to DESTINATION. Both SOURCE ;; and DESTINATION are memory locations as described above. -;; ffi-memmove can copy data between blobs and arbitrary +;; ffi-memmove can copy data between bytevectors and arbitrary ;; memory locations. ;; ($define! copy-location ($lambda (location size) - ($let ((blob (make-blob size))) + ($let ((blob (make-bytevector size))) (ffi-memmove blob location size) blob))) -($define! blob->list +($define! bytevector->list ($letrec ((aux ($lambda (blob index) - ($if (<? index (blob-length blob)) + ($if (<? index (bytevector-length blob)) (cons - (blob-u8-ref blob index) + (bytevector-u8-ref blob index) (aux blob (+ 1 index))) ())))) ($lambda (blob) @@ -258,7 +258,7 @@ ($define! parse-address ($lambda (location size) - (blob->list (copy-location location size)))) + (bytevector->list (copy-location location size)))) ($define! (voidptr-size voidptr-alignment voidptr-ref voidptr-set!) @@ -322,10 +322,10 @@ ($define! endianess ($let - ((buffer (make-blob 4))) + ((buffer (make-bytevector 4))) (uint32-set! buffer #x01020304) ($let - ((bytes (blob->list buffer))) + ((bytes (bytevector->list buffer))) ($cond ((equal? bytes (list 1 2 3 4)) "big-endian") ((equal? bytes (list 4 3 2 1)) "little-endian") diff --git a/src/kblob.c b/src/kblob.c @@ -1,66 +0,0 @@ -/* -** kblob.c -** Kernel Blobs (byte vectors) -** See Copyright Notice in klisp.h -*/ - -#include <string.h> - -#include "kblob.h" -#include "kobject.h" -#include "kstate.h" -#include "kmem.h" -#include "kgc.h" - -/* Constructors */ -TValue kblob_new_g(klisp_State *K, bool m, uint32_t size) -{ - Blob *new_blob; - - /* XXX: find a better way to do this! */ - if (size == 0 && ttisblob(K->empty_blob)) { - return K->empty_blob; - } - - new_blob = klispM_malloc(K, sizeof(Blob) + size); - - /* header + gc_fields */ - klispC_link(K, (GCObject *) new_blob, K_TBLOB, m? 0 : K_FLAG_IMMUTABLE); - - /* blob specific fields */ - new_blob->mark = KFALSE; - new_blob->size = size; - - /* clear the buffer */ - memset(new_blob->b, 0, size); - - return gc2blob(new_blob); -} - -TValue kblob_new(klisp_State *K, uint32_t size) -{ - return kblob_new_g(K, true, size); -} - -TValue kblob_new_imm(klisp_State *K, uint32_t size) -{ - return kblob_new_g(K, false, size); -} - -/* both obj1 and obj2 should be blobs */ -bool kblob_equalp(TValue obj1, TValue obj2) -{ - klisp_assert(ttisblob(obj1) && ttisblob(obj2)); - - Blob *blob1 = tv2blob(obj1); - Blob *blob2 = tv2blob(obj2); - - if (blob1->size == blob2->size) { - return (blob1->size == 0) || - (memcmp(blob1->b, blob2->b, blob1->size) == 0); - } else { - return false; - } -} - -bool kblobp(TValue obj) { return ttisblob(obj); } diff --git a/src/kblob.h b/src/kblob.h @@ -1,34 +0,0 @@ -/* -** kblob.h -** Kernel Blobs (byte vectors) -** See Copyright Notice in klisp.h -*/ - -#ifndef kblob_h -#define kblob_h - -#include "kobject.h" -#include "kstate.h" - -/* TODO change blob constructors to string like constructors */ -/* TODO change names to lua-like (e.g. klispB_new, etc) */ - -/* Constructors for blobs */ -TValue kblob_new_g(klisp_State *K, bool m, uint32_t size); -TValue kblob_new_imm(klisp_State *K, uint32_t size); -TValue kblob_new(klisp_State *K, uint32_t size); - -/* both obj1 and obj2 should be blobs, this compares byte by byte - and doesn't differentiate immutable from mutable blobs */ -bool kblob_equalp(TValue obj1, TValue obj2); -bool kblob(TValue obj); - -/* some macros to access the parts of the blobs */ -#define kblob_buf(tv_) (tv2blob(tv_)->b) -#define kblob_size(tv_) (tv2blob(tv_)->size) - -#define kblob_emptyp(tv_) (kblob_size(tv_) == 0) -#define kblob_mutablep(tv_) (kis_mutable(tv_)) -#define kblob_immutablep(tv_) (kis_immutable(tv_)) - -#endif diff --git a/src/kbytevector.c b/src/kbytevector.c @@ -0,0 +1,183 @@ +/* +** kbytevector.c +** Kernel Byte Vectors +** See Copyright Notice in klisp.h +*/ + +#include <string.h> + +#include "kbytevector.h" +#include "kobject.h" +#include "kstate.h" +#include "kmem.h" +#include "kgc.h" +/* for immutable table */ +#include "kstring.h" + +/* Constructors */ + +/* General constructor for bytevectors */ +TValue kbytevector_new_bs_g(klisp_State *K, bool m, const uint8_t *buf, + uint32_t size) +{ + return m? kbytevector_new_bs(K, buf, size) : + kbytevector_new_bs_imm(K, buf, size); +} + +/* +** Constructors for immutable bytevectors +*/ + +/* main constructor for immutable bytevectors */ +TValue kbytevector_new_bs_imm(klisp_State *K, const uint8_t *buf, uint32_t size) +{ + /* first check to see if it's in the stringtable */ + GCObject *o; + uint32_t h = size; /* seed */ + size_t step = (size>>5)+1; /* if bytevector is too long, don't hash all + its bytes */ + size_t size1; + for (size1 = size; size1 >= step; size1 -= step) /* compute hash */ + h = h ^ ((h<<5)+(h>>2)+ buf[size1-1]); + + for (o = K->strt.hash[lmod(h, K->strt.size)]; + o != NULL; o = o->gch.next) { + Bytevector *tb = NULL; + if (o->gch.tt == K_TBYTEVECTOR) { + tb = (Bytevector *) o; + } else if (o->gch.tt == K_TSYMBOL || o->gch.tt == K_TSTRING) { + continue; + } else { + /* only symbols, immutable bytevectors and immutable strings */ + klisp_assert(0); + } + if (tb->size == size && (memcmp(buf, tb->b, size) == 0)) { + /* bytevector may be dead */ + if (isdead(K, o)) changewhite(o); + return gc2bytevector(o); + } + } + + /* If it exits the loop, it means it wasn't found, hash is still in h */ + /* REFACTOR: move all of these to a new function */ + Bytevector *new_bb; + + if (size > (SIZE_MAX - sizeof(Bytevector))) + klispM_toobig(K); + + new_bb = (Bytevector *) klispM_malloc(K, sizeof(Bytevector) + size); + + /* header + gc_fields */ + /* can't use klispC_link, because strings use the next pointer + differently */ + new_bb->gct = klispC_white(K); + new_bb->tt = K_TBYTEVECTOR; + new_bb->kflags = K_FLAG_IMMUTABLE; + new_bb->si = NULL; + + /* bytevector specific fields */ + new_bb->hash = h; + new_bb->mark = KFALSE; + new_bb->size = size; + + if (size != 0) { + memcpy(new_bb->b, buf, size); + } + + /* add to the string/symbol table (and link it) */ + stringtable *tb; + tb = &K->strt; + h = lmod(h, tb->size); + new_bb->next = tb->hash[h]; /* chain new entry */ + tb->hash[h] = (GCObject *)(new_bb); + tb->nuse++; + TValue ret_tv = gc2bytevector(new_bb); + if (tb->nuse > ((uint32_t) tb->size) && tb->size <= INT32_MAX / 2) { + krooted_tvs_push(K, ret_tv); /* save in case of gc */ + klispS_resize(K, tb->size*2); /* too crowded */ + krooted_tvs_pop(K); + } + + return ret_tv; +} + +/* +** Constructors for mutable bytevectors +*/ + +/* main constructor for mutable bytevectors */ +/* with just size */ +TValue kbytevector_new_s(klisp_State *K, uint32_t size) +{ + Bytevector *new_bb; + + if (size == 0) { + klisp_assert(ttisbytevector(K->empty_bytevector)); + return K->empty_bytevector; + } + + new_bb = klispM_malloc(K, sizeof(Bytevector) + size); + + /* header + gc_fields */ + klispC_link(K, (GCObject *) new_bb, K_TBYTEVECTOR, 0); + + /* bytevector specific fields */ + new_bb->mark = KFALSE; + new_bb->size = size; + + /* the buffer is initialized elsewhere */ + + return gc2bytevector(new_bb); +} + +/* with buffer & size */ +TValue kbytevector_new_bs(klisp_State *K, const uint8_t *buf, uint32_t size) +{ + if (size == 0) { + klisp_assert(ttisbytevector(K->empty_bytevector)); + return K->empty_bytevector; + } + + TValue new_bb = kbytevector_new_s(K, size); + memcpy(kbytevector_buf(new_bb), buf, size); + return new_bb; +} + +/* with size and fill uint8_t */ +TValue kbytevector_new_sf(klisp_State *K, uint32_t size, uint8_t fill) +{ + if (size == 0) { + klisp_assert(ttisbytevector(K->empty_bytevector)); + return K->empty_bytevector; + } + + TValue new_bb = kbytevector_new_s(K, size); + memset(kbytevector_buf(new_bb), fill, size); + return new_bb; +} + +/* both obj1 and obj2 should be bytevectors */ +bool kbytevector_equalp(TValue obj1, TValue obj2) +{ + klisp_assert(ttisbytevector(obj1) && ttisbytevector(obj2)); + + Bytevector *bytevector1 = tv2bytevector(obj1); + Bytevector *bytevector2 = tv2bytevector(obj2); + + if (bytevector1->size == bytevector2->size) { + return (bytevector1->size == 0) || + (memcmp(bytevector1->b, bytevector2->b, bytevector1->size) == 0); + } else { + return false; + } +} + +bool kbytevectorp(TValue obj) { return ttisbytevector(obj); } +bool kimmutable_bytevectorp(TValue obj) +{ + return ttisbytevector(obj) && kis_immutable(obj); +} +bool kmutable_bytevectorp(TValue obj) +{ + return ttisbytevector(obj) && kis_mutable(obj); +} diff --git a/src/kbytevector.h b/src/kbytevector.h @@ -0,0 +1,54 @@ +/* +** kbytevector.h +** Kernel Byte Vectors +** See Copyright Notice in klisp.h +*/ + +#ifndef kbytevector_h +#define kbytevector_h + +#include "kobject.h" +#include "kstate.h" + +/* TODO change names to be lua-like (e.g. klispBB_new, etc) */ + +/* General constructor for bytevectors */ +TValue kbytevector_new_bs_g(klisp_State *K, bool m, const uint8_t *buf, + uint32_t size); + +/* +** Constructors for immutable bytevectors +*/ + +/* main immutable bytevector constructor */ +/* with buffer & size */ +TValue kbytevector_new_bs_imm(klisp_State *K, const uint8_t *buf, uint32_t size); + +/* +** Constructors for mutable bytevectors +*/ + +/* main mutable bytevector constructor */ +/* with just size */ +TValue kbytevector_new_s(klisp_State *K, uint32_t size); +/* with buffer & size */ +TValue kbytevector_new_bs(klisp_State *K, const uint8_t *buf, uint32_t size); +/* with size & fill byte */ +TValue kbytevector_new_sf(klisp_State *K, uint32_t size, uint8_t fill); + +/* both obj1 and obj2 should be bytevectors, this compares byte by byte + and doesn't differentiate immutable from mutable bytevectors */ +bool kbytevector_equalp(TValue obj1, TValue obj2); +bool kbytevectorp(TValue obj); +bool kimmutable_bytevectorp(TValue obj); +bool kmutable_bytevectorp(TValue obj); + +/* some macros to access the parts of the bytevectors */ +#define kbytevector_buf(tv_) (tv2bytevector(tv_)->b) +#define kbytevector_size(tv_) (tv2bytevector(tv_)->size) + +#define kbytevector_emptyp(tv_) (kbytevector_size(tv_) == 0) +#define kbytevector_mutablep(tv_) (kis_mutable(tv_)) +#define kbytevector_immutablep(tv_) (kis_immutable(tv_)) + +#endif diff --git a/src/kcontinuation.c b/src/kcontinuation.c @@ -12,7 +12,7 @@ #include "kmem.h" #include "kgc.h" -TValue kmake_continuation(klisp_State *K, TValue parent, klisp_Cfunc fn, +TValue kmake_continuation(klisp_State *K, TValue parent, klisp_CFunction fn, int32_t xcount, ...) { va_list argp; diff --git a/src/kcontinuation.h b/src/kcontinuation.h @@ -11,7 +11,7 @@ #include "kstate.h" /* TODO: make some specialized constructors for 0, 1 and 2 parameters */ -TValue kmake_continuation(klisp_State *K, TValue parent, klisp_Cfunc fn, +TValue kmake_continuation(klisp_State *K, TValue parent, klisp_CFunction fn, int xcount, ...); #endif diff --git a/src/kenvironment.c b/src/kenvironment.c @@ -314,7 +314,7 @@ TValue kget_keyed_static_var(klisp_State *K, TValue env, TValue key) } /* environments with hashtable bindings */ -/* TEMP: for now only for ground environment */ +/* TEMP: for now only for ground & std environments */ TValue kmake_table_environment(klisp_State *K, TValue parents) { TValue new_env = kmake_environment(K, parents); diff --git a/src/kerror.c b/src/kerror.c @@ -32,6 +32,21 @@ TValue klispE_new(klisp_State *K, TValue who, TValue cont, TValue msg, return gc2error(new_error); } +TValue klispE_new_with_errno_irritants(klisp_State *K, const char *service, + int errnum, TValue irritants) +{ + TValue error_description = klispE_describe_errno(K, service, errnum); + krooted_tvs_push(K, error_description); + TValue all_irritants = kimm_cons(K, error_description, irritants); + krooted_tvs_push(K, all_irritants); + TValue error_obj = klispE_new(K, K->next_obj, K->curr_cont, + kcaddr(error_description), + all_irritants); + krooted_tvs_pop(K); + krooted_tvs_pop(K); + return error_obj; +} + void klispE_free(klisp_State *K, Error *error) { klispM_free(K, error); @@ -102,15 +117,11 @@ void klispE_throw_with_irritants(klisp_State *K, char *msg, TValue irritants) kcall_cont(K, K->error_cont, error_obj); } -void klispE_throw_system_error_with_irritants(klisp_State *K, const char *service, int errnum, TValue irritants) +void klispE_throw_system_error_with_irritants( + klisp_State *K, const char *service, int errnum, TValue irritants) { - TValue error_description = klispE_describe_errno(K, service, errnum); - krooted_tvs_push(K, error_description); - TValue all_irritants = kimm_cons(K, error_description, irritants); - krooted_tvs_push(K, all_irritants); - TValue error_obj = klispE_new(K, K->next_obj, K->curr_cont, - kcaddr(error_description), - all_irritants); + TValue error_obj = klispE_new_with_errno_irritants(K, service, errnum, + irritants); krooted_tvs_push(K, error_obj); clear_buffers(K); kcall_cont(K, K->system_error_cont, error_obj); @@ -190,7 +201,8 @@ static const char * const symbolic_error_codes[] = { TValue klispE_describe_errno(klisp_State *K, const char *service, int errnum) { const char *code = NULL; - int tabsize = sizeof(symbolic_error_codes) / sizeof(symbolic_error_codes[0]); + int tabsize = sizeof(symbolic_error_codes) / + sizeof(symbolic_error_codes[0]); if (0 <= errnum && errnum < tabsize) code = symbolic_error_codes[errnum]; if (code == NULL) diff --git a/src/kerror.h b/src/kerror.h @@ -13,24 +13,42 @@ #include "klisp.h" #include "kstate.h" +#include "kpair.h" /* for klist */ TValue klispE_new(klisp_State *K, TValue who, TValue cont, TValue msg, TValue irritants); +TValue klispE_new_with_errno_irritants(klisp_State *K, const char *service, + int errnum, TValue irritants); void klispE_free(klisp_State *K, Error *error); void klispE_throw_simple(klisp_State *K, char *msg); void klispE_throw_with_irritants(klisp_State *K, char *msg, TValue irritants); -void klispE_throw_system_error_with_irritants(klisp_State *K, const char *service, int errnum, TValue irritants); +void klispE_throw_system_error_with_irritants( + klisp_State *K, const char *service, int errnum, TValue irritants); + +/* the objects should be rooted */ +#define klispE_new_simple_with_errno_irritants(K__, service__, ...) \ + ({ \ + int errnum__ = errno; \ + TValue ls__ = klist(K__, __VA_ARGS__); \ + krooted_tvs_push(K__, ls__); \ + TValue err__ = klispE_new_with_errno_irritants(K__, service__, \ + errnum__, ls__); \ + krooted_tvs_pop(K__); \ + err__; \ + }) /* evaluates K__ more than once */ +/* the objects should be rooted */ #define klispE_throw_simple_with_irritants(K__, msg__, ...) \ { TValue ls__ = klist(K__, __VA_ARGS__); \ krooted_tvs_push(K__, ls__); \ /* the pop is implicit in throw_with_irritants */ \ klispE_throw_with_irritants(K__, msg__, ls__); } +/* the objects should be rooted */ #define klispE_throw_errno_with_irritants(K__, service__, ...) \ { \ int errnum__ = errno; \ diff --git a/src/keval.c b/src/keval.c @@ -15,8 +15,11 @@ /* ** Eval helpers */ -void do_eval_ls(klisp_State *K, TValue *xparams, TValue obj) +void do_eval_ls(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: this argument list pair ** xparams[1]: dynamic environment @@ -89,8 +92,11 @@ inline TValue make_arg_ls(klisp_State *K, TValue operands, TValue *tail) return arg_ls; } -void do_combine(klisp_State *K, TValue *xparams, TValue obj) +void do_combine(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: operand list ** xparams[1]: dynamic environment @@ -138,22 +144,29 @@ void do_combine(klisp_State *K, TValue *xparams, TValue obj) } /* the underlying function of the eval operative */ -void keval_ofn(klisp_State *K, TValue *xparams, TValue obj, TValue env) +void keval_ofn(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); + TValue obj = ptree; + switch(ttype(obj)) { case K_TPAIR: { TValue new_cont = kmake_continuation(K, kget_cc(K), do_combine, 3, kcdr(obj), - env, ktry_get_si(K, obj)); + denv, ktry_get_si(K, obj)); kset_cc(K, new_cont); - ktail_eval(K, kcar(obj), env); + ktail_eval(K, kcar(obj), denv); break; } case K_TSYMBOL: /* error handling happens in kget_binding */ - kapply_cc(K, kget_binding(K, env, obj)); + kapply_cc(K, kget_binding(K, denv, obj)); break; default: kapply_cc(K, obj); diff --git a/src/keval.h b/src/keval.h @@ -11,8 +11,8 @@ #include "kstate.h" #include "kobject.h" -void keval_ofn(klisp_State *K, TValue *xparams, TValue obj, TValue env); -void do_eval_ls(klisp_State *K, TValue *xparams, TValue obj); -void do_combine(klisp_State *K, TValue *xparams, TValue obj); +void keval_ofn(klisp_State *K); +void do_eval_ls(klisp_State *K); +void do_combine(klisp_State *K); #endif diff --git a/src/kgblobs.c b/src/kgblobs.c @@ -1,250 +0,0 @@ -/* -** kgblobs.c -** Blobs features for the ground environment -** See Copyright Notice in klisp.h -*/ - -#include <assert.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "kstate.h" -#include "kobject.h" -#include "kapplicative.h" -#include "koperative.h" -#include "kcontinuation.h" -#include "kerror.h" -#include "kblob.h" - -#include "kghelpers.h" -#include "kgblobs.h" -#include "kgnumbers.h" /* for keintegerp & knegativep */ - -/* 13.1.1? blob? */ -/* uses typep */ - -/* 13.1.2? make-blob */ -void make_blob(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) -{ - UNUSED(xparams); - UNUSED(denv); - bind_al1tp(K, ptree, "exact integer", keintegerp, tv_s, - maybe_byte); - - uint8_t fill = 0; - if (get_opt_tpar(K, "make-blob", K_TFIXINT, &maybe_byte)) { - if (ivalue(maybe_byte) < 0 || ivalue(maybe_byte) > 255) { - klispE_throw_simple(K, "bad fill byte"); - return; - } - fill = ivalue(maybe_byte); - } - - if (knegativep(tv_s)) { - klispE_throw_simple(K, "negative size"); - return; - } else if (!ttisfixint(tv_s)) { - klispE_throw_simple(K, "size is too big"); - return; - } -/* XXX/TODO */ -/* TValue new_blob = kblob_new_sf(K, ivalue(tv_s), fill); */ - TValue new_blob = kblob_new(K, ivalue(tv_s)); - if (fill != 0) { - int32_t s = ivalue(tv_s); - uint8_t *ptr = kblob_buf(new_blob); - while(s--) - *ptr++ = fill; - } - - kapply_cc(K, new_blob); -} - -/* 13.1.3? blob-length */ -void blob_length(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) -{ - UNUSED(xparams); - UNUSED(denv); - bind_1tp(K, ptree, "blob", ttisblob, blob); - - TValue res = i2tv(kblob_size(blob)); - kapply_cc(K, res); -} - -/* 13.1.4? blob-u8-ref */ -void blob_u8_ref(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) -{ - UNUSED(xparams); - UNUSED(denv); - bind_2tp(K, ptree, "blob", ttisblob, blob, - "exact integer", keintegerp, tv_i); - - if (!ttisfixint(tv_i)) { - /* TODO show index */ - klispE_throw_simple(K, "index out of bounds"); - return; - } - int32_t i = ivalue(tv_i); - - if (i < 0 || i >= kblob_size(blob)) { - /* TODO show index */ - klispE_throw_simple(K, "index out of bounds"); - return; - } - - TValue res = i2tv(kblob_buf(blob)[i]); - kapply_cc(K, res); -} - -/* 13.1.5? blob-u8-set! */ -void blob_u8_setS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) -{ - UNUSED(xparams); - UNUSED(denv); - bind_3tp(K, ptree, "blob", ttisblob, blob, - "exact integer", keintegerp, tv_i, "exact integer", keintegerp, tv_byte); - - if (!ttisfixint(tv_i)) { - /* TODO show index */ - klispE_throw_simple(K, "index out of bounds"); - return; - } else if (kblob_immutablep(blob)) { - klispE_throw_simple(K, "immutable blob"); - return; - } else if (ivalue(tv_byte) < 0 || ivalue(tv_byte) > 255) { - klispE_throw_simple(K, "bad byte"); - return; - } - - int32_t i = ivalue(tv_i); - - if (i < 0 || i >= kblob_size(blob)) { - /* TODO show index */ - klispE_throw_simple(K, "index out of bounds"); - return; - } - - kblob_buf(blob)[i] = (uint8_t) ivalue(tv_byte); - kapply_cc(K, KINERT); -} - -/* TODO change blob constructors to string like constructors */ - -/* 13.2.8? blob-copy */ -/* TEMP: at least for now this always returns mutable blobs */ -void blob_copy(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) -{ - UNUSED(xparams); - UNUSED(denv); - bind_1tp(K, ptree, "blob", ttisblob, blob); - - TValue new_blob; - /* the if isn't strictly necessary but it's clearer this way */ - if (tv_equal(blob, K->empty_blob)) { - new_blob = blob; - } else { - new_blob = kblob_new(K, kblob_size(blob)); - memcpy(kblob_buf(new_blob), kblob_buf(blob), kblob_size(blob)); - } - kapply_cc(K, new_blob); -} - -/* 13.2.9? blob->immutable-blob */ -void blob_to_immutable_blob(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) -{ - UNUSED(xparams); - UNUSED(denv); - bind_1tp(K, ptree, "blob", ttisblob, blob); - - TValue res_blob; - if (kblob_immutablep(blob)) {/* this includes the empty blob */ - res_blob = blob; - } else { - res_blob = kblob_new_imm(K, kblob_size(blob)); - memcpy(kblob_buf(res_blob), kblob_buf(blob), kblob_size(blob)); - } - kapply_cc(K, res_blob); -} - -/* init ground */ -void kinit_blobs_ground_env(klisp_State *K) -{ - TValue ground_env = K->ground_env; - TValue symbol, value; - - /* - ** This section is not in the report. The bindings here are - ** taken from the r7rs scheme draft and should not be considered standard. - ** They are provided in the meantime to allow programs to use byte vectors. - */ - - /* ??.1.1? blob? */ - add_applicative(K, ground_env, "blob?", typep, 2, symbol, - i2tv(K_TBLOB)); - /* ??.1.2? make-blob */ - add_applicative(K, ground_env, "make-blob", make_blob, 0); - /* ??.1.3? blob-length */ - add_applicative(K, ground_env, "blob-length", blob_length, 0); - - /* ??.1.4? blob-u8-ref */ - add_applicative(K, ground_env, "blob-u8-ref", blob_u8_ref, 0); - /* ??.1.5? blob-u8-set! */ - add_applicative(K, ground_env, "blob-u8-set!", blob_u8_setS, 0); - - /* ??.1.?? blob-copy */ - add_applicative(K, ground_env, "blob-copy", blob_copy, 0); - /* ??.1.?? blob->immutable-blob */ - add_applicative(K, ground_env, "blob->immutable-blob", blob_to_immutable_blob, 0); - -/* TODO put the blob equivalents here */ -#if 0 - /* 13.2.1? string */ - add_applicative(K, ground_env, "string", string, 0); - /* 13.2.2? string=?, string-ci=? */ - add_applicative(K, ground_env, "string=?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_eqp)); - add_applicative(K, ground_env, "string-ci=?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_ci_eqp)); - /* 13.2.3? string<?, string<=?, string>?, string>=? */ - add_applicative(K, ground_env, "string<?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_ltp)); - add_applicative(K, ground_env, "string<=?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_lep)); - add_applicative(K, ground_env, "string>?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_gtp)); - add_applicative(K, ground_env, "string>=?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_gep)); - /* 13.2.4? string-ci<?, string-ci<=?, string-ci>?, string-ci>=? */ - add_applicative(K, ground_env, "string-ci<?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_ci_ltp)); - add_applicative(K, ground_env, "string-ci<=?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_ci_lep)); - add_applicative(K, ground_env, "string-ci>?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_ci_gtp)); - add_applicative(K, ground_env, "string-ci>=?", ftyped_bpredp, 3, - symbol, p2tv(kstringp), p2tv(kstring_ci_gep)); - /* 13.2.5? substring */ - add_applicative(K, ground_env, "substring", substring, 0); - /* 13.2.6? string-append */ - add_applicative(K, ground_env, "string-append", string_append, 0); - /* 13.2.7? string->list, list->string */ - add_applicative(K, ground_env, "string->list", string_to_list, 0); - add_applicative(K, ground_env, "list->string", list_to_string, 0); - /* 13.2.8? string-copy */ - add_applicative(K, ground_env, "string-copy", string_copy, 0); - /* 13.2.9? string->immutable-string */ - add_applicative(K, ground_env, "string->immutable-string", - string_to_immutable_string, 0); - - /* TODO: add string-immutable? or general immutable? */ - /* 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); -#endif -} diff --git a/src/kgblobs.h b/src/kgblobs.h @@ -1,48 +0,0 @@ -/* -** kgblobs.h -** Blobs features for the ground environment -** See Copyright Notice in klisp.h -*/ - -#ifndef kgblobs_h -#define kgblobs_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? blob? */ -/* uses typep */ - -/* ??.1.2? make-blob */ -void make_blob(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); - -/* ??.1.3? blob-length */ -void blob_length(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); - -/* ??.1.4? blob-u8-ref */ -void blob_u8_ref(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); - -/* ??.1.5? blob-u8-set! */ -void blob_u8_setS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); - -/* ??.2.?? blob-copy */ -void blob_copy(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); - -/* ??.2.?? blob->immutable-blob */ -void blob_to_immutable_blob(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); - -/* init ground */ -void kinit_blobs_ground_env(klisp_State *K); - -#endif diff --git a/src/kgbooleans.c b/src/kgbooleans.c @@ -23,8 +23,12 @@ /* uses typep */ /* 6.1.1 not? */ -void notp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void notp(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); @@ -38,8 +42,12 @@ void notp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) bool kbooleanp(TValue obj) { return ttisboolean(obj); } /* 6.1.2 and? */ -void andp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void andp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); UNUSED(denv); /* don't care about cycle pairs */ @@ -59,8 +67,12 @@ void andp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.1.3 or? */ -void orp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void orp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); UNUSED(denv); /* don't care about cycle pairs */ @@ -90,8 +102,11 @@ void orp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) ** call that is acomplished by checking if the current continuation will ** perform a boolean check, and in that case, no continuation is created */ -void do_Sandp_Sorp(klisp_State *K, TValue *xparams, TValue obj) +void do_Sandp_Sorp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: symbol name ** xparams[1]: termination boolean @@ -141,8 +156,12 @@ void do_Sandp_Sorp(klisp_State *K, TValue *xparams, TValue obj) } } -void Sandp_Sorp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Sandp_Sorp(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]: symbol name ** xparams[1]: termination boolean diff --git a/src/kgbooleans.h b/src/kgbooleans.h @@ -22,17 +22,17 @@ /* uses typep */ /* 6.1.1 not? */ -void notp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void notp(klisp_State *K); /* 6.1.2 and? */ -void andp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void andp(klisp_State *K); /* 6.1.3 or? */ -void orp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void orp(klisp_State *K); /* Helpers for $and? & $or? */ -void do_Sandp_Sorp(klisp_State *K, TValue *xparams, TValue obj); -void Sandp_Sorp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void do_Sandp_Sorp(klisp_State *K); +void Sandp_Sorp(klisp_State *K); /* 6.1.4 $and? */ /* uses Sandp_Sorp */ diff --git a/src/kgbytevectors.c b/src/kgbytevectors.c @@ -0,0 +1,379 @@ +/* +** kgbytevectors.c +** Bytevectors features for the ground environment +** See Copyright Notice in klisp.h +*/ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> + +#include "kstate.h" +#include "kobject.h" +#include "kapplicative.h" +#include "koperative.h" +#include "kcontinuation.h" +#include "kerror.h" +#include "kbytevector.h" + +#include "kghelpers.h" +#include "kgbytevectors.h" +#include "kgnumbers.h" /* for keintegerp & knegativep */ + +/* 13.1.1? bytevector? */ +/* uses typep */ + +/* 13.? immutable-bytevector?, mutable-bytevector? */ +/* use ftypep */ + +/* 13.1.2? make-bytevector */ +void make_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); + bind_al1tp(K, ptree, "exact integer", keintegerp, tv_s, + maybe_byte); + + uint8_t fill = 0; + if (get_opt_tpar(K, maybe_byte, "u8", ttisu8)) { + fill = ivalue(maybe_byte); + } + + if (knegativep(tv_s)) { + klispE_throw_simple(K, "negative size"); + return; + } else if (!ttisfixint(tv_s)) { + klispE_throw_simple(K, "size is too big"); + return; + } + TValue new_bytevector = kbytevector_new_sf(K, ivalue(tv_s), fill); + kapply_cc(K, new_bytevector); +} + +/* 13.1.3? bytevector-length */ +void bytevector_length(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, bytevector); + + TValue res = i2tv(kbytevector_size(bytevector)); + kapply_cc(K, res); +} + +/* 13.1.4? bytevector-u8-ref */ +void bytevector_u8_ref(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, + "exact integer", keintegerp, tv_i); + + if (!ttisfixint(tv_i)) { + /* TODO show index */ + klispE_throw_simple(K, "index out of bounds"); + return; + } + int32_t i = ivalue(tv_i); + + if (i < 0 || i >= kbytevector_size(bytevector)) { + /* TODO show index */ + klispE_throw_simple(K, "index out of bounds"); + return; + } + + TValue res = i2tv(kbytevector_buf(bytevector)[i]); + kapply_cc(K, res); +} + +/* 13.1.5? bytevector-u8-set! */ +void bytevector_u8_setS(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_3tp(K, ptree, "bytevector", ttisbytevector, bytevector, + "exact integer", keintegerp, tv_i, "u8", ttisu8, tv_byte); + + if (!ttisfixint(tv_i)) { + /* TODO show index */ + klispE_throw_simple(K, "index out of bounds"); + return; + } else if (kbytevector_immutablep(bytevector)) { + klispE_throw_simple(K, "immutable bytevector"); + return; + } + + int32_t i = ivalue(tv_i); + + if (i < 0 || i >= kbytevector_size(bytevector)) { + /* TODO show index */ + klispE_throw_simple(K, "index out of bounds"); + return; + } + + kbytevector_buf(bytevector)[i] = (uint8_t) ivalue(tv_byte); + kapply_cc(K, KINERT); +} + +/* 13.2.8? bytevector-copy */ +/* TEMP: at least for now this always returns mutable bytevectors */ +void bytevector_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_1tp(K, ptree, "bytevector", ttisbytevector, bytevector); + + TValue new_bytevector; + /* the if isn't strictly necessary but it's clearer this way */ + if (tv_equal(bytevector, K->empty_bytevector)) { + new_bytevector = bytevector; + } else { + new_bytevector = kbytevector_new_bs(K, kbytevector_buf(bytevector), + kbytevector_size(bytevector)); + } + kapply_cc(K, new_bytevector); +} + +/* 13.2.9? bytevector-copy! */ +void bytevector_copyS(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, bytevector1, + "bytevector", ttisbytevector, bytevector2); + + if (kbytevector_immutablep(bytevector2)) { + klispE_throw_simple(K, "immutable destination bytevector"); + return; + } else if (kbytevector_size(bytevector1) > kbytevector_size(bytevector2)) { + klispE_throw_simple(K, "destination bytevector is too small"); + return; + } + + if (!tv_equal(bytevector1, bytevector2) && + !tv_equal(bytevector1, K->empty_bytevector)) { + memcpy(kbytevector_buf(bytevector2), + kbytevector_buf(bytevector1), + kbytevector_size(bytevector1)); + } + kapply_cc(K, KINERT); +} + +/* 13.2.10? bytevector-copy-partial */ +/* TEMP: at least for now this always returns mutable bytevectors */ +void bytevector_copy_partial(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_3tp(K, ptree, "bytevector", ttisbytevector, bytevector, + "exact integer", keintegerp, tv_start, + "exact integer", keintegerp, tv_end); + + if (!ttisfixint(tv_start) || ivalue(tv_start) < 0 || + ivalue(tv_start) > kbytevector_size(bytevector)) { + /* TODO show index */ + klispE_throw_simple(K, "start index out of bounds"); + return; + } + + int32_t start = ivalue(tv_start); + + if (!ttisfixint(tv_end) || ivalue(tv_end) < 0 || + ivalue(tv_end) > kbytevector_size(bytevector)) { + klispE_throw_simple(K, "end index out of bounds"); + return; + } + + int32_t end = ivalue(tv_end); + + if (start > end) { + /* TODO show indexes */ + klispE_throw_simple(K, "end index is smaller than start index"); + return; + } + + int32_t size = end - start; + TValue new_bytevector; + /* the if isn't strictly necessary but it's clearer this way */ + if (size == 0) { + new_bytevector = K->empty_bytevector; + } else { + new_bytevector = kbytevector_new_bs(K, kbytevector_buf(bytevector) + + start, size); + } + kapply_cc(K, new_bytevector); +} + +/* 13.2.11? bytevector-copy-partial! */ +void bytevector_copy_partialS(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_al3tp(K, ptree, "bytevector", ttisbytevector, bytevector1, + "exact integer", keintegerp, tv_start, + "exact integer", keintegerp, tv_end, + rest); + + /* XXX: this will send wrong error msgs (bad number of arg) */ + bind_2tp(K, rest, + "bytevector", ttisbytevector, bytevector2, + "exact integer", keintegerp, tv_start2); + + if (!ttisfixint(tv_start) || ivalue(tv_start) < 0 || + ivalue(tv_start) > kbytevector_size(bytevector1)) { + /* TODO show index */ + klispE_throw_simple(K, "start index out of bounds"); + return; + } + + int32_t start = ivalue(tv_start); + + if (!ttisfixint(tv_end) || ivalue(tv_end) < 0 || + ivalue(tv_end) > kbytevector_size(bytevector1)) { + klispE_throw_simple(K, "end index out of bounds"); + return; + } + + int32_t end = ivalue(tv_end); + + if (start > end) { + /* TODO show indexes */ + klispE_throw_simple(K, "end index is smaller than start index"); + return; + } + + int32_t size = end - start; + + if (kbytevector_immutablep(bytevector2)) { + klispE_throw_simple(K, "immutable destination bytevector"); + return; + } + + if (!ttisfixint(tv_start2) || ivalue(tv_start2) < 0 || + ivalue(tv_start2) > kbytevector_size(bytevector2)) { + klispE_throw_simple(K, "to index out of bounds"); + return; + } + + int32_t start2 = ivalue(tv_start2); + int64_t end2 = (int64_t) start2 + size; + + if ((end2 > INT32_MAX) || + (((int32_t) end2) > kbytevector_size(bytevector2))) { + klispE_throw_simple(K, "not enough space in destination"); + return; + } + + if (size > 0) { + memcpy(kbytevector_buf(bytevector2) + start2, + kbytevector_buf(bytevector1) + start, + size); + } + kapply_cc(K, KINERT); +} + +/* 13.2.12? bytevector->immutable-bytevector */ +void bytevector_to_immutable_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); + bind_1tp(K, ptree, "bytevector", ttisbytevector, bytevector); + + TValue res_bytevector; + if (kbytevector_immutablep(bytevector)) { +/* this includes the empty bytevector */ + res_bytevector = bytevector; + } else { + res_bytevector = kbytevector_new_bs_imm(K, kbytevector_buf(bytevector), + kbytevector_size(bytevector)); + } + kapply_cc(K, res_bytevector); +} + +/* init ground */ +void kinit_bytevectors_ground_env(klisp_State *K) +{ + TValue ground_env = K->ground_env; + TValue symbol, value; + + /* + ** This section is not in the report. The bindings here are + ** taken from the r7rs scheme draft and should not be considered standard. + ** They are provided in the meantime to allow programs to use byte vectors. + */ + + /* ??.1.1? bytevector? */ + add_applicative(K, ground_env, "bytevector?", typep, 2, symbol, + i2tv(K_TBYTEVECTOR)); + /* ??.? immutable-bytevector?, mutable-bytevector? */ + add_applicative(K, ground_env, "immutable-bytevector?", ftypep, 2, symbol, + p2tv(kimmutable_bytevectorp)); + add_applicative(K, ground_env, "mutable-bytevector?", ftypep, 2, symbol, + p2tv(kmutable_bytevectorp)); + /* ??.1.2? make-bytevector */ + add_applicative(K, ground_env, "make-bytevector", make_bytevector, 0); + /* ??.1.3? bytevector-length */ + add_applicative(K, ground_env, "bytevector-length", bytevector_length, 0); + + /* ??.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, + 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); + + /* ??.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); + + /* ??.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 @@ -0,0 +1,54 @@ +/* +** kgbytevectors.h +** Bytevectors features for the ground environment +** See Copyright Notice in klisp.h +*/ + +#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); + +#endif diff --git a/src/kgc.c b/src/kgc.c @@ -20,7 +20,8 @@ #include "imrat.h" #include "ktable.h" #include "kstring.h" -#include "kblob.h" +#include "kbytevector.h" +#include "kvector.h" #include "kerror.h" #define GCSTEPSIZE 1024u @@ -106,10 +107,12 @@ static void reallymarkobject (klisp_State *K, GCObject *o) case K_TAPPLICATIVE: case K_TENCAPSULATION: case K_TPROMISE: - case K_TPORT: case K_TTABLE: case K_TERROR: - case K_TBLOB: + case K_TBYTEVECTOR: + case K_TVECTOR: + case K_TFPORT: + case K_TMPORT: o->gch.gclist = K->gray; K->gray = o; break; @@ -261,7 +264,7 @@ static int32_t propagatemark (klisp_State *K) { case K_TSTRING: { String *s = cast(String *, o); markvalue(K, s->mark); - return sizeof(String) + s->size * sizeof(char); + return sizeof(String) + (s->size + 1 * sizeof(char)); } case K_TENVIRONMENT: { Environment *e = cast(Environment *, o); @@ -301,11 +304,6 @@ static int32_t propagatemark (klisp_State *K) { markvalue(K, p->node); return sizeof(Promise); } - case K_TPORT: { - Port *p = cast(Port *, o); - markvalue(K, p->filename); - return sizeof(Port); - } case K_TTABLE: { Table *h = cast(Table *, o); if (traversetable(K, h)) /* table is weak? */ @@ -321,10 +319,27 @@ static int32_t propagatemark (klisp_State *K) { markvalue(K, e->irritants); return sizeof(Error); } - case K_TBLOB: { - Blob *b = cast(Blob *, o); + case K_TBYTEVECTOR: { + Bytevector *b = cast(Bytevector *, o); markvalue(K, b->mark); - return sizeof(String) + b->size * sizeof(uint8_t); + return sizeof(Bytevector) + b->size * sizeof(uint8_t); + } + case K_TFPORT: { + FPort *p = cast(FPort *, o); + markvalue(K, p->filename); + return sizeof(FPort); + } + case K_TMPORT: { + MPort *p = cast(MPort *, o); + markvalue(K, p->filename); + markvalue(K, p->buf); + return sizeof(MPort); + } + case K_TVECTOR: { + Vector *v = cast(Vector *, o); + markvalue(K, v->mark); + markvaluearray(K, v->array, v->sizearray); + return sizeof(Vector) + v->sizearray * sizeof(TValue); } default: fprintf(stderr, "Unknown GCObject type (in GC propagate): %d\n", @@ -347,6 +362,8 @@ static size_t propagateall (klisp_State *K) { ** other objects: if really collected, cannot keep them; for userdata ** being finalized, keep them in keys, but not in values */ +/* XXX what the hell is this, I should reread this part of the lua + source Andres Navarro */ static int32_t iscleared (TValue o, int iskey) { if (!iscollectable(o)) return 0; #if 0 /* klisp: strings may be mutable... */ @@ -441,24 +458,35 @@ static void freeobj (klisp_State *K, GCObject *o) { case K_TPROMISE: klispM_free(K, (Promise *)o); break; - case K_TPORT: - /* first close the port to free the FILE structure. - This works even if the port was already closed, - it is important that this don't throw errors, because - the mechanism used in error handling would crash at this - point */ - kclose_port(K, gc2port(o)); - klispM_free(K, (Port *)o); - break; case K_TTABLE: klispH_free(K, (Table *)o); break; case K_TERROR: klispE_free(K, (Error *)o); break; - case K_TBLOB: - klispM_freemem(K, o, sizeof(Blob)+o->blob.size); + case K_TBYTEVECTOR: + /* immutable bytevectors are in the string/symbol table */ + if (kbytevector_immutablep(gc2str(o))) + K->strt.nuse--; + klispM_freemem(K, o, sizeof(Bytevector)+o->bytevector.size); break; + case K_TFPORT: + /* first close the port to free the FILE structure. + This works even if the port was already closed, + it is important that this don't throw errors, because + the mechanism used in error handling would crash at this + point */ + kclose_port(K, gc2fport(o)); + klispM_free(K, (FPort *)o); + break; + case K_TMPORT: + /* memory ports (string & bytevector) don't need to be closed + explicitly */ + klispM_free(K, (MPort *)o); + break; + case K_TVECTOR: + klispM_freemem(K, o, sizeof(Vector) + sizeof(TValue) * o->vector.sizearray); + break; default: /* shouldn't happen */ fprintf(stderr, "Unknown GCObject type (in GC free): %d\n", @@ -552,7 +580,7 @@ void klispC_freeall (klisp_State *K) { K->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* in klisp this may not be necessary */ sweepwholelist(K, &K->rootgc); - /* free all symbol/string lists */ + /* free all symbol/string/bytevectors lists */ for (int32_t i = 0; i < K->strt.size; i++) sweepwholelist(K, &K->strt.hash[i]); } @@ -564,7 +592,7 @@ static void markroot (klisp_State *K) { K->grayagain = NULL; K->weak = NULL; - /* TEMP: this is quite awfull, think of other way to do this */ + /* TEMP: this is quite awful, think of other way to do this */ /* MAYBE: some of these could be FIXED */ markvalue(K, K->name_table); markvalue(K, K->cont_name_table); @@ -587,13 +615,17 @@ static void markroot (klisp_State *K) { markvalue(K, K->kd_error_port_key); markvalue(K, K->kd_strict_arith_key); markvalue(K, K->empty_string); - markvalue(K, K->empty_blob); + markvalue(K, K->empty_bytevector); + markvalue(K, K->empty_vector); markvalue(K, K->ktok_lparen); markvalue(K, K->ktok_rparen); markvalue(K, K->ktok_dot); + markvalue(K, K->ktok_sexp_comment); markvalue(K, K->shared_dict); + markvalue(K, K->curr_port); + /* Mark all objects in the auxiliary stack, (all valid indexes are below top), all the objects in the two protected areas, and the three dummy pairs */ @@ -778,7 +810,8 @@ void klispC_barrierback (klisp_State *K, Table *t) { } /* NOTE: kflags is added for klisp */ -/* NOTE: both symbols & strings do this "by hand", they don't call this */ +/* NOTE: symbols, immutable strings and immutable bytevectors do this + "by hand", they don't call this */ void klispC_link (klisp_State *K, GCObject *o, uint8_t tt, uint8_t kflags) { o->gch.next = K->rootgc; K->rootgc = o; diff --git a/src/kgchars.c b/src/kgchars.c @@ -39,9 +39,12 @@ 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, TValue *xparams, TValue ptree, - TValue denv) +void kchar_to_integer(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, ch); @@ -49,9 +52,12 @@ void kchar_to_integer(klisp_State *K, TValue *xparams, TValue ptree, kapply_cc(K, i2tv((int32_t) chvalue(ch))); } -void kinteger_to_char(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kinteger_to_char(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); UNUSED(denv); bind_1tp(K, ptree, "exact integer", ttiseinteger, itv); @@ -71,9 +77,12 @@ void kinteger_to_char(klisp_State *K, TValue *xparams, TValue ptree, } /* 14.1.4? char-upcase, char-downcase */ -void kchar_upcase(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +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); @@ -82,9 +91,12 @@ void kchar_upcase(klisp_State *K, TValue *xparams, TValue ptree, kapply_cc(K, ch2tv(ch)); } -void kchar_downcase(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kchar_downcase(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); diff --git a/src/kgchars.h b/src/kgchars.h @@ -38,16 +38,12 @@ 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, TValue *xparams, TValue ptree, - TValue denv); -void kinteger_to_char(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +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, TValue *xparams, TValue ptree, - TValue denv); -void kchar_downcase(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void kchar_upcase(klisp_State *K); +void kchar_downcase(klisp_State *K); /* 14.2.1? char=? */ /* uses ftyped_bpredp */ diff --git a/src/kgcombiners.c b/src/kgcombiners.c @@ -27,7 +27,7 @@ #include "kgcombiners.h" /* Helper (used by $vau & $lambda) */ -void do_vau(klisp_State *K, TValue *xparams, TValue obj, TValue denv); +void do_vau(klisp_State *K); /* 4.10.1 operative? */ /* uses typep */ @@ -37,8 +37,12 @@ void do_vau(klisp_State *K, TValue *xparams, TValue obj, TValue denv); /* 4.10.3 $vau */ /* 5.3.1 $vau */ -void Svau(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Svau(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) xparams; bind_al2p(K, ptree, vptree, vpenv, vbody); @@ -71,15 +75,22 @@ void Svau(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, new_op); } -void do_vau(klisp_State *K, TValue *xparams, TValue obj, TValue denv) +void do_vau(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + UNUSED(denv); + /* - ** xparams[0]: ptree + ** xparams[0]: op_ptree ** xparams[1]: penv ** xparams[2]: body ** xparams[3]: senv */ - TValue ptree = xparams[0]; + TValue op_ptree = xparams[0]; TValue penv = xparams[1]; TValue body = xparams[2]; TValue senv = xparams[3]; @@ -91,7 +102,7 @@ void do_vau(klisp_State *K, TValue *xparams, TValue obj, TValue denv) krooted_tvs_push(K, env); /* TODO use name from operative */ - match(K, "[user-operative]", env, ptree, obj); + match(K, "[user-operative]", env, op_ptree, ptree); if (!ttisignore(penv)) kadd_binding(K, env, penv, denv); @@ -120,8 +131,12 @@ void do_vau(klisp_State *K, TValue *xparams, TValue obj, TValue denv) } /* 4.10.4 wrap */ -void wrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void wrap(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -141,8 +156,12 @@ void wrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 4.10.5 unwrap */ -void unwrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void unwrap(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; (void) xparams; bind_1tp(K, ptree, "applicative", ttisapplicative, app); @@ -153,8 +172,12 @@ void unwrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 5.3.1 $vau */ /* DONE: above, together with 4.10.4 */ /* 5.3.2 $lambda */ -void Slambda(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Slambda(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) xparams; bind_al1p(K, ptree, vptree, vbody); @@ -188,9 +211,12 @@ void Slambda(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 5.5.1 apply */ -void apply(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void apply(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -199,7 +225,7 @@ void apply(klisp_State *K, TValue *xparams, TValue ptree, "any", anytype, obj, maybe_env); - TValue env = (get_opt_tpar(K, "apply", K_TENVIRONMENT, &maybe_env))? + TValue env = (get_opt_tpar(K, maybe_env, "environment", ttisenvironment))? maybe_env : kmake_empty_environment(K); krooted_tvs_push(K, env); @@ -411,8 +437,11 @@ TValue map_for_each_transpose(klisp_State *K, TValue lss, /* Continuation helpers for map */ /* For acyclic input lists: Return the mapped list */ -void do_map_ret(klisp_State *K, TValue *xparams, TValue obj) +void do_map_ret(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: (dummy . complete-ls) */ @@ -427,8 +456,11 @@ void do_map_ret(klisp_State *K, TValue *xparams, TValue obj) } /* For cyclic input list: close the cycle and return the mapped list */ -void do_map_encycle(klisp_State *K, TValue *xparams, TValue obj) +void do_map_encycle(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: (dummy . complete-ls) ** xparams[1]: last non-cycle pair @@ -450,8 +482,11 @@ void do_map_encycle(klisp_State *K, TValue *xparams, TValue obj) kapply_cc(K, copy); } -void do_map(klisp_State *K, TValue *xparams, TValue obj) +void do_map(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: app ** xparams[1]: rem-ls @@ -499,8 +534,11 @@ void do_map(klisp_State *K, TValue *xparams, TValue obj) } } -void do_map_cycle(klisp_State *K, TValue *xparams, TValue obj) +void do_map_cycle(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: app ** xparams[1]: (dummy . res-list) @@ -528,7 +566,9 @@ void do_map_cycle(klisp_State *K, TValue *xparams, TValue obj) the inert value passed to the first continuation */ TValue new_cont = kmake_continuation(K, encycle_cont, do_map, 6, app, ls, - last_apair, cpairs, denv, KTRUE); + last_apair, i2tv(cpairs), denv, KTRUE); + klisp_assert(ttisenvironment(denv)); + krooted_tvs_pop(K); kset_cc(K, new_cont); /* this will be like a nop and will continue with do_map */ @@ -536,8 +576,12 @@ void do_map_cycle(klisp_State *K, TValue *xparams, TValue obj) } /* 5.9.1 map */ -void map(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void map(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_al1tp(K, ptree, "applicative", ttisapplicative, app, lss); @@ -577,7 +621,6 @@ void map(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) : kmake_continuation(K, kget_cc(K), do_map_cycle, 4, app, dummy, i2tv(res_cpairs), denv); - krooted_tvs_push(K, ret_cont); /* schedule the mapping of the elements of the acyclic part. @@ -592,6 +635,7 @@ void map(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) krooted_tvs_pop(K); kset_cc(K, new_cont); + /* this will be a nop, and will continue with do_map */ kapply_cc(K, KINERT); } diff --git a/src/kgcombiners.h b/src/kgcombiners.h @@ -26,23 +26,22 @@ /* 4.10.3 $vau */ /* 5.3.1 $vau */ -void Svau(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Svau(klisp_State *K); /* 4.10.4 wrap */ -void wrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void wrap(klisp_State *K); /* 4.10.5 unwrap */ -void unwrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void unwrap(klisp_State *K); /* 5.3.1 $vau */ /* DONE: above, together with 4.10.4 */ /* 5.3.2 $lambda */ -void Slambda(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Slambda(klisp_State *K); /* 5.5.1 apply */ -void apply(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void apply(klisp_State *K); /* Helpers for map (also used by for each) */ @@ -69,7 +68,7 @@ TValue map_for_each_transpose(klisp_State *K, TValue lss, int32_t res_apairs, int32_t res_cpairs); /* 5.9.1 map */ -void map(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void map(klisp_State *K); /* 6.2.1 combiner? */ /* uses ftypedp */ @@ -78,11 +77,11 @@ void map(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); bool kcombinerp(TValue obj); -void do_vau(klisp_State *K, TValue *xparams, TValue obj, TValue denv); -void do_map_ret(klisp_State *K, TValue *xparams, TValue obj); -void do_map_encycle(klisp_State *K, TValue *xparams, TValue obj); -void do_map(klisp_State *K, TValue *xparams, TValue obj); -void do_map_cycle(klisp_State *K, TValue *xparams, TValue obj); +void do_vau(klisp_State *K); +void do_map_ret(klisp_State *K); +void do_map_encycle(klisp_State *K); +void do_map(klisp_State *K); +void do_map_cycle(klisp_State *K); /* init ground */ void kinit_combiners_ground_env(klisp_State *K); diff --git a/src/kgcontinuations.c b/src/kgcontinuations.c @@ -28,8 +28,12 @@ /* uses typep */ /* 7.2.2 call/cc */ -void call_cc(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void call_cc(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_1tp(K, ptree, "combiner", ttiscombiner, comb); @@ -38,8 +42,11 @@ void call_cc(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper for extend-continuation */ -void do_extended_cont(klisp_State *K, TValue *xparams, TValue obj) +void do_extended_cont(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: applicative ** xparams[1]: environment @@ -53,9 +60,12 @@ void do_extended_cont(klisp_State *K, TValue *xparams, TValue obj) } /* 7.2.3 extend-continuation */ -void extend_continuation(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void extend_continuation(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -64,7 +74,7 @@ void extend_continuation(klisp_State *K, TValue *xparams, TValue ptree, "applicative", ttisapplicative, app, maybe_env); - TValue env = (get_opt_tpar(K, "apply", K_TENVIRONMENT, &maybe_env))? + TValue env = (get_opt_tpar(K, maybe_env, "environment", ttisenvironment))? maybe_env : kmake_empty_environment(K); krooted_tvs_push(K, env); @@ -80,8 +90,11 @@ void extend_continuation(klisp_State *K, TValue *xparams, TValue ptree, passes the value. xparams is not actually empty, it contains the entry/exit guards, but they are used only in continuation->applicative (that is during abnormal passes) */ -void do_pass_value(klisp_State *K, TValue *xparams, TValue obj) +void do_pass_value(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); UNUSED(xparams); kapply_cc(K, obj); } @@ -158,9 +171,12 @@ TValue check_copy_guards(klisp_State *K, char *name, TValue obj) } /* 7.2.4 guard-continuation */ -void guard_continuation(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void guard_continuation(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_3tp(K, ptree, "any", anytype, entry_guards, @@ -194,10 +210,16 @@ void guard_continuation(klisp_State *K, TValue *xparams, TValue ptree, /* 7.2.5 continuation->applicative */ -void continuation_applicative(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void continuation_applicative(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, "continuation", ttiscontinuation, cont); /* cont_app is from kstate, it handles dynamic vars & @@ -217,9 +239,12 @@ void continuation_applicative(klisp_State *K, TValue *xparams, TValue ptree, */ /* 7.3.1 apply-continuation */ -void apply_continuation(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void apply_continuation(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); @@ -232,9 +257,12 @@ void apply_continuation(klisp_State *K, TValue *xparams, TValue ptree, } /* 7.3.2 $let/cc */ -void Slet_cc(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void Slet_cc(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); /* from the report: #ignore is not ok, only symbol */ bind_al1tp(K, ptree, "symbol", ttissymbol, sym, objs); @@ -272,9 +300,12 @@ void Slet_cc(klisp_State *K, TValue *xparams, TValue ptree, } /* 7.3.3 guard-dynamic-extent */ -void guard_dynamic_extent(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void guard_dynamic_extent(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_3tp(K, ptree, "any", anytype, entry_guards, @@ -310,9 +341,12 @@ void guard_dynamic_extent(klisp_State *K, TValue *xparams, TValue ptree, } /* 7.3.4 exit */ -void kgexit(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kgexit(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -344,11 +378,13 @@ void kinit_continuations_ground_env(klisp_State *K) add_applicative(K, ground_env, "continuation->applicative", continuation_applicative, 0); /* 7.2.6 root-continuation */ + klisp_assert(ttiscontinuation(K->root_cont)); add_value(K, ground_env, "root-continuation", K->root_cont); /* 7.2.7 error-continuation */ + klisp_assert(ttiscontinuation(K->error_cont)); add_value(K, ground_env, "error-continuation", - K->root_cont); + K->error_cont); /* 7.3.1 apply-continuation */ add_applicative(K, ground_env, "apply-continuation", apply_continuation, 0); diff --git a/src/kgcontinuations.h b/src/kgcontinuations.h @@ -19,25 +19,22 @@ #include "kghelpers.h" /* Helpers (also used in keyed dynamic code) */ -void do_pass_value(klisp_State *K, TValue *xparams, TValue obj); +void do_pass_value(klisp_State *K); /* 7.1.1 continuation? */ /* uses typep */ /* 7.2.2 call/cc */ -void call_cc(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void call_cc(klisp_State *K); /* 7.2.3 extend-continuation */ -void extend_continuation(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void extend_continuation(klisp_State *K); /* 7.2.4 guard-continuation */ -void guard_continuation(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void guard_continuation(klisp_State *K); /* 7.2.5 continuation->applicative */ -void continuation_applicative(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void continuation_applicative(klisp_State *K); /* 7.2.6 root-continuation */ /* done in kground.c/krepl.c */ @@ -46,23 +43,18 @@ void continuation_applicative(klisp_State *K, TValue *xparams, TValue ptree, /* done in kground.c/krepl.c */ /* 7.3.1 apply-continuation */ -void apply_continuation(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void apply_continuation(klisp_State *K); /* 7.3.2 $let/cc */ -void Slet_cc(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void Slet_cc(klisp_State *K); /* 7.3.3 guard-dynamic-extent */ -void guard_dynamic_extent(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void guard_dynamic_extent(klisp_State *K); /* 7.3.4 exit */ -void kgexit(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void kgexit(klisp_State *K); -void do_extended_cont(klisp_State *K, TValue *xparams, TValue obj); -void do_pass_value(klisp_State *K, TValue *xparams, TValue obj); +void do_extended_cont(klisp_State *K); /* init ground */ void kinit_continuations_ground_env(klisp_State *K); diff --git a/src/kgcontrol.c b/src/kgcontrol.c @@ -26,11 +26,15 @@ /* 4.5.2 $if */ /* helpers */ -void do_select_clause(klisp_State *K, TValue *xparams, TValue obj); +void do_select_clause(klisp_State *K); /* ASK JOHN: both clauses should probably be copied (copy-es-immutable) */ -void Sif(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Sif(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; (void) xparams; @@ -48,8 +52,11 @@ void Sif(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) ktail_eval(K, test, denv); } -void do_select_clause(klisp_State *K, TValue *xparams, TValue obj) +void do_select_clause(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: dynamic env ** xparams[1]: consequent clause @@ -66,8 +73,12 @@ void do_select_clause(klisp_State *K, TValue *xparams, TValue obj) } /* 5.1.1 $sequence */ -void Ssequence(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Ssequence(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); if (ttisnil(ptree)) { @@ -98,9 +109,15 @@ void Ssequence(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper (also used by $vau and $lambda) */ -/* the ramaining list can't be null, that case is managed before */ -void do_seq(klisp_State *K, TValue *xparams, TValue obj) +/* the remaining list can't be null, that case is managed before */ +void do_seq(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + + UNUSED(obj); + /* ** xparams[0]: remaining list ** xparams[1]: dynamic environment @@ -198,8 +215,11 @@ TValue split_check_cond_clauses(klisp_State *K, TValue clauses, } /* Helper for the $cond continuation */ -void do_cond(klisp_State *K, TValue *xparams, TValue obj) +void do_cond(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: the body corresponding to obj ** xparams[1]: remaining tests @@ -258,8 +278,12 @@ void do_cond(klisp_State *K, TValue *xparams, TValue obj) } /* 5.6.1 $cond */ -void Scond(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Scond(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) xparams; TValue bodies; @@ -289,8 +313,11 @@ void Scond(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper continuation for for-each */ -void do_for_each(klisp_State *K, TValue *xparams, TValue obj) +void do_for_each(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: app ** xparams[1]: rem-ls @@ -329,8 +356,12 @@ void do_for_each(klisp_State *K, TValue *xparams, TValue obj) } /* 6.9.1 for-each */ -void for_each(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void for_each(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) xparams; bind_al1tp(K, ptree, "applicative", ttisapplicative, app, lss); diff --git a/src/kgcontrol.h b/src/kgcontrol.h @@ -23,10 +23,10 @@ /* 4.5.2 $if */ -void Sif(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Sif(klisp_State *K); /* 5.1.1 $sequence */ -void Ssequence(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Ssequence(klisp_State *K); /* Helpers for $cond */ TValue split_check_cond_clauses(klisp_State *K, TValue clauses, @@ -34,15 +34,15 @@ TValue split_check_cond_clauses(klisp_State *K, TValue clauses, /* 5.6.1 $cond */ -void Scond(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Scond(klisp_State *K); /* 6.9.1 for-each */ -void for_each(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void for_each(klisp_State *K); -void do_seq(klisp_State *K, TValue *xparams, TValue obj); -void do_cond(klisp_State *K, TValue *xparams, TValue obj); -void do_select_clause(klisp_State *K, TValue *xparams, TValue obj); -void do_for_each(klisp_State *K, TValue *xparams, TValue obj); +void do_seq(klisp_State *K); +void do_cond(klisp_State *K); +void do_select_clause(klisp_State *K); +void do_for_each(klisp_State *K); /* init ground */ void kinit_control_ground_env(klisp_State *K); diff --git a/src/kgencapsulations.c b/src/kgencapsulations.c @@ -23,8 +23,12 @@ /* Helpers for make-encapsulation-type */ /* Type predicate for encapsulations */ -void enc_typep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void enc_typep(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: encapsulation key @@ -54,8 +58,12 @@ void enc_typep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Constructor for encapsulations */ -void enc_wrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void enc_wrap(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); bind_1p(K, ptree, obj); UNUSED(denv); /* @@ -67,8 +75,12 @@ void enc_wrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Accessor for encapsulations */ -void enc_unwrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void enc_unwrap(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); bind_1p(K, ptree, enc); UNUSED(denv); /* @@ -86,9 +98,12 @@ void enc_unwrap(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 8.1.1 make-encapsulation-type */ -void make_encapsulation_type(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void make_encapsulation_type(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); check_0p(K, ptree); UNUSED(denv); UNUSED(xparams); diff --git a/src/kgencapsulations.h b/src/kgencapsulations.h @@ -19,11 +19,10 @@ #include "kghelpers.h" /* needed by kgffi.c */ -void enc_typep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void enc_typep(klisp_State *K); /* 8.1.1 make-encapsulation-type */ -void make_encapsulation_type(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void make_encapsulation_type(klisp_State *K); /* init ground */ void kinit_encapsulations_ground_env(klisp_State *K); diff --git a/src/kgenv_mut.c b/src/kgenv_mut.c @@ -23,8 +23,12 @@ #include "kgcontrol.h" /* for do_seq */ /* 4.9.1 $define! */ -void SdefineB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void SdefineB(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] = define symbol */ @@ -45,8 +49,11 @@ void SdefineB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* helper */ -void do_match(klisp_State *K, TValue *xparams, TValue obj) +void do_match(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: ptree ** xparams[1]: dynamic environment @@ -61,8 +68,12 @@ void do_match(klisp_State *K, TValue *xparams, TValue obj) } /* 6.8.1 $set! */ -void SsetB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void SsetB(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); TValue sname = xparams[0]; @@ -82,8 +93,11 @@ void SsetB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helpers for $set! */ -void do_set_eval_obj(klisp_State *K, TValue *xparams, TValue obj) +void do_set_eval_obj(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: name as symbol ** xparams[1]: ptree @@ -169,8 +183,11 @@ TValue check_copy_symbol_list(klisp_State *K, char *name, TValue obj) return kcutoff_dummy1(K); } -void do_import(klisp_State *K, TValue *xparams, TValue obj) +void do_import(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: name as symbol ** xparams[1]: symbols @@ -195,8 +212,12 @@ void do_import(klisp_State *K, TValue *xparams, TValue obj) } /* 6.8.2 $provide! */ -void SprovideB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void SprovideB(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]: name as symbol */ @@ -251,8 +272,12 @@ void SprovideB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.8.3 $import! */ -void SimportB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void SimportB(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: The report says that symbols can have repeated symbols and even be cyclical (cf $provide!) however this doesn't work in the derivation (that uses $set! and so needs a ptree, which are diff --git a/src/kgenv_mut.h b/src/kgenv_mut.h @@ -21,12 +21,12 @@ /* helpers */ inline void match(klisp_State *K, char *name, TValue env, TValue ptree, TValue obj); -void do_match(klisp_State *K, TValue *xparams, TValue obj); +void do_match(klisp_State *K); inline void ptree_clear_all(klisp_State *K, TValue sym_ls); inline TValue check_copy_ptree(klisp_State *K, char *name, TValue ptree, TValue penv); /* 4.9.1 $define! */ -void SdefineB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void SdefineB(klisp_State *K); /* MAYBE: don't make these inline */ /* @@ -235,20 +235,20 @@ inline TValue check_copy_ptree(klisp_State *K, char *name, TValue ptree, } /* 6.8.1 $set! */ -void SsetB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void SsetB(klisp_State *K); /* Helper for $set! */ -void do_set_eval_obj(klisp_State *K, TValue *xparams, TValue obj); +void do_set_eval_obj(klisp_State *K); /* Helpers for $provide & $import! */ TValue check_copy_symbol_list(klisp_State *K, char *name, TValue obj); -void do_import(klisp_State *K, TValue *xparams, TValue obj); +void do_import(klisp_State *K); /* 6.8.2 $provide! */ -void SprovideB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void SprovideB(klisp_State *K); /* 6.8.3 $import! */ -void SimportB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void SimportB(klisp_State *K); /* init ground */ void kinit_env_mut_ground_env(klisp_State *K); diff --git a/src/kgenvironments.c b/src/kgenvironments.c @@ -32,9 +32,12 @@ /* uses typep */ /* 4.8.3 eval */ -void eval(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void eval(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -45,9 +48,12 @@ void eval(klisp_State *K, TValue *xparams, TValue ptree, } /* 4.8.4 make-environment */ -void make_environment(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void make_environment(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -156,8 +162,11 @@ TValue split_check_let_bindings(klisp_State *K, char *name, TValue bindings, ** it expects the result of the last evaluation to be matched to ** this-ptree */ -void do_let(klisp_State *K, TValue *xparams, TValue obj) +void do_let(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: symbol name ** xparams[1]: this ptree @@ -203,7 +212,7 @@ void do_let(klisp_State *K, TValue *xparams, TValue obj) TValue new_cont = kmake_continuation(K, kget_cc(K), do_let, 7, sname, kcar(bindings), kcdr(bindings), kcdr(exprs), - new_env, b2tv(false), body); + new_env, b2tv(recp), body); krooted_tvs_pop(K); kset_cc(K, new_cont); ktail_eval(K, kcar(exprs), recp? new_env : env); @@ -212,8 +221,12 @@ void do_let(klisp_State *K, TValue *xparams, TValue obj) /* 5.10.1 $let */ /* REFACTOR: reuse code in other members of the $let family */ -void Slet(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Slet(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]: symbol name */ @@ -248,8 +261,11 @@ void Slet(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper for $binds? */ -void do_bindsp(klisp_State *K, TValue *xparams, TValue obj) +void do_bindsp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: symbol list (may contain cycles) ** xparams[1]: symbol list count @@ -278,8 +294,12 @@ void do_bindsp(klisp_State *K, TValue *xparams, TValue obj) } /* 6.7.1 $binds? */ -void Sbindsp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Sbindsp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_al1p(K, ptree, env_expr, symbols); @@ -297,29 +317,41 @@ void Sbindsp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.7.2 get-current-environment */ -void get_current_environment(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void get_current_environment(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); check_0p(K, ptree); kapply_cc(K, denv); } /* 6.7.3 make-kernel-standard-environment */ -void make_kernel_standard_environment(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void make_kernel_standard_environment(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_0p(K, ptree); - TValue new_env = kmake_environment(K, K->ground_env); + /* std environments have hashtable for bindings */ + TValue new_env = kmake_table_environment(K, K->ground_env); +// TValue new_env = kmake_environment(K, K->ground_env); kapply_cc(K, new_env); } /* 6.7.4 $let* */ -void SletS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void SletS(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]: symbol name */ @@ -367,8 +399,12 @@ void SletS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.7.5 $letrec */ -void Sletrec(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Sletrec(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]: symbol name */ @@ -404,8 +440,12 @@ void Sletrec(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.7.6 $letrec* */ -void SletrecS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void SletrecS(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]: symbol name */ @@ -454,8 +494,11 @@ void SletrecS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper for $let-redirect */ -void do_let_redirect(klisp_State *K, TValue *xparams, TValue obj) +void do_let_redirect(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: symbol name ** xparams[1]: ptree @@ -485,8 +528,12 @@ void do_let_redirect(klisp_State *K, TValue *xparams, TValue obj) } /* 6.7.7 $let-redirect */ -void Slet_redirect(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Slet_redirect(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]: symbol name */ @@ -520,8 +567,12 @@ void Slet_redirect(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.7.8 $let-safe */ -void Slet_safe(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Slet_safe(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]: symbol name */ @@ -559,8 +610,12 @@ void Slet_safe(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.7.9 $remote-eval */ -void Sremote_eval(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Sremote_eval(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); @@ -574,8 +629,11 @@ void Sremote_eval(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper for $remote-eval */ -void do_remote_eval(klisp_State *K, TValue *xparams, TValue obj) +void do_remote_eval(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); if (!ttisenvironment(obj)) { klispE_throw_simple(K, "bad type from second operand " "evaluation (expected environment)"); @@ -587,8 +645,11 @@ void do_remote_eval(klisp_State *K, TValue *xparams, TValue obj) } /* Helper for $bindings->environment */ -void do_b_to_env(klisp_State *K, TValue *xparams, TValue obj) +void do_b_to_env(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: ptree ** xparams[1]: created env @@ -601,9 +662,12 @@ void do_b_to_env(klisp_State *K, TValue *xparams, TValue obj) } /* 6.7.10 $bindings->environment */ -void Sbindings_to_environment(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void Sbindings_to_environment(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); TValue exprs; TValue bptree = split_check_let_bindings(K, "$bindings->environment", diff --git a/src/kgenvironments.h b/src/kgenvironments.h @@ -25,65 +25,60 @@ /* uses typep */ /* 4.8.3 eval */ -void eval(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void eval(klisp_State *K); /* 4.8.4 make-environment */ -void make_environment(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void make_environment(klisp_State *K); /* Helpers for all $let family */ TValue split_check_let_bindings(klisp_State *K, char *name, TValue bindings, TValue *exprs, bool starp); /* 5.10.1 $let */ -void Slet(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Slet(klisp_State *K); /* Helper for $binds? */ -void do_bindsp(klisp_State *K, TValue *xparams, TValue obj); +void do_bindsp(klisp_State *K); /* 6.7.1 $binds? */ -void Sbindsp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Sbindsp(klisp_State *K); /* 6.7.2 get-current-environment */ -void get_current_environment(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void get_current_environment(klisp_State *K); /* 6.7.3 make-kernel-standard-environment */ -void make_kernel_standard_environment(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); +void make_kernel_standard_environment(klisp_State *K); /* 6.7.4 $let* */ -void SletS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void SletS(klisp_State *K); /* 6.7.5 $letrec */ -void Sletrec(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Sletrec(klisp_State *K); /* 6.7.6 $letrec* */ -void SletrecS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void SletrecS(klisp_State *K); /* Helper for $let-redirect */ -void do_let_redirect(klisp_State *K, TValue *xparams, TValue obj); +void do_let_redirect(klisp_State *K); /* 6.7.7 $let-redirect */ -void Slet_redirect(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Slet_redirect(klisp_State *K); /* 6.7.8 $let-safe */ -void Slet_safe(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Slet_safe(klisp_State *K); /* 6.7.9 $remote-eval */ -void Sremote_eval(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Sremote_eval(klisp_State *K); /* Helper for $remote-eval */ -void do_remote_eval(klisp_State *K, TValue *xparams, TValue obj); +void do_remote_eval(klisp_State *K); /* Helper for $bindings->environment */ -void do_b_to_env(klisp_State *K, TValue *xparams, TValue obj); +void do_b_to_env(klisp_State *K); /* 6.7.10 $bindings->environment */ -void Sbindings_to_environment(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void Sbindings_to_environment(klisp_State *K); -void do_let(klisp_State *K, TValue *xparams, TValue obj); +void do_let(klisp_State *K); /* init ground */ void kinit_environments_ground_env(klisp_State *K); diff --git a/src/kgeqp.c b/src/kgeqp.c @@ -22,8 +22,12 @@ /* 4.2.1 eq? */ /* 6.5.1 eq? */ /* NOTE: this does 2 passes but could do it in one */ -void eqp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void eqp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); diff --git a/src/kgeqp.h b/src/kgeqp.h @@ -23,13 +23,11 @@ /* 4.2.1 eq? */ /* 6.5.1 eq? */ -void eqp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void eqp(klisp_State *K); /* Helper (also used in equal?) */ inline bool eq2p(klisp_State *K, TValue obj1, TValue obj2) { - /* TODO/FIXME: immutable blobs aren't interned and so will compare - as un-eq? even if the contents are the same */ bool res = (tv_equal(obj1, obj2)); if (!res && (ttype(obj1) == ttype(obj2))) { switch (ttype(obj1)) { @@ -56,7 +54,9 @@ inline bool eq2p(klisp_State *K, TValue obj1, TValue obj2) (eq? obj1 obj2) */ res = kbigrat_eqp(K, obj1, obj2); break; - } /* immutable strings are interned so are covered already */ + } /* immutable strings & bytevectors are interned so they are + covered already by tv_equalp */ + } return res; } diff --git a/src/kgequalp.c b/src/kgequalp.c @@ -14,7 +14,7 @@ #include "kobject.h" #include "kpair.h" #include "kstring.h" /* for kstring_equalp */ -#include "kblob.h" /* for kblob_equalp */ +#include "kbytevector.h" /* for kbytevector_equalp */ #include "kcontinuation.h" #include "kerror.h" @@ -34,8 +34,12 @@ ** Idea to look up these papers from srfi 85: ** "Recursive Equivalence Predicates" by William D. Clinger */ -void equalp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void equalp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -197,11 +201,14 @@ bool equal2p(klisp_State *K, TValue obj1, TValue obj2) result = false; break; } - } else if (ttisblob(obj1) && ttisblob(obj2)) { - if (!kblob_equalp(obj1, obj2)) { + } else if (ttisbytevector(obj1) && ttisbytevector(obj2)) { + if (!kbytevector_equalp(obj1, obj2)) { result = false; break; } + } else if (ttisvector(obj1) && ttisvector(obj2)) { + fprintf(stderr, "TODO: equal? for vectors not implemented!\n"); + result = false; } else { result = false; break; diff --git a/src/kgequalp.h b/src/kgequalp.h @@ -20,7 +20,7 @@ /* 4.3.1 equal? */ /* 6.6.1 equal? */ -void equalp(klisp_State *K, TValue *xparas, TValue ptree, TValue denv); +void equalp(klisp_State *K); /* Helper (may be used in assoc and member) */ /* compare two objects and check to see if they are "equal?". */ diff --git a/src/kgerror.c b/src/kgerror.c @@ -4,7 +4,6 @@ ** See Copyright Notice in klisp.h */ -#include <assert.h> #include <stdbool.h> #include <stdint.h> @@ -17,9 +16,12 @@ #include "kghelpers.h" #include "kgerror.h" -void r7rs_error(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +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))) { @@ -29,45 +31,52 @@ void r7rs_error(klisp_State *K, TValue *xparams, TValue ptree, } } -void error_object_message(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +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); - assert(ttisstring(err_obj->msg)); + klisp_assert(ttisstring(err_obj->msg)); kapply_cc(K, err_obj->msg); } -void error_object_irritants(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +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); } - -void do_exception_cont(klisp_State *K, TValue *xparams, TValue obj) +/* 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) { - assert(ttiscontinuation(K->error_cont)); - assert(ttisinert(K->system_error_cont)); + 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); - TValue symbol = ksymbol_new(K, "system-error-continuation", KNIL); - krooted_tvs_push(K, symbol); - kadd_binding(K, K->ground_env, symbol, K->system_error_cont); - krooted_tvs_pop(K); + K->system_error_cont = kmake_continuation(K, K->error_cont, + do_exception_cont, 0); } /* init ground */ @@ -80,4 +89,7 @@ void kinit_error_ground_env(klisp_State *K) 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/kgffi.c b/src/kgffi.c @@ -36,7 +36,7 @@ #include "kinteger.h" #include "kpair.h" #include "kerror.h" -#include "kblob.h" +#include "kbytevector.h" #include "kencapsulation.h" #include "ktable.h" @@ -123,8 +123,8 @@ static TValue ffi_decode_pointer(ffi_codec_t *self, klisp_State *K, const void * static void ffi_encode_pointer(ffi_codec_t *self, klisp_State *K, TValue v, void *buf) { - if (ttisblob(v)) { - *(void **)buf = tv2blob(v)->b; + if (ttisbytevector(v)) { + *(void **)buf = tv2bytevector(v)->b; } else if (ttisstring(v)) { *(void **)buf = kstring_buf(v); } else if (ttisnil(v)) { @@ -133,7 +133,7 @@ static void ffi_encode_pointer(ffi_codec_t *self, klisp_State *K, TValue v, void /* TODO: do not use internal macro tbasetype_ */ *(void **)buf = pvalue(v); } else { - klispE_throw_simple_with_irritants(K, "neither blob, string, pointer or nil", 1, v); + klispE_throw_simple_with_irritants(K, "neither bytevector, string, pointer or nil", 1, v); } } @@ -260,6 +260,23 @@ static void ffi_encode_uint32(ffi_codec_t *self, klisp_State *K, TValue v, void } } +static TValue ffi_decode_sint32(ffi_codec_t *self, klisp_State *K, const void *buf) +{ + UNUSED(self); + return i2tv(*(int32_t *)buf); +} + +static void ffi_encode_sint32(ffi_codec_t *self, klisp_State *K, TValue v, void *buf) +{ + UNUSED(self); + if (ttisfixint(v)) { + *(int32_t *) buf = ivalue(v); + } else { + klispE_throw_simple_with_irritants(K, "unable to convert to C int32_t", 1, v); + return; + } +} + static TValue ffi_decode_uint64(ffi_codec_t *self, klisp_State *K, const void *buf) { /* TODO */ @@ -352,6 +369,7 @@ static ffi_codec_t ffi_codecs[] = { SIMPLE_TYPE(uint16), SIMPLE_TYPE(sint16), SIMPLE_TYPE(uint32), + SIMPLE_TYPE(sint32), SIMPLE_TYPE(uint64), SIMPLE_TYPE(float), SIMPLE_TYPE(double) @@ -376,9 +394,12 @@ static TValue ffi_win32_error_message(klisp_State *K, DWORD dwMessageId) } #endif -void ffi_load_library(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void ffi_load_library(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: encapsulation key denoting loaded library @@ -386,8 +407,8 @@ void ffi_load_library(klisp_State *K, TValue *xparams, TValue filename = ptree; const char *filename_c = - get_opt_tpar(K, "ffi-load-library", K_TSTRING, &filename) - ? kstring_buf(filename) : NULL; + get_opt_tpar(K, filename, "string", ttisstring) + ? kstring_buf(filename) : NULL; #if KGFFI_DLFCN void *handle = dlopen(filename_c, RTLD_LAZY | RTLD_GLOBAL); @@ -460,9 +481,12 @@ inline size_t align(size_t offset, size_t alignment) return offset + (alignment - offset % alignment) % alignment; } -void ffi_make_call_interface(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void ffi_make_call_interface(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: encapsulation key denoting call interface @@ -478,30 +502,24 @@ void ffi_make_call_interface(klisp_State *K, TValue *xparams, size_t nargs = check_typed_list(K, "ffi-make-call-interface", "argtype string", kstringp, false, argtypes_tv, NULL); - krooted_tvs_push(K, abi_tv); - krooted_tvs_push(K, rtype_tv); - krooted_tvs_push(K, argtypes_tv); - TValue key = xparams[0]; - krooted_tvs_push(K, key); - size_t blob_size = sizeof(ffi_call_interface_t) + (sizeof(ffi_codec_t *) + sizeof(ffi_type)) * nargs; - TValue blob = kblob_new_imm(K, blob_size); - krooted_tvs_push(K, blob); - TValue enc = kmake_encapsulation(K, key, blob); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); + /* Allocate C structure ffi_call_interface_t inside + a mutable bytevector. The structure contains C pointers + into itself. It must never be reallocated or copied. + The bytevector will be encapsulated later to protect + it from lisp code. */ - ffi_call_interface_t *p = (ffi_call_interface_t *) tv2blob(blob)->b; + size_t bytevector_size = sizeof(ffi_call_interface_t) + (sizeof(ffi_codec_t *) + sizeof(ffi_type)) * nargs; + TValue bytevector = kbytevector_new_sf(K, bytevector_size, 0); + krooted_tvs_push(K, bytevector); + + ffi_call_interface_t *p = (ffi_call_interface_t *) tv2bytevector(bytevector)->b; p->acodecs = (ffi_codec_t **) ((char *) p + sizeof(ffi_call_interface_t)); p->argtypes = (ffi_type **) ((char *) p + sizeof(ffi_call_interface_t) + nargs * sizeof(ffi_codec_t *)); - p->nargs = nargs; p->rcodec = tv2ffi_codec(K, rtype_tv); if (p->rcodec->decode == NULL) { - klispE_throw_simple(K, "this type is not allowed as a return type"); - return; + klispE_throw_simple_with_irritants(K, "this type is not allowed as a return type", 1, rtype_tv); + return; } p->buffer_size = p->rcodec->libffi_type->size; @@ -509,7 +527,7 @@ void ffi_make_call_interface(klisp_State *K, TValue *xparams, for (int i = 0; i < nargs; i++) { p->acodecs[i] = tv2ffi_codec(K, kcar(tail)); if (p->acodecs[i]->encode == NULL) { - klispE_throw_simple(K, "this type is not allowed in argument list"); + klispE_throw_simple_with_irritants(K, "this type is not allowed in argument list", 1, kcar(tail)); return; } ffi_type *t = p->acodecs[i]->libffi_type; @@ -533,19 +551,27 @@ void ffi_make_call_interface(klisp_State *K, TValue *xparams, klispE_throw_simple(K, "unknown error in ffi_prep_cif"); return; } + + TValue key = xparams[0]; + TValue enc = kmake_encapsulation(K, key, bytevector); + krooted_tvs_pop(K); kapply_cc(K, enc); } -void do_ffi_call(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void do_ffi_call(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: function pointer - ** xparams[1]: call interface (encapsulated blob) + ** xparams[1]: call interface (encapsulated bytevector) */ void *funptr = pvalue(xparams[0]); - ffi_call_interface_t *p = (ffi_call_interface_t *) tv2blob(kget_enc_val(xparams[1]))->b; + ffi_call_interface_t *p = (ffi_call_interface_t *) tv2bytevector(kget_enc_val(xparams[1]))->b; int64_t buffer[(p->buffer_size + sizeof(int64_t) - 1) / sizeof(int64_t)]; @@ -580,9 +606,12 @@ void do_ffi_call(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, result); } -void ffi_make_applicative(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void ffi_make_applicative(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: encapsulation key denoting dynamically loaded library @@ -671,7 +700,7 @@ static TValue ffi_callback_pop(ffi_callback_t *cb) return v; } -static TValue ffi_callback_guard(ffi_callback_t *cb, klisp_Ofunc fn) +static TValue ffi_callback_guard(ffi_callback_t *cb, klisp_CFunction fn) { TValue app = kmake_applicative(cb->K, fn, 1, p2tv(cb)); krooted_tvs_push(cb->K, app); @@ -683,22 +712,27 @@ static TValue ffi_callback_guard(ffi_callback_t *cb, klisp_Ofunc fn) return ls2; } -void do_ffi_callback_encode_result(klisp_State *K, TValue *xparams, - TValue obj) +void do_ffi_callback_encode_result(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: cif ** xparams[1]: p2tv(libffi return buffer) */ - ffi_call_interface_t *p = (ffi_call_interface_t *) kblob_buf(kget_enc_val(xparams[0])); + ffi_call_interface_t *p = (ffi_call_interface_t *) kbytevector_buf(kget_enc_val(xparams[0])); void *ret = pvalue(xparams[1]); p->rcodec->encode(p->rcodec, K, obj, ret); kapply_cc(K, KINERT); } -void do_ffi_callback_decode_arguments(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void do_ffi_callback_decode_arguments(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]: p2tv(ffi_callback_t) ** xparams[1]: p2tv(libffi return buffer) @@ -719,7 +753,7 @@ void do_ffi_callback_decode_arguments(klisp_State *K, TValue *xparams, assert(ttisencapsulation(cif_tv)); krooted_tvs_push(K, app_tv); krooted_tvs_push(K, cif_tv); - ffi_call_interface_t *p = (ffi_call_interface_t *) kblob_buf(kget_enc_val(cif_tv)); + ffi_call_interface_t *p = (ffi_call_interface_t *) kbytevector_buf(kget_enc_val(cif_tv)); /* Decode arguments. */ @@ -748,8 +782,11 @@ void do_ffi_callback_decode_arguments(klisp_State *K, TValue *xparams, ktail_call(K, app_tv, tail, denv); } -void do_ffi_callback_return(klisp_State *K, TValue *xparams, TValue obj) +void do_ffi_callback_return(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); UNUSED(obj); /* ** xparams[0]: p2tv(ffi_callback_t) @@ -762,11 +799,15 @@ void do_ffi_callback_return(klisp_State *K, TValue *xparams, TValue obj) K->next_func = NULL; } -void do_ffi_callback_entry_guard(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void do_ffi_callback_entry_guard(klisp_State *K) { - UNUSED(denv); + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); + UNUSED(ptree); + UNUSED(denv); /* The entry guard is invoked only if the user captured * the continuation under foreign callback and applied * it later after the foreign callback terminated. @@ -778,9 +819,13 @@ void do_ffi_callback_entry_guard(klisp_State *K, TValue *xparams, klispE_throw_simple(K, "tried to re-enter continuation under FFI callback"); } -void do_ffi_callback_exit_guard(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void do_ffi_callback_exit_guard(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(ptree); UNUSED(denv); /* ** xparams[0]: p2tv(ffi_callback_t) @@ -829,7 +874,10 @@ static void ffi_callback_entry(ffi_cif *cif, void *ret, void **args, void *user_ krooted_tvs_pop(K); krooted_tvs_pop(K); - guard_dynamic_extent(K, NULL, ptree, K->next_env); + K->next_xparams = NULL; + K->next_value = ptree; + /* K->next_env already has the correct value */ + guard_dynamic_extent(K); /* Enter new "inner" trampoline loop. */ @@ -862,9 +910,12 @@ static void ffi_callback_entry(ffi_cif *cif, void *ret, void **args, void *user_ } -void ffi_make_callback(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void ffi_make_callback(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: encapsulation key denoting call interface @@ -878,7 +929,7 @@ void ffi_make_callback(klisp_State *K, TValue *xparams, klispE_throw_simple(K, "second argument shall be call interface"); return; } - ffi_call_interface_t *p = (ffi_call_interface_t *) kblob_buf(kget_enc_val(cif_tv)); + ffi_call_interface_t *p = (ffi_call_interface_t *) kbytevector_buf(kget_enc_val(cif_tv)); TValue cb_tab = xparams[1]; /* Allocate memory for libffi closure. */ @@ -936,15 +987,15 @@ void ffi_make_callback(klisp_State *K, TValue *xparams, static uint8_t * ffi_memory_location(klisp_State *K, bool allow_nesting, TValue v, bool mutable, size_t size) { - if (ttisblob(v)) { - if (mutable && kblob_immutablep(v)) { - klispE_throw_simple_with_irritants(K, "blob not mutable", 1, v); + if (ttisbytevector(v)) { + if (mutable && kbytevector_immutablep(v)) { + klispE_throw_simple_with_irritants(K, "bytevector not mutable", 1, v); return NULL; - } else if (size > kblob_size(v)) { - klispE_throw_simple_with_irritants(K, "blob too small", 1, v); + } else if (size > kbytevector_size(v)) { + klispE_throw_simple_with_irritants(K, "bytevector too small", 1, v); return NULL; } else { - return kblob_buf(v); + return kbytevector_buf(v); } } else if (ttisstring(v)) { if (mutable && kstring_immutablep(v)) { @@ -980,9 +1031,12 @@ static uint8_t * ffi_memory_location(klisp_State *K, bool allow_nesting, } } -void ffi_memmove(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void ffi_memmove(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); @@ -1002,10 +1056,14 @@ void ffi_memmove(klisp_State *K, TValue *xparams, kapply_cc(K, KINERT); } -static void ffi_type_ref(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +static void ffi_type_ref(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); + /* ** xparams[0]: pointer to ffi_codec_t */ @@ -1022,10 +1080,14 @@ static void ffi_type_ref(klisp_State *K, TValue *xparams, kapply_cc(K, result); } -static void ffi_type_set(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +static void ffi_type_set(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); + /* ** xparams[0]: pointer to ffi_codec_t */ @@ -1044,9 +1106,16 @@ static void ffi_type_set(klisp_State *K, TValue *xparams, kapply_cc(K, KINERT); } -void ffi_type_suite(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void ffi_type_suite(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, type_tv); ffi_codec_t *codec = tv2ffi_codec(K, type_tv); @@ -1078,9 +1147,12 @@ void ffi_type_suite(klisp_State *K, TValue *xparams, kapply_cc(K, suite_tv); } -void ffi_klisp_state(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void ffi_klisp_state(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_0p(K, ptree); diff --git a/src/kgffi.h b/src/kgffi.h @@ -21,8 +21,7 @@ #include "kstate.h" #include "kghelpers.h" -void ffi_load_library(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); +void ffi_load_library(klisp_State *K); /* init ground */ void kinit_ffi_ground_env(klisp_State *K); diff --git a/src/kghelpers.c b/src/kghelpers.c @@ -17,8 +17,12 @@ #include "kerror.h" #include "ksymbol.h" -void typep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void typep(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); /* ** xparams[0]: name symbol ** xparams[1]: type tag (as by i2tv) @@ -47,8 +51,12 @@ void typep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } } -void ftypep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void ftypep(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; /* ** xparams[0]: name symbol @@ -80,8 +88,12 @@ void ftypep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* ** REFACTOR: Change this to make it a single pass */ -void ftyped_predp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void ftyped_predp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; /* ** xparams[0]: name symbol @@ -120,8 +132,12 @@ void ftyped_predp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* ** REFACTOR: Change this to make it a single pass */ -void ftyped_bpredp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void ftyped_bpredp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; /* ** xparams[0]: name symbol @@ -176,8 +192,12 @@ void ftyped_bpredp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* This is the same, but the comparison predicate takes a klisp_State */ /* TODO unify them */ -void ftyped_kbpredp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void ftyped_kbpredp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; /* ** xparams[0]: name symbol @@ -268,7 +288,7 @@ int32_t check_typed_list(klisp_State *K, char *name, char *typename, return pairs; } -int32_t check_list(klisp_State *K, char *name, bool allow_infp, +int32_t check_list(klisp_State *K, const char *name, bool allow_infp, TValue obj, int32_t *cpairs) { TValue tail = obj; @@ -301,8 +321,11 @@ int32_t check_list(klisp_State *K, char *name, bool allow_infp, ** Continuation that ignores the value received and instead returns ** a previously computed value. */ -void do_return_value(klisp_State *K, TValue *xparams, TValue obj) +void do_return_value(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: saved_obj */ diff --git a/src/kghelpers.h b/src/kghelpers.h @@ -34,6 +34,10 @@ */ /* XXX: add parens around macro vars!! */ +/* TODO try to rewrite all of these with just check_0p and check_al1p, + (the same with check_0tp and check_al1tp) + add a number param and use an array of strings for msgs */ + #define check_0p(K_, ptree_) \ if (!ttisnil(ptree_)) { \ klispE_throw_simple((K_), \ @@ -195,31 +199,26 @@ /* returns true if the obj pointed by par is a list of one element of type type, and puts that element in par - returns false if *par is nil + returns false if par is nil In any other case it throws an error */ -inline bool get_opt_tpar(klisp_State *K, char *name, int32_t type, TValue *par) -{ - if (ttisnil(*par)) { - return false; - } else if (ttispair(*par) && ttisnil(kcdr(*par))) { - *par = kcar(*par); - if (ttype(*par) != type) { - /* TODO show expected type */ - klispE_throw_simple(K, "Bad type on optional argument " - "(expected ?)"); - /* avoid warning */ - return false; - } else { - return true; - } - } else { - klispE_throw_simple(K, "Bad ptree structure (in optional " - "argument)"); - /* avoid warning */ - return false; - } -} - +#define get_opt_tpar(K_, par_, tstr_, t_) ({ \ + bool res_; \ + if (ttisnil(par_)) { \ + res_ = false; \ + } else if (!ttispair(par_) || !ttisnil(kcdr(par_))) { \ + klispE_throw_simple((K_), \ + "Bad ptree structure " \ + "(in optional argument)"); \ + return; \ + } else if (!t_(kcar(par_))) { \ + klispE_throw_simple(K_, "Bad type on optional argument " \ + "(expected " tstr_ ")"); \ + return; \ + } else { \ + par_ = kcar(par_); \ + res_ = true; \ + } \ + res_; }) /* ** This states are useful for traversing trees, saving the state in the @@ -274,7 +273,7 @@ int32_t check_typed_list(klisp_State *K, char *name, char *typename, /* 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, char *name, bool allow_infp, +int32_t check_list(klisp_State *K, const char *name, bool allow_infp, TValue obj, int32_t *cpairs); /* @@ -364,13 +363,13 @@ inline TValue check_copy_env_list(klisp_State *K, char *name, TValue obj) ** Generic function for type predicates ** It can only be used by types that have a unique tag */ -void typep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void typep(klisp_State *K); /* ** Generic function for type predicates ** It takes an arbitrary function pointer of type bool (*fn)(TValue o) */ -void ftypep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void ftypep(klisp_State *K); /* ** Generic function for typed predicates (like char-alphabetic? or finite?) @@ -379,7 +378,7 @@ void ftypep(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); ** both of the same type: bool (*fn)(TValue o). ** On zero operands this return true */ -void ftyped_predp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void ftyped_predp(klisp_State *K); /* ** Generic function for typed binary predicates (like =? & char<?) @@ -389,18 +388,18 @@ void ftyped_predp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); ** This assumes the predicate is transitive and works even in cyclic lists ** On zero and one operand this return true */ -void ftyped_bpredp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void ftyped_bpredp(klisp_State *K); /* This is the same, but the comparison predicate takes a klisp_State */ /* TODO unify them */ -void ftyped_kbpredp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void ftyped_kbpredp(klisp_State *K); /* ** Continuation that ignores the value received and instead returns ** a previously computed value. */ -void do_return_value(klisp_State *K, TValue *xparams, TValue obj); +void do_return_value(klisp_State *K); /* GC: assumes parent & obj are rooted */ inline TValue make_return_value_cont(klisp_State *K, TValue parent, TValue obj) diff --git a/src/kgkd_vars.c b/src/kgkd_vars.c @@ -32,9 +32,12 @@ /* Helpers for make-keyed-dynamic-variable */ /* accesor returned */ -void do_access(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void do_access(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]: dynamic key */ @@ -51,8 +54,11 @@ void do_access(klisp_State *K, TValue *xparams, TValue ptree, } /* continuation to set the key to the old value on normal return */ -void do_unbind(klisp_State *K, TValue *xparams, TValue obj) +void do_unbind(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: dynamic key ** xparams[1]: old flag @@ -70,9 +76,12 @@ void do_unbind(klisp_State *K, TValue *xparams, TValue obj) } /* operative for setting the key to the new/old flag/value */ -void do_set_pass(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void do_set_pass(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]: dynamic key ** xparams[1]: flag @@ -149,9 +158,12 @@ inline TValue make_bind_continuation(klisp_State *K, TValue key, } /* binder returned */ -void do_bind(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void do_bind(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]: dynamic key */ @@ -186,9 +198,12 @@ void do_bind(klisp_State *K, TValue *xparams, TValue ptree, } /* 10.1.1 make-keyed-dynamic-variable */ -void make_keyed_dynamic_variable(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void make_keyed_dynamic_variable(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); diff --git a/src/kgkd_vars.h b/src/kgkd_vars.h @@ -19,16 +19,13 @@ #include "kghelpers.h" /* This is also used by kgports.c */ -void do_bind(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); -void do_access(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void do_bind(klisp_State *K); +void do_access(klisp_State *K); /* 10.1.1 make-keyed-dynamic-variable */ -void make_keyed_dynamic_variable(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); +void make_keyed_dynamic_variable(klisp_State *K); -void do_unbind(klisp_State *K, TValue *xparams, TValue obj); +void do_unbind(klisp_State *K); /* init ground */ void kinit_kgkd_vars_ground_env(klisp_State *K); diff --git a/src/kgks_vars.c b/src/kgks_vars.c @@ -25,9 +25,12 @@ /* Helpers for make-static-dynamic-variable */ /* accesor returned */ -void do_sv_access(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void do_sv_access(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]: static key */ @@ -40,9 +43,12 @@ void do_sv_access(klisp_State *K, TValue *xparams, TValue ptree, } /* binder returned */ -void do_sv_bind(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void do_sv_bind(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]: static key */ @@ -56,9 +62,12 @@ void do_sv_bind(klisp_State *K, TValue *xparams, TValue ptree, } /* 11.1.1 make-static-dynamic-variable */ -void make_keyed_static_variable(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void make_keyed_static_variable(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); diff --git a/src/kgks_vars.h b/src/kgks_vars.h @@ -19,8 +19,7 @@ #include "kghelpers.h" /* 11.1.1 make-static-dynamic-variable */ -void make_keyed_static_variable(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); +void make_keyed_static_variable(klisp_State *K); /* init ground */ void kinit_kgks_vars_ground_env(klisp_State *K); diff --git a/src/kgnumbers.c b/src/kgnumbers.c @@ -50,6 +50,8 @@ bool kfinitep(TValue obj) { return !ttisinf(obj); } bool kintegerp(TValue obj) { return ttisinteger(obj); } /* only exact integers (like for indices), bigints & fixints */ bool keintegerp(TValue obj) { return ttiseinteger(obj); } +/* exact integers between 0 and 255 inclusive */ +bool ku8p(TValue obj) { return ttisu8(obj); } bool krationalp(TValue obj) { return ttisrational(obj); } bool krealp(TValue obj) { return ttisreal(obj); } /* TEMP used (as a type predicate) in all predicates that need a real with @@ -896,8 +898,12 @@ TValue knum_rationalize(klisp_State *K, TValue n1, TValue n2) } /* 12.5.4 + */ -void kplus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kplus(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); /* cycles are allowed, loop counting pairs */ @@ -963,8 +969,12 @@ void kplus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 12.5.5 * */ -void ktimes(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void ktimes(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); /* cycles are allowed, loop counting pairs */ @@ -1041,8 +1051,12 @@ void ktimes(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 12.5.6 - */ -void kminus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kminus(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); /* cycles are allowed, loop counting pairs */ @@ -1193,8 +1207,12 @@ int32_t kfixint_div0_mod0(int32_t n, int32_t d, int32_t *res_mod) } /* flags are FDIV_DIV, FDIV_MOD, FDIV_ZERO */ -void kdiv_mod(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kdiv_mod(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]: name symbol ** xparams[1]: div_mod_flags @@ -1434,8 +1452,12 @@ bool kevenp(TValue n) } /* 12.5.12 abs */ -void kabs(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kabs(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); @@ -1448,8 +1470,12 @@ void kabs(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 12.5.13 min, max */ /* NOTE: this does two passes, one for error checking and one for doing the actual work */ -void kmin_max(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kmin_max(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]: symbol name ** xparams[1]: bool: true min, false max @@ -1486,8 +1512,12 @@ void kmin_max(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 12.5.14 gcm, lcm */ -void kgcd(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kgcd(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); /* cycles are allowed, loop counting pairs */ @@ -1520,8 +1550,12 @@ void kgcd(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) arith_kapply_cc(K, res); } -void klcm(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void klcm(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); /* cycles are allowed, loop counting pairs */ @@ -1549,9 +1583,16 @@ void klcm(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* use fyped_predp */ /* 12.6.2 get-real-internal-bounds, get-real-exact-bounds */ -void kget_real_internal_bounds(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kget_real_internal_bounds(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + UNUSED(denv); + UNUSED(xparams); + bind_1tp(K, ptree, "real", krealp, tv_n); /* TEMP: do it here directly, for now all inexact objects have [-inf, +inf] bounds */ @@ -1564,9 +1605,15 @@ void kget_real_internal_bounds(klisp_State *K, TValue *xparams, TValue ptree, kapply_cc(K, res); } -void kget_real_exact_bounds(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kget_real_exact_bounds(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(denv); + UNUSED(xparams); + bind_1tp(K, ptree, "real", krealp, tv_n); /* TEMP: do it here directly, for now all inexact objects have [-inf, +inf] bounds, when bounded reals are implemented this @@ -1582,9 +1629,15 @@ void kget_real_exact_bounds(klisp_State *K, TValue *xparams, TValue ptree, } /* 12.6.3 get-real-internal-primary, get-real-exact-primary */ -void kget_real_internal_primary(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void kget_real_internal_primary(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(denv); + UNUSED(xparams); + bind_1tp(K, ptree, "real", krealp, tv_n); /* TEMP: do it here directly */ if (ttisrwnpv(tv_n)) { @@ -1595,9 +1648,15 @@ void kget_real_internal_primary(klisp_State *K, TValue *xparams, } } -void kget_real_exact_primary(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void kget_real_exact_primary(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + UNUSED(denv); + UNUSED(xparams); + + klisp_assert(ttisenvironment(K->next_env)); bind_1tp(K, ptree, "real", krealp, tv_n); /* NOTE: this handles no primary value errors & exact cases just fine */ @@ -1606,8 +1665,15 @@ void kget_real_exact_primary(klisp_State *K, TValue *xparams, } /* 12.6.4 make-inexact */ -void kmake_inexact(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kmake_inexact(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(denv); + UNUSED(xparams); + bind_3tp(K, ptree, "real", krealp, real1, "real", krealp, real2, "real", krealp, real3); @@ -1625,9 +1691,12 @@ void kmake_inexact(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 12.6.5 real->inexact, real->exact */ -void kreal_to_inexact(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kreal_to_inexact(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1638,9 +1707,12 @@ void kreal_to_inexact(klisp_State *K, TValue *xparams, TValue ptree, kapply_cc(K, res); } -void kreal_to_exact(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kreal_to_exact(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1651,9 +1723,14 @@ void kreal_to_exact(klisp_State *K, TValue *xparams, TValue ptree, } /* 12.6.6 with-strict-arithmetic, get-strict-arithmetic? */ -void kwith_strict_arithmetic(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kwith_strict_arithmetic(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + UNUSED(xparams); + bind_2tp(K, ptree, "bool", ttisboolean, strictp, "combiner", ttiscombiner, comb); @@ -1669,9 +1746,12 @@ void kwith_strict_arithmetic(klisp_State *K, TValue *xparams, TValue ptree, ktail_call(K, op, args, denv); } -void kget_strict_arithmeticp(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kget_strict_arithmeticp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1686,8 +1766,12 @@ void kget_strict_arithmeticp(klisp_State *K, TValue *xparams, TValue ptree, /* uses ftypep */ /* 12.8.2 / */ -void kdivided(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kdivided(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); /* cycles are allowed, loop counting pairs */ @@ -1781,8 +1865,12 @@ void kdivided(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 12.8.3 numerator, denominator */ -void knumerator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void knumerator(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1792,8 +1880,12 @@ void knumerator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, res); } -void kdenominator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kdenominator(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1804,9 +1896,12 @@ void kdenominator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 12.8.4 floor, ceiling, truncate, round */ -void kreal_to_integer(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void kreal_to_integer(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]: symbol name ** xparams[1]: bool: true min, false max @@ -1821,9 +1916,12 @@ void kreal_to_integer(klisp_State *K, TValue *xparams, TValue ptree, } /* 12.8.5 rationalize, simplest-rational */ -void krationalize(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void krationalize(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1834,9 +1932,12 @@ void krationalize(klisp_State *K, TValue *xparams, TValue ptree, kapply_cc(K, res); } -void ksimplest_rational(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void ksimplest_rational(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1847,8 +1948,12 @@ void ksimplest_rational(klisp_State *K, TValue *xparams, TValue ptree, kapply_cc(K, res); } -void kexp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kexp(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1884,8 +1989,12 @@ void kexp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, res); } -void klog(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void klog(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -1931,8 +2040,12 @@ void klog(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, res); } -void ktrig(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void ktrig(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: trig function @@ -1971,8 +2084,12 @@ void ktrig(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) arith_kapply_cc(K, res); } -void katrig(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void katrig(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); /* ** xparams[0]: trig function @@ -2016,8 +2133,12 @@ void katrig(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) arith_kapply_cc(K, res); } -void katan(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void katan(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -2103,8 +2224,12 @@ void katan(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) arith_kapply_cc(K, res); } -void ksqrt(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void ksqrt(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -2144,8 +2269,12 @@ void ksqrt(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) arith_kapply_cc(K, res); } -void kexpt(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void kexpt(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); @@ -2349,4 +2478,6 @@ void kinit_numbers_ground_env(klisp_State *K) add_applicative(K, ground_env, "sqrt", ksqrt, 0); /* 12.9.6 expt */ add_applicative(K, ground_env, "expt", kexpt, 0); + + /* TODO add some conversion like number->string, string->number */ } diff --git a/src/kgnumbers.h b/src/kgnumbers.h @@ -36,6 +36,7 @@ bool kexactp(TValue obj); bool kinexactp(TValue obj); bool kundefinedp(TValue obj); bool krobustp(TValue obj); +bool ku8p(TValue obj); /* 12.5.2 =? */ @@ -55,15 +56,15 @@ bool knum_gep(klisp_State *K, TValue n1, TValue n2); /* 12.5.4 + */ /* TEMP: for now only accept two arguments */ -void kplus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kplus(klisp_State *K); /* 12.5.5 * */ /* TEMP: for now only accept two arguments */ -void ktimes(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void ktimes(klisp_State *K); /* 12.5.6 - */ /* TEMP: for now only accept two arguments */ -void kminus(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kminus(klisp_State *K); /* 12.5.7 zero? */ /* uses ftyped_predp */ @@ -100,11 +101,11 @@ bool kevenp(TValue n); #define FDIV_MOD 2 #define FDIV_ZERO 4 -void kdiv_mod(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kdiv_mod(klisp_State *K); /* 12.5.12 abs */ -void kabs(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kabs(klisp_State *K); /* 12.5.13 min, max */ /* use kmin_max */ @@ -112,84 +113,73 @@ void kabs(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); /* Helper */ #define FMIN (true) #define FMAX (false) -void kmin_max(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kmin_max(klisp_State *K); /* 12.5.14 gcm, lcm */ -void kgcd(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); -void klcm(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kgcd(klisp_State *K); +void klcm(klisp_State *K); /* 12.6.1 exact?, inexact?, robust?, undefined? */ /* use fyped_predp */ /* 12.6.2 get-real-internal-bounds, get-real-exact-bounds */ -void kget_real_internal_bounds(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); -void kget_real_exact_bounds(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void kget_real_internal_bounds(klisp_State *K); +void kget_real_exact_bounds(klisp_State *K); /* 12.6.3 get-real-internal-primary, get-real-exact-primary */ -void kget_real_internal_primary(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); -void kget_real_exact_primary(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); +void kget_real_internal_primary(klisp_State *K); +void kget_real_exact_primary(klisp_State *K); /* 12.6.4 make-inexact */ -void kmake_inexact(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kmake_inexact(klisp_State *K); /* 12.6.5 real->inexact, real->exact */ -void kreal_to_inexact(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); -void kreal_to_exact(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void kreal_to_inexact(klisp_State *K); +void kreal_to_exact(klisp_State *K); /* 12.6.6 with-strict-arithmetic, get-strict-arithmetic? */ -void kwith_strict_arithmetic(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void kwith_strict_arithmetic(klisp_State *K); -void kget_strict_arithmeticp(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void kget_strict_arithmeticp(klisp_State *K); /* 12.8.1 rational? */ /* uses ftypep */ /* 12.8.2 / */ -void kdivided(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kdivided(klisp_State *K); /* 12.8.3 numerator, denominator */ -void knumerator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); -void kdenominator(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void knumerator(klisp_State *K); +void kdenominator(klisp_State *K); /* 12.8.4 floor, ceiling, truncate, round */ -void kreal_to_integer(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void kreal_to_integer(klisp_State *K); /* 12.8.5 rationalize, simplest-rational */ -void krationalize(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void krationalize(klisp_State *K); -void ksimplest_rational(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void ksimplest_rational(klisp_State *K); /* 12.9.1 real? */ /* uses ftypep */ /* 12.9.2 exp, log */ -void kexp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); -void klog(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kexp(klisp_State *K); +void klog(klisp_State *K); /* 12.9.3 sin, cos, tan */ -void ktrig(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void ktrig(klisp_State *K); /* 12.9.4 asin, acos, atan */ -void katrig(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); -void katan(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void katrig(klisp_State *K); +void katan(klisp_State *K); /* 12.9.5 sqrt */ -void ksqrt(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void ksqrt(klisp_State *K); /* 12.9.6 expt */ -void kexpt(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void kexpt(klisp_State *K); /* REFACTOR: These should be in a knumber.h header */ diff --git a/src/kgpair_mut.c b/src/kgpair_mut.c @@ -23,8 +23,12 @@ #include "kgnumbers.h" /* for kpositivep and keintegerp */ /* 4.7.1 set-car!, set-cdr! */ -void set_carB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void set_carB(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; (void) xparams; bind_2tp(K, ptree, "pair", ttispair, pair, @@ -38,8 +42,12 @@ void set_carB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, KINERT); } -void set_cdrB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void set_cdrB(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); (void) denv; (void) xparams; bind_2tp(K, ptree, "pair", ttispair, pair, @@ -54,9 +62,15 @@ void set_cdrB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper for copy-es-immutable & copy-es */ -void copy_es(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void copy_es(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + UNUSED(denv); + /* ** xparams[0]: copy-es-immutable symbol ** xparams[1]: boolean (#t: use mutable pairs, #f: use immutable pairs) @@ -154,9 +168,12 @@ TValue copy_es_immutable_h(klisp_State *K, char *name, TValue obj, } /* 5.8.1 encycle! */ -void encycleB(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void encycleB(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 a cyclic list of length less than k1+k2? the wording of the report seems to indicate that can't be the case, and here it makes sense to forbid it because otherwise the list-metrics @@ -400,9 +417,12 @@ TValue appendB_get_lss_endpoints(klisp_State *K, TValue lss, int32_t apairs, } /* 6.4.1 append! */ -void appendB(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void appendB(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 (ttisnil(ptree)) { @@ -444,8 +464,12 @@ void appendB(klisp_State *K, TValue *xparams, TValue ptree, /* 6.4.3 assq */ /* REFACTOR: do just one pass, maybe use generalized accum function */ -void assq(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void assq(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); @@ -469,8 +493,12 @@ void assq(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 6.4.3 memq? */ /* REFACTOR: do just one pass, maybe use generalized accum function */ -void memqp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void memqp(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); @@ -491,6 +519,9 @@ void memqp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, res); } +/* ?.? immutable-pair?, mutable-pair */ +/* use ftypep */ + /* init ground */ void kinit_pair_mut_ground_env(klisp_State *K) { @@ -513,4 +544,9 @@ void kinit_pair_mut_ground_env(klisp_State *K) add_applicative(K, ground_env, "assq", assq, 0); /* 6.4.3 memq? */ add_applicative(K, ground_env, "memq?", memqp, 0); + /* ?.? immutable-pair?, mutable-pair? */ + add_applicative(K, ground_env, "immutable-pair?", ftypep, 2, symbol, + p2tv(kimmutable_pairp)); + add_applicative(K, ground_env, "mutable-pair?", ftypep, 2, symbol, + p2tv(kmutable_pairp)); } diff --git a/src/kgpair_mut.h b/src/kgpair_mut.h @@ -23,33 +23,34 @@ TValue copy_es_immutable_h(klisp_State *K, char *name, TValue ptree, bool mut_flag); /* 4.7.1 set-car!, set-cdr! */ -void set_carB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void set_carB(klisp_State *K); -void set_cdrB(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void set_cdrB(klisp_State *K); /* Helper for copy-es & copy-es-immutable */ -void copy_es(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void copy_es(klisp_State *K); /* 4.7.2 copy-es-immutable */ /* uses copy_es helper */ /* 5.8.1 encycle! */ -void encycleB(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void encycleB(klisp_State *K); /* 6.4.1 append! */ -void appendB(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void appendB(klisp_State *K); /* 6.4.2 copy-es */ /* uses copy_es helper */ /* 6.4.3 assq */ -void assq(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void assq(klisp_State *K); /* 6.4.3 memq? */ -void memqp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void memqp(klisp_State *K); + +/* ?.? immutable-pair?, mutable-pair */ +/* use ftypep */ /* init ground */ void kinit_pair_mut_ground_env(klisp_State *K); diff --git a/src/kgpairs_lists.c b/src/kgpairs_lists.c @@ -32,8 +32,12 @@ /* uses typep */ /* 4.6.3 cons */ -void cons(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void cons(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); UNUSED(xparams); bind_2p(K, ptree, car, cdr); @@ -44,8 +48,12 @@ void cons(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 5.2.1 list */ -void list(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void 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)); /* the underlying combiner of list return the complete ptree, the only list checking is implicit in the applicative evaluation */ UNUSED(xparams); @@ -54,8 +62,12 @@ void list(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 5.2.2 list* */ -void listS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void listS(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); /* TODO: OPTIMIZE: if this call is a result of a call to eval, we could get away with just setting the kcdr of the next to last pair to the car of @@ -103,8 +115,14 @@ void listS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 5.4.1 car, cdr */ /* 5.4.2 caar, cadr, ... cddddr */ -void c_ad_r( klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void c_ad_r(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + UNUSED(denv); /* ** xparams[0]: name as symbol @@ -177,9 +195,12 @@ void get_list_metrics_aux(klisp_State *K, TValue obj, int32_t *p, int32_t *n, } /* 5.7.1 get-list-metrics */ -void get_list_metrics(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void get_list_metrics(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); @@ -230,9 +251,12 @@ int32_t ksmallest_index(klisp_State *K, char *name, TValue obj, /* 5.7.2 list-tail */ -void list_tail(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void list_tail(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 a cyclic list? the wording of the report seems to indicate that can't be the case, but it makes sense here (cf $encycle!) to allow cyclic lists, so that's what I do */ @@ -262,8 +286,12 @@ void list_tail(klisp_State *K, TValue *xparams, TValue ptree, } /* 6.3.1 length */ -void length(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void length(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); @@ -283,8 +311,12 @@ void length(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.3.2 list-ref */ -void list_ref(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void list_ref(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? the wording of the report seems to indicate that can't be the case, but it makes sense (cf list-tail) For now we allow it. */ @@ -358,8 +390,12 @@ TValue append_check_copy_list(klisp_State *K, char *name, TValue obj, } /* 6.3.3 append */ -void append(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void append(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); @@ -420,9 +456,12 @@ void append(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.3.4 list-neighbors */ -void list_neighbors(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void list_neighbors(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); @@ -469,8 +508,11 @@ void list_neighbors(klisp_State *K, TValue *xparams, TValue ptree, /* Helpers for filter */ /* For acyclic input lists: Return the filtered list */ -void do_ret_cdr(klisp_State *K, TValue *xparams, TValue obj) +void do_ret_cdr(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: (dummy . complete-ls) */ @@ -487,8 +529,11 @@ void do_ret_cdr(klisp_State *K, TValue *xparams, TValue obj) /* For cyclic input list: If the result cycle is non empty, close it and return filtered list */ -void do_filter_encycle(klisp_State *K, TValue *xparams, TValue obj) +void do_filter_encycle(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: (dummy . complete-ls) ** xparams[1]: last non-cycle pair @@ -518,8 +563,11 @@ void do_filter_encycle(klisp_State *K, TValue *xparams, TValue obj) kapply_cc(K, copy); } -void do_filter(klisp_State *K, TValue *xparams, TValue obj) +void do_filter(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: app ** xparams[1]: (last-obj . rem-ls) @@ -565,8 +613,11 @@ void do_filter(klisp_State *K, TValue *xparams, TValue obj) } } -void do_filter_cycle(klisp_State *K, TValue *xparams, TValue obj) +void do_filter_cycle(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: app ** xparams[1]: (dummy . res-list) @@ -599,8 +650,12 @@ void do_filter_cycle(klisp_State *K, TValue *xparams, TValue obj) } /* 6.3.5 filter */ -void filter(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void filter(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, "applicative", ttisapplicative, app, @@ -640,8 +695,12 @@ void filter(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.3.6 assoc */ -void assoc(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void assoc(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); @@ -664,8 +723,12 @@ void assoc(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 6.3.7 member? */ -void memberp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void memberp(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); @@ -688,8 +751,12 @@ void memberp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 6.3.8 finite-list? */ /* NOTE: can't use ftypep because the predicate marks pairs too */ -void finite_listp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void finite_listp(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); int32_t pairs = check_list(K, "finite-list?", true, ptree, NULL); @@ -716,9 +783,12 @@ void finite_listp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 6.3.9 countable-list? */ /* NOTE: can't use ftypep because the predicate marks pairs too */ -void countable_listp(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void countable_listp(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); int32_t pairs = check_list(K, "countable-list?", true, ptree, NULL); @@ -746,10 +816,13 @@ void countable_listp(klisp_State *K, TValue *xparams, TValue ptree, /* Helpers for reduce */ /* NOTE: This is used from both do_reduce_cycle and reduce */ -void do_reduce(klisp_State *K, TValue *xparams, TValue obj); +void do_reduce(klisp_State *K); -void do_reduce_prec(klisp_State *K, TValue *xparams, TValue obj) +void do_reduce_prec(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: first-pair ** xparams[1]: (old-obj . rem-ls) @@ -783,8 +856,11 @@ void do_reduce_prec(klisp_State *K, TValue *xparams, TValue obj) } } -void do_reduce_postc(klisp_State *K, TValue *xparams, TValue obj) +void do_reduce_postc(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: postc ** xparams[1]: denv @@ -799,8 +875,11 @@ void do_reduce_postc(klisp_State *K, TValue *xparams, TValue obj) /* This could be avoided by contructing a list and calling do_reduce, but the order would be backwards if the cycle is processed after the acyclic part */ -void do_reduce_combine(klisp_State *K, TValue *xparams, TValue obj) +void do_reduce_combine(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: acyclic result ** xparams[1]: bin @@ -818,8 +897,11 @@ void do_reduce_combine(klisp_State *K, TValue *xparams, TValue obj) ktail_eval(K, expr, denv); } -void do_reduce_cycle(klisp_State *K, TValue *xparams, TValue obj) +void do_reduce_cycle(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: first-cpair ** xparams[1]: cpairs @@ -879,8 +961,11 @@ void do_reduce_cycle(klisp_State *K, TValue *xparams, TValue obj) } /* NOTE: This is used from both do_reduce_cycle and reduce */ -void do_reduce(klisp_State *K, TValue *xparams, TValue obj) +void do_reduce(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: remaining list ** xparams[1]: remaining pairs @@ -920,8 +1005,12 @@ void do_reduce(klisp_State *K, TValue *xparams, TValue obj) srfi-1 also defines reduce-left/reduce-right that work as in kernel. The difference is the use or not of the id value if the list is not null */ -void reduce(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void reduce(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_al3tp(K, ptree, "any", anytype, ls, "applicative", @@ -1101,4 +1190,6 @@ void kinit_pairs_lists_ground_env(klisp_State *K) add_applicative(K, ground_env, "countable-list?", countable_listp, 0); /* 6.3.10 reduce */ add_applicative(K, ground_env, "reduce", reduce, 0); + + /* TODO add make-list, list-copy and reverse (from r7rs) */ } diff --git a/src/kgpairs_lists.h b/src/kgpairs_lists.h @@ -25,17 +25,17 @@ /* uses typep */ /* 4.6.3 cons */ -void cons(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void cons(klisp_State *K); /* 5.2.1 list */ -void list(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void list(klisp_State *K); /* 5.2.2 list* */ -void listS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +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, TValue ptree, TValue denv); +void c_ad_r(klisp_State *K); /* Helper macros to construct xparams[1] for c[ad]{1,4}r */ #define C_AD_R_PARAM(len_, br_) \ @@ -48,54 +48,51 @@ void c_ad_r( klisp_State *K, TValue *xparams, TValue ptree, TValue denv); (br_ & 0x1000? 0x8 : 0)) /* 5.7.1 get-list-metrics */ -void get_list_metrics(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void get_list_metrics(klisp_State *K); /* 5.7.2 list-tail */ -void list_tail(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void list_tail(klisp_State *K); /* 6.3.1 length */ -void length(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void length(klisp_State *K); /* 6.3.2 list-ref */ -void list_ref(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void list_ref(klisp_State *K); /* 6.3.3 append */ -void append(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void append(klisp_State *K); /* 6.3.4 list-neighbors */ -void list_neighbors(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void list_neighbors(klisp_State *K); /* 6.3.5 filter */ -void filter(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void filter(klisp_State *K); /* 6.3.6 assoc */ -void assoc(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void assoc(klisp_State *K); /* 6.3.7 member? */ -void memberp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void memberp(klisp_State *K); /* 6.3.8 finite-list? */ -void finite_listp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void finite_listp(klisp_State *K); /* 6.3.9 countable-list? */ -void countable_listp(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void countable_listp(klisp_State *K); /* 6.3.10 reduce */ -void reduce(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); - - -void do_ret_cdr(klisp_State *K, TValue *xparams, TValue obj); -void do_filter_encycle(klisp_State *K, TValue *xparams, TValue obj); -void do_filter_cycle(klisp_State *K, TValue *xparams, TValue obj); -void do_filter(klisp_State *K, TValue *xparams, TValue obj); -void do_reduce_prec(klisp_State *K, TValue *xparams, TValue obj); -void do_reduce_postc(klisp_State *K, TValue *xparams, TValue obj); -void do_reduce_combine(klisp_State *K, TValue *xparams, TValue obj); -void do_reduce_cycle(klisp_State *K, TValue *xparams, TValue obj); -void do_reduce(klisp_State *K, TValue *xparams, TValue obj); +void reduce(klisp_State *K); + + +void do_ret_cdr(klisp_State *K); +void do_filter_encycle(klisp_State *K); +void do_filter_cycle(klisp_State *K); +void do_filter(klisp_State *K); +void do_reduce_prec(klisp_State *K); +void do_reduce_postc(klisp_State *K); +void do_reduce_combine(klisp_State *K); +void do_reduce_cycle(klisp_State *K); +void do_reduce(klisp_State *K); /* init ground */ void kinit_pairs_lists_ground_env(klisp_State *K); diff --git a/src/kgports.c b/src/kgports.c @@ -13,6 +13,8 @@ #include "kstate.h" #include "kobject.h" #include "kport.h" +#include "kstring.h" +#include "kbytevector.h" #include "kenvironment.h" #include "kapplicative.h" #include "koperative.h" @@ -39,10 +41,24 @@ /* 15.1.2 input-port?, output-port? */ /* use ftypep */ +/* 15.1.? binary-port?, textual-port? */ +/* use ftypep */ + +/* 15.1.? file-port?, string-port?, bytevector-port? */ +/* use ftypep */ + +/* 15.1.? port-open? */ +/* uses ftyped_predp */ + +/* uses ftyped_predp */ + /* 15.1.3 with-input-from-file, with-ouput-to-file */ /* helper for with-i/o-from/to-file & call-with-i/o-file */ -void do_close_file_ret(klisp_State *K, TValue *xparams, TValue obj) +void do_close_file_ret(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: port */ @@ -57,16 +73,19 @@ void do_close_file_ret(klisp_State *K, TValue *xparams, TValue obj) the dynamic environment can be captured in the construction of the combiner ASK John */ -void with_file(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void with_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)); bool writep = bvalue(xparams[1]); TValue key = xparams[2]; bind_2tp(K, ptree, "string", ttisstring, filename, "combiner", ttiscombiner, comb); - TValue new_port = kmake_port(K, filename, writep); + TValue new_port = kmake_fport(K, filename, writep, false); krooted_tvs_push(K, new_port); /* make the continuation to close the file before returning */ TValue new_cont = kmake_continuation(K, kget_cc(K), @@ -87,9 +106,12 @@ void with_file(klisp_State *K, TValue *xparams, TValue ptree, } /* 15.1.4 get-current-input-port, get-current-output-port */ -void get_current_port(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void get_current_port(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]: symbol name ** xparams[1]: dynamic key @@ -106,26 +128,109 @@ void get_current_port(klisp_State *K, TValue *xparams, TValue ptree, /* 15.1.5 open-input-file, open-output-file */ -void open_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +/* 15.1.? open-binary-input-file, open-binary-output-file */ +void open_file(klisp_State *K) { - bool writep = bvalue(xparams[1]); + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); + /* + ** xparams[0]: write? + ** xparams[1]: binary? + */ + bool writep = bvalue(xparams[0]); + bool binaryp = bvalue(xparams[1]); + bind_1tp(K, ptree, "string", ttisstring, filename); - TValue new_port = kmake_port(K, filename, writep); + TValue new_port = kmake_fport(K, filename, writep, binaryp); + kapply_cc(K, new_port); +} + +/* 15.1.? open-input-string, open-output-string */ +/* 15.1.? open-input-bytevector, open-output-bytevector */ +void open_mport(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]: write? + ** xparams[1]: binary? + */ + bool writep = bvalue(xparams[0]); + bool binaryp = bvalue(xparams[1]); + UNUSED(denv); + + TValue buffer; + + /* This is kinda ugly but... */ + if (writep) { + check_0p(K, ptree); + buffer = KINERT; + } else if (binaryp) { + bind_1tp(K, ptree, "bytevector", ttisbytevector, bb); + buffer = bb; + } else { + bind_1tp(K, ptree, "string", ttisstring, str); + buffer = str; + } + + TValue new_port = kmake_mport(K, buffer, writep, binaryp); kapply_cc(K, new_port); } +/* 15.1.? open-output-string, open-output-bytevector */ + /* 15.1.6 close-input-file, close-output-file */ -void close_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void close_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)); + /* + ** xparams[0]: write? + */ + bool writep = bvalue(xparams[0]); + UNUSED(denv); + + bind_1tp(K, ptree, "file port", ttisfport, port); + + bool dir_ok = writep? kport_is_output(port) : kport_is_input(port); + + if (dir_ok) { + kclose_port(K, port); + kapply_cc(K, KINERT); + } else { + klispE_throw_simple(K, "wrong input/output direction"); + return; + } +} + +/* 15.1.? close-input-port, close-output-port, close-port */ +void close_port(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]: read? + ** xparams[1]: write? + */ + bool readp = bvalue(xparams[0]); bool writep = bvalue(xparams[1]); UNUSED(denv); bind_1tp(K, ptree, "port", ttisport, port); - bool dir_ok = writep? kport_is_output(port) : kport_is_input(port); + bool dir_ok = !((writep && !kport_is_output(port)) || + (readp && !kport_is_input(port))); if (dir_ok) { kclose_port(K, port); @@ -136,20 +241,61 @@ void close_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } } +/* 15.1.? get-output-string, get-output-bytevector */ +void get_output_buffer(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]: binary? + */ + bool binaryp = bvalue(xparams[0]); + UNUSED(denv); + bind_1tp(K, ptree, "port", ttismport, port); + + if (binaryp && !kport_is_binary(port)) { + klispE_throw_simple(K, "the port should be a bytevector port"); + return; + } else if (!binaryp && !kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a string port"); + return; + } else if (!kport_is_output(port)) { + klispE_throw_simple(K, "the port should be an output port"); + return; + } + + TValue ret = binaryp? + kbytevector_new_bs(K, + kbytevector_buf(kmport_buf(port)), + kmport_off(port)) : + kstring_new_bs(K, kstring_buf(kmport_buf(port)), kmport_off(port)); + kapply_cc(K, ret); +} + /* 15.1.7 read */ -void read(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void gread(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 port = ptree; - if (!get_opt_tpar(K, "read", K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_in_port_key); /* access directly */ - } else if (!kport_is_input(port)) { + } + + if (!kport_is_input(port)) { klispE_throw_simple(K, "the port should be an input port"); return; - } - if (kport_is_closed(port)) { + } else if (!kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a textual port"); + return; + } else if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } @@ -160,21 +306,29 @@ void read(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 15.1.8 write */ -void write(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void gwrite(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, "any", anytype, obj, port); - if (!get_opt_tpar(K, "write", K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_out_port_key); /* access directly */ - } else if (!kport_is_output(port)) { + } + + if (!kport_is_output(port)) { klispE_throw_simple(K, "the port should be an output port"); return; - } - if (kport_is_closed(port)) { + } else if (!kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a textual port"); + return; + } else if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } @@ -188,19 +342,27 @@ void write(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* uses typep */ /* 15.1.? newline */ -void newline(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void newline(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 port = ptree; - if (!get_opt_tpar(K, "newline", K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_out_port_key); /* access directly */ - } else if (!kport_is_output(port)) { + } + + if (!kport_is_output(port)) { klispE_throw_simple(K, "the port should be an output port"); return; - } - if (kport_is_closed(port)) { + } else if (!kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a textual port"); + return; + } else if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } @@ -210,21 +372,29 @@ void newline(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 15.1.? write-char */ -void write_char(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void write_char(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); UNUSED(denv); bind_al1tp(K, ptree, "char", ttischar, ch, port); - if (!get_opt_tpar(K, "write-char", K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_out_port_key); /* access directly */ - } else if (!kport_is_output(port)) { + } + + if (!kport_is_output(port)) { klispE_throw_simple(K, "the port should be an output port"); return; - } - if (kport_is_closed(port)) { + } else if (!kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a textual port"); + return; + } else if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } @@ -234,26 +404,31 @@ void write_char(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* Helper for read-char and peek-char */ -void read_peek_char(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void read_peek_char(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); /* - ** xparams[0]: symbol name - ** xparams[1]: ret-char-after-readp + ** xparams[0]: ret-char-after-readp */ UNUSED(denv); - char *name = ksymbol_buf(xparams[0]); - bool ret_charp = bvalue(xparams[1]); + bool ret_charp = bvalue(xparams[0]); TValue port = ptree; - if (!get_opt_tpar(K, name, K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_in_port_key); /* access directly */ - } else if (!kport_is_input(port)) { + } + + if (!kport_is_input(port)) { klispE_throw_simple(K, "the port should be an input port"); return; - } - if (kport_is_closed(port)) { + } else if (!kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a textual port"); + return; + } else if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } @@ -274,19 +449,27 @@ void read_peek_char(klisp_State *K, TValue *xparams, TValue ptree, specific code (probably select for posix & a thread for windows (at least for files & consoles, I think pipes and sockets may have something) */ -void char_readyp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void char_readyp(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 port = ptree; - if (!get_opt_tpar(K, "char-ready?", K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_in_port_key); /* access directly */ - } else if (!kport_is_input(port)) { + } + + if (!kport_is_input(port)) { klispE_throw_simple(K, "the port should be an input port"); return; - } - if (kport_is_closed(port)) { + } else if (!kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a textual port"); + return; + } else if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } @@ -295,22 +478,130 @@ void char_readyp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) kapply_cc(K, KTRUE); } +/* 15.1.? write-u8 */ +void write_u8(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, "u8", ttisu8, u8, port); + + if (!get_opt_tpar(K, port, "port", ttisport)) { + port = kcdr(K->kd_out_port_key); /* access directly */ + } + + if (!kport_is_output(port)) { + klispE_throw_simple(K, "the port should be an output port"); + return; + } else if (!kport_is_binary(port)) { + klispE_throw_simple(K, "the port should be a binary port"); + return; + } else if (kport_is_closed(port)) { + klispE_throw_simple(K, "the port is already closed"); + return; + } + + kwrite_u8_to_port(K, port, u8); + kapply_cc(K, KINERT); +} + +/* Helper for read-u8 and peek-u8 */ +void read_peek_u8(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]: ret-u8-after-readp + */ + UNUSED(denv); + + bool ret_u8p = bvalue(xparams[0]); + + TValue port = ptree; + if (!get_opt_tpar(K, port, "port", ttisport)) { + port = kcdr(K->kd_in_port_key); /* access directly */ + } + + if (!kport_is_input(port)) { + klispE_throw_simple(K, "the port should be an input port"); + return; + } else if (!kport_is_binary(port)) { + klispE_throw_simple(K, "the port should be a binary port"); + return; + } else if (kport_is_closed(port)) { + klispE_throw_simple(K, "the port is already closed"); + return; + } + + TValue obj = kread_peek_u8_from_port(K, port, ret_u8p); + kapply_cc(K, obj); +} + + +/* 15.1.? read-u8 */ +/* uses read_peek_u8 */ + +/* 15.1.? peek-u8 */ +/* uses read_peek_u8 */ + +/* 15.1.? u8-ready? */ +/* XXX: this always return #t, proper behaviour requires platform + specific code (probably select for posix & a thread for windows + (at least for files & consoles, I think pipes and sockets may + have something) */ +void u8_readyp(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 port = ptree; + if (!get_opt_tpar(K, port, "port", ttisport)) { + port = kcdr(K->kd_in_port_key); /* access directly */ + } + + if (!kport_is_input(port)) { + klispE_throw_simple(K, "the port should be an input port"); + return; + } else if (!kport_is_binary(port)) { + klispE_throw_simple(K, "the port should be a binary port"); + return; + } else if (kport_is_closed(port)) { + klispE_throw_simple(K, "the port is already closed"); + return; + } + + /* TODO: check if there are pending chars */ + kapply_cc(K, KTRUE); +} /* 15.2.1 call-with-input-file, call-with-output-file */ /* XXX: The report is incomplete here... for now use an empty environment, the dynamic environment can be captured in the construction of the combiner ASK John */ -void call_with_file(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void call_with_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)); bool writep = bvalue(xparams[1]); UNUSED(denv); bind_2tp(K, ptree, "string", ttisstring, filename, "combiner", ttiscombiner, comb); - TValue new_port = kmake_port(K, filename, writep); + TValue new_port = kmake_fport(K, filename, writep, false); krooted_tvs_push(K, new_port); /* make the continuation to close the file before returning */ TValue new_cont = kmake_continuation(K, kget_cc(K), @@ -327,40 +618,13 @@ void call_with_file(klisp_State *K, TValue *xparams, TValue ptree, /* helpers for load */ -/* read all expressions in a file, as immutable pairs */ -/* GC: assume port is rooted */ -TValue read_all_expr(klisp_State *K, TValue port) -{ - /* GC: root dummy and obj */ - TValue tail = kget_dummy1(K); - TValue obj = KINERT; - krooted_vars_push(K, &obj); - - while(true) { - obj = kread_from_port(K, port, false); /* read immutable pairs */ - if (ttiseof(obj)) { - krooted_vars_pop(K); - return kcutoff_dummy1(K); - } else { - TValue new_pair = kimm_cons(K, obj, KNIL); -#if KTRACK_SI - /* put the source info */ - /* XXX: should first read all comments and whitespace, - then save the source info, then read the object and - lastly put the saved source info on the new pair... - For now this will do, but it's not technically correct */ - kset_source_info(K, new_pair, ktry_get_si(K, obj)); -#endif - kset_cdr_unsafe(K, tail, new_pair); - tail = new_pair; - } - } -} - -/* interceptor for errors during reading, also for the continuat */ -void do_int_close_file(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +/* interceptor for errors during reading */ +void do_int_close_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)); /* ** xparams[0]: port */ @@ -420,15 +684,19 @@ TValue make_guarded_read_cont(klisp_State *K, TValue parent, TValue port) applicative. ASK John: maybe we should return the result of the last expression. */ -void load(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void load(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_1tp(K, ptree, "string", ttisstring, filename); /* the reads must be guarded to close the file if there is some error this continuation also will return inert after the evaluation of the last expression is done */ - TValue port = kmake_port(K, filename, false); + TValue port = kmake_fport(K, filename, false, false); krooted_tvs_push(K, port); TValue inert_cont = make_return_value_cont(K, kget_cc(K), KINERT); @@ -439,7 +707,8 @@ void load(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) current continuation as parent GC: root this obj */ kset_cc(K, guarded_cont); /* implicit rooting */ - TValue ls = read_all_expr(K, port); /* any error will close the port */ + /* any error will close the port */ + TValue ls = kread_list_from_port(K, port, false); /* immutable pairs */ /* now the sequence of expresions should be evaluated in denv and #inert returned after all are done */ @@ -470,20 +739,26 @@ void load(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 15.2.3 get-module */ -void get_module(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void get_module(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, filename, maybe_env); - TValue port = kmake_port(K, filename, false); + TValue port = kmake_fport(K, filename, false, false); krooted_tvs_push(K, port); - TValue env = kmake_environment(K, K->ground_env); + /* std environments have hashtable for bindings */ + TValue env = kmake_table_environment(K, K->ground_env); +// TValue env = kmake_environment(K, K->ground_env); krooted_tvs_push(K, env); - if (get_opt_tpar(K, "", K_TENVIRONMENT, &maybe_env)) { + if (get_opt_tpar(K, maybe_env, "environment", ttisenvironment)) { kadd_binding(K, env, K->module_params_sym, maybe_env); } @@ -497,7 +772,9 @@ void get_module(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) TValue guarded_cont = make_guarded_read_cont(K, kget_cc(K), port); kset_cc(K, guarded_cont); /* implicit roooting */ - TValue ls = read_all_expr(K, port); /* any error will close the port */ + + /* any error will close the port */ + TValue ls = kread_list_from_port(K, port, false); /* use immutable pairs */ /* now the sequence of expresions should be evaluated in the created env and the environment returned after all are done */ @@ -527,21 +804,29 @@ void get_module(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 15.2.? display */ -void display(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void display(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, "any", anytype, obj, port); - if (!get_opt_tpar(K, "display", K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_out_port_key); /* access directly */ - } else if (!kport_is_output(port)) { + } + + if (!kport_is_output(port)) { klispE_throw_simple(K, "the port should be an output port"); return; - } - if (kport_is_closed(port)) { + } else if (!kport_is_textual(port)) { + klispE_throw_simple(K, "the port should be a textual port"); + return; + } else if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } @@ -552,34 +837,42 @@ void display(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 15.1.? flush-output-port */ -void flush(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void flush(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 port = ptree; - if (!get_opt_tpar(K, "flush-output-port", K_TPORT, &port)) { + if (!get_opt_tpar(K, port, "port", ttisport)) { port = kcdr(K->kd_out_port_key); /* access directly */ - } else if (!kport_is_output(port)) { + } + + if (!kport_is_output(port)) { klispE_throw_simple(K, "the port should be an output port"); return; } + if (kport_is_closed(port)) { klispE_throw_simple(K, "the port is already closed"); return; } - FILE *file = kport_file(port); - if (file) { /* only do for file ports */ - UNUSED(fflush(file)); /* TEMP for now don't signal errors on flush */ - } + kwrite_flush_port(K, port); kapply_cc(K, KINERT); } /* 15.1.? file-exists? */ -void file_existsp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +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); @@ -597,8 +890,12 @@ void file_existsp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 15.1.? delete-file */ -void delete_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +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); @@ -618,8 +915,12 @@ void delete_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 15.1.? rename-file */ -void rename_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +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); @@ -642,17 +943,37 @@ void rename_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* init ground */ void kinit_ports_ground_env(klisp_State *K) { + /* + ** Some of these are from r7rs scheme + */ + TValue ground_env = K->ground_env; TValue symbol, value; /* 15.1.1 port? */ - add_applicative(K, ground_env, "port?", typep, 2, symbol, - i2tv(K_TPORT)); + add_applicative(K, ground_env, "port?", ftypep, 2, symbol, + p2tv(kportp)); /* 15.1.2 input-port?, output-port? */ add_applicative(K, ground_env, "input-port?", ftypep, 2, symbol, - p2tv(kis_input_port)); + p2tv(kinput_portp)); add_applicative(K, ground_env, "output-port?", ftypep, 2, symbol, - p2tv(kis_output_port)); + p2tv(koutput_portp)); + /* 15.1.? binary-port?, textual-port? */ + add_applicative(K, ground_env, "binary-port?", ftypep, 2, symbol, + p2tv(kbinary_portp)); + add_applicative(K, ground_env, "textual-port?", ftypep, 2, symbol, + p2tv(ktextual_portp)); + /* 15.1.2 file-port?, string-port?, bytevector-port? */ + add_applicative(K, ground_env, "file-port?", ftypep, 2, symbol, + p2tv(kfile_portp)); + add_applicative(K, ground_env, "string-port?", ftypep, 2, symbol, + p2tv(kstring_portp)); + add_applicative(K, ground_env, "bytevector-port?", ftypep, 2, symbol, + p2tv(kbytevector_portp)); + /* 15.1.? port-open? */ + add_applicative(K, ground_env, "port-open?", ftyped_predp, 3, symbol, + p2tv(kportp), p2tv(kport_openp)); + /* 15.1.3 with-input-from-file, with-ouput-to-file */ /* 15.1.? with-error-to-file */ add_applicative(K, ground_env, "with-input-from-file", with_file, @@ -670,25 +991,51 @@ void kinit_ports_ground_env(klisp_State *K) add_applicative(K, ground_env, "get-current-error-port", get_current_port, 2, symbol, K->kd_error_port_key); /* 15.1.5 open-input-file, open-output-file */ - add_applicative(K, ground_env, "open-input-file", open_file, 2, symbol, - b2tv(false)); - add_applicative(K, ground_env, "open-output-file", open_file, 2, symbol, - b2tv(true)); + add_applicative(K, ground_env, "open-input-file", open_file, 2, + b2tv(false), b2tv(false)); + add_applicative(K, ground_env, "open-output-file", open_file, 2, + b2tv(true), b2tv(false)); + /* 15.1.? open-binary-input-file, open-binary-output-file */ + add_applicative(K, ground_env, "open-binary-input-file", open_file, 2, + b2tv(false), b2tv(true)); + add_applicative(K, ground_env, "open-binary-output-file", open_file, 2, + b2tv(true), b2tv(true)); + /* 15.1.? open-input-string, open-output-string */ + /* 15.1.? open-input-bytevector, open-output-bytevector */ + add_applicative(K, ground_env, "open-input-string", open_mport, 2, + b2tv(false), b2tv(false)); + add_applicative(K, ground_env, "open-output-string", open_mport, 2, + b2tv(true), b2tv(false)); + add_applicative(K, ground_env, "open-input-bytevector", open_mport, 2, + b2tv(false), b2tv(true)); + add_applicative(K, ground_env, "open-output-bytevector", open_mport, 2, + b2tv(true), b2tv(true)); + /* 15.1.6 close-input-file, close-output-file */ /* ASK John: should this be called close-input-port & close-ouput-port like in r5rs? that doesn't seem consistent with open thou */ - add_applicative(K, ground_env, "close-input-file", close_file, 2, symbol, + add_applicative(K, ground_env, "close-input-file", close_file, 1, b2tv(false)); - add_applicative(K, ground_env, "close-output-file", close_file, 2, symbol, + add_applicative(K, ground_env, "close-output-file", close_file, 1, b2tv(true)); + /* 15.1.? Use the r7rs names, in preparation for other kind of ports */ + add_applicative(K, ground_env, "close-input-port", close_port, 2, + b2tv(true), b2tv(false)); + add_applicative(K, ground_env, "close-output-port", close_port, 2, + b2tv(false), b2tv(true)); + add_applicative(K, ground_env, "close-port", close_port, 2, + b2tv(false), b2tv(false)); + + /* 15.1.? get-output-string, get-output-bytevector */ + add_applicative(K, ground_env, "get-output-string", get_output_buffer, 1, + b2tv(false)); + add_applicative(K, ground_env, "get-output-bytevector", get_output_buffer, + 1, b2tv(true)); + /* 15.1.7 read */ - add_applicative(K, ground_env, "read", read, 0); + add_applicative(K, ground_env, "read", gread, 0); /* 15.1.8 write */ - add_applicative(K, ground_env, "write", write, 0); - - /* - ** These are from scheme (r5rs) - */ + add_applicative(K, ground_env, "write", gwrite, 0); /* 15.1.? eof-object? */ add_applicative(K, ground_env, "eof-object?", typep, 2, symbol, @@ -698,10 +1045,10 @@ void kinit_ports_ground_env(klisp_State *K) /* 15.1.? write-char */ add_applicative(K, ground_env, "write-char", write_char, 0); /* 15.1.? read-char */ - add_applicative(K, ground_env, "read-char", read_peek_char, 2, symbol, + add_applicative(K, ground_env, "read-char", read_peek_char, 1, b2tv(false)); /* 15.1.? peek-char */ - add_applicative(K, ground_env, "peek-char", read_peek_char, 2, symbol, + add_applicative(K, ground_env, "peek-char", read_peek_char, 1, b2tv(true)); /* 15.1.? char-ready? */ /* XXX: this always return #t, proper behaviour requires platform @@ -709,6 +1056,20 @@ void kinit_ports_ground_env(klisp_State *K) (at least for files & consoles), I think pipes and sockets may have something */ add_applicative(K, ground_env, "char-ready?", char_readyp, 0); + /* 15.1.? write-u8 */ + add_applicative(K, ground_env, "write-u8", write_u8, 0); + /* 15.1.? read-u8 */ + add_applicative(K, ground_env, "read-u8", read_peek_u8, 1, + b2tv(false)); + /* 15.1.? peek-u8 */ + add_applicative(K, ground_env, "peek-u8", read_peek_u8, 1, + b2tv(true)); + /* 15.1.? u8-ready? */ + /* XXX: this always return #t, proper behaviour requires platform + specific code (probably select for posix, a thread for windows + (at least for files & consoles), I think pipes and sockets may + have something */ + add_applicative(K, ground_env, "u8-ready?", u8_readyp, 0); /* 15.2.1 call-with-input-file, call-with-output-file */ add_applicative(K, ground_env, "call-with-input-file", call_with_file, 2, symbol, b2tv(false)); @@ -721,11 +1082,11 @@ void kinit_ports_ground_env(klisp_State *K) /* 15.2.? display */ add_applicative(K, ground_env, "display", display, 0); - /* r7rs */ - /* 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); diff --git a/src/kgports.h b/src/kgports.h @@ -24,40 +24,56 @@ /* 15.1.2 input-port?, output-port? */ /* use ftypep */ +/* 15.1.? binary-port?, textual-port? */ +/* use ftypep */ + +/* 15.1.? file-port?, string-port?, bytevector-port? */ +/* use ftypep */ + +/* 15.1.? port-open? */ +/* uses ftyped_predp */ + /* 15.1.3 with-input-from-file, with-ouput-to-file */ /* 15.1.? with-error-to-file */ -void with_file(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void with_file(klisp_State *K); /* 15.1.4 get-current-input-port, get-current-output-port */ /* 15.1.? get-current-error-port */ -void get_current_port(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void get_current_port(klisp_State *K); /* 15.1.5 open-input-file, open-output-file */ -void open_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void open_file(klisp_State *K); + +/* 15.1.? open-input-string, open-output-string */ +/* 15.1.? open-input-bytevector, open-output-bytevector */ +void open_mport(klisp_State *K); /* 15.1.6 close-input-file, close-output-file */ -void close_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void close_file(klisp_State *K); + +/* 15.1.? close-port, close-input-port, close-output-port */ +void close_port(klisp_State *K); + +/* 15.1.? get-output-string, get-output-bytevector */ +void get_output_buffer(klisp_State *K); /* 15.1.7 read */ -void read(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void gread(klisp_State *K); /* 15.1.8 write */ -void write(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void gwrite(klisp_State *K); /* 15.1.? eof-object? */ /* uses typep */ /* 15.1.? newline */ -void newline(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void newline(klisp_State *K); /* 15.1.? write-char */ -void write_char(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void write_char(klisp_State *K); /* Helper for read-char and peek-char */ -void read_peek_char(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void read_peek_char(klisp_State *K); /* 15.1.? read-char */ /* uses read_peek_char */ @@ -70,34 +86,33 @@ void read_peek_char(klisp_State *K, TValue *xparams, TValue ptree, specific code (probably select for posix, a thread for windows (at least for files & consoles), I think pipes and sockets may have something */ -void char_readyp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void char_readyp(klisp_State *K); /* 15.2.1 call-with-input-file, call-with-output-file */ -void call_with_file(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void call_with_file(klisp_State *K); /* 15.2.2 load */ -void load(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void load(klisp_State *K); /* 15.2.3 get-module */ -void get_module(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void get_module(klisp_State *K); /* 15.2.? display */ -void display(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void display(klisp_State *K); -void do_close_file_ret(klisp_State *K, TValue *xparams, TValue obj); +void do_close_file_ret(klisp_State *K); /* 15.1.? flush-output-port */ -void flush(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void flush(klisp_State *K); /* 15.1.? file-exists? */ -void file_existsp(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void file_existsp(klisp_State *K); /* 15.1.? delete-file */ -void delete_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void delete_file(klisp_State *K); /* 15.1.? rename-file */ -void rename_file(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void rename_file(klisp_State *K); /* init ground */ void kinit_ports_ground_env(klisp_State *K); diff --git a/src/kgpromises.c b/src/kgpromises.c @@ -28,8 +28,11 @@ /* uses typep */ /* Helper for force */ -void do_handle_result(klisp_State *K, TValue *xparams, TValue obj) +void do_handle_result(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: promise */ @@ -64,8 +67,12 @@ void do_handle_result(klisp_State *K, TValue *xparams, TValue obj) } /* 9.1.2 force */ -void force(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void force(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); @@ -86,8 +93,12 @@ void force(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 9.1.3 $lazy */ -void Slazy(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void Slazy(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(xparams); bind_1p(K, ptree, exp); @@ -96,8 +107,12 @@ void Slazy(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 9.1.4 memoize */ -void memoize(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void memoize(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); diff --git a/src/kgpromises.h b/src/kgpromises.h @@ -22,15 +22,15 @@ /* uses typep */ /* 9.1.2 force */ -void force(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void force(klisp_State *K); /* 9.1.3 $lazy */ -void Slazy(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void Slazy(klisp_State *K); /* 9.1.4 memoize */ -void memoize(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void memoize(klisp_State *K); -void do_handle_result(klisp_State *K, TValue *xparams, TValue obj); +void do_handle_result(klisp_State *K); /* init ground */ void kinit_promises_ground_env(klisp_State *K); diff --git a/src/kground.c b/src/kground.c @@ -35,7 +35,8 @@ #include "kgstrings.h" #include "kgchars.h" #include "kgports.h" -#include "kgblobs.h" +#include "kgbytevectors.h" +#include "kgvectors.h" #include "kgsystem.h" #include "kgerror.h" @@ -67,11 +68,11 @@ void kinit_cont_names(klisp_State *K) Table *t = tv2table(K->cont_name_table); /* REPL, root-continuation & error-continuation */ - add_cont_name(K, t, do_repl_exit, "exit"); + add_cont_name(K, t, do_root_exit, "exit"); + add_cont_name(K, t, do_error_exit, "error"); add_cont_name(K, t, do_repl_read, "repl-read"); add_cont_name(K, t, do_repl_eval, "repl-eval"); add_cont_name(K, t, do_repl_loop, "repl-loop"); - add_cont_name(K, t, do_repl_error, "repl-report-error"); /* SCRIPT, root-continuation & error-continuation */ add_cont_name(K, t, do_script_exit, "script-exit"); @@ -142,7 +143,8 @@ void kinit_ground_env(klisp_State *K) kinit_strings_ground_env(K); kinit_chars_ground_env(K); kinit_ports_ground_env(K); - kinit_blobs_ground_env(K); + kinit_bytevectors_ground_env(K); + kinit_vectors_ground_env(K); kinit_system_ground_env(K); kinit_error_ground_env(K); #if KUSE_LIBFFI diff --git a/src/kgstrings.c b/src/kgstrings.c @@ -29,16 +29,23 @@ /* 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, TValue *xparams, TValue ptree, TValue denv) +void make_string(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, "exact integer", keintegerp, tv_s, maybe_char); char fill = ' '; - if (get_opt_tpar(K, "make-string", K_TCHAR, &maybe_char)) + if (get_opt_tpar(K, maybe_char, "char", ttischar)) fill = chvalue(maybe_char); if (knegativep(tv_s)) { @@ -54,9 +61,12 @@ void make_string(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 13.1.3? string-length */ -void string_length(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void string_length(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); @@ -66,8 +76,12 @@ void string_length(klisp_State *K, TValue *xparams, TValue ptree, } /* 13.1.4? string-ref */ -void string_ref(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void string_ref(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, str, @@ -91,8 +105,12 @@ void string_ref(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 13.1.5? string-set! */ -void string_setS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void string_setS(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_3tp(K, ptree, "string", ttisstring, str, @@ -145,8 +163,12 @@ inline TValue list_to_string_h(klisp_State *K, char *name, TValue ls) } /* 13.2.1? string */ -void string(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void string(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); @@ -239,9 +261,15 @@ bool kstring_ci_gep(TValue str1, TValue str2) } /* 13.2.5? substring */ -/* Note: This will return an mutable string iff the source string is mutable */ -void substring(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +/* TEMP: at least for now this always returns mutable strings (like in Racket and + following the Kernel Report where it says that object returned should be mutable + unless stated) */ +void substring(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_3tp(K, ptree, "string", ttisstring, str, @@ -276,10 +304,9 @@ void substring(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* the if isn't strictly necessary but it's clearer this way */ if (size == 0) { new_str = K->empty_string; - } else if (kstring_mutablep(str)) { - new_str = kstring_new_bs(K, kstring_buf(str)+start, size); } else { - new_str = kstring_new_bs_imm(K, kstring_buf(str)+start, size); + /* always returns mutable strings */ + new_str = kstring_new_bs(K, kstring_buf(str)+start, size); } kapply_cc(K, new_str); } @@ -287,9 +314,12 @@ void substring(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) /* 13.2.6? string-append */ /* TEMP: at least for now this always returns mutable strings */ /* TEMP: this does 3 passes over the list */ -void string_append(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void string_append(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); int32_t dummy; @@ -336,9 +366,12 @@ void string_append(klisp_State *K, TValue *xparams, TValue ptree, /* 13.2.7? string->list, list->string */ -void string_to_list(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void string_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); @@ -357,9 +390,12 @@ void string_to_list(klisp_State *K, TValue *xparams, TValue ptree, kapply_cc(K, kcutoff_dummy1(K)); } -void list_to_string(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void list_to_string(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); @@ -372,8 +408,12 @@ void list_to_string(klisp_State *K, TValue *xparams, TValue ptree, /* 13.2.8? string-copy */ /* TEMP: at least for now this always returns mutable strings */ -void string_copy(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void string_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_1tp(K, ptree, "string", ttisstring, str); @@ -389,9 +429,12 @@ void string_copy(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) } /* 13.2.9? string->immutable-string */ -void string_to_immutable_string(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv) +void string_to_immutable_string(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); @@ -406,8 +449,12 @@ void string_to_immutable_string(klisp_State *K, TValue *xparams, } /* 13.2.10? string-fill! */ -void string_fillS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void string_fillS(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, str, @@ -438,6 +485,11 @@ void kinit_strings_ground_env(klisp_State *K) /* 13.1.1? string? */ add_applicative(K, ground_env, "string?", typep, 2, symbol, i2tv(K_TSTRING)); + /* 13.? immutable-string?, mutable-string? */ + add_applicative(K, ground_env, "immutable-string?", ftypep, 2, symbol, + p2tv(kimmutable_stringp)); + add_applicative(K, ground_env, "mutable-string?", ftypep, 2, symbol, + p2tv(kmutable_stringp)); /* 13.1.2? make-string */ add_applicative(K, ground_env, "make-string", make_string, 0); /* 13.1.3? string-length */ @@ -484,7 +536,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-immutable? or general immutable? */ /* TODO: add string-upcase and string-downcase like in r7rs-draft */ /* 13.2.10? string-fill! */ diff --git a/src/kgstrings.h b/src/kgstrings.h @@ -21,21 +21,23 @@ /* 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, TValue *xparams, TValue ptree, TValue denv); +void make_string(klisp_State *K); /* 13.1.3? string-length */ -void string_length(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void string_length(klisp_State *K); /* 13.1.4? string-ref */ -void string_ref (klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void string_ref (klisp_State *K); /* 13.1.5? string-set! */ -void string_setS (klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void string_setS (klisp_State *K); /* 13.2.1? string */ -void string(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void string(klisp_State *K); /* 13.2.2? string=?, string-ci=? */ /* use ftyped_bpredp */ @@ -63,27 +65,23 @@ bool kstring_ci_gep(TValue str1, TValue str2); /* 13.2.5? substring */ -void substring(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void substring(klisp_State *K); /* 13.2.6? string-append */ -void string_append(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void string_append(klisp_State *K); /* 13.2.7? string->list, list->string */ -void list_to_string(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); -void string_to_list(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +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, TValue *xparams, TValue ptree, TValue denv); +void string_copy(klisp_State *K); /* 13.2.9? string->immutable-string */ -void string_to_immutable_string(klisp_State *K, TValue *xparams, - TValue ptree, TValue denv); +void string_to_immutable_string(klisp_State *K); /* 13.2.10? string-fill! */ -void string_fillS(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void string_fillS(klisp_State *K); /* Helpers */ bool kstringp(TValue obj); diff --git a/src/kgsymbols.c b/src/kgsymbols.c @@ -27,9 +27,12 @@ /* 13.3.1? symbol->string */ /* The strings in symbols are immutable so we can just return that */ -void symbol_to_string(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void symbol_to_string(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, "symbol", ttissymbol, sym); @@ -48,9 +51,12 @@ void symbol_to_string(klisp_State *K, TValue *xparams, TValue ptree, again must be equal? which happens here */ /* If the string is mutable it is copied */ -void string_to_symbol(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void string_to_symbol(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); diff --git a/src/kgsymbols.h b/src/kgsymbols.h @@ -22,8 +22,7 @@ /* uses typep */ /* ?.?.1? symbol->string */ -void symbol_to_string(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void symbol_to_string(klisp_State *K); /* ?.?.2? string->symbol */ /* TEMP: for now this can create symbols with no external representation @@ -35,8 +34,7 @@ void symbol_to_string(klisp_State *K, TValue *xparams, TValue ptree, because the report only says that read objects when written and read again must be equal? which happens here */ -void string_to_symbol(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void string_to_symbol(klisp_State *K); /* init ground */ void kinit_symbols_ground_env(klisp_State *K); diff --git a/src/kgsystem.c b/src/kgsystem.c @@ -23,9 +23,16 @@ */ /* ??.?.? current-second */ -void current_second(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void current_second(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_0p(K, ptree); time_t now = time(NULL); if (now == -1) { klispE_throw_simple(K, "couldn't get time"); @@ -43,9 +50,16 @@ void current_second(klisp_State *K, TValue *xparams, TValue ptree, } /* ??.?.? current-jiffy */ -void current_jiffy(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void current_jiffy(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_0p(K, ptree); /* TODO, this may wrap around... use time+clock to a better number */ /* XXX doesn't seem to work... should probably use gettimeofday in posix anyways */ @@ -66,9 +80,16 @@ void current_jiffy(klisp_State *K, TValue *xparams, TValue ptree, } /* ??.?.? jiffies-per-second */ -void jiffies_per_second(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv) +void jiffies_per_second(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_0p(K, ptree); if (CLOCKS_PER_SEC > INT32_MAX) { /* XXX/TODO create bigint */ klispE_throw_simple(K, "integer too big"); diff --git a/src/kgsystem.h b/src/kgsystem.h @@ -19,11 +19,9 @@ #include "kghelpers.h" /* ??.?.? current-second */ -void current_second(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void current_second(klisp_State *K); /* ??.?.? current-jiffy */ -void current_jiffy(klisp_State *K, TValue *xparams, TValue ptree, - TValue denv); +void current_jiffy(klisp_State *K); /* init ground */ void kinit_system_ground_env(klisp_State *K); diff --git a/src/kgvectors.c b/src/kgvectors.c @@ -0,0 +1,245 @@ +/* +** kgvectors.c +** Vector (heterogenous array) features for the ground environment +** See Copyright Notice in klisp.h +*/ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> + +#include "kstate.h" +#include "kobject.h" +#include "kapplicative.h" +#include "koperative.h" +#include "kcontinuation.h" +#include "kerror.h" +#include "kvector.h" +#include "kpair.h" + +#include "kghelpers.h" +#include "kgvectors.h" +#include "kgnumbers.h" /* for keintegerp & knegativep */ + +/* (R7RS 3rd draft 6.3.6) vector? */ +/* uses typep */ + +/* ?.?.? immutable-vector?, mutable-vector? */ +/* use ftypep */ + +/* (R7RS 3rd draft 6.3.6) make-vector */ +void make_vector(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + TValue ptree = K->next_value; + + 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 vector length"); + return; + } else if (!ttisfixint(tv_s)) { + klispE_throw_simple(K, "vector length is too big"); + return; + } + TValue new_vector = (ivalue(tv_s) == 0) + ? K->empty_vector + : kvector_new_sf(K, ivalue(tv_s), fill); + kapply_cc(K, new_vector); +} + +/* (R7RS 3rd draft 6.3.6) vector-length */ +void vector_length(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + TValue ptree = K->next_value; + + bind_1tp(K, ptree, "vector", ttisvector, vector); + + TValue res = i2tv(kvector_length(vector)); + kapply_cc(K, res); +} + +/* (R7RS 3rd draft 6.3.6) vector-ref */ +void vector_ref(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + + TValue ptree = K->next_value; + bind_2tp(K, ptree, "vector", ttisvector, vector, + "exact integer", keintegerp, tv_i); + + if (!ttisfixint(tv_i)) { + klispE_throw_simple_with_irritants(K, "vector index out of bounds", + 1, tv_i); + return; + } + int32_t i = ivalue(tv_i); + if (i < 0 || i >= kvector_length(vector)) { + klispE_throw_simple_with_irritants(K, "vector index out of bounds", + 1, tv_i); + return; + } + kapply_cc(K, kvector_array(vector)[i]); +} + +/* (R7RS 3rd draft 6.3.6) vector-set! */ +void vector_setS(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + + TValue ptree = K->next_value; + bind_3tp(K, ptree, "vector", ttisvector, vector, + "exact integer", keintegerp, tv_i, "any", anytype, tv_new_value); + + if (!ttisfixint(tv_i)) { + klispE_throw_simple_with_irritants(K, "vector index out of bounds", + 1, tv_i); + return; + } else if (kvector_immutablep(vector)) { + klispE_throw_simple(K, "immutable vector"); + return; + } + + int32_t i = ivalue(tv_i); + if (i < 0 || i >= kvector_length(vector)) { + klispE_throw_simple_with_irritants(K, "vector index out of bounds", + 1, tv_i); + return; + } + + kvector_array(vector)[i] = tv_new_value; + kapply_cc(K, KINERT); +} + +/* (R7RS 3rd draft 6.3.6) vector-copy */ +/* TEMP: at least for now this always returns mutable vectors */ +void vector_copy(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + TValue ptree = K->next_value; + + bind_1tp(K, ptree, "vector", ttisvector, v); + + TValue new_vector = kvector_emptyp(v)? + v + : kvector_new_bs_g(K, true, kvector_array(v), kvector_length(v)); + kapply_cc(K, new_vector); +} + +static TValue list_to_vector_h(klisp_State *K, const char *name, TValue ls) +{ + int32_t dummy; + int32_t pairs = check_list(K, name, false, ls, &dummy); + + if (pairs == 0) { + return K->empty_vector; + } else { + TValue res = kvector_new_sf(K, pairs, KINERT); + for (int i = 0; i < pairs; i++) { + kvector_array(res)[i] = kcar(ls); + ls = kcdr(ls); + } + return res; + } +} + +/* (R7RS 3rd draft 6.3.6) vector */ +void vector(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + + TValue ptree = K->next_value; + kapply_cc(K, list_to_vector_h(K, "vector", ptree)); +} + +/* (R7RS 3rd draft 6.3.6) list->vector */ +void list_to_vector(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + + TValue ptree = K->next_value; + bind_1p(K, ptree, ls); + kapply_cc(K, list_to_vector_h(K, "list->vector", ls)); +} + +/* (R7RS 3rd draft 6.3.6) vector->list */ +void vector_to_list(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + + TValue ptree = K->next_value; + bind_1tp(K, ptree, "vector", ttisvector, v); + + TValue tail = KNIL; + krooted_vars_push(K, &tail); + size_t i = kvector_length(v); + while (i-- > 0) + tail = kcons(K, kvector_array(v)[i], tail); + krooted_vars_pop(K); + kapply_cc(K, tail); +} + +/* ??.?.? vector->immutable-vector */ +void vector_to_immutable_vector(klisp_State *K) +{ + klisp_assert(ttisenvironment(K->next_env)); + + TValue ptree = K->next_value; + bind_1tp(K, ptree, "vector", ttisvector, v); + + TValue res = kvector_immutablep(v)? + v + : kvector_new_bs_g(K, false, kvector_array(v), kvector_length(v)); + kapply_cc(K, res); +} + +/* init ground */ +void kinit_vectors_ground_env(klisp_State *K) +{ + TValue ground_env = K->ground_env; + TValue symbol, value; + + /* + ** This section is not in the report. The bindings here are + ** taken from the r7rs scheme draft and should not be considered standard. + ** They are provided in the meantime to allow programs to use vectors. + */ + + /* (R7RS 3rd draft 6.3.6) vector? */ + add_applicative(K, ground_env, "vector?", typep, 2, symbol, + i2tv(K_TVECTOR)); + /* ??.? immutable-vector?, mutable-vector? */ + add_applicative(K, ground_env, "immutable-vector?", ftypep, 2, symbol, + p2tv(kimmutable_vectorp)); + add_applicative(K, ground_env, "mutable-vector?", ftypep, 2, symbol, + p2tv(kmutable_vectorp)); + /* (R7RS 3rd draft 6.3.6) make-vector */ + add_applicative(K, ground_env, "make-vector", make_vector, 0); + /* (R7RS 3rd draft 6.3.6) vector-length */ + add_applicative(K, ground_env, "vector-length", vector_length, 0); + + /* (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); + + /* (R7RS 3rd draft 6.3.6) vector, vector->list, list->vector */ + add_applicative(K, ground_env, "vector", vector, 0); + add_applicative(K, ground_env, "vector->list", vector_to_list, 0); + add_applicative(K, ground_env, "list->vector", list_to_vector, 0); + + /* ??.1.?? vector-copy */ + add_applicative(K, ground_env, "vector-copy", vector_copy, 0); + + /* TODO: vector->string, string->vector, vector-fill */ + /* TODO: vector-copy! vector-copy-partial vector-copy-partial! */ + + /* ??.1.?? vector->immutable-vector */ + add_applicative(K, ground_env, "vector->immutable-vector", + vector_to_immutable_vector, 0); +} diff --git a/src/kgvectors.h b/src/kgvectors.h @@ -0,0 +1,15 @@ +/* +** kgvectors.h +** Vector (heterogenous array) features for the ground environment +** See Copyright Notice in klisp.h +*/ + +#ifndef kgvectors_h +#define kgvectors_h + +#include "kstate.h" + +/* init ground */ +void kinit_vectors_ground_env(klisp_State *K); + +#endif diff --git a/src/klimits.h b/src/klimits.h @@ -67,4 +67,14 @@ /* at last count, there were about 200 bindings in ground env */ #define ENVTABSIZE 512 +/* starting size for string port buffers */ +#ifndef MINSTRINGPORTBUFFER +#define MINSTRINGPORTBUFFER 256 +#endif + +/* starting size for bytevector port buffers */ +#ifndef MINBYTEVECTORPORTBUFFER +#define MINBYTEVECTORPORTBUFFER 256 +#endif + #endif diff --git a/src/klisp.c b/src/klisp.c @@ -4,7 +4,13 @@ ** See Copyright Notice in klisp.h */ +/* +** TODO This needs a serious clean up, I hacked it together during +** an all nighter... +*/ + #include <stdio.h> +#include <string.h> #include <stdlib.h> #include <assert.h> @@ -15,22 +21,568 @@ #include "klisp.h" #include "kstate.h" #include "kauxlib.h" + +#include "kstring.h" +#include "kcontinuation.h" +#include "koperative.h" +#include "kenvironment.h" +#include "kport.h" +#include "kread.h" +#include "kwrite.h" +#include "kerror.h" +#include "kgcontinuations.h" /* for do_pass_value */ +#include "kgcontrol.h" /* for do_seq */ #include "kscript.h" +#include "krepl.h" -int main(int argc, char *argv[]) +/* TODO update dependencies in makefile */ + +static const char *progname = KLISP_PROGNAME; + +static void print_usage (void) +{ + fprintf(stderr, + "usage: %s [options] [script [args]].\n" + "Available options are:\n" + " -e exp eval string " KLISP_QL("exp") "\n" +// " -l name require library " KLISP_QL("name") "\n" + " -i enter interactive mode after executing " + KLISP_QL("script") "\n" + " -v show version information\n" + " -- stop handling options\n" + " - execute stdin and stop handling options\n" + , + progname); + fflush(stderr); +} + +static void k_message (const char *pname, const char *msg) +{ + if (pname) + fprintf(stderr, "%s: ", pname); + fprintf(stderr, "%s\n", msg); + fflush(stderr); +} + +/* TODO move this to a common place to use it from elsewhere +(like the repl) */ +static void show_error(klisp_State *K, TValue obj) { + /* FOR NOW used only for irritant list */ + TValue port = kcdr(K->kd_error_port_key); + klisp_assert(ttisfport(port) && 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"); + } + fflush(stderr); +} + +static int report (klisp_State *K, int status) +{ + if (status != 0) { + const char *msg = "Error!"; + k_message(progname, msg); + show_error(K, K->next_value); + } + return status; +} + +static void print_version(void) +{ + k_message(NULL, KLISP_RELEASE " " KLISP_COPYRIGHT); +} + +/* REFACTOR maybe these should be moved to a general place to be used + from any program */ +void do_str_eval(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + /* + ** xparams[0]: dynamic environment + */ + TValue denv = xparams[0]; + ktail_eval(K, obj, denv); +} + +void do_str_read(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + /* + ** xparams[0]: port + */ + TValue port = xparams[0]; + UNUSED(obj); + /* read just one value (as mutable data) */ + TValue obj1 = kread_from_port(K, port, true); + + /* obj may be eof, that's not a problem, it just won't do anything */ + + krooted_tvs_push(K, obj1); + TValue obj2 = kread_from_port(K, port, true); + krooted_tvs_pop(K); + + if (!ttiseof(obj2)) { + klispE_throw_simple_with_irritants(K, "More than one expression read", + 1, port); + return; + } + + /* all ok, just one exp read (or none and obj1 is eof) */ + kapply_cc(K, obj1); +} + +void do_int_mark_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)); + /* + ** xparams[0]: errorp pointer + */ + UNUSED(denv); + bool *errorp = (bool *) pvalue(xparams[0]); + *errorp = true; + /* ptree is (object divert) */ + TValue error_obj = kcar(ptree); + /* pass the error along after setting the flag */ + kapply_cc(K, error_obj); +} + +static int dostring (klisp_State *K, const char *s, const char *name) +{ + bool errorp = false; /* may be set to true in error handler */ + + UNUSED(name); /* could use as filename?? */ + /* create a string input port */ + TValue str = kstring_new_b(K, s); + krooted_tvs_push(K, str); + TValue port = kmake_mport(K, str, false, false); + krooted_tvs_pop(K); + krooted_tvs_push(K, port); + + /* create the guard set error flag after errors */ + TValue exit_int = kmake_operative(K, do_int_mark_error, + 1, p2tv(&errorp)); + krooted_tvs_push(K, exit_int); + TValue exit_guard = kcons(K, K->error_cont, exit_int); + krooted_tvs_pop(K); /* already in guard */ + krooted_tvs_push(K, exit_guard); + TValue exit_guards = kcons(K, exit_guard, KNIL); + krooted_tvs_pop(K); /* already in guards */ + krooted_tvs_push(K, exit_guards); + + TValue entry_guards = KNIL; + + /* this is needed for interception code */ + TValue env = kmake_empty_environment(K); + krooted_tvs_push(K, env); + TValue outer_cont = kmake_continuation(K, K->root_cont, + do_pass_value, 2, entry_guards, env); + kset_outer_cont(outer_cont); + krooted_tvs_push(K, outer_cont); + TValue inner_cont = kmake_continuation(K, outer_cont, + do_pass_value, 2, exit_guards, env); + kset_inner_cont(inner_cont); + krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K); + + /* only port remains in the root stack */ + krooted_tvs_push(K, inner_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, + 1, env); + krooted_tvs_pop(K); /* pop inner cont */ + krooted_tvs_push(K, eval_cont); + TValue read_cont = kmake_continuation(K, eval_cont, do_str_read, + 1, port); + krooted_tvs_pop(K); /* pop eval cont */ + krooted_tvs_pop(K); /* pop port */ + kset_cc(K, read_cont); /* this will protect all conts from gc */ + klispS_apply_cc(K, KINERT); + + klispS_run(K); + + int status = errorp? 1 : 0; + + /* get the standard environment again in K->next_env */ + K->next_env = env; + return report(K, status); +} + +void do_file_eval(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + /* + ** xparams[0]: dynamic environment + */ + TValue denv = xparams[0]; + TValue ls = obj; + if (!ttisnil(ls)) { + TValue new_cont = kmake_continuation(K, kget_cc(K), do_seq, 2, ls, denv); + kset_cc(K, new_cont); + } + kapply_cc(K, KINERT); +} + +void do_file_read(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + UNUSED(obj); + TValue port = xparams[0]; + /* read all file as a list (as immutable data) */ + TValue ls = kread_list_from_port(K, port, false); + + /* all ok, just one exp read (or none and obj1 is eof) */ + kapply_cc(K, ls); +} + +/* name = NULL means use stdin */ +static int dofile(klisp_State *K, const char *name) { - if (argc <= 1) { - klisp_State *K = klispL_newstate(); - klispS_init_repl(K); - klispS_run(K); - klisp_close(K); - return 0; + bool errorp = false; /* may be set to true in error handler */ + + /* create a file input port (unless it's stdin, then just use) */ + TValue port; + + /* XXX better do this in a continuation */ + if (name == NULL) { + port = kcdr(K->kd_in_port_key); } else { - klisp_State *K = klispL_newstate(); - kinit_script(K, argc - 1, argv + 1); - klispS_run(K); - int exit_code = K->script_exit_code; - klisp_close(K); - return exit_code; + FILE *file = fopen(name, "r"); + if (file == NULL) { + TValue mode_str = kstring_new_b(K, "r"); + krooted_tvs_push(K, mode_str); + TValue name_str = kstring_new_b(K, name); + krooted_tvs_push(K, mode_str); + TValue error_obj = klispE_new_simple_with_errno_irritants + (K, "fopen", 2, name_str, mode_str); + krooted_tvs_pop(K); + krooted_tvs_pop(K); + K->next_value = error_obj; + return report(K, 1); + } + + TValue name_str = kstring_new_b(K, name); + krooted_tvs_push(K, name_str); + port = kmake_std_fport(K, name_str, false, false, file); + krooted_tvs_pop(K); + } + + krooted_tvs_push(K, port); + /* TODO this is exactly the same as in string, factor the code out */ + /* create the guard set error flag after errors */ + TValue exit_int = kmake_operative(K, do_int_mark_error, + 1, p2tv(&errorp)); + krooted_tvs_push(K, exit_int); + TValue exit_guard = kcons(K, K->error_cont, exit_int); + krooted_tvs_pop(K); /* already in guard */ + krooted_tvs_push(K, exit_guard); + TValue exit_guards = kcons(K, exit_guard, KNIL); + krooted_tvs_pop(K); /* already in guards */ + krooted_tvs_push(K, exit_guards); + + TValue entry_guards = KNIL; + + /* this is needed for interception code */ + TValue env = kmake_empty_environment(K); + krooted_tvs_push(K, env); + TValue outer_cont = kmake_continuation(K, K->root_cont, + do_pass_value, 2, entry_guards, env); + kset_outer_cont(outer_cont); + krooted_tvs_push(K, outer_cont); + TValue inner_cont = kmake_continuation(K, outer_cont, + do_pass_value, 2, exit_guards, env); + kset_inner_cont(inner_cont); + krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K); + + /* only port remains in the root stack */ + krooted_tvs_push(K, inner_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, + 1, env); + krooted_tvs_pop(K); /* pop inner cont */ + krooted_tvs_push(K, eval_cont); + TValue read_cont = kmake_continuation(K, eval_cont, do_file_read, + 1, port); + krooted_tvs_pop(K); /* pop eval cont */ + krooted_tvs_pop(K); /* pop port */ + kset_cc(K, read_cont); /* this will protect all conts from gc */ + klispS_apply_cc(K, KINERT); + + klispS_run(K); + + int status = errorp? 1 : 0; + + /* get the standard environment again in K->next_env */ + K->next_env = env; + return report(K, status); +} + +static void dotty(klisp_State *K) +{ + TValue env = K->next_env; + kinit_repl(K); + klispS_run(K); + /* get the standard environment again in K->next_env */ + K->next_env = env; +} + +static int handle_script(klisp_State *K, char **argv, int n) +{ + const char *fname; + /* XXX/TODO save arguments to script */ +// int narg = getargs(L, argv, n); /* collect arguments */ +// lua_setglobal(L, "arg"); + fname = argv[n]; + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + fname = NULL; /* stdin */ + + return dofile(K, fname); +} + +/* check that argument has no extra characters at the end */ +#define notail(x) {if ((x)[2] != '\0') return -1;} + +static int collectargs (char **argv, bool *pi, bool *pv, bool *pe) +{ + int i; + for (i = 1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') /* not an option? */ + return i; + switch (argv[i][1]) { /* option */ + case '-': + notail(argv[i]); + return (argv[i+1] != NULL ? i+1 : 0); + case '\0': + return i; + case 'i': + notail(argv[i]); + *pi = true; /* go through */ + case 'v': + notail(argv[i]); + *pv = true; + break; + case 'e': + *pe = true; /* go through */ +// case 'l': /* No library for now */ + if (argv[i][2] == '\0') { + i++; + if (argv[i] == NULL) + return -1; + } + break; + default: + return -1; /* invalid option */ + } + } + return 0; +} + +static int runargs (klisp_State *K, char **argv, int n) +{ + /* There is a standard env in K->next_env, a common one is used for all + evaluations (init, expression args, script/repl) */ + TValue env = K->next_env; + UNUSED(env); + + for (int i = 1; i < n; i++) { + if (argv[i] == NULL) + continue; + + klisp_assert(argv[i][0] == '-'); + + switch (argv[i][1]) { /* option */ + case 'e': { + const char *chunk = argv[i] + 2; + if (*chunk == '\0') + chunk = argv[++i]; + klisp_assert(chunk != NULL); + + if (dostring(K, chunk, "=(command line)") != 0) + return 1; + break; + } +// case 'l': /* no libraries for now */ + default: + break; + } + } + return 0; +} + +static int handle_klispinit(klisp_State *K) +{ + const char *init = getenv(KLISP_INIT); + if (init == NULL) + return 0; /* status OK */ + else + return dostring(K, init, "=" KLISP_INIT); +} + +/* This is weird but was done to follow lua scheme */ +struct Smain { + int argc; + char **argv; + int status; +}; + +static int 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; + + /* There is a standard env in K->next_env, a common one is used for all + evaluations (init, expression args, script/repl) */ + //TValue env = K->next_env; + + if (argv[0] && argv[0][0]) + progname = argv[0]; + + /* TODO Here we should load libraries, however we don't have any + non native bindings in the ground environment yet */ + + /* RATIONALE I wanted to write all bindings in c, so that I can later on + profile them against non native versions and see how they fare. + Also by writing all in c it's easy to be consistent, especially with + error messages */ + + /* init (eval KLISP_INIT env variable contents) */ + s->status = handle_klispinit(K); + if (s->status != 0) + return 0; + + 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; } + + if (has_v) + print_version(); + + s->status = runargs(K, argv, (script > 0) ? script : s->argc); + + if (s->status != 0) + return 0; + + if (script > 0) { + s->status = handle_script(K, argv, script); + } + + if (s->status != 0) + return 0; + + if (has_i) { + dotty(K); + } else if (script == 0 && !has_e && !has_v) { + if (true) { + print_version(); + dotty(K); + } else { + s->status = dofile(K, NULL); + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int status; + struct Smain s; + klisp_State *K = klispL_newstate(); + + if (K == NULL) { + k_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + + /* This is weird but was done to follow lua scheme */ + s.argc = argc; + s.argv = argv; + K->next_value = p2tv(&s); + status = pmain(K); + + klisp_close(K); + + return (status || s.status)? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/klisp.h b/src/klisp.h @@ -16,6 +16,12 @@ ** SOURCE NOTE: This is mostly from Lua. */ +#define KLISP_VERSION "klisp 0.2" +#define KLISP_RELEASE "klisp 0.2" +#define KLISP_VERSION_NUM 02 +#define KLISP_COPYRIGHT "Copyright (C) 2011 Andres Navarro, Oto Havle" +#define KLISP_AUTHORS "Andres Navarro, Oto Havle" + typedef struct klisp_State klisp_State; /* diff --git a/src/klispconf.h b/src/klispconf.h @@ -13,6 +13,101 @@ #include <stdint.h> #include <stdbool.h> +/* +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + +/* +@@ KLISP_ANSI controls the use of non-ansi features. +** CHANGE it (define it) if you want Klisp to avoid the use of any +** non-ansi feature or library. +*/ +#if defined(__STRICT_ANSI__) +#define KLISP_ANSI +#endif + + +#if !defined(KLISP_ANSI) && defined(_WIN32) +#define KLISP_WIN +#endif + +#if defined(KLISP_USE_LINUX) +#define KLISP_USE_POSIX +#define KLISP_USE_DLOPEN /* needs an extra library: -ldl */ +#define KLISP_USE_READLINE /* needs some extra libraries */ +#endif + +#if defined(KLISP_USE_MACOSX) +#define KLISP_USE_POSIX +#define KLISP_DL_DYLD /* does not need extra library */ +#endif + +/* +@@ KLISP_PROGNAME is the default name for the stand-alone klisp program. +** CHANGE it if your stand-alone interpreter has a different name and +** your system is not able to detect that name automatically. +*/ +#define KLISP_PROGNAME "klisp" + +/* +@@ KLISP_QL describes how error messages quote program elements. +** CHANGE it if you want a different appearance. +*/ +#define KLISP_QL(x) "'" x "'" +#define KLISP_QS KLISP_QL("%s") +/* /TODO */ + +/* +@@ KLISP_USE_POSIX includes all functionallity listed as X/Open System +@* Interfaces Extension (XSI). +** CHANGE it (define it) if your system is XSI compatible. +*/ +#if defined(KLISP_USE_POSIX) +#define KLISP_USE_MKSTEMP +#define KLISP_USE_ISATTY +#define KLISP_USE_POPEN +#define KLISP_USE_ULONGJMP +#endif + +/* +@@ LUA_PATH and LUA_CPATH are the names of the environment variables that +@* Lua check to set its paths. +@@ KLISP_INIT is the name of the environment variable that klisp +@* checks for initialization code. +** CHANGE them if you want different names. +*/ +//#define LUA_PATH "LUA_PATH" +//#define LUA_CPATH "LUA_CPATH" +#define KLISP_INIT "KLISP_INIT" + +/* +@@ klisp_stdin_is_tty detects whether the standard input is a 'tty' (that +@* is, whether we're running klisp interactively). +** CHANGE it if you have a better definition for non-POSIX/non-Windows +** systems. +*/ +#if defined(KLISP_USE_ISATTY) +#include <unistd.h> +#define klisp_stdin_is_tty() isatty(0) +#elif defined(KLISP_WIN) +#include <io.h> +#include <stdio.h> +#define klisp_stdin_is_tty() _isatty(_fileno(stdin)) +#else +#define klisp_stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + +/* +@@ KLISP_PROMPT is the default prompt used by stand-alone Klisp. +@@ KLISP_PROMPT2 is not currently used. +** CHANGE them if you want different prompts. +*/ +#define KLISP_PROMPT "klisp> " +/* XXX not used for now */ +#define KLISP_PROMPT2 ">> " + /* temp defines till gc is stabilized */ #define KUSE_GC 1 /* Print msgs when starting and ending gc */ diff --git a/src/kobject.c b/src/kobject.c @@ -30,6 +30,7 @@ const TValue kfree = KFREE_; /* ** The name strings for all TValue types +** This should be updated if types are modified in kobject.h */ char *ktv_names[] = { [K_TFIXINT] = "fixint", @@ -39,11 +40,12 @@ char *ktv_names[] = { [K_TEINF] = "einf", [K_TDOUBLE] = "double", [K_TBDOUBLE] = "bdouble", + [K_TIINF] = "einf", [K_TIINF] = "iinf", [K_TRWNPV] = "rwnpv", - [K_TUNDEFINED] = "undefined", [K_TCOMPLEX] = "complex", + [K_TUNDEFINED] = "undefined", [K_TNIL] = "nil", [K_TIGNORE] = "ignore", @@ -51,7 +53,7 @@ char *ktv_names[] = { [K_TEOF] = "eof", [K_TBOOLEAN] = "boolean", [K_TCHAR] = "char", - [K_TCHAR] = "free entry", + [K_TFREE] = "free entry", [K_TDEADKEY] = "dead key", [K_TUSER] = "user pointer", @@ -65,19 +67,13 @@ char *ktv_names[] = { [K_TAPPLICATIVE] = "applicative", [K_TENCAPSULATION] = "encapsulation", [K_TPROMISE] = "promise", - [K_TPORT] = "port" + [K_TTABLE] = "table", + [K_TERROR] = "error", + [K_TBYTEVECTOR] = "bytevector", + [K_TFPORT] = "file port", + [K_TMPORT] = "mem port" }; -bool kis_input_port(TValue o) -{ - return ttisport(o) && kport_is_input(o); -} - -bool kis_output_port(TValue o) -{ - return ttisport(o) && kport_is_output(o); -} - int32_t klispO_log2 (uint32_t x) { static const uint8_t log_2[256] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, diff --git a/src/kobject.h b/src/kobject.h @@ -46,7 +46,7 @@ typedef union GCObject GCObject; ** included in other objects) */ #define CommonHeader GCObject *next; uint8_t tt; uint8_t kflags; \ - uint16_t gct; GCObject *si; GCObject *gclist; + uint16_t gct; GCObject *si; GCObject *gclist /* NOTE: the gc flags are called marked in lua, but we reserve that them for marks used in cycle traversal. The field kflags is also missing @@ -127,6 +127,10 @@ typedef struct __attribute__ ((__packed__)) GCheader { */ /* LUA NOTE: In Lua the corresponding defines are in lua.h */ +/* +** The name strings for all TValue types are in kobject.c +** Thoseshould be updated if types here are modified +*/ #define K_TFIXINT 0 #define K_TBIGINT 1 #define K_TFIXRAT 2 @@ -158,10 +162,12 @@ typedef struct __attribute__ ((__packed__)) GCheader { #define K_TAPPLICATIVE 36 #define K_TENCAPSULATION 37 #define K_TPROMISE 38 -#define K_TPORT 39 -#define K_TTABLE 40 -#define K_TERROR 41 -#define K_TBLOB 42 +#define K_TTABLE 39 +#define K_TERROR 40 +#define K_TBYTEVECTOR 41 +#define K_TFPORT 42 +#define K_TMPORT 43 +#define K_TVECTOR 44 /* for tables */ #define K_TDEADKEY 60 @@ -211,11 +217,12 @@ typedef struct __attribute__ ((__packed__)) GCheader { #define K_TAG_APPLICATIVE K_MAKE_VTAG(K_TAPPLICATIVE) #define K_TAG_ENCAPSULATION K_MAKE_VTAG(K_TENCAPSULATION) #define K_TAG_PROMISE K_MAKE_VTAG(K_TPROMISE) -#define K_TAG_PORT K_MAKE_VTAG(K_TPORT) #define K_TAG_TABLE K_MAKE_VTAG(K_TTABLE) #define K_TAG_ERROR K_MAKE_VTAG(K_TERROR) -#define K_TAG_BLOB K_MAKE_VTAG(K_TBLOB) - +#define K_TAG_BYTEVECTOR K_MAKE_VTAG(K_TBYTEVECTOR) +#define K_TAG_FPORT K_MAKE_VTAG(K_TFPORT) +#define K_TAG_MPORT K_MAKE_VTAG(K_TMPORT) +#define K_TAG_VECTOR K_MAKE_VTAG(K_TVECTOR) /* ** Macros to test types @@ -237,6 +244,9 @@ typedef struct __attribute__ ((__packed__)) GCheader { #define ttisbigint(o) (tbasetype_(o) == K_TAG_BIGINT) #define ttiseinteger(o_) ({ int32_t t_ = tbasetype_(o_); \ t_ == K_TAG_FIXINT || t_ == K_TAG_BIGINT;}) +#define ttisu8(o) ({ \ + TValue o__ = (o); \ + (ttisfixint(o__) && ivalue(o__) >= 0 && ivalue(o__) < 256); }) #define ttisinteger(o) ({ TValue o__ = (o); \ (ttiseinteger(o__) || \ (ttisdouble(o__) && (floor(dvalue(o__)) == dvalue(o__))));}) @@ -293,10 +303,14 @@ typedef struct __attribute__ ((__packed__)) GCheader { #define ttiscontinuation(o) (tbasetype_(o) == K_TAG_CONTINUATION) #define ttisencapsulation(o) (tbasetype_(o) == K_TAG_ENCAPSULATION) #define ttispromise(o) (tbasetype_(o) == K_TAG_PROMISE) -#define ttisport(o) (tbasetype_(o) == K_TAG_PORT) #define ttistable(o) (tbasetype_(o) == K_TAG_TABLE) #define ttiserror(o) (tbasetype_(o) == K_TAG_ERROR) -#define ttisblob(o) (tbasetype_(o) == K_TAG_BLOB) +#define ttisbytevector(o) (tbasetype_(o) == K_TAG_BYTEVECTOR) +#define ttisfport(o) (tbasetype_(o) == K_TAG_FPORT) +#define ttismport(o) (tbasetype_(o) == K_TAG_MPORT) +#define ttisport(o_) ({ int32_t t_ = tbasetype_(o_); \ + t_ == K_TAG_FPORT || t_ == K_TAG_MPORT;}) +#define ttisvector(o) (tbasetype_(o) == K_TAG_VECTOR) /* macros to easily check boolean values */ #define kis_true(o_) (tv_equal((o_), KTRUE)) @@ -430,17 +444,30 @@ typedef struct __attribute__ ((__packed__)) { sharing the pair */ } Promise; +/* common fields for all types of ports */ +/* TEMP: for now source code info is in fixints */ +#define PortCommonFields TValue filename; int32_t row; int32_t col + +typedef struct __attribute__ ((__packed__)) { + CommonHeader; + PortCommonFields; +} Port; + /* input/output direction and open/close status are in kflags */ typedef struct __attribute__ ((__packed__)) { CommonHeader; - TValue filename; - /* TEMP: for now source code info is in fixints */ - int32_t row; - int32_t col; + PortCommonFields; FILE *file; -} Port; +} FPort; /* input/output direction and open/close status are in kflags */ +typedef struct __attribute__ ((__packed__)) { + CommonHeader; + PortCommonFields; + TValue buf; + uint32_t off; +} MPort; + /* ** Hashtables @@ -481,14 +508,22 @@ typedef struct __attribute__ ((__packed__)) { TValue irritants; /* list of extra objs */ } Error; -/* Blobs (binary vectors) */ +/* Bytevectors */ typedef struct __attribute__ ((__packed__)) { CommonHeader; TValue mark; /* for cycle/sharing aware algorithms */ uint32_t size; - int32_t __dummy; /* for alignment to 64 bits */ + uint32_t hash; /* only used for immutable strings */ uint8_t b[]; /* buffer */ -} Blob; +} Bytevector; + +/* Vectors (heterogenous arrays) */ +typedef struct __attribute__ ((__packed__)) { + CommonHeader; + TValue mark; /* for cycle/sharing aware algorithms */ + uint32_t sizearray; /* number of elements in array[] */ + TValue array[]; /* array of elements */ +} Vector; /* ** `module' operation for hashing (size is always a power of 2) @@ -546,9 +581,12 @@ union GCObject { Applicative app; Encapsulation enc; Promise prom; - Port port; Table table; - Blob blob; + Bytevector bytevector; + Port port; /* common fields for all types of ports */ + FPort fport; + MPort mport; + Vector vector; }; @@ -647,10 +685,12 @@ const TValue kfree; #define gc2app(o_) (gc2tv(K_TAG_APPLICATIVE, o_)) #define gc2enc(o_) (gc2tv(K_TAG_ENCAPSULATION, o_)) #define gc2prom(o_) (gc2tv(K_TAG_PROMISE, o_)) -#define gc2port(o_) (gc2tv(K_TAG_PORT, o_)) +#define gc2fport(o_) (gc2tv(K_TAG_FPORT, o_)) +#define gc2mport(o_) (gc2tv(K_TAG_MPORT, o_)) #define gc2table(o_) (gc2tv(K_TAG_TABLE, o_)) #define gc2error(o_) (gc2tv(K_TAG_ERROR, o_)) -#define gc2blob(o_) (gc2tv(K_TAG_BLOB, o_)) +#define gc2bytevector(o_) (gc2tv(K_TAG_BYTEVECTOR, o_)) +#define gc2vector(o_) (gc2tv(K_TAG_VECTOR, o_)) #define gc2deadkey(o_) (gc2tv(K_TAG_DEADKEY, o_)) /* Macro to convert a TValue into a specific heap allocated object */ @@ -665,10 +705,13 @@ const TValue kfree; #define tv2app(v_) ((Applicative *) gcvalue(v_)) #define tv2enc(v_) ((Encapsulation *) gcvalue(v_)) #define tv2prom(v_) ((Promise *) gcvalue(v_)) -#define tv2port(v_) ((Port *) gcvalue(v_)) #define tv2table(v_) ((Table *) gcvalue(v_)) #define tv2error(v_) ((Error *) gcvalue(v_)) -#define tv2blob(v_) ((Blob *) gcvalue(v_)) +#define tv2bytevector(v_) ((Bytevector *) gcvalue(v_)) +#define tv2vector(v_) ((Vector *) gcvalue(v_)) +#define tv2fport(v_) ((FPort *) gcvalue(v_)) +#define tv2mport(v_) ((MPort *) gcvalue(v_)) +#define tv2port(v_) ((Port *) gcvalue(v_)) #define tv2gch(v_) ((GCheader *) gcvalue(v_)) #define tv2mgch(v_) ((MGCheader *) gcvalue(v_)) @@ -789,14 +832,20 @@ int32_t kmark_count; #define K_FLAG_OUTPUT_PORT 0x01 #define K_FLAG_INPUT_PORT 0x02 #define K_FLAG_CLOSED_PORT 0x04 +/* At least for now ports are either binary or textual */ +#define K_FLAG_BINARY_PORT 0x08 #define kport_set_input(o_) (tv_get_kflags(o_) |= K_FLAG_INPUT_PORT) #define kport_set_output(o_) (tv_get_kflags(o_) |= K_FLAG_INPUT_PORT) #define kport_set_closed(o_) (tv_get_kflags(o_) |= K_FLAG_CLOSED_PORT) +#define kport_set_binary(o_) (tv_get_kflags(o_) |= K_FLAG_BINARY_PORT) #define kport_is_input(o_) ((tv_get_kflags(o_) & K_FLAG_INPUT_PORT) != 0) #define kport_is_output(o_) ((tv_get_kflags(o_) & K_FLAG_OUTPUT_PORT) != 0) +#define kport_is_open(o_) ((tv_get_kflags(o_) & K_FLAG_CLOSED_PORT) == 0) #define kport_is_closed(o_) ((tv_get_kflags(o_) & K_FLAG_CLOSED_PORT) != 0) +#define kport_is_binary(o_) ((tv_get_kflags(o_) & K_FLAG_BINARY_PORT) != 0) +#define kport_is_textual(o_) ((tv_get_kflags(o_) & K_FLAG_BINARY_PORT) == 0) #define K_FLAG_WEAK_KEYS 0x01 #define K_FLAG_WEAK_VALUES 0x02 @@ -807,11 +856,6 @@ int32_t kmark_count; #define ktable_has_weak_values(o_) \ ((tv_get_kflags(o_) & K_FLAG_WEAK_VALUES) != 0) -/* can't be inline because we also use pointers to them, - (at least gcc doesn't bother to create them and the linker fails) */ -bool kis_input_port(TValue o); -bool kis_output_port(TValue o); - /* Macro to test the most basic equality on TValues */ #define tv_equal(tv1_, tv2_) ((tv1_).raw == (tv2_).raw) diff --git a/src/koperative.c b/src/koperative.c @@ -13,7 +13,7 @@ #include "kgc.h" /* GC: Assumes all argps are rooted */ -TValue kmake_operative(klisp_State *K, klisp_Ofunc fn, int32_t xcount, ...) +TValue kmake_operative(klisp_State *K, klisp_CFunction fn, int32_t xcount, ...) { va_list argp; diff --git a/src/koperative.h b/src/koperative.h @@ -13,6 +13,7 @@ /* TODO: make some specialized constructors for 0, 1 and 2 parameters */ /* GC: Assumes all argps are rooted */ -TValue kmake_operative(klisp_State *K, klisp_Ofunc fn, int xcount, ...); +TValue kmake_operative(klisp_State *K, klisp_CFunction fn, int32_t xcount, + ...); #endif diff --git a/src/kpair.c b/src/kpair.c @@ -58,3 +58,11 @@ TValue klist_g(klisp_State *K, bool m, int32_t n, ...) bool kpairp(TValue obj) { return ttispair(obj); } +bool kimmutable_pairp(TValue obj) +{ + return ttispair(obj) && kis_immutable(obj); +} +bool kmutable_pairp(TValue obj) +{ + return ttispair(obj) && kis_mutable(obj); +} diff --git a/src/kpair.h b/src/kpair.h @@ -14,11 +14,8 @@ /* can't be inlined... */ bool kpairp(TValue obj); - -inline bool kmutable_pairp(TValue obj) -{ - return ttispair(obj) && kis_mutable(obj); -} +bool kimmutable_pairp(TValue obj); +bool kmutable_pairp(TValue obj); inline TValue kcar(TValue p) { diff --git a/src/kport.c b/src/kport.c @@ -6,6 +6,7 @@ #include <stdio.h> #include <assert.h> +#include <string.h> #include "kport.h" #include "kobject.h" @@ -13,9 +14,62 @@ #include "kmem.h" #include "kerror.h" #include "kstring.h" +#include "kbytevector.h" #include "kgc.h" #include "kpair.h" +bool kportp(TValue o) +{ + return ttisport(o); +} + +bool kinput_portp(TValue o) +{ + return ttisport(o) && kport_is_input(o); +} + +bool koutput_portp(TValue o) +{ + return ttisport(o) && kport_is_output(o); +} + +bool kbinary_portp(TValue o) +{ + return ttisport(o) && kport_is_binary(o); +} + +bool ktextual_portp(TValue o) +{ + return ttisport(o) && kport_is_textual(o); +} + +bool kfile_portp(TValue o) +{ + return ttisfport(o); +} + +bool kstring_portp(TValue o) +{ + return ttismport(o) && kport_is_textual(o); +} + +bool kbytevector_portp(TValue o) +{ + return ttismport(o) && kport_is_binary(o); +} + +bool kport_openp(TValue o) +{ + klisp_assert(ttisport(o)); + return kport_is_open(o); +} + +bool kport_closedp(TValue o) +{ + klisp_assert(ttisport(o)); + return kport_is_closed(o); +} + /* XXX: per the c spec, this truncates the file if it exists! */ /* Ask John: what would be best? Probably should also include delete, file-exists? and a mechanism to truncate or append to a file, or @@ -23,16 +77,23 @@ Should use open, but it is non standard (fcntl.h, POSIX only) */ /* GC: Assumes filename is rooted */ -TValue kmake_port(klisp_State *K, TValue filename, bool writep) +TValue kmake_fport(klisp_State *K, TValue filename, bool writep, bool binaryp) { /* for now always use text mode */ - FILE *f = fopen(kstring_buf(filename), writep? "w": "r"); + char *mode; + if (binaryp) + mode = writep? "wb": "rb"; + else + mode = writep? "w": "r"; + + FILE *f = fopen(kstring_buf(filename), mode); if (f == NULL) { - klispE_throw_errno_with_irritants(K, "fopen", 2, filename, - kstring_new_b_imm(K, writep? "w": "r")); + TValue mode_str = kstring_new_b(K, mode); + krooted_tvs_push(K, mode_str); + klispE_throw_errno_with_irritants(K, "fopen", 2, filename, mode_str); return KINERT; } else { - return kmake_std_port(K, filename, writep, f); + return kmake_std_fport(K, filename, writep, binaryp, f); } } @@ -40,20 +101,21 @@ TValue kmake_port(klisp_State *K, TValue filename, bool writep) also a helper for the above */ /* GC: Assumes filename, name & si are rooted */ -TValue kmake_std_port(klisp_State *K, TValue filename, bool writep, - FILE *file) +TValue kmake_std_fport(klisp_State *K, TValue filename, bool writep, + bool binaryp, FILE *file) { - Port *new_port = klispM_new(K, Port); + FPort *new_port = klispM_new(K, FPort); /* header + gc_fields */ - klispC_link(K, (GCObject *) new_port, K_TPORT, + klispC_link(K, (GCObject *) new_port, K_TFPORT, K_FLAG_CAN_HAVE_NAME | - (writep? K_FLAG_OUTPUT_PORT : K_FLAG_INPUT_PORT)); + (writep? K_FLAG_OUTPUT_PORT : K_FLAG_INPUT_PORT) | + (binaryp? K_FLAG_BINARY_PORT : 0)); /* port specific fields */ new_port->filename = filename; new_port->file = file; - TValue tv_port = gc2port(new_port); + TValue tv_port = gc2fport(new_port); /* line is 1-based and col is 0-based */ kport_line(tv_port) = 1; kport_col(tv_port) = 0; @@ -61,16 +123,51 @@ TValue kmake_std_port(klisp_State *K, TValue filename, bool writep, return tv_port; } +TValue kmake_mport(klisp_State *K, TValue buffer, bool writep, bool binaryp) +{ + klisp_assert(!writep || ttisinert(buffer)); + klisp_assert(writep || (ttisbytevector(buffer) && binaryp) || + (ttisstring(buffer) && !binaryp)); + + if (writep) { + buffer = binaryp? kbytevector_new_s(K, MINBYTEVECTORPORTBUFFER) : + kstring_new_s(K, MINSTRINGPORTBUFFER); + } + + krooted_tvs_push(K, buffer); + + MPort *new_port = klispM_new(K, MPort); + + /* header + gc_fields */ + klispC_link(K, (GCObject *) new_port, K_TMPORT, + K_FLAG_CAN_HAVE_NAME | + (writep? K_FLAG_OUTPUT_PORT : K_FLAG_INPUT_PORT) | + (binaryp? K_FLAG_BINARY_PORT : 0)); + + /* port specific fields */ + TValue tv_port = gc2mport(new_port); + kport_filename(tv_port) = K->empty_string; /* XXX for now no filename */ + /* line is 1-based and col is 0-based */ + kport_line(tv_port) = 1; + kport_col(tv_port) = 0; + kmport_buf(tv_port) = buffer; + kmport_off(tv_port) = 0; /* no bytes read/written */ + krooted_tvs_pop(K); + return tv_port; +} + /* if the port is already closed do nothing */ +/* This is also called from GC, so it shouldn't throw any error */ void kclose_port(klisp_State *K, TValue port) { assert(ttisport(port)); if (!kport_is_closed(port)) { - FILE *f = tv2port(port)->file; - if (f != stdin && f != stderr && f != stdout) - fclose(f); /* it isn't necessary to check the close ret val */ - + if (ttisfport(port)) { + FILE *f = tv2fport(port)->file; + if (f != stdin && f != stderr && f != stdout) + fclose(f); /* it isn't necessary to check the close ret val */ + } kport_set_closed(port); } @@ -89,3 +186,45 @@ void kport_update_source_info(TValue port, int32_t line, int32_t col) kport_line(port) = line; kport_col(port) = col; } + +/* Always grow by doubling the size (until min_size is reached) */ +/* GC: port should be rooted */ +void kmport_resize_buffer(klisp_State *K, TValue port, size_t min_size) +{ + klisp_assert(ttismport(port)); + klisp_assert(kport_is_output(port)); + + uint32_t old_size = (kport_is_binary(port))? + kbytevector_size(kmport_buf(port)) : + kstring_size(kmport_buf(port)); + uint64_t new_size = old_size; + + while (new_size < min_size) { + new_size *= 2; + if (new_size > SIZE_MAX) + klispM_toobig(K); + } + + if (new_size == old_size) + return; + + if (kport_is_binary(port)) { + TValue new_bb = kbytevector_new_s(K, new_size); + uint32_t off = kmport_off(port); + if (off != 0) { + memcpy(kbytevector_buf(new_bb), + kbytevector_buf(kmport_buf(port)), + off); + } + kmport_buf(port) = new_bb; + } else { + TValue new_str = kstring_new_s(K, new_size); + uint32_t off = kmport_off(port); + if (off != 0) { + memcpy(kstring_buf(new_str), + kstring_buf(kmport_buf(port)), + off); + } + kmport_buf(port) = new_str; + } +} diff --git a/src/kport.h b/src/kport.h @@ -12,27 +12,49 @@ #include "kobject.h" #include "kstate.h" +/* can't be inline because we also use pointers to them, + (at least gcc doesn't bother to create them and the linker fails) */ +bool kportp(TValue o); +bool kinput_portp(TValue o); +bool koutput_portp(TValue o); +bool kbinary_portp(TValue o); +bool ktextual_portp(TValue o); +bool kfile_portp(TValue o); +bool kstring_portp(TValue o); +bool kbytevector_portp(TValue o); +bool kport_openp(TValue o); +bool kport_closedp(TValue o); + /* GC: Assumes filename is rooted */ -TValue kmake_port(klisp_State *K, TValue filename, bool writep); +TValue kmake_fport(klisp_State *K, TValue filename, bool writep, bool binaryp); /* this is for creating ports for stdin/stdout/stderr & helper for the one above */ /* GC: Assumes filename, name & si are rooted */ -TValue kmake_std_port(klisp_State *K, TValue filename, bool writep, - FILE *file); +TValue kmake_std_fport(klisp_State *K, TValue filename, bool writep, + bool binaryp, FILE *file); + +/* GC: buffer doesn't need to be rooted, but should probably do it anyways */ +TValue kmake_mport(klisp_State *K, TValue buffer, bool writep, bool binaryp); -/* This closes the underlying FILE * (unless it is a std port) and also - set the closed flag to true, this shouldn't throw errors because it - is also called when deallocating all objs. If errors need to be thrown +/* This closes the underlying FILE * (unless it is a std port or memory port) + and also set the closed flag to true, this shouldn't throw errors because + it is also called when deallocating all objs. If errors need to be thrown fork this function instead of simply modifying */ void kclose_port(klisp_State *K, TValue port); -#define kport_file(p_) (tv2port(p_)->file) #define kport_filename(p_) (tv2port(p_)->filename) #define kport_line(p_) (tv2port(p_)->row) #define kport_col(p_) (tv2port(p_)->col) +#define kfport_file(p_) (tv2fport(p_)->file) + +#define kmport_off(p_) (tv2mport(p_)->off) +#define kmport_buf(p_) (tv2mport(p_)->buf) + void kport_reset_source_info(TValue port); void kport_update_source_info(TValue port, int32_t line, int32_t col); +/* GC: port should be rooted */ +void kmport_resize_buffer(klisp_State *K, TValue port, uint32_t min_size); #endif diff --git a/src/kread.c b/src/kread.c @@ -6,7 +6,6 @@ #include <stdio.h> #include <stdlib.h> -#include <assert.h> #include "kread.h" #include "kobject.h" @@ -36,12 +35,18 @@ ** info as above (but no pair with last pair). ** ST_SHARED_DEF: a pair with car: shared def token and cdr: source ** info of the shared def token. -** +** ST_SEXP_COMMENT: the source info of the comment token +** ST_FIRST_EOF_LIST: first pair of the list (with source info, start of file) +** ST_MIDDLE_EOF_LIST: two elements, first below, second on top: +** - a pair with car: first pair of the list (with source info corrected +** to car of list) and cdr: source info of the start of file. +** - last pair of the list so far. */ typedef enum { ST_READ, ST_SHARED_DEF, ST_LAST_ILIST, ST_PAST_LAST_ILIST, - ST_FIRST_LIST, ST_MIDDLE_LIST + ST_FIRST_LIST, ST_MIDDLE_LIST, ST_SEXP_COMMENT, ST_FIRST_EOF_LIST, + ST_MIDDLE_EOF_LIST } state_t; #define push_state(kst_, st_) (ks_spush(kst_, (i2tv((int32_t)(st_))))) @@ -56,7 +61,12 @@ typedef enum { /* ** Error management */ -void kread_error(klisp_State *K, char *str) +#define kread_error(K, str) \ + kread_error_g(K, str, false, KINERT) +#define kread_error_extra(K, str, extra) \ + kread_error_g(K, str, true, extra) + +void kread_error_g(klisp_State *K, char *str, bool extra, TValue extra_value) { /* all cleaning is done in throw (stacks, shared_dict, rooted objs) */ @@ -65,10 +75,18 @@ void kread_error(klisp_State *K, char *str) kport_update_source_info(K->curr_port, K->ktok_source_info.line, K->ktok_source_info.col); - /* include the source info in the error */ - TValue si = ktok_get_source_info(K); - krooted_tvs_push(K, si); /* will be popped by throw */ - klispE_throw_with_irritants(K, str, si); + /* include the source info (and extra value if present) in the error */ + TValue irritants; + if (extra) { + krooted_tvs_push(K, extra_value); /* will be popped by throw */ + TValue si = ktok_get_source_info(K); + krooted_tvs_push(K, si); /* will be popped by throw */ + irritants = klist_g(K, false, 2, si, extra_value); + } else { + irritants = ktok_get_source_info(K); + } + krooted_tvs_push(K, irritants); /* will be popped by throw */ + klispE_throw_with_irritants(K, str, irritants); } /* @@ -89,7 +107,7 @@ TValue try_shared_ref(klisp_State *K, TValue ref_token) tail = kcdr(tail); } - kread_error(K, "undefined shared ref found"); + kread_error_extra(K, "undefined shared ref found", i2tv(ref_num)); /* avoid warning */ return KINERT; } @@ -103,7 +121,7 @@ void try_shared_def(klisp_State *K, TValue def_token, TValue value) while (!ttisnil(tail)) { TValue head = kcar(tail); if (ref_num == ivalue(kcar(head))) { - kread_error(K, "duplicate shared def found"); + kread_error_extra(K, "duplicate shared def found", i2tv(ref_num)); /* avoid warning */ return; } @@ -132,29 +150,92 @@ void change_shared_def(klisp_State *K, TValue def_token, TValue value) } tail = kcdr(tail); } - /* NOTE: can't really happen */ + klisp_assert(0); /* shouldn't happen */ + return; +} + +/* NOTE: the shared def is guaranteed to exist */ +void remove_shared_def(klisp_State *K, TValue def_token) +{ + /* IMPLEMENTATION RESTRICTION: only allow fixints in shared tokens */ + int32_t ref_num = ivalue(kcdr(def_token)); + TValue tail = K->shared_dict; + TValue last_pair = KNIL; + while (!ttisnil(tail)) { + TValue head = kcar(tail); + if (ref_num == ivalue(kcar(head))) { + if (ttisnil(last_pair)) { + /* this is the first value */ + K->shared_dict = kcdr(tail); + } else { + kset_cdr(last_pair, kcdr(tail)); + } + return; + } + last_pair = tail; + tail = kcdr(tail); + } + klisp_assert(0); /* shouldn't happen */ return; } /* ** Reader FSM */ + +/* +** listp: +** false: read one value +** true: read all values as a list +*/ + /* TEMP: For now we'll use just one big function */ -TValue kread_fsm(klisp_State *K) +TValue kread_fsm(klisp_State *K, bool listp) { - assert(ks_sisempty(K)); - assert(ttisnil(K->shared_dict)); + /* TODO add more specific sexp comment error msgs */ + /* TODO replace some read errors with asserts where appropriate */ + klisp_assert(ks_sisempty(K)); + klisp_assert(ttisnil(K->shared_dict)); + push_state(K, ST_READ); + if (listp) { /* read a list of values */ + /* create the first pair */ + TValue np = kcons_g(K, K->read_mconsp, KINERT, KNIL); + krooted_tvs_push(K, np); + /* + ** NOTE: the source info of the start of file is temporarily + ** saved in np (later it will be replace by the source info + ** of the car of the list) + */ + TValue si = ktok_get_source_info(K); + krooted_tvs_push(K, si); +#if KTRACK_SI + kset_source_info(K, np, si); +#endif + krooted_tvs_pop(K); + push_data(K, np); + krooted_tvs_pop(K); + push_state(K, ST_FIRST_EOF_LIST); + } + /* read next token or process obj */ bool read_next_token = true; /* the obj just read/completed */ TValue obj = KINERT; /* put some value for gc */ /* the source code information of that obj */ TValue obj_si = KNIL; /* put some value for gc */ + int32_t sexp_comments = 0; + TValue last_sexp_comment_si = KNIL; /* put some value for gc */ + /* list of shared list, each element represent a nested sexp comment, + each is a list of shared defs in that particular level, to be + undefined after the sexp comment ends */ + TValue sexp_comment_shared = KNIL; krooted_vars_push(K, &obj); krooted_vars_push(K, &obj_si); + krooted_vars_push(K, &last_sexp_comment_si); + krooted_vars_push(K, &sexp_comment_shared); while (!(get_state(K) == ST_READ && !read_next_token)) { if (read_next_token) { @@ -218,6 +299,7 @@ TValue kread_fsm(klisp_State *K) obj_si = kget_source_info(K, fp_with_old_si); #else UNUSED(fp_with_old_si); + obj_si = KNIL; #endif read_next_token = false; break; @@ -246,7 +328,14 @@ TValue kread_fsm(klisp_State *K) "in shared def"); /* avoid warning */ return KINERT; + case ST_SEXP_COMMENT: + kread_error_extra(K, "unmatched closing paren found in " + "sexp comment", last_sexp_comment_si); + /* avoid warning */ + return KINERT; case ST_READ: + case ST_FIRST_EOF_LIST: + case ST_MIDDLE_EOF_LIST: kread_error(K, "unmatched closing paren found"); /* avoid warning */ return KINERT; @@ -280,7 +369,14 @@ TValue kread_fsm(klisp_State *K) kread_error(K, "dot found in shared def"); /* avoid warning */ return KINERT; + case ST_SEXP_COMMENT: + kread_error_extra(K, "dot found outside list in sexp " + "comment", last_sexp_comment_si); + /* avoid warning */ + return KINERT; case ST_READ: + case ST_FIRST_EOF_LIST: + case ST_MIDDLE_EOF_LIST: kread_error(K, "dot found outside list"); /* avoid warning */ return KINERT; @@ -307,7 +403,13 @@ TValue kread_fsm(klisp_State *K) default: { krooted_tvs_push(K, tok); try_shared_def(K, tok, KNIL); - /* token ok, read defined object */ + /* token ok */ + /* save the token for later undefining */ + if (sexp_comments > 0) { + kset_car(sexp_comment_shared, + kcons(K, tok, kcar(sexp_comment_shared))); + } + /* read defined object */ /* NOTE: save the source info to return it after the defined object is read */ TValue si = ktok_get_source_info(K); @@ -344,6 +446,17 @@ TValue kread_fsm(klisp_State *K) } break; } + case ';': { /* sexp comment */ + klisp_assert(sexp_comments < 1000); + ++sexp_comments; + sexp_comment_shared = + kcons(K, KNIL, sexp_comment_shared); + push_data(K, last_sexp_comment_si); + push_state(K, ST_SEXP_COMMENT); + last_sexp_comment_si = ktok_get_source_info(K); + read_next_token = true; + break; + } default: /* shouldn't happen */ kread_error(K, "unknown special token"); @@ -352,10 +465,42 @@ TValue kread_fsm(klisp_State *K) } } else if (ttiseof(tok)) { switch (get_state(K)) { + case ST_SEXP_COMMENT: + kread_error_extra(K, "EOF found while reading sexp " + " comment", last_sexp_comment_si); + /* avoid warning */ + return KINERT; + case ST_FIRST_EOF_LIST: { + pop_state(K); + TValue fp_with_old_si = get_data(K); + pop_data(K); + obj = KNIL; + #if KTRACK_SI + obj_si = kget_source_info(K, fp_with_old_si); + #else + UNUSED(fp_with_old_si); + obj_si = KNIL; + #endif + read_next_token = false; + break; + } + case ST_MIDDLE_EOF_LIST: { + pop_state(K); + /* discard info on last pair */ + pop_data(K); + pop_state(K); + TValue fp_old_si = get_data(K); + pop_data(K); + /* list read ok, process it in next iteration */ + obj = kcar(fp_old_si); + obj_si = kcdr(fp_old_si); + read_next_token = false; + break; + } case ST_READ: - /* will exit in next loop */ obj = tok; obj_si = ktok_get_source_info(K); + /* will exit in next loop */ read_next_token = false; break; case ST_FIRST_LIST: @@ -395,7 +540,9 @@ TValue kread_fsm(klisp_State *K) } else { /* if(read_next_token) */ /* process the object just read */ switch(get_state(K)) { + case ST_FIRST_EOF_LIST: case ST_FIRST_LIST: { + state_t state = get_state(K); /* get the state out of the way */ pop_state(K); TValue fp = get_data(K); @@ -421,13 +568,22 @@ TValue kread_fsm(klisp_State *K) push_data(K, kcons (K, fp, fp_old_si)); krooted_tvs_pop(K); krooted_tvs_pop(K); - push_state(K, ST_FIRST_LIST); + push_state(K, state); push_data(K, fp); - push_state(K, ST_MIDDLE_LIST); + if (state == ST_FIRST_LIST) { + push_state(K, ST_MIDDLE_LIST); + } else { + push_state(K, ST_MIDDLE_EOF_LIST); + /* shared dict must be cleared after every element + of an eof list */ + clear_shared_dict(K); + } read_next_token = true; break; } - case ST_MIDDLE_LIST: { + case ST_MIDDLE_LIST: + case ST_MIDDLE_EOF_LIST: { + state_t state = get_state(K); /* get the state out of the way */ pop_state(K); /* construct the list with the correct type of pair */ @@ -441,7 +597,12 @@ TValue kread_fsm(klisp_State *K) /* replace last pair of the (still incomplete) read next obj */ pop_data(K); push_data(K, np); - push_state(K, ST_MIDDLE_LIST); + push_state(K, state); + if (state == ST_MIDDLE_EOF_LIST) { + /* shared dict must be cleared after every element + of an eof list */ + clear_shared_dict(K); + } krooted_tvs_pop(K); read_next_token = true; break; @@ -473,6 +634,22 @@ TValue kread_fsm(klisp_State *K) kread_error(K, "invalid read state (read in while)"); /* avoid warning */ return KINERT; + case ST_SEXP_COMMENT: + klisp_assert(sexp_comments > 0); + --sexp_comments; + /* undefine all shared obj defined in the context + of this sexp comment */ + while(!ttisnil(kcar(sexp_comment_shared))) { + TValue first = kcaar(sexp_comment_shared); + remove_shared_def(K, first); + kset_car(sexp_comment_shared, kcdar(sexp_comment_shared)); + } + sexp_comment_shared = kcdr(sexp_comment_shared); + pop_state(K); + last_sexp_comment_si = get_data(K); + pop_data(K); + read_next_token = true; + break; default: /* shouldn't happen */ kread_error(K, "unknown read state in process obj"); @@ -484,24 +661,26 @@ TValue kread_fsm(klisp_State *K) krooted_vars_pop(K); krooted_vars_pop(K); + krooted_vars_pop(K); + krooted_vars_pop(K); pop_state(K); - assert(ks_sisempty(K)); + klisp_assert(ks_sisempty(K)); return obj; } /* ** Reader Main Function */ -TValue kread(klisp_State *K) +TValue kread(klisp_State *K, bool listp) { TValue obj; - assert(ttisnil(K->shared_dict)); - /* TEMP: workaround repl problem with eofs */ + klisp_assert(ttisnil(K->shared_dict)); + /* WORKAROUND: for repl problem with eofs */ K->ktok_seen_eof = false; - obj = kread_fsm(K); + obj = kread_fsm(K, listp); /* NOTE: clear after function to allow earlier gc */ clear_shared_dict(K); @@ -509,23 +688,32 @@ TValue kread(klisp_State *K) return obj; } - -TValue kread_from_port(klisp_State *K, TValue port, bool mut) +/* port is protected from GC in curr_port */ +TValue kread_from_port_g(klisp_State *K, TValue port, bool mut, bool listp) { K->curr_port = port; - K->curr_in = kport_file(port); K->read_mconsp = mut; ktok_set_source_info(K, kport_filename(port), kport_line(port), kport_col(port)); - TValue obj = kread(K); + TValue obj = kread(K, listp); kport_update_source_info(port, K->ktok_source_info.line, K->ktok_source_info.col); return obj; } +TValue kread_from_port(klisp_State *K, TValue port, bool mut) +{ + return kread_from_port_g(K, port, mut, false); +} + +TValue kread_list_from_port(klisp_State *K, TValue port, bool mut) +{ + return kread_from_port_g(K, port, mut, true); +} + TValue kread_peek_char_from_port(klisp_State *K, TValue port, bool peek) { /* Reset the EOF flag in the tokenizer. The flag is shared, @@ -533,7 +721,6 @@ TValue kread_peek_char_from_port(klisp_State *K, TValue port, bool peek) K->ktok_seen_eof = false; K->curr_port = port; - K->curr_in = kport_file(port); int ch; if (peek) { ch = ktok_peekc(K); @@ -547,13 +734,33 @@ TValue kread_peek_char_from_port(klisp_State *K, TValue port, bool peek) return ch == EOF? KEOF : ch2tv((char)ch); } +TValue kread_peek_u8_from_port(klisp_State *K, TValue port, bool peek) +{ + /* Reset the EOF flag in the tokenizer. The flag is shared, + by operations on all ports. */ + K->ktok_seen_eof = false; + K->curr_port = port; + int32_t u8; + if (peek) { + u8 = ktok_peekc(K); + } else { + ktok_set_source_info(K, kport_filename(port), + kport_line(port), kport_col(port)); + u8 = ktok_getc(K); + kport_update_source_info(port, K->ktok_source_info.line, + K->ktok_source_info.col); + } + return u8 == EOF? KEOF : i2tv(u8 & 0xff); +} + /* This is needed by the repl to ignore trailing spaces (especially newlines) that could affect the source info */ +/* XXX This should be replaced somehow, as it doesn't work for sexp and + multi line comments */ void kread_ignore_whitespace_and_comments_from_port(klisp_State *K, TValue port) { K->curr_port = port; - K->curr_in = kport_file(port); /* source code info isn't important because it will be reset later */ ktok_ignore_whitespace_and_comments(K); } diff --git a/src/kread.h b/src/kread.h @@ -14,7 +14,9 @@ ** Reader interface */ TValue kread_from_port(klisp_State *K, TValue port, bool mut); +TValue kread_list_from_port(klisp_State *K, TValue port, bool mut); TValue kread_peek_char_from_port(klisp_State *K, TValue port, bool peek); +TValue kread_peek_u8_from_port(klisp_State *K, TValue port, bool peek); void kread_ignore_whitespace_and_comments_from_port(klisp_State *K, TValue port); diff --git a/src/krepl.c b/src/krepl.c @@ -22,31 +22,25 @@ #include "kgerror.h" /* for names */ #include "ktable.h" +/* for do_pass_value */ +#include "kgcontinuations.h" /* TODO add names & source info to the repl continuations */ -/* the exit continuation, it exits the loop */ -void do_repl_exit(klisp_State *K, TValue *xparams, TValue obj) -{ - UNUSED(xparams); - UNUSED(obj); - - /* force the loop to terminate */ - K->next_func = NULL; - return; -} - /* the underlying function of the read cont */ -void do_repl_read(klisp_State *K, TValue *xparams, TValue obj) +void do_repl_read(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); UNUSED(xparams); UNUSED(obj); /* show prompt */ - fprintf(stdout, "klisp> "); + fprintf(stdout, KLISP_PROMPT); TValue port = kcdr(K->kd_in_port_key); - klisp_assert(kport_file(port) == stdin); + klisp_assert(kfport_file(port) == stdin); #if 0 /* Let's disable this for now */ /* workaround to the problem of the dangling '\n' in repl (from previous line) */ @@ -59,8 +53,11 @@ void do_repl_read(klisp_State *K, TValue *xparams, TValue obj) } /* the underlying function of the eval cont */ -void do_repl_eval(klisp_State *K, TValue *xparams, TValue obj) +void do_repl_eval(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: dynamic environment */ @@ -71,6 +68,7 @@ void do_repl_eval(klisp_State *K, TValue *xparams, TValue obj) /* this will in turn call main_cont */ /* print a newline to allow the shell a fresh line */ printf("\n"); + /* This is ok because there is no interception possible */ kset_cc(K, K->root_cont); kapply_cc(K, KINERT); } else { @@ -84,15 +82,46 @@ void do_repl_eval(klisp_State *K, TValue *xparams, TValue obj) } } -void do_repl_loop(klisp_State *K, TValue *xparams, TValue obj); +void do_repl_loop(klisp_State *K); +void do_int_repl_error(klisp_State *K); /* this is called from both do_repl_loop and do_repl_error */ /* GC: assumes denv is NOT rooted */ -inline void create_loop(klisp_State *K, TValue denv) +void create_loop(klisp_State *K, TValue denv) { krooted_tvs_push(K, denv); + + /* TODO this should be factored out, it is quite common */ + TValue error_int = kmake_operative(K, do_int_repl_error, 1, denv); + krooted_tvs_pop(K); /* already in cont */ + krooted_tvs_push(K, error_int); + TValue exit_guard = kcons(K, K->error_cont, error_int); + krooted_tvs_pop(K); /* already in guard */ + krooted_tvs_push(K, exit_guard); + TValue exit_guards = kcons(K, exit_guard, KNIL); + krooted_tvs_pop(K); /* already in guards */ + krooted_tvs_push(K, exit_guards); + + TValue entry_guards = KNIL; + + /* this is needed for interception code */ + TValue env = kmake_empty_environment(K); + krooted_tvs_push(K, env); + TValue outer_cont = kmake_continuation(K, K->root_cont, + do_pass_value, 2, entry_guards, env); + kset_outer_cont(outer_cont); + krooted_tvs_push(K, outer_cont); + TValue inner_cont = kmake_continuation(K, outer_cont, + do_pass_value, 2, exit_guards, env); + kset_inner_cont(inner_cont); + krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K); + + /* stack is empty now */ + krooted_tvs_push(K, inner_cont); + TValue loop_cont = - kmake_continuation(K, K->root_cont, do_repl_loop, 1, denv); + kmake_continuation(K, inner_cont, do_repl_loop, 1, denv); + krooted_tvs_pop(K); /* in loop cont */ krooted_tvs_push(K, loop_cont); TValue eval_cont = kmake_continuation(K, loop_cont, do_repl_eval, 1, denv); krooted_tvs_pop(K); /* in eval cont */ @@ -100,19 +129,21 @@ inline void create_loop(klisp_State *K, TValue denv) TValue read_cont = kmake_continuation(K, eval_cont, do_repl_read, 0); kset_cc(K, read_cont); krooted_tvs_pop(K); - krooted_tvs_pop(K); kapply_cc(K, KINERT); } /* the underlying function of the write & loop cont */ -void do_repl_loop(klisp_State *K, TValue *xparams, TValue obj) +void do_repl_loop(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: dynamic environment */ TValue port = kcdr(K->kd_out_port_key); - klisp_assert(kport_file(port) == stdout); + klisp_assert(kfport_file(port) == stdout); /* false: quote strings, escape chars */ kwrite_display_to_port(K, port, obj, false); @@ -123,15 +154,27 @@ void do_repl_loop(klisp_State *K, TValue *xparams, TValue obj) } /* the underlying function of the error cont */ -void do_repl_error(klisp_State *K, TValue *xparams, TValue obj) +void do_int_repl_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)); /* ** xparams[0]: dynamic environment */ + UNUSED(denv); + + /* + ** ptree is (object divert) + */ + TValue obj = kcar(ptree); + TValue divert = kcadr(ptree); + /* FOR NOW used only for irritant list */ TValue port = kcdr(K->kd_error_port_key); - klisp_assert(kport_file(port) == stderr); + klisp_assert(ttisfport(port) && kfport_file(port) == stderr); /* TEMP: obj should be an error obj */ if (ttiserror(obj)) { @@ -197,76 +240,17 @@ void do_repl_error(klisp_State *K, TValue *xparams, TValue obj) "error continuation"); } - TValue denv = xparams[0]; - create_loop(K, denv); + UNUSED(divert); + TValue old_denv = xparams[0]; + /* this is the same as a divert */ + create_loop(K, old_denv); } /* call this to init the repl in a newly created klisp state */ +/* the standard environment should be in K->next_env */ void kinit_repl(klisp_State *K) { - TValue std_env = kmake_environment(K, K->ground_env); - krooted_tvs_push(K, std_env); - - /* set up the continuations */ - TValue root_cont = kmake_continuation(K, KNIL, do_repl_exit, 0); - krooted_tvs_push(K, root_cont); - - TValue error_cont = kmake_continuation(K, root_cont, do_repl_error, - 1, std_env); - krooted_tvs_push(K, error_cont); - - /* update the ground environment with these two conts */ - TValue symbol; - /* TODO si */ - symbol = ksymbol_new(K, "root-continuation", KNIL); - krooted_tvs_push(K, symbol); - kadd_binding(K, K->ground_env, symbol, root_cont); - krooted_tvs_pop(K); - - #if KTRACK_SI - /* TODO: find a cleaner way of doing this..., maybe disable gc */ - /* Add source info to the cont */ - TValue str = kstring_new_b_imm(K, __FILE__); - krooted_tvs_push(K, str); - TValue tail = kcons(K, i2tv(__LINE__), i2tv(0)); - krooted_tvs_push(K, tail); - TValue si = kcons(K, str, tail); - krooted_tvs_push(K, si); - kset_source_info(K, root_cont, si); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - #endif - - /* TODO si */ - symbol = ksymbol_new(K, "error-continuation", KNIL); - krooted_tvs_push(K, symbol); - kadd_binding(K, K->ground_env, symbol, error_cont); - krooted_tvs_pop(K); - - #if KTRACK_SI - str = kstring_new_b_imm(K, __FILE__); - krooted_tvs_push(K, str); - tail = kcons(K, i2tv(__LINE__), i2tv(0)); - krooted_tvs_push(K, tail); - si = kcons(K, str, tail); - krooted_tvs_push(K, si); - kset_source_info(K, error_cont, si); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - #endif - - /* and save them in the structure */ - K->root_cont = root_cont; - K->error_cont = error_cont; - - krooted_tvs_pop(K); - krooted_tvs_pop(K); - krooted_tvs_pop(K); - - /* Create error continuation hierarchy. */ - kinit_error_hierarchy(K); + TValue std_env = K->next_env; #if KTRACK_SI /* save the root cont in next_si to let the loop continuations have diff --git a/src/krepl.h b/src/krepl.h @@ -14,10 +14,10 @@ void kinit_repl(klisp_State *K); /* continuation functions */ -void do_repl_exit(klisp_State *K, TValue *xparams, TValue obj); -void do_repl_read(klisp_State *K, TValue *xparams, TValue obj); -void do_repl_eval(klisp_State *K, TValue *xparams, TValue obj); -void do_repl_loop(klisp_State *K, TValue *xparams, TValue obj); -void do_repl_error(klisp_State *K, TValue *xparams, TValue obj); +void do_repl_exit(klisp_State *K); +void do_repl_read(klisp_State *K); +void do_repl_eval(klisp_State *K); +void do_repl_loop(klisp_State *K); +void do_repl_error(klisp_State *K); #endif diff --git a/src/kscript.c b/src/kscript.c @@ -42,8 +42,11 @@ static inline TValue krooted_tvs_pass_si(klisp_State *K, TValue v, TValue si) #endif /* the exit continuation, it exits the loop */ -void do_script_exit(klisp_State *K, TValue *xparams, TValue obj) +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 */ @@ -68,15 +71,18 @@ void do_script_exit(klisp_State *K, TValue *xparams, TValue obj) /* the underlying function of the error cont */ -void do_script_error(klisp_State *K, TValue *xparams, TValue obj) +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(kport_file(port) == stderr); + klisp_assert(kfport_file(port) == stderr); /* TEMP: obj should be an error obj */ if (ttiserror(obj)) { diff --git a/src/kscript.h b/src/kscript.h @@ -15,8 +15,8 @@ void kinit_script(klisp_State *K, int argc, char *argv[]); /* continuation functions */ -void do_script_exit(klisp_State *K, TValue *xparams, TValue obj); -void do_script_error(klisp_State *K, TValue *xparams, TValue obj); +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 */ diff --git a/src/kstate.c b/src/kstate.c @@ -35,9 +35,11 @@ #include "kstring.h" #include "kport.h" #include "ktable.h" -#include "kblob.h" +#include "kbytevector.h" +#include "kvector.h" #include "kgpairs_lists.h" /* for creating list_app */ +#include "kgerror.h" /* for creating error hierarchy */ #include "kgc.h" /* for memory freeing & gc init */ @@ -85,8 +87,6 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { K->ud = ud; /* current input and output */ - K->curr_in = NULL; /* set on each call to read */ - K->curr_out = NULL; /* set on each call to write */ K->curr_port = KINERT; /* set on each call to read/write */ /* input / output for dynamic keys */ @@ -153,11 +153,15 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { /* MAYBE: fix it so we can remove empty_string from roots */ K->empty_string = kstring_new_b_imm(K, ""); - /* Empty blob */ - /* MAYBE: fix it so we can remove empty_blob from roots */ + /* Empty bytevector */ + /* MAYBE: fix it so we can remove empty_bytevector from roots */ /* XXX: find a better way to do this */ - K->empty_blob = KNIL; /* trick constructor to create empty blob */ - K->empty_blob = kblob_new_imm(K, 0); + K->empty_bytevector = KNIL; /* trick constructor to create empty bytevector */ + K->empty_bytevector = kbytevector_new_bs_imm(K, NULL, 0); + + /* Empty vector */ + /* MAYBE: see above */ + K->empty_vector = kvector_new_bs_g(K, false, NULL, 0); /* initialize tokenizer */ @@ -172,6 +176,7 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { K->ktok_lparen = kcons(K, ch2tv('('), KNIL); K->ktok_rparen = kcons(K, ch2tv(')'), KNIL); K->ktok_dot = kcons(K, ch2tv('.'), KNIL); + K->ktok_sexp_comment = kcons(K, ch2tv(';'), KNIL); /* TEMP: For now just hardcode it to 8 spaces tab-stop */ K->ktok_source_info.tab_width = 8; @@ -180,6 +185,8 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { K->ktok_source_info.line = 1; K->ktok_source_info.col = 0; + K->ktok_nested_comments = 0; + ktok_init(K); /* initialize reader */ @@ -198,12 +205,12 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { K->sbuf = (TValue *)s; /* the dynamic ports and the keys for the dynamic ports */ - TValue in_port = kmake_std_port(K, kstring_new_b_imm(K, "*STDIN*"), - false, stdin); - TValue out_port = kmake_std_port(K, kstring_new_b_imm(K, "*STDOUT*"), - true, stdout); - TValue error_port = kmake_std_port(K, kstring_new_b_imm(K, "*STDERR*"), - true, stderr); + TValue in_port = kmake_std_fport(K, kstring_new_b_imm(K, "*STDIN*"), + false, false, stdin); + TValue out_port = kmake_std_fport(K, kstring_new_b_imm(K, "*STDOUT*"), + true, false, stdout); + TValue error_port = kmake_std_fport(K, kstring_new_b_imm(K, "*STDERR*"), + true, false, stderr); K->kd_in_port_key = kcons(K, KTRUE, in_port); K->kd_out_port_key = kcons(K, KTRUE, out_port); K->kd_error_port_key = kcons(K, KTRUE, error_port); @@ -237,8 +244,35 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { /* TODO si */ K->module_params_sym = ksymbol_new(K, "module-parameters", KNIL); + /* Create the root and error continuation (will be added to the + environment in kinit_ground_env) */ + K->root_cont = kmake_continuation(K, KNIL, do_root_exit, 0); + + #if KTRACK_SI + /* Add source info to the cont */ + TValue str = kstring_new_b_imm(K, __FILE__); + TValue tail = kcons(K, i2tv(__LINE__), i2tv(0)); + si = kcons(K, str, tail); + kset_source_info(K, K->root_cont, si); + #endif + + K->error_cont = kmake_continuation(K, K->root_cont, do_error_exit, 0); + + #if KTRACK_SI + str = kstring_new_b_imm(K, __FILE__); + tail = kcons(K, i2tv(__LINE__), i2tv(0)); + si = kcons(K, str, tail); + kset_source_info(K, K->error_cont, si); + #endif + + /* this must be done before calling kinit_ground_env */ + kinit_error_hierarchy(K); + kinit_ground_env(K); + /* create a std environment and leave it in K->next_env */ + K->next_env = kmake_table_environment(K, K->ground_env); + /* set the threshold for gc start now that we have allocated all mem */ K->GCthreshold = 4*K->totalbytes; @@ -246,6 +280,33 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { } /* +** Root and Error continuations +*/ +void do_root_exit(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + UNUSED(xparams); + + /* Just save the value and end the loop */ + K->next_value = obj; + K->next_func = NULL; /* force the loop to terminate */ + return; +} + +void do_error_exit(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); + UNUSED(xparams); + + /* TEMP Just pass the error to the root continuation */ + kapply_cc(K, obj); +} + +/* ** Stacks memory management */ @@ -448,16 +509,23 @@ inline TValue create_interception_list(klisp_State *K, TValue src_cont, } /* this passes the operand tree to the continuation */ -void cont_app(klisp_State *K, TValue *xparams, TValue ptree, TValue denv) +void cont_app(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); UNUSED(denv); TValue cont = xparams[0]; /* guards and dynamic variables are handled in kcall_cont() */ kcall_cont(K, cont, ptree); } -void do_interception(klisp_State *K, TValue *xparams, TValue obj) +void do_interception(klisp_State *K) { + TValue *xparams = K->next_xparams; + TValue obj = K->next_value; + klisp_assert(ttisnil(K->next_env)); /* ** xparams[0]: ** xparams[1]: dst cont @@ -545,16 +613,11 @@ void klispS_run(klisp_State *K) } else { /* all ok, continue with next func */ while (K->next_func) { - if (ttisnil(K->next_env)) { - /* continuation application */ - klisp_Cfunc fn = (klisp_Cfunc) K->next_func; - (*fn)(K, K->next_xparams, K->next_value); - } else { - /* operative calling */ - klisp_Ofunc fn = (klisp_Ofunc) K->next_func; - (*fn)(K, K->next_xparams, K->next_value, K->next_env); - } + /* next_func is either operative or continuation + but in any case the call is the same */ + (*(K->next_func))(K); } + /* K->next_func is NULL, this means we should exit already */ break; } } diff --git a/src/kstate.h b/src/kstate.h @@ -21,6 +21,12 @@ #include "ktoken.h" #include "kmem.h" +/* +** prototype for underlying c functions of continuations & +** operatives +*/ +typedef void (*klisp_CFunction) (klisp_State *K); + /* XXX: for now, lines and column names are fixints */ /* MAYBE: this should be in tokenizer */ typedef struct { @@ -51,13 +57,13 @@ struct klisp_State { TValue curr_cont; /* - ** If next_env is NIL, then the next_func is of type klisp_Cfunc - ** (from a continuation) and otherwise next_func is of type - ** klisp_Ofunc (from an operative) + ** If next_env is NIL, then the next_func from a continuation + ** and otherwise next_func is from an operative */ TValue next_obj; /* this is the operative or continuation to call must be here to protect it from gc */ - void *next_func; /* the next function to call (operative or cont) */ + klisp_CFunction next_func; /* the next function to call + (operative or continuation) */ TValue next_value; /* the value to be passed to the next function */ TValue next_env; /* either NIL or an environment for next operative */ TValue *next_xparams; @@ -99,10 +105,8 @@ struct klisp_State { /* TEMP: error handling */ jmp_buf error_jb; - /* input and output files in use (for read & write) */ + /* input/output port in use (for read & write) */ TValue curr_port; /* save the port to update source info on errors */ - FILE *curr_in; - FILE *curr_out; /* for current-input-port, current-output-port, current-error-port */ TValue kd_in_port_key; @@ -115,14 +119,19 @@ struct klisp_State { /* Strings */ TValue empty_string; - /* Blobs */ - TValue empty_blob; + /* Bytevectors */ + TValue empty_bytevector; + + /* Vectors */ + TValue empty_vector; + /* tokenizer */ /* special tokens, see ktoken.c for rationale */ TValue ktok_lparen; TValue ktok_rparen; TValue ktok_dot; + TValue ktok_sexp_comment; /* WORKAROUND for repl */ bool ktok_seen_eof; @@ -132,6 +141,8 @@ struct klisp_State { int32_t ktok_buffer_idx; char *ktok_buffer; + int32_t ktok_nested_comments; + /* reader */ /* TODO: replace the list with a hashtable */ TValue shared_dict; @@ -141,6 +152,7 @@ struct klisp_State { bool write_displayp; /* script */ + /* REFACTOR rename to exit_code */ int script_exit_code; /* auxiliary stack */ @@ -346,14 +358,6 @@ inline void krooted_vars_clear(klisp_State *K) { K->rooted_vars_top = 0; } /* dummy functions will be in kpair.h, because we can't include it from here */ -/* -** prototypes for underlying c functions of continuations & -** operatives -*/ -typedef void (*klisp_Cfunc) (klisp_State*K, TValue *ud, TValue val); -typedef void (*klisp_Ofunc) (klisp_State *K, TValue *ud, TValue ptree, - TValue env); - /* XXX: this is ugly but we can't include kpair.h here so... */ /* MAYBE: move car & cdr to kobject.h */ #define kstate_car(p_) (tv2pair(p_)->car) @@ -466,6 +470,7 @@ inline void klispS_tail_call_si(klisp_State *K, TValue top, TValue ptree, K->next_func = op->fn; K->next_value = ptree; /* NOTE: this is what differentiates a tail call from a return */ + klisp_assert(ttisenvironment(env)); K->next_env = env; K->next_xparams = op->extra; K->next_si = si; @@ -488,13 +493,17 @@ inline void klispS_tail_call_si(klisp_State *K, TValue top, TValue ptree, return; } /* helper for continuation->applicative & kcall_cont */ -void cont_app(klisp_State *K, TValue *xparams, TValue ptree, TValue denv); +void cont_app(klisp_State *K); void kcall_cont(klisp_State *K, TValue dst_cont, TValue obj); void klispS_init_repl(klisp_State *K); void klispS_run(klisp_State *K); void klisp_close (klisp_State *K); -void do_interception(klisp_State *K, TValue *xparams, TValue obj); +void do_interception(klisp_State *K); + +/* for root and error continuations */ +void do_root_exit(klisp_State *K); +void do_error_exit(klisp_State *K); /* simple accessors for dynamic keys */ diff --git a/src/kstring.c b/src/kstring.c @@ -15,7 +15,7 @@ #include "kmem.h" #include "kgc.h" -/* for immutable string/symbols table */ +/* for immutable string/symbols/bytevector table */ void klispS_resize (klisp_State *K, int32_t newsize) { GCObject **newhash; @@ -30,8 +30,8 @@ void klispS_resize (klisp_State *K, int32_t newsize) for (i = 0; i < tb->size; i++) { GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ - /* imm string & symbols aren't chained with all other - objs, but with each other in strt */ + /* imm string, imm bytevectors & symbols aren't chained with + all other objs, but with each other in strt */ GCObject *next = p->gch.next; /* save next */ uint32_t h = 0; @@ -40,6 +40,8 @@ void klispS_resize (klisp_State *K, int32_t newsize) h = ((Symbol *) p)->hash; } else if (p->gch.tt == K_TSTRING) { h = ((String *) p)->hash; + } else if (p->gch.tt == K_TBYTEVECTOR) { + h = ((Bytevector *) p)->hash; } else { klisp_assert(0); } @@ -85,10 +87,11 @@ TValue kstring_new_bs_imm(klisp_State *K, const char *buf, uint32_t size) String *ts = NULL; if (o->gch.tt == K_TSTRING) { ts = (String *) o; - } else if (o->gch.tt == K_TSYMBOL) { + } else if (o->gch.tt == K_TSYMBOL || o->gch.tt == K_TBYTEVECTOR) { continue; } else { - klisp_assert(0); /* only symbols and immutable strings */ + /* only symbols, immutable bytevectors and immutable strings */ + klisp_assert(0); } if (ts->size == size && (memcmp(buf, ts->b, size) == 0)) { /* string may be dead */ @@ -101,7 +104,7 @@ TValue kstring_new_bs_imm(klisp_State *K, const char *buf, uint32_t size) /* REFACTOR: move all of these to a new function */ String *new_str; - if (size+1 > (SIZE_MAX - sizeof(String))) + if (size > (SIZE_MAX - sizeof(String) - 1)) klispM_toobig(K); new_str = (String *) klispM_malloc(K, sizeof(String) + size + 1); @@ -156,6 +159,7 @@ TValue kstring_new_s(klisp_State *K, uint32_t size) String *new_str; if (size == 0) { + klisp_assert(ttisstring(K->empty_string)); return K->empty_string; } @@ -217,3 +221,11 @@ bool kstring_equalp(TValue obj1, TValue obj2) } bool kstringp(TValue obj) { return ttisstring(obj); } +bool kimmutable_stringp(TValue obj) +{ + return ttisstring(obj) && kis_immutable(obj); +} +bool kmutable_stringp(TValue obj) +{ + return ttisstring(obj) && kis_mutable(obj); +} diff --git a/src/kstring.h b/src/kstring.h @@ -46,27 +46,6 @@ TValue kstring_new_b(klisp_State *K, const char *buf); /* with size & fill char */ TValue kstring_new_sf(klisp_State *K, uint32_t size, char fill); -/* macros for mutable & immutable versions of the above */ -#if 0 -#define kstring_new_s(K_, size_) \ - kstring_new_s_g(K_, true, size_) -#define kstring_new_bs(K_, buf_, size_) \ - kstring_new_bs_g(K_, true, buf_, size_) -#define kstring_new_b(K_, buf_) \ - kstring_new_b_g(K_, true, buf_) -#define kstring_new_sf(K_, size_, fill_) \ - kstring_new_sf_g(K_, true, size_, fill_) - -#define kstring_new_s_imm(K_, size_) \ - kstring_new_s_g(K_, false, size_) -#define kstring_new_bs_imm(K_, buf_, size_) \ - kstring_new_bs_g(K_, false, buf_, size_) -#define kstring_new_b_imm(K_, buf_) \ - kstring_new_b_g(K_, false, buf_) -#define kstring_new_sf_imm(K_, size_, fill_) \ - kstring_new_sf_g(K_, false, size_, fill_) -#endif - /* some macros to access the parts of the string */ #define kstring_buf(tv_) (tv2str(tv_)->b) #define kstring_size(tv_) (tv2str(tv_)->size) @@ -79,5 +58,7 @@ TValue kstring_new_sf(klisp_State *K, uint32_t size, char fill); and doesn't differentiate immutable from mutable strings */ bool kstring_equalp(TValue obj1, TValue obj2); bool kstringp(TValue obj); +bool kimmutable_stringp(TValue obj); +bool kmutable_stringp(TValue obj); #endif diff --git a/src/ksymbol.c b/src/ksymbol.c @@ -13,6 +13,8 @@ #include "kstate.h" #include "kmem.h" #include "kgc.h" +/* for immutable table */ +#include "kstring.h" /* NOTE: symbols can have source info, they should be compared with tv_sym_equal, NOT tv_equal */ @@ -39,12 +41,13 @@ TValue ksymbol_new_g(klisp_State *K, const char *buf, int32_t size, for (o = K->strt.hash[lmod(h, K->strt.size)]; o != NULL; o = o->gch.next) { String *ts = NULL; - if (o->gch.tt == K_TSTRING) { + if (o->gch.tt == K_TSTRING || o->gch.tt == K_TBYTEVECTOR) { continue; } else if (o->gch.tt == K_TSYMBOL) { ts = tv2str(((Symbol *) o)->str); } else { - klisp_assert(0); /* only symbols and immutable strings */ + /* only symbols, immutable bytevectors and immutable strings */ + klisp_assert(0); } if (ts->size == size && (memcmp(buf, ts->b, size) == 0)) { /* symbol may be dead */ diff --git a/src/ktoken.c b/src/ktoken.c @@ -26,7 +26,6 @@ */ #include <stdio.h> #include <stdlib.h> -#include <assert.h> #include <string.h> #include <ctype.h> #include <stdint.h> @@ -40,6 +39,7 @@ #include "kreal.h" #include "kpair.h" #include "kstring.h" +#include "kbytevector.h" #include "ksymbol.h" #include "kerror.h" #include "kport.h" @@ -134,7 +134,10 @@ void clear_shared_dict(klisp_State *K) K->shared_dict = KNIL; } -void ktok_error(klisp_State *K, char *str) +#define ktok_error(K, str) ktok_error_g(K, str, false, KINERT) +#define ktok_error_extra(K, str, extra) ktok_error_g(K, str, true, extra) + +void ktok_error_g(klisp_State *K, char *str, bool extra, TValue extra_value) { /* all cleaning is done in throw (stacks, shared_dict, rooted objs) */ @@ -143,69 +146,137 @@ void ktok_error(klisp_State *K, char *str) kport_update_source_info(K->curr_port, K->ktok_source_info.line, K->ktok_source_info.col); - /* include the source info in the error */ - TValue si = ktok_get_source_info(K); - krooted_tvs_push(K, si); /* will be popped by throw */ - klispE_throw_with_irritants(K, str, si); + /* include the source info (and extra value if present) in the error */ + TValue irritants; + if (extra) { + krooted_tvs_push(K, extra_value); /* will be popped by throw */ + TValue si = ktok_get_source_info(K); + krooted_tvs_push(K, si); /* will be popped by throw */ + irritants = klist_g(K, false, 2, si, extra_value); + } else { + irritants = ktok_get_source_info(K); + } + krooted_tvs_push(K, irritants); /* will be popped by throw */ + klispE_throw_with_irritants(K, str, irritants); } /* ** Underlying stream interface & source code location tracking */ -/* TODO check for error if getc returns EOF */ -int ktok_getc(klisp_State *K) { - /* WORKAROUND: for stdin line buffering & reading of EOF */ - /* Is this really necessary?? double check */ - if (K->ktok_seen_eof) { - return EOF; - } else { - int chi = getc(K->curr_in); +/* TODO/OPTIMIZE We should use buffering to shorten the + average code path to read each char */ +/* this reads one character from curr_port */ +int ktok_ggetc(klisp_State *K) +{ + /* XXX when full unicode is used (uint32_t) a different way should + be use to signal EOF */ + + TValue port = K->curr_port; + if (ttisfport(port)) { + /* fport */ + FILE *file = kfport_file(port); + int chi = getc(file); if (chi == EOF) { /* NOTE: eof doesn't change source code location info */ - if (ferror(K->curr_in) != 0) { + if (ferror(file) != 0) { /* clear error marker to allow retries later */ - clearerr(K->curr_in); + clearerr(file); + /* TODO put error info on the error obj */ ktok_error(K, "reading error"); return 0; - } else { /* if (feof(K->curr_in) != 0) */ + } else { /* if (feof(file) != 0) */ /* let the eof marker set */ K->ktok_seen_eof = true; return EOF; } - } - - /* track source code location before returning the char */ - if (chi == '\t') { - /* align column to next tab stop */ - K->ktok_source_info.col = - (K->ktok_source_info.col + K->ktok_source_info.tab_width) - - (K->ktok_source_info.col % K->ktok_source_info.tab_width); - return '\t'; - } else if (chi == '\n') { - K->ktok_source_info.line++; - K->ktok_source_info.col = 0; - return '\n'; + } else + return chi; + } else { + /* mport */ + if (kport_is_binary(port)) { + /* bytevector port */ + if (kmport_off(port) >= kbytevector_size(kmport_buf(port))) { + K->ktok_seen_eof = true; + return EOF; + } + int chi = kbytevector_buf(kmport_buf(port))[kmport_off(port)]; + ++kmport_off(port); + return chi; } else { - K->ktok_source_info.col++; + /* string port */ + if (kmport_off(port) >= kstring_size(kmport_buf(port))) { + K->ktok_seen_eof = true; + return EOF; + } + int chi = kstring_buf(kmport_buf(port))[kmport_off(port)]; + ++kmport_off(port); return chi; } } } -int ktok_peekc(klisp_State *K) { - /* WORKAROUND: for stdin line buffering & reading of EOF */ - /* Is this really necessary?? double check */ - if (K->ktok_seen_eof) { - return EOF; +/* this returns one character to curr_port */ +void ktok_gungetc(klisp_State *K, int chi) +{ + if (chi == EOF) + return; + + TValue port = K->curr_port; + if (ttisfport(port)) { + /* fport */ + FILE *file = kfport_file(port); + + if (ungetc(chi, file) == EOF) { + if (ferror(file) != 0) { + /* clear error marker to allow retries later */ + clearerr(file); + } + /* TODO put error info on the error obj */ + ktok_error(K, "reading error"); + return; + } } else { - int chi = getc(K->curr_in); - if (chi == EOF) - K->ktok_seen_eof = true; - else - ungetc(chi, K->curr_in); + /* mport */ + if (kport_is_binary(port)) { + /* bytevector port */ + --kmport_off(port); + } else { + /* string port */ + --kmport_off(port); + } + } +} + +int ktok_peekc_getc(klisp_State *K, bool peekp) +{ + /* WORKAROUND: for stdin line buffering & reading of EOF, this flag + is reset on every read */ + /* Otherwise, at least in linux, after reading or peeking an EOF from the + console, the next char isn't eof anymore */ + if (K->ktok_seen_eof) + return EOF; + + int chi = ktok_ggetc(K); + + if (peekp) { + ktok_gungetc(K, chi); return chi; } + + /* track source code location before returning the char */ + if (chi == '\t') { + /* align column to next tab stop */ + K->ktok_source_info.col = + (K->ktok_source_info.col + K->ktok_source_info.tab_width) - + (K->ktok_source_info.col % K->ktok_source_info.tab_width); + } else if (chi == '\n') { + K->ktok_source_info.line++; + K->ktok_source_info.col = 0; + } else { + K->ktok_source_info.col++; + } + return chi; } void ktok_save_source_info(klisp_State *K) @@ -240,6 +311,7 @@ void ktok_set_source_info(klisp_State *K, TValue filename, int32_t line, */ void ktok_ignore_whitespace(klisp_State *K); void ktok_ignore_single_line_comment(klisp_State *K); +void ktok_ignore_multi_line_comment(klisp_State *K); bool ktok_check_delimiter(klisp_State *K); TValue ktok_read_string(klisp_State *K); TValue ktok_read_special(klisp_State *K); @@ -255,7 +327,7 @@ int ktok_read_until_delimiter(klisp_State *K); */ TValue ktok_read_token(klisp_State *K) { - assert(ks_tbisempty(K)); + klisp_assert(ks_tbisempty(K)); while(true) { ktok_ignore_whitespace(K); @@ -293,12 +365,26 @@ TValue ktok_read_token(klisp_State *K) case '#': { ktok_getc(K); chi = ktok_peekc(K); - if ((chi != EOF) && (char) chi == '!') { + + switch(chi) { + case EOF: + ktok_error(K, "# constant is too short"); + /* avoid warning */ + return KINERT; + case '!': /* single line comment (alternative syntax) */ /* this handles the #! style script header too! */ ktok_ignore_single_line_comment(K); continue; - } else { - /* also handles EOF case */ + case '|': /* nested/multiline comment */ + ktok_getc(K); /* discard the '|' */ + klisp_assert(K->ktok_nested_comments == 0); + K->ktok_nested_comments = 1; + ktok_ignore_multi_line_comment(K); + continue; + case ';': /* sexp comment */ + ktok_getc(K); /* discard the ';' */ + return K->ktok_sexp_comment; + default: return ktok_read_special(K); } } @@ -330,9 +416,22 @@ TValue ktok_read_token(klisp_State *K) ** identifier-first-char (in the cases above) */ return ktok_read_identifier(K); - default: + case '|': + ktok_getc(K); + chi = ktok_peekc(K); + if (chi == EOF || chi != '#') { + chi = '|'; + goto unrecognized_error; + } ktok_getc(K); - ktok_error(K, "unrecognized token starting char"); + ktok_error(K, "unmatched multiline comment close (\"|#\")"); + /* avoid warning */ + return KINERT; + default: + chi = ktok_getc(K); + /* TODO add char to error */ + unrecognized_error: + ktok_error_extra(K, "unrecognized token starting char", ch2tv((char) chi)); /* avoid warning */ return KINERT; } @@ -350,6 +449,63 @@ void ktok_ignore_single_line_comment(klisp_State *K) } while (chi != EOF && chi != '\n'); } +void ktok_ignore_multi_line_comment(klisp_State *K) +{ + /* the first "#|' was already read */ + klisp_assert(K->ktok_nested_comments == 1); + int chi; + TValue last_nested_comment_si = ktok_get_source_info(K); + krooted_vars_push(K, &last_nested_comment_si); + ks_spush(K, KNIL); + + while(K->ktok_nested_comments > 0) { + chi = ktok_peekc(K); + while (chi != EOF && chi != '|' && chi != '#') { + UNUSED(ktok_getc(K)); + chi = ktok_peekc(K); + } + if (chi == EOF) + goto eof_error; + + char first_char = (char) chi; + + /* this first char will actually be the same just peeked, that's no + problem, it will save the source info the first time around the + loop */ + chi = ktok_peekc(K); + while (chi != EOF && chi == first_char) { + ktok_save_source_info(K); + UNUSED(ktok_getc(K)); + chi = ktok_peekc(K); + } + if (chi == EOF) + goto eof_error; + + UNUSED(ktok_getc(K)); + + if (chi == '#') { + /* close comment (first char was '|', so the seq is "|#") */ + --K->ktok_nested_comments; + last_nested_comment_si = ks_spop(K); + } else if (chi == '|') { + /* open comment (first char was '#', so the seq is "#|") */ + klisp_assert(K->ktok_nested_comments < 1000); + ++K->ktok_nested_comments; + ks_spush(K, last_nested_comment_si); + last_nested_comment_si = ktok_get_source_info(K); + } + /* else lone '#' or '|', just continue */ + } + krooted_vars_pop(K); + return; +eof_error: + K->ktok_nested_comments = 0; + ktok_save_source_info(K); + UNUSED(ktok_getc(K)); + krooted_vars_pop(K); + ktok_error_extra(K, "unterminated multi line comment", last_nested_comment_si); +} + void ktok_ignore_whitespace(klisp_State *K) { /* NOTE: if it's not whitespace do nothing (even on eof) */ @@ -728,7 +884,8 @@ TValue ktok_read_special(klisp_State *K) has_radixp = true; break; default: - ktok_error(K, "unexpected char in number after #"); + ktok_error(K, "unknown # constant or " + "unexpected char in number after #"); /* avoid warning */ return KINERT; } diff --git a/src/ktoken.h b/src/ktoken.h @@ -26,9 +26,11 @@ void ktok_set_source_info(klisp_State *K, TValue filename, int32_t line, /* This is needed here to allow cleanup of shared dict from tokenizer */ void clear_shared_dict(klisp_State *K); -/* This is used in for peek-char & read-char */ -int ktok_getc(klisp_State *K); -int ktok_peekc(klisp_State *K); +/* These are used in peek-char, peek-u8, read-char & read-u8 */ +int ktok_peekc_getc(klisp_State *K, bool peekp); +inline int ktok_getc(klisp_State *K) { return ktok_peekc_getc(K, false); } +inline int ktok_peekc(klisp_State *K) { return ktok_peekc_getc(K, true); } + /* needed by the repl */ void ktok_ignore_whitespace_and_comments(klisp_State *K); diff --git a/src/kvector.c b/src/kvector.c @@ -0,0 +1,65 @@ +/* +** kvector.c +** Kernel Vectors (heterogenous arrays) +** See Copyright Notice in klisp.h +*/ + +#include <string.h> + +#include "kvector.h" +#include "kobject.h" +#include "kstate.h" +#include "kmem.h" +#include "kgc.h" + +/* helper function allocating vectors */ + +static Vector *kvector_alloc(klisp_State *K, bool m, uint32_t length) +{ + Vector *new_vector; + + if (length > (SIZE_MAX - sizeof(Vector)) / sizeof(TValue)) + klispM_toobig(K); + + klisp_assert(!m || length > 0); + + size_t size = sizeof(Vector) + length * sizeof(TValue); + new_vector = (Vector *) klispM_malloc(K, size); + klispC_link(K, (GCObject *) new_vector, K_TVECTOR, + (m? 0 : K_FLAG_IMMUTABLE)); + new_vector->mark = KFALSE; + new_vector->sizearray = length; + + return new_vector; +} + +TValue kvector_new_sf(klisp_State *K, uint32_t length, TValue fill) +{ + Vector *v = kvector_alloc(K, true, length); + for (int i = 0; i < length; i++) + v->array[i] = fill; + return gc2vector(v); +} + +TValue kvector_new_bs_g(klisp_State *K, bool m, + const TValue *buf, uint32_t length) +{ + Vector *v = kvector_alloc(K, m, length); + memcpy(v->array, buf, sizeof(TValue) * length); + return gc2vector(v); +} + +bool kvectorp(TValue obj) +{ + return ttisvector(obj); +} + +bool kimmutable_vectorp(TValue obj) +{ + return ttisvector(obj) && kis_immutable(obj); +} + +bool kmutable_vectorp(TValue obj) +{ + return ttisvector(obj) && kis_mutable(obj); +} diff --git a/src/kvector.h b/src/kvector.h @@ -0,0 +1,34 @@ +/* +** kvector.h +** Kernel Vectors (heterogenous arrays) +** See Copyright Notice in klisp.h +*/ + +#ifndef kvector_h +#define kvector_h + +#include "kobject.h" +#include "kstate.h" + +/* constructors */ + +TValue kvector_new_sf(klisp_State *K, uint32_t length, TValue fill); +TValue kvector_new_bs_g(klisp_State *K, bool m, + const TValue *buf, uint32_t length); + +/* predicates */ + +bool kvectorp(TValue obj); +bool kimmutable_vectorp(TValue obj); +bool kmutable_vectorp(TValue obj); + +/* some macros to access the parts of vectors */ + +#define kvector_array(tv_) (tv2vector(tv_)->array) +#define kvector_length(tv_) (tv2vector(tv_)->sizearray) + +#define kvector_emptyp(tv_) (kvector_length(tv_) == 0) +#define kvector_mutablep(tv_) (kis_mutable(tv_)) +#define kvector_immutablep(tv_) (kis_immutable(tv_)) + +#endif diff --git a/src/kwrite.c b/src/kwrite.c @@ -6,6 +6,7 @@ #include <stdio.h> #include <stdlib.h> +#include <stdarg.h> #include <assert.h> #include <inttypes.h> #include <string.h> @@ -23,7 +24,8 @@ #include "ktable.h" #include "kport.h" #include "kenvironment.h" -#include "kblob.h" +#include "kbytevector.h" +#include "kvector.h" /* ** Stack for the write FSM @@ -34,27 +36,70 @@ #define get_data(ks_) (ks_sget(ks_)) #define data_is_empty(ks_) (ks_sisempty(ks_)) -/* macro for printing */ -#define kw_printf(ks_, ...) \ - if (fprintf((ks_)->curr_out, __VA_ARGS__) < 0) { \ - clearerr((ks_)->curr_out); /* clear error for next time */ \ - kwrite_error(ks_, "error writing"); \ - } - -#define kw_flush(ks_) \ - if (fflush((ks_)->curr_out) == EOF) { \ - clearerr((ks_)->curr_out); /* clear error for next time */ \ - kwrite_error(ks_, "error writing"); \ - } - void kwrite_error(klisp_State *K, char *msg) { /* all cleaning is done in throw (stacks, shared_dict, rooted objs) */ - klispE_throw_simple(K, msg); } +void kw_printf(klisp_State *K, const char *format, ...) +{ + va_list argp; + TValue port = K->curr_port; + + if (ttisfport(port)) { + FILE *file = kfport_file(port); + va_start(argp, format); + int ret = vfprintf(file, format, argp); + va_end(argp); + + if (ret < 0) { + clearerr(file); /* clear error for next time */ + kwrite_error(K, "error writing"); + return; + } + } else if (ttismport(port)) { + /* bytevector ports shouldn't write chars */ + klisp_assert(kport_is_textual(port)); + /* string port */ + uint32_t size; + int written; + uint32_t off = kmport_off(port); + + size = kstring_size(kmport_buf(port)) - + kmport_off(port) + 1; + + /* size is always at least 1 (for the '\0') */ + va_start(argp, format); + written = vsnprintf(kstring_buf(kmport_buf(port)) + off, + size, format, argp); + va_end(argp); + + if (written >= size) { /* space wasn't enough */ + kmport_resize_buffer(K, port, off + written); + /* size may be greater than off + written, so get again */ + size = kstring_size(kmport_buf(port)) - off + 1; + va_start(argp, format); + written = vsnprintf(kstring_buf(kmport_buf(port)) + off, + size, format, argp); + va_end(argp); + if (written < 0 || written >= size) { + /* shouldn't happen */ + kwrite_error(K, "error writing"); + return; + } + } + kmport_off(port) = off + written; + } else { + kwrite_error(K, "unknown port type"); + return; + } +} + +void kw_flush(klisp_State *K) { kwrite_flush_port(K, K->curr_port); } + + /* TODO: check for return codes and throw error if necessary */ #define KDEFAULT_NUMBER_RADIX 10 void kw_print_bigint(klisp_State *K, TValue bigint) @@ -421,9 +466,22 @@ void kwrite_simple(klisp_State *K, TValue obj) /* TODO try to get the name */ kw_printf(K, "#[promise]"); break; - case K_TPORT: - /* TODO try to get the name/ I/O direction / filename */ - kw_printf(K, "#[%s port", kport_is_input(obj)? "input" : "output"); + case K_TFPORT: + /* TODO try to get the filename */ + kw_printf(K, "#[%s %s file port", + kport_is_binary(obj)? "binary" : "textual", + kport_is_input(obj)? "input" : "output"); + #if KTRACK_NAMES + if (khas_name(obj)) { + kw_print_name(K, obj); + } + #endif + kw_printf(K, "]"); + break; + case K_TMPORT: + kw_printf(K, "#[%s %s port", + kport_is_binary(obj)? "bytevector" : "string", + kport_is_input(obj)? "input" : "output"); #if KTRACK_NAMES if (khas_name(obj)) { kw_print_name(K, obj); @@ -443,8 +501,8 @@ void kwrite_simple(klisp_State *K, TValue obj) kw_printf(K, "]"); break; } - case K_TBLOB: - kw_printf(K, "#[blob"); + case K_TBYTEVECTOR: + kw_printf(K, "#[bytevector"); #if KTRACK_NAMES if (khas_name(obj)) { kw_print_name(K, obj); @@ -452,6 +510,15 @@ void kwrite_simple(klisp_State *K, TValue obj) #endif kw_printf(K, "]"); break; + case K_TVECTOR: + kw_printf(K, "#[vector"); + #if KTRACK_NAMES + if (khas_name(obj)) { + kw_print_name(K, obj); + } + #endif + kw_printf(K, "]"); + break; default: /* shouldn't happen */ kwrite_error(K, "unknown object type"); @@ -565,12 +632,6 @@ void kwrite(klisp_State *K, TValue obj) krooted_tvs_pop(K); } -void kwrite_newline(klisp_State *K) -{ - kw_printf(K, "\n"); - kw_flush(K); -} - /* ** Interface */ @@ -578,27 +639,98 @@ void kwrite_display_to_port(klisp_State *K, TValue port, TValue obj, bool displayp) { K->curr_port = port; - K->curr_out = kport_file(port); K->write_displayp = displayp; kwrite(K, obj); } void kwrite_newline_to_port(klisp_State *K, TValue port) { + K->curr_port = port; /* this isn't needed but all other + i/o functions set it */ kwrite_char_to_port(K, port, ch2tv('\n')); } void kwrite_char_to_port(klisp_State *K, TValue port, TValue ch) { - K->curr_port = port; - K->curr_out = kport_file(port); - int res = fputc(chvalue(ch), K->curr_out); - /* implicit flush, MAYBE add flush call */ - if (res != EOF) - res = fflush(K->curr_out); - - if (res == EOF) { - clearerr(K->curr_out); /* clear error for next time */ - kwrite_error(K, "error writing char"); + K->curr_port = port; /* this isn't needed but all other + i/o functions set it */ + + if (ttisfport(port)) { + FILE *file = kfport_file(port); + int res = fputc(chvalue(ch), file); + + if (res == EOF) { + clearerr(file); /* clear error for next time */ + kwrite_error(K, "error writing char"); + } + } else if (ttismport(port)) { + if (kport_is_binary(port)) { + /* bytebuffer port */ + if (kmport_off(port) >= kbytevector_size(kmport_buf(port))) { + kmport_resize_buffer(K, port, kmport_off(port) + 1); + } + kbytevector_buf(kmport_buf(port))[kmport_off(port)] = chvalue(ch); + ++kmport_off(port); + } else { + /* string port */ + if (kmport_off(port) >= kstring_size(kmport_buf(port))) { + kmport_resize_buffer(K, port, kmport_off(port) + 1); + } + kstring_buf(kmport_buf(port))[kmport_off(port)] = chvalue(ch); + ++kmport_off(port); + } + } else { + kwrite_error(K, "unknown port type"); + return; + } +} + +void kwrite_u8_to_port(klisp_State *K, TValue port, TValue u8) +{ + K->curr_port = port; /* this isn't needed but all other + i/o functions set it */ + if (ttisfport(port)) { + FILE *file = kfport_file(port); + int res = fputc(ivalue(u8), file); + + if (res == EOF) { + clearerr(file); /* clear error for next time */ + kwrite_error(K, "error writing u8"); + } + } else if (ttismport(port)) { + if (kport_is_binary(port)) { + /* bytebuffer port */ + if (kmport_off(port) >= kbytevector_size(kmport_buf(port))) { + kmport_resize_buffer(K, port, kmport_off(port) + 1); + } + kbytevector_buf(kmport_buf(port))[kmport_off(port)] = + (uint8_t) ivalue(u8); + ++kmport_off(port); + } else { + /* string port */ + if (kmport_off(port) >= kstring_size(kmport_buf(port))) { + kmport_resize_buffer(K, port, kmport_off(port) + 1); + } + kstring_buf(kmport_buf(port))[kmport_off(port)] = + (char) ivalue(u8); + ++kmport_off(port); + } + } else { + kwrite_error(K, "unknown port type"); + return; + } +} + +void kwrite_flush_port(klisp_State *K, TValue port) +{ + K->curr_port = port; /* this isn't needed but all other + i/o functions set it */ + if (ttisfport(port)) { /* only necessary for file ports */ + FILE *file = kfport_file(port); + klisp_assert(file); + if ((fflush(file)) == EOF) { + clearerr(file); /* clear error for next time */ + kwrite_error(K, "error writing"); + } } } diff --git a/src/kwrite.h b/src/kwrite.h @@ -17,6 +17,8 @@ void kwrite_display_to_port(klisp_State *K, TValue port, TValue obj, bool displayp); void kwrite_newline_to_port(klisp_State *K, TValue port); void kwrite_char_to_port(klisp_State *K, TValue port, TValue ch); +void kwrite_u8_to_port(klisp_State *K, TValue port, TValue u8); +void kwrite_flush_port(klisp_State *K, TValue port); #endif diff --git a/src/rep_op_c.sed b/src/rep_op_c.sed @@ -0,0 +1,78 @@ +# 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 @@ -0,0 +1,31 @@ +# 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 @@ -0,0 +1,170 @@ +;; check.k & test-helpers.k should be loaded +;; +;; Tests of bytevector features. +;; + +;; 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 +;; +;; (u16 X_0 X_1 ... X_{N-1}) returns a bytevector B of length 2N, +;; such that the bytes B[2k], B[2k+1], combined into 16-bit +;; unsigned integer, represent the number X_k +;; +;; (u32 X_0 X_1 ... X_{N-1}) returns a bytevector of length 4N +;; 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))) + +;; TODO: endianess +($define! u16 + ($let + ((decompose ($lambda (w) (list (mod w 256) (div w 256))))) + ($lambda words + (list->bytevector (apply append (map decompose words)))))) + +;; TODO: endianess +($define! u32 + ($let + ((decompose + ($lambda (w) + (list (mod w 256) (mod (div w 256) 256) + (mod (div w 65536) 256) (div w 16777216))))) + ($lambda words + (list->bytevector (apply append (map decompose words)))))) + + +;; XXX bytevector? + +($check-predicate (bytevector?)) +($check-predicate (bytevector? (make-bytevector 0))) +($check-predicate (bytevector? (make-bytevector 1))) + +($check-not-predicate (bytevector? 0)) +($check-not-predicate (bytevector? "")) +($check-not-predicate (bytevector? ())) + +;; XXX immutable-bytevector? mutable-bytevector? + +($check-predicate (immutable-bytevector?)) +($check-predicate (immutable-bytevector? (make-bytevector 0))) + +($check-predicate (mutable-bytevector?)) +($check-predicate (mutable-bytevector? (make-bytevector 1))) + +;; (R7RS 3rd draft, section 6.3.7) make-bytevector bytevector-length + +($check equal? (bytevector-length (make-bytevector 0)) 0) +($check equal? (bytevector-length (make-bytevector 0 0)) 0) +($check equal? (bytevector-length (make-bytevector 1)) 1) +($check equal? (bytevector-length (make-bytevector 1 2)) 1) +($check equal? (bytevector-length (make-bytevector 8192)) 8192) + +;; (R7RS 3rd draft, section 6.3.7) bytevector-u8-ref + +($check equal? (bytevector-u8-ref (make-bytevector 10 0) 1) 0) +($check equal? (bytevector-u8-ref (make-bytevector 10 123) 5) 123) +($check equal? (bytevector-u8-ref (make-bytevector 10 255) 9) 255) + +;; (R7RS 3rd draft, section 6.3.7) bytevector-u8-set! +;; additional property: returns #inert +;; additional property: destination must be mutable +;; +($let* + ((v (make-bytevector 10)) + (w (bytevector->immutable-bytevector v))) + ($check equal? (bytevector-u8-set! v 0 1) #inert) + ($check equal? (bytevector-u8-ref v 0) 1) + ($check equal? (bytevector-u8-set! v 0 32) #inert) + ($check equal? (bytevector-u8-ref v 0) 32) + ($check equal? (bytevector-u8-set! v 6 42) #inert) + ($check equal? (bytevector-u8-ref v 0) 32) + ($check equal? (bytevector-u8-ref v 6) 42) + ($check-error (bytevector-u8-ref v -1)) + ($check-error (bytevector-u8-ref v 10)) + ($check-error (bytevector-u8-ref v 12345)) + ($check-error (bytevector-u8-set! v -1 0)) + ($check-error (bytevector-u8-set! v 10 255)) + ($check-error (bytevector-u8-set! v 5 -1)) + ($check-error (bytevector-u8-set! v 9 256)) + ($check-error (bytevector-u8-set! v 9 #\x)) + ($check-error (bytevector-u8-set! v 9 #f)) + ($check-error (bytevector-u8-set! w 0 0))) + +;; (R7RS 3rd draft, section 6.3.7) bytevector-copy +;; +($check equal? (bytevector-copy (u8 1 2 3)) (u8 1 2 3)) +($check-predicate (mutable-bytevector? (bytevector-copy (u8 1 2 3)))) + +($check-predicate + (mutable-bytevector? + (bytevector-copy (bytevector->immutable-bytevector (u8 1 2 3))))) + +;; XXX bytevector-copy! +;; additional property: returns #inert +;; additional property: destination must be mutable +;; +($let ((v (make-bytevector 5 0))) + ($check equal? (bytevector-copy! (u8 1 2 3 4 5) v) #inert) + ($check equal? v (u8 1 2 3 4 5)) + ($check-no-error (bytevector-copy! (bytevector->immutable-bytevector (u8 9 9)) v)) + ($check equal? v (u8 9 9 3 4 5)) + ($check-error (bytevector-copy! (u8 1 2 3 4 5 6) v)) + ($check-error + (bytevector-copy! + (u8 1) + (bytevector->immutable-bytevector (u8 1))))) + +;; (R7RS 3rd draft, section 6.3.7) bytevector-copy-partial + +($check equal? (bytevector-copy-partial (u8 1 2 3) 0 0) (u8)) +($check equal? (bytevector-copy-partial (u8 1 2 3) 0 2) (u8 1 2)) +($check equal? (bytevector-copy-partial (u8 1 2 3) 2 3) (u8 3)) +($check equal? (bytevector-copy-partial (u8 1 2 3) 3 3) (u8)) +($check-error (bytevector-copy-partial (u8 1 2 3) 2 4)) +($check-error (bytevector-copy-partial (u8 1 2 3) -1 0)) + +;; R7RS 3rd draft, section 6.3.7) bytevector-copy-partial! +;; additional property: returns #inert +;; additional property: destination must be mutable +;; +($let* + ((v (make-bytevector 5 9)) + (w (bytevector->immutable-bytevector v))) + ($check equal? (bytevector-copy-partial! (u8 1 2) 0 2 v 0) #inert) + ($check equal? v (u8 1 2 9 9 9)) + ($check equal? (bytevector-copy-partial! (u8 5 6) 1 2 v 4) #inert) + ($check equal? v (u8 1 2 9 9 6)) + ($check-error (bytevector-copy-partial! (u8 1 2) 0 2 v -1)) + ($check-error (bytevector-copy-partial! (u8 1 2) 0 2 v 4)) + ($check-error (bytevector-copy-partial! (u8 1 2) 2 3 v 0)) + ($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->immutable-bytevector + +($check-predicate + (immutable-bytevector? (bytevector->immutable-bytevector (u8 1 2)))) +($check-not-predicate + (mutable-bytevector? (bytevector->immutable-bytevector (u8 1 2)))) diff --git a/src/tests/environments.k b/src/tests/environments.k @@ -4,6 +4,399 @@ ;;; Basic Functionality ;;; -;; environment +;; 4.8.1 environment? + ($check-predicate (applicative? environment?)) -;; .... +($check-predicate (environment?)) +($check-predicate (environment? (get-current-environment))) +($check-not-predicate (environment? ())) + +;; 4.8.2 ignore? + +($check-predicate (applicative? ignore?)) +($check-predicate (ignore?)) +($check-predicate (ignore? #ignore)) +($check-not-predicate (ignore? #f)) +($check-not-predicate (ignore? 0)) +($check-not-predicate (ignore? ())) +($check-not-predicate (ignore? #inert)) +($check-not-predicate (ignore? #undefined)) + +;; 4.8.3 eval + +($check-predicate (applicative? eval)) +($check-error (eval)) +($check-error (eval 0)) +($check-error (eval 0 1)) +($check-error (eval 0 (get-current-environment) 2)) + +($let* + ((env (make-environment)) + ((encapsulate #ignore #ignore) (make-encapsulation-type)) + (encapsulation (encapsulate 0)) + (promise ($lazy (+ 1 1))) + (bytevector (make-bytevector 1))) + ($check eq? (eval #t env) #t) + ($check eq? (eval #inert env) #inert) + ($check eq? (eval () env) ()) + ($check eq? (eval #ignore env) #ignore) + ($check eq? (eval env env) env) + ($check eq? (eval eval env) eval) + ($check eq? (eval $vau env) $vau) + ($check eq? (eval root-continuation env) root-continuation) + ($check eq? (eval encapsulation env) encapsulation) + ($check eq? (eval promise env) promise) + ($check eq? (eval 0 env) 0) + ($check eq? (eval "string" env) "string") + ($check eq? (eval #\c env) #\c) + ($check eq? (eval (get-current-input-port) env) (get-current-input-port)) + ($check eq? (eval bytevector env) bytevector) + ($check-error (eval (string->symbol "eval") env)) + ($check eq? (eval (list $quote 1) env) 1) + ($check equal? (eval (list + 1 1) env) 2) + ($check-error (eval (list* not? #t) env)) + ($check-error (eval (list 1) env))) + +($let ((env ($bindings->environment (+ *)))) + ($check equal? (eval ($quote (+ 1 1)) env) 1)) + +;; 4.8.4 make-environment + +($check-predicate (applicative? make-environment)) +($check-predicate (environment? (make-environment))) +($let* + ((x 0) + (e1 (make-environment)) + (e2 (make-environment (get-current-environment))) + (e3 (make-environment e1)) + (e4 (make-environment e2)) + (es (list e1 e2 e3 e4))) + ($check-not-predicate ($binds? e1 x)) + ($check-predicate ($binds? e2 x)) + ($check-not-predicate ($binds? e3 x)) + ($check-predicate ($binds? e4 x)) + (encycle! es 1 3) + ($check-predicate ($binds? (apply make-environment es)))) + +($check-not-predicate (eq? (make-environment) (make-environment))) +($check-not-predicate (equal? (make-environment) (make-environment))) +($check-not-predicate (equal? (make-environment) (get-current-environment))) + +;; 5.10.1 $let + +($check-predicate (operative? $let)) +($check equal? ($let () #t) #t) +($check-error ($let (sym) #inert)) +($check-error ($let (sym 0) #inert)) +($check-error ($let loop ((x 0)) #inert)) +($check-error ($let ((sym 0 1)) #inert)) + +($check-predicate + ($let + ((a (and? + (not? ($binds? (get-current-environment) a)) + (not? ($binds? (get-current-environment) b)))) + (b (and? + (not? ($binds? (get-current-environment) a)) + (not? ($binds? (get-current-environment) b)))) + (f ($lambda () + (and? + (not? ($binds? (get-current-environment) f)) + (not? ($binds? (get-current-environment) g))))) + (g ($lambda () + (and? + (not? ($binds? (get-current-environment) f)) + (not? ($binds? (get-current-environment) g)))))) + (and? a b (f) (g)))) + +;; 6.7.1 $binds? + +($check-predicate (operative? $binds?)) +($check-predicate ($binds? (make-environment))) + +;; 6.7.2 get-current-environment + +($check-predicate (applicative? get-current-environment)) +($check-predicate (environment? (get-current-environment))) +($check-not-predicate ($binds? (get-current-environment) x)) +($let ((x 0)) + ($check-predicate ($binds? (get-current-environment) x))) + +;; 6.7.3 make-kernel-standard-environment + +($check-predicate (applicative? make-kernel-standard-environment)) + +($let ((x 0)) + ($check-not-predicate + ($binds? (make-kernel-standard-environment) x))) + +;; symbols defined in the Kernel Report + +($check-predicate + ($binds? (make-kernel-standard-environment) + ;; 4.1 - 4.10 + boolean? + eq? + equal? + symbol? + inert? $if + pair? null? cons + set-car! set-cdr! copy-es-immutable + environment? ignore? eval make-environment + $define! + operative? applicative? $vau wrap unwrap + ;; 5.1 - 5.10 + $sequence + list list* + $vau $lambda + car cdr + caar cadr cdar cddr + caaar caadr cadar caddr cdaar cdadr cddar cdddr + caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr + cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr + apply + $cond + get-list-metrics list-tail + encycle! + map + $let + ;; 6.1 - 6.4, 6.7 - 6.9 + not? and? or? $and? $or? + combiner? + length list-ref append list-neighbors filter + assoc member? finite-list? countable-list? reduce + append! copy-es assq memq? + $binds? get-current-environment make-kernel-standard-environment + $let* $letrec $letrec* $let-redirect $let-safe $remote-eval + $bindings->environment + $set! $provide! $import! + for-each + ;; 7.1 - 7.3 + continuation? call/cc extend-continuation guard-continuation + continuation->applicative root-continuation error-continuation + apply-continuation $let/cc guard-dynamic-extent exit + ;; 8.1 + make-encapsulation-type + ;; 9.1 + promise? force $lazy memoize + ;; 10.1 + make-keyed-dynamic-variable + ;; 11.1 + make-keyed-static-variable + ;; 12.1 - 12.10 + number? finite? integer? + =? <? <=? >=? >? + + * - + zero? + div mod div-and-mod + div0 mod0 div0-and-mod0 + positive? negative? + odd? even? + abs + max min + lcm gcd + exact? inexact? robust? undefined? + get-real-internal-bounds get-real-exact-bounds + get-real-internal-primary get-real-exact-primary + make-inexact + real->inexact real->exact + with-strict-arithmetic get-strict-arithmetic? + ;; not implemented: with-narrow-arithmetic get-narrow-arithmetic? + rational? + / + numerator denominator + floor ceiling truncate round + rationalize simplest-rational + real? + exp log + sin cos tan asin acos atan + sqrt expt + ;; not implemented: complex? + ;; not implemented: make-rectangular real-part imag-part + ;; not implemented: make-polar magnitude angle + ;; 13.1 + string->symbol + ;; 15.1 - 15.2 + port? + input-port? output-port? + with-input-from-file with-output-to-file + get-current-input-port get-current-output-port + open-input-file open-output-file + close-input-file close-output-file + read + write + call-with-input-file call-with-output-file + load + get-module)) + +;; Additional symbols defined in klisp. + +($check-predicate + ($binds? (make-kernel-standard-environment) + ;; symbols + symbol->string + ;; strings + string? + symbol->string + ;; TODO + ;; chars + char? + char=? char<? char<=? char>=? char>? + char->integer integer->char + ;; TODO + ;; ports + textual-port? binary-port? + with-error-to-file + get-current-error-port + open-binary-input-file open-binary-output-file + close-input-port close-output-port close-port + eof-object? + read-char peek-char char-ready? write-char + newline + display + read-u8 peek-u8 u8-ready? write-u8 + flush-output-port + file-exists? delete-file rename-file + ;; system functions + current-second current-jiffy jiffies-per-second + ;; bytevectors + bytevector? + ;; error handling + error system-error-continuation)) + +;; 6.7.4 $let* + +($check-predicate (operative? $let*)) +($check equal? ($let* () #f) #f) +($check equal? ($let* () #f #t) #t) +($check-error ($let* (sym) #inert)) +($check-error ($let* (sym 0) #inert)) +($check-error ($let* loop ((x 0)) #inert)) +($check-error ($let* ((sym 0 1)) #inert)) + +($check-predicate + ($let* + ((a (and? + (not? ($binds? (get-current-environment) a)) + (not? ($binds? (get-current-environment) b)) + (not? ($binds? (get-current-environment) c)))) + (b (and? + ($binds? (get-current-environment) a) + (not? ($binds? (get-current-environment) b)) + (not? ($binds? (get-current-environment) c)))) + (c (and? + ($binds? (get-current-environment) a) + ($binds? (get-current-environment) b) + (not? ($binds? (get-current-environment) c)))) + (f ($lambda () + (and? + ($binds? (get-current-environment) a) + ($binds? (get-current-environment) b) + ($binds? (get-current-environment) c) + (not? ($binds? (get-current-environment) f)) + (not? ($binds? (get-current-environment) g))))) + (g ($lambda () + (and? + ($binds? (get-current-environment) a) + ($binds? (get-current-environment) b) + ($binds? (get-current-environment) c) + ($binds? (get-current-environment) f) + (not? ($binds? (get-current-environment) g)))))) + (and? a b c (f) (g)))) + +;; 6.7.5 $letrec + +($check-predicate (operative? $letrec)) +($check-no-error ($letrec () #inert)) + +($check-predicate + ($letrec ((x (not? ($binds? (get-current-environment) x)))) x)) + +($check-predicate + ($letrec + ((f ($lambda () + (and? + ($binds? (get-current-environment) f) + ($binds? (get-current-environment) g)))) + (g ($lambda () + (and? + ($binds? (get-current-environment) f) + ($binds? (get-current-environment) g))))) + (and? (f) (g)))) + +;; 6.7.6 $letrec* + +($check-predicate (operative? $letrec*)) +($check equal? ($letrec* () 123) 123) + +($check-predicate + ($letrec* ((x (not? ($binds? (get-current-environment) x)))) x)) + +($check-predicate + ($letrec* + ((a 1) + (f ($lambda () + (and? + ($binds? (get-current-environment) a) + ($binds? (get-current-environment) f))))) + (f))) + +($check-predicate + ($letrec* + ((f ($lambda () + ($binds? (get-current-environment) f))) + (g ($lambda () + (and? + ($binds? (get-current-environment) f) + ($binds? (get-current-environment) g))))) + (and? (f) (g)))) + +($check-predicate + ($letrec* + ((a 1) + (b 2) + (f ($lambda () ($binds? (get-current-environment) f)))) + (f))) + +;; 6.7.7 $let-redirect + +($check-predicate (operative? $let-redirect)) +($check equal? ($let-redirect (make-environment) () 42) 42) + +($let + ((a 1) + (env ($let ((a 2)) (get-current-environment)))) + ($check equal? ($let-redirect (get-current-environment) () a) 1) + ($check equal? ($let-redirect env () a) 2) + ($check equal? ($let-redirect env ((a 3)) a) 3) + ($check equal? ($let-redirect env ((a a)) a) 1)) + +;; 6.7.8 $let-safe + +($check-predicate (operative? $let-safe)) +($check equal? ($let-safe () 42) 42) +($let + (($lambda 42)) + ($check equal? ($let-safe ((x $lambda)) (($lambda () x))) 42) + ($check-error ($let ((x $lambda)) (($lambda () x))))) + +;; 6.7.9 $remote-eval + +($check-predicate (operative? $remote-eval)) +($check equal? ($remote-eval 42 (make-environment)) 42) + +($let + ((e0 (make-kernel-standard-environment)) + (e1 ($let ((or? not?)) (get-current-environment)))) + ($check equal? ($remote-eval (or? #t) e0) #t) + ($check equal? ($remote-eval (or? #t) e1) #f)) + +;; 6.7.10 $bindings->environment + +($check-predicate (operative? $bindings->environment)) +($check-predicate (environment? ($bindings->environment))) +($let + ((env ($bindings->environment (a 1) (b 2)))) + ($check-predicate ($binds? env a b)) + ($check equal? (eval ($quote a) env) 1) + ($check equal? (eval ($quote b) env) 2)) diff --git a/src/tests/memory-ports.k b/src/tests/memory-ports.k @@ -0,0 +1,98 @@ +;; check.k & test-helpers.k should be loaded +;; +;; Tests of string and bytevector port features. +;; + +;; (R7RS 3rd draft, section 6.7.1) open-input-string +;; TODO: char-ready? +;; TODO: unicode input +;; TODO: closing +;; +($let ((p (open-input-string ""))) + ($check-predicate (port? p)) + ($check-predicate (input-port? p)) + ($check-not-predicate (output-port? p)) + ($check-predicate (textual-port? p)) + ($check-not-predicate (binary-port? p)) + ($check-predicate (port-open? p)) + ($check-predicate (eof-object? (peek-char p))) + ($check-predicate (eof-object? (read-char p)))) + +($let ((p (open-input-string "abc"))) + ($check equal? (read-char p) #\a) + ($check equal? (peek-char p) #\b) + ($check equal? (read-char p) #\b) + ($check equal? (read-char p) #\c) + ($check-predicate (eof-object? (read-char p)))) + +($let ((p (open-input-string "(1 2 #ignore) \"x\""))) + ($check equal? (read p) (list 1 2 #ignore)) + ($check equal? (read p) "x") + ($check-predicate (eof-object? (read p)))) + +;; (R7RS 3rd draft, section 6.7.1) open-output-string get-output-string +;; TODO: newline +;; +($let ((p (open-output-string))) + ($check-predicate (port? p)) + ($check-predicate (output-port? p)) + ($check-not-predicate (input-port? p)) + ($check-predicate (textual-port? p)) + ($check-not-predicate (binary-port? p)) + ($check-predicate (port-open? p)) + ($check equal? (get-output-string p) "") + ($check-no-error (write-char #\a p)) + ($check equal? (get-output-string p) "a") + ($check-no-error (display "bc" p)) + ($check equal? (get-output-string p) "abc") + ($check-no-error (write (list 1 "2" 3) p)) + ($check equal? (get-output-string p) "abc(1 \"2\" 3)")) + +($check-error (get-output-string (get-current-input-port))) +($check-error (get-output-string (get-current-output-port))) + +($let ((p (open-output-string))) + ($check-no-error (display (make-string 100 #\a) p)) + ($check-no-error (display (make-string 1000 #\b) p)) + ($check-no-error (display (make-string 10000 #\c) p)) + ($check equal? (string-length (get-output-string p)) 11100) + ($check equal? (string-ref (get-output-string p) 11001) #\c)) + +;; (R7RS 3rd draft, section 6.7.1) open-input-bytevector +;; TODO: u8-ready? +;; TODO: closing +;; +($let ((p (open-input-bytevector (make-bytevector 0)))) + ($check-predicate (port? p)) + ($check-predicate (input-port? p)) + ($check-not-predicate (output-port? p)) + ($check-predicate (binary-port? p)) + ($check-not-predicate (textual-port? p)) + ($check-predicate (eof-object? (peek-u8 p))) + ($check-predicate (eof-object? (read-u8 p)))) + +($let* + ((v (make-bytevector 3 0)) + (p ($sequence + (bytevector-u8-set! v 0 2) + (bytevector-u8-set! v 1 129) + (open-input-bytevector v)))) + ($check equal? (read-u8 p) 2) + ($check equal? (peek-u8 p) 129) + ($check equal? (read-u8 p) 129) + ($check equal? (read-u8 p) 0) + ($check-predicate (eof-object? (read-u8 p)))) + +;; (R7RS 3rd draft, section 6.7.1) open-output-bytevector get-output-bytevector + +($let ((p (open-output-bytevector))) + ($check equal? (bytevector-length (get-output-bytevector p)) 0) + ($check-no-error (write-u8 1 p)) + ($check equal? (bytevector-length (get-output-bytevector p)) 1) + ($check-no-error (write-u8 10 p)) + ($check-no-error (write-u8 129 p)) + ($let ((v (get-output-bytevector p))) + ($check equal? (bytevector-length v) 3) + ($check equal? (bytevector-u8-ref v 0) 1) + ($check equal? (bytevector-u8-ref v 1) 10) + ($check equal? (bytevector-u8-ref v 2) 129))) diff --git a/src/tests/ports.k b/src/tests/ports.k @@ -2,6 +2,8 @@ ;; ;; Tests of i/o features. ;; +;; TODO binary ports +;; ;; Utilities for testing input and output features: ;; ;; temp-file .......... temporary file for input and output diff --git a/src/tests/strings.k b/src/tests/strings.k @@ -131,9 +131,10 @@ ;; immutable strings are eq? iff string=? +;; substring generates mutable strings ;; Andres Navarro ($check-predicate - ($let* ((p "abc") (q (substring p 0 3))) + ($let* ((p "abc") (q (string->immutable-string (substring p 0 3)))) (eq? p q))) ;; string-copy always generate mutable strings @@ -142,8 +143,9 @@ ($let* ((p (string-copy "abc")) (q (substring p 0 3))) (eq? p q))) +;; substring always generate mutable strings ($check-predicate (immutable-string? (substring "abc" 0 0))) -($check-predicate (immutable-string? (substring "abc" 0 1))) +($check-not-predicate (immutable-string? (substring "abc" 0 1))) ;; XXX string-append diff --git a/src/tests/test-all.k b/src/tests/test-all.k @@ -1,9 +1,9 @@ (load "tests/check.k") (load "tests/test-helpers.k") -;(check-set-mode! check-mode-report) +;; (check-set-mode! check-mode-report) -;; TODO add applicative?/operative? check in pairs and lists and pair-mutation +;; TODO add applicative?/operative? for all cominers in all test files (load "tests/booleans.k") (load "tests/eq-equal.k") @@ -21,6 +21,9 @@ (load "tests/strings.k") (load "tests/characters.k") (load "tests/ports.k") +(load "tests/memory-ports.k") (load "tests/error.k") +(load "tests/bytevectors.k") +(load "tests/vectors.k") (check-report) diff --git a/src/tests/test-helpers.k b/src/tests/test-helpers.k @@ -14,6 +14,9 @@ #inert) denv))) +;; mutable-pair?, immutable-pair?, mutable-string? & immutable-string? +;; were added to the ground environment +#| ($define! mutable-pair? ($lambda (obj) ($and? (pair? obj) @@ -46,6 +49,9 @@ ($define! immutable-string? ($lambda (obj) ($and? (string? obj) (not? (nonempty-mutable-string? obj))))) +|# + +($define! nonempty-mutable-string? mutable-string?) ;; XXX/TODO Some of these could be removed if we had eager comprehension in ;; check.k (which would also complete the srfi-78 implementation). The problem diff --git a/src/tests/vectors.k b/src/tests/vectors.k @@ -0,0 +1,98 @@ +;; check.k & test-helpers.k should be loaded +;; +;; Tests of vector (heterogenous array) features. +;; + +;; (R7RS 3rd draft 6.3.6) vector? + +($check-predicate (applicative? vector?)) +($check-predicate (vector?)) +($check-predicate (vector? (make-vector 0))) +($check-predicate (vector? (make-vector 1))) + +($check-not-predicate (vector? 0)) +($check-not-predicate (vector? "")) +($check-not-predicate (vector? ())) +($check-not-predicate (vector? (make-bytevector 0))) +($check-not-predicate (vector? (make-bytevector 1))) + +;; XXX immutable-vector? mutable-vector? + +($check-predicate (applicative? immutable-vector? mutable-vector?)) + +($check-predicate (immutable-vector?)) +($check-predicate (immutable-vector? (make-vector 0))) +($check-not-predicate (immutable-vector? (make-vector 1))) +($check-not-predicate (immutable-vector? (make-bytevector 0))) + +($check-predicate (mutable-vector?)) +($check-predicate (mutable-vector? (make-vector 1))) +($check-not-predicate (mutable-vector? (make-vector 0))) +($check-not-predicate (mutable-vector? (make-bytevector 1))) + +;; (R7RS 3rd draft, section 6.3.6) make-vector vector-length + +($check-predicate (applicative? make-vector vector-length)) +($check equal? (vector-length (make-vector 0)) 0) +($check equal? (vector-length (make-vector 0 "value")) 0) +($check equal? (vector-length (make-vector 1)) 1) +($check equal? (vector-length (make-vector 1 (list 1 2 3))) 1) +($check equal? (vector-length (make-vector 8192)) 8192) + +;; (R7RS 3rd draft, section 6.3.6) vector + +($check-predicate (applicative? vector?)) +($check-predicate (vector? (vector))) +($check-predicate (immutable-vector? (vector))) +($check equal? (vector-length (vector)) 0) +($check-predicate (mutable-vector? (vector "x" "y"))) +($check equal? (vector-length (vector "x" "y")) 2) + +;; (R7RS 3rd draft, section 6.3.6) vector-ref + +($check-predicate (applicative? vector-ref)) +($check equal? (vector-ref (make-vector 10 #t) 1) #t) +($check equal? (vector-ref (make-vector 10 "abc") 5) "abc") +($check equal? (vector-ref (make-vector 10 1/2) 9) 1/2) +($check equal? (vector-ref (vector 1/2 1/3 1/4) 2) 1/4) + +;; (R7RS 3rd draft, section 6.3.6) vector-set! +;; additional property: returns #inert +;; additional property: destination must be mutable + +($check-predicate (applicative? vector-set!)) + +($let* + ((v (make-vector 10)) + (w (vector->immutable-vector v))) + ($check equal? (vector-set! v 0 1) #inert) + ($check equal? (vector-ref v 0) 1) + ($check equal? (vector-set! v 0 "abc") #inert) + ($check equal? (vector-ref v 0) "abc") + ($check equal? (vector-set! v 6 v) #inert) + ($check equal? (vector-ref v 0) "abc") + ($check eq? (vector-ref v 6) v) + ($check-error (vector-ref v -1)) + ($check-error (vector-ref v 10)) + ($check-error (vector-ref v 12345)) + ($check-error (vector-set! v -1 0)) + ($check-error (vector-set! v 10 1/2)) + ($check-error (vector-set! w 0 #t))) + +;; (R7RS 3rd draft, section 6.3.6) list->vector, vector->list + +($check-predicate (applicative? list->vector)) +($check-predicate (immutable-vector? (list->vector ()))) +($check-predicate (mutable-vector? (list->vector (list "a" "b")))) + +;; (R7RS 3rd draft, section 6.3.6) vector-copy +;; TODO: implement equal? for vectors first + +;; XXX vector->immutable-vector + +($check-predicate (applicative? vector->immutable-vector)) + +($check-predicate + (immutable-vector? (vector->immutable-vector (vector 1 2)))) +($check-not-predicate + (mutable-vector? (vector->immutable-vector (vector 1 2))))