# OBJECT adding a special form for classes
       # need a bunch of extra machinery first, will push this
       # back into previous sections eventually, and simplify
[
hear] (define list-append
         (lambda (lst1 lst2)
           (if (> (list-length (lst1)) 0)
           (list-append (except-last (lst1))
                    (prepend (last (lst1)) (lst2)))
           (lst2))));

[hear] (= (list-append (vector 1 2 3) (vector 4 5 6)) (vector 1 2 3 4 5 6));

[hear] (define append
         (? x
            (? lst
           (if (> (list-length (lst)) 0)
               (prepend (head (lst)) (append (x) (tail (lst))))
               (vector (x))))));

[hear] (= (append 5 (vector 1 2)) (vector 1 2 5));

[hear] (define select-match
         (lambda (test lst)
           (if (> (list-length (lst)) 0)
           (if (test (head (lst)))
               (prepend (head (lst)) (select-match (test) (tail (lst))))
               (select-match (test) (tail (lst))))
           (lst))));

[hear] (define unique
         (let ((store (make-cell 0)))
           (lambda (x)
             (let ((id (get! (store))))
           (begin
             (set! (store) (+ (id) 1))
             (id))))));

[hear] (= (unique new) 0);

[hear] (= (unique new) 1);

[hear] (= (unique new) 2);

[hear] (not (= (unique new) (unique new)));

       # okay, here it comes. don't panic!
       # I need to split this up into helpers, and simplify.
       # It basically just writes code for classes like we saw in
       # a previous section.
[hear] (define prev-translate (translate));

[hear] (define translate
         (let ((prev (prev-translate)))
           (? x
              (if (number? (x))
              (prev (x))
              (if (= (head (x)) class)
                  (let ((name (list-ref (x) 1))
                    (args (list-ref (x) 2))
                    (fields (tail (tail (tail (x))))))
                (translate
                 (vector
                  define
                  (name)
                  (vector
                   lambda
                   (prepend method (args))
                   (vector
                    let
                    (append
                     (vector unique-id (vector unique new))
                     (map
                      (tail)
                      (select-match (? x (= (first (x)) field)) (fields))))
                    (vector
                     let
                     (vector
                      (vector
                   self
                   (vector
                    reflective
                    (vector
                     lambda
                     (vector self method)
                     (list-append
                      (prepend
                       cond
                       (list-append
                        (map
                         (? x
                        (vector
                         (vector = (vector method) (first (x)))
                         (second (x))))
                         (map (tail)
                          (select-match
                           (? x (= (first (x)) method))
                           (fields))))
                        (map
                         (? x
                        (vector
                         (vector = (vector method) (x))
                         (vector (x))))
                         (map (second)
                          (select-match
                           (? x (= (first (x)) field))
                           (fields))))))
                      (vector
                       (vector
                        (vector = (vector method) self)
                        (vector self))
                       (vector
                        (vector = (vector method) (name))
                        (vector self self))
                       (vector
                        (vector = (vector method) unknown)
                        (vector lambda (vector x) 0))
                       (vector
                        (vector = (vector method) new)
                        0)
                       (vector
                        (vector = (vector method) unique-id)
                        (vector unique-id))
                       (vector
                        (vector = (vector method) ==)
                        (vector
                         lambda
                         (vector x)
                         (vector =
                             (vector unique-id)
                             (vector x unique-id))))
                       (vector self unknown (vector method))))))))
                     (vector
                      begin
                      (vector self (vector method))
                      (vector self))))))))
                  (prev (x)))))));

       # revisit the point class example
[hear] (class point (x y)
              (method x (x))
              (method y (y))
              (method + (lambda ((p point))
                  (point new
                     (+ (x) (p x))
                     (+ (y) (p y)))))
              (method = (lambda ((p point))
                  (and (= (x) (p x))
                   (= (y) (p y))))));

       # note the appearance of new in the next line --
       # this is the only difference to previous version
[hear] (define point1 (point new 1 11));

[hear] (define point2 (point new 2 22));

[hear] (= 1 (point1 x));

[hear] (= 22 (point2 y));

[hear] (= 11 ((point new 11 12) x));

[hear] (= 11 (((point new 11 12) point) x));

[hear] (= 16 (((point new 16 17) point) x));

[hear] (= 33 (point1 + (point2) y));

[hear] (point1 + (point2) = (point new 3 33));

[hear] (point2 + (point1) = (point new 3 33));

[hear] ((point new 100 200) + (point new 200 100) = (point new 300 300));

[hear] (instanceof point (point1));

[hear] (not (instanceof int (point1)));