#lang scheme
(require htdp/testing)
(require lang/htdp-advanced)
(provide (all-defined-out))
(require "data.scm")
(require "parser.scm")
(define (struct->defines str)
(let ((name (<definition-struct>-id str))
(fields (<definition-struct>-field-ids str)))
(append
(list (define-the-struct name)
(define-the-maker name fields)
(define-the-pred name))
(define-the-accs name fields))))
(check-expect
(struct->defines (parse-definition '(define-struct f (x y z))))
(map parse-definition
'((define f (make-structure-type 'f))
(define make-f (lambda (x y z) (make-structure f (vector x y z))))
(define f? (has-type? f))
(define f-x (struct-ref f 0))
(define f-y (struct-ref f 1))
(define f-z (struct-ref f 2)))))
(define (define-the-struct name)
(make-<definition-value>
name
(make-<application>
(make-<identifier> 'make-structure-type)
(list (make-<quote> name)))))
(check-expect (define-the-struct (parse-expr 'f))
(parse-definition '(define f (make-structure-type 'f))))
(define (define-the-maker name fields)
(make-<definition-value>
(id-prefix 'make- name)
(make-<lambda> fields
(make-<application>
(make-<identifier> 'make-structure)
(list
name
(make-<application> (make-<identifier> 'vector)
fields))))))
(check-expect (define-the-maker (parse-expr 'f) (map parse-expr '(x y z)))
(parse-definition
'(define make-f
(lambda (x y z) (make-structure f (vector x y z))))))
(define (define-the-pred name)
(make-<definition-value>
(id-suffix name '?)
(make-<application> (make-<identifier> 'has-type?)
(list name))))
(check-expect (define-the-pred (parse-expr 'f))
(parse-definition '(define f? (has-type? f))))
(define (define-the-accs name fields)
(map (lambda (f i)
(make-<definition-value>
(id-hyphen name f)
(make-<application> (make-<identifier> 'struct-ref)
(list name
(make-<number> i)))))
fields
(build-list (length fields) identity)))
(check-expect (define-the-accs (parse-expr 'f) (map parse-expr '(x y z)))
(map parse-definition
'((define f-x (struct-ref f 0))
(define f-y (struct-ref f 1))
(define f-z (struct-ref f 2)))))
(define (id-prefix sym id)
(make-<identifier>
(string->symbol
(string-append (symbol->string sym)
(symbol->string (<identifier>-symbol id))))))
(check-expect (id-prefix 'foo- (parse-expr 'bar))
(parse-expr 'foo-bar))
(define (id-suffix id sym)
(make-<identifier>
(string->symbol
(string-append (symbol->string (<identifier>-symbol id))
(symbol->string sym)))))
(check-expect (id-suffix (parse-expr 'foo-) 'bar)
(parse-expr 'foo-bar))
(define (id-hyphen id1 id2)
(id-prefix (<identifier>-symbol (id-suffix id1 '-)) id2))
(check-expect (id-hyphen (parse-expr 'foo) (parse-expr 'bar))
(parse-expr 'foo-bar))
(define-struct structure (type vals))
(define (make-structure-type sym) (lambda () sym))
(check-expect ((lambda (_) 'ok) ((make-structure-type 'foo)))
'ok)
(define (has-type? t)
(lambda (x)
(and (structure? x)
(eq? t (structure-type x)))))
(check-expect ((has-type? (make-structure-type 'foo))
(make-structure (make-structure-type 'foo) 'ignore))
false)
(check-expect (let ((f (make-structure-type 'foo)))
((has-type? f)
(make-structure f 'ignore)))
true)
(define (struct-ref t i)
(lambda (x)
(cond [((has-type? t) x) (vector-ref (structure-vals x) i)]
[else (error 'struct-ref "not a struct")])))
(check-expect (let ((f (make-structure-type 'foo)))
((struct-ref f 0) (make-structure f (vector 'x))))
'x)
(check-error (let ((f (make-structure-type 'foo)))
((struct-ref f 0) false))
"struct-ref: not a struct")
(generate-report)