Coverage report: /home/ellis/comp/core/lib/syn/gen/proto.lisp
Kind | Covered | All | % |
expression | 14 | 278 | 5.0 |
branch | 4 | 62 | 6.5 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; proto.lisp --- SYN/GEN Protocol
9
(defgeneric load-gen (self))
10
(defgeneric unload-gen (self))
11
(defgeneric gen-package (self))
12
(defgeneric gen-reader (self))
13
(defgeneric gen-reader-switch (self))
15
(defnode function-call () (function arguments))
16
(defmethod ast ((self function-call))
17
(list (slot-value self 'function) (slot-value self 'arguments)))
18
(defnode src-location (ast) (line file info))
19
(defexpr ident (literal-expr) ())
20
(defmethod id ((self ident)) (val self))
21
(defexpr str-literal (literal-expr) ())
22
(defexpr num-literal (literal-expr) ())
23
(defexpr char-literal (literal-expr) ())
24
(defnode proxy (ast) (info))
27
;; Inverts the case when interning a string.
28
;; This is needed to keep the correct internal (inverted) case.
29
;; Use this function for all c depending code.
30
(defun cintern (name &optional package)
31
(macrolet ((case-test (test string)
32
`(reduce #'(lambda (a b) (and a b))
33
(mapcar (lambda(x) (or (not (both-case-p x)) (,test x)))
34
(coerce ,string 'list)))))
35
(let ((string (cond ((case-test upper-case-p name) (string-downcase name))
36
((case-test lower-case-p name) (string-upcase name))
39
(intern string package)
42
(defmacro defsyntax (tags langs lambda-list &body body)
43
"Define syntax for tags from specific langs."
44
(let ((tags (if (consp tags) tags (list tags))))
51
(declare (ignorable tag))
52
(defmacro ,(intern (format nil "~:@(~a~)" i) (gen-package k)) ,lambda-list
56
(defmacro quoty (item &environment env)
57
"Quote undefined symbols, build functions from unknown lists."
61
(if (or (listp (car item))
62
(not (fboundp! (car item) env)))
63
`(make-instance 'function-call
64
:function (make-node ,(car item))
65
:arguments (make-nodes ,(cdr item)))
68
(if (vboundp! item env)
73
(defmacro make-nodes (nodes &key prepend quoty)
74
"Build general or specific AST."
75
(let ((prepend (if (listp prepend) prepend `(,prepend))))
78
(list ,@(loop for i in nodes
82
`(,@prepend (quoty ,i))
84
`(%make-node (quoty ,i))))))))
86
(defmacro make-node (item)
87
"Try to identify and make a NODE from ITEM."
88
`(%make-node (quoty ,item)))
90
(defun %make-node (item)
91
"Build NODE from ITEM."
94
((eql item nil) (values))
95
;; item is already c-mera node
96
((typep item 'node) item)
97
;; Item is most possibly an atom or a quoted symbol
98
((symbolp item) (make-instance 'ident :val item))
99
((numberp item) (make-instance 'num-literal :val item))
100
((stringp item) (make-instance 'str-literal :val item))
101
((characterp item) (make-instance 'char-literal :val item))
102
;; Item is not a known atom
103
(t (error "code generator encountered an unknown atom: ~a" item))))
105
(defclass ast-traverser () ())
107
(defmethod traverse :before ((self ast-traverser) (item ast) level)
108
"remove unnecessary trees"
109
(declare (ignore level))
110
(with-slots (nodes) item
112
do (if (not (= (length nodes) 1))
115
((eql (class-of (first nodes)) (find-class 'ast))
116
(setf nodes (slot-value nodes 'ast)))
117
((eql (class-of (first nodes)) (find-class 'src-location))
118
(if (eql (class-of (slot-value (first nodes) 'subnode)) (find-class 'ast))
119
(setf nodes (slot-value (slot-value (first nodes) 'subnode) 'nodes))
121
(t (loop-finish)))))))
123
(defclass code-printer ()
124
((indent :initform 0)
125
(sign-stack :initform nil)
126
(info-stack :initform nil)
127
(stream :initform t :initarg :stream :accessor stream-of)))
131
;; The PRINT-CODE and WRITE-CODE functions are defined here in addition to
132
;; several macros which may be used to define new lang-specific dispatch
133
;; tables, printer methods, and printer dispatch entries.
134
(defvar *code-dispatch-table* (copy-pprint-dispatch *ast-dispatch-table*))
136
(defun write-code (expr &rest args)
137
(apply 'write expr :pprint-dispatch *code-dispatch-table* args))
139
(defun print-code (tree)
140
(let ((pp (make-instance 'code-printer))
141
(d (make-instance 'debug-traverser)))
143
(traverse pp tree 0)))
145
(defmacro define-code-printer (qual node &body body)
147
`(defmethod traverse ((self code-printer)
150
(declare (ignorable level))
152
`(defmethod traverse ,qual ((self code-printer) (node ,node) level)
153
(declare (ignorable level))
156
(defmacro delete-code-printer (qual node)
157
(let ((quali (if (eql qual :self)
160
`(remove-method #'traverser
161
(find-method #'traverser
164
,(find-class 'code-printer)
168
(defmacro with-code-printer (&body body)
169
`(symbol-macrolet ((stream (slot-value self 'stream))
170
(indent (format nil "~{~A~}"
173
to (slot-value self 'indent)
177
(--indent (decf (slot-value self 'indent)))
178
(++indent (incf (slot-value self 'indent))))
179
(macrolet ((push-sign (x) `(push ,x (slot-value self 'sign-stack)))
180
(pop-sign () `(pop (slot-value self 'sign-stack)))
181
(top-sign () `(car (slot-value self 'sign-stack)))
182
(find-sign (x) `(find ,x (slot-value self 'sign-stack)))
183
(push-info (x) `(push ,x (slot-value self 'info-stack)))
184
(pop-info () `(pop (slot-value self 'info-stack)))
185
(top-info () `(car (slot-value self 'info-stack)))
186
(find-info (x) `(find ,x (slot-value self 'info-stack)))
187
(info-size () `(length (slot-value self 'info-stack)))
188
(node-slot (x) `(slot-value node ',x)))
192
(define-code-printer :self literal-expr
193
(let ((val (val node)))
197
(format stream "\"~a\"" val))
201
(format stream "'\\t'"))
202
((or (eql val #\nul) (eql val #\null))
203
(format stream "'\\0'"))
205
(format stream "'\\r'"))
207
(format stream "'\\n'"))
209
(format stream "'\\''"))
210
(t (format stream "'~a'" val))))
211
((floatp val) (format stream "~a"
213
(format nil "~,8e" val))))
214
(t (format stream "~a" val)))))))
216
;; TODO 2024-10-20: gen-file-header
217
;; (defclass gen-file-header (file-header)