some Racket-y (102); arrows and renaming for define-struct in teaching languages; need to find and run lang tests
This commit is contained in:
parent
a57734d7ae
commit
e430753b6c
|
@ -32,8 +32,8 @@
|
||||||
;; reporting. As always, avoid using `local-expand' if there's no
|
;; reporting. As always, avoid using `local-expand' if there's no
|
||||||
;; error.
|
;; error.
|
||||||
|
|
||||||
(module teach mzscheme
|
#lang mzscheme
|
||||||
(require mzlib/etc
|
(require mzlib/etc
|
||||||
mzlib/list
|
mzlib/list
|
||||||
mzlib/math
|
mzlib/math
|
||||||
mzlib/pconvert-prop
|
mzlib/pconvert-prop
|
||||||
|
@ -55,9 +55,9 @@
|
||||||
beginner-equal? beginner-equal~? teach-equal?
|
beginner-equal? beginner-equal~? teach-equal?
|
||||||
advanced-cons advanced-list*))
|
advanced-cons advanced-list*))
|
||||||
|
|
||||||
(require "rewrite-error-message.rkt")
|
(require "rewrite-error-message.rkt")
|
||||||
|
|
||||||
(require-for-syntax "teachhelp.rkt"
|
(require-for-syntax "teachhelp.rkt"
|
||||||
"rewrite-error-message.rkt"
|
"rewrite-error-message.rkt"
|
||||||
"teach-shared.rkt"
|
"teach-shared.rkt"
|
||||||
"rewrite-error-message.rkt"
|
"rewrite-error-message.rkt"
|
||||||
|
@ -74,12 +74,21 @@
|
||||||
stepper/private/syntax-property
|
stepper/private/syntax-property
|
||||||
test-engine/racket-tests)
|
test-engine/racket-tests)
|
||||||
|
|
||||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
(define-for-syntax EXPECTED-HEADER
|
||||||
;; run-time helpers
|
"expected a variable name, or a function name and its variables (in parentheses), but found ~a")
|
||||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
;; verify-boolean is inserted to check for boolean results:
|
(define-for-syntax EXPECTED-MATCH-PATTERN
|
||||||
(define (verify-boolean b where)
|
"expected a pattern--answer clause after the expression following `match', but nothing's there")
|
||||||
|
|
||||||
|
(define-for-syntax EXPECTED-FUNCTION-NAME
|
||||||
|
"expected a function after the open parenthesis, but found a structure name")
|
||||||
|
|
||||||
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; run-time helpers
|
||||||
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; verify-boolean is inserted to check for boolean results:
|
||||||
|
(define (verify-boolean b where)
|
||||||
(if (or (eq? b #t) (eq? b #f))
|
(if (or (eq? b #t) (eq? b #f))
|
||||||
b
|
b
|
||||||
(raise
|
(raise
|
||||||
|
@ -87,34 +96,34 @@
|
||||||
(format "~a: question result is not true or false: ~e" where b)
|
(format "~a: question result is not true or false: ~e" where b)
|
||||||
(current-continuation-marks)))))
|
(current-continuation-marks)))))
|
||||||
|
|
||||||
(define (identifier-is-bound? id)
|
(define (identifier-is-bound? id)
|
||||||
(or (identifier-binding id)
|
(or (identifier-binding id)
|
||||||
;; identifier-binding returns #f for variable bound at the top-level,
|
;; identifier-binding returns #f for variable bound at the top-level,
|
||||||
;; check explicitly:
|
;; check explicitly:
|
||||||
(and (namespace-variable-value (syntax-e id) #t (lambda () #f)) #t)))
|
(and (namespace-variable-value (syntax-e id) #t (lambda () #f)) #t)))
|
||||||
|
|
||||||
;; Wrapped around top-level definitions to disallow re-definition:
|
;; Wrapped around top-level definitions to disallow re-definition:
|
||||||
(define (check-top-level-not-defined who id)
|
(define (check-top-level-not-defined who id)
|
||||||
(when (identifier-is-bound? id)
|
(when (identifier-is-bound? id)
|
||||||
(raise-syntax-error #f "this name was defined previously and cannot be re-defined" id)))
|
(raise-syntax-error #f "this name was defined previously and cannot be re-defined" id)))
|
||||||
|
|
||||||
(define (top/check-defined id)
|
(define (top/check-defined id)
|
||||||
(namespace-variable-value (syntax-e id) #t (lambda () (raise-not-bound-error id))))
|
(namespace-variable-value (syntax-e id) #t (lambda () (raise-not-bound-error id))))
|
||||||
|
|
||||||
;; For quasiquote and shared:
|
;; For quasiquote and shared:
|
||||||
(require (rename "teachprims.rkt" the-cons advanced-cons))
|
(require (rename "teachprims.rkt" the-cons advanced-cons))
|
||||||
(require (only "teachprims.rkt" cyclic-list?))
|
(require (only "teachprims.rkt" cyclic-list?))
|
||||||
|
|
||||||
;; Referenced to ensure that evaluating `lambda' always
|
;; Referenced to ensure that evaluating `lambda' always
|
||||||
;; produces a new closure (instead of using a closure
|
;; produces a new closure (instead of using a closure
|
||||||
;; that's allocated once)
|
;; that's allocated once)
|
||||||
(define make-lambda-generative 5)
|
(define make-lambda-generative 5)
|
||||||
|
|
||||||
;; A consistent pattern for stepper-skipto:
|
;; A consistent pattern for stepper-skipto:
|
||||||
(define-for-syntax (stepper-ignore-checker stx)
|
(define-for-syntax (stepper-ignore-checker stx)
|
||||||
(stepper-syntax-property stx 'stepper-skipto '(syntax-e cdr syntax-e cdr car)))
|
(stepper-syntax-property stx 'stepper-skipto '(syntax-e cdr syntax-e cdr car)))
|
||||||
|
|
||||||
(define-for-syntax (map-with-index proc . lists)
|
(define-for-syntax (map-with-index proc . lists)
|
||||||
(let loop ([i 0] [lists lists] [rev-result '()])
|
(let loop ([i 0] [lists lists] [rev-result '()])
|
||||||
(if (null? (car lists))
|
(if (null? (car lists))
|
||||||
(reverse rev-result)
|
(reverse rev-result)
|
||||||
|
@ -122,8 +131,8 @@
|
||||||
(map cdr lists)
|
(map cdr lists)
|
||||||
(cons (apply proc i (map car lists)) rev-result)))))
|
(cons (apply proc i (map car lists)) rev-result)))))
|
||||||
|
|
||||||
;; build-struct-names is hard to handle
|
;; build-struct-names is hard to handle
|
||||||
(define-for-syntax (make-struct-names name fields stx)
|
(define-for-syntax (make-struct-names name fields stx)
|
||||||
(apply (lambda (struct: constructor predicate . rest)
|
(apply (lambda (struct: constructor predicate . rest)
|
||||||
(let loop ([rest rest]
|
(let loop ([rest rest]
|
||||||
[getters '()]
|
[getters '()]
|
||||||
|
@ -135,11 +144,11 @@
|
||||||
(cons (cadr rest) setters)))))
|
(cons (cadr rest) setters)))))
|
||||||
(build-struct-names name fields #f #f stx)))
|
(build-struct-names name fields #f #f stx)))
|
||||||
|
|
||||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; syntax implementations
|
;; syntax implementations
|
||||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(define-syntax define-syntax-set/provide
|
(define-syntax define-syntax-set/provide
|
||||||
(lambda (stx)
|
(lambda (stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ (id ...) defn ...)
|
[(_ (id ...) defn ...)
|
||||||
|
@ -159,14 +168,14 @@
|
||||||
defn ...))))])))
|
defn ...))))])))
|
||||||
|
|
||||||
|
|
||||||
;; The implementation of form X is defined below as X/proc. The
|
;; The implementation of form X is defined below as X/proc. The
|
||||||
;; reason for this is to allow the implementation of Y to re-use the
|
;; reason for this is to allow the implementation of Y to re-use the
|
||||||
;; implementation of X (expanding to a use of X would mangle syntax
|
;; implementation of X (expanding to a use of X would mangle syntax
|
||||||
;; error messages), while preserving the binding of X as the one for
|
;; error messages), while preserving the binding of X as the one for
|
||||||
;; the syntax definition (so that quasiquote can recognize unquote,
|
;; the syntax definition (so that quasiquote can recognize unquote,
|
||||||
;; etc.).
|
;; etc.).
|
||||||
|
|
||||||
(define-syntax-set/provide (beginner-define
|
(define-syntax-set/provide (beginner-define
|
||||||
beginner-define-struct
|
beginner-define-struct
|
||||||
beginner-lambda
|
beginner-lambda
|
||||||
beginner-app beginner-app-continue
|
beginner-app beginner-app-continue
|
||||||
|
@ -329,7 +338,8 @@
|
||||||
assign)]
|
assign)]
|
||||||
[made-up (gensym)]
|
[made-up (gensym)]
|
||||||
[defn defn])
|
[defn defn])
|
||||||
(with-syntax ([made-up-defn (stepper-syntax-property
|
(with-syntax ([made-up-defn
|
||||||
|
(stepper-syntax-property
|
||||||
(syntax (define made-up (lambda () (advanced-set! name 10) ...)))
|
(syntax (define made-up (lambda () (advanced-set! name 10) ...)))
|
||||||
'stepper-skip-completely
|
'stepper-skip-completely
|
||||||
#t)])
|
#t)])
|
||||||
|
@ -635,7 +645,7 @@
|
||||||
'define
|
'define
|
||||||
stx
|
stx
|
||||||
(syntax non-name)
|
(syntax non-name)
|
||||||
"expected a variable name, or a function name and its variables (in parentheses), but found ~a"
|
EXPECTED-HEADER
|
||||||
(something-else/kw (syntax non-name)))]
|
(something-else/kw (syntax non-name)))]
|
||||||
;; Missing name:
|
;; Missing name:
|
||||||
[(_)
|
[(_)
|
||||||
|
@ -657,7 +667,8 @@
|
||||||
#`(define (#,#'name x)
|
#`(define (#,#'name x)
|
||||||
(begin
|
(begin
|
||||||
(send (send (get-test-engine) get-info) add-wish-call (quote #,#'name))
|
(send (send (get-test-engine) get-info) add-wish-call (quote #,#'name))
|
||||||
(raise (exn:fail:wish (format "wished for function ~a not implemented" (quote #,#'name))
|
(raise (exn:fail:wish
|
||||||
|
(format "wished for function ~a not implemented" (quote #,#'name))
|
||||||
(current-continuation-marks) (quote #,#'name) x)))) #'lambda)]
|
(current-continuation-marks) (quote #,#'name) x)))) #'lambda)]
|
||||||
[(_ name default-value)
|
[(_ name default-value)
|
||||||
(define/proc #t #f
|
(define/proc #t #f
|
||||||
|
@ -951,7 +962,85 @@
|
||||||
(values #,signature-name #,parametric-signature-name proc-name ...)))
|
(values #,signature-name #,parametric-signature-name proc-name ...)))
|
||||||
'stepper-black-box-expr
|
'stepper-black-box-expr
|
||||||
stx))))])
|
stx))))])
|
||||||
(let ([defn
|
;; --------------------------------------------------------------------------------
|
||||||
|
(define struct-name-size (string-length (symbol->string (syntax-e #'name_))))
|
||||||
|
(define struct-name/locally-introduced (syntax-local-introduce #'name_))
|
||||||
|
|
||||||
|
(define struct-name-to-maker-directive
|
||||||
|
(vector (syntax-local-introduce constructor-name)
|
||||||
|
5
|
||||||
|
struct-name-size
|
||||||
|
struct-name/locally-introduced
|
||||||
|
0
|
||||||
|
struct-name-size))
|
||||||
|
|
||||||
|
(define struct-name-to-predicate-directive
|
||||||
|
(vector (syntax-local-introduce predicate-name)
|
||||||
|
0
|
||||||
|
struct-name-size
|
||||||
|
struct-name/locally-introduced
|
||||||
|
0
|
||||||
|
struct-name-size))
|
||||||
|
|
||||||
|
(define (struct->selector-directive selector)
|
||||||
|
(define selector-name/locally-introduced (syntax-local-introduce selector))
|
||||||
|
(vector selector-name/locally-introduced
|
||||||
|
0
|
||||||
|
struct-name-size
|
||||||
|
struct-name/locally-introduced
|
||||||
|
0
|
||||||
|
struct-name-size))
|
||||||
|
|
||||||
|
(define (field->selector-directive field selector)
|
||||||
|
(define field-name/locally-introduced (syntax-local-introduce field))
|
||||||
|
(define field-name-size (string-length (symbol->string (syntax-e field))))
|
||||||
|
(define selector-name/locally-introduced (syntax-local-introduce selector))
|
||||||
|
(vector selector-name/locally-introduced
|
||||||
|
(+ struct-name-size 1)
|
||||||
|
field-name-size
|
||||||
|
field-name/locally-introduced
|
||||||
|
0
|
||||||
|
field-name-size))
|
||||||
|
|
||||||
|
(define (struct->setter-directive setter)
|
||||||
|
(define setter-name/locally-introduced (syntax-local-introduce setter))
|
||||||
|
(vector setter-name/locally-introduced
|
||||||
|
;; set-name_-field!
|
||||||
|
;; 012|--->|
|
||||||
|
(string-length "set-")
|
||||||
|
struct-name-size
|
||||||
|
struct-name/locally-introduced
|
||||||
|
0
|
||||||
|
struct-name-size))
|
||||||
|
|
||||||
|
(define (field->setter-directive field setter)
|
||||||
|
(define field-name/locally-introduced (syntax-local-introduce field))
|
||||||
|
(define field-name-size (string-length (symbol->string (syntax-e field))))
|
||||||
|
(define setter-name/locally-introduced (syntax-local-introduce setter))
|
||||||
|
(vector setter-name/locally-introduced
|
||||||
|
;; set-name_-field!
|
||||||
|
;; 012|4...X|--->
|
||||||
|
(+ (string-length "set-") struct-name-size 1)
|
||||||
|
field-name-size
|
||||||
|
field-name/locally-introduced
|
||||||
|
0
|
||||||
|
field-name-size))
|
||||||
|
|
||||||
|
(define signature-name-directive #f)
|
||||||
|
(define parametric-signature-name-directive #f)
|
||||||
|
|
||||||
|
(define all-directives
|
||||||
|
(list* signature-name-directive
|
||||||
|
parametric-signature-name-directive
|
||||||
|
struct-name-to-maker-directive
|
||||||
|
struct-name-to-predicate-directive
|
||||||
|
(map field->selector-directive fields getter-names)
|
||||||
|
(map struct->selector-directive getter-names)
|
||||||
|
(map field->setter-directive fields setter-names)
|
||||||
|
(map struct->setter-directive setter-names)))
|
||||||
|
|
||||||
|
;; --------------------------------------------------------------------------------
|
||||||
|
(let* ([defn
|
||||||
(quasisyntax/loc stx
|
(quasisyntax/loc stx
|
||||||
(begin
|
(begin
|
||||||
#,(stepper-syntax-property
|
#,(stepper-syntax-property
|
||||||
|
@ -967,7 +1056,7 @@
|
||||||
[(self . args)
|
[(self . args)
|
||||||
(raise-syntax-error
|
(raise-syntax-error
|
||||||
#f
|
#f
|
||||||
"expected a function after the open parenthesis, but found a structure name"
|
EXPECTED-FUNCTION-NAME
|
||||||
stx
|
stx
|
||||||
#'self)]
|
#'self)]
|
||||||
[_ #'#,signature-name])))
|
[_ #'#,signature-name])))
|
||||||
|
@ -975,12 +1064,15 @@
|
||||||
(make-info (lambda () compile-info))))
|
(make-info (lambda () compile-info))))
|
||||||
'stepper-skip-completely
|
'stepper-skip-completely
|
||||||
#t)
|
#t)
|
||||||
#,defn0))])
|
#,defn0))]
|
||||||
(check-definitions-new 'define-struct
|
[defn (check-definitions-new 'define-struct
|
||||||
stx
|
stx
|
||||||
(list* name parametric-signature-name to-define-names)
|
(list* name parametric-signature-name to-define-names)
|
||||||
defn
|
defn
|
||||||
(and setters? bind-names))))))))]
|
(and setters? bind-names))]
|
||||||
|
[defn (syntax-property defn 'disappeared-use (list (syntax-local-introduce #'name_)))]
|
||||||
|
[defn (syntax-property defn 'sub-range-binders all-directives)])
|
||||||
|
defn))))))]
|
||||||
[(_ name_ something . rest)
|
[(_ name_ something . rest)
|
||||||
(teach-syntax-error
|
(teach-syntax-error
|
||||||
'define-struct
|
'define-struct
|
||||||
|
@ -2631,7 +2723,7 @@
|
||||||
'match
|
'match
|
||||||
stx
|
stx
|
||||||
#f
|
#f
|
||||||
"expected a pattern--answer clause after the expression following `match', but nothing's there")]
|
EXPECTED-MATCH-PATTERN)]
|
||||||
[(_ v-expr clause ...)
|
[(_ v-expr clause ...)
|
||||||
(let ([clauses (syntax->list (syntax (clause ...)))])
|
(let ([clauses (syntax->list (syntax (clause ...)))])
|
||||||
(for-each
|
(for-each
|
||||||
|
@ -2677,7 +2769,18 @@
|
||||||
qqp]))]
|
qqp]))]
|
||||||
[check-and-translate-p
|
[check-and-translate-p
|
||||||
(λ (p)
|
(λ (p)
|
||||||
(syntax-case p (struct posn beginner-true beginner-false empty intermediate-quote intermediate-quasiquote advanced-cons list advanced-list* vector box)
|
(syntax-case p (struct
|
||||||
|
posn
|
||||||
|
beginner-true
|
||||||
|
beginner-false
|
||||||
|
empty
|
||||||
|
intermediate-quote
|
||||||
|
intermediate-quasiquote
|
||||||
|
advanced-cons
|
||||||
|
list
|
||||||
|
advanced-list*
|
||||||
|
vector
|
||||||
|
box)
|
||||||
[beginner-true
|
[beginner-true
|
||||||
(syntax/loc p
|
(syntax/loc p
|
||||||
#t)]
|
#t)]
|
||||||
|
@ -2854,10 +2957,10 @@
|
||||||
;; The main implementation
|
;; The main implementation
|
||||||
(shared/proc stx make-check-cdr))))))
|
(shared/proc stx make-check-cdr))))))
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
;; Utilities for `define-struct':
|
;; Utilities for `define-struct':
|
||||||
|
|
||||||
(define (make-equal-hash generic-access field-count)
|
(define (make-equal-hash generic-access field-count)
|
||||||
(lambda (r recur)
|
(lambda (r recur)
|
||||||
(let loop ((i 0)
|
(let loop ((i 0)
|
||||||
(factor 1)
|
(factor 1)
|
||||||
|
@ -2868,7 +2971,7 @@
|
||||||
(* factor 33)
|
(* factor 33)
|
||||||
(+ hash (* factor (recur (generic-access r i)))))))))
|
(+ hash (* factor (recur (generic-access r i)))))))))
|
||||||
|
|
||||||
(define (make-equal2-hash generic-access field-count)
|
(define (make-equal2-hash generic-access field-count)
|
||||||
(lambda (r recur)
|
(lambda (r recur)
|
||||||
(let loop ((i 0)
|
(let loop ((i 0)
|
||||||
(factor 1)
|
(factor 1)
|
||||||
|
@ -2880,22 +2983,22 @@
|
||||||
(+ hash (* factor
|
(+ hash (* factor
|
||||||
(recur (generic-access r (- field-count i 1))))))))))
|
(recur (generic-access r (- field-count i 1))))))))))
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
;; Extend quote forms to work with `match':
|
;; Extend quote forms to work with `match':
|
||||||
|
|
||||||
(provide beginner-quote
|
(provide beginner-quote
|
||||||
intermediate-quote
|
intermediate-quote
|
||||||
intermediate-quasiquote)
|
intermediate-quasiquote)
|
||||||
|
|
||||||
(define-match-expander beginner-quote
|
(define-match-expander beginner-quote
|
||||||
(syntax-local-value #'beginner-quote/expr)
|
(syntax-local-value #'beginner-quote/expr)
|
||||||
(syntax-local-value #'beginner-quote/expr))
|
(syntax-local-value #'beginner-quote/expr))
|
||||||
|
|
||||||
(define-match-expander intermediate-quote
|
(define-match-expander intermediate-quote
|
||||||
(syntax-local-value #'intermediate-quote/expr)
|
(syntax-local-value #'intermediate-quote/expr)
|
||||||
(syntax-local-value #'intermediate-quote/expr))
|
(syntax-local-value #'intermediate-quote/expr))
|
||||||
|
|
||||||
(define-match-expander intermediate-quasiquote
|
(define-match-expander intermediate-quasiquote
|
||||||
;; Match expander:
|
;; Match expander:
|
||||||
(let ([qq (syntax-local-value #'intermediate-quasiquote/expr)])
|
(let ([qq (syntax-local-value #'intermediate-quasiquote/expr)])
|
||||||
(lambda (stx)
|
(lambda (stx)
|
||||||
|
@ -2932,7 +3035,7 @@
|
||||||
;; Expression expander:
|
;; Expression expander:
|
||||||
(syntax-local-value #'intermediate-quasiquote/expr))
|
(syntax-local-value #'intermediate-quasiquote/expr))
|
||||||
|
|
||||||
(define-match-expander the-cons/matchable
|
(define-match-expander the-cons/matchable
|
||||||
;; For match (no cdr check needed for deconstruction):
|
;; For match (no cdr check needed for deconstruction):
|
||||||
(lambda (stx)
|
(lambda (stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
|
@ -3095,4 +3198,4 @@
|
||||||
(or (boolean? x)
|
(or (boolean? x)
|
||||||
(property? x))))))
|
(property? x))))))
|
||||||
|
|
||||||
)
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user