(perform-replace): Move START and END parameters
[bpt/emacs.git] / lisp / progmodes / simula.el
1 ;;; simula.el --- SIMULA 87 code editing commands for Emacs
2
3 ;; Copyright (C) 1992, 1994, 1996 Free Software Foundation, Inc.
4
5 ;; Author: Hans Henrik Eriksen <hhe@ifi.uio.no>
6 ;; Maintainer: simula-mode@ifi.uio.no
7 ;; Adapted-By: ESR
8 ;; Keywords: languages
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Commentary:
28
29 ;; A major mode for editing the Simula language. It knows about Simula
30 ;; syntax and standard indentation commands. It also provides convenient
31 ;; abbrevs for Simula keywords.
32 ;;
33 ;; Hans Henrik Eriksen (the author) may be reached at:
34 ;; Institutt for informatikk,
35 ;; Universitetet i Oslo
36
37 ;;; Code:
38
39 \f
40 (defgroup simula nil
41 "Major mode for editing Simula code."
42 :prefix "simula-"
43 :group 'languages)
44
45 (defconst simula-tab-always-indent-default nil
46 "Non-nil means TAB in SIMULA mode should always reindent the current line.
47 Otherwise TAB indents only when point is within
48 the run of whitespace at the beginning of the line.")
49
50 (defcustom simula-tab-always-indent simula-tab-always-indent-default
51 "*Non-nil means TAB in SIMULA mode should always reindent the current line.
52 Otherwise TAB indents only when point is within
53 the run of whitespace at the beginning of the line."
54 :type 'boolean
55 :group 'simula)
56
57 (defconst simula-indent-level-default 3
58 "Indentation of SIMULA statements with respect to containing block.")
59
60 (defcustom simula-indent-level simula-indent-level-default
61 "*Indentation of SIMULA statements with respect to containing block."
62 :type 'integer
63 :group 'simula)
64
65
66 (defconst simula-substatement-offset-default 3
67 "Extra indentation after DO, THEN, ELSE, WHEN and OTHERWISE.")
68
69 (defcustom simula-substatement-offset simula-substatement-offset-default
70 "*Extra indentation after DO, THEN, ELSE, WHEN and OTHERWISE."
71 :type 'integer
72 :group 'simula)
73
74 (defconst simula-continued-statement-offset-default 3
75 "Extra indentation for lines not starting a statement or substatement.
76 If value is a list, each line in a multipleline continued statement
77 will have the car of the list extra indentation with respect to
78 the previous line of the statement.")
79
80 (defcustom simula-continued-statement-offset
81 simula-continued-statement-offset-default
82 "*Extra indentation for lines not starting a statement or substatement.
83 If value is a list, each line in a multipleline continued statement
84 will have the car of the list extra indentation with respect to
85 the previous line of the statement."
86 :type 'integer
87 :group 'simula)
88
89 (defconst simula-label-offset-default -4711
90 "Offset of SIMULA label lines relative to usual indentation.")
91
92 (defcustom simula-label-offset simula-label-offset-default
93 "*Offset of SIMULA label lines relative to usual indentation."
94 :type 'integer
95 :group 'simula)
96
97 (defconst simula-if-indent-default '(0 . 0)
98 "Extra indentation of THEN and ELSE with respect to the starting IF.
99 Value is a cons cell, the car is extra THEN indentation and the cdr
100 extra ELSE indentation. IF after ELSE is indented as the starting IF.")
101
102 (defcustom simula-if-indent simula-if-indent-default
103 "*Extra indentation of THEN and ELSE with respect to the starting IF.
104 Value is a cons cell, the car is extra THEN indentation and the cdr
105 extra ELSE indentation. IF after ELSE is indented as the starting IF."
106 :type '(cons integer integer)
107 :group 'simula)
108
109 (defconst simula-inspect-indent-default '(0 . 0)
110 "Extra indentation of WHEN and OTHERWISE with respect to the INSPECT.
111 Value is a cons cell, the car is extra WHEN indentation
112 and the cdr extra OTHERWISE indentation.")
113
114 (defcustom simula-inspect-indent simula-inspect-indent-default
115 "*Extra indentation of WHEN and OTHERWISE with respect to the INSPECT.
116 Value is a cons cell, the car is extra WHEN indentation
117 and the cdr extra OTHERWISE indentation."
118 :type '(cons integer integer)
119 :group 'simula)
120
121 (defconst simula-electric-indent-default nil
122 "Non-nil means `simula-indent-line' function may reindent previous line.")
123
124 (defcustom simula-electric-indent simula-electric-indent-default
125 "*Non-nil means `simula-indent-line' function may reindent previous line."
126 :type 'boolean
127 :group 'simula)
128
129 (defconst simula-abbrev-keyword-default 'upcase
130 "Specify how to convert case for SIMULA keywords.
131 Value is one of the symbols `upcase', `downcase', `capitalize',
132 (as in) `abbrev-table' or nil if they should not be changed.")
133
134 (defcustom simula-abbrev-keyword simula-abbrev-keyword-default
135 "*Specify how to convert case for SIMULA keywords.
136 Value is one of the symbols `upcase', `downcase', `capitalize',
137 (as in) `abbrev-table' or nil if they should not be changed."
138 :type '(choice (const upcase) (const downcase) (const capitalize)(const nil))
139 :group 'simula)
140
141 (defconst simula-abbrev-stdproc-default 'abbrev-table
142 "Specify how to convert case for standard SIMULA procedure and class names.
143 Value is one of the symbols `upcase', `downcase', `capitalize',
144 (as in) `abbrev-table', or nil if they should not be changed.")
145
146 (defcustom simula-abbrev-stdproc simula-abbrev-stdproc-default
147 "*Specify how to convert case for standard SIMULA procedure and class names.
148 Value is one of the symbols `upcase', `downcase', `capitalize',
149 (as in) `abbrev-table', or nil if they should not be changed."
150 :type '(choice (const upcase) (const downcase) (const capitalize)
151 (const abbrev-table) (const nil))
152 :group 'simula)
153
154 (defcustom simula-abbrev-file nil
155 "*File with extra abbrev definitions for use in SIMULA mode.
156 These are used together with the standard abbrev definitions for SIMULA.
157 Please note that the standard definitions are required
158 for SIMULA mode to function correctly."
159 :type '(choice file (const nil))
160 :group 'simula)
161
162 (defvar simula-mode-syntax-table nil
163 "Syntax table in SIMULA mode buffers.")
164
165 ;; Regexps written with help from Alf-Ivar Holm <alfh@ifi.uio.no>.
166 (defconst simula-font-lock-keywords-1
167 (list
168 ;;
169 ;; Comments and strings.
170 '(simula-match-string-or-comment 0
171 (if (match-beginning 1) font-lock-string-face font-lock-comment-face))
172 ;;
173 ;; Compiler directives.
174 '("^%\\([^ \t\n].*\\)" 1 font-lock-constant-face)
175 ;;
176 ;; Class and procedure names.
177 '("\\<\\(class\\|procedure\\)\\>[ \t]*\\(\\sw+\\)?"
178 (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
179 )
180 "Subdued level highlighting for Simula mode.")
181
182 (defconst simula-font-lock-keywords-2
183 (append simula-font-lock-keywords-1
184 (list
185 ;;
186 ;; Constants.
187 '("\\<\\(false\\|none\\|notext\\|true\\)\\>" . font-lock-constant-face)
188 ;;
189 ;; Keywords.
190 (concat "\\<\\("
191 ; (make-regexp
192 ; '("activate" "after" "and" "at" "before" "begin" "delay" "do"
193 ; "else" "end" "eq" "eqv" "external" "for" "ge" "go" "goto" "gt"
194 ; "hidden" "if" "imp" "in" "inner" "inspect" "is" "label" "le"
195 ; "lt" "ne" "new" "not" "or" "otherwise" "prior" "protected"
196 ; "qua" "reactivate" "step" "switch" "then" "this" "to" "until"
197 ; "virtual" "when" "while"))
198 "a\\(ctivate\\|fter\\|nd\\|t\\)\\|be\\(fore\\|gin\\)\\|"
199 "d\\(elay\\|o\\)\\|e\\(lse\\|nd\\|qv?\\|xternal\\)\\|for\\|"
200 "g\\([eot]\\|oto\\)\\|hidden\\|i\\([fns]\\|mp\\|n\\(ner\\|"
201 "spect\\)\\)\\|l\\([et]\\|abel\\)\\|n\\(ew?\\|ot\\)\\|"
202 "o\\(r\\|therwise\\)\\|pr\\(ior\\|otected\\)\\|qua\\|"
203 "reactivate\\|s\\(tep\\|witch\\)\\|t\\(h\\(en\\|is\\)\\|o\\)\\|"
204 "until\\|virtual\\|wh\\(en\\|ile\\)"
205 "\\)\\>")
206 ;;
207 ;; Types.
208 (cons (concat "\\<\\(array\\|boolean\\|character\\|integer\\|"
209 "long\\|name\\|real\\|short\\|text\\|value\\|ref\\)\\>")
210 'font-lock-type-face)
211 ))
212 "Medium level highlighting for Simula mode.")
213
214 (defconst simula-font-lock-keywords-3
215 (append simula-font-lock-keywords-2
216 (list
217 ;;
218 ;; Super-class names and super-slow.
219 '("\\<\\(\\sw+\\)[ \t]+class\\>" 1 font-lock-function-name-face)
220 ;;
221 ;; Types and their declarations.
222 (list (concat "\\<\\(array\\|boolean\\|character\\|integer\\|"
223 "long\\|name\\|real\\|short\\|text\\|value\\)\\>"
224 "\\([ \t]+\\sw+\\>\\)*")
225 '(font-lock-match-c-style-declaration-item-and-skip-to-next
226 ;; Start with point after all type specifiers.
227 (goto-char (or (match-beginning 2) (match-end 1)))
228 ;; Finish with point after first type specifier.
229 (goto-char (match-end 1))
230 ;; Fontify as a variable name.
231 (1 font-lock-variable-name-face)))
232 ;;
233 ;; Object references and their declarations.
234 '("\\<\\(ref\\)\\>[ \t]*\\((\\(\\sw+\\))\\)?"
235 (3 font-lock-function-name-face nil t)
236 (font-lock-match-c-style-declaration-item-and-skip-to-next nil nil
237 (1 font-lock-variable-name-face)))
238 ))
239 "Gaudy level highlighting for Simula mode.")
240
241 (defvar simula-font-lock-keywords simula-font-lock-keywords-1
242 "Default expressions to highlight in Simula mode.")
243
244 ; The following function is taken from cc-mode.el,
245 ; it determines the flavor of the Emacs running
246 (defconst simula-emacs-features
247 (let ((major (and (boundp 'emacs-major-version)
248 emacs-major-version))
249 (minor (and (boundp 'emacs-minor-version)
250 emacs-minor-version))
251 flavor comments)
252 ;; figure out version numbers if not already discovered
253 (and (or (not major) (not minor))
254 (string-match "\\([0-9]+\\).\\([0-9]+\\)" emacs-version)
255 (setq major (string-to-int (substring emacs-version
256 (match-beginning 1)
257 (match-end 1)))
258 minor (string-to-int (substring emacs-version
259 (match-beginning 2)
260 (match-end 2)))))
261 (if (not (and major minor))
262 (error "Cannot figure out the major and minor version numbers"))
263 ;; calculate the major version
264 (cond
265 ((= major 18) (setq major 'v18)) ;Emacs 18
266 ((= major 4) (setq major 'v18)) ;Epoch 4
267 ((>= major 19) (setq major 'v19 ;Emacs 19 or 20
268 flavor (if (string-match "Lucid" emacs-version)
269 'Lucid 'FSF)))
270 ;; I don't know
271 (t (error "Cannot recognize major version number: %s" major)))
272 (list major flavor comments))
273 "A list of features extant in the Emacs you are using.
274 There are many flavors of Emacs out there, each with different
275 features supporting those needed by simula-mode. Here's the current
276 supported list, along with the values for this variable:
277
278 Emacs 19: (v19 FSF 1-bit)
279 Vanilla Emacs 18/Epoch 4: (v18 no-dual-comments)
280 Emacs 18/Epoch 4 (patch2): (v18 8-bit)
281 Lucid Emacs 19: (v19 Lucid 8-bit).")
282
283 (defvar simula-mode-menu
284 '(["Report Bug" simula-submit-bug-report t]
285 ["Indent Line" simula-indent-line t]
286 ["Backward Statement" simula-previous-statement t]
287 ["Forward Statement" simula-next-statement t]
288 ["Backward Up Level" simula-backward-up-level t]
289 ["Forward Down Statement" simula-forward-down-level t]
290 )
291 "Lucid Emacs menu for SIMULA mode.")
292
293 (if simula-mode-syntax-table
294 ()
295 (setq simula-mode-syntax-table (copy-syntax-table (standard-syntax-table)))
296 (modify-syntax-entry ?! "<" simula-mode-syntax-table)
297 (modify-syntax-entry ?$ "." simula-mode-syntax-table)
298 (modify-syntax-entry ?% "." simula-mode-syntax-table)
299 (modify-syntax-entry ?' "\"" simula-mode-syntax-table)
300 (modify-syntax-entry ?\( "()" simula-mode-syntax-table)
301 (modify-syntax-entry ?\) ")(" simula-mode-syntax-table)
302 (modify-syntax-entry ?\; ">" simula-mode-syntax-table)
303 (modify-syntax-entry ?\[ "." simula-mode-syntax-table)
304 (modify-syntax-entry ?\\ "." simula-mode-syntax-table)
305 (modify-syntax-entry ?\] "." simula-mode-syntax-table)
306 (modify-syntax-entry ?_ "_" simula-mode-syntax-table)
307 (modify-syntax-entry ?\| "." simula-mode-syntax-table)
308 (modify-syntax-entry ?\{ "." simula-mode-syntax-table)
309 (modify-syntax-entry ?\} "." simula-mode-syntax-table))
310
311 (defvar simula-mode-map ()
312 "Keymap used in SIMULA mode.")
313
314 (if simula-mode-map
315 ()
316 (setq simula-mode-map (make-sparse-keymap))
317 (define-key simula-mode-map "\C-c\C-u" 'simula-backward-up-level)
318 (define-key simula-mode-map "\C-c\C-p" 'simula-previous-statement)
319 (define-key simula-mode-map "\C-c\C-d" 'simula-forward-down-level)
320 (define-key simula-mode-map "\C-c\C-n" 'simula-next-statement)
321 ;(define-key simula-mode-map "\C-c\C-g" 'simula-goto-definition)
322 ;(define-key simula-mode-map "\C-c\C-h" 'simula-standard-help)
323 (define-key simula-mode-map "\177" 'backward-delete-char-untabify)
324 (define-key simula-mode-map ":" 'simula-electric-label)
325 (define-key simula-mode-map "\e\C-q" 'simula-indent-exp)
326 (define-key simula-mode-map "\t" 'simula-indent-command)
327 ;; Emacs 19 defines menus in the mode map
328 (if (memq 'FSF simula-emacs-features)
329 (progn
330 (define-key simula-mode-map [menu-bar] (make-sparse-keymap))
331
332 (define-key simula-mode-map [menu-bar simula]
333 (cons "SIMULA" (make-sparse-keymap "SIMULA")))
334 (define-key simula-mode-map [menu-bar simula bug-report]
335 '("Submit Bug Report" . simula-submit-bug-report))
336 (define-key simula-mode-map [menu-bar simula separator-indent]
337 '("--"))
338 (define-key simula-mode-map [menu-bar simula indent-exp]
339 '("Indent Expression" . simula-indent-exp))
340 (define-key simula-mode-map [menu-bar simula indent-line]
341 '("Indent Line" . simula-indent-command))
342 (define-key simula-mode-map [menu-bar simula separator-navigate]
343 '("--"))
344 (define-key simula-mode-map [menu-bar simula backward-stmt]
345 '("Previous Statement" . simula-previous-statement))
346 (define-key simula-mode-map [menu-bar simula forward-stmt]
347 '("Next Statement" . simula-next-statement))
348 (define-key simula-mode-map [menu-bar simula backward-up]
349 '("Backward Up Level" . simula-backward-up-level))
350 (define-key simula-mode-map [menu-bar simula forward-down]
351 '("Forward Down Statement" . simula-forward-down-level))
352
353 (put 'simula-next-statement 'menu-enable '(not (eobp)))
354 (put 'simula-previous-statement 'menu-enable '(not (bobp)))
355 (put 'simula-forward-down-level 'menu-enable '(not (eobp)))
356 (put 'simula-backward-up-level 'menu-enable '(not (bobp)))
357 (put 'simula-indent-command 'menu-enable '(not buffer-read-only))
358 (put 'simula-indent-exp 'menu-enable '(not buffer-read-only))))
359
360 ;; RMS: mouse-3 should not select this menu. mouse-3's global
361 ;; definition is useful in SIMULA mode and we should not interfere
362 ;; with that. The menu is mainly for beginners, and for them,
363 ;; the menubar requires less memory than a special click.
364 ;; in Lucid Emacs, we want the menu to popup when the 3rd button is
365 ;; hit. In 19.10 and beyond this is done automatically if we put
366 ;; the menu on mode-popup-menu variable, see c-common-init [cc-mode.el]
367 (if (memq 'Lucid simula-emacs-features)
368 (if (not (boundp 'mode-popup-menu))
369 (define-key simula-mode-map 'button3 'simula-popup-menu))))
370
371 ;; menus for Lucid
372 (defun simula-popup-menu (e)
373 "Pops up the SIMULA menu."
374 (interactive "@e")
375 (popup-menu (cons (concat mode-name " Mode Commands") simula-mode-menu))
376 (simula-keep-region-active))
377
378 ;; active regions, and auto-newline/hungry delete key
379 (defun simula-keep-region-active ()
380 ;; do whatever is necessary to keep the region active in
381 ;; Lucid. ignore byte-compiler warnings you might see
382 (and (boundp 'zmacs-region-stays)
383 (setq zmacs-region-stays t)))
384
385 (defvar simula-mode-abbrev-table nil
386 "Abbrev table in SIMULA mode buffers")
387
388
389 ;;;###autoload
390 (defun simula-mode ()
391 "Major mode for editing SIMULA code.
392 \\{simula-mode-map}
393 Variables controlling indentation style:
394 simula-tab-always-indent
395 Non-nil means TAB in SIMULA mode should always reindent the current line,
396 regardless of where in the line point is when the TAB command is used.
397 simula-indent-level
398 Indentation of SIMULA statements with respect to containing block.
399 simula-substatement-offset
400 Extra indentation after DO, THEN, ELSE, WHEN and OTHERWISE.
401 simula-continued-statement-offset 3
402 Extra indentation for lines not starting a statement or substatement,
403 e.g. a nested FOR-loop. If value is a list, each line in a multiple-
404 line continued statement will have the car of the list extra indentation
405 with respect to the previous line of the statement.
406 simula-label-offset -4711
407 Offset of SIMULA label lines relative to usual indentation.
408 simula-if-indent '(0 . 0)
409 Extra indentation of THEN and ELSE with respect to the starting IF.
410 Value is a cons cell, the car is extra THEN indentation and the cdr
411 extra ELSE indentation. IF after ELSE is indented as the starting IF.
412 simula-inspect-indent '(0 . 0)
413 Extra indentation of WHEN and OTHERWISE with respect to the
414 corresponding INSPECT. Value is a cons cell, the car is
415 extra WHEN indentation and the cdr extra OTHERWISE indentation.
416 simula-electric-indent nil
417 If this variable is non-nil, `simula-indent-line'
418 will check the previous line to see if it has to be reindented.
419 simula-abbrev-keyword 'upcase
420 Determine how SIMULA keywords will be expanded. Value is one of
421 the symbols `upcase', `downcase', `capitalize', (as in) `abbrev-table',
422 or nil if they should not be changed.
423 simula-abbrev-stdproc 'abbrev-table
424 Determine how standard SIMULA procedure and class names will be
425 expanded. Value is one of the symbols `upcase', `downcase', `capitalize',
426 (as in) `abbrev-table', or nil if they should not be changed.
427
428 Turning on SIMULA mode calls the value of the variable simula-mode-hook
429 with no arguments, if that value is non-nil
430
431 Warning: simula-mode-hook should not read in an abbrev file without calling
432 the function simula-install-standard-abbrevs afterwards, preferably not
433 at all."
434 (interactive)
435 (kill-all-local-variables)
436 (use-local-map simula-mode-map)
437 (setq major-mode 'simula-mode)
438 (setq mode-name "SIMULA")
439 (make-local-variable 'comment-column)
440 (setq comment-column 40)
441 ; (make-local-variable 'end-comment-column)
442 ; (setq end-comment-column 75)
443 (set-syntax-table simula-mode-syntax-table)
444 (make-local-variable 'paragraph-start)
445 (setq paragraph-start "[ \t]*$\\|\\f")
446 (make-local-variable 'paragraph-separate)
447 (setq paragraph-separate paragraph-start)
448 (make-local-variable 'indent-line-function)
449 (setq indent-line-function 'simula-indent-line)
450 (make-local-variable 'require-final-newline)
451 (setq require-final-newline t)
452 (make-local-variable 'comment-start)
453 (setq comment-start "! ")
454 (make-local-variable 'comment-end)
455 (setq comment-end " ;")
456 (make-local-variable 'comment-start-skip)
457 (setq comment-start-skip "!+ *")
458 (make-local-variable 'parse-sexp-ignore-comments)
459 (setq parse-sexp-ignore-comments nil)
460 (make-local-variable 'comment-multi-line)
461 (setq comment-multi-line t)
462 (make-local-variable 'font-lock-defaults)
463 (setq font-lock-defaults
464 '((simula-font-lock-keywords simula-font-lock-keywords-1
465 simula-font-lock-keywords-2 simula-font-lock-keywords-3)
466 t t ((?_ . "w"))))
467 (if simula-mode-abbrev-table
468 ()
469 (if simula-abbrev-file
470 (read-abbrev-file simula-abbrev-file)
471 (define-abbrev-table 'simula-mode-abbrev-table ()))
472 (let (abbrevs-changed)
473 (simula-install-standard-abbrevs)))
474 (setq local-abbrev-table simula-mode-abbrev-table)
475 (abbrev-mode 1)
476 (run-hooks 'simula-mode-hook))
477
478
479 (defun simula-indent-exp ()
480 "Indent SIMULA expression following point."
481 (interactive)
482 (let ((here (point))
483 (simula-electric-indent nil)
484 end)
485 (simula-skip-comment-forward)
486 (if (eobp)
487 (goto-char here)
488 (unwind-protect
489 (progn
490 (simula-next-statement 1)
491 (setq end (point-marker))
492 (simula-previous-statement 1)
493 (beginning-of-line)
494 (while (< (point) end)
495 (if (not (looking-at "[ \t]*$"))
496 (simula-indent-line))
497 (forward-line 1)))
498 (and end (set-marker end nil))))))
499
500
501 (defun simula-indent-line ()
502 "Indent this line as SIMULA code.
503 If `simula-electric-indent' is non-nil, indent previous line if necessary."
504 (let ((origin (- (point-max) (point)))
505 (indent (simula-calculate-indent))
506 (case-fold-search t))
507 (unwind-protect
508 (if simula-electric-indent
509 (progn
510 ;;
511 ;; manually expand abbrev on last line, if any
512 ;;
513 (end-of-line 0)
514 (expand-abbrev)
515 ;; now maybe we should reindent that line
516 (beginning-of-line)
517 (skip-chars-forward " \t\f")
518 (if (and
519 (looking-at
520 "\\(end\\|if\\|then\\|else\\|when\\|otherwise\\)\\>")
521 (not (simula-context)))
522 ;; yes - reindent
523 (let ((post-indent (simula-calculate-indent)))
524 (if (eq (current-indentation) post-indent)
525 ()
526 (delete-horizontal-space)
527 (indent-to post-indent))))))
528 (goto-char (- (point-max) origin))
529 (if (eq (current-indentation) indent)
530 (back-to-indentation)
531 (delete-horizontal-space)
532 (indent-to indent)))))
533
534
535 (defun simula-indent-command (&optional whole-exp)
536 "Indent current line as SIMULA code, or insert TAB character.
537 If `simula-tab-always-indent' is non-nil, always indent current line.
538 Otherwise, indent only if point is before any non-whitespace
539 character on the line.
540
541 A numeric argument, regardless of its value, means indent rigidly
542 all the lines of the SIMULA statement after point so that this line
543 becomes properly indented.
544 The relative indentation among the lines of the statement are preserved."
545 (interactive "P")
546 (let ((case-fold-search t))
547 (if (or whole-exp simula-tab-always-indent
548 (save-excursion
549 (skip-chars-backward " \t\f")
550 (bolp)))
551 ;; reindent current line
552 (let ((indent (save-excursion
553 (beginning-of-line)
554 (simula-calculate-indent)))
555 (current (current-indentation))
556 (origin (- (point-max) (point)))
557 (bol (save-excursion
558 (skip-chars-backward " \t\f")
559 (bolp)))
560 beg end)
561 (unwind-protect
562 (if (eq current indent)
563 (if (save-excursion
564 (skip-chars-backward " \t\f")
565 (bolp))
566 (back-to-indentation))
567 (beginning-of-line)
568 (delete-horizontal-space)
569 (indent-to indent))
570 (if (not bol)
571 (goto-char (- (point-max) origin))))
572 (setq origin (point))
573 (if whole-exp
574 (save-excursion
575 (beginning-of-line 2)
576 (setq beg (point))
577 (goto-char origin)
578 (simula-next-statement 1)
579 (setq end (point))
580 (if (and (> end beg) (not (eq indent current)))
581 (indent-code-rigidly beg end (- indent current) "%")))))
582 (insert-tab))))
583
584
585 (defun simula-context ()
586 "Returns value according to syntactic SIMULA context of point.
587 0 point inside COMMENT comment
588 1 point on SIMULA-compiler directive line
589 2 point inside END comment
590 3 point inside string
591 4 point inside character constant
592 nil otherwise."
593 ;; first, find out if this is a compiler directive line
594 (if (save-excursion
595 (beginning-of-line)
596 (eq (following-char) ?%))
597 ;; YES - return 1
598 1
599 (save-excursion
600 ;; The current line is NOT a compiler directive line.
601 ;; Now, the strategy is to search backward to find a semicolon
602 ;; that is NOT inside a string. The point after semicolon MUST be
603 ;; outside a comment, since semicolons are comment-ending and
604 ;; comments are non-recursive. We take advantage of the fact
605 ;; that strings MUST end on the same line as they started, so
606 ;; that we can easily decide whether we are inside a string or not.
607 (let (return-value (origin (point)))
608 (skip-chars-backward "^;" (point-min))
609 ;; found semicolon or beginning of buffer
610 (let (loopvalue (saved-point origin))
611 (while (and (not (bobp))
612 (if (progn
613 (beginning-of-line)
614 ;; compiler directive line? If so, cont searching..
615 (eq (following-char) ?%))
616 t
617 (while (< (point) saved-point)
618 (skip-chars-forward "^;\"'")
619 (forward-char 1)
620 (cond
621 ((eq (preceding-char) ?\;)
622 (setq saved-point (point)))
623 ((eq (preceding-char) ?\")
624 (skip-chars-forward "^\";")
625 (if (eq (following-char) ?\;)
626 (setq saved-point (point) loopvalue t)
627 (forward-char 1)))
628 (t
629 (if (eq (following-char) ?')
630 (forward-char 1))
631 (skip-chars-forward "^';")
632 (if (eq (following-char) ?\;)
633 (setq saved-point (point) loopvalue t)
634 (forward-char 1)))))
635 loopvalue))
636 (backward-char 1)
637 (skip-chars-backward "^;")
638 (setq saved-point (point) loopvalue nil)))
639 ;; Now we are CERTAIN that we are outside comments and strings.
640 ;; The job now is to search forward again towards the origin
641 ;; skipping directives, comments and strings correctly,
642 ;; so that we know what context we are in when we find the origin.
643 (while (and
644 (< (point) origin)
645 (re-search-forward
646 "\\<end\\>\\|!\\|\"\\|'\\|^%\\|\\<comment\\>" origin 'move))
647 (cond
648 ((memq (preceding-char) '(?d ?D))
649 (setq return-value 2)
650 (while (and (re-search-forward
651 ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>\\|^%"
652 origin 'move)
653 ;; found another END?
654 (or (memq (preceding-char) '(?d ?D))
655 ;; if directive, skip line
656 (and (eq (preceding-char) ?%)
657 (beginning-of-line 2))
658 ;; found other keyword, out of END comment
659 (setq return-value nil))))
660 (if (and (eq (char-syntax (preceding-char)) ?w)
661 (eq (char-syntax (following-char)) ?w))
662 (save-excursion
663 (backward-word 1)
664 (if (looking-at "end\\>\\|else\\>\\|otherwise\\>\\|when\\>")
665 (setq return-value nil)))))
666 ((memq (preceding-char) '(?! ?t ?T))
667 ; skip comment
668 (setq return-value 0)
669 (skip-chars-forward "^%;" origin)
670 (while (and return-value (< (point) origin))
671 (if (eq (following-char) ?\;)
672 (setq return-value nil)
673 (if (bolp)
674 (beginning-of-line 2) ; skip directive inside comment
675 (forward-char 1)) ; or single '%'
676 (skip-chars-forward "^%;" origin))))
677 ((eq (preceding-char) ?\")
678 (if (not (search-forward "\"" origin 'move))
679 (setq return-value 3)))
680 ((eq (preceding-char) ?\')
681 (if (or (eq (point) origin) (eobp))
682 (setq return-value 4)
683 (forward-char 1)
684 (if (not (search-forward "'" origin 'move))
685 (setq return-value 4))))
686 ;; compiler directive line - skip
687 (t (beginning-of-line 2))))
688 return-value)
689 )))
690
691
692 (defun simula-electric-label ()
693 "If this is a label that starts the line, reindent the line."
694 (interactive)
695 (expand-abbrev)
696 (insert ?:)
697 (let ((origin (- (point-max) (point)))
698 (case-fold-search t)
699 ;; don't mix a label with an assignment operator := :-
700 ;; therefore take a peek at next typed character...
701 (next-char (read-event)))
702 (unwind-protect
703 (setq unread-command-events (append unread-command-events
704 (list next-char)))
705 ;; Problem: find out if character just read is a command char
706 ;; that would insert something after ':' making it a label.
707 ;; At least \n, \r (and maybe \t) falls into this category.
708 ;; This is a real crock, it depends on traditional keymap
709 ;; bindings, that is, printing characters doing self-insert,
710 ;; and no other command sequence inserting '-' or '='.
711 ;; simula-electric-label can be easily fooled...
712 (if (and (not (memq next-char '(?= ?-)))
713 (or (memq next-char '(?\n ?\r))
714 (and (eq next-char ?\t)
715 simula-tab-always-indent)
716 (not (memq (following-char) '(?= ?-))))
717 (not (simula-context))
718 ;; label?
719 (progn
720 (backward-char 1)
721 (skip-chars-backward " \t\f")
722 (skip-chars-backward "a-zA-Z0-9_")
723 (if (looking-at "virtual\\>")
724 nil
725 (skip-chars-backward " \t\f")
726 (bolp))))
727 (let ((amount (simula-calculate-indent)))
728 (delete-horizontal-space)
729 (indent-to amount)))
730 (goto-char (- (point-max) origin)))))
731
732
733 (defun simula-backward-up-level (count)
734 "Move backward up COUNT block levels.
735 If COUNT is negative, move forward up block level instead."
736 (interactive "p")
737 (let ((origin (point))
738 (case-fold-search t))
739 (condition-case ()
740 (if (> count 0)
741 (while (> count 0)
742 (re-search-backward "\\<begin\\>\\|\\<end\\>")
743 (if (not (simula-context))
744 (setq count (if (memq (following-char) '(?b ?B))
745 (1- count)
746 (1+ count)))))
747 (while (< count 0)
748 (re-search-forward "\\<begin\\>\\|\\<end\\>")
749 (backward-word 1)
750 (if (not (simula-context))
751 (setq count (if (memq (following-char) '(?e ?E))
752 (1+ count)
753 (1- count))))
754 (backward-word -1)))
755 ;; If block level not found, jump back to origin and signal an error
756 (error (progn
757 (goto-char origin)
758 (error "No higher block level")))
759 (quit (progn
760 (goto-char origin)
761 (signal 'quit nil))))))
762
763
764 (defun simula-forward-down-level (count)
765 "Move forward down COUNT block levels.
766 If COUNT is negative, move backward down block level instead."
767 (interactive "p")
768 ;; When we search for a deeper block level, we must never
769 ;; get out of the block where we started -> count >= start-count
770 (let ((start-count count)
771 (origin (point))
772 (case-fold-search t))
773 (condition-case ()
774 (if (< count 0)
775 (while (< count 0)
776 (re-search-backward "\\<begin\\>\\|\\<end\\>")
777 (if (not (simula-context))
778 (setq count (if (memq (following-char) '(?e ?E))
779 (1+ count)
780 (1- count))))
781 (if (< count start-count) (signal 'error nil)))
782 (while (> count 0)
783 (re-search-forward "\\<begin\\>\\|\\<end\\>")
784 (backward-word 1)
785 (if (not (simula-context))
786 (setq count (if (memq (following-char) '(?b ?B))
787 (1- count)
788 (1+ count))))
789 (backward-word -1)
790 ;; deeper level has to be found within starting block
791 (if (> count start-count) (signal 'error nil))))
792 ;; If block level not found, jump back to origin and signal an error
793 (error (progn
794 (goto-char origin)
795 (error "No containing block level")))
796 (quit (progn
797 (goto-char origin)
798 (signal 'quit nil))))))
799
800
801 (defun simula-previous-statement (count)
802 "Move backward COUNT statements.
803 If COUNT is negative, move forward instead."
804 (interactive "p")
805 (if (< count 0)
806 (simula-next-statement (- count))
807 (let (status
808 (case-fold-search t)
809 (origin (point)))
810 (condition-case ()
811 ;;
812 (progn
813 (simula-skip-comment-backward)
814 (if (memq (preceding-char) '(?n ?N))
815 (progn
816 (backward-word 1)
817 (if (not (looking-at "\\<begin\\>"))
818 (backward-word -1)))
819 (if (eq (preceding-char) ?\;)
820 (backward-char 1))
821 )
822 (while (and (natnump (setq count (1- count)))
823 (setq status (simula-search-backward
824 ";\\|\\<begin\\>" nil 'move))))
825 (if status
826 (progn
827 (if (eq (following-char) ?\;)
828 (forward-char 1)
829 (backward-word -1))))
830 (simula-skip-comment-forward))
831 (error (progn (goto-char origin)
832 (error "Incomplete statement (too many ENDs)")))
833 (quit (progn (goto-char origin) (signal 'quit nil)))))))
834
835
836 (defun simula-next-statement (count)
837 "Move forward COUNT statements.
838 If COUNT is negative, move backward instead."
839 (interactive "p")
840 (if (< count 0)
841 (simula-previous-statement (- count))
842 (let (status
843 (case-fold-search t)
844 (origin (point)))
845 (condition-case ()
846 (progn
847 (simula-skip-comment-forward)
848 (if (looking-at "\\<end\\>") (forward-word 1))
849 (while (and (natnump (setq count (1- count)))
850 (setq status (simula-search-forward
851 ";\\|\\<end\\>" (point-max) 'move))))
852 (if (and status (/= (preceding-char) ?\;))
853 (progn
854 (backward-word 1)
855 (simula-skip-comment-backward))))
856 (error (progn (goto-char origin)
857 (error "Incomplete statement (too few ENDs)")))
858 (quit (progn (goto-char origin) (signal 'quit nil)))))))
859
860
861 (defun simula-skip-comment-backward (&optional stop-at-end)
862 "Search towards bob to find first char that is outside a comment."
863 (interactive)
864 (catch 'simula-out
865 (let (context)
866 (while t
867 (skip-chars-backward " \t\n\f")
868 (if (eq (preceding-char) ?\;)
869 (save-excursion
870 (backward-char 1)
871 (setq context (simula-context))
872 (if (and stop-at-end (eq context 2))
873 (setq context nil)))
874 (setq context (simula-context)))
875 (cond
876 ((memq context '(nil 3 4))
877 ;; check to see if we found a label
878 (if (and (eq (preceding-char) ?:)
879 (not (memq (following-char) '(?- ?=)))
880 (save-excursion
881 (skip-chars-backward ": \t\fa-zA-Z0-9_")
882 (not (looking-at "virtual\\>"))))
883 (skip-chars-backward ": \t\fa-zA-Z0-9_")
884 (throw 'simula-out nil)))
885 ((eq context 0)
886 ;; since we are inside a comment, it must start somewhere!
887 (while (and (re-search-backward "!\\|\\<comment\\>")
888 (memq (simula-context) '(0 1)))))
889 ((eq context 1)
890 (beginning-of-line)
891 (if (bobp)
892 (throw 'simula-out nil)
893 (backward-char)))
894 ((eq context 2)
895 ;; an END-comment must belong to an END
896 (re-search-backward "\\<end\\>")
897 (forward-word 1)
898 (throw 'simula-out nil))
899 ;; should be impossible to get here..
900 )))))
901
902
903 (defun simula-skip-comment-forward ()
904 "Search towards eob to find first char that is outside a comment."
905 ;; this function assumes we start with point .outside a comment
906 (interactive)
907 (catch 'simula-out
908 (while t
909 (skip-chars-forward " \t\n\f")
910 ;; BUG: the following (0 2) branches don't take into account intermixing
911 ;; directive lines
912 (cond
913 ((looking-at "!\\|\\<comment\\>")
914 (search-forward ";" nil 'move))
915 ((and (bolp) (eq (following-char) ?%))
916 (beginning-of-line 2))
917 ((and (looking-at "[a-z0-9_]*[ \t\f]*:[^-=]")
918 (not (looking-at "virtual\\>")))
919 (skip-chars-forward "a-zA-Z0-9_ \t\f:"))
920 (t
921 (throw 'simula-out t))))))
922
923
924 (defun simula-forward-up-level ()
925 (let ((continue-loop t)
926 (origin (point))
927 (case-fold-search t)
928 return-value
929 temp)
930 (while continue-loop
931 (if (re-search-backward "\\<begin\\>\\|\\<end\\>" (point-min) 'move)
932 (setq temp (simula-context)
933 return-value (and (memq (preceding-char) '(?d ?D))
934 (memq temp '(nil 2)))
935 continue-loop (and (not return-value)
936 (simula-forward-up-level)))
937 (setq continue-loop nil)))
938 (if return-value
939 t
940 (goto-char origin)
941 nil)))
942
943
944 (defun simula-calculate-indent ()
945 (save-excursion
946 (let ((where (simula-context))
947 (origin (point))
948 (indent 0)
949 continued
950 start-line
951 temp
952 found-end
953 prev-cont)
954 (cond
955 ((eq where 0)
956 ;;
957 ;; Comment.
958 ;; If comment started on previous non-blank line, indent to the
959 ;; column where the comment started, else indent as that line.
960 ;;
961 (skip-chars-backward " \t\n\f")
962 (while (and (not (bolp)) (eq (simula-context) 0))
963 (re-search-backward "^\\|!\\|\\<comment\\>"))
964 (skip-chars-forward " \t\n\f")
965 (prog1
966 (current-column)
967 (goto-char origin)))
968 ((eq where 1)
969 ;;
970 ;; Directive. Always 0.
971 ;;
972 0)
973 ;;
974 ;; Detect missing string delimiters
975 ;;
976 ((eq where 3)
977 (error "Inside string"))
978 ((eq where 4)
979 (error "Inside character constant"))
980 ;;
981 ;; check to see if inside ()'s
982 ;;
983 ((setq temp (simula-inside-parens))
984 temp)
985 ;;
986 ;; Calculate non-comment indentation
987 (t
988 ;; first, find out if this line starts with something that needs
989 ;; special indentation (END/IF/THEN/ELSE/WHEN/OTHERWISE or label)
990 ;;
991 (skip-chars-forward " \t\f")
992 (cond
993 ;;
994 ;; END
995 ;;
996 ((looking-at "end\\>")
997 (setq indent (- simula-indent-level)
998 found-end t))
999 ;;
1000 ;; IF/THEN/ELSE
1001 ;;
1002 ((looking-at "if\\>\\|then\\>\\|else\\>")
1003 ;; search for the *starting* IF
1004 (cond
1005 ((memq (following-char) '(?T ?t))
1006 (setq indent (car simula-if-indent)))
1007 ((memq (following-char) '(?E ?e))
1008 (setq indent (cdr simula-if-indent)))
1009 (t
1010 (forward-word 1)
1011 (setq indent 0)))
1012 (simula-find-if))
1013 ;;
1014 ;; WHEN/OTHERWISE
1015 ;;
1016 ((looking-at "when\\>\\|otherwise\\>")
1017 ;; search for corresponding INSPECT
1018 (if (memq (following-char) '(?W ?w))
1019 (setq indent (car simula-inspect-indent))
1020 (setq indent (cdr simula-inspect-indent)))
1021 (simula-find-inspect))
1022 ;;
1023 ;; label:
1024 ;;
1025 ((and (not (looking-at "virtual\\>"))
1026 (looking-at "[a-z0-9_]*[ \t\f]*:[^-=]"))
1027 (setq indent simula-label-offset)))
1028 ;; find line with non-comment text
1029 (simula-skip-comment-backward 'dont-skip-end)
1030 (if (and found-end
1031 (not (eq (preceding-char) ?\;))
1032 (if (memq (preceding-char) '(?N ?n))
1033 (save-excursion
1034 (backward-word 1)
1035 (not (looking-at "begin\\>")))
1036 t))
1037 (progn
1038 (simula-previous-statement 1)
1039 (simula-skip-comment-backward)))
1040 (setq start-line
1041 (save-excursion (beginning-of-line) (point))
1042 ;; - perhaps this is a continued statement
1043 continued
1044 (save-excursion
1045 (and (not (bobp))
1046 ;; (not found-end)
1047 (if (eq (char-syntax (preceding-char)) ?w)
1048 (progn
1049 (backward-word 1)
1050 (not (looking-at
1051 "begin\\|then\\|else\\|when\\|otherwise\\|do"
1052 )))
1053 (not (memq (preceding-char) '(?: ?\;)))))))
1054 ;;
1055 ;; MAIN calculation loop - count BEGIN/DO etc.
1056 ;;
1057 (while (not (bolp))
1058 (if (re-search-backward
1059 ";\\|\\<\\(begin\\|end\\|if\\|else\\|then\\|when\\|otherwise\\|do\\)\\>"
1060 start-line 'move)
1061 (if (simula-context)
1062 ();; found something in a comment/string - ignore
1063 (setq temp (following-char))
1064 (cond
1065 ((eq temp ?\;)
1066 (simula-previous-statement 1))
1067 ((looking-at "begin\\>")
1068 (setq indent (+ indent simula-indent-level)))
1069 ((looking-at "end\\>")
1070 (forward-word 1)
1071 (simula-previous-statement 1))
1072 ((looking-at "do\\>")
1073 (setq indent (+ indent simula-substatement-offset))
1074 (simula-find-do-match))
1075 ((looking-at "\\(if\\|then\\|else\\)\\>")
1076 (if (memq temp '(?I ?i))
1077 (forward-word 1)
1078 (setq indent (+ indent
1079 simula-substatement-offset
1080 (if (memq temp '(?T ?t))
1081 (car simula-if-indent)
1082 (cdr simula-if-indent)))))
1083 (simula-find-if))
1084 ((looking-at "\\<when\\>\\|\\<otherwise\\>")
1085 (setq indent (+ indent
1086 simula-substatement-offset
1087 (if (memq temp '(?W ?w))
1088 (car simula-if-indent)
1089 (cdr simula-if-indent))))
1090 (simula-find-inspect)))
1091 ;; found the start of a [sub]statement
1092 ;; add indentation for continued statement
1093 (if continued
1094 (setq indent
1095 (+ indent
1096 (if (listp simula-continued-statement-offset)
1097 (car simula-continued-statement-offset)
1098 simula-continued-statement-offset))))
1099 (setq start-line
1100 (save-excursion (beginning-of-line) (point))
1101 continued nil))
1102 ;; search failed .. point is at beginning of line
1103 ;; determine if we should continue searching
1104 ;; (at or before comment or label)
1105 ;; temp = t means finished
1106 (setq temp
1107 (and (not (simula-context))
1108 (save-excursion
1109 (skip-chars-forward " \t\f")
1110 (or (looking-at "virtual")
1111 (not
1112 (looking-at
1113 "!\\|comment\\>\\|[a-z0-9_]*[ \t\f]*:[^-=]")))))
1114 prev-cont continued)
1115 ;; if we are finished, find current line's indentation
1116 (if temp
1117 (setq indent (+ indent (current-indentation))))
1118 ;; find next line with non-comment SIMULA text
1119 ;; maybe indent extra if statement continues
1120 (simula-skip-comment-backward)
1121 (setq continued
1122 (and (not (bobp))
1123 (if (eq (char-syntax (preceding-char)) ?w)
1124 (save-excursion
1125 (backward-word 1)
1126 (not (looking-at
1127 "begin\\|then\\|else\\|when\\|otherwise\\|do")))
1128 (not (memq (preceding-char) '(?: ?\;))))))
1129 ;; if we the state of the continued-variable
1130 ;; changed, add indentation for continued statement
1131 (if (or (and prev-cont (not continued))
1132 (and continued
1133 (listp simula-continued-statement-offset)))
1134 (setq indent
1135 (+ indent
1136 (if (listp simula-continued-statement-offset)
1137 (car simula-continued-statement-offset)
1138 simula-continued-statement-offset))))
1139 ;; while ends if point is at beginning of line at loop test
1140 (if (not temp)
1141 (setq start-line (save-excursion (beginning-of-line) (point)))
1142 (beginning-of-line))))
1143 ;;
1144 ;; return indentation
1145 ;;
1146 indent)))))
1147
1148
1149 (defun simula-find-if ()
1150 "Find starting IF of a IF-THEN[-ELSE[-IF-THEN...]] statement."
1151 (catch 'simula-out
1152 (while t
1153 (if (and (simula-search-backward "\\<if\\>\\|;\\|\\<begin\\>"nil t)
1154 (memq (following-char) '(?I ?i)))
1155 (save-excursion
1156 ;;
1157 ;; find out if this IF was really the start of the IF statement
1158 ;;
1159 (simula-skip-comment-backward)
1160 (if (and (eq (char-syntax (preceding-char)) ?w)
1161 (progn
1162 (backward-word 1)
1163 (looking-at "else\\>")))
1164 ()
1165 (throw 'simula-out t)))
1166 (if (not (looking-at "\\<if\\>"))
1167 (error "Missing IF or misplaced BEGIN or ';' (can't find IF)")
1168 ;;
1169 ;; we were at the starting IF in the first place..
1170 ;;
1171 (throw 'simula-out t))))))
1172
1173
1174 (defun simula-find-inspect ()
1175 "Find INSPECT matching WHEN or OTHERWISE."
1176 (catch 'simula-out
1177 (let ((level 0))
1178 ;;
1179 ;; INSPECTs can be nested, have to find the corresponding one
1180 ;;
1181 (while t
1182 (if (and (simula-search-backward "\\<inspect\\>\\|\\<otherwise\\>\\|;"
1183 nil t)
1184 (/= (following-char) ?\;))
1185 (if (memq (following-char) '(?O ?o))
1186 (setq level (1+ level))
1187 (if (zerop level)
1188 (throw 'simula-out t)
1189 (setq level (1- level))))
1190 (error "Missing INSPECT or misplaced ';' (can't find INSPECT)"))))))
1191
1192
1193 (defun simula-find-do-match ()
1194 "Find keyword matching DO: FOR, WHILE, INSPECT or WHEN"
1195 (while (and (re-search-backward
1196 "\\<\\(do\\|for\\|while\\|inspect\\|when\\|end\\|begin\\)\\>\\|;"
1197 nil 'move)
1198 (simula-context)))
1199 (if (and (looking-at "\\<\\(for\\|while\\|inspect\\|when\\)\\>")
1200 (not (simula-context)))
1201 () ;; found match
1202 (error "No matching FOR, WHILE or INSPECT for DO, or misplaced ';'")))
1203
1204
1205 (defun simula-inside-parens ()
1206 "Return position after `(' on line if inside parentheses, nil otherwise."
1207 (save-excursion
1208 (let ((parlevel 0))
1209 (catch 'simula-out
1210 (while t
1211 (if (re-search-backward "(\\|)\\|;" nil t)
1212 (if (eq (simula-context) nil)
1213 ;; found something - check it out
1214 (cond
1215 ((eq (following-char) ?\;)
1216 (if (zerop parlevel)
1217 (throw 'simula-out nil)
1218 (error "Parenthesis mismatch or misplaced ';'")))
1219 ((eq (following-char) ?\()
1220 (if (zerop parlevel)
1221 (throw 'simula-out (1+ (current-column)))
1222 (setq parlevel (1- parlevel))))
1223 (t (setq parlevel (1+ parlevel))))
1224 );; nothing - inside comment or string
1225 ;; search failed
1226 (throw 'simula-out nil)))))))
1227
1228
1229 (defun simula-goto-definition ()
1230 "Goto point of definition of variable, procedure or class."
1231 (interactive))
1232
1233
1234 (defun simula-expand-stdproc ()
1235 (if (or (not simula-abbrev-stdproc) (simula-context))
1236 (unexpand-abbrev)
1237 (cond
1238 ((eq simula-abbrev-stdproc 'upcase) (upcase-word -1))
1239 ((eq simula-abbrev-stdproc 'downcase) (downcase-word -1))
1240 ((eq simula-abbrev-stdproc 'capitalize) (capitalize-word -1))
1241 ((eq simula-abbrev-stdproc 'abbrev-table)
1242 ;; If not in lowercase, expansions are always capitalized.
1243 ;; We then want to replace with the exact expansion.
1244 (if (equal (symbol-name last-abbrev) last-abbrev-text)
1245 ()
1246 (downcase-word -1)
1247 (expand-abbrev))))))
1248
1249
1250 (defun simula-expand-keyword ()
1251 (if (or (not simula-abbrev-keyword) (simula-context))
1252 (unexpand-abbrev)
1253 (cond
1254 ((eq simula-abbrev-keyword 'upcase) (upcase-word -1))
1255 ((eq simula-abbrev-keyword 'downcase) (downcase-word -1))
1256 ((eq simula-abbrev-keyword 'capitalize) (capitalize-word -1))
1257 ((eq simula-abbrev-stdproc 'abbrev-table)
1258 (if (equal (symbol-name last-abbrev) last-abbrev-text)
1259 ()
1260 (downcase-word -1)
1261 (expand-abbrev))))))
1262
1263
1264 (defun simula-electric-keyword ()
1265 "Expand SIMULA keyword. If it starts the line, reindent."
1266 ;; redisplay
1267 (let ((show-char (eq this-command 'self-insert-command)))
1268 ;; If the abbrev expansion results in reindentation, the user may have
1269 ;; to wait some time before the character he typed is displayed
1270 ;; (the char causing the expansion is inserted AFTER the hook function
1271 ;; is called). This is annoying in case of normal characters.
1272 ;; However, if the user pressed a key bound to newline, it is better
1273 ;; to have the line inserted after the begin-end match.
1274 (if show-char
1275 (progn
1276 (insert-char last-command-char 1)
1277 (sit-for 0)
1278 (backward-char 1)))
1279 (if (let ((where (simula-context))
1280 (case-fold-search t))
1281 (if where
1282 (if (and (eq where 2) (eq (char-syntax (preceding-char)) ?w))
1283 (save-excursion
1284 (backward-word 1)
1285 (not (looking-at "end\\>"))))))
1286 (unexpand-abbrev)
1287 (cond
1288 ((not simula-abbrev-keyword) (unexpand-abbrev))
1289 ((eq simula-abbrev-keyword 'upcase) (upcase-word -1))
1290 ((eq simula-abbrev-keyword 'downcase) (downcase-word -1))
1291 ((eq simula-abbrev-keyword 'capitalize) (capitalize-word -1)))
1292 (let ((pos (- (point-max) (point)))
1293 (case-fold-search t)
1294 null)
1295 (condition-case null
1296 (progn
1297 ;; check if the expanded word is on the beginning of the line.
1298 (if (and (eq (char-syntax (preceding-char)) ?w)
1299 (progn
1300 (backward-word 1)
1301 (if (looking-at "end\\>")
1302 (save-excursion
1303 (simula-backward-up-level 1)
1304 (if (pos-visible-in-window-p)
1305 (sit-for 1)
1306 (message "Matches %s"
1307 (buffer-substring
1308 (point)
1309 (+ (point) (window-width)))))))
1310 (skip-chars-backward " \t\f")
1311 (bolp)))
1312 (let ((indent (simula-calculate-indent)))
1313 (if (eq indent (current-indentation))
1314 ()
1315 (delete-horizontal-space)
1316 (indent-to indent)))
1317 (skip-chars-forward " \t\f"))
1318 ;; check for END - blow whistles and ring bells
1319
1320 (goto-char (- (point-max) pos))
1321 (if show-char
1322 (delete-char 1)))
1323 (quit (goto-char (- (point-max) pos))))))))
1324
1325
1326 (defun simula-search-backward (regexp &optional bound noerror)
1327 "Search backward from point for regular expression REGEXP, ignoring matches
1328 found inside SIMULA comments, string literals, and BEGIN..END blocks.
1329 Set point to the end of the occurrence found, and return point.
1330 An optional second argument BOUND bounds the search, it is a buffer position.
1331 The match found must not extend after that position. Optional third argument
1332 NOERROR, if t, means if fail just return nil (no error).
1333 If not nil and not t, move to limit of search and return nil."
1334 (let (begin end context (comb-regexp (concat regexp "\\|\\<end\\>"))
1335 match (start-point (point)))
1336 (catch 'simula-backward
1337 (while (re-search-backward comb-regexp bound 1)
1338 ;; We have a match, check SIMULA context at match-beginning
1339 ;; to see if we are outside comments etc.
1340 ;; Set MATCH to t if we found a true match,
1341 ;; set MATCH to 'BLOCK if we found a BEGIN..END block,
1342 ;; else set MATCH to nil.
1343 (save-match-data
1344 (setq context (simula-context))
1345 (cond
1346 ((eq context nil)
1347 (setq match (if (looking-at regexp) t 'BLOCK)))
1348 ;;; A comment-ending semicolon is part of the comment, and shouldn't match.
1349 ;;; ((eq context 0)
1350 ;;; (setq match (if (eq (following-char) ?\;) t nil)))
1351 ((eq context 2)
1352 (setq match (if (and (looking-at regexp)
1353 (looking-at ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>"))
1354 t
1355 (if (looking-at "\\<end\\>") 'BLOCK nil))))
1356 (t (setq match nil))))
1357 ;; Exit if true match
1358 (if (eq match t) (throw 'simula-backward (point)))
1359 (if (eq match 'BLOCK)
1360 ;; We found the END of a block
1361 (let ((level 0))
1362 (while (natnump level)
1363 (if (re-search-backward "\\<begin\\>\\|\\<end\\>" bound 1)
1364 (let ((context (simula-context)))
1365 ;; We found a BEGIN -> decrease level count
1366 (cond ((and (eq context nil)
1367 (memq (following-char) '(?b ?B)))
1368 (setq level (1- level)))
1369 ;; END -> increase level count
1370 ((and (memq context '(nil 2))
1371 (memq (following-char) '(?e ?E)))
1372 (setq level (1+ level)))))
1373 ;; Block search failed. Action depends on noerror.
1374 (if (or (not noerror) (eq noerror t))
1375 (goto-char start-point))
1376 (if (not noerror)
1377 (signal 'search-failed (list regexp)))
1378 (throw 'simula-backward nil))))))
1379 ;; Search failed. Action depends on noerror.
1380 (if (or (not noerror) (eq noerror t))
1381 (goto-char start-point))
1382 (if noerror
1383 nil
1384 (signal 'search-failed (list regexp))))))
1385
1386
1387 (defun simula-search-forward (regexp &optional bound noerror)
1388 "Search forward from point for regular expression REGEXP, ignoring matches
1389 found inside SIMULA comments, string literals, and BEGIN..END blocks.
1390 Set point to the end of the occurrence found, and return point.
1391 An optional second argument BOUND bounds the search, it is a buffer position.
1392 The match found must not extend after that position. Optional third argument
1393 NOERROR, if t, means if fail just return nil (no error).
1394 If not nil and not t, move to limit of search and return nil."
1395 (let (begin end context (comb-regexp (concat regexp "\\|\\<begin\\>"))
1396 match (start-point (point)))
1397 (catch 'simula-forward
1398 (while (re-search-forward comb-regexp bound 1)
1399 ;; We have a match, check SIMULA context at match-beginning
1400 ;; to see if we are outside comments.
1401 ;; Set MATCH to t if we found a true match,
1402 ;; set MATCH to 'BLOCK if we found a BEGIN..END block,
1403 ;; else set MATCH to nil.
1404 (save-match-data
1405 (save-excursion
1406 (goto-char (match-beginning 0))
1407 (setq context (simula-context))
1408 (cond
1409 ((not context)
1410 (setq match (if (looking-at regexp) t 'BLOCK)))
1411 ;;; A comment-ending semicolon is part of the comment, and shouldn't match.
1412 ;;; ((eq context 0)
1413 ;;; (setq match (if (eq (following-char) ?\;) t nil)))
1414 ((eq context 2)
1415 (setq match (if (and (looking-at regexp)
1416 (looking-at ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>")) t nil)))
1417 (t (setq match nil)))))
1418 ;; Exit if true match
1419 (if (eq match t) (throw 'simula-forward (point)))
1420 (if (eq match 'BLOCK)
1421 ;; We found the BEGINning of a block
1422 (let ((level 0))
1423 (while (natnump level)
1424 (if (re-search-forward "\\<begin\\>\\|\\<end\\>" bound 1)
1425 (let ((context (simula-context)))
1426 ;; We found a BEGIN -> increase level count
1427 (cond ((eq context nil) (setq level (1+ level)))
1428 ;; END -> decrease level count
1429 ((and (eq context 2)
1430 ;; Don't match BEGIN inside END comment
1431 (memq (preceding-char) '(?d ?D)))
1432 (setq level (1- level)))))
1433 ;; Block search failed. Action depends on noerror.
1434 (if (or (not noerror) (eq noerror t))
1435 (goto-char start-point))
1436 (if (not noerror)
1437 (signal 'search-failed (list regexp)))
1438 (throw 'simula-forward nil))))))
1439 ;; Search failed. Action depends on noerror.
1440 (if (or (not noerror) (eq noerror t))
1441 (goto-char start-point))
1442 (if noerror
1443 nil
1444 (signal 'search-failed (list regexp))))))
1445
1446
1447 (defun simula-install-standard-abbrevs ()
1448 "Define Simula keywords, procedures and classes in local abbrev table."
1449 ;; procedure and class names are as of the SIMULA 87 standard.
1450 (interactive)
1451 (mapcar (function (lambda (args)
1452 (apply 'define-abbrev simula-mode-abbrev-table args)))
1453 '(("abs" "Abs" simula-expand-stdproc)
1454 ("accum" "Accum" simula-expand-stdproc)
1455 ("activate" "ACTIVATE" simula-expand-keyword)
1456 ("addepsilon" "AddEpsilon" simula-expand-stdproc)
1457 ("after" "AFTER" simula-expand-keyword)
1458 ("and" "AND" simula-expand-keyword)
1459 ("arccos" "ArcCos" simula-expand-stdproc)
1460 ("arcsin" "ArcSin" simula-expand-stdproc)
1461 ("arctan" "ArcTan" simula-expand-stdproc)
1462 ("arctan2" "ArcTan2" simula-expand-stdproc)
1463 ("array" "ARRAY" simula-expand-keyword)
1464 ("at" "AT" simula-expand-keyword)
1465 ("before" "BEFORE" simula-expand-keyword)
1466 ("begin" "BEGIN" simula-expand-keyword)
1467 ("blanks" "Blanks" simula-expand-stdproc)
1468 ("boolean" "BOOLEAN" simula-expand-keyword)
1469 ("breakoutimage" "BreakOutImage" simula-expand-stdproc)
1470 ("bytefile" "ByteFile" simula-expand-stdproc)
1471 ("call" "Call" simula-expand-stdproc)
1472 ("cancel" "Cancel" simula-expand-stdproc)
1473 ("cardinal" "Cardinal" simula-expand-stdproc)
1474 ("char" "Char" simula-expand-stdproc)
1475 ("character" "CHARACTER" simula-expand-keyword)
1476 ("checkpoint" "CheckPoint" simula-expand-stdproc)
1477 ("class" "CLASS" simula-expand-keyword)
1478 ("clear" "Clear" simula-expand-stdproc)
1479 ("clocktime" "ClockTime" simula-expand-stdproc)
1480 ("close" "Close" simula-expand-stdproc)
1481 ("comment" "COMMENT" simula-expand-keyword)
1482 ("constant" "Constant" simula-expand-stdproc)
1483 ("copy" "Copy" simula-expand-stdproc)
1484 ("cos" "Cos" simula-expand-stdproc)
1485 ("cosh" "CosH" simula-expand-stdproc)
1486 ("cotan" "CoTan" simula-expand-stdproc)
1487 ("cputime" "CpuTime" simula-expand-stdproc)
1488 ("current" "Current" simula-expand-stdproc)
1489 ("datetime" "DateTime" simula-expand-stdproc)
1490 ("decimalmark" "DecimalMark" simula-expand-stdproc)
1491 ("delay" "DELAY" simula-expand-keyword)
1492 ("deleteimage" "DeleteImage" simula-expand-stdproc)
1493 ("detach" "Detach" simula-expand-stdproc)
1494 ("digit" "Digit" simula-expand-stdproc)
1495 ("directbytefile" "DirectByteFile" simula-expand-stdproc)
1496 ("directfile" "DirectFile" simula-expand-stdproc)
1497 ("discrete" "Discrete" simula-expand-stdproc)
1498 ("do" "DO" simula-expand-keyword)
1499 ("downcase" "Downcase" simula-expand-stdproc)
1500 ("draw" "Draw" simula-expand-stdproc)
1501 ("eject" "Eject" simula-expand-stdproc)
1502 ("else" "ELSE" simula-electric-keyword)
1503 ("empty" "Empty" simula-expand-stdproc)
1504 ("end" "END" simula-electric-keyword)
1505 ("endfile" "Endfile" simula-expand-stdproc)
1506 ("entier" "Entier" simula-expand-stdproc)
1507 ("eq" "EQ" simula-expand-keyword)
1508 ("eqv" "EQV" simula-expand-keyword)
1509 ("erlang" "Erlang" simula-expand-stdproc)
1510 ("error" "Error" simula-expand-stdproc)
1511 ("evtime" "EvTime" simula-expand-stdproc)
1512 ("exp" "Exp" simula-expand-stdproc)
1513 ("external" "EXTERNAL" simula-expand-keyword)
1514 ("false" "FALSE" simula-expand-keyword)
1515 ("field" "Field" simula-expand-stdproc)
1516 ("file" "File" simula-expand-stdproc)
1517 ("first" "First" simula-expand-stdproc)
1518 ("follow" "Follow" simula-expand-stdproc)
1519 ("for" "FOR" simula-expand-keyword)
1520 ("ge" "GE" simula-expand-keyword)
1521 ("getchar" "GetChar" simula-expand-stdproc)
1522 ("getfrac" "GetFrac" simula-expand-stdproc)
1523 ("getint" "GetInt" simula-expand-stdproc)
1524 ("getreal" "GetReal" simula-expand-stdproc)
1525 ("go" "GO" simula-expand-keyword)
1526 ("goto" "GOTO" simula-expand-keyword)
1527 ("gt" "GT" simula-expand-keyword)
1528 ("head" "Head" simula-expand-stdproc)
1529 ("hidden" "HIDDEN" simula-expand-keyword)
1530 ("histd" "HistD" simula-expand-stdproc)
1531 ("histo" "Histo" simula-expand-stdproc)
1532 ("hold" "Hold" simula-expand-stdproc)
1533 ("idle" "Idle" simula-expand-stdproc)
1534 ("if" "IF" simula-expand-keyword)
1535 ("image" "Image" simula-expand-stdproc)
1536 ("imagefile" "ImageFile" simula-expand-stdproc)
1537 ("imp" "IMP" simula-expand-keyword)
1538 ("in" "IN" simula-expand-keyword)
1539 ("inbyte" "InByte" simula-expand-stdproc)
1540 ("inbytefile" "InByteFile" simula-expand-stdproc)
1541 ("inchar" "InChar" simula-expand-stdproc)
1542 ("infile" "InFile" simula-expand-stdproc)
1543 ("infrac" "InFrac" simula-expand-stdproc)
1544 ("inimage" "InImage" simula-expand-stdproc)
1545 ("inint" "InInt" simula-expand-stdproc)
1546 ("inner" "INNER" simula-expand-keyword)
1547 ("inreal" "InReal" simula-expand-stdproc)
1548 ("inrecord" "InRecord" simula-expand-stdproc)
1549 ("inspect" "INSPECT" simula-expand-keyword)
1550 ("integer" "INTEGER" simula-expand-keyword)
1551 ("intext" "InText" simula-expand-stdproc)
1552 ("into" "Into" simula-expand-stdproc)
1553 ("is" "IS" simula-expand-keyword)
1554 ("isochar" "ISOChar" simula-expand-stdproc)
1555 ("isopen" "IsOpen" simula-expand-stdproc)
1556 ("isorank" "ISORank" simula-expand-stdproc)
1557 ("label" "LABEL" simula-expand-keyword)
1558 ("last" "Last" simula-expand-stdproc)
1559 ("lastitem" "LastItem" simula-expand-stdproc)
1560 ("lastloc" "LastLoc" simula-expand-stdproc)
1561 ("le" "LE" simula-expand-keyword)
1562 ("length" "Length" simula-expand-stdproc)
1563 ("letter" "Letter" simula-expand-stdproc)
1564 ("line" "Line" simula-expand-stdproc)
1565 ("linear" "Linear" simula-expand-stdproc)
1566 ("linesperpage" "LinesPerPage" simula-expand-stdproc)
1567 ("link" "Link" simula-expand-stdproc)
1568 ("linkage" "Linkage" simula-expand-stdproc)
1569 ("ln" "Ln" simula-expand-stdproc)
1570 ("locate" "Locate" simula-expand-stdproc)
1571 ("location" "Location" simula-expand-stdproc)
1572 ("lock" "Lock" simula-expand-stdproc)
1573 ("locked" "Locked" simula-expand-stdproc)
1574 ("log10" "Log10" simula-expand-stdproc)
1575 ("long" "LONG" simula-expand-keyword)
1576 ("lowcase" "LowCase" simula-expand-stdproc)
1577 ("lowerbound" "LowerBound" simula-expand-stdproc)
1578 ("lowten" "LowTen" simula-expand-stdproc)
1579 ("lt" "LT" simula-expand-keyword)
1580 ("main" "Main" simula-expand-stdproc)
1581 ("max" "Max" simula-expand-stdproc)
1582 ("maxint" "MaxInt" simula-expand-stdproc)
1583 ("maxlongreal" "MaxLongReal" simula-expand-stdproc)
1584 ("maxloc" "MaxLoc" simula-expand-stdproc)
1585 ("maxrank" "MaxRank" simula-expand-stdproc)
1586 ("maxreal" "MaxReal" simula-expand-stdproc)
1587 ("min" "Min" simula-expand-stdproc)
1588 ("minint" "MinInt" simula-expand-stdproc)
1589 ("minlongreal" "MinLongReal" simula-expand-stdproc)
1590 ("minrank" "MinRank" simula-expand-stdproc)
1591 ("minreal" "MinReal" simula-expand-stdproc)
1592 ("mod" "Mod" simula-expand-stdproc)
1593 ("more" "More" simula-expand-stdproc)
1594 ("name" "NAME" simula-expand-keyword)
1595 ("ne" "NE" simula-expand-keyword)
1596 ("negexp" "NegExp" simula-expand-stdproc)
1597 ("new" "NEW" simula-expand-keyword)
1598 ("nextev" "NextEv" simula-expand-stdproc)
1599 ("none" "NONE" simula-expand-keyword)
1600 ("normal" "Normal" simula-expand-stdproc)
1601 ("not" "NOT" simula-expand-keyword)
1602 ("notext" "NOTEXT" simula-expand-keyword)
1603 ("open" "Open" simula-expand-stdproc)
1604 ("or" "OR" simula-expand-keyword)
1605 ("otherwise" "OTHERWISE" simula-electric-keyword)
1606 ("out" "Out" simula-expand-stdproc)
1607 ("outbyte" "OutByte" simula-expand-stdproc)
1608 ("outbytefile" "OutByteFile" simula-expand-stdproc)
1609 ("outchar" "OutChar" simula-expand-stdproc)
1610 ("outfile" "OutFile" simula-expand-stdproc)
1611 ("outfix" "OutFix" simula-expand-stdproc)
1612 ("outfrac" "OutFrac" simula-expand-stdproc)
1613 ("outimage" "OutImage" simula-expand-stdproc)
1614 ("outint" "OutInt" simula-expand-stdproc)
1615 ("outreal" "OutReal" simula-expand-stdproc)
1616 ("outrecord" "OutRecord" simula-expand-stdproc)
1617 ("outtext" "OutText" simula-expand-stdproc)
1618 ("page" "Page" simula-expand-stdproc)
1619 ("passivate" "Passivate" simula-expand-stdproc)
1620 ("poisson" "Poisson" simula-expand-stdproc)
1621 ("pos" "Pos" simula-expand-stdproc)
1622 ("precede" "Precede" simula-expand-stdproc)
1623 ("pred" "Pred" simula-expand-stdproc)
1624 ("prev" "Prev" simula-expand-stdproc)
1625 ("printfile" "PrintFile" simula-expand-stdproc)
1626 ("prior" "PRIOR" simula-expand-keyword)
1627 ("procedure" "PROCEDURE" simula-expand-keyword)
1628 ("process" "Process" simula-expand-stdproc)
1629 ("protected" "PROTECTED" simula-expand-keyword)
1630 ("putchar" "PutChar" simula-expand-stdproc)
1631 ("putfix" "PutFix" simula-expand-stdproc)
1632 ("putfrac" "PutFrac" simula-expand-stdproc)
1633 ("putint" "PutInt" simula-expand-stdproc)
1634 ("putreal" "PutReal" simula-expand-stdproc)
1635 ("qua" "QUA" simula-expand-keyword)
1636 ("randint" "RandInt" simula-expand-stdproc)
1637 ("rank" "Rank" simula-expand-stdproc)
1638 ("reactivate" "REACTIVATE" simula-expand-keyword)
1639 ("real" "REAL" simula-expand-keyword)
1640 ("ref" "REF" simula-expand-keyword)
1641 ("resume" "Resume" simula-expand-stdproc)
1642 ("setaccess" "SetAccess" simula-expand-stdproc)
1643 ("setpos" "SetPos" simula-expand-stdproc)
1644 ("short" "SHORT" simula-expand-keyword)
1645 ("sign" "Sign" simula-expand-stdproc)
1646 ("simset" "SimSet" simula-expand-stdproc)
1647 ("simulaid" "SimulaId" simula-expand-stdproc)
1648 ("simulation" "Simulation" simula-expand-stdproc)
1649 ("sin" "Sin" simula-expand-stdproc)
1650 ("sinh" "SinH" simula-expand-stdproc)
1651 ("sourceline" "SourceLine" simula-expand-stdproc)
1652 ("spacing" "Spacing" simula-expand-stdproc)
1653 ("sqrt" "Sqrt" simula-expand-stdproc)
1654 ("start" "Start" simula-expand-stdproc)
1655 ("step" "STEP" simula-expand-keyword)
1656 ("strip" "Strip" simula-expand-stdproc)
1657 ("sub" "Sub" simula-expand-stdproc)
1658 ("subepsilon" "SubEpsilon" simula-expand-stdproc)
1659 ("suc" "Suc" simula-expand-stdproc)
1660 ("switch" "SWITCH" simula-expand-keyword)
1661 ("sysin" "SysIn" simula-expand-stdproc)
1662 ("sysout" "SysOut" simula-expand-stdproc)
1663 ("tan" "Tan" simula-expand-stdproc)
1664 ("tanh" "TanH" simula-expand-stdproc)
1665 ("terminate_program" "Terminate_Program" simula-expand-stdproc)
1666 ("terminated" "Terminated" simula-expand-stdproc)
1667 ("text" "TEXT" simula-expand-keyword)
1668 ("then" "THEN" simula-electric-keyword)
1669 ("this" "THIS" simula-expand-keyword)
1670 ("time" "Time" simula-expand-stdproc)
1671 ("to" "TO" simula-expand-keyword)
1672 ("true" "TRUE" simula-expand-keyword)
1673 ("uniform" "Uniform" simula-expand-stdproc)
1674 ("unlock" "Unlock" simula-expand-stdproc)
1675 ("until" "UNTIL" simula-expand-keyword)
1676 ("upcase" "Upcase" simula-expand-stdproc)
1677 ("upperbound" "UpperBound" simula-expand-stdproc)
1678 ("value" "VALUE" simula-expand-keyword)
1679 ("virtual" "VIRTUAL" simula-expand-keyword)
1680 ("wait" "Wait" simula-expand-stdproc)
1681 ("when" "WHEN" simula-electric-keyword)
1682 ("while" "WHILE" simula-expand-keyword))))
1683
1684 ;;; Font Lock mode support.
1685 (eval-when-compile
1686 (require 'cl))
1687
1688 ;; SIMULA comments and strings are a mess. If we rely on the syntax table,
1689 ;; then %-comments may be shown incorrectly (and prematurely) ended by a
1690 ;; semicolon, !-comments by a newline and '-strings may screw up the rest of
1691 ;; the buffer. And of course we can't do comment- or end-comments using the
1692 ;; syntax table. We can do everything except end-comments in one fast regexp,
1693 ;; but we aught to do end-comments too, so we need a function. simon@gnu.
1694 (defun simula-match-string-or-comment (limit)
1695 ;; Return t if there is a string or comment before LIMIT.
1696 ;; Matches buffer text so that if (match-string 1) is non-nil, it is the
1697 ;; string. Otherwise, (match-string 0) is non-nil, and is the comment.
1698 (when (re-search-forward
1699 (eval-when-compile
1700 (concat "\\(\"[^\"\n]*\"\\|'\\(.\\|![0-9]+!\\)'\\)\\|"
1701 "\\(\\<end[ \t\n]+\\)\\|"
1702 "^%[ \t].*\\|\\(!\\|\\<comment\\>\\)[^;]*;?"))
1703 limit t)
1704 (when (match-beginning 3)
1705 ;; We've matched an end-comment. Yuck. Find the extent of it.
1706 (set-match-data
1707 (list (point)
1708 (if (re-search-forward "\\<\\(end\\|else\\|when\\|otherwise\\)\\>\\|;"
1709 limit 'move)
1710 (match-beginning 0)
1711 (point)))))
1712 t))
1713
1714 ;;; Hilit mode support.
1715 (if (and (fboundp 'hilit-set-mode-patterns)
1716 (boundp 'hilit-patterns-alist)
1717 (not (assoc 'simula-mode hilit-patterns-alist)))
1718 (hilit-set-mode-patterns
1719 'simula-mode
1720 '(
1721 ("^%\\([ \t\f].*\\)?$" nil comment)
1722 ("^%include\\>" nil include)
1723 ("\"[^\"\n]*\"\\|'.'\\|'![0-9]+!'" nil string)
1724 ("\\<\\(ACTIVATE\\|AFTER\\|AND\\|ARRAY\\|AT\\|BEFORE\\|BEGIN\\|BOOLEAN\\|CHARACTER\\|CLASS\\|DELAY\\|DO\\|ELSE\\|END\\|EQ\\|EQV\\|EXTERNAL\\|FALSE\\|FOR\\|GE\\|GO\\|GOTO\\|GT\\|HIDDEN\\|IF\\|IMP\\|IN\\|INNER\\|INSPECT\\|INTEGER\\|IS\\|LABEL\\|LE\\|LONG\\|LT\\|NAME\\|NE\\|NEW\\|NONE\\|NOT\\|NOTEXT\\|OR\\|OTHERWISE\\|PRIOR\\|PROCEDURE\\|PROTECTED\\|QUA\\|REACTIVATE\\|REAL\\|REF\\|SHORT\\|STEP\\|SWITCH\\|TEXT\\|THEN\\|THIS\\|TO\\|TRUE\\|UNTIL\\|VALUE\\|VIRTUAL\\|WHEN\\|WHILE\\)\\>" nil keyword)
1725 ("!\\|\\<COMMENT\\>" ";" comment))
1726 nil 'case-insensitive))
1727
1728 ;; None of this seems to be used by anything, including hilit19.el. simon@gnu.
1729 ;(setq simula-find-comment-point -1
1730 ; simula-find-comment-context nil)
1731 ;
1732 ;;; function used by hilit19
1733 ;(defun simula-find-next-comment-region (param)
1734 ; "Return region (start end) cons of comment after point, or NIL"
1735 ; (let (start end)
1736 ; ;; This function is called repeatedly, check if point is
1737 ; ;; where we left it in the last call
1738 ; (if (not (eq simula-find-comment-point (point)))
1739 ; (setq simula-find-comment-point (point)
1740 ; simula-find-comment-context (simula-context)))
1741 ; ;; loop as long as we haven't found the end of a comment
1742 ; (if (memq simula-find-comment-context '(0 1 2))
1743 ; (setq start (point))
1744 ; (if (re-search-forward "\\<end\\>\\|!\\|\"\\|'\\|^%\\|\\<comment\\>"
1745 ; nil 'move)
1746 ; (let ((previous-char (preceding-char)))
1747 ; (cond
1748 ; ((memq previous-char '(?d ?D))
1749 ; (setq start (point)
1750 ; simula-find-comment-context 2))
1751 ; ((memq previous-char '(?t ?T ?\!))
1752 ; (setq start (point)
1753 ; simula-find-comment-context 0))
1754 ; ((eq previous-char ?%)
1755 ; (setq start (point)
1756 ; simula-find-comment-context 0))))))
1757 ; ;; BUG: the following (0 2) branches don't take into account intermixing
1758 ; ;; directive lines
1759 ; (cond
1760 ; ((eq simula-find-comment-context 0)
1761 ; (search-forward ";" nil 'move))
1762 ; ((eq simula-find-comment-context 1)
1763 ; (beginning-of-line 2))
1764 ; ((eq simula-find-comment-context 2)
1765 ; (re-search-forward ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>\\" (point-max) 'move)))
1766 ; (if start
1767 ; (setq end (point)))
1768 ; ;; save point for later calls to this function
1769 ; (setq simula-find-comment-point (if end (point) -1))
1770 ; (and end (cons start end))))
1771 \f
1772 ;; defuns for submitting bug reports
1773
1774 (defconst simula-mode-help-address "simula-mode@ifi.uio.no"
1775 "Address accepting submission of simula-mode bug reports.")
1776
1777 (defun simula-submit-bug-report ()
1778 "Submit via mail a bug report on simula-mode."
1779 (interactive)
1780 (and
1781 (y-or-n-p "Do you want to submit a report on simula-mode? ")
1782 (reporter-submit-bug-report
1783 simula-mode-help-address
1784 (concat "simula-mode from Emacs " emacs-version)
1785 (list
1786 ;; report only the vars that affect indentation
1787 'simula-emacs-features
1788 'simula-indent-level
1789 'simula-substatement-offset
1790 'simula-continued-statement-offset
1791 'simula-label-offset
1792 'simula-if-indent
1793 'simula-inspect-indent
1794 'simula-electric-indent
1795 'simula-abbrev-keyword
1796 'simula-abbrev-stdproc
1797 'simula-abbrev-file
1798 'simula-tab-always-indent
1799 ))))
1800
1801 (provide 'simula)
1802
1803 ;;; simula.el ends here