Merge branch 'master' of git://factorcode.org/git/factor
[factor/jcg.git] / misc / fuel / fuel-syntax.el
blob6f33eb2993f5cb6575b82886f03981b9d570e3b7
1 ;;; fuel-syntax.el --- auxiliar definitions for factor code navigation.
3 ;; Copyright (C) 2008, 2009 Jose Antonio Ortega Ruiz
4 ;; See http://factorcode.org/license.txt for BSD license.
6 ;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
7 ;; Keywords: languages
9 ;;; Commentary:
11 ;; Auxiliar constants and functions to parse factor code.
13 ;;; Code:
15 (require 'thingatpt)
18 ;;; Thing-at-point support for factor symbols:
20 (defun fuel-syntax--beginning-of-symbol ()
21 "Move point to the beginning of the current symbol."
22 (skip-syntax-backward "w_()"))
24 (defsubst fuel-syntax--beginning-of-symbol-pos ()
25 (save-excursion (fuel-syntax--beginning-of-symbol) (point)))
27 (defun fuel-syntax--end-of-symbol ()
28 "Move point to the end of the current symbol."
29 (skip-syntax-forward "w_()"))
31 (defsubst fuel-syntax--end-of-symbol-pos ()
32 (save-excursion (fuel-syntax--end-of-symbol) (point)))
34 (put 'factor-symbol 'end-op 'fuel-syntax--end-of-symbol)
35 (put 'factor-symbol 'beginning-op 'fuel-syntax--beginning-of-symbol)
37 (defsubst fuel-syntax-symbol-at-point ()
38 (let ((s (substring-no-properties (thing-at-point 'factor-symbol))))
39 (and (> (length s) 0) s)))
43 ;;; Regexps galore:
45 (defconst fuel-syntax--parsing-words
46 '(":" "::" ";" "<<" "<PRIVATE" ">>"
47 "ABOUT:" "ALIAS:" "ARTICLE:"
48 "B" "BIN:"
49 "C:" "C-STRUCT:" "C-UNION:" "CHAR:" "CONSTANT:" "call-next-method"
50 "DEFER:"
51 "ERROR:" "EXCLUDE:"
52 "f" "FORGET:" "FROM:"
53 "GENERIC#" "GENERIC:"
54 "HELP:" "HEX:" "HOOK:"
55 "IN:" "initial:" "INSTANCE:" "INTERSECTION:"
56 "M:" "MACRO:" "MACRO::" "MAIN:" "MATH:" "MEMO:" "MEMO:" "METHOD:" "MIXIN:"
57 "OCT:"
58 "POSTPONE:" "PREDICATE:" "PRIMITIVE:" "PRIVATE>" "PROVIDE:"
59 "QUALIFIED-WITH:" "QUALIFIED:"
60 "read-only" "RENAME:" "REQUIRE:" "REQUIRES:"
61 "SINGLETON:" "SINGLETONS:" "SLOT:" "SYMBOL:" "SYMBOLS:"
62 "TUPLE:" "t" "t?" "TYPEDEF:"
63 "UNION:" "USE:" "USING:"
64 "VARS:"))
66 (defconst fuel-syntax--parsing-words-regex
67 (regexp-opt fuel-syntax--parsing-words 'words))
69 (defconst fuel-syntax--bracers
70 '("B" "BV" "C" "CS" "H" "T" "V" "W"))
72 (defconst fuel-syntax--brace-words-regex
73 (format "%s{" (regexp-opt fuel-syntax--bracers t)))
75 (defconst fuel-syntax--declaration-words
76 '("flushable" "foldable" "inline" "parsing" "recursive" "delimiter"))
78 (defconst fuel-syntax--declaration-words-regex
79 (regexp-opt fuel-syntax--declaration-words 'words))
81 (defsubst fuel-syntax--second-word-regex (prefixes)
82 (format "%s +\\([^ \r\n]+\\)" (regexp-opt prefixes t)))
84 (defconst fuel-syntax--method-definition-regex
85 "^M: +\\([^ ]+\\) +\\([^ ]+\\)")
87 (defconst fuel-syntax--integer-regex
88 "\\_<-?[0-9]+\\_>")
90 (defconst fuel-syntax--raw-float-regex
91 "[0-9]*\\.[0-9]*\\([eE][+-]?[0-9]+\\)?")
93 (defconst fuel-syntax--float-regex
94 (format "\\_<-?%s\\_>" fuel-syntax--raw-float-regex))
96 (defconst fuel-syntax--number-regex
97 (format "\\([0-9]+\\|%s\\)" fuel-syntax--raw-float-regex))
99 (defconst fuel-syntax--ratio-regex
100 (format "\\_<[+-]?%s/-?%s\\_>"
101 fuel-syntax--number-regex
102 fuel-syntax--number-regex))
104 (defconst fuel-syntax--bad-string-regex
105 "\\_<\"[^>]\\([^\"\n]\\|\\\\\"\\)*\n")
107 (defconst fuel-syntax--word-definition-regex
108 (fuel-syntax--second-word-regex
109 '(":" "::" "GENERIC:" "DEFER:" "HOOK:" "MAIN:" "MATH:" "POSTPONE:"
110 "SYMBOL:" "RENAME:")))
112 (defconst fuel-syntax--alias-definition-regex
113 "^ALIAS: +\\(\\_<.+?\\_>\\) +\\(\\_<.+?\\_>\\)")
115 (defconst fuel-syntax--vocab-ref-regexp
116 (fuel-syntax--second-word-regex
117 '("IN:" "USE:" "FROM:" "EXCLUDE:" "QUALIFIED:" "QUALIFIED-WITH:")))
119 (defconst fuel-syntax--int-constant-def-regex
120 (fuel-syntax--second-word-regex '("CHAR:" "BIN:" "HEX:" "OCT:")))
122 (defconst fuel-syntax--type-definition-regex
123 (fuel-syntax--second-word-regex '("MIXIN:" "TUPLE:" "SINGLETON:" "UNION:")))
125 (defconst fuel-syntax--tuple-decl-regex
126 "^TUPLE: +\\([^ \n]+\\) +< +\\([^ \n]+\\)\\_>")
128 (defconst fuel-syntax--constructor-regex "<[^ >]+>")
130 (defconst fuel-syntax--getter-regex "\\(^\\|\\_<\\)[^ ]+?>>\\_>")
131 (defconst fuel-syntax--setter-regex "\\_<>>.+?\\_>")
133 (defconst fuel-syntax--symbol-definition-regex
134 (fuel-syntax--second-word-regex '("SYMBOL:" "VAR:")))
136 (defconst fuel-syntax--stack-effect-regex
137 "\\( ( .* )\\)\\|\\( (( .* ))\\)")
139 (defconst fuel-syntax--using-lines-regex "^USING: +\\([^;]+\\);")
141 (defconst fuel-syntax--use-line-regex "^USE: +\\(.*\\)$")
143 (defconst fuel-syntax--current-vocab-regex "^IN: +\\([^ \r\n\f]+\\)")
145 (defconst fuel-syntax--sub-vocab-regex "^<\\([^ \n]+\\) *$")
147 (defconst fuel-syntax--indent-def-starts '("" ":"
148 "FROM"
149 "INTERSECTION:"
150 "M" "MACRO" "MACRO:"
151 "MEMO" "MEMO:" "METHOD"
152 "PREDICATE" "PRIMITIVE"
153 "UNION"))
155 (defconst fuel-syntax--no-indent-def-starts '("SINGLETONS"
156 "SYMBOLS"
157 "TUPLE"
158 "VARS"))
160 (defconst fuel-syntax--indent-def-start-regex
161 (format "^\\(%s:\\) " (regexp-opt fuel-syntax--indent-def-starts)))
163 (defconst fuel-syntax--no-indent-def-start-regex
164 (format "^\\(%s:\\) " (regexp-opt fuel-syntax--no-indent-def-starts)))
166 (defconst fuel-syntax--definition-start-regex
167 (format "^\\(%s:\\) " (regexp-opt (append fuel-syntax--no-indent-def-starts
168 fuel-syntax--indent-def-starts))))
170 (defconst fuel-syntax--definition-end-regex
171 (format "\\(\\(^\\| +\\);\\( *%s\\)*\\($\\| +\\)\\)"
172 fuel-syntax--declaration-words-regex))
174 (defconst fuel-syntax--single-liner-regex
175 (regexp-opt '("ABOUT:"
176 "ARTICLE:"
177 "ALIAS:"
178 "CONSTANT:" "C:"
179 "DEFER:"
180 "FORGET:"
181 "GENERIC:" "GENERIC#"
182 "HELP:" "HEX:" "HOOK:"
183 "IN:" "INSTANCE:"
184 "MAIN:" "MATH:" "MIXIN:"
185 "OCT:"
186 "POSTPONE:" "PRIVATE>" "<PRIVATE"
187 "QUALIFIED-WITH:" "QUALIFIED:"
188 "RENAME:"
189 "SINGLETON:" "SLOT:" "SYMBOL:"
190 "TYPEDEF:"
191 "USE:"
192 "VAR:")))
194 (defconst fuel-syntax--begin-of-def-regex
195 (format "^USING: \\|\\(%s\\)\\|\\(^%s .*\\)"
196 fuel-syntax--definition-start-regex
197 fuel-syntax--single-liner-regex))
199 (defconst fuel-syntax--end-of-def-line-regex
200 (format "^.*%s" fuel-syntax--definition-end-regex))
202 (defconst fuel-syntax--end-of-def-regex
203 (format "\\(%s\\)\\|\\(^%s .*\\)"
204 fuel-syntax--end-of-def-line-regex
205 fuel-syntax--single-liner-regex))
207 (defconst fuel-syntax--defun-signature-regex
208 (format "\\(%s\\|%s\\)"
209 (format ":[^ ]* [^ ]+\\(%s\\)*" fuel-syntax--stack-effect-regex)
210 "M[^:]*: [^ ]+ [^ ]+"))
212 (defconst fuel-syntax--constructor-decl-regex
213 "\\_<C: +\\(\\w+\\) +\\(\\w+\\)\\( .*\\)?$")
215 (defconst fuel-syntax--typedef-regex
216 "\\_<TYPEDEF: +\\(\\w+\\) +\\(\\w+\\)\\( .*\\)?$")
218 (defconst fuel-syntax--rename-regex
219 "\\_<RENAME: +\\(\\w+\\) +\\(\\w+\\) +=> +\\(\\w+\\)\\( .*\\)?$")
222 ;;; Factor syntax table
224 (setq fuel-syntax--syntax-table
225 (let ((table (make-syntax-table)))
226 ;; Default is word constituent
227 (dotimes (i 256)
228 (modify-syntax-entry i "w" table))
230 ;; Whitespace (TAB is not whitespace)
231 (modify-syntax-entry ?\f " " table)
232 (modify-syntax-entry ?\r " " table)
233 (modify-syntax-entry ?\ " " table)
234 (modify-syntax-entry ?\n " " table)
236 ;; Char quote
237 (modify-syntax-entry ?\\ "/" table)
239 table))
241 (defconst fuel-syntax--syntactic-keywords
242 `(;; CHARs:
243 ("\\(CHAR:\\|POSTPONE:\\|\\\\\\) \\(.\\)\\( \\|$\\)" (2 "w"))
244 ;; Comments:
245 ("\\_<\\(#?!\\) .*\\(\n\\|$\\)" (1 "<") (2 ">"))
246 ("\\_<\\(#?!\\)\\(\n\\|$\\)" (1 "<") (2 ">"))
247 (" \\((\\)( \\([^\n]*\\) )\\()\\)\\( \\|\n\\)" (1 "<b") (2 "w") (3 ">b"))
248 (" \\((\\) \\([^\n]*\\) \\()\\)\\( \\|\n\\)" (1 "<b") (2 "w") (3 ">b"))
249 ;; Strings
250 ("\\( \\|^\\)\\(\"\\)[^\n\r\f]*\\(\"\\)\\( \\|\n\\)" (2 "\"") (3 "\""))
251 ("\\_<<\\(\"\\)\\_>" (1 "<b"))
252 ("\\_<\\(\"\\)>\\_>" (1 ">b"))
253 ;; Multiline constructs
254 ("\\_<\\(U\\)SING: \\(;\\)" (1 "<b") (2 ">b"))
255 ("\\_<USING:\\( \\)" (1 "<b"))
256 ("\\_<TUPLE: +\\w+? +< +\\w+? *\\( \\|\n\\)\\([^;]\\|$\\)" (1 "<b"))
257 ("\\_<\\(TUPLE\\|SYMBOLS\\|VARS\\): +\\w+? *\\( \\|\n\\)\\([^;<\n]\\|\\_>\\)"
258 (2 "<b"))
259 ("\\(\n\\| \\);\\_>" (1 ">b"))
260 ;; Let and lambda:
261 ("\\_<\\(!(\\) .* \\()\\)" (1 "<") (2 ">"))
262 ("\\(\\[\\)\\(let\\|wlet\\|let\\*\\)\\( \\|$\\)" (1 "(]"))
263 ("\\(\\[\\)\\(|\\) +[^|]* \\(|\\)" (1 "(]") (2 "(|") (3 ")|"))
264 (" \\(|\\) " (1 "(|"))
265 (" \\(|\\)$" (1 ")"))
266 ;; Opening brace words:
267 ("\\_<\\w*\\({\\)\\_>" (1 "(}"))
268 ("\\_<\\(}\\)\\_>" (1 "){"))
269 ;; Parenthesis:
270 ("\\_<\\((\\)\\_>" (1 "()"))
271 ("\\_<\\()\\)\\_>" (1 ")("))
272 ;; Quotations:
273 ("\\_<'\\(\\[\\)\\_>" (1 "(]")) ; fried
274 ("\\_<\\(\\[\\)\\_>" (1 "(]"))
275 ("\\_<\\(\\]\\)\\_>" (1 ")["))))
278 ;;; Source code analysis:
280 (defsubst fuel-syntax--brackets-depth ()
281 (nth 0 (syntax-ppss)))
283 (defsubst fuel-syntax--brackets-start ()
284 (nth 1 (syntax-ppss)))
286 (defun fuel-syntax--brackets-end ()
287 (save-excursion
288 (goto-char (fuel-syntax--brackets-start))
289 (condition-case nil
290 (progn (forward-sexp)
291 (1- (point)))
292 (error -1))))
294 (defsubst fuel-syntax--indentation-at (pos)
295 (save-excursion (goto-char pos) (current-indentation)))
297 (defsubst fuel-syntax--increased-indentation (&optional i)
298 (+ (or i (current-indentation)) factor-indent-width))
299 (defsubst fuel-syntax--decreased-indentation (&optional i)
300 (- (or i (current-indentation)) factor-indent-width))
302 (defsubst fuel-syntax--at-begin-of-def ()
303 (looking-at fuel-syntax--begin-of-def-regex))
305 (defsubst fuel-syntax--at-begin-of-indent-def ()
306 (looking-at fuel-syntax--indent-def-start-regex))
308 (defsubst fuel-syntax--at-end-of-def ()
309 (looking-at fuel-syntax--end-of-def-regex))
311 (defsubst fuel-syntax--looking-at-emptiness ()
312 (looking-at "^[ ]*$\\|$"))
314 (defsubst fuel-syntax--is-last-char (pos)
315 (save-excursion
316 (goto-char (1+ pos))
317 (fuel-syntax--looking-at-emptiness)))
319 (defsubst fuel-syntax--line-offset (pos)
320 (- pos (save-excursion
321 (goto-char pos)
322 (beginning-of-line)
323 (point))))
325 (defun fuel-syntax--previous-non-blank ()
326 (forward-line -1)
327 (while (and (not (bobp)) (fuel-syntax--looking-at-emptiness))
328 (forward-line -1)))
330 (defun fuel-syntax--beginning-of-block-pos ()
331 (save-excursion
332 (if (> (fuel-syntax--brackets-depth) 0)
333 (fuel-syntax--brackets-start)
334 (fuel-syntax--beginning-of-defun)
335 (point))))
337 (defun fuel-syntax--at-setter-line ()
338 (save-excursion
339 (beginning-of-line)
340 (when (re-search-forward fuel-syntax--setter-regex
341 (line-end-position)
343 (let* ((to (match-beginning 0))
344 (from (fuel-syntax--beginning-of-block-pos)))
345 (goto-char from)
346 (let ((depth (fuel-syntax--brackets-depth)))
347 (and (or (re-search-forward fuel-syntax--constructor-regex to t)
348 (re-search-forward fuel-syntax--setter-regex to t))
349 (= depth (fuel-syntax--brackets-depth))))))))
351 (defun fuel-syntax--at-constructor-line ()
352 (save-excursion
353 (beginning-of-line)
354 (re-search-forward fuel-syntax--constructor-regex (line-end-position) t)))
356 (defsubst fuel-syntax--at-using ()
357 (looking-at fuel-syntax--using-lines-regex))
359 (defun fuel-syntax--in-using ()
360 (let ((p (point)))
361 (save-excursion
362 (and (re-search-backward "^USING: " nil t)
363 (re-search-forward " ;" nil t)
364 (< p (match-end 0))))))
366 (defsubst fuel-syntax--beginning-of-defun (&optional times)
367 (re-search-backward fuel-syntax--begin-of-def-regex nil t times))
369 (defsubst fuel-syntax--end-of-defun ()
370 (re-search-forward fuel-syntax--end-of-def-regex nil t))
372 (defsubst fuel-syntax--end-of-defun-pos ()
373 (save-excursion
374 (re-search-forward fuel-syntax--end-of-def-regex nil t)
375 (point)))
377 (defun fuel-syntax--beginning-of-body ()
378 (let ((p (point)))
379 (and (fuel-syntax--beginning-of-defun)
380 (re-search-forward fuel-syntax--defun-signature-regex p t)
381 (not (re-search-forward fuel-syntax--end-of-def-regex p t)))))
383 (defun fuel-syntax--beginning-of-sexp ()
384 (if (> (fuel-syntax--brackets-depth) 0)
385 (goto-char (fuel-syntax--brackets-start))
386 (fuel-syntax--beginning-of-body)))
388 (defsubst fuel-syntax--beginning-of-sexp-pos ()
389 (save-excursion (fuel-syntax--beginning-of-sexp) (point)))
392 ;;; USING/IN:
394 (make-variable-buffer-local
395 (defvar fuel-syntax--current-vocab-function 'fuel-syntax--find-in))
397 (defsubst fuel-syntax--current-vocab ()
398 (funcall fuel-syntax--current-vocab-function))
400 (defun fuel-syntax--find-in ()
401 (save-excursion
402 (when (re-search-backward fuel-syntax--current-vocab-regex nil t)
403 (match-string-no-properties 1))))
405 (make-variable-buffer-local
406 (defvar fuel-syntax--usings-function 'fuel-syntax--find-usings))
408 (defsubst fuel-syntax--usings ()
409 (funcall fuel-syntax--usings-function))
411 (defun fuel-syntax--file-has-private ()
412 (save-excursion
413 (goto-char (point-min))
414 (and (re-search-forward "\\_<<PRIVATE\\_>" nil t)
415 (re-search-forward "\\_<PRIVATE>\\_>" nil t))))
417 (defun fuel-syntax--find-usings (&optional no-private)
418 (save-excursion
419 (let ((usings))
420 (goto-char (point-max))
421 (while (re-search-backward fuel-syntax--using-lines-regex nil t)
422 (dolist (u (split-string (match-string-no-properties 1) nil t))
423 (push u usings)))
424 (when (and (not no-private) (fuel-syntax--file-has-private))
425 (goto-char (point-max))
426 (push (concat (fuel-syntax--find-in) ".private") usings))
427 usings)))
430 (provide 'fuel-syntax)
431 ;;; fuel-syntax.el ends here