888 lines
23 KiB
Scheme
888 lines
23 KiB
Scheme
(define-library (scheme base)
|
|
(import (picrin base)
|
|
(only (picrin math)
|
|
abs
|
|
expt
|
|
floor/
|
|
truncate/
|
|
floor
|
|
ceiling
|
|
truncate
|
|
round
|
|
sqrt
|
|
nan?
|
|
infinite?)
|
|
(picrin macro)
|
|
(scheme file))
|
|
|
|
;; 4.1.2. Literal expressions
|
|
|
|
(export quote)
|
|
|
|
;; 4.1.4. Procedures
|
|
|
|
(export lambda)
|
|
|
|
;; 4.1.5. Conditionals
|
|
|
|
(export if)
|
|
|
|
;; 4.1.6. Assignments
|
|
|
|
(export set!)
|
|
|
|
;; 4.1.7. Inclusion
|
|
|
|
(define-macro include
|
|
(letrec ((read-file
|
|
(lambda (filename)
|
|
(call-with-port (open-input-file filename)
|
|
(lambda (port)
|
|
(let loop ((expr (read port)) (exprs '()))
|
|
(if (eof-object? expr)
|
|
(reverse exprs)
|
|
(loop (read port) (cons expr exprs)))))))))
|
|
(er-macro-transformer
|
|
(lambda (form rename compare)
|
|
(let ((filenames (cdr form)))
|
|
(let ((exprs (apply append (map read-file filenames))))
|
|
`(,(rename 'begin) ,@exprs)))))))
|
|
|
|
(export include)
|
|
|
|
;; 4.2.1. Conditionals
|
|
|
|
(export cond
|
|
case
|
|
else
|
|
=>
|
|
and
|
|
or
|
|
when
|
|
unless)
|
|
|
|
;; 4.2.2. Binding constructs
|
|
|
|
(export let
|
|
let*
|
|
letrec
|
|
letrec*
|
|
let-values
|
|
let*-values)
|
|
|
|
;; 4.2.3. Sequencing
|
|
|
|
(export begin)
|
|
|
|
;; 4.2.4. Iteration
|
|
|
|
(export do)
|
|
|
|
;; 4.2.6. Dynamic bindings
|
|
|
|
(export make-parameter
|
|
parameterize)
|
|
|
|
;; 4.2.7. Exception handling
|
|
|
|
(define-syntax (guard-aux reraise . clauses)
|
|
(letrec
|
|
((else?
|
|
(lambda (clause)
|
|
(and (list? clause) (equal? #'else (car clause)))))
|
|
(=>?
|
|
(lambda (clause)
|
|
(and (list? clause) (= (length clause) 3) (equal? #'=> (list-ref clause 1))))))
|
|
(if (null? clauses)
|
|
reraise
|
|
(let ((clause (car clauses))
|
|
(rest (cdr clauses)))
|
|
(cond
|
|
((else? clause)
|
|
#`(begin #,@(cdr clause)))
|
|
((=>? clause)
|
|
#`(let ((tmp #,(list-ref clause 0)))
|
|
(if tmp
|
|
(#,(list-ref clause 2) tmp)
|
|
(guard-aux #,reraise #,@rest))))
|
|
((= (length clause) 1)
|
|
#`(or #,(car clause) (guard-aux #,reraise #,@rest)))
|
|
(else
|
|
#`(if #,(car clause)
|
|
(begin #,@(cdr clause))
|
|
(guard-aux #,reraise #,@rest))))))))
|
|
|
|
(define-syntax (guard formal . body)
|
|
(let ((var (car formal))
|
|
(clauses (cdr formal)))
|
|
#`((call/cc
|
|
(lambda (guard-k)
|
|
(with-exception-handler
|
|
(lambda (condition)
|
|
((call/cc
|
|
(lambda (handler-k)
|
|
(guard-k
|
|
(lambda ()
|
|
(let ((#,var condition))
|
|
(guard-aux
|
|
(handler-k
|
|
(lambda ()
|
|
(raise-continuable condition)))
|
|
#,@clauses))))))))
|
|
(lambda ()
|
|
(call-with-values
|
|
(lambda () #,@body)
|
|
(lambda args
|
|
(guard-k
|
|
(lambda ()
|
|
(apply values args))))))))))))
|
|
|
|
(export guard)
|
|
|
|
;; 4.2.8. Quasiquotation
|
|
|
|
(export quasiquote
|
|
unquote
|
|
unquote-splicing)
|
|
|
|
;; 4.3.1. Binding constructs for syntactic keywords
|
|
|
|
(export let-syntax
|
|
letrec-syntax)
|
|
|
|
;; 4.3.2 Pattern language
|
|
|
|
(define (succ n)
|
|
(+ n 1))
|
|
|
|
(define (pred n)
|
|
(if (= n 0)
|
|
0
|
|
(- n 1)))
|
|
|
|
(define (every? args)
|
|
(if (null? args)
|
|
#t
|
|
(if (car args)
|
|
(every? (cdr args))
|
|
#f)))
|
|
|
|
(define (filter f list)
|
|
(if (null? list)
|
|
'()
|
|
(if (f (car list))
|
|
(cons (car list)
|
|
(filter f (cdr list)))
|
|
(filter f (cdr list)))))
|
|
|
|
(define (take-tail n list)
|
|
(let drop ((n (- (length list) n)) (list list))
|
|
(if (= n 0)
|
|
list
|
|
(drop (- n 1) (cdr list)))))
|
|
|
|
(define (drop-tail n list)
|
|
(let take ((n (- (length list) n)) (list list))
|
|
(if (= n 0)
|
|
'()
|
|
(cons (car list) (take (- n 1) (cdr list))))))
|
|
|
|
(define (map-keys f assoc)
|
|
(map (lambda (s) `(,(f (car s)) . ,(cdr s))) assoc))
|
|
|
|
(define (map-values f assoc)
|
|
(map (lambda (s) `(,(car s) . ,(f (cdr s)))) assoc))
|
|
|
|
;; TODO
|
|
;; - placeholder
|
|
;; - vector
|
|
;; - (... template) pattern
|
|
|
|
;; p ::= constant
|
|
;; | var
|
|
;; | (p ... . p) (in input pattern, tail p should be a proper list)
|
|
;; | (p . p)
|
|
|
|
(define (compile ellipsis literals rules)
|
|
|
|
(define (constant? obj)
|
|
(and (not (pair? obj))
|
|
(not (identifier? obj))))
|
|
|
|
(define (literal? obj)
|
|
(and (identifier? obj)
|
|
(memq obj literals)))
|
|
|
|
(define (many? pat)
|
|
(and (pair? pat)
|
|
(pair? (cdr pat))
|
|
(identifier? (cadr pat))
|
|
(identifier=? (cadr pat) ellipsis)))
|
|
|
|
(define (pattern-validator pat) ; pattern -> validator
|
|
(letrec
|
|
((pattern-validator
|
|
(lambda (pat form)
|
|
(cond
|
|
((constant? pat)
|
|
#`(equal? '#,pat #,form))
|
|
((literal? pat)
|
|
#`(and (identifier? #,form) (identifier=? #'#,pat #,form)))
|
|
((identifier? pat)
|
|
#t)
|
|
((many? pat)
|
|
(let ((head #`(drop-tail #,(length (cddr pat)) #,form))
|
|
(tail #`(take-tail #,(length (cddr pat)) #,form)))
|
|
#`(and (list? #,form)
|
|
(>= (length #,form) #,(length (cddr pat)))
|
|
(every? (map (lambda (#,'it) #,(pattern-validator (car pat) 'it)) #,head))
|
|
#,(pattern-validator (cddr pat) tail))))
|
|
((pair? pat)
|
|
#`(and (pair? #,form)
|
|
#,(pattern-validator (car pat) #`(car #,form))
|
|
#,(pattern-validator (cdr pat) #`(cdr #,form))))
|
|
(else
|
|
#f)))))
|
|
(pattern-validator pat 'it)))
|
|
|
|
(define (pattern-variables pat) ; pattern -> (freevar)
|
|
(cond
|
|
((constant? pat)
|
|
'())
|
|
((literal? pat)
|
|
'())
|
|
((identifier? pat)
|
|
`(,pat))
|
|
((many? pat)
|
|
(append (pattern-variables (car pat))
|
|
(pattern-variables (cddr pat))))
|
|
((pair? pat)
|
|
(append (pattern-variables (car pat))
|
|
(pattern-variables (cdr pat))))))
|
|
|
|
(define (pattern-levels pat) ; pattern -> ((var * int))
|
|
(cond
|
|
((constant? pat)
|
|
'())
|
|
((literal? pat)
|
|
'())
|
|
((identifier? pat)
|
|
`((,pat . 0)))
|
|
((many? pat)
|
|
(append (map-values succ (pattern-levels (car pat)))
|
|
(pattern-levels (cddr pat))))
|
|
((pair? pat)
|
|
(append (pattern-levels (car pat))
|
|
(pattern-levels (cdr pat))))))
|
|
|
|
(define (pattern-selectors pat) ; pattern -> ((var * selector))
|
|
(letrec
|
|
((pattern-selectors
|
|
(lambda (pat form)
|
|
(cond
|
|
((constant? pat)
|
|
'())
|
|
((literal? pat)
|
|
'())
|
|
((identifier? pat)
|
|
`((,pat . ,form)))
|
|
((many? pat)
|
|
(let ((head #`(drop-tail #,(length (cddr pat)) #,form))
|
|
(tail #`(take-tail #,(length (cddr pat)) #,form)))
|
|
(let ((envs (pattern-selectors (car pat) 'it)))
|
|
(append
|
|
(map-values (lambda (s) #`(map (lambda (#,'it) #,s) #,head)) envs)
|
|
(pattern-selectors (cddr pat) tail)))))
|
|
((pair? pat)
|
|
(append (pattern-selectors (car pat) #`(car #,form))
|
|
(pattern-selectors (cdr pat) #`(cdr #,form))))))))
|
|
(pattern-selectors pat 'it)))
|
|
|
|
(define (template-representation pat levels selectors)
|
|
(cond
|
|
((constant? pat)
|
|
pat)
|
|
((identifier? pat)
|
|
(let ((it (assq pat levels)))
|
|
(if it
|
|
(if (= 0 (cdr it))
|
|
(cdr (assq pat selectors))
|
|
(error "unmatched pattern variable level" pat))
|
|
#`(#,'rename '#,pat))))
|
|
((many? pat)
|
|
(letrec*
|
|
((inner-pat
|
|
(car pat))
|
|
(inner-levels
|
|
(map (lambda (s) `(,(car s) . ,(pred (cdr s)))) levels))
|
|
(inner-freevars
|
|
(filter (lambda (v) (assq v levels)) (pattern-variables inner-pat)))
|
|
(inner-vars
|
|
;; select only vars declared with ellipsis
|
|
(filter (lambda (v) (> (cdr (assq v levels)) 0)) inner-freevars))
|
|
(inner-tmps
|
|
(map (lambda (v) #'it) inner-vars))
|
|
(inner-selectors
|
|
;; first env '(map cons ...)' shadows second env 'selectors'
|
|
(append (map cons inner-vars inner-tmps) selectors))
|
|
(inner-rep
|
|
(template-representation inner-pat inner-levels inner-selectors))
|
|
(sorted-selectors
|
|
(map (lambda (v) (assq v selectors)) inner-vars))
|
|
(list-of-selectors
|
|
;; ((a . xs) (b . ys) (c . zs)) -> (xs ys zs)
|
|
(map cdr sorted-selectors)))
|
|
(let ((rep1 #`(map (lambda #,inner-tmps #,inner-rep) #,@list-of-selectors))
|
|
(rep2 (template-representation (cddr pat) levels selectors)))
|
|
#`(append #,rep1 #,rep2))))
|
|
((pair? pat)
|
|
#`(cons #,(template-representation (car pat) levels selectors)
|
|
#,(template-representation (cdr pat) levels selectors)))))
|
|
|
|
(define (compile-rule pattern template)
|
|
(let ((levels
|
|
(pattern-levels pattern))
|
|
(selectors
|
|
(pattern-selectors pattern)))
|
|
(template-representation template levels selectors)))
|
|
|
|
(define (compile-rules rules)
|
|
(if (null? rules)
|
|
#`(error "unmatch")
|
|
(let ((pattern (car (car rules)))
|
|
(template (cadr (car rules))))
|
|
#`(if #,(pattern-validator pattern)
|
|
#,(compile-rule pattern template)
|
|
#,(compile-rules (cdr rules))))))
|
|
|
|
(define (compile rules)
|
|
#`(call-with-current-environment
|
|
(lambda (env)
|
|
(letrec
|
|
((#,'rename (let ((wm (make-ephemeron)))
|
|
(lambda (x)
|
|
(let ((y (wm x)))
|
|
(if y
|
|
(cdr y)
|
|
(let ((id (make-identifier x env)))
|
|
(wm x id)
|
|
id)))))))
|
|
(lambda #,'it
|
|
#,(compile-rules rules))))))
|
|
|
|
(let ((rules (map-keys cdr rules))) ; TODO: check pattern head is a variable
|
|
(compile rules)))
|
|
|
|
(define-syntax (syntax-rules . args)
|
|
(if (list? (car args))
|
|
#`(syntax-rules ... #,@args)
|
|
(let ((ellipsis (car args))
|
|
(literals (car (cdr args)))
|
|
(rules (cdr (cdr args))))
|
|
(compile ellipsis literals rules))))
|
|
|
|
(define-syntax (define-auxiliary-syntax var)
|
|
#`(define-macro #,var
|
|
(lambda _
|
|
(error "invalid use of auxiliary syntax" '#,var))))
|
|
|
|
(define-auxiliary-syntax _)
|
|
(define-auxiliary-syntax ...)
|
|
|
|
(export syntax-rules
|
|
_
|
|
...)
|
|
|
|
;; 4.3.3. Signaling errors in macro transformers
|
|
|
|
(export syntax-error)
|
|
|
|
;; 5.3. Variable definitions
|
|
|
|
(export define)
|
|
|
|
;; 5.3.3. Multiple-value definitions
|
|
|
|
(export define-values)
|
|
|
|
;; 5.4. Syntax definitions
|
|
|
|
(export define-syntax)
|
|
|
|
;; 5.5 Record-type definitions
|
|
|
|
(define (make-record-type name)
|
|
(vector name)) ; TODO
|
|
|
|
(define-syntax (define-record-constructor type field-alist name . fields)
|
|
(let ((record #'record))
|
|
#`(define (#,name . #,fields)
|
|
(let ((#,record (make-record #,type (make-vector #,(length field-alist)))))
|
|
#,@(map
|
|
(lambda (field)
|
|
#`(vector-set! (record-datum #,record) #,(cdr (assq field field-alist)) #,field))
|
|
fields)
|
|
#,record))))
|
|
|
|
(define-syntax (define-record-predicate type name)
|
|
#`(define (#,name obj)
|
|
(and (record? obj)
|
|
(eq? (record-type obj) #,type))))
|
|
|
|
(define-syntax (define-record-accessor pred field-alist field accessor)
|
|
#`(define (#,accessor record)
|
|
(if (#,pred record)
|
|
(vector-ref (record-datum record) #,(cdr (assq field field-alist)))
|
|
(error (string-append (symbol->string '#,accessor) ": wrong record type") record))))
|
|
|
|
(define-syntax (define-record-modifier pred field-alist field modifier)
|
|
#`(define (#,modifier record val)
|
|
(if (#,pred record)
|
|
(vector-set! (record-datum record) #,(cdr (assq field field-alist)) val)
|
|
(error (string-append (symbol->string '#,modifier) ": wrong record type") record))))
|
|
|
|
(define-syntax (define-record-field pred field-alist field accessor . modifier-opt)
|
|
(if (null? modifier-opt)
|
|
#`(define-record-accessor #,pred #,field-alist #,field #,accessor)
|
|
#`(begin
|
|
(define-record-accessor #,pred #,field-alist #,field #,accessor)
|
|
(define-record-modifier #,pred #,field-alist #,field #,(car modifier-opt)))))
|
|
|
|
(define-syntax (define-record-type name ctor pred . fields)
|
|
(let ((field-alist (let lp ((fds fields) (idx 0) (alst '()))
|
|
(if (null? fds)
|
|
alst
|
|
(lp (cdr fds)
|
|
(+ idx 1)
|
|
(cons
|
|
(cons (if (pair? (car fds)) (car (car fds)) (car fds)) idx)
|
|
alst))))))
|
|
#`(begin
|
|
(define #,name (make-record-type '#,name))
|
|
(define-record-constructor #,name #,field-alist #,@ctor)
|
|
(define-record-predicate #,name #,pred)
|
|
#,@(map (lambda (field) #`(define-record-field #,pred #,field-alist #,@field)) fields))))
|
|
|
|
(export define-record-type)
|
|
|
|
;; 6.1. Equivalence predicates
|
|
|
|
(export eq?
|
|
eqv?
|
|
equal?)
|
|
|
|
;; 6.2. Numbers
|
|
|
|
(define complex? number?)
|
|
(define real? number?)
|
|
(define rational? number?)
|
|
(define (integer? o)
|
|
(or (exact? o)
|
|
(and (inexact? o)
|
|
(not (nan? o))
|
|
(not (infinite? o))
|
|
(= o (floor o)))))
|
|
|
|
(define (exact-integer? x)
|
|
(and (exact? x)
|
|
(integer? x)))
|
|
|
|
(define (zero? x)
|
|
(= x 0))
|
|
|
|
(define (positive? x)
|
|
(> x 0))
|
|
|
|
(define (negative? x)
|
|
(< x 0))
|
|
|
|
(define (even? x)
|
|
(= x (* (exact (floor (/ x 2))) 2)))
|
|
|
|
(define (odd? x)
|
|
(not (even? x)))
|
|
|
|
(define (min . args)
|
|
(define (min a b)
|
|
(if (< a b) a b))
|
|
(let loop ((args args) (acc +inf.0) (exactp #t))
|
|
(if (null? args)
|
|
(if exactp acc (inexact acc))
|
|
(loop (cdr args) (min (car args) acc) (and (exact? (car args)) exactp)))))
|
|
|
|
(define (max . args)
|
|
(define (max a b)
|
|
(if (> a b) a b))
|
|
(let loop ((args args) (acc -inf.0) (exactp #t))
|
|
(if (null? args)
|
|
(if exactp acc (inexact acc))
|
|
(loop (cdr args) (max (car args) acc) (and (exact? (car args)) exactp)))))
|
|
|
|
(define (floor-quotient i j)
|
|
(call-with-values (lambda () (floor/ i j))
|
|
(lambda (q r)
|
|
q)))
|
|
|
|
(define (floor-remainder i j)
|
|
(call-with-values (lambda () (floor/ i j))
|
|
(lambda (q r)
|
|
r)))
|
|
|
|
(define (truncate-quotient i j)
|
|
(call-with-values (lambda () (truncate/ i j))
|
|
(lambda (q r)
|
|
q)))
|
|
|
|
(define (truncate-remainder i j)
|
|
(call-with-values (lambda () (truncate/ i j))
|
|
(lambda (q r)
|
|
r)))
|
|
|
|
(define (gcd . args)
|
|
(define (gcd i j)
|
|
(cond
|
|
((> i j) (gcd j i))
|
|
((< i 0) (gcd (- i) j))
|
|
((> i 0) (gcd (truncate-remainder j i) i))
|
|
(else j)))
|
|
(let loop ((args args) (acc 0))
|
|
(if (null? args)
|
|
acc
|
|
(loop (cdr args)
|
|
(gcd acc (car args))))))
|
|
|
|
(define (lcm . args)
|
|
(define (lcm i j)
|
|
(/ (abs (* i j)) (gcd i j)))
|
|
(let loop ((args args) (acc 1))
|
|
(if (null? args)
|
|
acc
|
|
(loop (cdr args)
|
|
(lcm acc (car args))))))
|
|
|
|
(define (square x)
|
|
(* x x))
|
|
|
|
(define (exact-integer-sqrt k)
|
|
(let ((s (exact (floor (sqrt k)))))
|
|
(values s (- k (square s)))))
|
|
|
|
(export number?
|
|
complex?
|
|
real?
|
|
rational?
|
|
integer?
|
|
exact?
|
|
inexact?
|
|
exact-integer?
|
|
exact
|
|
inexact
|
|
=
|
|
<
|
|
>
|
|
<=
|
|
>=
|
|
zero?
|
|
positive?
|
|
negative?
|
|
odd?
|
|
even?
|
|
min
|
|
max
|
|
+
|
|
-
|
|
*
|
|
/
|
|
abs
|
|
floor-quotient
|
|
floor-remainder
|
|
floor/
|
|
truncate-quotient
|
|
truncate-remainder
|
|
truncate/
|
|
(rename truncate-quotient quotient)
|
|
(rename truncate-remainder remainder)
|
|
(rename floor-remainder modulo)
|
|
gcd
|
|
lcm
|
|
floor
|
|
ceiling
|
|
truncate
|
|
round
|
|
exact-integer-sqrt
|
|
square
|
|
expt
|
|
number->string
|
|
string->number)
|
|
|
|
;; 6.3. Booleans
|
|
|
|
(export boolean?
|
|
boolean=?
|
|
not)
|
|
|
|
;; 6.4 Pairs and lists
|
|
|
|
(export pair?
|
|
cons
|
|
car
|
|
cdr
|
|
set-car!
|
|
set-cdr!
|
|
null?
|
|
caar
|
|
cadr
|
|
cdar
|
|
cddr
|
|
list?
|
|
make-list
|
|
list
|
|
length
|
|
append
|
|
reverse
|
|
list-tail
|
|
list-ref
|
|
list-set!
|
|
list-copy
|
|
memq
|
|
memv
|
|
member
|
|
assq
|
|
assv
|
|
assoc)
|
|
|
|
;; 6.5. Symbols
|
|
|
|
(export symbol?
|
|
symbol=?
|
|
symbol->string
|
|
string->symbol)
|
|
|
|
;; 6.6. Characters
|
|
|
|
(export char?
|
|
char->integer
|
|
integer->char
|
|
char=?
|
|
char<?
|
|
char>?
|
|
char<=?
|
|
char>=?)
|
|
|
|
;; 6.7. Strings
|
|
|
|
(export string?
|
|
string
|
|
make-string
|
|
string-length
|
|
string-ref
|
|
string-set!
|
|
string-copy
|
|
string-copy!
|
|
string-append
|
|
(rename string-copy substring)
|
|
string-fill!
|
|
string->list
|
|
list->string
|
|
string=?
|
|
string<?
|
|
string>?
|
|
string<=?
|
|
string>=?)
|
|
|
|
;; 6.8. Vectors
|
|
|
|
(export vector?
|
|
vector
|
|
make-vector
|
|
vector-length
|
|
vector-ref
|
|
vector-set!
|
|
vector-copy!
|
|
vector-copy
|
|
vector-append
|
|
vector-fill!
|
|
list->vector
|
|
vector->list
|
|
string->vector
|
|
vector->string)
|
|
|
|
;; 6.9. Bytevectors
|
|
|
|
(define (utf8->string v . opts)
|
|
(let ((start (if (pair? opts) (car opts) 0))
|
|
(end (if (>= (length opts) 2)
|
|
(cadr opts)
|
|
(bytevector-length v))))
|
|
(list->string (map integer->char (bytevector->list v start end)))))
|
|
|
|
(define (string->utf8 s . opts)
|
|
(let ((start (if (pair? opts) (car opts) 0))
|
|
(end (if (>= (length opts) 2)
|
|
(cadr opts)
|
|
(string-length s))))
|
|
(list->bytevector (map char->integer (string->list s start end)))))
|
|
|
|
(export bytevector?
|
|
bytevector
|
|
make-bytevector
|
|
bytevector-length
|
|
bytevector-u8-ref
|
|
bytevector-u8-set!
|
|
bytevector-copy
|
|
bytevector-copy!
|
|
bytevector-append
|
|
bytevector->list
|
|
list->bytevector
|
|
utf8->string
|
|
string->utf8)
|
|
|
|
;; 6.10. Control features
|
|
|
|
(export procedure?
|
|
apply
|
|
map
|
|
for-each
|
|
string-map
|
|
string-for-each
|
|
vector-map
|
|
vector-for-each
|
|
call-with-current-continuation
|
|
call/cc
|
|
dynamic-wind
|
|
values
|
|
call-with-values)
|
|
|
|
;; 6.11. Exceptions
|
|
|
|
(define (read-error? obj)
|
|
(and (error-object? obj)
|
|
(eq? (error-object-type obj) 'read)))
|
|
|
|
(define (file-error? obj)
|
|
(and (error-object? obj)
|
|
(eq? (error-object-type obj) 'file)))
|
|
|
|
(export with-exception-handler
|
|
raise
|
|
raise-continuable
|
|
error
|
|
error-object?
|
|
error-object-message
|
|
error-object-irritants
|
|
read-error?
|
|
file-error?)
|
|
|
|
;; 6.13. Input and output
|
|
|
|
(define (input-port-open? port)
|
|
(and (input-port? port) (port-open? port)))
|
|
|
|
(define (output-port-open? port)
|
|
(and (output-port? port) (port-open? port)))
|
|
|
|
(define (call-with-port port handler)
|
|
(let ((res (handler port)))
|
|
(close-port port)
|
|
res))
|
|
|
|
(define (open-input-string str)
|
|
(open-input-bytevector (list->bytevector (map char->integer (string->list str)))))
|
|
|
|
(define (open-output-string)
|
|
(open-output-bytevector))
|
|
|
|
(define (get-output-string port)
|
|
(list->string (map integer->char (bytevector->list (get-output-bytevector port)))))
|
|
|
|
(define (read-char . opt)
|
|
(let ((b (apply read-u8 opt)))
|
|
(if (eof-object? b)
|
|
b
|
|
(integer->char b))))
|
|
|
|
(define (peek-char . opt)
|
|
(let ((b (apply peek-u8 opt)))
|
|
(if (eof-object? b)
|
|
b
|
|
(integer->char b))))
|
|
|
|
(define (char-ready? . opt)
|
|
(apply u8-ready? opt))
|
|
|
|
(define (newline . opt)
|
|
(apply write-u8 (char->integer #\newline) opt))
|
|
|
|
(define (write-char c . opt)
|
|
(apply write-u8 (char->integer c) opt))
|
|
|
|
(define (write-string s . opt)
|
|
(apply write-bytevector (list->bytevector (map char->integer (string->list s))) opt))
|
|
|
|
(define (read-line . opt)
|
|
(if (eof-object? (apply peek-char opt))
|
|
(eof-object)
|
|
(let loop ((str "") (c (apply read-char opt)))
|
|
(if (or (eof-object? c)
|
|
(char=? c #\newline))
|
|
str
|
|
(loop (string-append str (string c)) (apply read-char opt))))))
|
|
|
|
(define (read-string k . opt)
|
|
(if (eof-object? (apply peek-char opt))
|
|
(eof-object)
|
|
(let loop ((k k) (str "") (c (apply read-char opt)))
|
|
(if (or (eof-object? c)
|
|
(zero? k))
|
|
str
|
|
(loop (- k 1) (string-append str (string c)) (apply read-char opt))))))
|
|
|
|
(export current-input-port
|
|
current-output-port
|
|
current-error-port
|
|
|
|
call-with-port
|
|
|
|
port?
|
|
input-port?
|
|
output-port?
|
|
(rename port? textual-port?)
|
|
(rename port? binary-port?)
|
|
|
|
input-port-open?
|
|
output-port-open?
|
|
close-port
|
|
(rename close-port close-input-port)
|
|
(rename close-port close-output-port)
|
|
|
|
open-input-string
|
|
open-output-string
|
|
get-output-string
|
|
open-input-bytevector
|
|
open-output-bytevector
|
|
get-output-bytevector
|
|
|
|
eof-object?
|
|
eof-object
|
|
|
|
read-char
|
|
peek-char
|
|
char-ready?
|
|
read-line
|
|
read-string
|
|
|
|
read-u8
|
|
peek-u8
|
|
u8-ready?
|
|
read-bytevector
|
|
read-bytevector!
|
|
|
|
newline
|
|
write-char
|
|
write-string
|
|
write-u8
|
|
write-bytevector
|
|
flush-output-port)
|
|
|
|
(export features))
|