|
|
|
@ -2,136 +2,10 @@
|
|
|
|
|
(require (for-syntax racket/base racket/syntax br/syntax) br/define racket/class sugar/list racket/list (only-in br/list push! pop!) racket/string racket/format racket/contract)
|
|
|
|
|
(provide (all-defined-out) push! pop!)
|
|
|
|
|
|
|
|
|
|
(define-syntax (· stx)
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
[(_ x ref)
|
|
|
|
|
#'(cond
|
|
|
|
|
[(object? x) (with-handlers ([exn:fail:object? (λ (exn) (send x ref))])
|
|
|
|
|
(get-field ref x))]
|
|
|
|
|
[(hash? x) (hash-ref x 'ref #f)]
|
|
|
|
|
[else (raise-argument-error '· (format "~a must be object or hash" 'x) x)])]
|
|
|
|
|
[(_ x ref0 . refs) #'(· (· x ref0) . refs)]))
|
|
|
|
|
|
|
|
|
|
(define-syntax (·map stx)
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
[(_ ref xs) #'(for/list ([x (in-list xs)]) (· x ref))]))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (+= id thing) (begin (set! id (+ id thing)) id))
|
|
|
|
|
(define-syntax-rule (++ id) (+= id 1))
|
|
|
|
|
(define-syntax-rule (-- id) (+= id -1))
|
|
|
|
|
(define-syntax-rule (-= id thing) (+= id (- thing)))
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(require rackunit)
|
|
|
|
|
(define C
|
|
|
|
|
(class object%
|
|
|
|
|
(super-new)
|
|
|
|
|
(field [foo 'field])
|
|
|
|
|
(define/public (bar) 'method)
|
|
|
|
|
(define/public (zam) (hasheq 'zoom 'hash))))
|
|
|
|
|
(define h (hasheq 'bam (new C) 'foo 'hashlet))
|
|
|
|
|
(define o (new C))
|
|
|
|
|
(check-equal? (· o foo) 'field)
|
|
|
|
|
(check-equal? (· o bar) 'method)
|
|
|
|
|
(check-equal? (· o zam zoom) 'hash)
|
|
|
|
|
(check-equal? (· h bam foo) 'field)
|
|
|
|
|
(check-equal? (· h bam bar) 'method)
|
|
|
|
|
(check-equal? (· h bam zam zoom) 'hash)
|
|
|
|
|
(check-equal? (·map foo (list o h)) '(field hashlet)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (listify kvs)
|
|
|
|
|
(for/list ([slice (in-list (slice-at kvs 2))])
|
|
|
|
|
(cons (first slice) (second slice))))
|
|
|
|
|
(define-syntax-rule (define-hashifier id hasher) (define (id . kvs) (hasher (listify kvs))))
|
|
|
|
|
(define-hashifier mhash make-hash)
|
|
|
|
|
(define-hashifier mhasheq make-hasheq)
|
|
|
|
|
(define-hashifier mhasheqv make-hasheqv)
|
|
|
|
|
(define (dictify . xs) (listify xs))
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(check-equal? (mhash 'k "v") (make-hash (list (cons 'k "v")))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define isBuffer? bytes?)
|
|
|
|
|
(define (newBuffer x) (string->bytes/latin-1 (format "~a" x)))
|
|
|
|
|
(define buffer-length bytes-length)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; js-style `push`, which appends to end of list
|
|
|
|
|
(define-syntax-rule (push-end! id thing) (set! id (append id (list thing))))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (push-field! field o expr) (set-field! field o (cons expr (get-field field o))))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (push-end-field! field o expr)
|
|
|
|
|
(set-field! field o (append (get-field field o) (list expr))))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (pop-field! field o) (let ([xs (get-field field o)])
|
|
|
|
|
(set-field! field o (cdr xs))
|
|
|
|
|
(car xs)))
|
|
|
|
|
(define-syntax (increment-field! stx)
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
[(_ field o) #'(increment-field! field o 1)]
|
|
|
|
|
[(_ field o expr)
|
|
|
|
|
#'(begin (set-field! field o (+ (get-field field o) expr)) (get-field field o))]))
|
|
|
|
|
|
|
|
|
|
(define-syntax (increment! stx)
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
[(_ id) #'(increment! id 1)]
|
|
|
|
|
[(_ id expr)
|
|
|
|
|
#'(begin (set! id (+ id expr)) id)]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(define xs '(1 2 3))
|
|
|
|
|
(push-end! xs 4)
|
|
|
|
|
(check-equal? xs '(1 2 3 4)))
|
|
|
|
|
|
|
|
|
|
;; fancy number->string. bounds are checked, inexact integers are coerced.
|
|
|
|
|
(define (number x)
|
|
|
|
|
(unless (and (number? x) (< -1e21 x 1e21))
|
|
|
|
|
(raise-argument-error 'number "valid number" x))
|
|
|
|
|
(let ([x (/ (round (* x 1e6)) 1e6)])
|
|
|
|
|
(number->string (if (integer? x)
|
|
|
|
|
(inexact->exact x)
|
|
|
|
|
x))))
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(check-equal? (number 4.5) "4.5")
|
|
|
|
|
(check-equal? (number 4.0) "4")
|
|
|
|
|
(check-equal? (number 4) "4")
|
|
|
|
|
(check-equal? (number -4) "-4"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define-syntax (send*/fold stx)
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
[(_ o) #'o]
|
|
|
|
|
[(_ o [m0 . args0] [m . args] ...)
|
|
|
|
|
#'(send*/fold (send o m0 . args0) [m . args] ...)]))
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(define SFC (class object%
|
|
|
|
|
(super-new)
|
|
|
|
|
(field [sum 0])
|
|
|
|
|
(define/public (add x) (set! sum (+ sum x)) this)))
|
|
|
|
|
(define sfo (new SFC))
|
|
|
|
|
(check-equal? (get-field sum (send*/fold sfo [add 1] [add 2] [add 3])) 6))
|
|
|
|
|
|
|
|
|
|
(define (bounded low x high)
|
|
|
|
|
(if (high . < . low)
|
|
|
|
|
(bounded high x low)
|
|
|
|
|
(max low (min high x))))
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(check-equal? (bounded 0 2 1) 1)
|
|
|
|
|
(check-equal? (bounded 1 2 0) 1)
|
|
|
|
|
(check-equal? (bounded 0 -2 1) 0)
|
|
|
|
|
(check-equal? (bounded 1 -2 0) 0)
|
|
|
|
|
(check-equal? (bounded 0 .5 1) 0.5)
|
|
|
|
|
(check-equal? (bounded 0 0 1) 0)
|
|
|
|
|
(check-equal? (bounded 0 1 1) 1))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(struct exn:pitfall:test exn (data))
|
|
|
|
|
|
|
|
|
|
(define (raise-test-exn val)
|
|
|
|
@ -140,30 +14,6 @@
|
|
|
|
|
(define-syntax-rule (test-when cond expr)
|
|
|
|
|
(if cond (raise-test-exn expr) expr))
|
|
|
|
|
|
|
|
|
|
(define string%
|
|
|
|
|
(class* object% (writable<%>)
|
|
|
|
|
(super-new)
|
|
|
|
|
(init-field [data #f])
|
|
|
|
|
(define (get-string)
|
|
|
|
|
(with-handlers ([exn:fail:object? (λ (exn) data)])
|
|
|
|
|
(send this toString)))
|
|
|
|
|
(define/public (custom-write port) (write (get-string) port))
|
|
|
|
|
(define/public (custom-display port) (display (get-string) port))))
|
|
|
|
|
|
|
|
|
|
(define mixin-tester%
|
|
|
|
|
(class object%
|
|
|
|
|
(super-new)
|
|
|
|
|
(define/public (addContent val) (make-object string% val))))
|
|
|
|
|
|
|
|
|
|
(define-syntax (as-method stx)
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
[(_ id) (with-syntax ([private-id (generate-temporary #'id)])
|
|
|
|
|
#'(begin
|
|
|
|
|
(public [private-id id])
|
|
|
|
|
(define (private-id . args) (apply id this args))))]))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (as-methods id ...)
|
|
|
|
|
(begin (as-method id) ...))
|
|
|
|
|
|
|
|
|
|
(define (color-string? x)
|
|
|
|
|
(and (string? x)
|
|
|
|
@ -171,17 +21,6 @@
|
|
|
|
|
(or (= (string-length x) 4) (= (string-length x) 7))
|
|
|
|
|
#t)))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (define-subclass CLASS-ID (SUBCLASS-ID INIT-FIELD ...) . EXPRS)
|
|
|
|
|
(define SUBCLASS-ID
|
|
|
|
|
(class CLASS-ID
|
|
|
|
|
(init-field INIT-FIELD ...) . EXPRS)))
|
|
|
|
|
|
|
|
|
|
(define (bytes->hex bstr)
|
|
|
|
|
(map (λ (b) (string->symbol (string-append (if (< b 16)
|
|
|
|
|
"x0" "x") (~r b #:base 16)))) (bytes->list bstr)))
|
|
|
|
|
|
|
|
|
|
(module+ test
|
|
|
|
|
(check-equal? (bytes->hex #"PNG") '(x50 x4e x47)))
|
|
|
|
|
|
|
|
|
|
(define (layout? x)
|
|
|
|
|
(and (hash? x) (hash-has-key? x 'glyphs) (hash-has-key? x 'positions)))
|
|
|
|
@ -189,26 +28,4 @@
|
|
|
|
|
(define index? (and/c (not/c negative?) integer?))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define-macro (define-stub-stop ID)
|
|
|
|
|
(with-pattern ([ERROR-ID (suffix-id (prefix-id (syntax-source #'this) ":" #'ID) ":not-implemented")])
|
|
|
|
|
#'(define (ID . args)
|
|
|
|
|
(error 'ERROR-ID))))
|
|
|
|
|
|
|
|
|
|
(provide (rename-out [define-stub-stop define-stub]))
|
|
|
|
|
|
|
|
|
|
(define-macro (define-stub-go ID)
|
|
|
|
|
(with-pattern ([ERROR-ID (suffix-id (prefix-id (syntax-source #'this) ":" #'ID) ":not-implemented")])
|
|
|
|
|
#'(define (ID . args)
|
|
|
|
|
(displayln 'ERROR-ID))))
|
|
|
|
|
|
|
|
|
|
(define-macro (define-unfinished (ID . ARGS) . BODY)
|
|
|
|
|
(with-pattern ([ID-UNFINISHED (suffix-id (prefix-id (syntax-source #'this) ":" #'ID) ":unfinished")])
|
|
|
|
|
#'(define (ID . ARGS)
|
|
|
|
|
(begin . BODY)
|
|
|
|
|
(error 'ID-UNFINISHED))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define-macro (unfinished)
|
|
|
|
|
(with-pattern ([ID-UNFINISHED (prefix-id (syntax-source caller-stx) ":" (syntax-line caller-stx) ":" #'unfinished)])
|
|
|
|
|
#'(error 'ID-UNFINISHED)))
|
|
|
|
|
|