diff options
| author | Stefan Monnier | 2010-11-11 16:06:15 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2010-11-11 16:06:15 -0500 |
| commit | cbf83ce9f9163ef95b62c778f4d3efa3cc465cfe (patch) | |
| tree | 0afbfc0bbcb18c98499e5683b7823cae82585fd2 | |
| parent | 90639ceacd6842d168bad3a18090a00b8b140c87 (diff) | |
| download | emacs-cbf83ce9f9163ef95b62c778f4d3efa3cc465cfe.tar.gz emacs-cbf83ce9f9163ef95b62c778f4d3efa3cc465cfe.zip | |
* lisp/progmodes/modula2.el: Use SMIE and skeleton.
(m2-mode-syntax-table): (*..*) can be nested.
Add //...\n. Fix paren syntax.
(m2-mode-map): Remove LF and TAB bindings.
(m2-indent): Add safety property.
(m2-smie-grammar): New var.
(m2-smie-refine-colon, m2-smie-refine-of, m2-smie-backward-token)
(m2-smie-forward-token, m2-smie-refine-semi, m2-smie-rules): New funs.
(m2-mode): Use define-derived-mode.
(m2-newline, m2-tab): Remove.
(m2-begin, m2-case, m2-definition, m2-else, m2-for, m2-header)
(m2-if, m2-loop, m2-module, m2-or, m2-procedure, m2-with, m2-record)
(m2-stdio, m2-type, m2-until, m2-var, m2-while, m2-export)
(m2-import): Use define-skeleton.
* test/indent/modula2.mod: New file.
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | lisp/ChangeLog | 21 | ||||
| -rw-r--r-- | lisp/progmodes/modula2.el | 599 | ||||
| -rw-r--r-- | test/ChangeLog | 4 | ||||
| -rw-r--r-- | test/indent/modula2.mod | 53 |
5 files changed, 404 insertions, 275 deletions
| @@ -289,6 +289,8 @@ set `x-select-enable-clipboard' to nil. | |||
| 289 | 289 | ||
| 290 | * Changes in Specialized Modes and Packages in Emacs 24.1 | 290 | * Changes in Specialized Modes and Packages in Emacs 24.1 |
| 291 | 291 | ||
| 292 | ** Modula-2 mode provides auto-indentation. | ||
| 293 | |||
| 292 | ** latex-electric-env-pair-mode keeps \begin..\end matched on the fly. | 294 | ** latex-electric-env-pair-mode keeps \begin..\end matched on the fly. |
| 293 | 295 | ||
| 294 | ** FIXME: xdg-open for browse-url and reportbug, 2010/08. | 296 | ** FIXME: xdg-open for browse-url and reportbug, 2010/08. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 5ba650c43b0..70452c73254 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,20 @@ | |||
| 1 | 2010-11-11 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * progmodes/modula2.el: Use SMIE and skeleton. | ||
| 4 | (m2-mode-syntax-table): (*..*) can be nested. | ||
| 5 | Add //...\n. Fix paren syntax. | ||
| 6 | (m2-mode-map): Remove LF and TAB bindings. | ||
| 7 | (m2-indent): Add safety property. | ||
| 8 | (m2-smie-grammar): New var. | ||
| 9 | (m2-smie-refine-colon, m2-smie-refine-of, m2-smie-backward-token) | ||
| 10 | (m2-smie-forward-token, m2-smie-refine-semi, m2-smie-rules): New funs. | ||
| 11 | (m2-mode): Use define-derived-mode. | ||
| 12 | (m2-newline, m2-tab): Remove. | ||
| 13 | (m2-begin, m2-case, m2-definition, m2-else, m2-for, m2-header) | ||
| 14 | (m2-if, m2-loop, m2-module, m2-or, m2-procedure, m2-with, m2-record) | ||
| 15 | (m2-stdio, m2-type, m2-until, m2-var, m2-while, m2-export) | ||
| 16 | (m2-import): Use define-skeleton. | ||
| 17 | |||
| 1 | 2010-11-11 Glenn Morris <rgm@gnu.org> | 18 | 2010-11-11 Glenn Morris <rgm@gnu.org> |
| 2 | 19 | ||
| 3 | * obsolete/lucid.el: Don't warn about any CL functions in this file. | 20 | * obsolete/lucid.el: Don't warn about any CL functions in this file. |
| @@ -37,8 +54,8 @@ | |||
| 37 | 54 | ||
| 38 | 2010-11-10 Chong Yidong <cyd@stupidchicken.com> | 55 | 2010-11-10 Chong Yidong <cyd@stupidchicken.com> |
| 39 | 56 | ||
| 40 | * emacs-lisp/package.el (package-read-all-archive-contents): Reset | 57 | * emacs-lisp/package.el (package-read-all-archive-contents): |
| 41 | package-archive-contents to nil before re-reading. | 58 | Reset package-archive-contents to nil before re-reading. |
| 42 | 59 | ||
| 43 | 2010-11-10 Brandon Craig Rhodes <brandon@rhodesmill.org> | 60 | 2010-11-10 Brandon Craig Rhodes <brandon@rhodesmill.org> |
| 44 | 61 | ||
diff --git a/lisp/progmodes/modula2.el b/lisp/progmodes/modula2.el index 3d2af5e217e..c6ab5347065 100644 --- a/lisp/progmodes/modula2.el +++ b/lisp/progmodes/modula2.el | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | 22 | ||
| 23 | ;;; Code: | 23 | ;;; Code: |
| 24 | 24 | ||
| 25 | (require 'smie) | ||
| 26 | |||
| 25 | (defgroup modula2 nil | 27 | (defgroup modula2 nil |
| 26 | "Major mode for editing Modula-2 code." | 28 | "Major mode for editing Modula-2 code." |
| 27 | :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) | 29 | :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) |
| @@ -29,7 +31,22 @@ | |||
| 29 | :group 'languages) | 31 | :group 'languages) |
| 30 | 32 | ||
| 31 | ;;; Added by Tom Perrine (TEP) | 33 | ;;; Added by Tom Perrine (TEP) |
| 32 | (defvar m2-mode-syntax-table nil | 34 | (defvar m2-mode-syntax-table |
| 35 | (let ((table (make-syntax-table))) | ||
| 36 | (modify-syntax-entry ?\\ "\\" table) | ||
| 37 | (modify-syntax-entry ?/ ". 12" table) | ||
| 38 | (modify-syntax-entry ?\n ">" table) | ||
| 39 | (modify-syntax-entry ?\( "()1" table) | ||
| 40 | (modify-syntax-entry ?\) ")(4" table) | ||
| 41 | (modify-syntax-entry ?* ". 23nb" table) | ||
| 42 | (modify-syntax-entry ?+ "." table) | ||
| 43 | (modify-syntax-entry ?- "." table) | ||
| 44 | (modify-syntax-entry ?= "." table) | ||
| 45 | (modify-syntax-entry ?% "." table) | ||
| 46 | (modify-syntax-entry ?< "." table) | ||
| 47 | (modify-syntax-entry ?> "." table) | ||
| 48 | (modify-syntax-entry ?\' "\"" table) | ||
| 49 | table) | ||
| 33 | "Syntax table in use in Modula-2 buffers.") | 50 | "Syntax table in use in Modula-2 buffers.") |
| 34 | 51 | ||
| 35 | (defcustom m2-compile-command "m2c" | 52 | (defcustom m2-compile-command "m2c" |
| @@ -52,26 +69,10 @@ | |||
| 52 | :type 'integer | 69 | :type 'integer |
| 53 | :group 'modula2) | 70 | :group 'modula2) |
| 54 | 71 | ||
| 55 | (if m2-mode-syntax-table | ||
| 56 | () | ||
| 57 | (let ((table (make-syntax-table))) | ||
| 58 | (modify-syntax-entry ?\\ "\\" table) | ||
| 59 | (modify-syntax-entry ?\( ". 1" table) | ||
| 60 | (modify-syntax-entry ?\) ". 4" table) | ||
| 61 | (modify-syntax-entry ?* ". 23" table) | ||
| 62 | (modify-syntax-entry ?+ "." table) | ||
| 63 | (modify-syntax-entry ?- "." table) | ||
| 64 | (modify-syntax-entry ?= "." table) | ||
| 65 | (modify-syntax-entry ?% "." table) | ||
| 66 | (modify-syntax-entry ?< "." table) | ||
| 67 | (modify-syntax-entry ?> "." table) | ||
| 68 | (modify-syntax-entry ?\' "\"" table) | ||
| 69 | (setq m2-mode-syntax-table table))) | ||
| 70 | |||
| 71 | ;;; Added by TEP | 72 | ;;; Added by TEP |
| 72 | (defvar m2-mode-map | 73 | (defvar m2-mode-map |
| 73 | (let ((map (make-sparse-keymap))) | 74 | (let ((map (make-sparse-keymap))) |
| 74 | (define-key map "\^i" 'm2-tab) | 75 | ;; FIXME: Many of those bindings are contrary to coding conventions. |
| 75 | (define-key map "\C-cb" 'm2-begin) | 76 | (define-key map "\C-cb" 'm2-begin) |
| 76 | (define-key map "\C-cc" 'm2-case) | 77 | (define-key map "\C-cc" 'm2-case) |
| 77 | (define-key map "\C-cd" 'm2-definition) | 78 | (define-key map "\C-cd" 'm2-definition) |
| @@ -94,7 +95,6 @@ | |||
| 94 | (define-key map "\C-cy" 'm2-import) | 95 | (define-key map "\C-cy" 'm2-import) |
| 95 | (define-key map "\C-c{" 'm2-begin-comment) | 96 | (define-key map "\C-c{" 'm2-begin-comment) |
| 96 | (define-key map "\C-c}" 'm2-end-comment) | 97 | (define-key map "\C-c}" 'm2-end-comment) |
| 97 | (define-key map "\C-j" 'm2-newline) | ||
| 98 | (define-key map "\C-c\C-z" 'suspend-emacs) | 98 | (define-key map "\C-c\C-z" 'suspend-emacs) |
| 99 | (define-key map "\C-c\C-v" 'm2-visit) | 99 | (define-key map "\C-c\C-v" 'm2-visit) |
| 100 | (define-key map "\C-c\C-t" 'm2-toggle) | 100 | (define-key map "\C-c\C-t" 'm2-toggle) |
| @@ -107,9 +107,185 @@ | |||
| 107 | "*This variable gives the indentation in Modula-2-Mode." | 107 | "*This variable gives the indentation in Modula-2-Mode." |
| 108 | :type 'integer | 108 | :type 'integer |
| 109 | :group 'modula2) | 109 | :group 'modula2) |
| 110 | (put 'm2-indent 'safe-local-variable | ||
| 111 | (lambda (v) (or (null v) (integerp v)))) | ||
| 112 | |||
| 113 | (defconst m2-smie-grammar | ||
| 114 | ;; An official definition can be found as "M2R10.pdf". This grammar does | ||
| 115 | ;; not really follow it, for lots of technical reasons, but it can still be | ||
| 116 | ;; useful to refer to it. | ||
| 117 | (smie-prec2->grammar | ||
| 118 | (smie-merge-prec2s | ||
| 119 | (smie-bnf->prec2 | ||
| 120 | '((range) (id) (epsilon) | ||
| 121 | (fields (fields ";" fields) (ids ":" type)) | ||
| 122 | (proctype (id ":" type)) | ||
| 123 | (type ("RECORD" fields "END") | ||
| 124 | ("POINTER" "TO" type) | ||
| 125 | ;; The PROCEDURE type is indistinguishable from the beginning | ||
| 126 | ;; of a PROCEDURE definition, so we need a "PROCEDURE-type" to | ||
| 127 | ;; prevent SMIE from trying to find the matching END. | ||
| 128 | ("PROCEDURE-type" proctype) | ||
| 129 | ;; OF's right hand side should bind tighter than ; for array | ||
| 130 | ;; types, but should bind less tight than | which itself binds | ||
| 131 | ;; less tight than ;. So we use two distinct OFs. | ||
| 132 | ("SET" "OF-type" id) | ||
| 133 | ("ARRAY" range "OF-type" type)) | ||
| 134 | (args ("(" fargs ")")) | ||
| 135 | ;; VAR has lower precedence than ";" in formal args, but not | ||
| 136 | ;; in declarations. So we use "VAR-arg" for the formal arg case. | ||
| 137 | (farg (ids ":" type) ("CONST-arg" farg) ("VAR-arg" farg)) | ||
| 138 | (fargs (fargs ";" fargs) (farg)) | ||
| 139 | ;; Handling of PROCEDURE in decls is problematic: we'd want | ||
| 140 | ;; TYPE/CONST/VAR/PROCEDURE's parent to be any previous | ||
| 141 | ;; CONST/TYPE/VAR/PROCEDURE, but we also want PROCEDURE to be an opener | ||
| 142 | ;; (so that its END has PROCEDURE as its parent). So instead, we treat | ||
| 143 | ;; the last ";" in those blocks as a separator (we call it ";-block"). | ||
| 144 | ;; FIXME: This means that "TYPE \n VAR" is not indented properly | ||
| 145 | ;; because there's no ";-block" between the two. | ||
| 146 | (decls (decls ";-block" decls) | ||
| 147 | ("TYPE" typedecls) ("CONST" constdecls) ("VAR" vardecls) | ||
| 148 | ;; END is usually a closer, but not quite for PROCEDURE...END. | ||
| 149 | ;; We could use "END-proc" for the procedure case, but | ||
| 150 | ;; I preferred to just pretend PROCEDURE's END is the closer. | ||
| 151 | ("PROCEDURE" decls "BEGIN" insts "END") ;END-proc id | ||
| 152 | ("PROCEDURE" decls "BEGIN" insts "FINALLY" insts "END") | ||
| 153 | ("PROCEDURE" decls "FORWARD") | ||
| 154 | ;; ("IMPLEMENTATION" epsilon "MODULE" decls | ||
| 155 | ;; "BEGIN" insts "FINALLY" insts "END") | ||
| 156 | ) | ||
| 157 | (typedecls (typedecls ";" typedecls) (id "=" type)) | ||
| 158 | (ids (ids "," ids)) | ||
| 159 | (vardecls (vardecls ";" vardecls) (ids ":" type)) | ||
| 160 | (constdecls (constdecls ";" constdecls) (id "=" exp)) | ||
| 161 | (exp (id "-anchor-" id) ("(" exp ")")) | ||
| 162 | (caselabel (caselabel ".." caselabel) (caselabel "," caselabel)) | ||
| 163 | ;; : for types binds tighter than ;, but the : for case labels binds | ||
| 164 | ;; less tight, so have to use two different :. | ||
| 165 | (cases (cases "|" cases) (caselabel ":-case" insts)) | ||
| 166 | (forspec (exp "TO" exp)) | ||
| 167 | (insts (insts ";" insts) | ||
| 168 | (id ":=" exp) | ||
| 169 | ("CASE" exp "OF" cases "END") | ||
| 170 | ("CASE" exp "OF" cases "ELSE" insts "END") | ||
| 171 | ("LOOP" insts "END") | ||
| 172 | ("WITH" exp "DO" insts "END") | ||
| 173 | ("REPEAT" insts "UNTIL" exp) | ||
| 174 | ("WHILE" exp "DO" insts "END") | ||
| 175 | ("FOR" forspec "DO" insts "END") | ||
| 176 | ("IF" exp "THEN" insts "END") | ||
| 177 | ("IF" exp "THEN" insts "ELSE" insts "END") | ||
| 178 | ("IF" exp "THEN" insts | ||
| 179 | "ELSIF" exp "THEN" insts "ELSE" insts "END") | ||
| 180 | ("IF" exp "THEN" insts | ||
| 181 | "ELSIF" exp "THEN" insts | ||
| 182 | "ELSIF" exp "THEN" insts "ELSE" insts "END")) | ||
| 183 | ;; This category is not used anywhere, but it adds some constraints that | ||
| 184 | ;; try to reduce the harm when an OF-type is not properly recognized. | ||
| 185 | (error-OF ("ARRAY" range "OF" type) ("SET" "OF" id))) | ||
| 186 | '((assoc ";")) '((assoc ";-block")) '((assoc "|")) | ||
| 187 | ;; For case labels. | ||
| 188 | '((assoc ",") (assoc "..")) | ||
| 189 | ;; '((assoc "TYPE" "CONST" "VAR" "PROCEDURE")) | ||
| 190 | ) | ||
| 191 | (smie-precs->prec2 | ||
| 192 | '((nonassoc "-anchor-" "=") | ||
| 193 | (nonassoc "<" "<=" ">=" ">" "<>" "#" "IN") | ||
| 194 | (assoc "OR" "+" "-") | ||
| 195 | (assoc "AND" "MOD" "DIV" "REM" "*" "/" "&") | ||
| 196 | (nonassoc "NOT" "~") | ||
| 197 | (left "." "^") | ||
| 198 | )) | ||
| 199 | ))) | ||
| 200 | |||
| 201 | (defun m2-smie-refine-colon () | ||
| 202 | (let ((res nil)) | ||
| 203 | (while (not res) | ||
| 204 | (let ((tok (smie-default-backward-token))) | ||
| 205 | (cond | ||
| 206 | ((zerop (length tok)) | ||
| 207 | (let ((forward-sexp-function nil)) | ||
| 208 | (condition-case nil | ||
| 209 | (forward-sexp -1) | ||
| 210 | (scan-error (setq res ":"))))) | ||
| 211 | ((member tok '("|" "OF" "..")) (setq res ":-case")) | ||
| 212 | ((member tok '(":" "END" ";" "BEGIN" "VAR" "RECORD" "PROCEDURE")) | ||
| 213 | (setq res ":"))))) | ||
| 214 | res)) | ||
| 215 | |||
| 216 | (defun m2-smie-refine-of () | ||
| 217 | (let ((tok (smie-default-backward-token))) | ||
| 218 | (when (zerop (length tok)) | ||
| 219 | (let ((forward-sexp-function nil)) | ||
| 220 | (condition-case nil | ||
| 221 | (backward-sexp 1) | ||
| 222 | (scan-error nil)) | ||
| 223 | (setq tok (smie-default-backward-token)))) | ||
| 224 | (if (member tok '("ARRAY" "SET")) | ||
| 225 | "OF-type" "OF"))) | ||
| 226 | |||
| 227 | (defun m2-smie-refine-semi () | ||
| 228 | (forward-comment (point-max)) | ||
| 229 | (if (looking-at (regexp-opt '("PROCEDURE" "TYPE" "VAR" "CONST" "BEGIN"))) | ||
| 230 | ";-block" ";")) | ||
| 231 | |||
| 232 | ;; FIXME: "^." are two tokens, not one. | ||
| 233 | (defun m2-smie-forward-token () | ||
| 234 | (pcase (smie-default-forward-token) | ||
| 235 | (`"VAR" (if (zerop (car (syntax-ppss))) "VAR" "VAR-arg")) | ||
| 236 | (`"CONST" (if (zerop (car (syntax-ppss))) "CONST" "CONST-arg")) | ||
| 237 | (`";" (save-excursion (m2-smie-refine-semi))) | ||
| 238 | (`"OF" (save-excursion (forward-char -2) (m2-smie-refine-of))) | ||
| 239 | (`":" (save-excursion (forward-char -1) (m2-smie-refine-colon))) | ||
| 240 | ;; (`"END" (if (and (looking-at "[ \t\n]*\\(\\(?:\\sw\\|\\s_\\)+\\)") | ||
| 241 | ;; (not (assoc (match-string 1) m2-smie-grammar))) | ||
| 242 | ;; "END-proc" "END")) | ||
| 243 | (token token))) | ||
| 244 | |||
| 245 | (defun m2-smie-backward-token () | ||
| 246 | (pcase (smie-default-backward-token) | ||
| 247 | (`"VAR" (if (zerop (car (syntax-ppss))) "VAR" "VAR-arg")) | ||
| 248 | (`"CONST" (if (zerop (car (syntax-ppss))) "CONST" "CONST-arg")) | ||
| 249 | (`";" (save-excursion (forward-char 1) (m2-smie-refine-semi))) | ||
| 250 | (`"OF" (save-excursion (m2-smie-refine-of))) | ||
| 251 | (`":" (save-excursion (m2-smie-refine-colon))) | ||
| 252 | ;; (`"END" (if (and (looking-at "\\sw+[ \t\n]+\\(\\(?:\\sw\\|\\s_\\)+\\)") | ||
| 253 | ;; (not (assoc (match-string 1) m2-smie-grammar))) | ||
| 254 | ;; "END-proc" "END")) | ||
| 255 | (token token))) | ||
| 256 | |||
| 257 | (defun m2-smie-rules (kind token) | ||
| 258 | ;; FIXME: Apparently, the usual indentation convention is something like: | ||
| 259 | ;; | ||
| 260 | ;; TYPE t1 = bar; | ||
| 261 | ;; VAR x : INTEGER; | ||
| 262 | ;; PROCEDURE f (); | ||
| 263 | ;; TYPE t2 = foo; | ||
| 264 | ;; PROCEDURE g (); | ||
| 265 | ;; BEGIN blabla END; | ||
| 266 | ;; VAR y : type; | ||
| 267 | ;; BEGIN blibli END | ||
| 268 | ;; | ||
| 269 | ;; This is inconsistent with the actual structure of the code in 2 ways: | ||
| 270 | ;; - The inner VAR/TYPE are indented just like the outer VAR/TYPE. | ||
| 271 | ;; - The inner PROCEDURE is not aligned with its VAR/TYPE siblings. | ||
| 272 | (pcase (cons kind token) | ||
| 273 | (`(:elem . basic) m2-indent) | ||
| 274 | (`(:after . ":=") (or m2-indent smie-indent-basic)) | ||
| 275 | (`(:after . ,(or `"CONST" `"VAR" `"TYPE")) | ||
| 276 | (or m2-indent smie-indent-basic)) | ||
| 277 | ;; (`(:before . ,(or `"VAR" `"TYPE" `"CONST")) | ||
| 278 | ;; (if (smie-rule-parent-p "PROCEDURE") 0)) | ||
| 279 | (`(:after . ";-block") | ||
| 280 | (if (smie-rule-parent-p "PROCEDURE") | ||
| 281 | (smie-rule-parent (or m2-indent smie-indent-basic)))) | ||
| 282 | (`(:before . "|") (smie-rule-separator kind)) | ||
| 283 | )) | ||
| 110 | 284 | ||
| 111 | ;;;###autoload | 285 | ;;;###autoload |
| 112 | (defun modula-2-mode () | 286 | (defalias 'modula-2-mode 'm2-mode) |
| 287 | ;;;###autoload | ||
| 288 | (define-derived-mode m2-mode prog-mode "Modula-2" | ||
| 113 | "This is a mode intended to support program development in Modula-2. | 289 | "This is a mode intended to support program development in Modula-2. |
| 114 | All control constructs of Modula-2 can be reached by typing C-c | 290 | All control constructs of Modula-2 can be reached by typing C-c |
| 115 | followed by the first character of the construct. | 291 | followed by the first character of the construct. |
| @@ -132,46 +308,23 @@ followed by the first character of the construct. | |||
| 132 | `m2-indent' controls the number of spaces for each indentation. | 308 | `m2-indent' controls the number of spaces for each indentation. |
| 133 | `m2-compile-command' holds the command to compile a Modula-2 program. | 309 | `m2-compile-command' holds the command to compile a Modula-2 program. |
| 134 | `m2-link-command' holds the command to link a Modula-2 program." | 310 | `m2-link-command' holds the command to link a Modula-2 program." |
| 135 | (interactive) | ||
| 136 | (kill-all-local-variables) | ||
| 137 | (use-local-map m2-mode-map) | ||
| 138 | (setq major-mode 'modula-2-mode) | ||
| 139 | (setq mode-name "Modula-2") | ||
| 140 | (make-local-variable 'comment-column) | ||
| 141 | (setq comment-column 41) | ||
| 142 | (make-local-variable 'm2-end-comment-column) | 311 | (make-local-variable 'm2-end-comment-column) |
| 143 | (set-syntax-table m2-mode-syntax-table) | 312 | |
| 144 | (make-local-variable 'paragraph-start) | 313 | (set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter)) |
| 145 | (setq paragraph-start (concat "$\\|" page-delimiter)) | 314 | (set (make-local-variable 'paragraph-separate) paragraph-start) |
| 146 | (make-local-variable 'paragraph-separate) | 315 | (set (make-local-variable 'paragraph-ignore-fill-prefix) t) |
| 147 | (setq paragraph-separate paragraph-start) | 316 | (set (make-local-variable 'comment-start) "(* ") |
| 148 | (make-local-variable 'paragraph-ignore-fill-prefix) | 317 | (set (make-local-variable 'comment-end) " *)") |
| 149 | (setq paragraph-ignore-fill-prefix t) | 318 | (set (make-local-variable 'comment-start-skip) "\\(?:(\\*+\\|//+\\) *") |
| 150 | ; (make-local-variable 'indent-line-function) | 319 | (set (make-local-variable 'parse-sexp-ignore-comments) t) |
| 151 | ; (setq indent-line-function 'c-indent-line) | 320 | (set (make-local-variable 'font-lock-defaults) |
| 152 | (make-local-variable 'require-final-newline) | ||
| 153 | (setq require-final-newline mode-require-final-newline) | ||
| 154 | (make-local-variable 'comment-start) | ||
| 155 | (setq comment-start "(* ") | ||
| 156 | (make-local-variable 'comment-end) | ||
| 157 | (setq comment-end " *)") | ||
| 158 | (make-local-variable 'comment-column) | ||
| 159 | (setq comment-column 41) | ||
| 160 | (make-local-variable 'comment-start-skip) | ||
| 161 | (setq comment-start-skip "/\\*+ *") | ||
| 162 | (make-local-variable 'comment-indent-function) | ||
| 163 | (setq comment-indent-function 'c-comment-indent) | ||
| 164 | (make-local-variable 'parse-sexp-ignore-comments) | ||
| 165 | (setq parse-sexp-ignore-comments t) | ||
| 166 | (make-local-variable 'font-lock-defaults) | ||
| 167 | (setq font-lock-defaults | ||
| 168 | '((m3-font-lock-keywords | 321 | '((m3-font-lock-keywords |
| 169 | m3-font-lock-keywords-1 m3-font-lock-keywords-2) | 322 | m3-font-lock-keywords-1 m3-font-lock-keywords-2) |
| 170 | nil nil ((?_ . "w") (?. . "w") (?< . ". 1") (?> . ". 4")) nil | 323 | nil nil ((?_ . "w") (?. . "w") (?< . ". 1") (?> . ". 4")) nil |
| 171 | ;; Obsoleted by Emacs 19.35 parse-partial-sexp's COMMENTSTOP. | ||
| 172 | ;(font-lock-comment-start-regexp . "(\\*") | ||
| 173 | )) | 324 | )) |
| 174 | (run-mode-hooks 'm2-mode-hook)) | 325 | (smie-setup m2-smie-grammar #'m2-smie-rules |
| 326 | :forward-token #'m2-smie-forward-token | ||
| 327 | :backward-token #'m2-smie-backward-token)) | ||
| 175 | 328 | ||
| 176 | ;; Regexps written with help from Ron Forrester <ron@orcad.com> | 329 | ;; Regexps written with help from Ron Forrester <ron@orcad.com> |
| 177 | ;; and Spencer Allain <sallain@teknowledge.com>. | 330 | ;; and Spencer Allain <sallain@teknowledge.com>. |
| @@ -257,231 +410,131 @@ followed by the first character of the construct. | |||
| 257 | (defvar m2-font-lock-keywords m2-font-lock-keywords-1 | 410 | (defvar m2-font-lock-keywords m2-font-lock-keywords-1 |
| 258 | "Default expressions to highlight in Modula-2 modes.") | 411 | "Default expressions to highlight in Modula-2 modes.") |
| 259 | 412 | ||
| 260 | (defun m2-newline () | 413 | (define-skeleton m2-begin |
| 261 | "Insert a newline and indent following line like previous line." | ||
| 262 | (interactive) | ||
| 263 | (let ((hpos (current-indentation))) | ||
| 264 | (newline) | ||
| 265 | (indent-to hpos))) | ||
| 266 | |||
| 267 | (defun m2-tab () | ||
| 268 | "Indent to next tab stop." | ||
| 269 | (interactive) | ||
| 270 | (indent-to (* (1+ (/ (current-indentation) m2-indent)) m2-indent))) | ||
| 271 | |||
| 272 | (defun m2-begin () | ||
| 273 | "Insert a BEGIN keyword and indent for the next line." | 414 | "Insert a BEGIN keyword and indent for the next line." |
| 274 | (interactive) | 415 | nil |
| 275 | (insert "BEGIN") | 416 | \n "BEGIN" > \n) |
| 276 | (m2-newline) | ||
| 277 | (m2-tab)) | ||
| 278 | 417 | ||
| 279 | (defun m2-case () | 418 | (define-skeleton m2-case |
| 280 | "Build skeleton CASE statement, prompting for the <expression>." | 419 | "Build skeleton CASE statement, prompting for the <expression>." |
| 281 | (interactive) | 420 | "Case-Expression: " |
| 282 | (let ((name (read-string "Case-Expression: "))) | 421 | \n "CASE " str " OF" > \n _ \n "END (* " str " *);" > \n) |
| 283 | (insert "CASE " name " OF") | 422 | |
| 284 | (m2-newline) | 423 | (define-skeleton m2-definition |
| 285 | (m2-newline) | ||
| 286 | (insert "END (* case " name " *);")) | ||
| 287 | (end-of-line 0) | ||
| 288 | (m2-tab)) | ||
| 289 | |||
| 290 | (defun m2-definition () | ||
| 291 | "Build skeleton DEFINITION MODULE, prompting for the <module name>." | 424 | "Build skeleton DEFINITION MODULE, prompting for the <module name>." |
| 292 | (interactive) | 425 | "Name: " |
| 293 | (insert "DEFINITION MODULE ") | 426 | \n "DEFINITION MODULE " str ";" > \n \n _ \n \n "END " str "." > \n) |
| 294 | (let ((name (read-string "Name: "))) | ||
| 295 | (insert name ";\n\n\n\nEND " name ".\n")) | ||
| 296 | (forward-line -3)) | ||
| 297 | 427 | ||
| 298 | (defun m2-else () | 428 | (define-skeleton m2-else |
| 299 | "Insert ELSE keyword and indent for next line." | 429 | "Insert ELSE keyword and indent for next line." |
| 300 | (interactive) | 430 | nil |
| 301 | (m2-newline) | 431 | \n "ELSE" > \n) |
| 302 | (backward-delete-char-untabify m2-indent ()) | ||
| 303 | (insert "ELSE") | ||
| 304 | (m2-newline) | ||
| 305 | (m2-tab)) | ||
| 306 | 432 | ||
| 307 | (defun m2-for () | 433 | (define-skeleton m2-for |
| 308 | "Build skeleton FOR loop statement, prompting for the loop parameters." | 434 | "Build skeleton FOR loop statement, prompting for the loop parameters." |
| 309 | (interactive) | 435 | "Loop Initializer: " |
| 310 | (insert "FOR ") | 436 | ;; FIXME: this seems to be lacking a "<var> :=". |
| 311 | (let ((name (read-string "Loop Initializer: ")) limit by) | 437 | \n "FOR " str " TO " |
| 312 | (insert name " TO ") | 438 | (setq v1 (read-string "Limit: ")) |
| 313 | (setq limit (read-string "Limit: ")) | 439 | (let ((by (read-string "Step: "))) |
| 314 | (insert limit) | ||
| 315 | (setq by (read-string "Step: ")) | ||
| 316 | (if (not (string-equal by "")) | 440 | (if (not (string-equal by "")) |
| 317 | (insert " BY " by)) | 441 | (concat " BY " by))) |
| 318 | (insert " DO") | 442 | " DO" > \n _ \n "END (* for " str " to " v1 " *);" > \n) |
| 319 | (m2-newline) | ||
| 320 | (m2-newline) | ||
| 321 | (insert "END (* for " name " to " limit " *);")) | ||
| 322 | (end-of-line 0) | ||
| 323 | (m2-tab)) | ||
| 324 | |||
| 325 | (defun m2-header () | ||
| 326 | "Insert a comment block containing the module title, author, etc." | ||
| 327 | (interactive) | ||
| 328 | (insert "(*\n Title: \t") | ||
| 329 | (insert (read-string "Title: ")) | ||
| 330 | (insert "\n Created:\t") | ||
| 331 | (insert (current-time-string)) | ||
| 332 | (insert "\n Author: \t") | ||
| 333 | (insert (user-full-name)) | ||
| 334 | (insert (concat "\n\t\t<" (user-login-name) "@" (system-name) ">\n")) | ||
| 335 | (insert "*)\n\n")) | ||
| 336 | |||
| 337 | (defun m2-if () | ||
| 338 | "Insert skeleton IF statement, prompting for <boolean-expression>." | ||
| 339 | (interactive) | ||
| 340 | (insert "IF ") | ||
| 341 | (let ((thecondition (read-string "<boolean-expression>: "))) | ||
| 342 | (insert thecondition " THEN") | ||
| 343 | (m2-newline) | ||
| 344 | (m2-newline) | ||
| 345 | (insert "END (* if " thecondition " *);")) | ||
| 346 | (end-of-line 0) | ||
| 347 | (m2-tab)) | ||
| 348 | |||
| 349 | (defun m2-loop () | ||
| 350 | "Build skeleton LOOP (with END)." | ||
| 351 | (interactive) | ||
| 352 | (insert "LOOP") | ||
| 353 | (m2-newline) | ||
| 354 | (m2-newline) | ||
| 355 | (insert "END (* loop *);") | ||
| 356 | (end-of-line 0) | ||
| 357 | (m2-tab)) | ||
| 358 | |||
| 359 | (defun m2-module () | ||
| 360 | "Build skeleton IMPLEMENTATION MODULE, prompting for <module-name>." | ||
| 361 | (interactive) | ||
| 362 | (insert "IMPLEMENTATION MODULE ") | ||
| 363 | (let ((name (read-string "Name: "))) | ||
| 364 | (insert name ";\n\n\n\nEND " name ".\n") | ||
| 365 | (forward-line -3) | ||
| 366 | (m2-header) | ||
| 367 | (m2-type) | ||
| 368 | (newline) | ||
| 369 | (m2-var) | ||
| 370 | (newline) | ||
| 371 | (m2-begin) | ||
| 372 | (m2-begin-comment) | ||
| 373 | (insert " Module " name " Initialisation Code ")) | ||
| 374 | (m2-end-comment) | ||
| 375 | (newline) | ||
| 376 | (m2-tab)) | ||
| 377 | |||
| 378 | (defun m2-or () | ||
| 379 | (interactive) | ||
| 380 | (m2-newline) | ||
| 381 | (backward-delete-char-untabify m2-indent) | ||
| 382 | (insert "|") | ||
| 383 | (m2-newline) | ||
| 384 | (m2-tab)) | ||
| 385 | 443 | ||
| 386 | (defun m2-procedure () | 444 | (define-skeleton m2-header |
| 387 | (interactive) | 445 | "Insert a comment block containing the module title, author, etc." |
| 388 | (insert "PROCEDURE ") | 446 | "Title: " |
| 389 | (let ((name (read-string "Name: " )) | 447 | "(*\n Title: \t" str |
| 390 | args) | 448 | "\n Created: \t" (current-time-string) |
| 391 | (insert name " (") | 449 | "\n Author: \t" (user-full-name) " <" user-mail-address ">\n" |
| 392 | (insert (read-string "Arguments: ") ")") | 450 | "*)" > \n) |
| 393 | (setq args (read-string "Result Type: ")) | ||
| 394 | (if (not (string-equal args "")) | ||
| 395 | (insert " : " args)) | ||
| 396 | (insert ";") | ||
| 397 | (m2-newline) | ||
| 398 | (insert "BEGIN") | ||
| 399 | (m2-newline) | ||
| 400 | (m2-newline) | ||
| 401 | (insert "END ") | ||
| 402 | (insert name) | ||
| 403 | (insert ";") | ||
| 404 | (end-of-line 0) | ||
| 405 | (m2-tab))) | ||
| 406 | |||
| 407 | (defun m2-with () | ||
| 408 | (interactive) | ||
| 409 | (insert "WITH ") | ||
| 410 | (let ((name (read-string "Record-Type: "))) | ||
| 411 | (insert name) | ||
| 412 | (insert " DO") | ||
| 413 | (m2-newline) | ||
| 414 | (m2-newline) | ||
| 415 | (insert "END (* with " name " *);")) | ||
| 416 | (end-of-line 0) | ||
| 417 | (m2-tab)) | ||
| 418 | |||
| 419 | (defun m2-record () | ||
| 420 | (interactive) | ||
| 421 | (insert "RECORD") | ||
| 422 | (m2-newline) | ||
| 423 | (m2-newline) | ||
| 424 | (insert "END (* record *);") | ||
| 425 | (end-of-line 0) | ||
| 426 | (m2-tab)) | ||
| 427 | |||
| 428 | (defun m2-stdio () | ||
| 429 | (interactive) | ||
| 430 | (insert " | ||
| 431 | FROM TextIO IMPORT | ||
| 432 | WriteCHAR, ReadCHAR, WriteINTEGER, ReadINTEGER, | ||
| 433 | WriteCARDINAL, ReadCARDINAL, WriteBOOLEAN, ReadBOOLEAN, | ||
| 434 | WriteREAL, ReadREAL, WriteBITSET, ReadBITSET, | ||
| 435 | WriteBasedCARDINAL, ReadBasedCARDINAL, WriteChars, ReadChars, | ||
| 436 | WriteString, ReadString, WhiteSpace, EndOfLine; | ||
| 437 | |||
| 438 | FROM SysStreams IMPORT sysIn, sysOut, sysErr; | ||
| 439 | |||
| 440 | ")) | ||
| 441 | |||
| 442 | (defun m2-type () | ||
| 443 | (interactive) | ||
| 444 | (insert "TYPE") | ||
| 445 | (m2-newline) | ||
| 446 | (m2-tab)) | ||
| 447 | 451 | ||
| 448 | (defun m2-until () | 452 | (define-skeleton m2-if |
| 449 | (interactive) | 453 | "Insert skeleton IF statement, prompting for <boolean-expression>." |
| 450 | (insert "REPEAT") | 454 | "<boolean-expression>: " |
| 451 | (m2-newline) | 455 | \n "IF " str " THEN" > \n _ \n "END (* if " str " *);" > \n) |
| 452 | (m2-newline) | ||
| 453 | (insert "UNTIL ") | ||
| 454 | (insert (read-string "<boolean-expression>: ") ";") | ||
| 455 | (end-of-line 0) | ||
| 456 | (m2-tab)) | ||
| 457 | |||
| 458 | (defun m2-var () | ||
| 459 | (interactive) | ||
| 460 | (m2-newline) | ||
| 461 | (insert "VAR") | ||
| 462 | (m2-newline) | ||
| 463 | (m2-tab)) | ||
| 464 | 456 | ||
| 465 | (defun m2-while () | 457 | (define-skeleton m2-loop |
| 466 | (interactive) | 458 | "Build skeleton LOOP (with END)." |
| 467 | (insert "WHILE ") | 459 | nil |
| 468 | (let ((name (read-string "<boolean-expression>: "))) | 460 | \n "LOOP" > \n _ \n "END (* loop *);" > \n) |
| 469 | (insert name " DO" ) | ||
| 470 | (m2-newline) | ||
| 471 | (m2-newline) | ||
| 472 | (insert "END (* while " name " *);")) | ||
| 473 | (end-of-line 0) | ||
| 474 | (m2-tab)) | ||
| 475 | |||
| 476 | (defun m2-export () | ||
| 477 | (interactive) | ||
| 478 | (insert "EXPORT QUALIFIED ")) | ||
| 479 | 461 | ||
| 480 | (defun m2-import () | 462 | (define-skeleton m2-module |
| 481 | (interactive) | 463 | "Build skeleton IMPLEMENTATION MODULE, prompting for <module-name>." |
| 482 | (insert "FROM ") | 464 | "Name: " |
| 483 | (insert (read-string "Module: ")) | 465 | \n "IMPLEMENTATION MODULE " str ";" > \n \n |
| 484 | (insert " IMPORT ")) | 466 | '(m2-header) |
| 467 | '(m2-type) \n | ||
| 468 | '(m2-var) \n _ \n \n | ||
| 469 | '(m2-begin) | ||
| 470 | '(m2-begin-comment) | ||
| 471 | " Module " str " Initialisation Code " | ||
| 472 | '(m2-end-comment) | ||
| 473 | \n \n "END " str "." > \n) | ||
| 474 | |||
| 475 | (define-skeleton m2-or | ||
| 476 | "No doc." | ||
| 477 | nil | ||
| 478 | \n "|" > \n) | ||
| 479 | |||
| 480 | (define-skeleton m2-procedure | ||
| 481 | "No doc." | ||
| 482 | "Name: " | ||
| 483 | \n "PROCEDURE " str " (" (read-string "Arguments: ") ")" | ||
| 484 | (let ((args (read-string "Result Type: "))) | ||
| 485 | (if (not (equal args "")) (concat " : " args))) | ||
| 486 | ";" > \n "BEGIN" > \n _ \n "END " str ";" > \n) | ||
| 487 | |||
| 488 | (define-skeleton m2-with | ||
| 489 | "No doc." | ||
| 490 | "Record-Type: " | ||
| 491 | \n "WITH " str " DO" > \n _ \n "END (* with " str " *);" > \n) | ||
| 492 | |||
| 493 | (define-skeleton m2-record | ||
| 494 | "No doc." | ||
| 495 | nil | ||
| 496 | \n "RECORD" > \n _ \n "END (* record *);" > \n) | ||
| 497 | |||
| 498 | (define-skeleton m2-stdio | ||
| 499 | "No doc." | ||
| 500 | nil | ||
| 501 | \n "FROM TextIO IMPORT" | ||
| 502 | > \n "WriteCHAR, ReadCHAR, WriteINTEGER, ReadINTEGER," | ||
| 503 | > \n "WriteCARDINAL, ReadCARDINAL, WriteBOOLEAN, ReadBOOLEAN," | ||
| 504 | > \n "WriteREAL, ReadREAL, WriteBITSET, ReadBITSET," | ||
| 505 | > \n "WriteBasedCARDINAL, ReadBasedCARDINAL, WriteChars, ReadChars," | ||
| 506 | > \n "WriteString, ReadString, WhiteSpace, EndOfLine;" | ||
| 507 | > \n \n "FROM SysStreams IMPORT sysIn, sysOut, sysErr;" > \n \n) | ||
| 508 | |||
| 509 | (define-skeleton m2-type | ||
| 510 | "No doc." | ||
| 511 | nil | ||
| 512 | \n "TYPE" > \n ";" > \n) | ||
| 513 | |||
| 514 | (define-skeleton m2-until | ||
| 515 | "No doc." | ||
| 516 | "<boolean-expression>: " | ||
| 517 | \n "REPEAT" > \n _ \n "UNTIL " str ";" > \n) | ||
| 518 | |||
| 519 | (define-skeleton m2-var | ||
| 520 | "No doc." | ||
| 521 | nil | ||
| 522 | \n "VAR" > \n ";" > \n) | ||
| 523 | |||
| 524 | (define-skeleton m2-while | ||
| 525 | "No doc." | ||
| 526 | "<boolean-expression>: " | ||
| 527 | \n "WHILE " str " DO" > \n _ \n "END (* while " str " *);" > \n) | ||
| 528 | |||
| 529 | (define-skeleton m2-export | ||
| 530 | "No doc." | ||
| 531 | nil | ||
| 532 | \n "EXPORT QUALIFIED " > _ \n) | ||
| 533 | |||
| 534 | (define-skeleton m2-import | ||
| 535 | "No doc." | ||
| 536 | "Module: " | ||
| 537 | \n "FROM " str " IMPORT " > _ \n) | ||
| 485 | 538 | ||
| 486 | (defun m2-begin-comment () | 539 | (defun m2-begin-comment () |
| 487 | (interactive) | 540 | (interactive) |
| @@ -501,15 +554,15 @@ FROM SysStreams IMPORT sysIn, sysOut, sysErr; | |||
| 501 | 554 | ||
| 502 | (defun m2-link () | 555 | (defun m2-link () |
| 503 | (interactive) | 556 | (interactive) |
| 504 | (if m2-link-name | 557 | (compile (concat m2-link-command " " |
| 505 | (compile (concat m2-link-command " " m2-link-name)) | 558 | (or m2-link-name |
| 506 | (compile (concat m2-link-command " " | 559 | (setq m2-link-name (read-string "Name of executable: " |
| 507 | (setq m2-link-name (read-string "Name of executable: " | 560 | (buffer-name))))))) |
| 508 | (buffer-name))))))) | ||
| 509 | 561 | ||
| 510 | (defun m2-execute-monitor-command (command) | 562 | (defun m2-execute-monitor-command (command) |
| 511 | (let* ((shell shell-file-name) | 563 | (let* ((shell shell-file-name) |
| 512 | (csh (equal (file-name-nondirectory shell) "csh"))) | 564 | ;; (csh (equal (file-name-nondirectory shell) "csh")) |
| 565 | ) | ||
| 513 | (call-process shell nil t t "-cf" (concat "exec " command)))) | 566 | (call-process shell nil t t "-cf" (concat "exec " command)))) |
| 514 | 567 | ||
| 515 | (defun m2-visit () | 568 | (defun m2-visit () |
diff --git a/test/ChangeLog b/test/ChangeLog index 5a5c202ad3c..3b1921c5987 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2010-11-11 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * indent/modula2.mod: New file. | ||
| 4 | |||
| 1 | 2010-10-27 Stefan Monnier <monnier@iro.umontreal.ca> | 5 | 2010-10-27 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 6 | ||
| 3 | * indent/octave.m: Add a test to ensure indentation is local. | 7 | * indent/octave.m: Add a test to ensure indentation is local. |
diff --git a/test/indent/modula2.mod b/test/indent/modula2.mod new file mode 100644 index 00000000000..f8fbcb7f4e5 --- /dev/null +++ b/test/indent/modula2.mod | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | (* -*- mode: modula-2; m2-indent:3 -*- *) | ||
| 2 | |||
| 3 | IMPLEMENTATION MODULE Indent ; | ||
| 4 | |||
| 5 | (* This is (* a nested comment *) *) | ||
| 6 | // This is a single-line comment. | ||
| 7 | |||
| 8 | FROM SYSTEM IMPORT ADR, TSIZE, SIZE, WORD ; | ||
| 9 | |||
| 10 | CONST | ||
| 11 | c1 = 2; | ||
| 12 | |||
| 13 | TYPE | ||
| 14 | t = POINTER TO ARRAY [0..10] OF LONGINT; | ||
| 15 | |||
| 16 | VAR x: t; | ||
| 17 | y:LONGINT; | ||
| 18 | |||
| 19 | |||
| 20 | PROCEDURE f1 (f: File) : INTEGER ; | ||
| 21 | VAR | ||
| 22 | fd: FileDescriptor ; | ||
| 23 | PROCEDURE foo (a:CARDINAL) : INTEGER; | ||
| 24 | BEGIN | ||
| 25 | END foo; | ||
| 26 | BEGIN | ||
| 27 | IF f#Error | ||
| 28 | THEN | ||
| 29 | fd := GetIndice(FileInfo, f) ; | ||
| 30 | IF fd#NIL THEN | ||
| 31 | RETURN( fd^.unixfd ) | ||
| 32 | ELSE | ||
| 33 | CASE z OF | ||
| 34 | 1: do1(); | ||
| 35 | | 2: do2(); | ||
| 36 | toto(x); | ||
| 37 | | 3: ; | ||
| 38 | | 4: do4(); | ||
| 39 | ELSE do5(); | ||
| 40 | END ; (* CASE selection *) | ||
| 41 | |||
| 42 | END | ||
| 43 | END ; | ||
| 44 | FormatError1('file %d has not been opened or is out of range\n', f) ; | ||
| 45 | RETURN( -1 ) | ||
| 46 | END f1 ; | ||
| 47 | |||
| 48 | |||
| 49 | BEGIN | ||
| 50 | init | ||
| 51 | FINALLY | ||
| 52 | done | ||
| 53 | END Indent. | ||