Coverage report: /home/ati/workspace/perec/query/partial-eval.lisp
Kind | Covered | All | % |
expression | 242 | 282 | 85.8 |
branch | 34 | 46 | 73.9 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;; -*- mode: Lisp; Syntax: Common-Lisp; -*-
3
;;; Copyright (c) 2006 by the authors.
5
;;; See LICENCE for details.
9
(enable-pattern-reader #\M)
14
(defun partial-eval (syntax query &optional static-vars)
15
"Returns the partially evaluated SYNTAX. The SYNTAX can be a SYNTAX-OBJECT or a lisp form
16
containing syntax objects. The result is always a SYNTAX-OBJECT."
17
(syntax-from-value (%partial-eval-syntax syntax query static-vars) syntax))
19
(defgeneric %partial-eval-syntax (syntax query static-vars)
21
"Partially evaluates SYNTAX and returns a partially evaluated SYNTAX-OBJECT or the value
22
if it was fully evaluated.")
24
(:method (syntax query static-vars)
25
(%partial-eval-syntax (parse-query-form syntax (get-variables query)) query static-vars))
27
(:method ((syntax syntax-object) query static-vars)
28
(error "Unknown syntax: ~S~%" syntax))
30
(:method ((unparsed unparsed-form) query static-vars)
33
(:method ((literal literal-value) query static-vars)
36
(:method ((variable variable) query static-vars)
39
(:method ((variable dynamic-variable) query static-vars)
40
(bind ((variable-name (name-of variable)))
41
(if (and (boundp variable-name) (member variable-name static-vars))
42
(symbol-value variable-name)
45
(:method ((call macro-call) query static-vars)
46
(bind ((args (args-of call)))
47
(%partial-eval-macro-call
48
(macro-of call) (length args) (first args) (second args) args call query static-vars)))
50
(:method ((call function-call) query static-vars)
51
(bind ((args (mapcar #L(%partial-eval-syntax !1 query static-vars) (args-of call))))
52
(%partial-eval-function-call
53
(fn-of call) (length args) (first args) (second args) args call)))
55
(:method ((form special-form) query static-vars)
56
(%partial-eval-special-form (operator-of form) (operands-of form) form query static-vars)))
58
(defgeneric %partial-eval-function-call (fn n-args arg-1 arg-2 args call)
60
(:method (fn n-args arg-1 arg-2 args call)
61
(if (some 'syntax-object-p args)
62
(progn (setf (args-of call) (mapcar 'syntax-from-value args (args-of call))) call)
65
;; (typep query-variable t1) -> nil
66
;; when the types t1 and (xtype-of query-variable) does not have common subtypes
67
(:method ((fn (eql 'typep)) (n-args (eql 2)) (variable query-variable) (type persistent-class) args call)
68
(let ((variable-type (xtype-of variable)))
69
(if (and (persistent-class-p variable-type)
70
(null (intersection (adjoin type (persistent-effective-sub-classes-of type))
71
(adjoin variable-type (persistent-effective-sub-classes-of variable-type)))))
75
;; (member x nil) -> nil
76
;; (member x <list>) -> (member x <list2>) where list2 contains those elements of list,
77
;; that have matching type
78
(:method ((fn (eql 'member)) (n-args (eql 2)) object (list list) args call)
79
(bind ((type (xtype-of object))
80
(list (if (persistent-class-p type) (collect-if #L(typep !1 type) list) list)))
83
(t (setf args (list object list))
84
(call-next-method 'member 2 object list args call))))))
86
(defgeneric %partial-eval-macro-call (macro n-args arg-1 arg-2 args call query static-vars)
88
(:method (macro n-args arg-1 arg-2 args call query static-vars)
91
(:method ((macro (eql 'and)) n-args arg-1 arg-2 args call query static-vars)
92
(%partial-eval-and/or call query static-vars))
94
(:method ((macro (eql 'or)) n-args arg-1 arg-2 args call query static-vars)
95
(%partial-eval-and/or call query static-vars)))
97
(defun %partial-eval-and/or (call query static-vars)
98
(bind ((args (mapcar #L(%partial-eval-syntax !1 query static-vars) (args-of call))))
99
(if (some 'syntax-object-p args)
100
(progn (setf (args-of call) (mapcar 'syntax-from-generalized-boolean args))
101
(simplify-boolean-syntax call))
102
(eval (cons (macro-of call) (mapcar 'boolean-from-generalized-boolean args))))))
104
(defgeneric %partial-eval-special-form (operator args form query static-vars)
105
;; special forms (currently not evaluated, TODO)
106
(:method (operator args form query static-vars)
109
(defun syntax-from-value (value orig-syntax)
111
((syntax-object-p value) value)
112
((syntax-object-p orig-syntax) (make-literal-value :value value :xtype (xtype-of orig-syntax)))
113
(t (make-literal-value :value value))))
115
(defun syntax-from-generalized-boolean (value)
116
(if (syntax-object-p value)
118
(make-literal-value :value (if value #t #f))))
120
(defun boolean-from-generalized-boolean (value)
121
(assert (not (syntax-object-p value)))
124
(defun is-true-literal (syntax)
125
"Returns #t if SYNTAX is a true literal as generalized boolean."
126
(and (typep syntax 'literal-value)
127
(not (eq (value-of syntax) #f))))
129
(defun is-false-literal (syntax)
130
"Returns #t if SYNTAX is a false literal."
131
(and (typep syntax 'literal-value)
132
(eq (value-of syntax) #f)))
134
(defun simplify-boolean-syntax (syntax)
135
"Makes the following simplifications on SYNTAX:
141
(or x... false y...) -> (or x... y...)
142
(or x... true y...) -> true
143
(or x... (or y...) z...) -> (or x... y... z...)
146
(and x... true y...) -> (and x... y...)
147
(and x... false y...) -> false
148
(and x... (and y...) z...) -> (and x... y... z...)
150
where x, y and z are arbitrary objects and '...' means zero or more occurence,
151
and false/true means a generalized boolean literal."
153
(flet ((simplify-args (operator args)
154
(iter (for arg in args)
155
(for simplified = (simplify-boolean-syntax arg))
156
(if (and (macro-call-p simplified) (eq (macro-of simplified) operator))
157
(appending (args-of simplified))
158
(collect simplified)))))
160
(#M(function-call :fn not :args (?arg))
161
(bind ((arg (simplify-boolean-syntax ?arg)))
163
(#M(function-call :fn not :args (?arg)) ?arg)
164
(#M(literal-value :value #f) (make-literal-value :value #t))
165
(#M(literal-value :value ?true) (make-literal-value :value #f))
166
(?otherwise syntax))))
167
(#M(macro-call :macro or :args ?args)
168
(bind ((operands (remove-if 'is-false-literal (simplify-args 'or ?args))))
170
((null operands) (make-literal-value :value #f))
171
((length=1 operands) (first operands))
172
((find-if 'is-true-literal operands) (make-literal-value :value #t))
173
(t (make-macro-call :macro 'or :args operands)))))
174
(#M(macro-call :macro and :args ?args)
175
(bind ((operands (remove-if 'is-true-literal (simplify-args 'and ?args))))
177
((null operands) (make-literal-value :value #t))
178
((length=1 operands) (first operands))
179
((find-if 'is-false-literal operands) (make-literal-value :value #f))
180
(t (make-macro-call :macro 'and :args operands)))))
181
(?otherwise syntax))))