(define (new-object class-object . initializer-fields)
(if (kappa? class-object)
(let* ((initializer-field-alist-from-class (class-fields-alist class-object))
(obj (apply make-object (alist-to-propertylist (cons (cons '$instance-of class-object) (filter (negate function-field?) initializer-field-alist-from-class)))))
)
(for-each
(lambda (field-key-val-pair)
(set-field! obj (car field-key-val-pair) (cdr field-key-val-pair) ))
(propertylist-to-alist initializer-fields))
obj
)
(error "Cannot instantiate non-class objects")))
(define (make-object . parameters)
(if (null? parameters)
(cons 'object (cons"" '()))
(let ((first-par (car parameters)))
(if (string? first-par)
(let* ((role-name first-par)
(fields (cdr parameters))
(role-class-rel (assoc role-name role-class-mapping)))
(if role-class-rel
(apply new-object (cons (cdr role-class-rel) fields))
(let ((obj (cons 'object (cons role-name (propertylist-to-alist fields)))))
(insert-object-with-role! obj role-name)
obj)
)
)
(let ((fields parameters))
(cons 'object (cons "" (propertylist-to-alist fields))))))))
(define (object-fields-alist object)
(if (asl-object? object)
(cdr (cdr object))
(error "The first parameter must be an object")))
(define (object-data-fields-alist object)
(filter (lambda (field-pair) (and (not (internal-field? field-pair)) (not (function-field? field-pair))))
(object-fields-alist object)))
(define (object-method-fields-alist object)
(filter (lambda (field-pair) (and (not (internal-field? field-pair)) (function-field? field-pair)))
(object-fields-alist object)))
(define (set-fields-of-objects-low-level! object new-field-alist)
(set-cdr! (cdr object) new-field-alist)
)
(define (as-object ass-array)
(if (asl-object? ass-array)
ass-array
(apply make-object (alist-to-propertylist ass-array))
)
)
(define (make-class . parameters)
(cond ((null? parameters)
(apply make-object (cons '$kind (cons 'class '()))))
((kappa? (first parameters))
(apply make-object (cons '$kind (cons 'class (cons '$superclass (cons (first parameters) (cdr parameters)))))))
(else
(apply make-object (cons '$kind (cons 'class parameters))))))
(define (single-kappa object)
(if (kappa? object)
(laml-error "It is illegal to apply kappa on a class object")
(apply make-class (object-property-list object)))
)
(define problem-object #f)
(define (check-sufficient-fields-in! objects field-name-list)
(set! problem-object #f)
(for-each
(lambda (object)
(let ((object-data-fields (object-data-fields-alist object)))
(if (not (subset-of-by-predicate field-name-list object-data-fields (lambda (name pair) (eq? name (car pair)))))
(begin
(set! problem-object object)
(laml-error "Insuffient data fields in object. Inspect the problem object with (inspect problem-object)")))))
objects))
(define (kappa . objects)
(multi-kappa objects))
(define (multi-kappa objects)
(if (null? objects) (laml-error "At least one object must be supplied to multi-kappa"))
(cond ((equal? (map kappa? objects) (make-list (length objects) #t))
(let ((class (apply make-class '())))
(for-each (lambda (object) (as-instance-of-class! object class)) objects)
class)
)
((equal? (map kappa? objects) (make-list (length objects) #f))
(check-sufficient-fields-in! objects (map car (object-data-fields-alist (first objects))))
(let ((class (apply make-class
(alist-to-propertylist
(append
(object-data-fields-alist (car objects))
(remove-duplicates-by-predicate
(flatten
(map object-method-fields-alist objects))
(lambda (m1 m2)
(eq? (car m1) (car m2)))
)
)))))
(for-each (lambda (object) (as-instance-of-class! object class)) objects)
(let ((roles (remove-duplicates (filter (negate empty-string?) (map object-role objects)))))
(if (= (length roles) 1)
(map-role-to-class! (car roles) class)))
class)
)
(else
(error "It is not possible to derive a class from a mixed set of non-class and class objects"))))
(define (add-member-old! object field-name field-value)
(let ((field-value-1 (if (function? field-value)
field-value
field-value)))
(if (asl-object? object)
(begin
(if (member field-name (map car (object-fields-alist object)))
(delete-member! object field-name))
(let ((last-pair (last-cons-cell (object-fields-alist object))))
(set-cdr! last-pair
(cons
(cons field-name field-value-1)
'()))
))
(error "The first parameter must be an object"))))
(define (add-member! object field-name field-value)
(cond ((object-with-class? object)
(let ((class (class-of object)))
(if (function? field-value)
(if (or (and (field-exists? class field-name) (function? (get-field class field-name))
(= (length (formal-parameters-of-function field-value)) (length (formal-parameters-of-function (get-field class field-name)))))
(and (getter-name? field-name) (field-exists? class (field-name-of-getter field-name)))
(and (setter-name? field-name) (field-exists? class (field-name-of-setter field-name)))
)
(begin
(if (member field-name (map car (object-fields-alist object)))
(delete-member! object field-name))
(let ((last-pair (last-cons-cell (object-fields-alist object))))
(set-cdr! last-pair
(cons
(cons field-name field-value)
'()))
))
(error "It is only possible to add a method to an instance of a class if the method is compatible with a method in the class (both methods have the same number of parameters)"))
(error "It is not possible to add a data member to an instance of class. Consider adding the member to the class as such."))))
((object-without-class? object)
(begin
(if (member field-name (map car (object-fields-alist object)))
(delete-member! object field-name))
(let ((last-pair (last-cons-cell (object-fields-alist object))))
(set-cdr! last-pair
(cons
(cons field-name field-value)
'()))
)))
(else (error "The first parameter must be an object"))))
(define (delete-member-old! object field-name)
(if (asl-object? object)
(if (field-exists? object field-name)
(begin
(set-fields-of-objects-low-level! object
(filter (lambda (pair) (not (eq? field-name (car pair)))) (object-fields-alist object))))
(error "Trying to delete non-existing field:" field-name))
(error "The first parameter must be an object")))
(define (delete-member! object field-name)
(if (asl-object? object)
(cond
((object-with-class? object)
(let ((class (class-of object)))
(if (field-exists-in-class? class field-name)
(if (field-exists? object field-name)
(begin
(set-fields-of-objects-low-level! object
(filter (lambda (pair) (not (eq? field-name (car pair)))) (object-fields-alist object))))
(error "Trying to delete non-existing field from an instance of class:" field-name))
(error "You cannot delete a field from an instance of a class C, where C does not contain the field."))))
((object-without-class? object)
(if (field-exists? object field-name)
(begin
(set-fields-of-objects-low-level! object
(filter (lambda (pair) (not (eq? field-name (car pair)))) (object-fields-alist object))))
(error "Trying to delete non-existing field:" field-name)))
(else (error "Should not happen")))
(error "The first parameter must be an object")))
(define (get-field object field-name)
(cond ((object-with-class? object)
(let ((class (class-of object)))
(if (field-exists-in-class? class field-name)
(if (field-exists? object field-name)
(if (field-exists-raw? object field-name)
(get field-name (object-fields-alist object))
(if (field-exists-raw? root-object field-name)
(get field-name (object-fields-alist root-object))
(error (string-append "Attempting to get the value of a non-existing field: " (as-string field-name)))))
(get-field class field-name)
)
(error (string-append "Attempting to get a field " (as-string field-name) " from an instance of class, where the class does not prescribe the field: "))))
)
((object-without-class? object)
(if (field-exists-raw? object field-name)
(get field-name (object-fields-alist object))
(if (field-exists-raw? root-object field-name)
(get field-name (object-fields-alist root-object))
(error (string-append "Attempting to get the value of a non-existing field: " (as-string field-name))))))
((kappa? object)
(get-field-in-class object field-name))
((and (boolean? object) (not object))
(eval-expr field-name '()))
(else (error "get-field should be activated on an object"))))
(define (set-field! object field-name field-value)
(cond ((object-with-class? object)
(let ((class (class-of object)))
(if (field-exists-in-class? class field-name)
(if (field-exists? object field-name)
(a-set! (object-fields-alist object) field-name field-value)
(forced-add-member-low-level object field-name field-value)
)
(error "It is not possible to set the value of field, which is not prescribed in the class of the object")
)
)
)
((object-without-class? object)
(if (field-exists? object field-name)
(begin
(a-set! (object-fields-alist object) field-name field-value)
)
(error "Cannot set the value of a non-existing field.")))
(else (error "set-field! must be activated on an object"))))
(define borrow-methods-from-objects-of-same-role? #t)
(define this-object #f)
(define this-object-stack '())
(define (send object selector . actual-parameters)
(dynamic-wind
(lambda ()
(if (asl-object? this-object)
(set! this-object-stack (cons this-object this-object-stack)))
(set! this-object object))
(lambda ()
(cond ((and (asl-object? object) (not (kappa? object)))
(let* ((obj-method (if (field-exists-in-object-non-class? object selector) (get-field-in-object-non-class object selector) #f))
(class-of-object (if (field-exists-raw? object '$instance-of) (get-field-raw object '$instance-of) #f))
(class-method (if class-of-object (if (field-exists-in-class? class-of-object selector) (get-field-in-class class-of-object selector) #f) #f))
)
(cond
((and obj-method (function? obj-method))
(call-method obj-method actual-parameters))
((and class-of-object class-method (function? class-method))
(call-method class-method actual-parameters))
((and borrow-methods-from-objects-of-same-role? (not (empty-string? (object-role object))))
(let ((borrowed-method (borrow-method-from-objects-of-same-role (object-role object) selector)))
(if (and borrowed-method (function? borrowed-method))
(call-method borrowed-method actual-parameters)
(attempt-getting-or-setting object selector actual-parameters))))
((or (and (getter-name? selector) (or (data-field? object (field-name-of-getter selector)) (data-field? class-of-object (field-name-of-getter selector))))
(and (setter-name? selector) (or (data-field? object (field-name-of-setter selector)) (data-field? class-of-object (field-name-of-getter selector)))))
(attempt-getting-or-setting object selector actual-parameters))
(else
(error (string-append "No appropriate method with selector " (as-string selector))))
)))
((kappa? object)
(let ((class-obj-method (if (field-exists-in-object-class? object selector)
(get-field-in-class object selector)
#f))
(class-of-object (if (field-exists-raw? object '$instance-of) (get-field-raw object '$instance-of) #f))
)
(cond
((and class-obj-method (function? class-obj-method))
(call-method class-obj-method actual-parameters))
(class-of-object
(let ((class-method (if (field-exists-in-class? class-of-object selector) (get-field-in-class class-of-object selector) #f)))
(if class-method
(call-method class-method actual-parameters)
(error (string-append "No appropriate method with selector " (as-string selector)))))
(error (string-append "No appropriate method with selector " (as-string selector))))
((or (and (getter-name? selector) (data-field? object (field-name-of-getter selector)))
(and (setter-name? selector) (data-field? object (field-name-of-setter selector))))
(attempt-getting-or-setting object selector actual-parameters))
(else
(error (string-append "No appropriate method with selector " (as-string selector))))
)
)
)))
(lambda ()
(if (not (null? this-object-stack))
(begin
(set! this-object (car this-object-stack))
(set! this-object-stack (cdr this-object-stack)))
(set! this-object #f)))
)
)
(define (attempt-getting-or-setting object selector actual-parameters)
(cond
((and (getter-name? selector) (data-field? object (field-name-of-getter selector)) (= (length actual-parameters) 0))
(get-field object (field-name-of-getter selector)))
((and (getter-name? selector) (object-with-class? object) (data-field? (class-of object) (field-name-of-getter selector)) (= (length actual-parameters) 0))
(get-field object (field-name-of-getter selector)))
((and (setter-name? selector) (data-field? object (field-name-of-setter selector)) (= (length actual-parameters) 1))
(set-field! object (field-name-of-setter selector) (car actual-parameters)))
((and (setter-name? selector) (object-with-class? object) (data-field? (class-of object) (field-name-of-setter selector)) (= (length actual-parameters) 1))
(set-field! object (field-name-of-setter selector) (car actual-parameters)))
((and (setter-name? selector) (not (= (length actual-parameters) 1)))
(error "A setter method must have exactly one actual parameter."))
(else (error (string-append "No appropriate method with selector " (as-string selector) )))))
(define (setter-name? selector-symbol)
(let ((selector-string (as-string selector-symbol)))
(if (> (string-length selector-string) 4)
(equal? (substring selector-string 0 4) "set-")
#f)))
(define (getter-name? selector-symbol)
(let ((selector-string (as-string selector-symbol)))
(if (> (string-length selector-string) 4)
(equal? (substring selector-string 0 4) "get-")
#f)))
(define (getter-name field-name)
(as-symbol (string-append "get" "-" (as-string field-name))))
(define (setter-name field-name)
(as-symbol (string-append "set" "-" (as-string field-name))))
(define (field-name-of-setter selector)
(let ((selector-string (as-string selector)))
(as-symbol (substring selector-string 4))))
(define (field-name-of-getter selector)
(let ((selector-string (as-string selector)))
(as-symbol (substring selector-string 4))))
(define (call-method method actual-parameters)
(if (not (function? method)) (error "The selected field exists, but it is not a function"))
(apply-function method actual-parameters))
(define (send-super object selector . actual-parameters)
(dynamic-wind
(lambda ()
(if (asl-object? this-object)
(set! this-object-stack (cons this-object this-object-stack)))
(set! this-object object))
(lambda ()
(cond ((and (asl-object? object) (not (kappa? object)))
(let ((obj-method (if (field-exists-raw? root-object selector) (get-field-raw root-object selector) #f)))
(if obj-method
(call-method obj-method actual-parameters)
(let* ((class-of-object (if (field-exists-raw? object '$instance-of) (get-field-raw object '$instance-of) #f))
(superclass-of-object (superclass-of class-of-object)))
(if class-of-object
(let ((class-method (if (field-exists-in-class? superclass-of-object selector) (get-field-in-class superclass-of-object selector) #f)))
(if class-method
(call-method class-method actual-parameters)
(error (string-append "No appropriate method with selector " (as-string selector)))))
(error (string-append "No appropriate method with selector " (as-string selector)))))
)))
((kappa? object)
(let ((class-obj-method (if (field-exists-in-object-class? class-object selector) (get-field-in-object-class class-object selector) #f)))
(if class-obj-method
(call-method class-obj-method actual-parameters)
(let* ((class-of-object (if (field-exists-raw? object '$instance-of) (get-field-raw object '$instance-of) #f))
(superclass-of-object (superclass-of class-of-object)))
(if class-of-object
(let ((class-method (if (field-exists-in-class? superclass-of-object selector) (get-field-in-class superclass-of-object selector) #f)))
(if class-method
(call-method class-method actual-parameters)
(error (string-append "No appropriate method with selector " (as-string selector)))))
(error (string-append "No appropriate method with selector " (as-string selector)))))
)))))
(lambda ()
(if (not (null? this-object-stack))
(begin
(set! this-object (car this-object-stack))
(set! this-object-stack (cdr this-object-stack)))
(set! this-object #f)))
)
)
(define (clone-object obj . initializer-fields)
(if (asl-object? obj)
(let ((new-object (as-object (object-fields-alist obj)))
)
(for-each
(lambda (field-key-val-pair)
(set-field! new-object (car field-key-val-pair) (cdr field-key-val-pair) ))
(propertylist-to-alist initializer-fields))
new-object)
(error "Cannot clone a non-object")))
(define (as-instance-of-class! object class)
(if (kappa? object)
(error "The first parameter is not supposed to be a class"))
(if (not (kappa? class))
(error "The second parameter must be a class"))
(cond
((eq? class (class-of object))
object)
((subset-of-by-predicate (member-names-of object) (map car (class-fields-alist class)) eq?)
(forced-add-member-low-level object '$instance-of class)
(let ((method-names-in-object
(map name-of-field (filter (lambda (f) (function? (value-of-field f))) (object-fields-alist object)))))
(for-each (lambda (method-name)
(if (field-exists? object method-name)
(delete-member! object method-name)))
method-names-in-object))
)
(else (error "The object does not conform with the class. One or more members of the object is not present in the class.")))
)
(define (as-independent-object! object)
(if (object-with-class? object)
(let ((class (class-of object)))
(for-each
(lambda (data-field)
(if (not (field-exists-raw? object (name-of-field data-field)))
(forced-add-member-low-level object (name-of-field data-field) (value-of-field data-field))))
(filter (negate function-field?) (class-fields-alist class))
)
(for-each
(lambda (method-field)
(if (not (field-exists-raw? object (name-of-field method-field)))
(forced-add-member-low-level object (name-of-field method-field) (value-of-field method-field))))
(filter function-field? (class-fields-alist class #t))
)
(forced-delete-member-low-level object '$instance-of)
)
object))
(define (as-instance-of-class-old! object class)
(if (kappa? object)
(error "The first parameter is not supposed to be a class"))
(if (not (kappa? class))
(error "The second parameter must be a class"))
(cond
((eq? class (class-of object))
object)
((subset-of-by-predicate (data-field-names-of class) (data-field-names-of object) eq?)
(add-member! object '$instance-of class)
(let ((method-names-in-class
(map name-of-field (filter (lambda (f) (function? (value-of-field f))) (class-fields-alist class)))))
(for-each (lambda (method-name)
(if (field-exists? object method-name)
(delete-member! object method-name)))
method-names-in-class))
)
(else (error "Some data fields in the class are not present in the object.")))
)
(define (generalize class-list member-names)
(generalize-multiple-classes-from-list! class-list member-names)
)
(define (generalize-from-list! class member-names)
(laml-error "Use generalize!")
(generalize-multiple-classes-from-list! (list class) member-names))
(define (generalize-multiple-classes! class-list . member-names)
(laml-error "Use generalize!")
(generalize-multiple-classes-from-list! class-list member-names))
(define (generalize-multiple-classes-from-list! class-list member-names)
(if (all-true (lambda (class) (kappa? class)) class-list)
(if (not (all-true (lambda (class) (field-exists? class '$superclass)) class-list))
(let ((first-class (if (not (null? class-list)) (first class-list) #f))
(new-superclass (apply make-class '())))
(for-each (lambda (class)
(add-member! class '$superclass new-superclass)
(let ((class-member-pairs (object-fields-alist class)))
(add-member! class '$superclass new-superclass)
(for-each (lambda (m)
(let ((member-name (car m))
(member-value (cdr m)))
(if (member member-name member-names)
(begin
(delete-member! class member-name)
(if (not (function-value? member-value))
(if (eq? class first-class)
(begin
(add-member! new-superclass member-name member-value)))
(begin
(add-member! new-superclass member-name member-value)))
)
)
)
)
class-member-pairs)
))
class-list)
new-superclass
)
(error "Cannot generalize a class which already has a superclass field"))
(error "Can only generalize class objects")))
(define (and-fn x y)
(and x y))
(define (all-true p lst)
(accumulate-right and-fn #t (map p lst)))
(define (specialize class . fields)
(if (kappa? class)
(apply make-class (cons class fields))
(error "Can only specialize class objects")))
(define (flatten-class class)
(apply make-class (alist-to-propertylist (class-fields-alist class))))
(define (class-of obj)
(let* ((fields (object-fields-alist obj))
(internal-instance-of-field (assq '$instance-of fields)))
(if internal-instance-of-field
(cdr internal-instance-of-field)
#f)))
(define (superclass-of class-obj)
(let* ((fields (object-fields-alist class-obj))
(superclass-pair (assq '$superclass fields)))
(if superclass-pair
(cdr superclass-pair)
class-object)))
(define (object-role object)
(if (asl-object? object)
(cadr object)
(error "The first parameter must be an object")))
(define (asl-object? x)
(and (list? x)
(>= (length x) 1)
(eq? (car x) 'object)))
(define (object-without-class? x)
(and (asl-object? x)
(not (field-exists-raw? x '$instance-of))))
(define (object-with-class? x)
(and (asl-object? x)
(field-exists-raw? x '$instance-of)))
(define (kappa? x)
(and (asl-object? x)
(field-exists-raw? x '$kind)
(eq? 'class (get-field-raw x '$kind))))
(define (instance-of? object class)
(let ((obj-fields (map car (object-fields-alist object)))
(class-fields (map car (object-fields-alist class))))
(subset-of-by-predicate obj-fields class-fields eq?)
)
)
(define (get-field-in-class class field-name)
(cond ((kappa? class)
(if (field-exists-in-class? class field-name)
(get field-name (class-fields-alist class))
(error (string-append "Attempting to get the value of a non-existing field of a class: " (as-string field-name)))))
(else (error "get-field should be activated on a class object"))))
(define (get-field-in-object-class object field-name)
(if (field-exists-raw? object field-name)
(get field-name (object-fields-alist object))
(if (field-exists-raw? class-object field-name)
(get field-name (object-fields-alist class-object))
(if (field-exists-raw? root-object field-name)
(get field-name (object-fields-alist root-object))
(error (string-append "Attempting to get the value of a non-existing field: " (as-string field-name)))))))
(define (get-field-in-object-non-class object field-name)
(if (field-exists-raw? object field-name)
(get field-name (object-fields-alist object))
(if (field-exists-raw? root-object field-name)
(get field-name (object-fields-alist root-object))
(error (string-append "Attempting to get the value of a non-existing field: " (as-string field-name))))))
(define (data-field? object field-name)
(if (internal-field-name? field-name)
#f
(if (field-exists? object field-name)
(let ((val (get-field object field-name)))
(not (function? val)))
#f)))
(define (field-exists? object field)
(cond ((asl-object? object)
(let ((exists-in-object? (field-exists-raw? object field)))
(if exists-in-object?
exists-in-object?
(field-exists-raw? root-object field))))
(error "The first parameter must be an object")))
(define (field-exists-in-general? object field-name)
(cond ((object-with-class? object)
(let ((class (class-of object)))
(field-exists-in-class? class field-name))
)
((object-without-class? object)
(if (field-exists-raw? object field-name)
#t
(field-exists-raw? root-object field-name)))
((kappa? object)
(field-exists-in-class? object field-name))
(else (error "get-field should be activated on an object"))))
(define (field-exists-in-object-non-class? object field)
(let ((exists-in-object? (field-exists-raw? object field)))
(if exists-in-object?
exists-in-object?
(field-exists-raw? root-object field))))
(define (field-exists-in-class? class field)
(if (kappa? class)
(turn-into-boolean (find-in-list (lambda (pair) (eq? (car pair) field)) (class-fields-alist class)))
(error "The first parameter must be a class object")))
(define (field-exists-in-object-class? object field)
(let ((exists-in-object? (field-exists-raw? object field)))
(if exists-in-object?
exists-in-object?
(if (field-exists-in-explicit-superclasses-of object field)
#t
(let ((exists-in-class? (field-exists-raw? class-object field)))
(if exists-in-class?
exists-in-class?
(field-exists-raw? root-object field)))))))
(define (field-exists-in-explicit-superclasses-of class-object field)
(if (assq '$superclass (object-fields-alist class-object))
(let ((super-class-object (superclass-of class-object)))
(if (field-exists-raw? super-class-object field)
#t
(field-exists-in-explicit-superclasses-of super-class-object field)
)
)
#f))
(define (forced-add-member-low-level object field-name field-value)
(let ((last-pair (last-cons-cell (object-fields-alist object))))
(set-cdr! last-pair
(cons
(cons field-name field-value)
'()))))
(define (forced-delete-member-low-level object field-name)
(let ((a-list (object-fields-alist object)))
(set-fields-of-objects-low-level! object
(remove-associations (list field-name) a-list))))
(define (function-field? f)
(and (pair? f)
(function-value? (cdr f))))
(define (function-value? x)
(and (pair? x)
(list? x)
(= (length x) 4)
(eq? (car x) 'function)))
(define (inspect-old object)
(if (function? object)
(display-message (as-string object))
(let* ((class? (kappa? object))
(fields (remove-internal-fields (object-fields-alist object)))
(has-superclass? (if class? (field-exists-raw? object '$superclass) #f)))
(display-message (if class?
(if has-superclass? (string-append "A class with superclass: " (short-class-inspect-string (flatten-class (get-field-raw object '$superclass)))) "A class without a given superclass")
"An non-class object"))
(for-each (lambda (pair)
(display-message
" "
(as-string (car pair)) ": "
(cond ((kappa? (cdr pair)) (short-class-inspect-string (flatten-class (cdr pair))))
((asl-object? (cdr pair)) "<Object>")
((function? (cdr pair)) (string-append "Function" (as-string (formal-parameters-of-function (cdr pair))) "..."))
(else (as-string (cdr pair))))
)
)
fields))))
(define (inspect-member-of-object in-object member-pair . optional-parameters)
(let ((indentation (optional-parameter 1 optional-parameters 0))
(show-automatic-getters-setters (optional-parameter 2 optional-parameters #t))
(member-name (car member-pair))
(member-value (cdr member-pair))
)
(display-message
(string-append
(make-string indentation #\space) (as-string member-name) ": "
(cond ((kappa? member-value) (short-class-inspect-string (flatten-class member-value)))
((asl-object? member-value)
(let* ((object member-value)
(obj-role (object-role object))
)
(if (empty-string? obj-role)
"<Object>"
(string-append "<" obj-role " " "Object>"))))
((function? member-value) (string-append "Function" (as-string (formal-parameters-of-function member-value)) "..."))
(else (as-string member-value)))))
(if (and show-automatic-getters-setters (not (function? member-value)))
(let ((getter-name (getter-name member-name))
(setter-name (setter-name member-name))
)
(if (not (field-exists? in-object getter-name))
(display-message
(string-append
(make-string indentation #\space) (as-string getter-name) ": " "Automatic getter")))
(if (not (field-exists? in-object setter-name))
(display-message
(string-append
(make-string indentation #\space) (as-string setter-name) ": " "Automatic setter")))))))
(define (inspect object . optional-parameters)
(let ((variation (optional-parameter 1 optional-parameters 'short)))
(cond ((function? object) (display-message (as-string object)))
((and (object-without-class? object) (not (kappa? object)))
(let ((role (object-role object)))
(if (empty-string? role)
(display-message "An object without a class:")
(display-message "An object of role" role "without a class:")))
(for-each (lambda (member-pair)
(inspect-member-of-object object member-pair 2))
(append (remove-internal-fields (object-fields-alist object))
(if (eq? variation 'full) (remove-internal-fields (object-fields-alist root-object)) '()))))
((and (asl-object? object) (not (kappa? object)))
(display-message "An instance of a class")
(display-message " Instance members:")
(for-each (lambda (member-pair)
(inspect-member-of-object object member-pair 4 #f))
(remove-internal-fields (append (object-fields-alist object)
(if (eq? variation 'full) (object-fields-alist root-object) '()))
(list '$superclass '$kind '$instance-of)))
(display-message " Class members:")
(for-each (lambda (member-pair)
(inspect-member-of-object object member-pair 4))
(remove-internal-fields (class-fields-alist (class-of object)
(if (eq? variation 'full) 'class #f)))))
((and (asl-object? object) (kappa? object))
(display-message "A class object")
(for-each (lambda (member-pair)
(inspect-member-of-object object member-pair 4))
(remove-internal-fields (object-fields-alist object)
(list '$superclass '$kind '$instance-of)))
(if (assq '$superclass (object-fields-alist object))
(let ((super-class (superclass-of object)))
(display-message "From superclass:")
(for-each (lambda (member-pair)
(inspect-member-of-object object member-pair 4))
(remove-internal-fields (class-fields-alist super-class (if (eq? variation 'full) 'object #t))))))
)
((and (asl-object? object) (kappa? object))
(display-message "A class object")
(for-each (lambda (member-pair)
(inspect-member-of-object object member-pair 4))
(remove-internal-fields (class-fields-alist object (if (eq? variation 'full) 'object #t)))))
(else object))))
(define (short-class-inspect-string class-obj)
(let* ((fields (object-fields-alist class-obj))
(non-internal-fields (filter (negate internal-field?) fields)))
(string-append
"A class with the fields: " (string-append CR " ")
(list-to-string
(map-bites
(bite-of-length 5)
(lambda (bite)
(list (list-to-string bite ", ")))
(map (compose as-string car) non-internal-fields)
)
(string-append CR " ")
)
)
)
)
(define (internal-field? pair)
(let ((name (as-string (car pair))))
(internal-field-name? name)))
(define (internal-field-name? name)
(let ((name-str (as-string name)))
(if (>= (string-length name-str) 1)
(eqv? #\$ (string-ref name-str 0))
#f)))
(define-syntax function
(syntax-rules ()
((function formal-parameters body-form ...)
(make-function (quote formal-parameters) (quote (begin body-form ...)) '()))))
(define (make-function formal-parameter-list expression environment)
(list 'function formal-parameter-list expression environment)
)
(define (function? x)
(and (list? x)
(= (length x) 4)
(eq? (car x) 'function)))
(define (expression-of-function function) (third function))
(define (formal-parameters-of-function function) (second function))
(define (environment-of-function function) (fourth function))
(define (refurnish-function function-object env)
(make-function
(formal-parameters-of-function function-object)
(expression-of-function function-object)
env))
(define (apply-function function-object actual-parameter-list)
(if (function? function-object)
(eval-expr (expression-of-function function-object)
(append (pair-up-parameters-in-function-application (formal-parameters-of-function function-object) actual-parameter-list) (environment-of-function function-object)))
(error "Apply-function needs a function object as the first parameter")))
(define (pair-up-parameters-in-function-application formal-parameters actual-parameter-list)
(cond ((symbol? formal-parameters) (list (cons formal-parameters actual-parameter-list)))
((and (null? formal-parameters) (null? actual-parameter-list)) '())
((and (pair? formal-parameters) (pair? actual-parameter-list) (symbol? (car formal-parameters)))
(cons
(cons (car formal-parameters) (car actual-parameter-list))
(pair-up-parameters-in-function-application (cdr formal-parameters) (cdr actual-parameter-list))))
((and (pair? formal-parameters) (null? actual-parameter-list))
(error "Insufficient number of actual parameters"))
((and (null? formal-parameters))
(error "Insufficient number of formal parameters"))
(else (error "Malformed formal or actual parameter list"))))
(define eval-expr #f)
(let ()
(define primitive-environment
`((+ . ,+) (- . ,-) (* . ,*) (/ . ,/) (= . ,=) (>= . ,>=) (<= . ,<=) (> . ,>) (< . ,<)
(string-append . ,string-append)
(apply . ,apply) (assq . ,assq) (call/cc . ,call-with-current-continuation)
(car . ,car) (cadr . ,cadr) (caddr . ,caddr)
(cadddr . ,cadddr) (cddr . ,cddr) (cdr . ,cdr)
(cons . ,cons) (eq? . ,eq?) (list . ,list)
(map . ,map) (memv . ,memv) (null? . ,null?)
(pair? . ,pair?) (read . ,read) (set-car! . ,set-car!)
(set-cdr! . ,set-cdr!) (symbol? . ,symbol?)
(clone-object . ,clone-object)
(sqrt . ,sqrt) (square . ,(lambda (x) (* x x)))
(get-field . ,get-field) (set-field! . ,set-field!)
(new . ,new-object)
(add-member! ,add-member!) (delete-member! ,delete-member!)
(kappa . ,kappa) (kappa? . ,kappa?)
(as-instance-of-class! . ,as-instance-of-class!)
(generalize-multiple-classes! . ,generalize-multiple-classes!)
)
)
(define new-env
(lambda (formals actuals env)
(cond
((null? formals) env)
((symbol? formals) (cons (cons formals actuals) env))
(else
(cons (cons (car formals) (car actuals))
(new-env (cdr formals) (cdr actuals) env))))))
(define lookup-orig
(lambda (var env)
(let ((res (assq var env)))
(if res
(cdr res)
(if (bound? var)
(eval var (interaction-environment))
(error (string-append "The variable " (as-string var) " is unbound in the local environment, the environment of the hosting object, the primitives environment, and in the implementation's interaction environment."))
)
))))
(define lookup
(lambda (var env)
(let ((res (assq var env))
(current-object (eval 'this-object (interaction-environment)))
)
(cond (res (cdr res))
((and (asl-object? current-object) (field-exists? current-object var)) (get-field current-object var))
((bound? var) (eval var (interaction-environment)))
(else (error (string-append "The variable " (as-string var) " is unbound in the given environment, the primitives environment, and in the implementation's interaction environment.")))))))
(define assign
(lambda (var val env)
(set-cdr! (assq var env) val)))
(define exec
(lambda (exp env)
(cond
((symbol? exp) (lookup exp env))
((pair? exp)
(case (car exp)
((quote) (cadr exp))
((lambda)
(lambda vals
(let ((env (new-env (cadr exp) vals env)))
(let loop ((exps (cddr exp)))
(if (null? (cdr exps))
(exec (car exps) env)
(begin
(exec (car exps) env)
(loop (cdr exps))))))))
((if)
(if (exec (cadr exp) env)
(exec (caddr exp) env)
(exec (cadddr exp) env)))
((function)
(let ((formal-parameters (cadr exp))
(body-forms (cddr exp)))
(make-function formal-parameters (cons 'begin body-forms) env)
)
)
((set!)
(let ((lhs (cadr exp))
(rhs (caddr exp))
(current-object (eval 'this-object (interaction-environment)))
)
(cond ((assq lhs env)
(assign lhs (exec rhs env) env)
)
((field-exists? current-object lhs)
(set-field! current-object lhs (exec rhs env)))
(else (error (string-append "Cannot assign: The variable " (as-string lhs) " is not a local variable, nor a field in the current object.")))
)
)
)
((begin)
(let ((imperatives (cdr exp)))
(if (not (null? imperatives))
(let ((prefix-imperatives (butlast imperatives))
(last-imperative (last imperatives)))
(for-each
(lambda (imperative) (exec imperative env))
prefix-imperatives)
(exec last-imperative env))))
)
((let)
(let* ((name-bindings (cadr exp))
(names (map car name-bindings))
(values (map cadr name-bindings))
(body-forms (cddr exp)))
(exec `((lambda ,names ,@body-forms) ,@values) env)
)
)
((dot)
(let ((object (exec (cadr exp) env))
(field-name (caddr exp)))
(if (not (= (length (cdr exp)) 2))
(error (string-append "Illegal dot form: " (as-string exp) " . " "Must be of the form: (dot object field-name)")))
(get-field object field-name))
)
(else
(apply (exec (car exp) env)
(map (lambda (x) (exec x env))
(cdr exp))))
)
)
(else exp))))
(define interpret
(lambda (expr env)
(exec expr (append env primitive-environment))))
(set! eval-expr interpret))
(define (object-property-list object)
(if (asl-object? object)
(alist-to-propertylist (object-fields-alist object))
(error "The first parameter must be an object")))
(define (field-exists-raw? object field)
(turn-into-boolean (find-in-list (lambda (pair) (eq? (car pair) field)) (object-fields-alist object))))
(define (get-field-raw object field-name)
(get field-name (object-fields-alist object)))
(define (data-field-names-of object)
(map car (filter (negate (disjunction internal-field? function-field?)) (object-fields-alist object))))
(define (member-names-of object)
(map car (filter (negate internal-field?) (object-fields-alist object))))
(define (class-fields-alist class . optional-parameters)
(let ((last-class (optional-parameter 1 optional-parameters 'object)))
(if (kappa? class)
(if (eq? class class-object)
(cond ((eq? last-class 'object)
(append (remove-internal-fields (object-fields-alist class-object)) (remove-internal-fields (object-fields-alist root-object))))
((eq? last-class 'class)
(remove-internal-fields (object-fields-alist class-object)))
(else '()))
(let* ((class-fields (object-fields-alist class))
(superclass-object (if (field-exists-raw? class '$superclass)
(get-field-raw class '$superclass)
class-object))
)
(append
(remove-internal-fields class-fields)
(class-fields-alist superclass-object last-class)
)
)
)
(error "Cannot extract class fields of a non-kappa object")) ))
(define (remove-internal-fields fields-alist . optional-parameters)
(let ((internal-fields (optional-parameter 1 optional-parameters (list '$superclass '$kind))))
(filter
(lambda (pair)
(not (memq (car pair) internal-fields)))
fields-alist)))
(define (a-set! a-list key val)
(let ((pair (find-in-list (lambda (p) (eq? key (car p))) a-list)))
(if pair (set-cdr! pair val))))
(define (a-set-equal! a-list key val)
(let ((pair (find-in-list (lambda (p) (equal? key (car p))) a-list)))
(if pair (set-cdr! pair val))))
(define (last-cons-cell lst)
(cond ((and (pair? lst) (null? (cdr lst))) lst)
((pair? lst) (last-cons-cell (cdr lst)))
(else (error "last-cons-cell applied on non-list"))))
(define name-of-field car)
(define value-of-field cdr)
(define root-object
(let ((class-obj (make-object '$kind 'class)))
(add-member! class-obj 'AddMember (function (memberName memberValue) (add-member! this-object memberName memberValue)))
(add-member! class-obj 'DeleteMember (function (memberName) (delete-member! this-object memberName)))
(add-member! class-obj 'Kappa (function () (kappa this-object)))
(add-member! class-obj 'Kappa? (function () (kappa? this-object)))
(add-member! class-obj 'AsInstanceOfClass (function (class) (as-instance-of-class! this-object class)))
(add-member! class-obj 'GetField (function (field-name) (get-field this-object field-name)))
(add-member! class-obj 'SetField (function (field-name field-value) (set-field! this-object field-name field-value)))
(add-member! class-obj 'Clone (function () (clone-object this-object)))
class-obj))
(define class-object
(let ((class-obj (make-object '$kind 'class)))
(add-member! class-obj '$superclass root-object)
(add-member! class-obj 'New (function fields-and-values (apply new-object (cons this-object fields-and-values))))
class-obj))
(define *objects-by-role* '())
(define (insert-object-with-role! object role-name)
(let ((role-collection (assoc role-name *objects-by-role*)))
(if role-collection
(let ((existing-role-objects (cdr role-collection)))
(a-set-equal! *objects-by-role* role-name (cons object existing-role-objects)))
(set! *objects-by-role* (extend-a-list-raw role-name (list object) *objects-by-role*)))))
(define (extend-a-list-raw key value a-list)
(cons (cons key value) a-list))
(define (objects-with-role role-string)
(let ((lookup-res (assoc role-string *objects-by-role*)))
(if lookup-res (cdr lookup-res) '())))
(define (reset-objects-with-role! role-string)
(a-set-equal! *objects-by-role* role-string '()))
(define (borrow-method-from-objects-of-same-role role selector)
(let ((candicate-objects (objects-with-role role)))
(if (not (null? candicate-objects))
(let ((objects-with-method (filter (lambda (obj) (field-exists-raw? obj selector)) candicate-objects)))
(cond ((= (length objects-with-method) 0) #f)
((= (length objects-with-method) 1) (get-field (car objects-with-method) selector))
(else (let* ((methods (map (lambda (obj) (get-field obj selector)) objects-with-method))
(methods-equals? (accumulate-right
(lambda (meth1 meth2) (methods-syntactical-equal? meth1 meth2))
#t
methods)))
(if methods-equals?
(car methods)
#f)))))
#f)))
(define (methods-syntactical-equal? m1 m2)
(equal? m1 m2))
(define role-class-mapping '())
(define (map-role-to-class! role-string class-object)
(for-each (lambda (obj) (as-instance-of-class! obj class-object)) (objects-with-role role-string))
(reset-objects-with-role! role-string)
(set! role-class-mapping (cons (cons role-string class-object) role-class-mapping))
)
(define-syntax class
(syntax-rules ()
((class class-name (superclass-name ...) member ...)
(define class-name (make-full-class (quote (superclass-name ...)) (quote (member ...)))))))
(define (make-full-class superclass-list member-list)
(let* ((superclass-object
(cond ((and (list? superclass-list) (= (length superclass-list) 1))
(let ((superclass-name (car superclass-list)))
(if (bound? superclass-name) (eval superclass-name) (laml-error "Name of superclass is unbound"))))
((and (list? superclass-list) (= (length superclass-list) 0))
#f)
(else (laml-error "At most one superclass can be supplied"))))
(class-object (if superclass-object (make-class superclass-object) (make-class))))
(for-each (lambda (member)
(let ((member-name (car member))
(member-value (if (= (length member) 2)
(eval (cadr member))
'undefined))
)
(add-member! class-object member-name member-value)))
member-list)
class-object))
(define (class-source class-object class-name superclass-name file-path . optional-parameters)
(let ((class-role (optional-parameter 1 optional-parameters #f))
)
(if (kappa? class-object)
(let* ((superclass-object-0 (superclass-of class-object))
(superclass-object (if (eq? superclass-object-0 class-object) #f superclass-object-0))
(field-list (object-data-fields-alist class-object))
(method-list (object-method-fields-alist class-object))
(indent (lambda (n) (lambda (str) (string-append (make-string n #\space) str))))
)
(let ((class-string
(string-append
"(" "class" " " class-name " " "(" (if superclass-object (as-string superclass-name) "") ")" CR
(list-to-string (map (indent 2) (map field-source field-list)) CR) CR
(list-to-string (map (indent 2) (map method-source method-list)) CR) CR
")"
))
(mapping-entry
(if class-role
(string-append
"(" "map-role-to-class!" " " (as-quoted-string class-role) " " class-name ")")
""))
)
(write-text-file (string-append class-string CR CR mapping-entry) file-path)
(lib-load "scheme-pretty-printing.scm")
(if (file-exists? file-path)
(begin
(pretty-print-lisp-file file-path)
'DONE-AND-PRETTY-PRINTED)
'DONE)
))
(laml-error "The first parameter must be a class"))))
(define (field-source member)
(let ((member-name (car member))
(member-value (cdr member)))
(if (asl-object? member-value)
(string-append "(" (as-quoted-string member-name) ")")
(string-append "(" (as-string member-name) " "
(as-quoted-string member-value)
")"))))
(define (method-source member)
(let ((member-name (car member))
(member-value (cdr member)))
(string-append "(" (as-string member-name) " "
(function-source member-value)
")")))
(define (function-source function-object)
(if (function? function-object)
(let* ((par-list (cadr function-object))
(body (caddr function-object))
(body-forms (if (and (list? body) (>= (length body) 1) (eq? (car body) 'begin))
(cdr body)
#f))
)
(string-append
"("
"function" " "
"(" (list-to-string (map as-string par-list) " ") ")" " "
(if body-forms
(list-to-string (map as-quoted-string body-forms) " ")
(as-quoted-string body)
)
")"))
(laml-error "Malformed function object")))
(define END-DEMO 'OK)
(define (END-SECTION txt)
'OK)
(send root-object 'AddMember 'Borrow
(function (member-name from-obj)
(send this-object 'AddMember member-name
(send from-obj 'GetField member-name))))
(send root-object 'AddMember 'PrivateField
(function (field-name)
(send this-object 'AddMember (getter-name field-name) (function () (error (string-append "ERROR: The field" " " (as-string field-name) " " "is private - you cannot read it from outside the object."))))
(send this-object 'AddMember (setter-name field-name) (function (value) (error (string-append "ERROR: The field" " " (as-string field-name) " " "is private - you cannot write to it from outside the object."))))
))
(define (other-corner-1 corner)
(cond ((eq? corner 'c1) 'c2)
((eq? corner 'c2) 'c3)
((eq? corner 'c3) 'c1)
(else (error "Illegal corner given til other-corner-1"))))
(define (other-corner-2 corner)
(cond ((eq? corner 'c1) 'c3)
((eq? corner 'c2) 'c1)
((eq? corner 'c3) 'c2)
(else (error "Illegal corner given til other-corner-1"))))
(define PI 3.1415962)
(define (radian-to-degree r)
(/ (* r 360) (* 2 PI)))
(define (degree-to-radians d)
(/ (* d 2 PI) 360))
(define (getter-of symbol)
(as-symbol (string-append "get" "-" (as-string symbol))))