#lang s-exp "../lang/base.rkt"
(current-print-mode "constructor")
(require (for-syntax racket/base syntax/stx racket/match))
(require "cs019-pre-base.rkt")
(provide (rename-out [cs019-lambda lambda]
[cs019-define define]
[cs019-when when]
[cs019-unless unless]
[cs019-case case]
[cs019-local local]
[cs019-dots ..]
[cs019-dots ...]
[cs019-dots ....]
[cs019-dots .....]
[cs019-dots ......]
))
(define-syntax λ (make-rename-transformer #'cs019-lambda))
(require "private/sigs-patched.rkt")
(provide [all-from-out "private/sigs-patched.rkt"])
(provide Image$)
(define Image$ (Sig: image?))
(require "../lang/posn.rkt")
(provide [all-from-out "../lang/posn.rkt"])
(define Posn$ (Sig: posn?))
(provide Posn$)
(require (prefix-in whalesong: "../lang/whalesong.rkt"))
(provide (except-out (filtered-out
(lambda (name)
(match name
[(regexp #rx"^whalesong:(.+)$" (list _ real-name))
real-name]
[else
#f]))
(except-out (all-from-out "../lang/whalesong.rkt")
whalesong:if
whalesong:cond
whalesong:case
whalesong:member
whalesong:memq
whalesong:define
whalesong:lambda
whalesong:unless
whalesong:when
whalesong:local
whalesong:first
whalesong:rest
whalesong:second
whalesong:third
whalesong:fourth
whalesong:fifth
whalesong:sixth
whalesong:seventh
whalesong:eighth
whalesong:ninth
)))
string-ith
replicate
int->string
string->int
explode
implode
string-numeric?
string-alphabetic?
string-whitespace?
string-upper-case?
string-lower-case?)
(require "lists.rkt")
(provide (all-from-out "lists.rkt"))
(require "../image.rkt")
(provide (all-from-out "../image.rkt"))
(require "../web-world.rkt")
(provide (all-from-out "../web-world.rkt"))
(define View$ (Sig: view?))
(provide View$)
(define Event$ (Sig: event?))
(provide Event$)
(require "../resource.rkt")
(provide (all-from-out "../resource.rkt"))
(define Resource$ (Sig: resource?))
(provide Resource$)
(define-for-syntax (local-expand-for-error stx ctx stops)
(when (memq (syntax-local-context) '(expression))
(local-expand stx ctx stops)))
(define-for-syntax (teach-syntax-error form stx detail msg . args)
(let ([form (if (eq? form '|function call|)
form
#f)] [msg (apply format msg args)])
(if detail
(raise-syntax-error form msg stx detail)
(raise-syntax-error form msg stx))))
(define-for-syntax (teach-syntax-error* form stx details msg . args)
(let ([exn (with-handlers ([exn:fail:syntax?
(lambda (x) x)])
(apply teach-syntax-error form stx #f msg args))])
(raise
(make-exn:fail:syntax
(exn-message exn)
(exn-continuation-marks exn)
details))))
(define-for-syntax (bad-use-error name stx)
(teach-syntax-error
name
stx
#f
"found a use of `~a' that does not follow an open parenthesis"
name))
(define-for-syntax (something-else v)
(let ([v (syntax-e v)])
(cond
[(number? v) "a number"]
[(string? v) "a string"]
[else "something else"])))
(define-for-syntax (verify-boolean b where)
(with-syntax ([b b]
[where where])
(quasisyntax/loc #'b
(let ([bv b])
(if (or (eq? bv #t) (eq? bv #f))
bv
#,(syntax/loc #'b
(whalesong:#%app raise
(make-exn:fail:contract
(format "~a: question result is not true or false: ~e" 'where bv)
(current-continuation-marks)))))))))
(define-syntax (-cond stx)
(syntax-case stx ()
[(_)
(teach-syntax-error
'cond
stx
#f
"expected a question--answer clause after `cond', but nothing's there")]
[(_ clause ...)
(let* ([clauses (syntax->list (syntax (clause ...)))]
[check-preceding-exprs
(lambda (stop-before)
(let/ec k
(for-each (lambda (clause)
(if (eq? clause stop-before)
(k #t)
(syntax-case clause ()
[(question answer)
(begin
(unless (and (identifier? (syntax question))
(free-identifier=? (syntax question)
#'else))
(local-expand-for-error (syntax question) 'expression null))
(local-expand-for-error (syntax answer) 'expression null))])))
clauses)))])
(let ([checked-clauses
(map
(lambda (clause)
(syntax-case clause (else)
[(else answer)
(let ([lpos (memq clause clauses)])
(when (not (null? (cdr lpos)))
(teach-syntax-error
'cond
stx
clause
"found an `else' clause that isn't the last clause ~
in its `cond' expression"))
(with-syntax ([new-test (syntax #t) ])
(syntax/loc clause (new-test answer))))]
[(question answer)
(with-syntax ([verified
(verify-boolean #'question 'cond)])
(syntax/loc clause (verified answer)))]
[()
(check-preceding-exprs clause)
(teach-syntax-error
'cond
stx
clause
"expected a question--answer clause, but found an empty clause")]
[(question?)
(check-preceding-exprs clause)
(teach-syntax-error
'cond
stx
clause
"expected a clause with a question and answer, but found a clause with only one part")]
[(question? answer? ...)
(check-preceding-exprs clause)
(let ([parts (syntax->list clause)])
(unless (and (identifier? (car parts))
(free-identifier=? (car parts) #'else))
(local-expand-for-error (car parts) 'expression null))
(unless (null? (cdr parts))
(local-expand-for-error (cadr parts) 'expression null))
(teach-syntax-error*
'cond
stx
parts
"expected a clause with one question and one answer, but found a clause with ~a parts"
(length parts)))]
[_else
(teach-syntax-error
'cond
stx
clause
"expected a question--answer clause, but found ~a"
(something-else clause))]))
clauses)])
(let ([clauses (append checked-clauses
(list
(with-syntax ([error-call (syntax/loc stx (whalesong:#%app raise (make-exn:fail:contract "cond: all question results were false" (current-continuation-marks))))])
(syntax [else error-call]))))])
(with-syntax ([clauses clauses])
(syntax/loc stx (cond . clauses))))))]
[_else (bad-use-error 'cond stx)]))
(provide (rename-out [-cond cond]))
(define-syntax (-if stx)
(syntax-case stx ()
[(_ test then else)
(with-syntax ([new-test (verify-boolean #'test 'if)])
(syntax/loc stx
(if new-test
then
else)))]
[(_ . rest)
(let ([n (length (syntax->list (syntax rest)))])
(teach-syntax-error
'if
stx
#f
"expected one question expression and two answer expressions, but found ~a expression~a"
(if (zero? n) "no" n)
(if (= n 1) "" "s")))]
[_else (bad-use-error 'if stx)]))
(provide (rename-out [-if if]))
(define 1-LET "1-letter string")
(define 1-LETTER (format "~a" 1-LET))
(define 1-LETTER* (format "list of ~as" 1-LET))
(define NAT "natural number")
(define (1-letter? tag s)
(unless (string? s) (err tag "expected a ~a, but received a string: ~e" 1-LETTER s))
(= (string-length s) 1))
(define (1-letter*? tag s)
(unless (list? s) (err tag "expected a ~a, but received: ~e" 1-LETTER* s))
(for-each
(lambda (c)
(unless (string? c) (err tag "expected a ~a, but received: ~e" 1-LETTER* c)))
s)
(andmap (compose (lambda (x) (= x 1)) string-length) s))
(define (err tag msg-format . args)
(raise
(make-exn:fail:contract
(apply format (string-append (symbol->string tag) ": " msg-format) args)
(current-continuation-marks))))
(define (a-or-an after)
(if (member (string-ref (format "~a" after) 0) '(#\a #\e #\i #\o #\u))
"an" "a"))
(define cerr
(case-lambda
[(tag check-result format-msg actual)
(unless check-result
(err tag (string-append "expected " (a-or-an format-msg) " " format-msg ", but received ~e") actual))]
[(tag check-result format-msg actual snd)
(unless check-result
(err tag (string-append "expected " (a-or-an format-msg) " " format-msg " for the ~a argument, but received ~e")
snd actual))]))
(define string-ith
(lambda (s n)
(define f "exact integer in [0, length of the given string]")
(cerr 'string-ith (string? s) "string" s "first")
(cerr 'string-ith (and (number? n) (integer? n) (>= n 0)) NAT n "second")
(let ([l (string-length s)])
(cerr 'string-ith (< n l) f n "second"))
(string (string-ref s n))))
(define replicate
(lambda (n s1)
(cerr 'replicate (and (number? n) (exact-integer? n) (>= n 0)) NAT n)
(cerr 'replicate (string? s1) "string" s1)
(apply string-append (build-list n (lambda (i) s1)))))
(define int->string
(lambda (i)
(cerr 'int->string
(and (exact-integer? i) (or (<= 0 i 55295) (<= 57344 i 1114111)))
"exact integer in [0,55295] or [57344 1114111]"
i)
(string (integer->char i))))
(define string->int
(lambda (s)
(cerr 'string->int (1-letter? 'string->int s) 1-LETTER s)
(char->integer (string-ref s 0))))
(define explode
(lambda (s)
(cerr 'explode (string? s) "string" s)
(map string (string->list s))))
(define implode
(lambda (los)
(cerr 'implode (1-letter*? 'implode los) 1-LETTER* los)
(apply string-append los)))
(define string-numeric?
(lambda (s1)
(cerr 'string-numeric? (string? s1) "string" s1)
(andmap char-numeric? (string->list s1))))
(define string-alphabetic?
(lambda (s1)
(cerr 'string-alphabetic? (string? s1) "string" s1)
(andmap char-alphabetic? (string->list s1))))
(define string-whitespace?
(lambda (s)
(cerr 'string-upper-case? (string? s) "string" s)
(andmap char-whitespace? (string->list s))))
(define string-upper-case?
(lambda (s)
(cerr 'string-upper-case? (string? s) "string" s)
(andmap char-upper-case? (string->list s))))
(define string-lower-case?
(lambda (s)
(cerr 'string-lower-case? (string? s) "string" s)
(andmap char-lower-case? (string->list s))))
(define (-member x L)
(cond
[(eq? (member x L) #f) #f]
[else #t]))
(define (-memq x L)
(cond
[(eq? (memq x L) #f) #f]
[else #t]))
(provide (rename-out [-member member]
[-member member?]
[-memq memq]))