[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Chicken-hackers] [PATCH 1/5] Generalize port directionality
From: |
Evan Hanson |
Subject: |
[Chicken-hackers] [PATCH 1/5] Generalize port directionality |
Date: |
Thu, 30 Jun 2016 20:09:45 +1200 |
Convert the port direction and closed flags from booleans to bitmasks,
to allow for multidirectional ports.
---
NEWS | 2 ++
chicken.h | 6 +++--
library.scm | 74 ++++++++++++++++++++++++++--------------------------
ports.scm | 14 +++++-----
posix-common.scm | 2 +-
posixunix.scm | 21 +++++++--------
posixwin.scm | 4 +--
runtime.c | 37 +++++---------------------
tcp.scm | 5 +---
tests/port-tests.scm | 29 ++++++++++++++++++++
types.db | 10 +++----
11 files changed, 103 insertions(+), 101 deletions(-)
diff --git a/NEWS b/NEWS
index 793c99a..fa8188c 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@
now return exact numbers where possible, so code relying on flonums
being returned may need to be changed if rational numbers do not
provide the desired performance.
+ - Port directionality has been generalized from a simple input/output
+ flag to a bitmap, to allow for multidirectional ports.
- Compiler
- Fixed an off by one allocation problem in generated C code for (list ...).
diff --git a/chicken.h b/chicken.h
index dc8cff0..dbb1e1b 100644
--- a/chicken.h
+++ b/chicken.h
@@ -673,8 +673,8 @@ static inline int isinf_ld (long double x)
#define C_BAD_ARGUMENT_TYPE_NO_BOOLEAN_ERROR 37
#define C_BAD_ARGUMENT_TYPE_NO_LOCATIVE_ERROR 38
#define C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR 39
-#define C_BAD_ARGUMENT_TYPE_NO_INPUT_PORT_ERROR 40
-#define C_BAD_ARGUMENT_TYPE_NO_OUTPUT_PORT_ERROR 41
+#define C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR 40
+/* unused 41 */
#define C_PORT_CLOSED_ERROR 42
#define C_ASCIIZ_REPRESENTATION_ERROR 43
#define C_MEMORY_VIOLATION_ERROR 44
@@ -1180,6 +1180,8 @@ typedef void (C_ccall *C_proc)(C_word, C_word *) C_noret;
#define C_vectorp(x) C_mk_bool(C_header_bits(x) == C_VECTOR_TYPE)
#define C_bytevectorp(x) C_mk_bool(C_header_bits(x) ==
C_BYTEVECTOR_TYPE)
#define C_portp(x) C_mk_bool(C_header_bits(x) == C_PORT_TYPE)
+#define C_input_portp(x) C_mk_bool(C_header_bits(x) == C_PORT_TYPE &&
C_block_item(x, 1) & 0x2)
+#define C_output_portp(x) C_mk_bool(C_header_bits(x) == C_PORT_TYPE &&
C_block_item(x, 1) & 0x4)
#define C_structurep(x) C_mk_bool(C_header_bits(x) ==
C_STRUCTURE_TYPE)
#define C_locativep(x) C_mk_bool(C_block_header(x) ==
C_LOCATIVE_TAG)
#define C_charp(x) C_mk_bool(((x) & C_IMMEDIATE_TYPE_BITS) ==
C_CHARACTER_BITS)
diff --git a/library.scm b/library.scm
index 20dd7bf..1c24ff1 100644
--- a/library.scm
+++ b/library.scm
@@ -2494,36 +2494,34 @@ EOF
;;; Ports:
-(define (port? x) (##core#inline "C_i_portp" x))
-
-(define-inline (%port? x)
+(define (port? x)
(and (##core#inline "C_blockp" x)
- (##core#inline "C_portp" x)) )
+ (##core#inline "C_portp" x)))
(define (input-port? x)
- (and (%port? x)
- (##sys#slot x 1) ) )
+ (and (##core#inline "C_blockp" x)
+ (##core#inline "C_input_portp" x)))
(define (output-port? x)
- (and (%port? x)
- (not (##sys#slot x 1)) ) )
+ (and (##core#inline "C_blockp" x)
+ (##core#inline "C_output_portp" x)))
(define (port-closed? p)
(##sys#check-port p 'port-closed?)
- (##sys#slot p 8))
+ (fx= (##sys#slot p 8) 0))
;;; Port layout:
;
; 0: FP (special)
-; 1: input/output (bool)
+; 1: direction (fixnum)
; 2: class (vector of procedures)
; 3: name (string)
; 4: row (fixnum)
; 5: col (fixnum)
; 6: EOF (bool)
; 7: type ('stream | 'custom | 'string | 'socket)
-; 8: closed (bool)
+; 8: closed (fixnum)
; 9: data
; 10-15: reserved, port class specific
;
@@ -2548,6 +2546,7 @@ EOF
(##sys#setislot port 4 1)
(##sys#setislot port 5 0)
(##sys#setslot port 7 type)
+ (##sys#setslot port 8 i/o)
port) )
;;; Stream ports:
@@ -2585,7 +2584,7 @@ EOF
(##core#inline "C_display_char" p c) )
(lambda (p s) ; write-string
(##core#inline "C_display_string" p s) )
- (lambda (p) ; close
+ (lambda (p d) ; close
(##core#inline "C_close_file" p)
(##sys#update-errno) )
(lambda (p) ; flush-output
@@ -2656,9 +2655,9 @@ EOF
(define ##sys#open-file-port (##core#primitive "C_open_file_port"))
-(define ##sys#standard-input (##sys#make-port #t ##sys#stream-port-class
"(stdin)" 'stream))
-(define ##sys#standard-output (##sys#make-port #f ##sys#stream-port-class
"(stdout)" 'stream))
-(define ##sys#standard-error (##sys#make-port #f ##sys#stream-port-class
"(stderr)" 'stream))
+(define ##sys#standard-input (##sys#make-port 1 ##sys#stream-port-class
"(stdin)" 'stream))
+(define ##sys#standard-output (##sys#make-port 2 ##sys#stream-port-class
"(stdout)" 'stream))
+(define ##sys#standard-error (##sys#make-port 2 ##sys#stream-port-class
"(stderr)" 'stream))
(##sys#open-file-port ##sys#standard-input 0 #f)
(##sys#open-file-port ##sys#standard-output 1 #f)
@@ -2666,13 +2665,13 @@ EOF
(define (##sys#check-input-port x open . loc)
(if (pair? loc)
- (##core#inline "C_i_check_port_2" x #t open (car loc))
- (##core#inline "C_i_check_port" x #t open) ) )
+ (##core#inline "C_i_check_port_2" x 1 open (car loc))
+ (##core#inline "C_i_check_port" x 1 open)))
(define (##sys#check-output-port x open . loc)
(if (pair? loc)
- (##core#inline "C_i_check_port_2" x #f open (car loc))
- (##core#inline "C_i_check_port" x #f open) ) )
+ (##core#inline "C_i_check_port_2" x 2 open (car loc))
+ (##core#inline "C_i_check_port" x 2 open)))
(define (##sys#check-port x . loc)
(if (pair? loc)
@@ -2753,24 +2752,25 @@ EOF
(##sys#error loc "cannot use append mode with input file")
(set! fmode "a") ) ]
[else (##sys#error loc "invalid file option" o)] ) ) )
- (let ([port (##sys#make-port inp ##sys#stream-port-class name 'stream)])
+ (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class name
'stream)))
(unless (##sys#open-file-port port name (##sys#string-append fmode
bmode))
(##sys#update-errno)
(##sys#signal-hook #:file-error loc (##sys#string-append "cannot
open file - " strerror) name) )
port) ) )
- (define (close port loc)
+ (define (close port inp loc)
(##sys#check-port port loc)
- ;; repeated closing is ignored
- (unless (##sys#slot port 8) ; closed?
- ((##sys#slot (##sys#slot port 2) 4) port) ; close
- (##sys#setislot port 8 #t) )
- (##core#undefined) )
+ ; repeated closing is ignored
+ (let* ((old-closed (##sys#slot port 8))
+ (new-closed (fxand old-closed (fxnot (if inp 1 2)))))
+ (unless (fx= new-closed old-closed) ; already closed?
+ (##sys#setislot port 8 new-closed)
+ ((##sys#slot (##sys#slot port 2) 4) port inp))))
(set! open-input-file (lambda (name . mode) (open name #t mode
'open-input-file)))
(set! open-output-file (lambda (name . mode) (open name #f mode
'open-output-file)))
- (set! close-input-port (lambda (port) (close port 'close-input-port)))
- (set! close-output-port (lambda (port) (close port 'close-output-port))) )
+ (set! close-input-port (lambda (port) (close port #t 'close-input-port)))
+ (set! close-output-port (lambda (port) (close port #f 'close-output-port))))
(define call-with-input-file
(let ([open-input-file open-input-file]
@@ -2857,12 +2857,12 @@ EOF
(##sys#setslot port 3 name) )
(define (##sys#port-line port)
- (and (##sys#slot port 1)
+ (and (fxodd? (##sys#slot port 1)) ; input port?
(##sys#slot port 4) ) )
(define (port-position #!optional (port ##sys#standard-input))
(##sys#check-port port 'port-position)
- (if (##sys#slot port 1)
+ (if (fxodd? (##sys#slot port 1)) ; input port?
(##sys#values (##sys#slot port 4) (##sys#slot port 5))
(##sys#error 'port-position "cannot compute position of port" port) ) )
@@ -4071,9 +4071,10 @@ EOF
(outstr port (##sys#lambda-info->string x))
(outchr port #\>) )
((##core#inline "C_portp" x)
- (if (##sys#slot x 1)
- (outstr port "#<input port \"")
- (outstr port "#<output port \"") )
+ (case (##sys#slot x 1)
+ ((1) (outstr port "#<input port \""))
+ ((2) (outstr port "#<output port \""))
+ (else (outstr port "#<port \"")))
(outstr port (##sys#slot x 3))
(outstr port "\">") )
((##core#inline "C_vectorp" x)
@@ -4295,14 +4296,14 @@ EOF
(define (open-input-string string)
(##sys#check-string string 'open-input-string)
- (let ([port (##sys#make-port #t ##sys#string-port-class "(string)" 'string)])
+ (let ((port (##sys#make-port 1 ##sys#string-port-class "(string)" 'string)))
(##sys#setislot port 11 (##core#inline "C_block_size" string))
(##sys#setislot port 10 0)
(##sys#setslot port 12 string)
port ) )
(define (open-output-string)
- (let ([port (##sys#make-port #f ##sys#string-port-class "(string)" 'string)])
+ (let ((port (##sys#make-port 2 ##sys#string-port-class "(string)" 'string)))
(##sys#setislot port 10 0)
(##sys#setislot port 11 output-string-initial-size)
(##sys#setslot port 12 (##sys#make-string output-string-initial-size))
@@ -4905,8 +4906,7 @@ EOF
((37) (apply ##sys#signal-hook #:type-error loc "bad argument type -
not a boolean" args))
((38) (apply ##sys#signal-hook #:type-error loc "bad argument type -
not a locative" args))
((39) (apply ##sys#signal-hook #:type-error loc "bad argument type -
not a port" args))
- ((40) (apply ##sys#signal-hook #:type-error loc "bad argument type -
not an input-port" args))
- ((41) (apply ##sys#signal-hook #:type-error loc "bad argument type -
not an output-port" args))
+ ((40) (apply ##sys#signal-hook #:type-error loc "bad argument type -
not a port of the correct type" args))
((42) (apply ##sys#signal-hook #:file-error loc "port already closed"
args))
((43) (apply ##sys#signal-hook #:type-error loc "cannot represent
string with NUL bytes as C string" args))
((44) (apply ##sys#signal-hook #:memory-error loc "segmentation
violation" args))
diff --git a/ports.scm b/ports.scm
index 1744c35..33390c4 100644
--- a/ports.scm
+++ b/ports.scm
@@ -254,9 +254,8 @@
last) ] ) ) )
#f ; write-char
#f ; write-string
- (lambda (p) ; close
- (close)
- (##sys#setislot p 8 #t) )
+ (lambda (p d) ; close
+ (close))
#f ; flush-output
(lambda (p) ; char-ready?
(ready?) )
@@ -264,7 +263,7 @@
read-line ; read-line
read-buffered))
(data (vector #f))
- (port (##sys#make-port #t class "(custom)" 'custom)) )
+ (port (##sys#make-port 1 class "(custom)" 'custom)))
(##sys#set-port-data! port data)
port) ) )
@@ -278,16 +277,15 @@
(write (string c)) )
(lambda (p s) ; write-string
(write s) )
- (lambda (p) ; close
- (close)
- (##sys#setislot p 8 #t) )
+ (lambda (p d) ; close
+ (close))
(lambda (p) ; flush-output
(when flush (flush)) )
#f ; char-ready?
#f ; read-string!
#f) ) ; read-line
(data (vector #f))
- (port (##sys#make-port #f class "(custom)" 'custom)) )
+ (port (##sys#make-port 2 class "(custom)" 'custom)))
(##sys#set-port-data! port data)
port) ) )
diff --git a/posix-common.scm b/posix-common.scm
index 991ac7d..4bb21fb 100644
--- a/posix-common.scm
+++ b/posix-common.scm
@@ -380,7 +380,7 @@ EOF
(define (check loc fd inp r)
(if (##sys#null-pointer? r)
(posix-error #:file-error loc "cannot open file" fd)
- (let ([port (##sys#make-port inp ##sys#stream-port-class "(fdport)"
'stream)])
+ (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class
"(fdport)" 'stream)))
(##core#inline "C_set_file_ptr" port r)
port) ) )
(set! open-input-file*
diff --git a/posixunix.scm b/posixunix.scm
index 3e25ff5..63cef98 100644
--- a/posixunix.scm
+++ b/posixunix.scm
@@ -662,7 +662,7 @@ EOF
(define (check loc cmd inp r)
(if (##sys#null-pointer? r)
(posix-error #:file-error loc "cannot open pipe" cmd)
- (let ([port (##sys#make-port inp ##sys#stream-port-class "(pipe)"
'stream)])
+ (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class
"(pipe)" 'stream)))
(##core#inline "C_set_file_ptr" port r)
port) ) )
(set! open-input-pipe
@@ -1122,12 +1122,10 @@ EOF
(lambda () ; char-ready?
(or (fx< bufpos buflen)
(ready?)) )
- (lambda () ; close
- ; Do nothing when closed already
- (unless (##sys#slot this-port 8)
- (when (fx< (##core#inline "C_close" fd) 0)
- (posix-error #:file-error loc "cannot close" fd nam) )
- (on-close) ) )
+ (lambda () ; close
+ (when (fx< (##core#inline "C_close" fd) 0)
+ (posix-error #:file-error loc "cannot close" fd nam))
+ (on-close))
(lambda () ; peek-char
(when (fx>= bufpos buflen)
(fetch))
@@ -1233,11 +1231,10 @@ EOF
(make-output-port
(lambda (str) ; write-string
(store str) )
- (lambda () ; close - do nothing when closed already
- (unless (##sys#slot this-port 8)
- (when (fx< (##core#inline "C_close" fd) 0)
- (posix-error #:file-error loc "cannot close" fd nam) )
- (on-close) ) )
+ (lambda () ; close
+ (when (fx< (##core#inline "C_close" fd) 0)
+ (posix-error #:file-error loc "cannot close" fd nam))
+ (on-close))
(lambda () ; flush
(store #f) ) )] )
(set-port-name! this-port nam)
diff --git a/posixwin.scm b/posixwin.scm
index 59776b2..9ad9eff 100644
--- a/posixwin.scm
+++ b/posixwin.scm
@@ -882,7 +882,7 @@ EOF
(##sys#update-errno)
(if (##sys#null-pointer? r)
(##sys#signal-hook #:file-error "cannot open pipe" cmd)
- (let ([port (##sys#make-port inp ##sys#stream-port-class "(pipe)"
'stream)])
+ (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class
"(pipe)" 'stream)))
(##core#inline "C_set_file_ptr" port r)
port) ) )
(set! open-input-pipe
@@ -1072,7 +1072,7 @@ EOF
(##sys#update-errno)
(if (##sys#null-pointer? r)
(##sys#signal-hook #:file-error "cannot open file" fd)
- (let ([port (##sys#make-port inp ##sys#stream-port-class "(fdport)"
'stream)])
+ (let ((port (##sys#make-port (if inp 1 2) ##sys#stream-port-class
"(fdport)" 'stream)))
(##core#inline "C_set_file_ptr" port r)
port) ) )
(set! open-input-file*
diff --git a/runtime.c b/runtime.c
index a7282f8..c7a35cb 100644
--- a/runtime.c
+++ b/runtime.c
@@ -1882,13 +1882,8 @@ void barf(int code, char *loc, ...)
c = 1;
break;
- case C_BAD_ARGUMENT_TYPE_NO_INPUT_PORT_ERROR:
- msg = C_text("bad argument type - not an input-port");
- c = 1;
- break;
-
- case C_BAD_ARGUMENT_TYPE_NO_OUTPUT_PORT_ERROR:
- msg = C_text("bad argument type - not an output-port");
+ case C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR:
+ msg = C_text("bad argument type - not a port of the correct type");
c = 1;
break;
@@ -7062,39 +7057,21 @@ C_regparm C_word C_fcall C_i_check_list_2(C_word x,
C_word loc)
}
-C_regparm C_word C_fcall C_i_check_port_2(C_word x, C_word input, C_word open,
C_word loc)
+C_regparm C_word C_fcall C_i_check_port_2(C_word x, C_word dir, C_word open,
C_word loc)
{
- int inp;
if(C_immediatep(x) || C_header_bits(x) != C_PORT_TYPE) {
error_location = loc;
barf(C_BAD_ARGUMENT_TYPE_NO_PORT_ERROR, NULL, x);
}
- inp = C_block_item(x, 1) == C_SCHEME_TRUE; /* slot #1: I/O flag */
-
- switch(input) {
- case C_SCHEME_TRUE:
- if(!inp) {
- error_location = loc;
- barf(C_BAD_ARGUMENT_TYPE_NO_INPUT_PORT_ERROR, NULL, x);
- }
-
- break;
-
- case C_SCHEME_FALSE:
- if(inp) {
- error_location = loc;
- barf(C_BAD_ARGUMENT_TYPE_NO_OUTPUT_PORT_ERROR, NULL, x);
- }
-
- break;
-
- /* any other value: omit direction check */
+ if((C_block_item(x, 1) & dir) != dir) { /* slot #1: I/O direction mask
*/
+ error_location = loc;
+ barf(C_BAD_ARGUMENT_TYPE_PORT_DIRECTION_ERROR, NULL, x);
}
if(open == C_SCHEME_TRUE) {
- if(C_block_item(x, 8) != C_SCHEME_FALSE) { /* slot #8: closed flag */
+ if(C_block_item(x, 8) == C_FIXNUM_BIT) { /* slot #8: closed mask */
error_location = loc;
barf(C_PORT_CLOSED_ERROR, NULL, x);
}
diff --git a/tcp.scm b/tcp.scm
index 5f5e519..bdb90ca 100644
--- a/tcp.scm
+++ b/tcp.scm
@@ -657,10 +657,7 @@ EOF
(define (tcp-abandon-port p)
(##sys#check-open-port p 'tcp-abandon-port)
- (##sys#setislot
- (##sys#port-data p)
- (if (##sys#slot p 1) 1 2)
- #t) )
+ (##sys#setislot (##sys#port-data p) (##sys#slot p 1) #t))
(define (tcp-listener-fileno l)
(##sys#check-structure l 'tcp-listener 'tcp-listener-fileno)
diff --git a/tests/port-tests.scm b/tests/port-tests.scm
index 78565e3..49b8e13 100644
--- a/tests/port-tests.scm
+++ b/tests/port-tests.scm
@@ -95,6 +95,35 @@ EOF
(lambda (in) (read-char in)))
(get-output-string out))))
+;; direction-specific port closure
+
+(let* ((n 0)
+ (p (make-input-port (constantly #\a)
+ (constantly #t)
+ (lambda () (set! n (add1 n))))))
+ (close-output-port p)
+ (assert (not (port-closed? p)))
+ (assert (= n 0))
+ (close-input-port p)
+ (assert (port-closed? p))
+ (assert (= n 1))
+ (close-input-port p)
+ (assert (port-closed? p))
+ (assert (= n 1)))
+
+(let* ((n 0)
+ (p (make-output-port (lambda () (display #\a))
+ (lambda () (set! n (add1 n))))))
+ (close-input-port p)
+ (assert (not (port-closed? p)))
+ (assert (= n 0))
+ (close-output-port p)
+ (assert (port-closed? p))
+ (assert (= n 1))
+ (close-output-port p)
+ (assert (port-closed? p))
+ (assert (= n 1)))
+
;; fill buffers
(with-input-from-file "compiler.scm" read-string)
diff --git a/types.db b/types.db
index d2b2b0b..dc070f7 100644
--- a/types.db
+++ b/types.db
@@ -1251,7 +1251,7 @@
(port? (#(procedure #:pure #:predicate (or input-port output-port)) port? (*)
boolean))
(port-closed? (#(procedure #:clean #:enforce) port-closed? (port) boolean)
- ((port) (##sys#slot #(1) '8)))
+ ((port) (eq? (##sys#slot #(1) '8) '0)))
(print (procedure print (#!rest *) undefined))
(print-call-chain (#(procedure #:clean #:enforce) print-call-chain (#!optional
output-port fixnum * string) undefined))
@@ -1403,13 +1403,13 @@
(##sys#check-input-port
(#(procedure #:clean #:enforce) ##sys#check-input-port (input-port *
#!optional *) *)
- ((* *) (##core#inline "C_i_check_port" #(1) '#t #(2)))
- ((* * *) (##core#inline "C_i_check_port_2" #(1) '#t #(2) #(3))))
+ ((* *) (##core#inline "C_i_check_port" #(1) '1 #(2)))
+ ((* * *) (##core#inline "C_i_check_port_2" #(1) '1 #(2) #(3))))
(##sys#check-output-port
(#(procedure #:clean #:enforce) ##sys#check-output-port (output-port *
#!optional *) *)
- ((* *) (##core#inline "C_i_check_port" #(1) '#f #(2)))
- ((* * *) (##core#inline "C_i_check_port_2" #(1) '#f #(2) #(3))))
+ ((* *) (##core#inline "C_i_check_port" #(1) '2 #(2)))
+ ((* * *) (##core#inline "C_i_check_port_2" #(1) '2 #(2) #(3))))
(##sys#check-open-port
(#(procedure #:clean #:enforce) ##sys#check-open-port ((or input-port
output-port) #!optional *) *)
--
2.1.4
- [Chicken-hackers] [PATCH 0/5][5] Generalize port directionality and add basic refinement types, Evan Hanson, 2016/06/30
- [Chicken-hackers] [PATCH 2/5] Add input-port-open? and output-port-open? procedures, Evan Hanson, 2016/06/30
- [Chicken-hackers] [PATCH 5/5] Add new `make-bidirectional-port` procedure to ports unit, Evan Hanson, 2016/06/30
- [Chicken-hackers] [PATCH 3/5] Add basic refinement types, Evan Hanson, 2016/06/30
- [Chicken-hackers] [PATCH 1/5] Generalize port directionality,
Evan Hanson <=
- [Chicken-hackers] [PATCH 4/5] Add scrutinizer test suite, Evan Hanson, 2016/06/30
- Re: [Chicken-hackers] [PATCH 4/5] Add scrutinizer test suite, felix . winkelmann, 2016/06/30
- [Chicken-hackers] [PATCH] Nicer port direction error messages, Evan Hanson, 2016/06/30