Mercurial > emacs
comparison lisp/progmodes/antlr-mode.el @ 26542:0d41332e3819
Major mode for ANTLR grammar files.
author | Gerd Moellmann <gerd@gnu.org> |
---|---|
date | Mon, 22 Nov 1999 15:18:35 +0000 |
parents | |
children | 048db40ddca6 |
comparison
equal
deleted
inserted
replaced
26541:ce6bf7b42bc7 | 26542:0d41332e3819 |
---|---|
1 ;;; antlr-mode.el --- Major mode for ANTLR grammar files | |
2 | |
3 ;; Copyright (C) 1999 Free Software Foundation, Inc. | |
4 ;; | |
5 ;; Author: Christoph.Wedler@sap.com | |
6 ;; Version: $Id: antlr-mode.el,v 1.2 1999/11/11 14:40:51 wedler Exp $ | |
7 | |
8 ;; This file is part of GNU Emacs. | |
9 | |
10 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
11 ;; it under the terms of the GNU General Public License as published by | |
12 ;; the Free Software Foundation; either version 2, or (at your option) | |
13 ;; any later version. | |
14 | |
15 ;; GNU Emacs is distributed in the hope that it will be useful, | |
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 ;; GNU General Public License for more details. | |
19 | |
20 ;; You should have received a copy of the GNU General Public License | |
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
23 ;; Boston, MA 02111-1307, USA. | |
24 | |
25 ;;; Commentary: | |
26 | |
27 ;; Major mode for editing ANTLR grammar files, i.e., files ending with `.g'. | |
28 ;; ANTLR is ANother Tool for Language Recognition (an excellent alternative to | |
29 ;; lex/yacc), see <http://www.ANTLR.org> and <news:comp.compilers.tools.pccts>. | |
30 | |
31 ;; Variable `antlr-language' is set according to the language in actions and | |
32 ;; semantic predicates of the grammar (see ANTLR's file option "language"). | |
33 ;; The supported languages are "Java" (java-mode) and "Cpp" (c++-mode). This | |
34 ;; package uses features of the Emacs package cc-mode. | |
35 | |
36 ;; This package provides the following features: | |
37 ;; * Indentation for the current line (TAB) and selected region (C-M-\). | |
38 ;; * Syntax coloring (via font-lock) with language dependend coloring. | |
39 ;; * Support for imenu/speedbar: menu "Index" (Parser, Lexer, TreeParser). | |
40 ;; * Direct move to previous/next rule, beginning/end of rule body etc. | |
41 | |
42 ;; INDENTATION. This package supports ANTLR's (intended) indentation style | |
43 ;; which is based on a simple paren/brace/bracket depth-level calculation, see | |
44 ;; `antlr-indent-line'. The indentation engine of cc-mode is only used inside | |
45 ;; block comments (it is not easy to use it for actions, esp if they come early | |
46 ;; in the rule body). By default, this package uses TABs for a basic offset of | |
47 ;; 4 to be consistent to both ANTLR's conventions (TABs usage) and the | |
48 ;; `c-indentation-style' "java" which sets `c-basic-offset' to 4, see | |
49 ;; `antlr-tab-offset-alist'. | |
50 | |
51 ;; SYNTAX COLORING comes in three phases. First, comments and strings are | |
52 ;; highlighted. Second, the grammar code is highlighted according to | |
53 ;; `antlr-font-lock-additional-keywords' (rule refs: blue, token refs: brown, | |
54 ;; definition: ditto+bold). Third, actions, semantic predicates and arguments | |
55 ;; are highlighted according to the usual font-lock keywords of | |
56 ;; `antlr-language', see also `antlr-font-lock-maximum-decoration'. We define | |
57 ;; special font-lock faces for the grammar code to allow you to distinguish | |
58 ;; ANTLR keywords from Java/C++ keywords. | |
59 | |
60 ;;; Installation: | |
61 | |
62 ;; This file requires Emacs-20.3, XEmacs-20.4 or higher. | |
63 | |
64 ;; If antlr-mode is not part of your distribution, put this file into your | |
65 ;; load-path and the following into your ~/.emacs: | |
66 ;; (autoload 'antlr-mode "antlr-mode" nil t) | |
67 ;; (setq auto-mode-alist (cons '("\\.g\\'" . antlr-mode) auto-mode-alist)) | |
68 ;; (add-hook 'speedbar-load-hook ; would be too late in antlr-mode.el | |
69 ;; (lambda () (speedbar-add-supported-extension ".g"))) | |
70 | |
71 ;; If you edit ANTLR's source files, you might also want to use | |
72 ;; (autoload 'antlr-set-tabs "antlr-mode") | |
73 ;; (add-hook 'java-mode-hook 'antlr-set-tabs) | |
74 | |
75 ;; To customize, use `M-x customize-group RET antlr RET' or the custom browser | |
76 ;; (Emacs->Programming->Languages->Antlr). | |
77 | |
78 ;;; Code: | |
79 | |
80 (provide 'antlr-mode) | |
81 (eval-when-compile (require 'cl)) | |
82 (require 'easymenu) ; Emacs | |
83 (eval-when-compile (require 'cc-mode)) ; shut up most warnings | |
84 | |
85 (eval-and-compile | |
86 (if (string-match "XEmacs" emacs-version) | |
87 (defalias 'antlr-scan-sexps 'scan-sexps) | |
88 (defalias 'antlr-scan-sexps 'antlr-scan-sexps-internal)) | |
89 (if (and (fboundp 'buffer-syntactic-context) | |
90 (fboundp 'buffer-syntactic-context-depth)) | |
91 (progn | |
92 (defalias 'antlr-invalidate-context-cache 'antlr-xemacs-bug-workaround) | |
93 (defalias 'antlr-syntactic-context 'antlr-fast-syntactic-context)) | |
94 (defalias 'antlr-invalidate-context-cache 'ignore) | |
95 (defalias 'antlr-syntactic-context 'antlr-slow-syntactic-context))) | |
96 | |
97 | |
98 | |
99 ;;;;########################################################################## | |
100 ;;;; Variables | |
101 ;;;;########################################################################## | |
102 | |
103 | |
104 (defgroup antlr nil | |
105 "Major mode for ANTLR grammar files." | |
106 :group 'languages | |
107 :link '(emacs-commentary-link "antlr-mode.el") | |
108 :prefix "antlr-") | |
109 | |
110 (defconst antlr-version "1.2" | |
111 "ANTLR major mode version number.") | |
112 | |
113 | |
114 ;;;=========================================================================== | |
115 ;;; Controlling ANTLR's code generator (language option) | |
116 ;;;=========================================================================== | |
117 | |
118 (defvar antlr-language nil | |
119 "Major mode corresponding to ANTLR's \"language\" option. | |
120 Set via `antlr-language-alist'. The only useful place to change this | |
121 buffer-local variable yourself is in `antlr-mode-hook' or in the \"local | |
122 variable list\" near the end of the file, see | |
123 `enable-local-variables'.") | |
124 | |
125 (defcustom antlr-language-alist | |
126 '((java-mode "Java" nil "Java") | |
127 (c++-mode "C++" "Cpp")) | |
128 "List of ANTLR's supported languages. | |
129 Each element in this list looks like | |
130 (MAJOR-MODE MODELINE-STRING OPTION-VALUE...) | |
131 | |
132 MAJOR-MODE, the major mode of the code in the grammar's actions, is the | |
133 value of `antlr-language' if the first regexp group matched by REGEXP in | |
134 `antlr-language-limit-n-regexp' is one of the OPTION-VALUEs. An | |
135 OPTION-VALUE of nil denotes the fallback element. MODELINE-STRING is | |
136 also displayed in the modeline next to \"Antlr\"." | |
137 :group 'antlr | |
138 :type '(repeat (group :value (java-mode "") | |
139 (function :tag "Major mode") | |
140 (string :tag "Modeline string") | |
141 (repeat :tag "ANTLR language option" :inline t | |
142 (choice (const :tag "Default" nil) | |
143 string ))))) | |
144 | |
145 (defcustom antlr-language-limit-n-regexp | |
146 '(3000 . "language[ \t]*=[ \t]*\"\\([A-Z][A-Za-z_]*\\)\"") | |
147 "Used to set a reasonable value for `antlr-language'. | |
148 Looks like (LIMIT . REGEXP). Search for REGEXP from the beginning of | |
149 the buffer to LIMIT to set the language according to | |
150 `antlr-language-alist'." | |
151 :group 'antlr | |
152 :type '(cons (choice :tag "Limit" (const :tag "No" nil) (integer :value 0)) | |
153 regexp)) | |
154 | |
155 | |
156 ;;;=========================================================================== | |
157 ;;; Indent/Tabs | |
158 ;;;=========================================================================== | |
159 | |
160 (defcustom antlr-indent-comment 'tab | |
161 "*Non-nil, if the indentation should touch lines in block comments. | |
162 If nil, no continuation line of a block comment is changed. If t, they | |
163 are changed according to `c-indentation-line'. When not nil and not t, | |
164 they are only changed by \\[antlr-indent-command]." | |
165 :group 'antlr | |
166 :type '(radio (const :tag "No" nil) | |
167 (const :tag "Always" t) | |
168 (sexp :tag "With TAB" :format "%t" :value tab))) | |
169 | |
170 (defcustom antlr-tab-offset-alist | |
171 '((antlr-mode nil 4 t) | |
172 (java-mode "antlr" 4 t)) | |
173 "Alist to determine whether to use ANTLR's convention for TABs. | |
174 Each element looks like (MAJOR-MODE REGEXP TAB-WIDTH INDENT-TABS-MODE). | |
175 The first element whose MAJOR-MODE is nil or equal to `major-mode' and | |
176 whose REGEXP is nil or matches `buffer-file-name' is used to set | |
177 `tab-width' and `indent-tabs-mode'. This is useful to support both | |
178 ANTLR's and Java's indentation styles. Used by `antlr-set-tabs'." | |
179 :group 'antlr | |
180 :type '(repeat (group :value (antlr-mode nil 8 nil) | |
181 (choice (const :tag "All" nil) | |
182 (function :tag "Major mode")) | |
183 (choice (const :tag "All" nil) regexp) | |
184 (integer :tag "Tab width") | |
185 (boolean :tag "Indent-tabs-mode")))) | |
186 | |
187 (defvar antlr-indent-item-regexp | |
188 "[]}):;|&]\\|default[ \t]*:\\|case[ \t]+\\('\\\\?.'\\|[0-9]+\\|[A-Za-z_][A-Za-z_0-9]*\\)[ \t]*:" ; & is local ANTLR extension | |
189 "Regexp matching lines which should be indented by one TAB less. | |
190 See command \\[antlr-indent-command].") | |
191 | |
192 | |
193 ;;;=========================================================================== | |
194 ;;; Menu | |
195 ;;;=========================================================================== | |
196 | |
197 (defcustom antlr-imenu-name t | |
198 "*Non-nil, if a \"Index\" menu should be added to the menubar. | |
199 If it is a string, it is used instead \"Index\". Requires package | |
200 imenu." | |
201 :group 'antlr | |
202 :type '(choice (const :tag "No menu" nil) | |
203 (const :tag "Index menu" t) | |
204 (string :tag "Other menu name"))) | |
205 | |
206 (defvar antlr-mode-map | |
207 (let ((map (make-sparse-keymap))) | |
208 (define-key map "\t" 'antlr-indent-command) | |
209 (define-key map "\e\C-a" 'antlr-beginning-of-rule) | |
210 (define-key map "\e\C-e" 'antlr-end-of-rule) | |
211 (define-key map "\C-c\C-a" 'antlr-beginning-of-body) | |
212 (define-key map "\C-c\C-e" 'antlr-end-of-body) | |
213 (define-key map "\C-c\C-f" 'c-forward-into-nomenclature) | |
214 (define-key map "\C-c\C-b" 'c-backward-into-nomenclature) | |
215 ;; I'm too lazy to define my own: | |
216 (define-key map "\ea" 'c-beginning-of-statement) | |
217 (define-key map "\ee" 'c-end-of-statement) | |
218 map) | |
219 "Keymap used in `antlr-mode' buffers.") | |
220 | |
221 (easy-menu-define antlr-mode-menu | |
222 antlr-mode-map | |
223 "Major mode menu." | |
224 '("Antlr" | |
225 ["Indent Line" antlr-indent-command | |
226 :active (not buffer-read-only)] | |
227 ["Indent for Comment" indent-for-comment | |
228 :active (not buffer-read-only)] | |
229 ["Backward Rule" antlr-beginning-of-rule t] | |
230 ["Forward Rule" antlr-end-of-rule t] | |
231 ["Start of Rule Body" antlr-beginning-of-body | |
232 :active (antlr-inside-rule-p)] | |
233 ["End of Rule Body" antlr-end-of-body | |
234 :active (antlr-inside-rule-p)] | |
235 "---" | |
236 ["Backward Statement" c-beginning-of-statement t] | |
237 ["Forward Statement" c-end-of-statement t] | |
238 ["Backward Into Nomencl." c-backward-into-nomenclature t] | |
239 ["Forward Into Nomencl." c-forward-into-nomenclature t])) | |
240 | |
241 | |
242 ;;;=========================================================================== | |
243 ;;; font-lock | |
244 ;;;=========================================================================== | |
245 | |
246 (defcustom antlr-font-lock-maximum-decoration 'inherit | |
247 "*The maximum decoration level for fontifying actions. | |
248 Value `none' means, do not fontify actions, just normal grammar code | |
249 according to `antlr-font-lock-additional-keywords'. Value `inherit' | |
250 means, use value of `font-lock-maximum-decoration'. Any other value is | |
251 interpreted as in `font-lock-maximum-decoration' with no level-0 | |
252 fontification, see `antlr-font-lock-keywords-alist'. | |
253 | |
254 While calculating the decoration level for actions, `major-mode' is | |
255 bound to `antlr-language'. For example, with value | |
256 ((java-mode . 2) (c++-mode . 0)) | |
257 Java actions are fontified with level 2 and C++ actions are not | |
258 fontified at all." | |
259 :type '(choice (const :tag "none" none) | |
260 (const :tag "inherit" inherit) | |
261 (const :tag "default" nil) | |
262 (const :tag "maximum" t) | |
263 (integer :tag "level" 1) | |
264 (repeat :menu-tag "mode specific" :tag "mode specific" | |
265 :value ((t . t)) | |
266 (cons :tag "Instance" | |
267 (radio :tag "Mode" | |
268 (const :tag "all" t) | |
269 (symbol :tag "name")) | |
270 (radio :tag "Decoration" | |
271 (const :tag "default" nil) | |
272 (const :tag "maximum" t) | |
273 (integer :tag "level" 1)))))) | |
274 | |
275 (defvar antlr-font-lock-keywords-alist | |
276 '((java-mode | |
277 (list) ; nil won't work (would use level-3) | |
278 java-font-lock-keywords-1 java-font-lock-keywords-2 | |
279 java-font-lock-keywords-3) | |
280 (c++-mode | |
281 (list) ; nil won't work (would use level-3) | |
282 c++-font-lock-keywords-1 c++-font-lock-keywords-2 | |
283 c++-font-lock-keywords-3)) | |
284 "List of font-lock keywords for actions in the grammar. | |
285 Each element in this list looks like | |
286 (MAJOR-MODE KEYWORD...) | |
287 | |
288 If `antlr-language' is equal to MAJOR-MODE, the KEYWORDs are the | |
289 font-lock keywords according to `font-lock-defaults' used for the code | |
290 in the grammar's actions and semantic predicates, see | |
291 `antlr-font-lock-maximum-decoration'.") | |
292 | |
293 (defvar antlr-font-lock-keyword-face 'antlr-font-lock-keyword-face) | |
294 (defface antlr-font-lock-keyword-face | |
295 '((((class color) (background light)) (:foreground "black" :bold t))) | |
296 "ANTLR keywords." | |
297 :group 'antlr) | |
298 | |
299 (defvar antlr-font-lock-ruledef-face 'antlr-font-lock-ruledef-face) | |
300 (defface antlr-font-lock-ruledef-face | |
301 '((((class color) (background light)) (:foreground "blue" :bold t))) | |
302 "ANTLR rule references (definition)." | |
303 :group 'antlr) | |
304 | |
305 (defvar antlr-font-lock-tokendef-face 'antlr-font-lock-tokendef-face) | |
306 (defface antlr-font-lock-tokendef-face | |
307 '((((class color) (background light)) (:foreground "brown3" :bold t))) | |
308 "ANTLR token references (definition)." | |
309 :group 'antlr) | |
310 | |
311 (defvar antlr-font-lock-ruleref-face 'antlr-font-lock-ruleref-face) | |
312 (defface antlr-font-lock-ruleref-face | |
313 '((((class color) (background light)) (:foreground "blue4"))) | |
314 "ANTLR rule references (usage)." | |
315 :group 'antlr) | |
316 | |
317 (defvar antlr-font-lock-tokenref-face 'antlr-font-lock-tokenref-face) | |
318 (defface antlr-font-lock-tokenref-face | |
319 '((((class color) (background light)) (:foreground "brown4"))) | |
320 "ANTLR token references (usage)." | |
321 :group 'antlr) | |
322 | |
323 (defvar antlr-font-lock-literal-face 'antlr-font-lock-literal-face) | |
324 (defface antlr-font-lock-literal-face | |
325 '((((class color) (background light)) (:foreground "brown4" :bold t))) | |
326 "ANTLR literal tokens consisting merely of letter-like characters." | |
327 :group 'antlr) | |
328 | |
329 (defvar antlr-font-lock-additional-keywords | |
330 `((antlr-invalidate-context-cache) | |
331 ("\\$setType[ \t]*(\\([A-Z\300-\326\330-\337]\\sw*\\))" | |
332 (1 antlr-font-lock-tokendef-face)) | |
333 ("\\$\\sw+" (0 font-lock-keyword-face)) | |
334 ;; the tokens are already fontified as string/docstrings: | |
335 (,(lambda (limit) | |
336 (antlr-re-search-forward "\"\\(\\sw\\(\\sw\\|-\\)*\\)\"" limit)) | |
337 (1 antlr-font-lock-literal-face t)) | |
338 (,(lambda (limit) | |
339 (antlr-re-search-forward | |
340 "^\\(class\\)[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]+\\(extends\\)[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]*;" limit)) | |
341 (1 antlr-font-lock-keyword-face) | |
342 (2 antlr-font-lock-ruledef-face) | |
343 (3 antlr-font-lock-keyword-face) | |
344 (4 (if (member (match-string 4) '("Lexer" "Parser" "TreeParser")) | |
345 'antlr-font-lock-keyword-face | |
346 'font-lock-type-face))) | |
347 (,(lambda (limit) | |
348 (antlr-re-search-forward | |
349 "\\<\\(header\\|options\\|tokens\\|exception\\|catch\\|returns\\)\\>" | |
350 limit)) | |
351 (1 antlr-font-lock-keyword-face)) | |
352 (,(lambda (limit) | |
353 (antlr-re-search-forward | |
354 "^\\(private\\|public\\|protected\\)\\>\\([ \t]+\\(\\sw+\\)\\)?" | |
355 limit)) | |
356 (1 font-lock-type-face) ; not XEmacs' java level-3 fruit salad | |
357 (3 (if (antlr-upcase-p (char-after (match-beginning 3))) | |
358 'antlr-font-lock-tokendef-face | |
359 'antlr-font-lock-ruledef-face) nil t)) | |
360 (,(lambda (limit) | |
361 (antlr-re-search-forward "^\\sw+" limit)) | |
362 (0 (if (antlr-upcase-p (char-after (match-beginning 0))) | |
363 'antlr-font-lock-tokendef-face | |
364 'antlr-font-lock-ruledef-face) nil t)) | |
365 (,(lambda (limit) | |
366 ;; not only before a rule ref, also before a literal | |
367 (antlr-re-search-forward "\\<\\(\\sw+\\)[ \t]*:" limit)) | |
368 (1 font-lock-variable-name-face)) | |
369 (,(lambda (limit) | |
370 (antlr-re-search-forward "\\<\\(\\sw+[ \t]*=[ \t]*\\)?\\(\\sw+[ \t]*:[ \t]*\\)?\\(\\sw+\\)" limit)) | |
371 ;;(1 antlr-font-lock-default-face nil t) ; fool java-font-lock-keywords | |
372 (3 (if (antlr-upcase-p (char-after (match-beginning 3))) | |
373 'antlr-font-lock-tokenref-face | |
374 'antlr-font-lock-ruleref-face)))) | |
375 "Font-lock keywords for ANTLR's normal grammar code. | |
376 See `antlr-font-lock-keywords-alist' for the keywords of actions.") | |
377 | |
378 (defvar antlr-font-lock-defaults | |
379 '(antlr-font-lock-keywords | |
380 nil nil ((?_ . "w") (?\( . ".") (?\) . ".")) beginning-of-defun) | |
381 "Font-lock defaults used for ANTLR syntax coloring. | |
382 The SYNTAX-ALIST element is also used to initialize | |
383 `antlr-action-syntax-table'.") | |
384 | |
385 | |
386 ;;;=========================================================================== | |
387 ;;; Internal variables | |
388 ;;;=========================================================================== | |
389 | |
390 (defvar antlr-mode-hook nil | |
391 "Hook called by `antlr-mode'.") | |
392 | |
393 ;; used for "in Java/C++ code" = syntactic-depth>0 | |
394 (defvar antlr-action-syntax-table nil | |
395 "Syntax table used for ANTLR action parsing. | |
396 Initialized by `java-mode-syntax-table', i.e., the syntax table used for | |
397 grammar files, changed by SYNTAX-ALIST in `antlr-font-lock-defaults'. | |
398 This table should be selected if you use `buffer-syntactic-context' and | |
399 `buffer-syntactic-context-depth' in order not to confuse their | |
400 context_cache.") | |
401 | |
402 (defvar antlr-mode-abbrev-table nil | |
403 "Abbreviation table used in `antlr-mode' buffers.") | |
404 (define-abbrev-table 'antlr-mode-abbrev-table ()) | |
405 | |
406 | |
407 | |
408 ;;;;########################################################################## | |
409 ;;;; The Code | |
410 ;;;;########################################################################## | |
411 | |
412 | |
413 ;;;=========================================================================== | |
414 ;;; Syntax functions -- Emacs vs XEmacs dependent | |
415 ;;;=========================================================================== | |
416 | |
417 ;; From help.el (XEmacs-21.1) | |
418 (defmacro antlr-with-syntax-table (syntab &rest body) | |
419 `(let ((stab (syntax-table))) | |
420 (unwind-protect | |
421 (progn (set-syntax-table (copy-syntax-table ,syntab)) ,@body) | |
422 (set-syntax-table stab)))) | |
423 (put 'antlr-with-syntax-table 'lisp-indent-function 1) | |
424 (put 'antlr-with-syntax-table 'edebug-form-spec '(form body)) | |
425 | |
426 (defun antlr-scan-sexps-internal (from count &optional dummy no-error) | |
427 ;; checkdoc-params: (from count dummy) | |
428 "Like `scan-sexps' but with additional arguments. | |
429 When optional arg NO-ERROR is non-nil, `scan-sexps' will return nil | |
430 instead of signalling an error." | |
431 (if no-error | |
432 (condition-case nil | |
433 (scan-sexps from count) | |
434 (t nil)) | |
435 (scan-sexps from count))) | |
436 | |
437 (defun antlr-xemacs-bug-workaround (&rest dummies) | |
438 ;; checkdoc-params: (dummies) | |
439 "Invalidate context_cache for syntactical context information." | |
440 ;; XEmacs bug workaround | |
441 (save-excursion | |
442 (set-buffer (get-buffer-create " ANTLR XEmacs bug workaround")) | |
443 (buffer-syntactic-context-depth)) | |
444 nil) | |
445 | |
446 (defun antlr-fast-syntactic-context () | |
447 "Return some syntactic context information. | |
448 Return `string' if point is within a string, `block-comment' or | |
449 `comment' is point is within a comment or the depth within all | |
450 parenthesis-syntax delimiters at point otherwise. | |
451 WARNING: this may alter `match-data'." | |
452 (or (buffer-syntactic-context) (buffer-syntactic-context-depth))) | |
453 | |
454 (defun antlr-slow-syntactic-context () | |
455 "Return some syntactic context information. | |
456 Return `string' if point is within a string, `block-comment' or | |
457 `comment' is point is within a comment or the depth within all | |
458 parenthesis-syntax delimiters at point otherwise. | |
459 WARNING: this may alter `match-data'." | |
460 (let ((orig (point))) | |
461 (beginning-of-defun) | |
462 (let ((state (parse-partial-sexp (point) orig))) | |
463 (goto-char orig) | |
464 (cond ((nth 3 state) 'string) | |
465 ((nth 4 state) 'comment) ; block-comment? -- we don't care | |
466 (t (car state)))))) | |
467 | |
468 | |
469 ;;;=========================================================================== | |
470 ;;; Misc functions | |
471 ;;;=========================================================================== | |
472 | |
473 (defun antlr-upcase-p (char) | |
474 "Non-nil, if CHAR is an uppercase character (if CHAR was a char)." | |
475 ;; in XEmacs, upcase only works for ASCII | |
476 (or (and (<= ?A char) (<= char ?Z)) | |
477 (and (<= ?\300 char) (<= char ?\337)))) ; ?\327 is no letter | |
478 | |
479 (defun antlr-re-search-forward (regexp bound) | |
480 "Search forward from point for regular expression REGEXP. | |
481 Set point to the end of the occurrence found, and return point. Return | |
482 nil if no occurence was found. Do not search within comments, strings | |
483 and actions/semantic predicates. BOUND bounds the search; it is a | |
484 buffer position. See also the functions `match-beginning', `match-end' | |
485 and `replace-match'." | |
486 ;; WARNING: Should only be used with `antlr-action-syntax-table'! | |
487 (let ((continue t)) | |
488 (while (and (re-search-forward regexp bound 'limit) | |
489 (save-match-data | |
490 (if (eq (antlr-syntactic-context) 0) (setq continue nil) t)))) | |
491 (if continue nil (point)))) | |
492 | |
493 (defun antlr-search-forward (string) | |
494 "Search forward from point for STRING. | |
495 Set point to the end of the occurrence found, and return point. Return | |
496 nil if no occurence was found. Do not search within comments, strings | |
497 and actions/semantic predicates." | |
498 ;; WARNING: Should only be used with `antlr-action-syntax-table'! | |
499 (let ((continue t)) | |
500 (while (and (search-forward string nil 'limit) | |
501 (if (eq (antlr-syntactic-context) 0) (setq continue nil) t))) | |
502 (if continue nil (point)))) | |
503 | |
504 (defun antlr-search-backward (string) | |
505 "Search backward from point for STRING. | |
506 Set point to the beginning of the occurrence found, and return point. | |
507 Return nil if no occurence was found. Do not search within comments, | |
508 strings and actions/semantic predicates." | |
509 ;; WARNING: Should only be used with `antlr-action-syntax-table'! | |
510 (let ((continue t)) | |
511 (while (and (search-backward string nil 'limit) | |
512 (if (eq (antlr-syntactic-context) 0) (setq continue nil) t))) | |
513 (if continue nil (point)))) | |
514 | |
515 (defsubst antlr-skip-sexps (count) | |
516 "Skip the next COUNT balanced expressions and the comments after it. | |
517 Return position before the comments after the last expression." | |
518 (goto-char (or (antlr-scan-sexps (point) count nil t) (point-max))) | |
519 (prog1 (point) | |
520 (c-forward-syntactic-ws))) | |
521 | |
522 | |
523 ;;;=========================================================================== | |
524 ;;; font-lock | |
525 ;;;=========================================================================== | |
526 | |
527 (defun antlr-font-lock-keywords () | |
528 "Return font-lock keywords for current buffer. | |
529 See `antlr-font-lock-additional-keywords', `antlr-language' and | |
530 `antlr-font-lock-maximum-decoration'." | |
531 (if (eq antlr-font-lock-maximum-decoration 'none) | |
532 antlr-font-lock-additional-keywords | |
533 (append antlr-font-lock-additional-keywords | |
534 (eval (let ((major-mode antlr-language)) ; dynamic | |
535 (font-lock-choose-keywords | |
536 (cdr (assq antlr-language | |
537 antlr-font-lock-keywords-alist)) | |
538 (if (eq antlr-font-lock-maximum-decoration 'inherit) | |
539 font-lock-maximum-decoration | |
540 antlr-font-lock-maximum-decoration))))))) | |
541 | |
542 | |
543 ;;;=========================================================================== | |
544 ;;; imenu support | |
545 ;;;=========================================================================== | |
546 | |
547 (defun antlr-imenu-create-index-function () | |
548 "Return imenu index-alist for ANTLR gramar files." | |
549 (let ((items nil) | |
550 (lexer nil) | |
551 (parser nil) | |
552 (treeparser nil) | |
553 (misc nil) | |
554 (classes nil) | |
555 (semi (point-max))) | |
556 ;; Using `imenu-progress-message' would require imenu for compilation -- | |
557 ;; nobody is missing these messages... | |
558 (antlr-with-syntax-table antlr-action-syntax-table | |
559 ;; We stick to the imenu standard and search backwards, although I don't | |
560 ;; think this is right. It is slower and more likely not to work during | |
561 ;; editing (you are more likely to add functions to the end of the file). | |
562 (while semi | |
563 (goto-char semi) | |
564 (if (setq semi (antlr-search-backward ";")) | |
565 (progn (forward-char) (antlr-skip-exception-part t)) | |
566 (antlr-skip-file-prelude t)) | |
567 (if (looking-at "{") (antlr-skip-sexps 1)) | |
568 (if (looking-at "class[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]+extends[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]*;") | |
569 (progn | |
570 (push (cons (match-string 1) | |
571 (if imenu-use-markers | |
572 (copy-marker (match-beginning 1)) | |
573 (match-beginning 1))) | |
574 classes) | |
575 (if items | |
576 (let ((super (match-string 2))) | |
577 (cond ((string-equal super "Parser") | |
578 (setq parser (nconc items parser))) | |
579 ((string-equal super "Lexer") | |
580 (setq lexer (nconc items lexer))) | |
581 ((string-equal super "TreeParser") | |
582 (setq treeparser (nconc items treeparser))) | |
583 (t | |
584 (setq misc (nconc items misc)))) | |
585 (setq items nil)))) | |
586 (if (looking-at "p\\(ublic\\|rotected\\|rivate\\)") | |
587 (antlr-skip-sexps 1)) | |
588 (when (looking-at "\\sw+") | |
589 (push (cons (match-string 0) | |
590 (if imenu-use-markers | |
591 (copy-marker (match-beginning 0)) | |
592 (match-beginning 0))) | |
593 items))))) | |
594 (or items ; outside any class | |
595 (prog1 (setq items misc) (setq misc nil)) | |
596 (prog1 (setq items parser) (setq parser nil)) | |
597 (prog1 (setq items lexer) (setq lexer nil)) | |
598 (prog1 (setq items treeparser) (setq treeparser nil))) | |
599 (if misc (push (cons "Miscellaneous" misc) items)) | |
600 (if treeparser (push (cons "TreeParser" treeparser) items)) | |
601 (if lexer (push (cons "Lexer" lexer) items)) | |
602 (if parser (push (cons "Parser" parser) items)) | |
603 (if classes (cons (cons "Classes" classes) items) items))) | |
604 | |
605 | |
606 ;;;=========================================================================== | |
607 ;;; Parse grammar files (internal functions) | |
608 ;;;=========================================================================== | |
609 | |
610 (defun antlr-skip-exception-part (skip-comment) | |
611 "Skip exception part of current rule, i.e., everything after `;'. | |
612 This also includes the options and tokens part of a grammar class | |
613 header. If SKIP-COMMENT is non-nil, also skip the comment after that | |
614 part." | |
615 (let ((pos (point)) | |
616 (class nil)) | |
617 (c-forward-syntactic-ws) | |
618 (while (looking-at "options\\>\\|tokens\\>") | |
619 (setq class t) | |
620 (setq pos (antlr-skip-sexps 2))) | |
621 (if class | |
622 ;; Problem: an action only belongs to a class def, not a normal rule. | |
623 ;; But checking the current rule type is too expensive => only expect | |
624 ;; an action if we have found an option or tokens part. | |
625 (if (looking-at "{") (setq pos (antlr-skip-sexps 1))) | |
626 (while (looking-at "exception\\>") | |
627 (setq pos (antlr-skip-sexps 1)) | |
628 (if (looking-at "\\[") (setq pos (antlr-skip-sexps 1))) | |
629 (while (looking-at "catch\\>") | |
630 (setq pos (antlr-skip-sexps 3))))) | |
631 (or skip-comment (goto-char pos)))) | |
632 | |
633 (defun antlr-skip-file-prelude (skip-comment) | |
634 "Skip the file prelude: the header and file options. | |
635 If SKIP-COMMENT is non-nil, also skip the comment after that part." | |
636 (let* ((pos (point)) | |
637 (pos0 pos)) | |
638 (c-forward-syntactic-ws) | |
639 (if skip-comment (setq pos0 (point))) | |
640 (if (looking-at "header\\>") (setq pos (antlr-skip-sexps 2))) | |
641 (if (looking-at "options\\>") (setq pos (antlr-skip-sexps 2))) | |
642 (or skip-comment (goto-char pos)) | |
643 pos0)) | |
644 | |
645 (defun antlr-next-rule (arg skip-comment) | |
646 "Move forward to next end of rule. Do it ARG many times. | |
647 A grammar class header and the file prelude are also considered as a | |
648 rule. Negative argument ARG means move back to ARGth preceding end of | |
649 rule. The behaviour is not defined when ARG is zero. If SKIP-COMMENT | |
650 is non-nil, move to beginning of the rule." | |
651 ;; WARNING: Should only be used with `antlr-action-syntax-table'! | |
652 ;; PRE: ARG<>0 | |
653 (let ((pos (point)) | |
654 (beg (point))) | |
655 ;; first look whether point is in exception part | |
656 (if (antlr-search-backward ";") | |
657 (progn | |
658 (setq beg (point)) | |
659 (forward-char) | |
660 (antlr-skip-exception-part skip-comment)) | |
661 (antlr-skip-file-prelude skip-comment)) | |
662 (if (< arg 0) | |
663 (unless (and (< (point) pos) (zerop (incf arg))) | |
664 ;; if we have moved backward, we already moved one defun backward | |
665 (goto-char beg) ; rewind (to ";" / point) | |
666 (while (and arg (<= (incf arg) 0)) | |
667 (if (antlr-search-backward ";") | |
668 (setq beg (point)) | |
669 (when (>= arg -1) | |
670 ;; try file prelude: | |
671 (setq pos (antlr-skip-file-prelude skip-comment)) | |
672 (if (zerop arg) | |
673 (if (>= (point) beg) | |
674 (goto-char (if (>= pos beg) (point-min) pos))) | |
675 (goto-char (if (or (>= (point) beg) (= (point) pos)) | |
676 (point-min) pos)))) | |
677 (setq arg nil))) | |
678 (when arg ; always found a ";" | |
679 (forward-char) | |
680 (antlr-skip-exception-part skip-comment))) | |
681 (if (<= (point) pos) ; moved backward? | |
682 (goto-char pos) ; rewind | |
683 (decf arg)) ; already moved one defun forward | |
684 (unless (zerop arg) | |
685 (while (>= (decf arg) 0) | |
686 (antlr-search-forward ";")) | |
687 (antlr-skip-exception-part skip-comment))))) | |
688 | |
689 (defun antlr-outside-rule-p () | |
690 "Non-nil if point is outside a grammar rule. | |
691 Move to the beginning of the current rule if point is inside a rule." | |
692 ;; WARNING: Should only be used with `antlr-action-syntax-table'! | |
693 (let ((pos (point))) | |
694 (antlr-next-rule -1 nil) | |
695 (let ((between (or (bobp) (< (point) pos)))) | |
696 (c-forward-syntactic-ws) | |
697 (and between (> (point) pos) (goto-char pos))))) | |
698 | |
699 | |
700 ;;;=========================================================================== | |
701 ;;; Parse grammar files (commands) | |
702 ;;;=========================================================================== | |
703 ;; No (interactive "_") in Emacs... use `zmacs-region-stays'. | |
704 | |
705 (defun antlr-inside-rule-p () | |
706 "Non-nil if point is inside a grammar rule. | |
707 A grammar class header and the file prelude are also considered as a | |
708 rule." | |
709 (save-excursion | |
710 (antlr-with-syntax-table antlr-action-syntax-table | |
711 (not (antlr-outside-rule-p))))) | |
712 | |
713 (defun antlr-end-of-rule (&optional arg) | |
714 "Move forward to next end of rule. Do it ARG [default: 1] many times. | |
715 A grammar class header and the file prelude are also considered as a | |
716 rule. Negative argument ARG means move back to ARGth preceding end of | |
717 rule. If ARG is zero, run `antlr-end-of-body'." | |
718 (interactive "p") | |
719 (if (zerop arg) | |
720 (antlr-end-of-body) | |
721 (antlr-with-syntax-table antlr-action-syntax-table | |
722 (antlr-next-rule arg nil)) | |
723 (setq zmacs-region-stays t))) | |
724 | |
725 (defun antlr-beginning-of-rule (&optional arg) | |
726 "Move backward to preceding beginning of rule. Do it ARG many times. | |
727 A grammar class header and the file prelude are also considered as a | |
728 rule. Negative argument ARG means move forward to ARGth next beginning | |
729 of rule. If ARG is zero, run `antlr-beginning-of-body'." | |
730 (interactive "p") | |
731 (if (zerop arg) | |
732 (antlr-beginning-of-body) | |
733 (antlr-with-syntax-table antlr-action-syntax-table | |
734 (antlr-next-rule (- arg) t)) | |
735 (setq zmacs-region-stays t))) | |
736 | |
737 (defun antlr-end-of-body (&optional msg) | |
738 "Move to position after the `;' of the current rule. | |
739 A grammar class header is also considered as a rule. With optional | |
740 prefix arg MSG, move to `:'." | |
741 (interactive) | |
742 (antlr-with-syntax-table antlr-action-syntax-table | |
743 (let ((orig (point))) | |
744 (if (antlr-outside-rule-p) | |
745 (error "Outside an ANTLR rule")) | |
746 (let ((bor (point))) | |
747 (when (< (antlr-skip-file-prelude t) (point)) | |
748 ;; Yes, we are in the file prelude | |
749 (goto-char orig) | |
750 (error (or msg "The file prelude is without `;'"))) | |
751 (antlr-search-forward ";") | |
752 (when msg | |
753 (when (< (point) | |
754 (progn (goto-char bor) | |
755 (or (antlr-search-forward ":") (point-max)))) | |
756 (goto-char orig) | |
757 (error msg)) | |
758 (c-forward-syntactic-ws))))) | |
759 (setq zmacs-region-stays t)) | |
760 | |
761 (defun antlr-beginning-of-body () | |
762 "Move to the first element after the `:' of the current rule." | |
763 (interactive) | |
764 (antlr-end-of-body "Class headers and the file prelude are without `:'")) | |
765 | |
766 | |
767 ;;;=========================================================================== | |
768 ;;; Indentation | |
769 ;;;=========================================================================== | |
770 | |
771 (defun antlr-indent-line () | |
772 "Indent the current line as ANTLR grammar code. | |
773 The indentation of non-comment lines are calculated by `c-basic-offset', | |
774 multiplied by: | |
775 - the level of the paren/brace/bracket depth, | |
776 - plus 0/2/1, depending on the position inside the rule: header, body, | |
777 exception part, | |
778 - minus 1 if `antlr-indent-item-regexp' matches the beginning of the | |
779 line starting from the first non-blank. | |
780 | |
781 Lines inside block commments are not changed or indented by | |
782 `c-indent-line', see `antlr-indent-comment'." | |
783 (let ((orig (point)) bol boi indent syntax) | |
784 (beginning-of-line) | |
785 (setq bol (point)) | |
786 (skip-chars-forward " \t") | |
787 (setq boi (point)) | |
788 ;; check syntax at beginning of indentation ------------------------------ | |
789 (antlr-with-syntax-table antlr-action-syntax-table | |
790 (antlr-invalidate-context-cache) | |
791 (cond ((symbolp (setq syntax (antlr-syntactic-context))) | |
792 (setq indent nil)) ; block-comments, strings, (comments) | |
793 ((progn | |
794 (antlr-next-rule -1 t) | |
795 (if (antlr-search-forward ":") (< boi (1- (point))) t)) | |
796 (setq indent 0)) ; in rule header | |
797 ((if (antlr-search-forward ";") (< boi (point)) t) | |
798 (setq indent 2)) ; in rule body | |
799 (t | |
800 (forward-char) | |
801 (antlr-skip-exception-part nil) | |
802 (setq indent (if (> (point) boi) 1 0))))) ; in exception part? | |
803 ;; compute the corresponding indentation and indent ---------------------- | |
804 (if (null indent) | |
805 (progn | |
806 (goto-char orig) | |
807 (and (eq antlr-indent-comment t) | |
808 (not (eq syntax 'string)) | |
809 (c-indent-line))) | |
810 ;; do it ourselves | |
811 (goto-char boi) | |
812 (antlr-invalidate-context-cache) | |
813 (incf indent (antlr-syntactic-context)) | |
814 (and (> indent 0) (looking-at antlr-indent-item-regexp) (decf indent)) | |
815 (setq indent (* indent c-basic-offset)) | |
816 ;; the usual major-mode indent stuff: | |
817 (setq orig (- (point-max) orig)) | |
818 (unless (= (current-column) indent) | |
819 (delete-region bol boi) | |
820 (beginning-of-line) | |
821 (indent-to indent)) | |
822 ;; If initial point was within line's indentation, | |
823 ;; position after the indentation. Else stay at same point in text. | |
824 (if (> (- (point-max) orig) (point)) | |
825 (goto-char (- (point-max) orig)))))) | |
826 | |
827 (defun antlr-indent-command (&optional arg) | |
828 "Indent the current line or insert tabs/spaces. | |
829 With optional prefix argument ARG or if the previous command was this | |
830 command, insert ARG tabs or spaces according to `indent-tabs-mode'. | |
831 Otherwise, indent the current line with `antlr-indent-line'." | |
832 (interactive "P") | |
833 (if (or arg (eq last-command 'antlr-indent-command)) | |
834 (insert-tab arg) | |
835 (let ((antlr-indent-comment (and antlr-indent-comment t))) ; dynamic | |
836 (antlr-indent-line)))) | |
837 | |
838 | |
839 ;;;=========================================================================== | |
840 ;;; Mode entry | |
841 ;;;=========================================================================== | |
842 | |
843 (defun antlr-c-common-init () | |
844 "Like `c-common-init' except menu, auto-hungry and c-style stuff." | |
845 ;; X/Emacs 20 only | |
846 (make-local-variable 'paragraph-start) | |
847 (make-local-variable 'paragraph-separate) | |
848 (make-local-variable 'paragraph-ignore-fill-prefix) | |
849 (make-local-variable 'require-final-newline) | |
850 (make-local-variable 'parse-sexp-ignore-comments) | |
851 (make-local-variable 'indent-line-function) | |
852 (make-local-variable 'indent-region-function) | |
853 (make-local-variable 'comment-start) | |
854 (make-local-variable 'comment-end) | |
855 (make-local-variable 'comment-column) | |
856 (make-local-variable 'comment-start-skip) | |
857 (make-local-variable 'comment-multi-line) | |
858 (make-local-variable 'outline-regexp) | |
859 (make-local-variable 'outline-level) | |
860 (make-local-variable 'adaptive-fill-regexp) | |
861 (make-local-variable 'adaptive-fill-mode) | |
862 (make-local-variable 'imenu-generic-expression) ;set in the mode functions | |
863 (and (boundp 'comment-line-break-function) | |
864 (make-local-variable 'comment-line-break-function)) | |
865 ;; Emacs 19.30 and beyond only, AFAIK | |
866 (if (boundp 'fill-paragraph-function) | |
867 (progn | |
868 (make-local-variable 'fill-paragraph-function) | |
869 (setq fill-paragraph-function 'c-fill-paragraph))) | |
870 ;; now set their values | |
871 (setq paragraph-start (concat page-delimiter "\\|$") | |
872 paragraph-separate paragraph-start | |
873 paragraph-ignore-fill-prefix t | |
874 require-final-newline t | |
875 parse-sexp-ignore-comments t | |
876 indent-line-function 'c-indent-line | |
877 indent-region-function 'c-indent-region | |
878 outline-regexp "[^#\n\^M]" | |
879 outline-level 'c-outline-level | |
880 comment-column 32 | |
881 comment-start-skip "/\\*+ *\\|// *" | |
882 comment-multi-line nil | |
883 comment-line-break-function 'c-comment-line-break-function | |
884 adaptive-fill-regexp nil | |
885 adaptive-fill-mode nil) | |
886 ;; we have to do something special for c-offsets-alist so that the | |
887 ;; buffer local value has its own alist structure. | |
888 (setq c-offsets-alist (copy-alist c-offsets-alist)) | |
889 ;; setup the comment indent variable in a Emacs version portable way | |
890 ;; ignore any byte compiler warnings you might get here | |
891 (make-local-variable 'comment-indent-function) | |
892 (setq comment-indent-function 'c-comment-indent)) | |
893 | |
894 (defun antlr-language-for-option (option-value) | |
895 "Find element in `antlr-language-alist' for OPTION-VALUE." | |
896 ;; Like (find OPTION-VALUE antlr-language-alist :key 'cddr :test 'member) | |
897 (let ((seq antlr-language-alist) | |
898 r) | |
899 (while seq | |
900 (setq r (pop seq)) | |
901 (if (member option-value (cddr r)) | |
902 (setq seq nil) ; stop | |
903 (setq r nil))) ; no result yet | |
904 r)) | |
905 | |
906 ;;;###autoload | |
907 (defun antlr-mode () | |
908 "Major mode for editing ANTLR grammar files. | |
909 \\{antlr-mode-map}" | |
910 (interactive) | |
911 (c-initialize-cc-mode) ; for java syntax table | |
912 (kill-all-local-variables) | |
913 ;; ANTLR specific ---------------------------------------------------------- | |
914 (setq major-mode 'antlr-mode | |
915 mode-name "Antlr") | |
916 (setq local-abbrev-table antlr-mode-abbrev-table) | |
917 (set-syntax-table java-mode-syntax-table) | |
918 (unless antlr-action-syntax-table | |
919 (let ((slist (nth 3 antlr-font-lock-defaults))) | |
920 (setq antlr-action-syntax-table | |
921 (copy-syntax-table java-mode-syntax-table)) | |
922 (while slist | |
923 (modify-syntax-entry (caar slist) (cdar slist) | |
924 antlr-action-syntax-table) | |
925 (setq slist (cdr slist))))) | |
926 (use-local-map antlr-mode-map) | |
927 (make-local-variable 'antlr-language) | |
928 (unless antlr-language | |
929 (save-excursion | |
930 (goto-char (point-min)) | |
931 (setq antlr-language | |
932 (car (or (and (re-search-forward (cdr antlr-language-limit-n-regexp) | |
933 (car antlr-language-limit-n-regexp) | |
934 t) | |
935 (antlr-language-for-option (match-string 1))) | |
936 (antlr-language-for-option nil)))))) | |
937 (if (stringp (cadr (assq antlr-language antlr-language-alist))) | |
938 (setq mode-name | |
939 (concat "Antlr/" | |
940 (cadr (assq antlr-language antlr-language-alist))))) | |
941 ;; indentation, for the C engine ------------------------------------------- | |
942 (antlr-c-common-init) | |
943 (setq indent-line-function 'antlr-indent-line | |
944 indent-region-function nil) ; too lazy | |
945 (setq comment-start "// " | |
946 comment-end "") | |
947 (c-set-style "java") | |
948 (if (eq antlr-language 'c++-mode) | |
949 (setq c-conditional-key c-C++-conditional-key | |
950 c-comment-start-regexp c-C++-comment-start-regexp | |
951 c-class-key c-C++-class-key | |
952 c-extra-toplevel-key c-C++-extra-toplevel-key | |
953 c-access-key c-C++-access-key | |
954 c-recognize-knr-p nil) | |
955 (setq c-conditional-key c-Java-conditional-key | |
956 c-comment-start-regexp c-Java-comment-start-regexp | |
957 c-class-key c-Java-class-key | |
958 c-method-key nil | |
959 c-baseclass-key nil | |
960 c-recognize-knr-p nil | |
961 c-access-key c-Java-access-key) | |
962 (and (boundp 'c-inexpr-class-key) (boundp 'c-Java-inexpr-class-key) | |
963 (setq c-inexpr-class-key c-Java-inexpr-class-key))) | |
964 ;; various ----------------------------------------------------------------- | |
965 (make-local-variable 'font-lock-defaults) | |
966 (setq font-lock-defaults antlr-font-lock-defaults) | |
967 (easy-menu-add antlr-mode-menu) | |
968 (make-local-variable 'imenu-create-index-function) | |
969 (setq imenu-create-index-function 'antlr-imenu-create-index-function) | |
970 (make-local-variable 'imenu-generic-expression) | |
971 (setq imenu-generic-expression t) ; fool stupid test | |
972 (and antlr-imenu-name ; there should be a global variable... | |
973 (fboundp 'imenu-add-to-menubar) | |
974 (imenu-add-to-menubar | |
975 (if (stringp antlr-imenu-name) antlr-imenu-name "Index"))) | |
976 (antlr-set-tabs) | |
977 (run-hooks 'antlr-mode-hook)) | |
978 | |
979 ;;;###autoload | |
980 (defun antlr-set-tabs () | |
981 "Use ANTLR's convention for TABs according to `antlr-tab-offset-alist'. | |
982 Used in `antlr-mode'. Also a useful function in `java-mode-hook'." | |
983 (if buffer-file-name | |
984 (let ((alist antlr-tab-offset-alist) elem) | |
985 (while alist | |
986 (setq elem (pop alist)) | |
987 (and (or (null (car elem)) (eq (car elem) major-mode)) | |
988 (or (null (cadr elem)) | |
989 (string-match (cadr elem) buffer-file-name)) | |
990 (setq tab-width (caddr elem) | |
991 indent-tabs-mode (cadddr elem) | |
992 alist nil)))))) | |
993 | |
994 ;;; antlr-mode.el ends here |