It's terrible. Not sure how to do better.
* split-by-tests
(defun split-by-tests (msg-lst test-lst &key ((:test default-test) #'eql)) (flet ((do-test (test msg) (if (functionp test) (funcall test msg) (funcall default-test test msg)))) (loop with tests = test-lst with done-tests = nil with section = nil ; What I really want is use collect instead, but see next comment for msgs on msg-lst for msg = (car msgs) for is-separator? = (loop for test in tests collect test into done-tests2 thereis (and (do-test test msg) (setq done-tests (append done-tests2 done-tests)) done-tests2)) if is-separator? collect (nreverse section) into sections and do (setq section (list msg) ; I need to set section nil here. Loop facility resets it back when collecting. tests (cdr tests)) else if (loop for test in done-tests thereis (do-test test msg)) do (error "repeated separator ~S found. With tests ~S on list ~S" msg test-lst msg-lst) else do (push msg section) end end finally (return (nconc sections (list (nreverse section)))))))
This is a utility function I need for parsing the message passing syntax of javascript forms.
* A few tests for split-by-tests:
(split-by-tests '(~ @) '(~ @)) => (NIL (~) (@)) (split-by-tests '(1 ~ @) '(~ @)) => ((1) (~) (@)) (split-by-tests '(~ 2 @) '(~ @)) => (NIL (~ 2) (@)) (split-by-tests '(~ @ 3) '(~ @)) => (NIL (~) (@ 3)) (split-by-tests '(~ 2 @ 3) '(~ @)) => (NIL (~ 2) (@ 3)) (split-by-tests '(1 ~ 2 @ 3) '(~ @)) => ((1) (~ 2) (@ 3)) (split-by-tests '(1 1 ~ 2 2 @ 3 3) '(~ @)) => ((1 1) (~ 2 2) (@ 3 3)) (split-by-tests '(1 1 ~ 2 2 @ 3 3 ~ 4 4) '(~ @)) [error]
(defparameter foo (loop for i to 100 collect i)) (defparameter foo-tests (mapcar #'(lambda (x) #'(lambda (y) (eql x y))) (loop for i to 100 by 10 collect i)))
(split-by-tests '(1 1 1 1 1 2 1 1 1 1 ) (list #'evenp)) => ((1 1 1 1 1) (2 1 1 1 1)) (split-by-tests foo foo-tests) => (NIL (0 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 67 68 69) (70 71 72 73 74 75 76 77 78 79) (80 81 82 83 84 85 86 87 88 89) (90 91 92 93 94 95 96 97 98 99) (100))
(split-by-tests foo '(6 25 30 90)) => ((0 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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89) (90 91 92 93 94 95 96 97 98 99 100))
* The planned javascript syntax is:
(foo ~) foo();
1 Special Case for 0 arguments application: (foo) foo();
foo foo
(foo @) foo[];
(foo @ a) foo[a];
(foo bar ~) foo.bar();
(foo ~ a b) foo(a,b);
(foo bar ~ a b @ c d) foo.bar(a,b)[c][d];
((foo bar ~ a b @ c d) ~ e f) foo.bar(a,b)[c][d](e,f);