
Also, remove signatures from primref. Now the record is reverted to the one in the main ChezScheme version. And lift most of the code outside the cptypes function. original commit: 8f4384e0a5e1e9b383f65e097d6088b30d8069e5
271 lines
12 KiB
Scheme
271 lines
12 KiB
Scheme
;;; priminfo.ss
|
|
;;; Copyright 1984-2017 Cisco Systems, Inc.
|
|
;;;
|
|
;;; 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.
|
|
|
|
(module priminfo (priminfo-unprefixed priminfo-libraries priminfo-mask priminfo-arity primvec get-priminfo
|
|
priminfo-arguments-type priminfo-rest-type priminfo-last-type priminfo-result-type)
|
|
(define-record-type priminfo
|
|
(nongenerative)
|
|
(sealed #t)
|
|
(fields unprefixed libraries mask arity arguments-type rest-type last-type result-type))
|
|
|
|
(define make-parameterlike box)
|
|
|
|
(define prim-db (make-eq-hashtable))
|
|
|
|
(define primvec
|
|
(lambda ()
|
|
(hashtable-keys prim-db)))
|
|
|
|
(define get-priminfo
|
|
(lambda (name)
|
|
(or (eq-hashtable-ref prim-db name #f)
|
|
($oops #f "unknown primitive ~s" name))))
|
|
|
|
(define (mask-result-type mask)
|
|
(cond
|
|
[(all-set? (prim-mask abort-op) mask)
|
|
'bottom]
|
|
[(all-set? (prim-mask boolean-valued) mask)
|
|
'boolean]
|
|
[(all-set? (prim-mask true) mask)
|
|
'true]
|
|
[(all-set? (prim-mask single-valued) mask)
|
|
'ptr]
|
|
[else #f]))
|
|
|
|
(define (signature-boolean? signature*)
|
|
(and (not (null? signature*))
|
|
(andmap (lambda (sig)
|
|
(let ([out (cdr sig)])
|
|
(and (fx= (length out) 1)
|
|
(or (eq? (car out) 'boolean)
|
|
(eq? (car out) 'bottom)))))
|
|
signature*)))
|
|
|
|
(define (signature-true? signature*)
|
|
(and (not (null? signature*))
|
|
(andmap (lambda (sig)
|
|
(let ([out (cdr sig)])
|
|
(and (pair? out)
|
|
(null? (cdr out))
|
|
(or (pair? (car out))
|
|
(not (or (eq? (car out) 'ptr)
|
|
(eq? (car out) 'sub-ptr)
|
|
(eq? (car out) 'boolean)
|
|
(let ([name (symbol->string (car out))])
|
|
(and (>= (string-length name) 6)
|
|
(string=? (substring name 0 6) "maybe-")))))))))
|
|
signature*)))
|
|
|
|
(define (signature-result-arity signature*)
|
|
(cond
|
|
[(null? signature*) 'unknown]
|
|
[(andmap (lambda (sig)
|
|
(let ([out (cdr sig)])
|
|
(and (pair? out) (null? (cdr out)))))
|
|
signature*)
|
|
;; Note that a `(bottom)` result is treated as single-valued,
|
|
;; which is ok in the sense that the aborting operation will
|
|
;; produce a single value when it (never) returns.
|
|
'single]
|
|
[else 'multiple]))
|
|
|
|
(define (signature-result-type signature*)
|
|
(cond
|
|
[(null? signature*) #f] ; no signature
|
|
[(and (fx= (length signature*) 2)
|
|
(let ([sig0 (car signature*)])
|
|
(and (fx= (length (car sig0)) 0)
|
|
(fx= (length (cdr sig0)) 1)))
|
|
(let ([sig1 (cadr signature*)])
|
|
(and (fx= (length (car sig1)) 1)
|
|
(fx= (length (cdr sig1)) 1)
|
|
(eq? (cadr sig1) 'void))))
|
|
; recognize parameter-like signatures
|
|
; TODO: recognize the inverse order
|
|
(let ([type (cadar signature*)])
|
|
(if (eq? type 'void)
|
|
'void
|
|
(make-parameterlike type)))]
|
|
[(andmap (lambda (sig)
|
|
(fx= (length (cdr sig)) 1))
|
|
signature*)
|
|
(let ([type (cadar signature*)])
|
|
(cond
|
|
[(andmap (lambda (sig)
|
|
(eq? (cadr sig) type))
|
|
(cdr signature*))
|
|
type]
|
|
[(signature-boolean? signature*) 'boolean]
|
|
[(signature-true? signature*) 'true]
|
|
[else 'ptr]))] ; a strange case, like list* and cons*
|
|
[else #f])) ; multivalued
|
|
|
|
(define (signature-parse signature*)
|
|
(define (ellipsis? x) (eq? x '...))
|
|
(define (type? x)
|
|
(syntax-case x ()
|
|
[(t1 . t2) (and (type? #'t1) (type? #'t2))]
|
|
[t (and (symbol? #'t) (not (ellipsis? #'t)))]))
|
|
(and (not (null? signature*))
|
|
(map (lambda (sig)
|
|
(syntax-case (car sig) ()
|
|
[(a ...)
|
|
(andmap type? #'(a ...))
|
|
(list (list->vector #'(a ...)) #f #f)]
|
|
[(a ... b dots)
|
|
(and (andmap type? #'(a ...))
|
|
(type? #'b)
|
|
(ellipsis? #'dots))
|
|
(list (list->vector #'(a ...)) #'b #f)]
|
|
[(a ... b dots d)
|
|
(and (andmap type? #'(a ...))
|
|
(type? #'b)
|
|
(ellipsis? #'dots)
|
|
(type? #'d))
|
|
(list (list->vector #'(a ...)) #'b #'d)]
|
|
[else
|
|
($oops 'prims "unexpected pattern ~s in signature ~s" sig signature*)]))
|
|
signature*)))
|
|
|
|
(define (parsed-signature->interface psignature*)
|
|
(and psignature*
|
|
(map (lambda (sig)
|
|
(define len (vector-length (car sig)))
|
|
(cond
|
|
[(and (not (cadr sig)) (not (caddr sig)))
|
|
len]
|
|
[(not (caddr sig))
|
|
(- -1 len)]
|
|
[else
|
|
(- -2 len)]))
|
|
psignature*)))
|
|
|
|
(define (parsed-signature->arguments-type psignature*)
|
|
; the last vector must be longer than the other, and the other must be subvectors
|
|
(and psignature*
|
|
(let ([longest (car (car (last-pair psignature*)))]) ; assume they are ordered
|
|
(cond
|
|
[(andmap (lambda (sig)
|
|
(define other (car sig))
|
|
(define l (vector-length other))
|
|
(let loop ([i 0])
|
|
(or (fx= i l)
|
|
(and (equal? (vector-ref longest i) (vector-ref other i))
|
|
(loop (fx+ i 1))))))
|
|
psignature*)
|
|
longest]
|
|
[else
|
|
; the arguments disagree
|
|
#f]))))
|
|
|
|
(define (parsed-signature->rest-type psignature*)
|
|
; only one must be not #f
|
|
(and psignature*
|
|
(let loop ([psig* (map cadr psignature*)] [found #f])
|
|
(cond
|
|
[(null? psig*)
|
|
found]
|
|
[(not found)
|
|
(loop (cdr psig*) (car psig*))]
|
|
[(not (car psig*))
|
|
(loop (cdr psig*) found)]
|
|
[else
|
|
($oops 'prims "unexpected two values of rest argument ~s and ~s in signature with ~s" found (car psig*) psignature*)]))))
|
|
|
|
(define (parsed-signature->last-type psignature*)
|
|
; only one must be not #f
|
|
(and psignature*
|
|
(let loop ([psig* (map caddr psignature*)] [found #f])
|
|
(cond
|
|
[(null? psig*)
|
|
found]
|
|
[(not found)
|
|
(loop (cdr psig*) (car psig*))]
|
|
[(not (car psig*))
|
|
(loop (cdr psig*) found)]
|
|
[else
|
|
($oops 'prims "unexpected two values of last argument ~s and ~s in signature with ~s" found (car psig*) psignature*)]))))
|
|
|
|
(define put-priminfo!
|
|
(lambda (prim unprefixed lib* mask sig*)
|
|
(when (eq-hashtable-contains? prim-db prim)
|
|
(warningf 'define-symbol-type "extra entry for ~s" prim))
|
|
(unless (any-set? (prim-mask (or primitive system keyword system-keyword)) mask)
|
|
(warningf 'define-symbol-type "none of primitive, system, keyword, and system-keyword is set for ~s" prim))
|
|
(when (let ([mask (fxlogand mask (prim-mask (or primitive system keyword system-keyword)))])
|
|
(not (fx= (fxlogand mask (fx- mask 1)) 0)))
|
|
(warningf 'define-symbol-type "more than one of primitive, system, keyword, and system-keyword is set for ~s" prim))
|
|
(when (and (null? sig*) (any-set? (prim-mask primitive) mask))
|
|
(warningf 'define-symbol-type "no signatures for primitive ~s" prim))
|
|
(when (and (not (null? sig*)) (any-set? (prim-mask (or keyword system-keyword)) mask))
|
|
(warningf 'define-symbol-type "signatures given for keyword ~s" prim))
|
|
(let ([result-arity (signature-result-arity sig*)]
|
|
[result-type (if (null? sig*)
|
|
(mask-result-type mask)
|
|
(signature-result-type sig*))])
|
|
(when (and (eq? result-arity 'multiple) (all-set? (prim-mask single-valued) mask))
|
|
($oops 'prims "inconsistent single-value information for ~s" prim))
|
|
(when (and (eq? result-type 'ptr) (all-set? (prim-mask true) mask))
|
|
($oops 'prims "inconsistent true information for ~s ~s ~s ~s" prim result-type mask sig*))
|
|
(let* ([mask (fxlogor mask
|
|
(if (eq? result-type 'bottom) (prim-mask abort-op) 0)
|
|
(if (eq? result-arity 'single) (prim-mask single-valued) 0)
|
|
(if (signature-boolean? sig*) (prim-mask boolean-valued) 0)
|
|
(if (signature-true? sig*) (prim-mask true) 0))]
|
|
[psig* (signature-parse sig*)]
|
|
[arguments-type (parsed-signature->arguments-type psig*)])
|
|
(eq-hashtable-set! prim-db prim
|
|
(make-priminfo unprefixed lib* mask (parsed-signature->interface psig*)
|
|
arguments-type
|
|
(and arguments-type (parsed-signature->rest-type psig*)) ; if arguments-type is confused, clean rest-type and last-type
|
|
(and arguments-type (parsed-signature->last-type psig*))
|
|
result-type))))))
|
|
|
|
(define-syntax define-symbol-flags*
|
|
(lambda (x)
|
|
(syntax-case x (libraries flags)
|
|
[(_ ([libraries lib ...] [flags shared-flag ...]) entry ...)
|
|
(andmap identifier? #'(shared-flag ...))
|
|
(let ()
|
|
(define prim-name
|
|
(lambda (x)
|
|
(syntax-case x ()
|
|
[(prefix prim)
|
|
(and (identifier? #'prefix) (identifier? #'prim))
|
|
(with-syntax ([prefix:prim (construct-name #'prim #'prefix #'prim)])
|
|
#'(prim . prefix:prim))]
|
|
[prim (identifier? #'prim) #'(prim . prim)])))
|
|
(define ins-and-outs
|
|
(lambda (ins outs)
|
|
(syntax-case ins (->)
|
|
[((in ...) ...) #`(((in ...) #,outs) ...)])))
|
|
(define do-entry
|
|
(lambda (x)
|
|
(syntax-case x (feature sig flags ->)
|
|
[(prim [feature f] . more) #`(when-feature f #,(do-entry #'(prim . more)))]
|
|
[(prim [flags flag ...]) (do-entry #'(prim [sig] [flags flag ...]))]
|
|
[(prim [sig [(in ...) ... -> (out ...)] ...] [flags flag ...])
|
|
(with-syntax ([(unprefixed . prim) (prim-name #'prim)])
|
|
(with-syntax ([((((in ...) (out ...)) ...) ...)
|
|
(map ins-and-outs #'(((in ...) ...) ...) #'((out ...) ...))])
|
|
#'(put-priminfo! 'prim 'unprefixed '(lib ...)
|
|
(prim-mask (or shared-flag ... flag ...))
|
|
'([(in ...) . (out ...)] ... ...))))])))
|
|
#`(begin #,@(map do-entry #'(entry ...))))])))
|
|
|
|
(include "primdata.ss")
|
|
)
|