123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- (define-module (hurd-cl-compat)
- ;; Common Lisp functions, syntax and variables
- #:export (in-package defvar defconstant
- defgeneric defun
- defmethod defmacro
- defclass
- setf
- t
- progn
- (eval-when/common-lisp . eval-when)
- (case/common-lisp . case)
- (reduce/common-lisp . reduce)
- (concatenate/common-lisp . concatenate)
- mapcar
- flet
- nil
- declare
- loop
- boole
- multiple-value-bind
- destructuring-bind
- check-type
- ;; Some predicates
- typep
- ;; Common Lisp bitwise functions (also see #:re-export)
- boole-1
- boole-2
- boole-andc1
- boole-andc2
- boole-c1
- boole-c2
- boole-clr
- boole-nor
- boole-orc1
- boole-orc2
- boole-set
- ;; List manipulation
- pushnew
- remove-if
- ;; Hash table operations
- gethash
- ;; Conditions
- warning style-warning define-condition
- ;; Not Common Lisp, but still useful
- define-report
- syntax-map syntax-car
- syntax-cdr syntax-cadr
- list-syntax->syntax-list
- loop*
- case/scheme) ; <-- XXX case/common-lisp should suffice
- ;; Predicates and comparison operators?
- #:re-export ((null? . null)
- (zero? . zerop)
- (number? . numberp)
- (symbol? . symbolp)
- (string? . stringp)
- (char? . charp)
- (eq? . eq)
- (eqv? . eql)
- (positive? . plusp) ; > 0
- ;; CL has equal and equalp,
- ;; where (equal 3 3.0) but not (equalp 3 3.0).
- ;; Let's silently use the latter behaviour and
- ;; hope nothhing notices. Likewise for eql.
- (equal? . equal)
- (equal? . equalp)
- ;; Bitwise operations
- (bitwise-ior . boole-ior)
- (bitwise-and . boole-and)
- (bitwise-xor . boole-xor)
- ;; Hash-Table operations
- (rnrs:make-eqv-hashtable . make-hashtable))
- #:replace (defmacro
- (eval-when/common-lisp . eval-when)
- (case/common-lisp . case)
- (concatenate/common-lisp . concatenate)
- reduce)
- #:use-module ((rnrs base) #:select (assert))
- #:use-module (oop goops)
- #:use-module (srfi srfi-1)
- ;; Procedural interface to (rnrs conditions)
- #:use-module ((srfi srfi-35) #:prefix srfi:)
- #:use-module ((rnrs hashtables) #:prefix rnrs:)
- #:use-module (rnrs arithmetic fixnums)
- #:use-module (rnrs arithmetic bitwise)
- #:use-module (ice-9 receive)
- #:use-module (rnrs conditions))
- ;; Common Lisp -- Scheme compatibility,
- ;; fudging over many details.
- ;; XXX recognise foreign-enum, foreign-type, ...
- (define-syntax typep
- (lambda (s)
- (syntax-case s (quote integer fixnum character string)
- ((_ object 'integer) #'(integer? object))
- ((_ object 'fixnum) #'(fixnum? object))
- ((_ object 'character) #'(character? object))
- ((_ object 'string) #'(string? object))
- (_ #'(XXX-implement #{perhaps a hash table for clos goops!}#)))))
- ;; Hash tables
- (define gethash
- (let ((v (cons #nil #nil)))
- ;; ^ not seen, merely an unique object to determine the hash table
- ;; does not have a certain key!
- (make-procedure-with-setter
- (lambda* (key hash-table #:optional (default #nil))
- (receive (result)
- (rnrs:hashtable-ref hash-table v)
- (if (eq? result v)
- (values default #nil)
- (values result #true))))
- (case-lambda
- ((key hash-table new-value)
- (hash-table-set! hash-table key new-value)
- (values))
- ((key hash-table default new-value)
- (hash-table-set! hash-table key new-value)
- (values))))))
- ;; Boolean. See
- ;; https://www.cs.utexas.edu/users/moore/acl2/manuals/current/manual/index-seo.php/ACL2____BOOLE_42
- (define (boole-1 x y)
- (assert (exact-integer? x))
- (assert (exact-integer? y))
- x)
- (define (boole-2 x y)
- (assert (exact-integer? x))
- (assert (exact-integer? y))
- x)
- (define (boole-andc2 x y)
- (bitwise-and x (bitwise-not y)))
- (define (boole-andc1 x y)
- (bitwise-and (bitwise-not x) y))
- (define (boole-c1 x y)
- (assert (exact-integer? x))
- (assert (exact-integer? y))
- (bitwise-not x))
- (define (boole-c2 x y)
- (assert (exact-integer? x))
- (assert (exact-integer? y))
- (bitwise-not y))
- (define (boole-clr x y)
- (assert (exact-integer? x))
- (assert (exact-integer? y))
- 0)
- (define (boole-set x y)
- (assert (exact-integer? x))
- (assert (exact-integer? y))
- -1)
- (define (boole-nor x y)
- (bitwise-not (bitwise-ior x y)))
- (define (boole-orc1 x y)
- (bitwise-ior (bitwise-not x) y))
- (define (boole-orc2 x y)
- (bitwise-ior x (bitwise-not y)))
- (define-syntax-rule (pushnew item var)
- (let ((old var)
- (val item))
- (if (memq val old)
- old
- (begin (set! var (cons item old))
- old))))
- (define* (remove-if test sequence)
- (if (vector? sequence)
- (list->vector (remove-if test (vector->list sequence)))
- (filter (negate test) sequence)))
- ;; Warning: syntax cannot (currently) be re-exported!
- ;; If you try, you'll end up with "Wrong type to apply: #<syntax-transformer case/scheme>".
- (define nil #nil)
- (define* (reduce/common-lisp proc ls #:key initial-value)
- (reduce proc initial-value ls))
- (define (concatenate/common-lisp type . stuff)
- (case type
- ((string) (apply string-append stuff))))
- (define-syntax declare
- (syntax-rules (type fixnum ignore)
- ((_ (type fixnum x ...))
- (begin
- (assert (fixnum? x))
- ...))
- ((_ (ignore stuff))
- (begin))))
- (define-syntax type-exp-predicate
- (lambda (s)
- (syntax-case s (and not null symbol)
- ((_ symbol) #'symbol?)
- ((_ (and x y))
- #'(lambda (z) (and ((type-exp-predicate x) z)
- ((type-exp-predicate y) z))))
- ((_ (not x))
- #'(lambda (z) (not ((type-exp-predicate x) z))))
- ((_ null) null?)
- ;; XXX why won't ((_ symbol) #'symbol?) work?
- ((_ rest) (eq? (syntax->datum #'rest) 'symbol)
- #'(lambda (x)
- (or (symbol? x)
- ;; Common Lisp symbols starting with : are mapped to Scheme keyword objects.
- (keyword? x))))
- ;; XXX likewise
- ((_ rest) (eq? (syntax->datum #'rest) 'null)
- #'null?))))
- (define-syntax-rule (check-type var type-exp)
- (assert ((type-exp-predicate type-exp) var)))
- (define-syntax eval-when/common-lisp
- (lambda (s)
- (define (eval-when-cl->scheme s)
- (syntax-case s (compile load eval expand)
- (#:compile-toplevel #'compile)
- (compile #'compile)
- (#:load-toplevel #'load)
- (load #'load)
- (#:execute #'eval)
- (eval #'eval)
- (expand #'expand)))
- (syntax-case s ()
- ((_ x exp exp* ...)
- #`(eval-when
- #,(map eval-when-cl->scheme
- (list-syntax->syntax-list #'x))
- exp exp* ...)))))
- (define-syntax case/common-lisp
- (syntax-rules (otherwise)
- ((_ what (otherwise stuff ...)) (begin stuff ...))
- ((_ what (x y))
- ;; XXX what does Common Lisp prescribe
- ;; in case there is no match?
- (case what
- ((x) y)))
- ((_ what (x y) . rest)
- (let ((save what))
- (if (eq? save 'x)
- y
- (case/common-lisp save . rest))))))
- ;; TODO
- (define (boole x y z)
- 0 ; <-- due to reasons, needs to be removed later
- #;(error "todo, implement!/4" x y))
- (define boole-ior 'todo)
- (define boole-and 'todo)
- (define-syntax setf
- (syntax-rules ()
- ((_ var value)
- (set! var value))
- ((_ var value var* value* . rest)
- (begin
- (set! var value)
- (setf var* value* . rest)))))
- (define-syntax-rule (progn x x* ...)
- (begin x x* ...))
- (define-syntax-rule (flet ((proc args exp) ...)
- exp^ exp^* ...)
- (let ((proc (lambda args exp)) ...)
- exp^ exp^* ...))
- (define t #t)
- (define-syntax loop*
- (syntax-rules ()
- ((_ (((x ...) #:in x^) . etc) #:do . rest)
- (for-each
- (lambda (obj)
- (apply (lambda (x ...)
- (loop* etc #:do . rest)) obj))
- x^))
- ((_ ((x #:in x^) . etc) #:do . rest)
- (for-each
- (lambda (x)
- (loop* etc #:do . rest))
- x^))
- ((_ ((i #:from a #:below b))
- #:collect exp)
- (let ((from a) (to/exclusive b))
- (let loop ((i from))
- (if (< i to/exclusive)
- (cons exp (loop (1+ i)))
- #nil))))
- ((_ () #:do . rest)
- (begin . rest))
- ((_ ((x #:in x^)) #:sum exp)
- (let loop ((total 0) (todo x^))
- (if (null? todo)
- total
- (loop (+ total (let ((x (car todo))) exp))
- (cdr todo)))))
- ((_ #:until stop?
- #:collect expression)
- (let loop ()
- (if stop?
- '()
- (let ((e expression))
- (cons e (loop))))))
- ((_ #:until stop?
- #:do stuff
- #:finally (#:return tail-position))
- (let loop ()
- (if stop?
- tail-position
- (loop))))))
- (define-syntax loop
- (syntax-rules (for in do collect from below while until finally return)
- ((_ for i from a below b collect exp)
- (loop* ((i #:from a #:below b)) #:collect exp))
- ((_ for x in list do stuff)
- (loop* ((x #:in list)) #:do stuff))
- ((_ until stop? collect stuff)
- (loop* #:until stop? #:collect stuff))
- ((_ until stop? do stuff finally (return tail-position))
- (loop* #:until stop? #:do stuff #:finally (#:return tail-position)))))
- ;; We ignore the variable / function
- ;; distinction.
- (define-syntax defvar
- (syntax-rules ()
- ((_ name)
- (define name))
- ((_ name value)
- (define name value))
- ((_ name value documentation)
- (define name value))))
- (define-syntax defconstant
- (syntax-rules ()
- ((_ name value)
- (define-syntax name (identifier-syntax value)))
- ((_ name value doc)
- (define-syntax name (identifier-syntax value)))))
- (define (syntax-cadr s)
- "Like cadr, but for syntax"
- (syntax-case s ()
- ((_ . (x . y)) #'x)))
- (define (syntax-car s)
- "Like car, but for syntax"
- (syntax-case s ()
- ((x . y) #'x)))
- (define (syntax-cdr s)
- "Like cdr, but for syntax"
- (syntax-case s ()
- ((x . y) #'y)))
- (define (syntax-map proc s)
- "Like map, but for syntax"
- (syntax-case s ()
- (() #'())
- ((x . rest) (cons (proc #'x) (syntax-map proc #'rest)))))
- ;; Dotted lists are allowed, in which case the component
- ;; after the dot is preserved. (But currently only if
- ;; what's after the dot, is an identifier, to avoid silently
- ;; introducing bugs.)
- (define (list-syntax->syntax-list s)
- (syntax-case s ()
- (() '())
- ((x . rest) (cons #'x (list-syntax->syntax-list #'rest)))
- (x (identifier? #'x) #'x)))
- (define (syntax->maybe-keyword s)
- (let ((d (syntax->datum s)))
- (if (keyword? d)
- d
- s)))
- (define-syntax-rule (defgeneric name (arg ...) . extra)
- (define-generic name))
- (define-syntax destructuring-bind
- (lambda (s)
- (syntax-case s ()
- ((_ () exp exp* exp** ...)
- #'(apply (lambda () exp* exp** ...) exp))
- ((_ rest exp exp* exp** ...)
- (identifier? #'rest)
- #'(let ((rest exp)) exp* exp** ...))
- ((_ (x . rest) exp exp* exp** ...)
- (identifier? #'x)
- #'(let* ((args exp))
- (destructuring-bind rest (cdr args) exp* exp** ...))))))
- (define-syntax-rule (multiple-value-bind args exp exp* ...)
- (receive args exp exp* ...))
- ;; Specialises in the first argument
- (eval-when (load compile eval)
- (define (cl->schemy-lambda*-list syntax-list)
- (syntax-case syntax-list (&key &optional &rest &body)
- (() #'())
- ((&key . tail)
- #`(#:key . #,(cl->schemy-lambda*-list #'tail)))
- ((&optional . tail)
- #`(#:optional . #,(cl->schemy-lambda*-list #'tail)))
- ((&rest r)
- #`(#:rest r))
- ;; XXX this is used in defmacro forms sometimes
- ;; instead of &rest. Does it mean the same thing?
- ((&body r)
- #`(#:rest r))
- ((something . tail)
- #`(something . #,(cl->schemy-lambda*-list #'tail)))
- (rest (identifier? #'rest) #'rest))))
- (define-syntax defun
- (lambda (s)
- (syntax-case s ()
- ((_ name args exp exp* ...)
- (with-syntax ((binders (cl->schemy-lambda*-list #'args)))
- #'(define* (name . binders)
- exp exp* ...))))))
- ;; Guile's (oop goops) does not support keyword argument methods.
- ;; Emulate it with rest arguments. (defmethod)
- (define (split-keyword-arguments argument-list)
- "Split @var{argument-list} into a syntax list of positional arguments
- and a syntax list of keyword arguments."
- (syntax-case argument-list (&key &rest &optional &body)
- (() (values #'() #'()))
- ((&key . stuff) (values #'() argument-list))
- ((&rest . stuff) (values #'() argument-list))
- ((&body . stuff) (values #'() argument-list))
- ((x . more)
- (receive (positional keywordial)
- (split-keyword-arguments #'more)
- (values #`(x . #,positional)
- keywordial)))))
- (define-syntax defmethod
- (lambda (s)
- (syntax-case s (setf)
- ((_ (setf accessor) . rest)
- #'(defmethod (setter accessor) . rest))
- ;; XXX these aren't exact matches to CLOS object system.
- ;; 1. only the most specific around-method should be called.
- ;; 3. the after methods should be called from least specific
- ;; to most specific.
- ((_ name #:after args . rest)
- #'(defmethod name args
- (next-method)
- . rest))
- ((_ name #:before args . rest)
- #'(defmethod name args
- (begin . rest)
- (next-method)))
- ((_ name #:around args . rest)
- #'(defmethod name args . rest))
- ((_ name ((first (eql obj)) . rest) exp exp* ...)
- ;; XXX for some reason including eql in the literal
- ;; list won't work
- (eq? 'eql (syntax->datum #'eql))
- #'(define-method (name first . rest)
- (if (eq? first obj)
- (begin exp exp* ...)
- (next-method))))
- ((_ name arguments exp exp* ...)
- (receive (positional keywordial)
- (split-keyword-arguments #'arguments)
- (syntax-case keywordial ()
- (()
- ;; No keyword arguments --> trivial
- #`(define-method (name . arguments) exp exp* ...))
- ((x . y)
- ;; Some keyword arguments --> rest argument
- (with-syntax ((binders (cl->schemy-lambda*-list keywordial)))
- #`(define-method (name #,@positional . rest*)
- (apply (lambda* binders exp exp* ...)
- rest*))))))))))
- ;; Like defmacro, but with define instead of define-syntax.
- ;; Also don't eat the first component.
- (define-syntax defnotmacro
- (lambda (s)
- (syntax-case s ()
- ((_ name kw-args exp exp* ...)
- (with-syntax ((binders (cl->schemy-lambda*-list #'kw-args)))
- #`(define (name s*)
- (apply (lambda* binders exp exp* ...)
- ;; XXX maybe too many arguments are converted
- (map syntax->maybe-keyword
- (list-syntax->syntax-list s*)))))))))
- (define-syntax defmacro
- (lambda (s)
- (syntax-case s ()
- ((_ name kw-args exp exp* ...)
- (with-syntax ((binders (cl->schemy-lambda*-list #'kw-args)))
- #`(define-syntax name
- (lambda (s*)
- (defnotmacro proc kw-args exp exp* ...)
- (syntax-case s* ()
- ((_ . rest) (proc #'rest))))))))))
- (define (mapcar proc . lists)
- (if (any null? lists)
- #nil
- (let* ((heads (map car lists))
- (tails (map cdr lists))
- (first (apply proc heads)))
- (cons first (apply mapcar proc tails)))))
- (defnotmacro clos-field-syntax->goops (ptr &key
- initform
- initarg accessor
- reader
- documentation)
- #`(#,ptr #:init-keyword #,initarg
- #,@(if accessor #`(#:accessor #,accessor) #'())
- #,@(if initform #`(#:init-form #,initform) #'())
- #,@(if reader #`(#:getter #,reader) #'())
- #:documentation #,documentation))
- (define-syntax defclass
- (lambda (s)
- (syntax-case s ()
- ((_ name supers
- fields
- . unsupported-cl-stuff)
- #`(define-class name supers
- #,@(syntax-map clos-field-syntax->goops #'fields))))))
- ;; Conditions
- (define-generic report)
- (define-generic make-cl-condition)
- (define-syntax-rule (define-report ((condition &type) stream) exp exp* ...)
- (define-method (report condition stream)
- (if ((condition-predicate &type) condition)
- (begin exp exp* ...)
- (next-method))))
- (defnotmacro define-cl-condition-field-accessors (type name &key
- initarg
- initform
- accessor
- reader
- documentation)
- #`(begin
- ;; TODO other fields
- #,@(if reader
- #`((define (reader c)
- (assert (srfi:condition-has-type? c #,type))
- (srfi:condition-ref c '#,name)))
- #'())))
- (define-syntax cl->srfi-initargs
- (lambda (s)
- ;; A list ((field-A . #:the-initarg) ...),
- ;; where FWIW field-A is a syntax (it will be quoted,
- ;; not bound to a variable.)
- (define (cl-field->cl-field-names+initargs cl)
- (syntax-case cl ()
- ((field-name . rest)
- (let loop ((rest #'rest))
- (syntax-case rest ()
- ((#:initform form . rest)
- (format (current-warning-port)
- "initforms for conditions are unsupported (field: ~a)~%"
- (syntax->datum #'field-name))
- (loop #'rest))
- ((#:accessor form . rest)
- (format (current-warning-port)
- "accessors for conditions are unsupported (field: ~a)~%"
- (syntax->datum #'field-name))
- (loop #'rest))
- ((#:initarg ia . rest)
- (keyword? (syntax->datum #'ia))
- #`((field-name . #,(datum->syntax #'ia
- (keyword->symbol
- (syntax->datum #'ia))))
- . #,(loop #'rest)))
- ((other r . rest)
- (memq (syntax->datum #'rest) '(#:reader #:documentation))
- (loop #'rest)))))))
- (define (names+initargs->argument-names names)
- (syntax-map syntax-cdr names))
- (define (names+initargs->srfi-list names+initargs)
- (syntax-case names+initargs ()
- (() #'())
- ;; XXX verify this #:initarg for?
- (((name . initarg) . rest)
- #`(name ,initarg . #,(names+initargs->srfi-list #'rest)))))
- (syntax-case s ()
- ((_ fields arguments)
- (let* ((names+initargs
- (syntax-map cl-field->cl-field-names+initargs #'fields))
- (argument-names (names+initargs->argument-names names+initargs))
- (srfi-list (names+initargs->srfi-list names+initargs)))
- #`(apply (lambda* (#:key . #,argument-names)
- `#,srfi-list)
- arguments))))))
- (define-syntax srfi-ify-supertype
- (lambda (s)
- ;; TODO: adding error to the literal
- ;; list doesn't work.
- (syntax-case s ()
- ((_ name)
- (case (syntax->datum #'name)
- ((error) #'&error)
- (else #'name))))))
- (define-syntax define-condition
- (lambda (s)
- (syntax-case s ()
- ((_ type (supertype)
- ((field-key . r) ...)
- . rest)
- #`(begin
- (define type
- (srfi:make-condition-type 'type
- (srfi-ify-supertype supertype)
- '(field-key ...)))
- ;; TODO investigate
- ;; (define-cl-condition-field-accessors field-key . r)
- ;; ...
- (define-method (make-cl-condition typ . rest*)
- (if (eq? typ 'type)
- (apply srfi:make-condition typ
- (cl->srfi-initargs ((field-key . r) ...) rest*))
- (next-method)))
- ;; TODO: rest argument
- )))))
- (define warning &warning)
- (define-condition style-warning (warning) ())
- ;; Some mess to figure out later.
- #|
- (import (system foreign) int)
- ;; First, define some basic syntax forms.
- ;; TODO: ignored forms
- (define-syntax-rule (in-package ???)
- (begin))
- (define-syntax parse-ctype
- (syntax-rules (:int)
- ((_ :int) int)))
- (define-syntax defctype (name type docstring)
- (define name (parse-ctype type)))
- (define-syntax-rule (defcfun name proc type)
- (define type
- (let ((cfun (dynamic-func name (dynamic-link))))
- (pointer->procedure
- |#
|