;; This is 5-4-1.scm: uses class-decls, list-of-parts representation (let ((time-stamp "Time-stamp: <2000-12-13 16:19:57 wand>")) (eopl:printf "5-4-1.scm - simplest implementation of OOPL ~a~%" (substring time-stamp 13 29))) ;;;;;;;;;;;;;;;; classes ;;;;;;;;;;;;;;;; ;;; classes are represented by their class-decls. (define class? class-decl?) ; not used ;;;;;;;;;;;;;;;; objects ;;;;;;;;;;;;;;;; ;; an object is a list of parts. An part is a class-declaration and a ;; vector representing the managed storage for the fields of that class. (define-datatype part part? (a-part (class-name symbol?) (fields vector?))) (define new-object (lambda (class-name) (if (eqv? class-name 'object) '() (let ((c-decl (lookup-class class-name))) (cons (make-first-part c-decl) (new-object (class-decl->super-name c-decl))))))) (define make-first-part (lambda (c-decl) (a-part (class-decl->class-name c-decl) (make-vector (length (class-decl->field-ids c-decl)))))) ;;;;;;;;;;;;;;;; methods ;;;;;;;;;;;;;;;; ;;; methods are represented by their declarations. They are closed ;;; over their fields at application time, by apply-method. (define find-method-and-apply (lambda (m-name host-name self args) (if (eqv? host-name 'object) (eopl:error 'find-method-and-apply "No method for name ~s" m-name) (let ((m-decl (lookup-method-decl m-name (class-name->method-decls host-name)))) (if (method-decl? m-decl) (apply-method m-decl host-name self args) (find-method-and-apply m-name (class-name->super-name host-name) self args)))))) (define view-object-as (lambda (parts class-name) (if (eqv? (part->class-name (car parts)) class-name) parts (view-object-as (cdr parts) class-name)))) (define apply-method (lambda (m-decl host-name self args) (let ((ids (method-decl->ids m-decl)) (body (method-decl->body m-decl)) (super-name (class-name->super-name host-name))) (eval-expression body (extend-env (cons '%super (cons 'self ids)) (cons super-name (cons self args)) (build-field-env (view-object-as self host-name))))))) (define build-field-env (lambda (parts) (if (null? parts) (empty-env) (extend-env-refs (part->field-ids (car parts)) (part->fields (car parts)) (build-field-env (cdr parts)))))) ;;;;;;;;;;;;;;;; method environments ;;;;;;;;;;;;;;;; ;; find a method in a list of method-decls, else return #f (define lookup-method-decl (lambda (m-name m-decls) (cond ((null? m-decls) #f) ((eqv? m-name (method-decl->method-name (car m-decls))) (car m-decls)) (else (lookup-method-decl m-name (cdr m-decls)))))) ;;;;;;;;;;;;;;;; class environments ;;;;;;;;;;;;;;;; ;;; we'll just use the list of class-decls. (define the-class-env '()) (define elaborate-class-decls! (lambda (c-decls) (set! the-class-env c-decls))) (define lookup-class (lambda (name) (let loop ((env the-class-env)) (cond ((null? env) (eopl:error 'lookup-class "Unknown class ~s" name)) ((eqv? (class-decl->class-name (car env)) name) (car env)) (else (loop (cdr env))))))) ;;;;;;;;;;;;;;;; selectors of all sorts ;;;;;;;;;;;;;;;; (define part->class-name (lambda (prt) (cases part prt (a-part (class-name fields) class-name)))) (define part->fields (lambda (prt) (cases part prt (a-part (class-name fields) fields)))) (define part->field-ids (lambda (part) (class-decl->field-ids (part->class-decl part)))) (define part->class-decl (lambda (part) (lookup-class (part->class-name part)))) (define part->method-decls (lambda (part) (class-decl->method-decls (part->class-decl part)))) (define part->super-name (lambda (part) (class-decl->super-name (part->class-decl part)))) (define class-name->method-decls (lambda (class-name) (class-decl->method-decls (lookup-class class-name)))) (define class-name->super-name (lambda (class-name) (class-decl->super-name (lookup-class class-name)))) (define object->class-name (lambda (parts) (part->class-name (car parts))))