aboutsummaryrefslogtreecommitdiff
path: root/src/eval.lisp
diff options
context:
space:
mode:
authorThomas Albers Raviola <thomas@thomaslabs.org>2025-01-05 16:55:51 +0100
committerThomas Albers Raviola <thomas@thomaslabs.org>2025-01-05 17:11:20 +0100
commit5b518ad7205b3432d95ff2b3757e49914233d913 (patch)
treec4abb63c32cc1821a1f072a9e6487d067a873bc3 /src/eval.lisp
parentbc69faaa5bbd8a2d8afb9ab81882b1ba21c4bb8e (diff)
Clean up eval-tree
Diffstat (limited to 'src/eval.lisp')
-rw-r--r--src/eval.lisp104
1 files changed, 62 insertions, 42 deletions
diff --git a/src/eval.lisp b/src/eval.lisp
index e3e6617..b2c399c 100644
--- a/src/eval.lisp
+++ b/src/eval.lisp
@@ -1,44 +1,64 @@
(in-package #:chains)
-(defun tree-eval (environment node)
- (cond ((null node)
- nil)
- ((object-symbol-p node)
- (get-var environment (object-value node)))
- ((not (consp node))
- node)
- ((chainp (first node))
- (destructuring-bind (flink &rest rlinks) (chain-links (first node))
- (setf flink (tree-eval environment flink))
- (assert (and (consp flink)
- (closurep (first flink))
- (null (rest flink)))
- (flink)
- "1~A ~A" flink (content (second flink)))
- (let* ((closure (first flink))
- (function (closure-function closure))
- (group-predicate (closure-group-p closure)))
- (multiple-value-bind (siblings rest)
- (group-if group-predicate (rest node))
- (append
- ;; Evaluating a function returns a sublink, flatten all sublink
- (flatten
- (let ((eval-with-environment (curry #'tree-eval environment)))
- (case (closure-type closure)
- (:syntax
- (let ((body (ensure-list (apply function environment siblings rlinks)))
- (ret nil))
- ;; (format t "~&Body: ~A~%" body)
- (setf ret (tree-eval environment (append body (rest node))))
- (setf rest nil)
- ret))
- (:special
- (ensure-list (apply function environment siblings rlinks)))
- (:function
- (let ((args (mapcar eval-with-environment rlinks))
- (siblings (funcall eval-with-environment siblings)))
- (ensure-list (apply function environment siblings args)))))))
- (tree-eval environment rest))))))
- (t
- (cons (tree-eval environment (first node))
- (tree-eval environment (rest node))))))
+(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 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)
+ (type closure-type)
+ (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
+ (apply function
+ environment
+ consumed-siblings
+ (ecase type
+ (:special
+ arguments)
+ (:function
+ (mapcar (curry #'eval-tree environment) arguments))))
+ 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)))