36
36
:symbol
37
37
:keyword
38
38
:string
39
+ :regex
39
40
:character )
40
41
" Types of tokens that represent leaf nodes in the AST." )
41
42
44
45
:rbrace )
45
46
" Types of tokens that mark the end of a non-atomic form." )
46
47
48
+ (defvar parseclj-lex--prefix-tokens '(:quote
49
+ :backquote
50
+ :unquote
51
+ :unquote-splice
52
+ :discard
53
+ :tag
54
+ :reader-conditional
55
+ :reader-conditional-splice
56
+ :var
57
+ :deref )
58
+ " Tokens that modify the form that follows." )
59
+
60
+ (defvar parseclj-lex--prefix-2-tokens '(:metadata )
61
+ " Tokens that modify the two forms that follow." )
62
+
47
63
; ; Token interface
48
64
49
65
(defun parseclj-lex-token (type form pos &rest attributes )
@@ -81,6 +97,11 @@ A token is an association list with :token-type as its first key."
81
97
(and (consp token)
82
98
(cdr (assq :token-type token))))
83
99
100
+ (defun parseclj-lex-token-form (token )
101
+ " Get the form of TOKEN."
102
+ (and (consp token)
103
+ (cdr (assq :form token))))
104
+
84
105
(defun parseclj-lex-leaf-token-p (token )
85
106
" Return t if the given AST TOKEN is a leaf node."
86
107
(member (parseclj-lex-token-type token) parseclj-lex--leaf-tokens))
@@ -89,6 +110,9 @@ A token is an association list with :token-type as its first key."
89
110
" Return t if the given ast TOKEN is a closing token."
90
111
(member (parseclj-lex-token-type token) parseclj-lex--closing-tokens))
91
112
113
+ (defun parseclj-lex-error-p (token )
114
+ " Return t if the TOKEN represents a lexing error token."
115
+ (eq (parseclj-lex-token-type token) :lex-error ))
92
116
93
117
; ; Elisp values from tokens
94
118
@@ -177,18 +201,32 @@ S goes through three transformations:
177
201
(<= (char-after (point )) ?9 ))
178
202
(right-char )))
179
203
204
+ (defun parseclj-lex-skip-hex ()
205
+ " Skip all consecutive hex digits after point."
206
+ (while (and (char-after (point ))
207
+ (or (<= ?0 (char-after (point )) ?9 )
208
+ (<= ?a (char-after (point )) ?f )
209
+ (<= ?A (char-after (point )) ?F )))
210
+ (right-char )))
211
+
180
212
(defun parseclj-lex-skip-number ()
181
213
" Skip a number at point."
182
214
; ; [\+\-]?\d+\.\d+
183
- (when (member (char-after (point )) '(?+ ?- ))
184
- (right-char ))
215
+ (if (and (eq ?0 (char-after (point )))
216
+ (eq ?x (char-after (1+ (point )))))
217
+ (progn
218
+ (right-char 2 )
219
+ (parseclj-lex-skip-hex))
220
+ (progn
221
+ (when (member (char-after (point )) '(?+ ?- ))
222
+ (right-char ))
185
223
186
- (parseclj-lex-skip-digits)
224
+ (parseclj-lex-skip-digits)
187
225
188
- (when (eq (char-after (point )) ?. )
189
- (right-char ))
226
+ (when (eq (char-after (point )) ?. )
227
+ (right-char ))
190
228
191
- (parseclj-lex-skip-digits))
229
+ (parseclj-lex-skip-digits)) ))
192
230
193
231
(defun parseclj-lex-number ()
194
232
" Consume a number and return a `:number' token representing it."
@@ -270,22 +308,39 @@ are returned as their own lex tokens."
270
308
((equal sym " false" ) (parseclj-lex-token :false " false" pos))
271
309
(t (parseclj-lex-token :symbol sym pos))))))
272
310
273
- (defun parseclj-lex-string ()
274
- " Return a lex token representing a string.
275
- If EOF is reached without finding a closing double quote, a :lex-error
276
- token is returned."
311
+ (defun parseclj-lex-string* ()
312
+ " Helper for string/regex lexing.
313
+ Returns either the string, or an error token"
277
314
(let ((pos (point )))
278
315
(right-char )
279
316
(while (not (or (equal (char-after (point )) ?\" ) (parseclj-lex-at-eof-p)))
280
317
(if (equal (char-after (point )) ?\\ )
281
318
(right-char 2 )
282
319
(right-char )))
283
- (if (equal (char-after (point )) ?\" )
284
- (progn
285
- (right-char )
286
- (parseclj-lex-token :string (buffer-substring-no-properties pos (point )) pos))
320
+ (when (equal (char-after (point )) ?\" )
321
+ (right-char )
322
+ (buffer-substring-no-properties pos (point )))))
323
+
324
+ (defun parseclj-lex-string ()
325
+ " Return a lex token representing a string.
326
+ If EOF is reached without finding a closing double quote, a :lex-error
327
+ token is returned."
328
+ (let ((pos (point ))
329
+ (str (parseclj-lex-string*)))
330
+ (if str
331
+ (parseclj-lex-token :string str pos)
287
332
(parseclj-lex-error-token pos :invalid-string ))))
288
333
334
+ (defun parseclj-lex-regex ()
335
+ " Return a lex token representing a regular expression.
336
+ If EOF is reached without finding a closing double quote, a :lex-error
337
+ token is returned."
338
+ (let ((pos (1- (point )))
339
+ (str (parseclj-lex-string*)))
340
+ (if str
341
+ (parseclj-lex-token :regex (concat " #" str) pos)
342
+ (parseclj-lex-error-token pos :invalid-regex ))))
343
+
289
344
(defun parseclj-lex-lookahead (n )
290
345
" Return a lookahead string of N characters after point."
291
346
(buffer-substring-no-properties (point ) (min (+ (point ) n) (point-max ))))
@@ -387,6 +442,22 @@ See `parseclj-lex-token'."
387
442
(right-char )
388
443
(parseclj-lex-token :rbrace " }" pos))
389
444
445
+ ((equal char ?' )
446
+ (right-char )
447
+ (parseclj-lex-token :quote " '" pos))
448
+
449
+ ((equal char ?` )
450
+ (right-char )
451
+ (parseclj-lex-token :backquote " '" pos))
452
+
453
+ ((equal char ?~ )
454
+ (right-char )
455
+ (if (eq ?@ (char-after (point )))
456
+ (progn
457
+ (right-char )
458
+ (parseclj-lex-token :unquote-splice " ~@" pos))
459
+ (parseclj-lex-token :unquote " ~" pos)))
460
+
390
461
((parseclj-lex-at-number-p)
391
462
(parseclj-lex-number))
392
463
@@ -405,6 +476,14 @@ See `parseclj-lex-token'."
405
476
((equal char ?\; )
406
477
(parseclj-lex-comment))
407
478
479
+ ((equal char ?^ )
480
+ (right-char )
481
+ (parseclj-lex-token :metadata " ^" pos))
482
+
483
+ ((equal char ?@ )
484
+ (right-char )
485
+ (parseclj-lex-token :deref " @" pos))
486
+
408
487
((equal char ?# )
409
488
(right-char )
410
489
(let ((char (char-after (point ))))
@@ -415,6 +494,21 @@ See `parseclj-lex-token'."
415
494
((equal char ?_ )
416
495
(right-char )
417
496
(parseclj-lex-token :discard " #_" pos))
497
+ ((equal char ?\( )
498
+ (right-char )
499
+ (parseclj-lex-token :lambda " #(" pos))
500
+ ((equal char ?' )
501
+ (right-char )
502
+ (parseclj-lex-token :var " #'" pos))
503
+ ((equal char ?\" )
504
+ (parseclj-lex-regex))
505
+ ((equal char ?\? )
506
+ (right-char )
507
+ (if (eq ?@ (char-after (point )))
508
+ (progn
509
+ (right-char )
510
+ (parseclj-lex-token :reader-conditional-splice " #?@" pos))
511
+ (parseclj-lex-token :reader-conditional " #?" pos)))
418
512
((parseclj-lex-symbol-start-p char t )
419
513
(right-char )
420
514
(parseclj-lex-token :tag (concat " #" (parseclj-lex-get-symbol-at-point (1+ pos))) pos))
0 commit comments