aboutsummaryrefslogtreecommitdiff
path: root/src/eval.lisp
blob: bc1d1c8cd6f950a3d80f0d6e6b6f19d7c6f3627d (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
(in-package #:chains)

(defun group-if (predicate sequence)
  (loop :for (head . tail) :on sequence
        :while (funcall predicate head)
        :collect head :into group
        :finally
           (return (values group (if (not (funcall predicate head))
                                     (cons head tail)
                                     tail)))))

(defun group (item sequence &key (test #'eql))
  (group-if #'(lambda (x) (funcall test item x)) sequence))

(defun group-if-not (predicate sequence)
  (group-if (complement predicate) sequence))

(defun link-closure (link)
  "Returns the function object inside the first link of a chain"
  (setf link (remove-if #'whitespace-text-p link))
  (assert (and (not (null link))
               (closurep (first link))
               (null (rest link)))
          (link)
          "Link is not callable: ~A" link)
  (first link))

(defun bind-arguments (environment lambda-list arguments specialp)
  (unless specialp
    (map-into arguments (curry #'eval-tree environment) arguments))
  (append (mapcar #'cons lambda-list arguments)
          environment))

(defun eval-chain (environment chain siblings)
  "Evaluate CHAIN inside ENVIRONMENT and possibly consume SIBLINGS. Returns a
link with the evaluated body of the function under the ENVIRONMENT"
  (destructuring-bind (head &rest arguments)
      (chain-links chain)
    (with-accessors ((function closure-function)
                     (special closure-special-p)
                     (lambda-list closure-lambda-list)
                     (group-predicate closure-group-p))
        ;; Evaluate all elements of first link and get closure object
        (link-closure (eval-tree environment head))
      (multiple-value-bind (consumed-siblings rest)
          (group-if group-predicate siblings)
        (values
         (funcall function
                  (bind-arguments environment lambda-list arguments special)
                  consumed-siblings)
         rest)))))

(defun eval-tree (environment node)
  (typecase node
    (object-symbol
     (get-var environment (object-value node)))
    (cons
     (destructuring-bind (head &rest tail)
         node
       (if (chainp head)
           (multiple-value-bind (result rest)
               (eval-chain environment head tail)
             (append (ensure-list result) (eval-tree environment rest)))
           (cons (eval-tree environment head) (eval-tree environment tail)))))
    (t
     node)))