diff --git a/README.md b/README.md
index 3028a4479..e461c181a 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,9 @@ Subset of R7RS-small.
| [ 6](https://srfi.schemers.org/srfi-6/srfi-6.html) | Basic String Ports | [`(srfi 6)`](./basis/srfi-6.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 6.13 |
| [ 8](https://srfi.schemers.org/srfi-8/srfi-8.html) | receive: Binding to multiple values | [`(srfi 8)`](./basis/srfi-8.ss) | |
| [ 10](https://srfi.schemers.org/srfi-10/srfi-10.html) | #, external form | built-in | |
+| [ 11](https://srfi.schemers.org/srfi-11/srfi-11.html) | Syntax for receiving multiple values | [`(srfi 11)`](./basis/srfi-11.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 4.2.2 |
| [ 23](https://srfi.schemers.org/srfi-23/srfi-23.html) | Error reporting mechanism | [`(srfi 23)`](./basis/srfi-23.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 6.11 |
+| [ 30](https://srfi.schemers.org/srfi-30/srfi-30.html) | Nested Multi-line Comments | built-in | R7RS 2.2 |
| [ 34](https://srfi.schemers.org/srfi-34/srfi-34.html) | Exception Handling for Programs | [`(srfi 34)`](./basis/srfi-34.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 6.11 |
| [ 39](https://srfi.schemers.org/srfi-39/srfi-39.html) | Parameter objects | [`(srfi 39)`](./basis/srfi-39.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 4.2.6 |
| [ 45](https://srfi.schemers.org/srfi-45/srfi-45.html) | Primitives for Expressing Iterative Lazy Algorithms | [`(srfi 45)`](./basis/srfi-45.ss) | [#296](https://github.com/yamacir-kit/meevax/issues/296)
@@ -103,9 +105,9 @@ sudo rm -rf /usr/local/share/meevax
| Target Name | Description
|:-------------------|:--
-| `all` (default) | Build shared-library `libmeevax.0.4.117.so` and executable `meevax`.
+| `all` (default) | Build shared-library `libmeevax.0.4.166.so` and executable `meevax`.
| `test` | Test executable `meevax`.
-| `package` | Generate debian package `meevax_0.4.117_amd64.deb`.
+| `package` | Generate debian package `meevax_0.4.166_amd64.deb`.
| `install` | Copy files into `/usr/local` __(1)__.
| `install.deb` | `all` + `package` + `sudo apt install .deb`
| `safe-install.deb` | `all` + `test` + `package` + `sudo apt install .deb`
@@ -120,7 +122,7 @@ __(1)__ Meevax installed by `make install` cannot be uninstalled by the system's
## Usage
```
-Meevax Lisp System, version 0.4.117
+Meevax Lisp System, version 0.4.166
Usage: meevax [OPTION...] [FILE...]
diff --git a/VERSION b/VERSION
index 1356ff810..362b83357 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.4.117
+0.4.166
diff --git a/basis/r4rs-essential.ss b/basis/r4rs-essential.ss
index 6b893bd8f..815241138 100644
--- a/basis/r4rs-essential.ss
+++ b/basis/r4rs-essential.ss
@@ -11,7 +11,8 @@
(meevax read)
(meevax string)
(meevax symbol)
- (rename (meevax syntax) (call-with-current-continuation! call-with-current-continuation))
+ (rename (meevax syntax)
+ (call-with-current-continuation! call-with-current-continuation))
(meevax vector)
(meevax write)
(srfi 211 explicit-renaming))
@@ -40,15 +41,13 @@
open-output-file close-input-port close-output-port read read-char
peek-char eof-object? write display newline write-char load)
- (begin (define (unspecified) (if #f #f))
-
- (define (list . xs) xs)
+ (begin (define (list . xs) xs)
(define-syntax cond
(er-macro-transformer
(lambda (form rename compare)
(if (null? (cdr form))
- (unspecified)
+ (if #f #f)
((lambda (clause)
(if (compare (rename 'else) (car clause))
(cons (rename 'begin) (cdr clause))
@@ -284,7 +283,7 @@
(else `(,(rename 'begin) ,@xs))))
(define (each-clause clauses)
(cond ((null? clauses)
- (unspecified))
+ (if #f #f))
((compare (rename 'else) (caar clauses))
(body (cdar clauses)))
((and (pair? (caar clauses))
@@ -566,14 +565,14 @@
(current-input-port))))
(define (read-char . port)
- (%read-char (if (pair? port)
- (car port)
- (current-input-port))))
+ (get-char! (if (pair? port)
+ (car port)
+ (current-input-port))))
(define (peek-char . port)
- (%peek-char (if (pair? port)
- (car port)
- (current-input-port))))
+ (get-char (if (pair? port)
+ (car port)
+ (current-input-port))))
(define (write x . port)
(%write-simple x (if (pair? port)
diff --git a/basis/r4rs.ss b/basis/r4rs.ss
index 86712c318..71e161739 100644
--- a/basis/r4rs.ss
+++ b/basis/r4rs.ss
@@ -1,7 +1,7 @@
(define-library (scheme r4rs)
(import (meevax inexact)
(only (meevax number) exact-integer? expt exact inexact ratio?)
- (only (meevax port) read-ready? standard-input-port standard-output-port)
+ (only (meevax port) get-ready? standard-input-port standard-output-port)
(only (meevax string) string-copy)
(only (meevax syntax) define-syntax)
(only (meevax vector) vector-fill!)
@@ -119,10 +119,6 @@
(atan (imag-part z)
(real-part z)))
- ; (define exact->inexact inexact)
- ;
- ; (define inexact->exact exact)
-
(define (list-tail x k)
(let list-tail ((x x)
(k k))
@@ -166,6 +162,6 @@
(set! %current-output-port previous-output-port)))
(define (char-ready? . port)
- (read-ready? (if (pair? port)
- (car port)
- (current-input-port))))))
+ (get-ready? (if (pair? port)
+ (car port)
+ (current-input-port))))))
diff --git a/basis/r5rs.ss b/basis/r5rs.ss
index 28b7364b7..0a61ff1ff 100644
--- a/basis/r5rs.ss
+++ b/basis/r5rs.ss
@@ -37,8 +37,8 @@
(apply emergency-exit normally?))))
(define-library (scheme r5rs)
- (import (meevax environment)
- (meevax evaluate)
+ (import (only (meevax environment) environment)
+ (only (meevax evaluate) eval)
(only (meevax syntax) define-syntax let-syntax letrec-syntax)
(except (scheme r4rs) call-with-current-continuation)
(except (scheme r5rs continuation) exit)
diff --git a/basis/r7rs.ss b/basis/r7rs.ss
index 18faafef0..7ab11c823 100644
--- a/basis/r7rs.ss
+++ b/basis/r7rs.ss
@@ -1,32 +1,31 @@
(define-library (scheme base)
- (import (only (meevax exception) error? read-error? file-error? syntax-error?)
+ (import (only (meevax error) error? read-error? file-error?)
(only (meevax number) exact-integer?)
- (only (meevax vector) vector->string)
- (only (meevax port)
- binary-port?
- textual-port?
- port?
- input-port-open?
- output-port-open?
- standard-input-port
- standard-output-port
- standard-error-port
- eof-object
- %read-char
- %peek-char
- read-ready?
- put-char
- put-string
- %flush-output-port
- )
- (meevax version)
+ (only (meevax vector) vector-append vector-copy vector-copy! string->vector)
+ (only (meevax port) binary-port?
+ textual-port?
+ port?
+ input-port-open?
+ output-port-open?
+ standard-input-port
+ standard-output-port
+ standard-error-port
+ eof-object
+ get-ready?
+ get-char
+ get-char!
+ put-char
+ put-string
+ %flush-output-port)
+ (only (meevax string) string-copy! vector->string)
+ (only (meevax version) features)
(scheme r5rs)
- (srfi 6) ; Basic String Ports
+ (srfi 6) ; Basic String Ports
+ (srfi 11) ; Syntax for receiving multiple values
(srfi 23) ; Error reporting mechanism
(srfi 34) ; Exception Handling for Programs
(srfi 39) ; Parameter objects
- (srfi 211 explicit-renaming)
- )
+ (srfi 211 explicit-renaming))
(export quote
lambda
@@ -35,8 +34,8 @@
; include
; include-ci
cond
- ; else
- ; =>
+ else
+ =>
case
and
or
@@ -55,13 +54,13 @@
parameterize
guard
quasiquote
- ; unquote
- ; unquote-splicing
+ unquote
+ unquote-splicing
let-syntax
letrec-syntax
syntax-rules
- ; _
- ; ...
+ _
+ ...
; syntax-error
define
; define-values
@@ -116,8 +115,8 @@
square
; exact-integer-sqrt
expt
- inexact
- exact
+ (rename exact->inexact inexact)
+ (rename inexact->exact exact)
number->string
string->number
not
@@ -178,7 +177,7 @@
string->list
list->string
string-copy
- ; string-copy!
+ string-copy!
string-fill!
vector?
make-vector
@@ -189,10 +188,10 @@
vector->list
list->vector
vector->string
- ; string->vector
- ; vector-copy
- ; vector-copy!
- ; vector-append
+ string->vector
+ vector-copy
+ vector-copy!
+ vector-append
vector-fill!
; bytevector?
; make-bytevector
@@ -267,9 +266,7 @@
flush-output-port
features)
- (begin (define (unspecified) (if #f #f))
-
- (define-syntax when
+ (begin (define-syntax when
(er-macro-transformer
(lambda (form rename compare)
`(,(rename 'if) ,(cadr form)
@@ -306,11 +303,8 @@
(values (truncate-quotient x y)
(truncate-remainder x y)))
- (define (square z) (* z z))
-
- (define inexact exact->inexact)
-
- (define exact inexact->exact)
+ (define (square z)
+ (* z z))
(define (make-list k . x)
(let ((x (if (pair? x) (car x) #f)))
@@ -318,8 +312,8 @@
(xs '() (cons x xs)))
((<= i 0) xs))))
- (define (list-set! x k object)
- (set-car! (list-tail x k) object))
+ (define (list-set! xs k x)
+ (set-car! (list-tail xs k) x))
(define (list-copy x)
(let list-copy ((x x))
@@ -343,8 +337,7 @@
(define (error-object? x)
(or (error? x)
(read-error? x)
- (file-error? x)
- (syntax-error? x)))
+ (file-error? x)))
; (define (call-with-port port procedure)
; (let-values ((results (procedure port)))
@@ -386,22 +379,22 @@
(define (close-port x)
(cond ((input-port? x) (close-input-port x))
((output-port? x) (close-output-port x))
- (else (unspecified))))
+ (else (if #f #f))))
(define (read-char . x)
- (%read-char (if (pair? x)
- (car x)
- (current-input-port))))
+ (get-char! (if (pair? x)
+ (car x)
+ (current-input-port))))
(define (peek-char . x)
- (%peek-char (if (pair? x)
- (car x)
- (current-input-port))))
+ (get-char (if (pair? x)
+ (car x)
+ (current-input-port))))
(define (char-ready? . x)
- (read-ready? (if (pair? x)
- (car x)
- (current-input-port))))
+ (get-ready? (if (pair? x)
+ (car x)
+ (current-input-port))))
(define (write-char x . port)
(put-char x (if (pair? port)
@@ -422,183 +415,7 @@
(car port)
(current-output-port))))
)
-
- (begin (define-syntax cond
- (syntax-rules (else =>)
- ((cond (else result1 result2 ...))
- (begin result1 result2 ...))
- ((cond (test => result))
- (let ((temp test))
- (if temp (result temp))))
- ((cond (test => result) clause1 clause2 ...)
- (let ((temp test))
- (if temp
- (result temp)
- (cond clause1 clause2 ...))))
- ((cond (test)) test)
- ((cond (test) clause1 clause2 ...)
- (let ((temp test))
- (if temp
- temp
- (cond clause1 clause2 ...))))
- ((cond (test result1 result2 ...))
- (if test (begin result1 result2 ...)))
- ((cond (test result1 result2 ...)
- clause1 clause2 ...)
- (if test
- (begin result1 result2 ...)
- (cond clause1 clause2 ...)))))
-
- (define-syntax case ; errata version
- (syntax-rules (else =>)
- ((case (key ...) clauses ...)
- (let ((atom-key (key ...)))
- (case atom-key clauses ...)))
- ((case key
- (else => result))
- (result key))
- ((case key
- (else result1 result2 ...))
- (begin result1 result2 ...))
- ((case key
- ((atoms ...) => result))
- (if (memv key '(atoms ...))
- (result key)))
- ((case key ((atoms ...) => result) clause clauses ...)
- (if (memv key '(atoms ...))
- (result key)
- (case key clause clauses ...)))
- ((case key ((atoms ...) result1 result2 ...))
- (if (memv key '(atoms ...))
- (begin result1 result2 ...)))
- ((case key ((atoms ...) result1 result2 ...) clause clauses ...)
- (if (memv key '(atoms ...))
- (begin result1 result2 ...)
- (case key clause clauses ...)))))
-
- (define-syntax and
- (syntax-rules ()
- ((and) #t)
- ((and test) test)
- ((and test1 test2 ...)
- (if test1 (and test2 ...) #f))))
-
- (define-syntax or
- (syntax-rules ()
- ((or) #f)
- ((or test) test)
- ((or test1 test2 ...)
- (let ((x test1))
- (if x x (or test2 ...))))))
-
- (define-syntax when
- (syntax-rules ()
- ((when test result1 result2 ...)
- (if test
- (begin result1 result2 ...)))))
-
- (define-syntax unless
- (syntax-rules ()
- ((unless test result1 result2 ...)
- (if (not test)
- (begin result1 result2 ...)))))
-
- (define-syntax let
- (syntax-rules ()
- ((let ((name val) ...) body1 body2 ...)
- ((lambda (name ...) body1 body2 ...) val ...))
- ((let tag ((name val) ...) body1 body2 ...)
- ((letrec ((tag (lambda (name ...) body1 body2 ...))) tag) val ...))))
-
- (define-syntax let*
- (syntax-rules ()
- ((let* () body1 body2 ...)
- (let () body1 body2 ...))
- ((let* ((name1 val1) (name2 val2) ...) body1 body2 ...)
- (let ((name1 val1))
- (let* ((name2 val2) ...) body1 body2 ...)))))
-
- (define-syntax letrec*
- (syntax-rules ()
- ((letrec* ((var1 init1) ...) body1 body2 ...)
- (let ((var1 ) ...)
- (set! var1 init1)
- ...
- (let () body1 body2 ...)))))
-
- (define-syntax let-values
- (syntax-rules ()
- ((let-values (binding ...) body0 body1 ...)
- (let-values "bind" (binding ...) () (begin body0 body1 ...)))
- ((let-values "bind" () tmps body)
- (let tmps body))
- ((let-values "bind" ((b0 e0) binding ...) tmps body)
- (let-values "mktmp" b0 e0 () (binding ...) tmps body))
- ((let-values "mktmp" () e0 args bindings tmps body)
- (call-with-values
- (lambda () e0)
- (lambda args
- (let-values "bind" bindings tmps body))))
- ((let-values "mktmp" (a . b) e0 (arg ...) bindings (tmp ...) body)
- (let-values "mktmp" b e0 (arg ... x) bindings (tmp ... (a x)) body))
- ((let-values "mktmp" a e0 (arg ...) bindings (tmp ...) body)
- (call-with-values
- (lambda () e0)
- (lambda (arg ... . x)
- (let-values "bind" bindings (tmp ... (a x)) body))))))
-
- ; (define-syntax let-values
- ; (er-macro-transformer
- ; (lambda (form rename compare)
- ; (if (null? (cadr form))
- ; `(,(rename 'let) () ,@(cddr form))
- ; `(,(rename 'call-with-values)
- ; (,(rename 'lambda) () ,(cadar (cadr form)))
- ; (,(rename 'lambda) ,(caar (cadr form))
- ; (,(rename 'let-values) ,(cdr (cadr form))
- ; ,@(cddr form))))))))
-
- (define-syntax let*-values
- (syntax-rules ()
- ((let*-values () body0 body1 ...)
- (let () body0 body1 ...))
- ((let*-values (binding0 binding1 ...)
- body0 body1 ...)
- (let-values (binding0)
- (let*-values (binding1 ...)
- body0 body1 ...)))))
-
- ; (define-syntax let*-values
- ; (er-macro-transformer
- ; (lambda (form rename compare)
- ; (if (null? (cadr form))
- ; `(,(rename 'let) () ,@(cddr form))
- ; `(,(rename 'let-values) (,(caadr form))
- ; (,(rename 'let*-values) ,(cdadr form)
- ; ,@(cddr form)))))))
-
- (define-syntax do
- (syntax-rules ()
- ((do ((var init step ...) ...)
- (test expr ...)
- command ...)
- (letrec
- ((loop
- (lambda (var ...)
- (if test
- (begin
- (if #f #f)
- expr ...)
- (begin
- command
- ...
- (loop (do "step" var step ...)
- ...))))))
- (loop init ...)))
- ((do "step" x)
- x)
- ((do "step" x y)
- y)))))
+ )
(define-library (scheme lazy)
(import (srfi 45))
@@ -720,10 +537,9 @@
(string-map char-foldcase x))))
(define-library (scheme eval)
- (export environment
- eval
- )
- )
+ (import (only (meevax environment) environment)
+ (only (meevax evaluate) eval))
+ (export environment eval))
(define-library (scheme file)
(import (only (meevax port) open-input-file open-output-file)
diff --git a/basis/srfi-11.ss b/basis/srfi-11.ss
new file mode 100644
index 000000000..cae7ee306
--- /dev/null
+++ b/basis/srfi-11.ss
@@ -0,0 +1,32 @@
+(define-library (srfi 11)
+ (import (scheme r5rs)
+ (srfi 211 explicit-renaming))
+
+ (export let-values let*-values)
+
+ (begin (define-syntax let-values
+ (syntax-rules ()
+ ((let-values (binding ...) body0 body1 ...)
+ (let-values "bind" (binding ...) () (begin body0 body1 ...)))
+ ((let-values "bind" () tmps body)
+ (let tmps body))
+ ((let-values "bind" ((b0 e0) binding ...) tmps body)
+ (let-values "mktmp" b0 e0 () (binding ...) tmps body))
+ ((let-values "mktmp" () e0 args bindings tmps body)
+ (call-with-values (lambda () e0)
+ (lambda args
+ (let-values "bind" bindings tmps body))))
+ ((let-values "mktmp" (a . b) e0 (arg ...) bindings (tmp ...) body)
+ (let-values "mktmp" b e0 (arg ... x) bindings (tmp ... (a x)) body))
+ ((let-values "mktmp" a e0 (arg ...) bindings (tmp ...) body)
+ (call-with-values (lambda () e0)
+ (lambda (arg ... . x)
+ (let-values "bind" bindings (tmp ... (a x)) body))))))
+
+ (define-syntax let*-values
+ (syntax-rules ()
+ ((let*-values () body0 body1 ...)
+ (let () body0 body1 ...))
+ ((let*-values (binding0 binding1 ...) body0 body1 ...)
+ (let-values (binding0)
+ (let*-values (binding1 ...) body0 body1 ...)))))))
diff --git a/basis/srfi-23.ss b/basis/srfi-23.ss
index 091f35505..88aa8483b 100644
--- a/basis/srfi-23.ss
+++ b/basis/srfi-23.ss
@@ -1,5 +1,5 @@
(define-library (srfi 23)
- (import (only (meevax exception) make-error)
+ (import (only (meevax error) make-error)
(only (scheme r5rs) define apply)
(only (srfi 34) raise))
(export error)
diff --git a/basis/srfi-34.ss b/basis/srfi-34.ss
index b15fe5830..9e0ffe6de 100644
--- a/basis/srfi-34.ss
+++ b/basis/srfi-34.ss
@@ -19,15 +19,10 @@
; IN THE SOFTWARE.
(define-library (srfi 34)
- (import (only (meevax exception) throw)
- (scheme r5rs)
- )
+ (import (only (meevax error) throw)
+ (scheme r5rs))
- (export with-exception-handler
- raise
- raise-continuable
- guard
- )
+ (export with-exception-handler raise raise-continuable guard)
(begin (define %current-exception-handlers (list throw))
diff --git a/configure/README.md b/configure/README.md
index 1eb7467cf..2939d0148 100644
--- a/configure/README.md
+++ b/configure/README.md
@@ -48,7 +48,9 @@ Subset of R7RS-small.
| [ 6](https://srfi.schemers.org/srfi-6/srfi-6.html) | Basic String Ports | [`(srfi 6)`](./basis/srfi-6.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 6.13 |
| [ 8](https://srfi.schemers.org/srfi-8/srfi-8.html) | receive: Binding to multiple values | [`(srfi 8)`](./basis/srfi-8.ss) | |
| [ 10](https://srfi.schemers.org/srfi-10/srfi-10.html) | #, external form | built-in | |
+| [ 11](https://srfi.schemers.org/srfi-11/srfi-11.html) | Syntax for receiving multiple values | [`(srfi 11)`](./basis/srfi-11.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 4.2.2 |
| [ 23](https://srfi.schemers.org/srfi-23/srfi-23.html) | Error reporting mechanism | [`(srfi 23)`](./basis/srfi-23.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 6.11 |
+| [ 30](https://srfi.schemers.org/srfi-30/srfi-30.html) | Nested Multi-line Comments | built-in | R7RS 2.2 |
| [ 34](https://srfi.schemers.org/srfi-34/srfi-34.html) | Exception Handling for Programs | [`(srfi 34)`](./basis/srfi-34.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 6.11 |
| [ 39](https://srfi.schemers.org/srfi-39/srfi-39.html) | Parameter objects | [`(srfi 39)`](./basis/srfi-39.ss)
[`(scheme base)`](./basis/r7rs.ss) | R7RS 4.2.6 |
| [ 45](https://srfi.schemers.org/srfi-45/srfi-45.html) | Primitives for Expressing Iterative Lazy Algorithms | [`(srfi 45)`](./basis/srfi-45.ss) | [#296](https://github.com/yamacir-kit/meevax/issues/296)
diff --git a/include/meevax/iostream/concatenate.hpp b/include/meevax/iostream/concatenate.hpp
new file mode 100644
index 000000000..7c3abc932
--- /dev/null
+++ b/include/meevax/iostream/concatenate.hpp
@@ -0,0 +1,35 @@
+/*
+ Copyright 2018-2022 Tatsuya Yamasaki.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef INCLUDED_MEEVAX_IOSTREAM_CONCATENATE_HPP
+#define INCLUDED_MEEVAX_IOSTREAM_CONCATENATE_HPP
+
+#include
+
+namespace meevax
+{
+inline namespace iostream
+{
+ auto concatenate = [](auto&&... xs)
+ {
+ std::stringstream ss;
+ (ss << ... << xs);
+ return ss.str();
+ };
+} // namespace iostream
+} // namespace meevax
+
+#endif // INCLUDED_MEEVAX_IOSTREAM_CONCATENATE_HPP
diff --git a/include/meevax/iostream/lexical_cast.hpp b/include/meevax/iostream/lexical_cast.hpp
index 654a364e1..27fa81dad 100644
--- a/include/meevax/iostream/lexical_cast.hpp
+++ b/include/meevax/iostream/lexical_cast.hpp
@@ -25,10 +25,10 @@ namespace meevax
{
inline namespace iostream
{
- template
- auto lexical_cast(From const& from) -> To
+ template
+ auto lexical_cast(Ts&&... xs) -> To
{
- if (std::stringstream ss; ss << from)
+ if (std::stringstream ss; (ss << ... << xs))
{
if constexpr (std::is_same::type, std::string>::value)
{
@@ -51,7 +51,7 @@ inline namespace iostream
else
{
std::stringstream what;
- what << "failed to write " << typeid(From).name() << " type object to std::stringstream";
+ ((what << "failed to write"), ..., (what << " " << typeid(Ts).name())) << " type object to std::stringstream";
throw std::runtime_error(what.str());
}
}
diff --git a/include/meevax/iostream/putback.hpp b/include/meevax/iostream/putback.hpp
index 8eb6fbf47..35d59923d 100644
--- a/include/meevax/iostream/putback.hpp
+++ b/include/meevax/iostream/putback.hpp
@@ -23,6 +23,7 @@ namespace meevax
{
inline namespace iostream
{
+ [[deprecated]]
auto putback(std::istream &, std::string const&) -> std::istream &;
} // namespace iostream
} // namespace meevax
diff --git a/include/meevax/kernel/basis.hpp b/include/meevax/kernel/basis.hpp
index a0206fe8d..6129cdc0d 100644
--- a/include/meevax/kernel/basis.hpp
+++ b/include/meevax/kernel/basis.hpp
@@ -36,6 +36,7 @@ inline namespace kernel
extern string_view const srfi_1;
extern string_view const srfi_6;
extern string_view const srfi_8;
+ extern string_view const srfi_11;
extern string_view const srfi_23;
extern string_view const srfi_34;
extern string_view const srfi_39;
diff --git a/include/meevax/kernel/character.hpp b/include/meevax/kernel/character.hpp
index 730a89838..15398c519 100644
--- a/include/meevax/kernel/character.hpp
+++ b/include/meevax/kernel/character.hpp
@@ -27,17 +27,37 @@ inline namespace kernel
{
struct character
{
- using value_type = std::char_traits::int_type;
+ using char_type = char;
- value_type codepoint;
+ using int_type = std::char_traits::int_type;
+
+ int_type codepoint;
explicit character() = default;
- explicit character(value_type const); // integer->char
+ explicit constexpr character(int_type const& codepoint)
+ : codepoint { codepoint }
+ {}
+
+ static constexpr auto eq(int_type const& c1, int_type const& c2)
+ {
+ return std::char_traits::eq_int_type(c1, c2);
+ }
+
+ inline constexpr auto eq(int_type const& c) const
+ {
+ return std::char_traits::eq_int_type(codepoint, c);
+ }
- explicit character(std::istream &); // read-char
+ static constexpr auto is_eof(int_type const& c)
+ {
+ return eq(std::char_traits::eof(), c);
+ }
- operator value_type() const; // char->integer
+ inline constexpr operator int_type() const
+ {
+ return codepoint;
+ }
explicit operator external_representation() const; // write-char (for display)
};
diff --git a/include/meevax/kernel/configurator.hpp b/include/meevax/kernel/configurator.hpp
index 697d82ca3..55aa7120f 100644
--- a/include/meevax/kernel/configurator.hpp
+++ b/include/meevax/kernel/configurator.hpp
@@ -19,6 +19,7 @@
#include
+#include
#include
#include
#include
@@ -218,7 +219,7 @@ inline namespace kernel
}
else
{
- throw error(make(cat, "option -", name, " requires an argument"));
+ throw error(make(concatenate("option -", name, " requires an argument")));
}
}
else if (auto iter = short_options.find(*current_short_option); iter != std::end(short_options))
@@ -246,7 +247,7 @@ inline namespace kernel
}
else
{
- throw error(make(cat, "option --", current_long_option, " requires an argument"));
+ throw error(make(concatenate("option --", current_long_option, " requires an argument")));
}
}
else if (auto iter = long_options.find(current_long_option); iter != std::end(long_options))
diff --git a/include/meevax/kernel/environment.hpp b/include/meevax/kernel/environment.hpp
index a60bdd751..b3bcabd8c 100644
--- a/include/meevax/kernel/environment.hpp
+++ b/include/meevax/kernel/environment.hpp
@@ -39,8 +39,8 @@ inline namespace kernel
using configurator::debug;
using configurator::trace;
- using reader::intern;
using reader::read;
+ using reader::string_to_symbol;
explicit environment(environment &&) = default;
@@ -59,7 +59,7 @@ inline namespace kernel
auto operator [](symbol::value_type const& variable) -> decltype(auto)
{
- return (*this)[intern(variable)];
+ return (*this)[string_to_symbol(variable)];
}
auto define(const_reference, const_reference = undefined) -> void;
diff --git a/include/meevax/kernel/miscellaneous.hpp b/include/meevax/kernel/eof.hpp
similarity index 84%
rename from include/meevax/kernel/miscellaneous.hpp
rename to include/meevax/kernel/eof.hpp
index 77c9cfad0..b81aa0168 100644
--- a/include/meevax/kernel/miscellaneous.hpp
+++ b/include/meevax/kernel/eof.hpp
@@ -14,8 +14,8 @@
limitations under the License.
*/
-#ifndef INCLUDED_MEEVAX_KERNEL_MISCELLANEOUS_HPP
-#define INCLUDED_MEEVAX_KERNEL_MISCELLANEOUS_HPP
+#ifndef INCLUDED_MEEVAX_KERNEL_EOF_HPP
+#define INCLUDED_MEEVAX_KERNEL_EOF_HPP
#include
@@ -32,4 +32,4 @@ inline namespace kernel
} // namespace kernel
} // namespace meevax
-#endif // INCLUDED_MEEVAX_KERNEL_MISCELLANEOUS_HPP
+#endif // INCLUDED_MEEVAX_KERNEL_EOF_HPP
diff --git a/include/meevax/kernel/number.hpp b/include/meevax/kernel/number.hpp
index eea218cd5..3cc588f52 100644
--- a/include/meevax/kernel/number.hpp
+++ b/include/meevax/kernel/number.hpp
@@ -19,6 +19,7 @@
#include
+#include
#include
#include
#include
@@ -75,7 +76,7 @@ inline namespace kernel
}
else
{
- throw error(make(cat, "no viable operation ", demangle(typeid(F)), " with ", a, " and ", b));
+ throw error(make(concatenate("no viable operation ", demangle(typeid(F)), " with ", a, " and ", b)));
}
}
@@ -111,7 +112,7 @@ inline namespace kernel
}
else
{
- throw error(make(cat, "no viable operation ", demangle(typeid(F)), " with ", a, " and ", b));
+ throw error(make(concatenate("no viable operation ", demangle(typeid(F)), " with ", a, " and ", b)));
}
}
diff --git a/include/meevax/kernel/overview.hpp b/include/meevax/kernel/overview.hpp
index e17f720db..7875a2e65 100644
--- a/include/meevax/kernel/overview.hpp
+++ b/include/meevax/kernel/overview.hpp
@@ -34,6 +34,7 @@ inline namespace kernel
struct exact_integer; // exact_integer.hpp
struct pair; // pair.hpp
struct ratio; // ratio.hpp
+ struct vector; // vector.hpp
template
struct floating_point; // floating_point.hpp
diff --git a/include/meevax/kernel/reader.hpp b/include/meevax/kernel/reader.hpp
index e3dcd44a4..a20fffd0d 100644
--- a/include/meevax/kernel/reader.hpp
+++ b/include/meevax/kernel/reader.hpp
@@ -17,13 +17,10 @@
#ifndef INCLUDED_MEEVAX_KERNEL_READER_HPP
#define INCLUDED_MEEVAX_KERNEL_READER_HPP
-#include
-#include
-#include
#include
+#include
#include
#include
-#include // for eof
#include
#include
#include
@@ -33,205 +30,17 @@ namespace meevax
{
inline namespace kernel
{
- namespace parse
- {
- // using meevax::iostream::operator *;
- // using meevax::iostream::operator +;
- using meevax::iostream::operator |;
-
- // auto intraline_whitespace = satisfy([](auto c) { return std::isblank(c); });
-
- // auto line_ending = sequence("\r\n") | one_of('\n', '\r');
-
- // auto whitespace = intraline_whitespace | line_ending;
-
- // auto vertical_line = one_of('|');
-
- // auto delimiter = whitespace | vertical_line | one_of('(', ')', '"', ';');
-
- // auto letter = satisfy([](auto c) { return std::isalpha(c); });
-
- // auto special_initial = one_of('!', '$', '%', '&', '*', '/', ':', '<', '=', '>', '?', '^', '_', '~');
-
- // auto initial = letter | special_initial;
-
- // auto digit = satisfy([](auto c) { return std::isdigit(c); });
-
- // auto hex_digit = satisfy([](auto c) { return std::isxdigit(c); });
-
- // auto explicit_sign = one_of('+', '-');
-
- // auto special_subsequent = explicit_sign | one_of('.', '@');
-
- // auto subsequent = initial | digit | special_subsequent;
-
- // auto inline_hex_escape = sequence("\\x") + hex_digit + many(hex_digit);
-
- // TODO auto any_character_other_than_vertical_line_or_backslash
-
- // auto symbol_element = letter;
- // // any_character_other_than_vertical_line_or_backslash
- // // | inline_hex_escape
- // // | mnemonic_escape
- // // | s("\\|")
-
- // auto sign_subsequent = initial | explicit_sign | one_of('@');
-
- // auto dot_subsequent = sign_subsequent | one_of('.');
-
- // auto peculiar_identifier = explicit_sign
- // | explicit_sign + sign_subsequent + many(subsequent)
- // | explicit_sign + one_of('.') + dot_subsequent + many(subsequent)
- // | one_of('.') + dot_subsequent + many(subsequent);
-
- // auto identifier = initial + many(subsequent)
- // | vertical_line + many(symbol_element) + vertical_line
- // | peculiar_identifier;
-
- // auto boolean = sequence("#true") | sequence("#t") | sequence("#false") | sequence("#f");
-
- auto token = [](std::istream & is) // = | | | | | ( | ) | #( | #u8( | ’ | ` | , | ,@ | .
- {
- auto is_end = [](auto c) constexpr
- {
- auto one_of = [c](auto... xs) constexpr
- {
- return (std::char_traits::eq(c, xs) or ...);
- };
-
- return std::isspace(c) or one_of('"', '#', '\'', '(', ')', ',', ';', '[', ']', '`', '{', '|', '}', std::char_traits::eof()); // NOTE: What read treats specially.
- };
+ auto get_codepoint(std::istream &) -> character::int_type;
- external_representation result;
+ auto get_delimited_elements(std::istream & is, character::int_type) -> string;
- for (auto c = is.peek(); not is_end(c); c = is.peek())
- {
- result.push_back(is.get());
- }
+ auto get_token(std::istream &) -> external_representation;
- return result;
- };
+ auto ignore_nested_block_comment(std::istream &) -> std::istream &;
- auto any_character = [](std::istream & is)
- {
- switch (auto s = token(is); std::size(s))
- {
- case 0:
- return make(is.get());
-
- case 1:
- return make(s[0]);
-
- default:
- putback(is, s);
- throw read_error(make("If in #\\ is alphabetic, then any character immediately following cannot be one that can appear in an identifier"));
- }
- };
+ auto read_character_literal(std::istream &) -> value_type;
- auto character_name = [](std::istream & is)
- {
- std::unordered_map static const character_names
- {
- { "alarm" , 0x07 },
- { "backspace", 0x08 },
- { "delete" , 0x7F },
- { "escape" , 0x1B },
- { "newline" , 0x0A },
- { "null" , 0x00 },
- { "return" , 0x0D },
- { "space" , 0x20 },
- { "tab" , 0x09 },
- };
-
- auto const name = token(is);
-
- try
- {
- return make(character_names.at(name));
- }
- catch (...)
- {
- putback(is, name);
- throw read_error(make("invalid "), make("\\#" + name));
- }
- };
-
- auto hex_scalar_value = [](std::istream & is)
- {
- if (auto s = token(is); s[0] == 'x' and 1 < std::size(s))
- {
- std::stringstream ss;
- ss << std::hex << s.substr(1);
-
- character::value_type value = 0;
- ss >> value;
-
- return make(value);
- }
- else
- {
- putback(is, s);
- throw read_error(make("invalid "), make("\\#" + s));
- }
- };
-
- auto character = any_character | character_name | hex_scalar_value;
- }
-
- namespace string_to
- {
- template ,
- std::is_invocable)>
- auto operator |(F&& f, G&& g)
- {
- return [=](external_representation const& token, auto radix)
- {
- try
- {
- return f(token, radix);
- }
- catch (...)
- {
- return g(token, radix);
- }
- };
- }
-
- auto integer = [](external_representation const& token, auto radix = 10) -> value_type
- {
- auto const result = exact_integer(token, radix);
- return make(result);
- };
-
- auto ratio = [](external_representation const& token, auto radix = 10)
- {
- return meevax::ratio(token, radix).simple();
- };
-
- auto decimal = [](external_representation const& token, auto) -> value_type
- {
- auto const result = double_float(token);
- return make(result);
- };
-
- auto flonum = [](external_representation const& token, auto)
- {
- if (auto iter = constants.find(token); iter != std::end(constants))
- {
- return cdr(*iter);
- }
- else
- {
- throw read_error(make("not a number"), make(token));
- }
- };
-
- auto real = integer | ratio | decimal | flonum;
-
- auto complex = real;
-
- auto number = complex;
- } // namespace string_to
+ auto read_string_literal(std::istream &) -> value_type;
template
class reader
@@ -250,23 +59,8 @@ inline namespace kernel
inline auto char_ready() const
{
- return standard_input.is_also() and standard_input.as();
- }
-
- static auto intern(external_representation const& name) -> const_reference
- {
- if (auto const iter = symbols.find(name); iter != std::end(symbols))
- {
- return cdr(*iter);
- }
- else if (auto const [iter, success] = symbols.emplace(name, make(name)); success)
- {
- return cdr(*iter);
- }
- else
- {
- throw error(make("failed to intern a symbol"), make(name));
- }
+ assert(standard_input.is_also());
+ return static_cast(standard_input.as());
}
inline auto read(std::istream & is) -> value_type
@@ -275,144 +69,146 @@ inline namespace kernel
{
switch (auto const c = *head)
{
- case ';':
- is.ignore(std::numeric_limits::max(), '\n');
+ case '\t': // 0x09
+ case '\n': // 0x0A
+ case '\v': // 0x0B
+ case '\f': // 0x0C
+ case '\r': // 0x0D
+ case ' ': // 0x20
break;
- case ' ':
- case '\f':
- case '\n':
- case '\r':
- case '\t':
- case '\v':
- break;
-
- case '(':
- case '[':
- case '{':
- try
- {
- let const kar = read(is);
- is.putback(c);
- return cons(kar, read(is));
- }
- catch (std::integral_constant const&) { return std::char_traits::eq(c, '(') ? unit : throw; }
- catch (std::integral_constant const&) { return std::char_traits::eq(c, '[') ? unit : throw; }
- catch (std::integral_constant const&) { return std::char_traits::eq(c, '{') ? unit : throw; }
- catch (std::integral_constant const&)
- {
- let const kdr = read(is);
-
- switch (c)
- {
- case '(': ignore(is, [](auto c) { return not std::char_traits::eq(c, ')'); }).get(); break;
- case '[': ignore(is, [](auto c) { return not std::char_traits::eq(c, ']'); }).get(); break;
- case '{': ignore(is, [](auto c) { return not std::char_traits::eq(c, '}'); }).get(); break;
- }
-
- return kdr;
- }
-
- case ')': throw std::integral_constant();
- case ']': throw std::integral_constant();
- case '}': throw std::integral_constant();
-
- case '"':
- return make(is);
-
- case '\'':
- return list(intern("quote"), read(is));
-
- case '`':
- return list(intern("quasiquote"), read(is));
+ case '"': // 0x22
+ return read_string_literal(is.putback(c));
- case ',':
- switch (is.peek())
- {
- case '@':
- is.ignore(1);
- return list(intern("unquote-splicing"), read(is));
-
- default:
- return list(intern("unquote"), read(is));
- }
-
- case '#':
+ case '#': // 0x23
switch (auto const c = is.get())
{
- case '!': // from SRFI-22
+ case '!': // SRFI 22
is.ignore(std::numeric_limits::max(), '\n');
return read(is);
- case ',': // from SRFI-10
+ case ',': // SRFI 10
return evaluate(read(is));
- case ';': // from SRFI-62
+ case ';': // SRFI 62
return read(is), read(is);
+ case '"':
+ return string_to_symbol(get_delimited_elements(is.putback(c), c));
+
case 'b': // (string->number (read) 2)
- return string_to::number(is.peek() == '#' ? lexical_cast(read(is)) : parse::token(is), 2);
+ return string_to_number(is.peek() == '#' ? lexical_cast(read(is)) : get_token(is), 2);
- case 'c': // from Common Lisp
- if (let const xs = read(is); xs.is())
- {
- return make(e0, e0);
- }
- else if (not cdr(xs).is())
- {
- return make(car(xs), e0);
- }
- else
+ case 'c': // Common Lisp
{
- return make(car(xs), cadr(xs));
+ let const xs = read(is);
+ return make(list_tail(xs, 0).is() ? list_ref(xs, 0) : e0,
+ list_tail(xs, 1).is() ? list_ref(xs, 1) : e0);
}
case 'd':
- return string_to::number(is.peek() == '#' ? lexical_cast(read(is)) : parse::token(is), 10);
+ return string_to_number(is.peek() == '#' ? lexical_cast(read(is)) : get_token(is), 10);
case 'e':
return read(is).template as().exact(); // NOTE: Same as #,(exact (read))
case 'f':
- parse::token(is);
+ get_token(is);
return f;
case 'i':
return read(is).template as().inexact(); // NOTE: Same as #,(inexact (read))
case 'o':
- return string_to::number(is.peek() == '#' ? lexical_cast(read(is)) : parse::token(is), 8);
+ return string_to_number(is.peek() == '#' ? lexical_cast(read(is)) : get_token(is), 8);
case 't':
- parse::token(is);
+ get_token(is);
return t;
case 'x':
- return string_to::number(is.peek() == '#' ? lexical_cast(read(is)) : parse::token(is), 16);
+ return string_to_number(is.peek() == '#' ? lexical_cast(read(is)) : get_token(is), 16);
case '(':
is.putback(c);
return make(read(is));
case '\\':
- return parse::character(is);
+ return read_character_literal(is);
+
+ case '|': // SRFI 30
+ ignore_nested_block_comment(is);
+ return read(is);
default:
throw read_error(make("unknown discriminator"), make(c));
}
+ case '\'': // 0x27
+ return list(string_to_symbol("quote"), read(is));
+
+ case ',': // 0x2C
+ switch (is.peek())
+ {
+ case '@':
+ is.ignore(1);
+ return list(string_to_symbol("unquote-splicing"), read(is));
+
+ default:
+ return list(string_to_symbol("unquote"), read(is));
+ }
+
+ case ';': // 0x3B
+ is.ignore(std::numeric_limits::max(), '\n');
+ break;
+
+ case '`': // 0x60
+ return list(string_to_symbol("quasiquote"), read(is));
+
+ case '|': // 0x7C
+ return string_to_symbol(get_delimited_elements(is.putback(c), c));
+
+ case '(':
+ case '[':
+ case '{':
+ try
+ {
+ let const kar = read(is);
+ return cons(kar, read(is.putback(c)));
+ }
+ catch (std::integral_constant const&) { return character::eq(c, '(') ? unit : throw; }
+ catch (std::integral_constant const&) { return character::eq(c, '[') ? unit : throw; }
+ catch (std::integral_constant const&) { return character::eq(c, '{') ? unit : throw; }
+ catch (std::integral_constant const&)
+ {
+ let const kdr = read(is);
+
+ switch (c)
+ {
+ case '(': is.ignore(std::numeric_limits::max(), ')'); break;
+ case '[': is.ignore(std::numeric_limits::max(), ']'); break;
+ case '{': is.ignore(std::numeric_limits::max(), '}'); break;
+ }
+
+ return kdr;
+ }
+
+ case ')': throw std::integral_constant();
+ case ']': throw std::integral_constant();
+ case '}': throw std::integral_constant();
+
default:
- if (auto const token = c + parse::token(is); token == ".")
+ if (auto const token = get_token(is.putback(c)); token == ".")
{
throw std::integral_constant();
}
else try
{
- return string_to::number(token, 10);
+ return string_to_number(token, 10);
}
catch (...)
{
- return intern(token);
+ return string_to_symbol(token);
}
}
}
@@ -420,31 +216,70 @@ inline namespace kernel
return eof_object;
}
- inline auto read(std::istream && is)
+ inline auto read(const_reference x) -> decltype(auto)
{
- return read(is);
+ assert(x.is_also());
+ return read(x.as());
}
- inline auto read(const_reference x) -> value_type
+ inline auto read() -> decltype(auto)
{
- if (x.is_also())
+ return read(standard_input);
+ }
+
+ inline auto read(external_representation const& s) -> value_type // NOTE: Specifying `decltype(auto)` causes a `undefined reference to ...` error in GCC-7.
+ {
+ auto port = std::stringstream(s);
+ return read(port);
+ }
+
+ static auto string_to_number(external_representation const& token, int radix = 10)
+ {
+ try
{
- return read(x.as());
+ return make(token, radix);
}
- else
+ catch (...)
{
- throw read_error(make("not an input-port"), x);
+ try
+ {
+ return ratio(token, radix).simple();
+ }
+ catch (...)
+ {
+ try
+ {
+ return make(token);
+ }
+ catch (...)
+ {
+ if (auto iter = constants.find(token); iter != std::end(constants))
+ {
+ return iter->second;
+ }
+ else
+ {
+ throw read_error(make("not a number"), make(token));
+ }
+ }
+ }
}
}
- inline auto read() -> value_type
- {
- return read(standard_input);
- }
-
- inline auto read(external_representation const& s) -> value_type
+ static auto string_to_symbol(external_representation const& name) -> const_reference
{
- return read(std::stringstream(s));
+ if (auto const iter = symbols.find(name); iter != std::end(symbols))
+ {
+ return iter->second;
+ }
+ else if (auto const [iter, success] = symbols.emplace(name, make(name)); success)
+ {
+ return iter->second;
+ }
+ else
+ {
+ throw error(make("failed to intern a symbol"), make(name));
+ }
}
};
} // namespace kernel
diff --git a/include/meevax/kernel/string.hpp b/include/meevax/kernel/string.hpp
index 4b69beefc..279c6201e 100644
--- a/include/meevax/kernel/string.hpp
+++ b/include/meevax/kernel/string.hpp
@@ -23,35 +23,140 @@ namespace meevax
{
inline namespace kernel
{
- auto cat = [](auto&&... xs)
+ struct string
{
- std::stringstream ss;
- (ss << ... << xs);
- return ss.str();
- };
-
- struct string : public std::vector
- {
- using std::vector::vector; // make-string
-
- explicit string(std::istream &, std::size_t = std::numeric_limits::max()); // read-string
+ std::vector codepoints;
- explicit string(std::istream &&);
+ explicit string() = default;
explicit string(external_representation const&);
- template
- explicit string(decltype(cat), Ts&&... xs)
- : string { cat(std::forward(xs)...) }
- {}
-
- auto list(size_type, size_type) const -> meevax::value_type;
-
- auto list(size_type = 0) const -> meevax::value_type;
+ /*
+ (list->string list) procedure
+
+ It is an error if any element of list is not a character.
+
+ The string->list procedure returns a newly allocated list of the
+ characters of string between start and end. list->string returns a newly
+ allocated string formed from the elements in the list list. In both
+ procedures, order is preserved. string->list and list->string are
+ inverses so far as equal? is concerned.
+ */
+ explicit string(const_reference);
+
+ /*
+ (make-string k) procedure
+ (make-string k char) procedure
+
+ The make-string procedure returns a newly allocated string of length k.
+ If char is given, then all the characters of the string are initialized
+ to char, otherwise the contents of the string are unspecified.
+ */
+ explicit string(const_reference, const_reference);
+
+ /*
+ (vector->string vector) procedure
+ (vector->string vector start) procedure
+ (vector->string vector start end) procedure
+
+ It is an error if any element of vector between start and end is not a
+ character.
+
+ The vector->string procedure returns a newly allocated string of the
+ objects contained in the elements of vector between start and end. The
+ string->vector procedure returns a newly created vector initialized to
+ the elements of the string string between start and end.
+
+ In both procedures, order is preserved.
+ */
+ explicit string(vector const&, const_reference, const_reference);
+
+ /*
+ (string-append string ...) procedure
+
+ Returns a newly allocated string whose characters are the concatenation
+ of the characters in the given strings.
+ */
+ static auto append(const_reference) -> value_type;
+
+ /*
+ (string-copy string) procedure
+ (string-copy string start) procedure
+ (string-copy string start end) procedure
+
+ Returns a newly allocated copy of the part of the given string between
+ start and end.
+ */
+ auto copy(const_reference, const_reference) const -> value_type;
+
+ /*
+ (string-copy! to at from) procedure
+ (string-copy! to at from start) procedure
+ (string-copy! to at from start end) procedure
+
+ It is an error if at is less than zero or greater than the length of to.
+ It is also an error if (- (string-length to) at) is less than (- end
+ start).
+
+ Copies the characters of string from between start and end to string to,
+ starting at at. The order in which characters are copied is unspecified,
+ except that if the source and destination overlap, copying takes place
+ as if the source is first copied into a temporary string and then into
+ the destination. This can be achieved without allocating storage by
+ making sure to copy in the correct direction in such circumstances.
+ */
+ auto copy(const_reference, const_reference, const_reference, const_reference) -> void;
+
+ /*
+ (string-length string) procedure
+
+ Returns the number of characters in the given string.
+ */
+ auto length() const -> value_type;
+
+ /*
+ (string->list string) procedure
+ (string->list string start) procedure
+ (string->list string start end) procedure
+
+ (list->string list) procedure
+
+ It is an error if any element of list is not a character.
+
+ The string->list procedure returns a newly allocated list of the
+ characters of string between start and end. list->string returns a newly
+ allocated string formed from the elements in the list list. In both
+ procedures, order is preserved. string->list and list->string are
+ inverses so far as equal? is concerned.
+ */
+ auto make_list(const_reference, const_reference) const -> value_type;
+
+ /*
+ (string-ref string k) procedure
+
+ It is an error if k is not a valid index of string.
+
+ The string-ref procedure returns character k of string using zero-origin
+ indexing. There is no requirement for this procedure to execute in
+ constant time.
+ */
+ auto ref(const_reference) const -> value_type;
+
+ /*
+ (string-set! string k char) procedure
+
+ It is an error if k is not a valid index of string.
+
+ The string-set! procedure stores char in element k of string. There is
+ no requirement for this procedure to execute in constant time.
+ */
+ auto set(const_reference, const_reference) -> void;
operator external_representation() const; // write-string (for display)
};
+ auto operator ==(string const&, string const&) -> bool;
+
auto operator <<(std::ostream &, string const&) -> std::ostream &;
} // namespace kernel
} // namespace meevax
diff --git a/include/meevax/kernel/vector.hpp b/include/meevax/kernel/vector.hpp
index b8d5e483d..b84343afd 100644
--- a/include/meevax/kernel/vector.hpp
+++ b/include/meevax/kernel/vector.hpp
@@ -27,10 +27,10 @@ inline namespace kernel
{
std::vector data;
- using size_type = decltype(data)::size_type;
-
explicit vector() = default;
+ explicit vector(string const&);
+
/*
(vector obj ...) procedure
@@ -49,6 +49,43 @@ inline namespace kernel
*/
explicit vector(const_reference, const_reference);
+ /*
+ (vector-append vector ...) procedure
+
+ Returns a newly allocated vector whose elements are the concatenation of
+ the elements of the given vectors.
+ */
+ static auto append(const_reference) -> value_type;
+
+ /*
+ (vector-copy vector) procedure
+ (vector-copy vector start) procedure
+ (vector-copy vector start end) procedure
+
+ Returns a newly allocated copy of the elements of the given vector
+ between start and end. The elements of the new vector are the same (in
+ the sense of eqv?) as the elements of the old.
+ */
+ auto copy(const_reference, const_reference) const -> value_type;
+
+ /*
+ (vector-copy! to at from) procedure
+ (vector-copy! to at from start) procedure
+ (vector-copy! to at from start end) procedure
+
+ It is an error if at is less than zero or greater than the length of to.
+ It is also an error if (- (vector-length to) at) is less than
+ (- end start).
+
+ Copies the elements of vector from between start and end to vector to,
+ starting at at. The order in which elements are copied is unspecified,
+ except that if the source and destination overlap, copying takes place
+ as if the source is first copied into a temporary vector and then into
+ the destination. This can be achieved without allocating storage by
+ making sure to copy in the correct direction in such circumstances.
+ */
+ auto copy(const_reference, const_reference, const_reference, const_reference) -> void;
+
/*
(vector-fill! vector fill) procedure
(vector-fill! vector fill start) procedure
@@ -96,27 +133,6 @@ inline namespace kernel
procedure stores obj in element k of vector.
*/
auto set(const_reference, const_reference) -> const_reference;
-
- /*
- (vector->string vector) procedure
- (vector->string vector start) procedure
- (vector->string vector start end) procedure
-
- (string->vector string) procedure
- (string->vector string start) procedure
- (string->vector string start end) procedure
-
- It is an error if any element of vector between start and end is not a
- character.
-
- The vector->string procedure returns a newly allocated string of the
- objects contained in the elements of vector between start and end. The
- string->vector procedure returns a newly created vector initialized to
- the elements of the string string between start and end.
-
- In both procedures, order is preserved.
- */
- auto string(const_reference, const_reference) const -> value_type;
};
auto operator ==(vector const&, vector const&) -> bool;
diff --git a/include/meevax/parser/combinator.hpp b/include/meevax/parser/combinator.hpp
index 6664e661e..0f2bc6cd6 100644
--- a/include/meevax/parser/combinator.hpp
+++ b/include/meevax/parser/combinator.hpp
@@ -21,9 +21,9 @@
#include
#include
-#include
+#include
#include // for read_error
-#include // for eof
+#include
namespace meevax
{
diff --git a/src/kernel/basis.cpp b/src/kernel/basis.cpp
index b0f9ea6df..f2e8bb6dd 100644
--- a/src/kernel/basis.cpp
+++ b/src/kernel/basis.cpp
@@ -49,6 +49,7 @@ DEFINE_BINARY(r7rs);
DEFINE_BINARY(srfi_1);
DEFINE_BINARY(srfi_6);
DEFINE_BINARY(srfi_8);
+DEFINE_BINARY(srfi_11);
DEFINE_BINARY(srfi_23);
DEFINE_BINARY(srfi_34);
DEFINE_BINARY(srfi_39);
diff --git a/src/kernel/character.cpp b/src/kernel/character.cpp
index 64497a514..771845438 100644
--- a/src/kernel/character.cpp
+++ b/src/kernel/character.cpp
@@ -15,64 +15,13 @@
*/
#include
+#include
#include
-#include // for eof
namespace meevax
{
inline namespace kernel
{
- character::character(value_type const codepoint)
- : codepoint { codepoint }
- {}
-
- character::character(std::istream & is)
- : codepoint {}
- {
- /*
- 00000000 -- 0000007F: 0xxxxxxx
- 00000080 -- 000007FF: 110xxxxx 10xxxxxx
- 00000800 -- 0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
- 00010000 -- 001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- */
-
- if (auto const c = is.peek(); std::char_traits::eq(std::char_traits::eof(), c))
- {
- throw eof();
- }
- else if (0x00 <= c and c <= 0x7F) // 7 bit
- {
- codepoint = is.get();
- }
- else if (0xC2 <= c and c <= 0xDF) // 11 bit
- {
- codepoint |= is.get() bitand 0b0001'1111; codepoint <<= 6;
- codepoint |= is.get() bitand 0b0011'1111;
- }
- else if (0xE0 <= c and c <= 0xEF) // 16 bit
- {
- codepoint |= is.get() bitand 0b0000'1111; codepoint <<= 6;
- codepoint |= is.get() bitand 0b0011'1111; codepoint <<= 6;
- codepoint |= is.get() bitand 0b0011'1111;
- }
- else if (0xF0 <= c and c <= 0xF4) // 21 bit
- {
- codepoint |= is.get() bitand 0b0000'0111; codepoint <<= 6;
- codepoint |= is.get() bitand 0b0011'1111; codepoint <<= 6;
- codepoint |= is.get() bitand 0b0011'1111; codepoint <<= 6;
- codepoint |= is.get() bitand 0b0011'1111;
- }
- else
- {
- throw read_error(make("invalid stream"), unit);
- }
- }
-
- character::operator value_type() const
- {
- return codepoint;
- }
-
character::operator external_representation() const
{
std::array bytes {};
@@ -135,5 +84,7 @@ inline namespace kernel
static_assert(std::is_standard_layout::value);
static_assert(std::is_trivial::value);
+
+ static_assert(4 <= sizeof(character::int_type));
} // namespace kernel
} // namespace meevax
diff --git a/src/kernel/environment.cpp b/src/kernel/environment.cpp
index a8b0bab33..0c66ccc0d 100644
--- a/src/kernel/environment.cpp
+++ b/src/kernel/environment.cpp
@@ -28,7 +28,7 @@ inline namespace kernel
auto environment::define(external_representation const& name, const_reference value) -> void
{
- define(intern(name), value);
+ define(string_to_symbol(name), value);
}
auto environment::evaluate(const_reference expression) -> value_type
@@ -162,8 +162,8 @@ inline namespace kernel
{
return map1([&](let const& identity)
{
- return make(intern(car(prefixes).as().value +
- identity.as().symbol().as().value),
+ return make(string_to_symbol(car(prefixes).as().value +
+ identity.as().symbol().as().value),
identity.as().load());
},
resolve(import_set));
diff --git a/src/kernel/miscellaneous.cpp b/src/kernel/eof.cpp
similarity index 95%
rename from src/kernel/miscellaneous.cpp
rename to src/kernel/eof.cpp
index 8a59d763a..61b0b179b 100644
--- a/src/kernel/miscellaneous.cpp
+++ b/src/kernel/eof.cpp
@@ -14,7 +14,7 @@
limitations under the License.
*/
-#include
+#include
namespace meevax
{
diff --git a/src/kernel/library.cpp b/src/kernel/library.cpp
index 310bb404f..dd11043ad 100644
--- a/src/kernel/library.cpp
+++ b/src/kernel/library.cpp
@@ -43,7 +43,7 @@ inline namespace kernel
}
else
{
- throw invalid_application(intern("char->integer") | xs);
+ throw invalid_application(string_to_symbol("char->integer") | xs);
}
});
@@ -85,7 +85,7 @@ inline namespace kernel
else [[fallthrough]];
default:
- throw invalid_application(intern("emergency-exit") | xs);
+ throw invalid_application(string_to_symbol("emergency-exit") | xs);
}
});
@@ -156,7 +156,7 @@ inline namespace kernel
library.export_("eval");
});
- define_library("(meevax exception)", [](library & library)
+ define_library("(meevax error)", [](library & library)
{
library.define("throw", [](let const& xs) -> value_type
{
@@ -183,17 +183,11 @@ inline namespace kernel
return car(xs).is();
});
- library.define("syntax-error?", [](let const& xs)
- {
- return car(xs).is();
- });
-
library.export_("throw");
library.export_("make-error");
library.export_("error?");
library.export_("read-error?");
library.export_("file-error?");
- library.export_("syntax-error?");
});
define_library("(meevax experimental)", [](library & library)
@@ -297,7 +291,7 @@ inline namespace kernel
return car(xs).as().log() / cadr(xs).as().log();
default:
- throw invalid_application(intern("log") | xs);
+ throw invalid_application(string_to_symbol("log") | xs);
}
});
@@ -337,7 +331,7 @@ inline namespace kernel
return car(xs).as().atan2(cadr(xs));
default:
- throw invalid_application(intern("atan") | xs);
+ throw invalid_application(string_to_symbol("atan") | xs);
}
});
@@ -403,18 +397,6 @@ inline namespace kernel
return std::accumulate(std::begin(xs), std::end(xs), unit, append2);
});
- library.define("list->string", [](let const& xs)
- {
- string s;
-
- for (let const& x : car(xs))
- {
- s.push_back(x.as());
- }
-
- return make(std::move(s));
- });
-
library.define("list->vector", [](let const& xs)
{
return make(car(xs));
@@ -422,7 +404,6 @@ inline namespace kernel
library.export_("null?");
library.export_("append");
- library.export_("list->string");
library.export_("list->vector");
});
@@ -519,14 +500,14 @@ inline namespace kernel
return car(xs).is();
});
- #define DEFINE(SYMBOL, COMPARE) \
- library.define(#SYMBOL, [](let const& xs) \
- { \
- return std::adjacent_find( \
- std::begin(xs), std::end(xs), [](let const& a, let const& b) \
- { \
- return not COMPARE(a.as(), b); \
- }) == std::end(xs); \
+ #define DEFINE(SYMBOL, COMPARE) \
+ library.define(#SYMBOL, [](let const& xs) \
+ { \
+ return std::adjacent_find( \
+ std::begin(xs), std::end(xs), [](let const& a, let const& b) \
+ { \
+ return not COMPARE(a.as(), b); \
+ }) == std::end(xs); \
})
DEFINE(= , std::equal_to ());
@@ -548,25 +529,25 @@ inline namespace kernel
return std::accumulate(std::begin(xs), std::end(xs), e1, std::multiplies());
});
- #define DEFINE(SYMBOL, FUNCTION, BASIS) \
- library.define(SYMBOL, [](let const& xs) \
- { \
- switch (length(xs)) \
- { \
- case 0: \
- throw invalid_application(intern(SYMBOL) | xs); \
- \
- case 1: \
- return FUNCTION(BASIS, car(xs)); \
- \
- default: \
- return std::accumulate( \
- std::next(std::begin(xs)), std::end(xs), car(xs), \
- [](let const& a, let const& b) \
- { \
- return FUNCTION(a, b); \
- }); \
- } \
+ #define DEFINE(SYMBOL, FUNCTION, BASIS) \
+ library.define(SYMBOL, [](let const& xs) \
+ { \
+ switch (length(xs)) \
+ { \
+ case 0: \
+ throw invalid_application(string_to_symbol(SYMBOL) | xs); \
+ \
+ case 1: \
+ return FUNCTION(BASIS, car(xs)); \
+ \
+ default: \
+ return std::accumulate( \
+ std::next(std::begin(xs)), std::end(xs), car(xs), \
+ [](let const& a, let const& b) \
+ { \
+ return FUNCTION(a, b); \
+ }); \
+ } \
})
DEFINE("-", sub, e0);
@@ -614,17 +595,18 @@ inline namespace kernel
{
if (xs.is() and car(xs).is())
{
- return make(static_cast(car(xs).as()));
+ return make(car(xs).as());
}
else
{
- throw invalid_application(intern("integer->char") | xs);
+ throw invalid_application(string_to_symbol("integer->char") | xs);
}
});
- library.define("number->string", [](auto&& xs)
+ library.define("number->string", [](let const& xs)
{
- return make(lexical_cast(car(xs)));
+ return make(lexical_cast(std::setbase(cdr(xs).is() ? cadr(xs).as() : 10),
+ car(xs)));
});
library.export_("number?");
@@ -851,7 +833,7 @@ inline namespace kernel
return make(car(xs).as());
default:
- throw invalid_application(intern("open-input-string") | xs);
+ throw invalid_application(string_to_symbol("open-input-string") | xs);
}
});
@@ -866,7 +848,7 @@ inline namespace kernel
return make(car(xs).as());
default:
- throw invalid_application(intern("open-output-string") | xs);
+ throw invalid_application(string_to_symbol("open-output-string") | xs);
}
});
@@ -875,11 +857,19 @@ inline namespace kernel
return make(car(xs).as().str());
});
- library.define("%read-char", [](let const& xs) -> value_type
+ library.define("get-ready?", [](let const& xs)
+ {
+ return static_cast(car(xs).as());
+ });
+
+ library.define("get-char", [](let const& xs) -> value_type
{
try
{
- return make(car(xs).as());
+ auto const g = car(xs).as().tellg();
+ let const c = make(get_codepoint(car(xs).as()));
+ car(xs).as().seekg(g);
+ return c;
}
catch (eof const&)
{
@@ -891,14 +881,11 @@ inline namespace kernel
}
});
- library.define("%peek-char", [](let const& xs) -> value_type
+ library.define("get-char!", [](let const& xs) -> value_type
{
try
{
- auto const g = car(xs).as().tellg();
- let const c = make(car(xs).as());
- car(xs).as().seekg(g);
- return c;
+ return make(get_codepoint(car(xs).as()));
}
catch (eof const&)
{
@@ -920,21 +907,21 @@ inline namespace kernel
return eof_object;
});
- library.define("read-ready?", [](let const& xs)
- {
- return static_cast(car(xs).as());
- });
-
- library.define("%read-string", [](let const& xs)
+ library.define("get-string!", [](let const& xs)
{
- switch (length(xs))
+ auto read_k = [](string & string, std::size_t k, std::istream & is)
{
- case 2:
- return make(cadr(xs).as(), static_cast(car(xs).as()));
+ for (std::size_t i = 0; i < k and is; ++i)
+ {
+ string.codepoints.emplace_back(get_codepoint(is));
+ }
+ };
- default:
- throw invalid_application(intern("read-string") | xs);
- }
+ let const s = make();
+
+ read_k(s.as(), car(xs).as(), cadr(xs).as());
+
+ return s;
});
library.define("put-char", [](let const& xs)
@@ -955,7 +942,7 @@ inline namespace kernel
case 4: // TODO
default:
- throw invalid_application(intern("write-string") | xs);
+ throw invalid_application(string_to_symbol("write-string") | xs);
}
return unspecified;
@@ -984,12 +971,12 @@ inline namespace kernel
library.export_("open-input-string");
library.export_("open-output-string");
library.export_("get-output-string");
- library.export_("%read-char");
- library.export_("%peek-char");
library.export_("eof-object?");
library.export_("eof-object");
- library.export_("read-ready?");
- library.export_("%read-string");
+ library.export_("get-ready?");
+ library.export_("get-char");
+ library.export_("get-char!");
+ library.export_("get-string!");
library.export_("put-char");
library.export_("put-string");
library.export_("%flush-output-port");
@@ -1025,74 +1012,54 @@ inline namespace kernel
library.define("make-string", [](let const& xs)
{
- switch (length(xs))
- {
- case 1:
- return make(static_cast(car(xs).as()), character());
-
- case 2:
- return make(static_cast(car(xs).as