; This is 5-4-3.scm: class- and method- structs (let ((time-stamp "Time-stamp: <2000-12-13 16:24:08 wand>")) (eopl:printf "5-4-3.scm - class and method structs ~a~%" (substring time-stamp 13 29))) ;;;;;;;;;;;;;;;; classes ;;;;;;;;;;;;;;;; (define-datatype class class? (a-class (class-name symbol?) (super-name symbol?) (field-length integer?) (field-ids (list-of symbol?)) (methods method-environment?))) ;;;; constructing classes (define elaborate-class-decls! (lambda (c-decls) (initialize-class-env!) (for-each elaborate-class-decl! c-decls))) (define elaborate-class-decl! (lambda (c-decl) (let ((super-name (class-decl->super-name c-decl))) (let ((field-ids (append (class-name->field-ids super-name) (class-decl->field-ids c-decl)))) (add-to-class-env! (a-class (class-decl->class-name c-decl) super-name (length field-ids) field-ids (roll-up-method-decls c-decl super-name field-ids))))))) (define roll-up-method-decls (lambda (c-decl super-name field-ids) (map (lambda (m-decl) (a-method m-decl super-name field-ids)) (class-decl->method-decls c-decl)))) ;^;;;;;;;;;;;;;;; objects ;;;;;;;;;;;;;;;; ;^; an object is now just a single part, with a vector representing the ;^; managed storage for the all the fields. (define-datatype object object? (an-object (class-name symbol?) (fields vector?))) (define new-object (lambda (class-name) (an-object class-name (make-vector (class-name->field-length class-name))))) ;\new1 ;^;;;;;;;;;;;;;;; methods ;;;;;;;;;;;;;;;; (define-datatype method method? (a-method (method-decl method-decl?) (super-name symbol?) (field-ids (list-of symbol?)))) (define find-method-and-apply (lambda (m-name host-name self args) (let loop ((host-name host-name)) (if (eqv? host-name 'object) (eopl:error 'find-method-and-apply "No method for name ~s" m-name) (let ((method (lookup-method m-name ;^ m-decl -> method (class-name->methods host-name)))) (if (method? method) (apply-method method host-name self args) (loop (class-name->super-name host-name)))))))) (define apply-method (lambda (method host-name self args) ;\new5 (let ((ids (method->ids method)) (body (method->body method)) (super-name (method->super-name method)) (field-ids (method->field-ids method)) (fields (object->fields self))) (eval-expression body (extend-env (cons '%super (cons 'self ids)) (cons super-name (cons self args)) (extend-env-refs field-ids fields (empty-env))))))) (define rib-find-position (lambda (name symbols) (list-find-last-position name symbols))) ;;;;;;;;;;;;;;;; method environments ;;;;;;;;;;;;;;;; (define method-environment? (list-of method?)) (define lookup-method (lambda (m-name methods) (cond ((null? methods) #f) ((eqv? m-name (method->method-name (car methods))) (car methods)) (else (lookup-method m-name (cdr methods)))))) ;;;;;;;;;;;;;;;; class environments ;;;;;;;;;;;;;;;; ;;; we'll just use the list of classes (not class decls) (define the-class-env '()) (define initialize-class-env! (lambda () (set! the-class-env '()))) (define add-to-class-env! (lambda (class) (set! the-class-env (cons class the-class-env)))) (define lookup-class (lambda (name) (let loop ((env the-class-env)) (cond ((null? env) (eopl:error 'lookup-class "Unknown class ~s" name)) ((eqv? (class->class-name (car env)) name) (car env)) (else (loop (cdr env))))))) ;;;;;;;;;;;;;;;; selectors ;;;;;;;;;;;;;;;; (define class->class-name (lambda (c-struct) (cases class c-struct (a-class (class-name super-name field-length field-ids methods) class-name)))) (define class->super-name (lambda (c-struct) (cases class c-struct (a-class (class-name super-name field-length field-ids methods) super-name)))) (define class->field-length (lambda (c-struct) (cases class c-struct (a-class (class-name super-name field-length field-ids methods) field-length)))) (define class->field-ids (lambda (c-struct) (cases class c-struct (a-class (class-name super-name field-length field-ids methods) field-ids)))) (define class->methods (lambda (c-struct) (cases class c-struct (a-class (class-name super-name field-length field-ids methods) methods)))) (define object->class-name (lambda (obj) (cases object obj (an-object (class-name fields) class-name)))) (define object->class-name (lambda (obj) (cases object obj (an-object (class-name fields) class-name)))) (define object->fields (lambda (obj) (cases object obj (an-object (class-decl fields) fields)))) (define object->class-decl (lambda (obj) (lookup-class (object->class-name obj)))) (define object->field-ids (lambda (object) (class->field-ids (object->class-decl object)))) (define class-name->super-name (lambda (class-name) (class->super-name (lookup-class class-name)))) (define class-name->field-ids (lambda (class-name) (if (eqv? class-name 'object) '() (class->field-ids (lookup-class class-name))))) (define class-name->methods (lambda (class-name) (if (eqv? class-name 'object) '() (class->methods (lookup-class class-name))))) (define class-name->field-length (lambda (class-name) (if (eqv? class-name 'object) 0 (class->field-length (lookup-class class-name))))) (define method->method-decl (lambda (meth) (cases method meth (a-method (meth-decl super-name field-ids) meth-decl)))) (define method->super-name (lambda (meth) (cases method meth (a-method (meth-decl super-name field-ids) super-name)))) (define method->field-ids (lambda (meth) (cases method meth (a-method (method-decl super-name field-ids) field-ids)))) (define method->method-name (lambda (method) (method-decl->method-name (method->method-decl method)))) (define method->body (lambda (method) (method-decl->body (method->method-decl method)))) (define method->ids (lambda (method) (method-decl->ids (method->method-decl method))))