2019-06-02 19:31:59 +03:00
|
|
|
(define blodwen-read-args (lambda (desc)
|
|
|
|
(case (vector-ref desc 0)
|
|
|
|
((0) '())
|
|
|
|
((1) (cons (vector-ref desc 2)
|
|
|
|
(blodwen-read-args (vector-ref desc 3)))))))
|
|
|
|
(define b+ (lambda (x y bits) (remainder (+ x y) (expt 2 bits))))
|
|
|
|
(define b- (lambda (x y bits) (remainder (- x y) (expt 2 bits))))
|
|
|
|
(define b* (lambda (x y bits) (remainder (* x y) (expt 2 bits))))
|
|
|
|
(define b/ (lambda (x y bits) (remainder (/ x y) (expt 2 bits))))
|
2019-07-09 00:46:20 +03:00
|
|
|
|
|
|
|
(define blodwen-shl (lambda (x y) (arithmetic-shift x y)))
|
|
|
|
(define blodwen-shr (lambda (x y) (arithmetic-shift x (- y))))
|
2020-01-31 13:47:34 +03:00
|
|
|
(define blodwen-and (lambda (x y) (bitwise-and x y)))
|
2020-01-31 19:40:18 +03:00
|
|
|
(define blodwen-or (lambda (x y) (bitwise-ior x y)))
|
2020-01-31 13:47:34 +03:00
|
|
|
(define blodwen-xor (lambda (x y) (bitwise-xor x y)))
|
2019-07-09 00:46:20 +03:00
|
|
|
|
2020-03-05 11:55:20 +03:00
|
|
|
(define cast-num
|
|
|
|
(lambda (x)
|
2019-06-02 19:31:59 +03:00
|
|
|
(if (number? x) x 0)))
|
|
|
|
(define destroy-prefix
|
|
|
|
(lambda (x)
|
2020-03-29 23:26:42 +03:00
|
|
|
(cond
|
|
|
|
((equal? x "") "")
|
|
|
|
((equal? (string-ref x 0) #\#) "")
|
|
|
|
(else x))))
|
2019-06-02 19:31:59 +03:00
|
|
|
(define cast-string-int
|
|
|
|
(lambda (x)
|
|
|
|
(floor (cast-num (string->number (destroy-prefix x))))))
|
|
|
|
(define cast-string-double
|
|
|
|
(lambda (x)
|
|
|
|
(cast-num (string->number (destroy-prefix x)))))
|
|
|
|
(define string-cons (lambda (x y) (string-append (string x) y)))
|
|
|
|
(define get-tag (lambda (x) (vector-ref x 0)))
|
|
|
|
(define string-reverse (lambda (x)
|
|
|
|
(list->string (reverse (string->list x)))))
|
2020-03-05 11:55:20 +03:00
|
|
|
(define (string-substr off len s)
|
2019-06-02 19:31:59 +03:00
|
|
|
(let* ((l (string-length s))
|
|
|
|
(b (max 0 off))
|
|
|
|
(x (max 0 len))
|
|
|
|
(end (min l (+ b x))))
|
|
|
|
(substring s b end)))
|
|
|
|
|
2020-03-05 11:55:20 +03:00
|
|
|
(define either-left
|
2019-06-02 19:31:59 +03:00
|
|
|
(lambda (x)
|
|
|
|
(vector 0 #f #f x)))
|
|
|
|
|
|
|
|
(define either-right
|
|
|
|
(lambda (x)
|
|
|
|
(vector 1 #f #f x)))
|
|
|
|
|
2019-07-05 19:24:15 +03:00
|
|
|
(define blodwen-error-quit
|
|
|
|
(lambda (msg)
|
|
|
|
(display msg)
|
Experimenting with a new FFI
Functions can be declared as %foreign with a list of calling
conventions, which a backend will work through until it finds one it can
understand. Currently implemented only in Chez backend. If this works
out, I'll implement it for Racket too, and remove the old primitive
functions.
There's a bit more boiler plate here than before, but it has the benefit
of being more extensible and portable between different back ends.
Some examples, pending proper documentation:
%foreign "C:puts,libc" "scheme:display"
putline : String -> PrimIO ()
%foreign "C:exp, libm.so.6, math.h"
fexp : Double -> Double
%foreign "C:initscr, ncurses_glue.so, ncurses.h"
prim_initscr : PrimIO ()
2019-09-02 19:10:48 +03:00
|
|
|
(newline)
|
2019-07-05 19:24:15 +03:00
|
|
|
(exit 1)))
|
|
|
|
|
2019-09-28 20:10:14 +03:00
|
|
|
;; Buffers
|
|
|
|
|
|
|
|
(define (blodwen-new-buffer size)
|
|
|
|
(make-bytevector size 0))
|
|
|
|
|
|
|
|
(define (blodwen-buffer-size buf)
|
|
|
|
(bytevector-length buf))
|
|
|
|
|
|
|
|
(define (blodwen-buffer-setbyte buf loc val)
|
|
|
|
(bytevector-u8-set! buf loc val))
|
|
|
|
|
|
|
|
(define (blodwen-buffer-getbyte buf loc)
|
|
|
|
(bytevector-u8-ref buf loc))
|
|
|
|
|
|
|
|
(define (blodwen-buffer-setint buf loc val)
|
2020-03-27 23:54:39 +03:00
|
|
|
(bytevector-s32-set! buf loc val (native-endianness)))
|
2019-09-28 20:10:14 +03:00
|
|
|
|
|
|
|
(define (blodwen-buffer-getint buf loc)
|
2020-03-27 23:54:39 +03:00
|
|
|
(bytevector-s32-ref buf loc (native-endianness)))
|
2019-09-28 20:10:14 +03:00
|
|
|
|
|
|
|
(define (blodwen-buffer-setdouble buf loc val)
|
|
|
|
(bytevector-ieee-double-set! buf loc val (native-endianness)))
|
|
|
|
|
|
|
|
(define (blodwen-buffer-getdouble buf loc)
|
|
|
|
(bytevector-ieee-double-ref buf loc (native-endianness)))
|
|
|
|
|
2020-01-30 21:27:21 +03:00
|
|
|
(define (blodwen-stringbytelen str)
|
|
|
|
(bytevector-length (string->utf8 str)))
|
|
|
|
|
2019-09-28 20:10:14 +03:00
|
|
|
(define (blodwen-buffer-setstring buf loc val)
|
|
|
|
(let* [(strvec (string->utf8 val))
|
|
|
|
(len (bytevector-length strvec))]
|
|
|
|
(bytevector-copy! strvec 0 buf loc len)))
|
|
|
|
|
|
|
|
(define (blodwen-buffer-getstring buf loc len)
|
|
|
|
(let [(newvec (make-bytevector len))]
|
|
|
|
(bytevector-copy! buf loc newvec 0 len)
|
|
|
|
(utf8->string newvec)))
|
|
|
|
|
2020-01-30 21:27:21 +03:00
|
|
|
(define (blodwen-buffer-copydata buf start len dest loc)
|
|
|
|
(bytevector-copy! buf start dest loc len))
|
|
|
|
|
2020-01-31 19:40:18 +03:00
|
|
|
(define (blodwen-readbuffer-bytes h buf loc max)
|
2019-09-28 20:33:46 +03:00
|
|
|
(with-handlers
|
|
|
|
([(lambda (x) #t) (lambda (exn) -1)])
|
|
|
|
(get-bytevector-n! h buf loc max)))
|
2019-09-28 20:10:14 +03:00
|
|
|
|
2020-01-31 19:40:18 +03:00
|
|
|
(define (blodwen-readbuffer h)
|
|
|
|
(with-handlers
|
|
|
|
([(lambda (x) #t) (lambda (exn) (make-bytevector 0))])
|
|
|
|
(get-bytevector-all h)))
|
|
|
|
|
2019-09-28 20:10:14 +03:00
|
|
|
(define (blodwen-writebuffer h buf loc max)
|
2019-09-28 20:33:46 +03:00
|
|
|
(with-handlers
|
|
|
|
([(lambda (x) #t) (lambda (exn) -1)])
|
|
|
|
(put-bytevector h buf loc max)))
|
2019-09-28 20:10:14 +03:00
|
|
|
|
2019-06-02 19:31:59 +03:00
|
|
|
;; Files : Much of the following adapted from idris-chez, thanks to Niklas
|
|
|
|
;; Larsson
|
|
|
|
|
2020-03-05 11:55:20 +03:00
|
|
|
;; All the file operations are implemented as primitives which return
|
2019-06-02 19:31:59 +03:00
|
|
|
;; Either Int x, where the Int is an error code
|
2019-09-28 20:10:14 +03:00
|
|
|
(define (blodwen-error-code x)
|
2020-03-05 11:55:20 +03:00
|
|
|
(cond
|
2019-09-28 20:10:14 +03:00
|
|
|
((eq? x (lookup-errno 'ENOENT)) 3)
|
|
|
|
((eq? x (lookup-errno 'EACCES)) 4)
|
|
|
|
((eq? x (lookup-errno 'EEXIST)) 5)
|
|
|
|
(else (+ x 256))))
|
2019-06-02 19:31:59 +03:00
|
|
|
|
|
|
|
;; If the file operation raises an error, catch it and return an appropriate
|
|
|
|
;; error code
|
|
|
|
(define (blodwen-file-op op)
|
2020-03-05 11:55:20 +03:00
|
|
|
(with-handlers
|
2019-09-28 20:10:14 +03:00
|
|
|
([exn:fail:filesystem:errno?
|
|
|
|
(lambda (exn) (either-left (blodwen-error-code
|
|
|
|
(car (exn:fail:filesystem:errno-errno exn)))))]
|
2020-03-05 11:55:20 +03:00
|
|
|
[exn:fail:filesystem?
|
2019-09-28 20:10:14 +03:00
|
|
|
(lambda (exn) (either-left 255))]
|
|
|
|
)
|
2019-06-02 19:31:59 +03:00
|
|
|
(either-right (op))))
|
|
|
|
|
|
|
|
(define (blodwen-putstring p s)
|
|
|
|
(if (port? p) (write-string p s) void)
|
|
|
|
0)
|
|
|
|
|
|
|
|
(define (blodwen-open file mode bin)
|
2019-09-28 20:10:14 +03:00
|
|
|
(define tc (if (= bin 1) #f (make-transcoder (utf-8-codec))))
|
|
|
|
(define bm (buffer-mode line))
|
2020-03-05 11:55:20 +03:00
|
|
|
(case mode
|
2019-09-28 20:10:14 +03:00
|
|
|
(("r") (open-file-input-port file (file-options) bm tc))
|
|
|
|
(("w") (open-file-output-port file (file-options no-fail) bm tc))
|
|
|
|
(("wx") (open-file-output-port file (file-options) bm tc))
|
|
|
|
(("a") (open-file-output-port file (file-options no-fail no-truncate) bm tc))
|
|
|
|
(("r+") (open-file-input/output-port file (file-options no-create) bm tc))
|
|
|
|
(("w+") (open-file-input/output-port file (file-options no-fail) bm tc))
|
|
|
|
(("w+x") (open-file-input/output-port file (file-options) bm tc))
|
|
|
|
(("a+") (open-file-input/output-port file (file-options no-fail no-truncate) bm tc))
|
|
|
|
(else (raise (make-i/o-error)))))
|
|
|
|
|
2019-06-02 19:31:59 +03:00
|
|
|
|
|
|
|
(define (blodwen-close-port p)
|
2020-03-05 11:55:20 +03:00
|
|
|
(cond
|
2019-06-02 19:31:59 +03:00
|
|
|
((input-port? p) (close-input-port p))
|
|
|
|
((output-port? p) (close-output-port p))))
|
|
|
|
|
|
|
|
(define (blodwen-get-line p)
|
|
|
|
(if (port? p)
|
|
|
|
(let ((str (read-line p)))
|
|
|
|
(if (eof-object? str)
|
|
|
|
""
|
|
|
|
(string-append str "\n")))
|
|
|
|
void))
|
|
|
|
|
2020-03-05 11:55:20 +03:00
|
|
|
(define (blodwen-get-char p)
|
|
|
|
(if (port? p)
|
|
|
|
(let ((char (read-char p)))
|
|
|
|
(if (eof-object? char)
|
|
|
|
#\nul
|
|
|
|
char))
|
|
|
|
void))
|
|
|
|
|
2019-06-02 19:31:59 +03:00
|
|
|
(define (blodwen-eof p)
|
|
|
|
(if (eof-object? (peek-char p))
|
|
|
|
1
|
|
|
|
0))
|
|
|
|
|
2020-02-01 21:43:28 +03:00
|
|
|
;; Directories
|
|
|
|
|
|
|
|
(define (blodwen-current-directory)
|
|
|
|
(path->string (current-directory)))
|
|
|
|
|
|
|
|
(define (blodwen-change-directory dir)
|
|
|
|
(if (directory-exists? dir)
|
|
|
|
(begin (current-directory dir) 1)
|
|
|
|
0))
|
|
|
|
|
|
|
|
(define (blodwen-create-directory dir)
|
|
|
|
(blodwen-file-op (lambda () (make-directory dir))))
|
|
|
|
|
2020-02-23 15:17:36 +03:00
|
|
|
; Scheme only gives a primitive for reading all the files in a directory,
|
|
|
|
; so this is faking the C interface!
|
|
|
|
(define (blodwen-open-directory dir)
|
|
|
|
(blodwen-file-op (lambda () (box (directory-list dir)))))
|
|
|
|
|
|
|
|
(define (blodwen-close-directory dir) '()) ; no-op, it's not really open
|
|
|
|
|
|
|
|
(define (blodwen-next-dir-entry dir)
|
|
|
|
(let [(dlist (unbox dir))]
|
|
|
|
(if (null? dlist)
|
|
|
|
(either-left 255)
|
|
|
|
(begin (set-box! dir (cdr dlist))
|
|
|
|
(either-right (path->string (car dlist)))))))
|
|
|
|
|
2019-06-02 19:31:59 +03:00
|
|
|
;; Threads
|
|
|
|
|
|
|
|
(define blodwen-thread-data (make-thread-cell #f))
|
|
|
|
|
|
|
|
(define (blodwen-thread p)
|
|
|
|
(thread (lambda () (p (vector 0)))))
|
|
|
|
|
|
|
|
(define (blodwen-get-thread-data)
|
|
|
|
(thread-cell-ref blodwen-thread-data))
|
|
|
|
|
|
|
|
(define (blodwen-set-thread-data a)
|
|
|
|
(thread-cell-set! blodwen-thread-data a))
|
|
|
|
|
|
|
|
(define (blodwen-mutex) (make-semaphore 1))
|
|
|
|
(define (blodwen-lock m) (semaphore-post m))
|
|
|
|
(define (blodwen-unlock m) (semaphore-wait m))
|
|
|
|
(define (blodwen-thisthread) (current-thread))
|
|
|
|
|
|
|
|
(define (blodwen-condition) (make-channel))
|
|
|
|
(define (blodwen-condition-wait c m)
|
|
|
|
(blodwen-unlock m) ;; consistency with interface for posix condition variables
|
|
|
|
(sync c)
|
|
|
|
(blodwen-lock m))
|
|
|
|
(define (blodwen-condition-wait-timeout c m t)
|
|
|
|
(blodwen-unlock m) ;; consistency with interface for posix condition variables
|
|
|
|
(sync/timeout t c)
|
|
|
|
(blodwen-lock m))
|
|
|
|
(define (blodwen-condition-signal c)
|
|
|
|
(channel-put c 'ready))
|
|
|
|
|
|
|
|
(define (blodwen-sleep s) (sleep s))
|
|
|
|
|
2019-07-09 00:46:20 +03:00
|
|
|
(define (blodwen-time) (current-seconds))
|
|
|
|
|
2019-06-02 19:31:59 +03:00
|
|
|
(define (blodwen-args)
|
|
|
|
(define (blodwen-build-args args)
|
|
|
|
(if (null? args)
|
|
|
|
(vector 0 '())
|
|
|
|
(vector 1 '() (car args) (blodwen-build-args (cdr args)))))
|
2020-03-05 11:55:20 +03:00
|
|
|
(blodwen-build-args
|
2019-06-02 19:31:59 +03:00
|
|
|
(cons (path->string (find-system-path 'run-file))
|
|
|
|
(vector->list (current-command-line-arguments)))))
|
2020-03-30 15:06:59 +03:00
|
|
|
|
|
|
|
(define (blodwen-system cmd)
|
|
|
|
(if (system cmd)
|
|
|
|
0
|
|
|
|
1))
|