Blame


1 6c5ab754 2021-11-07 op ;;; a68-mode.el --- Major mode for editing Algol 68 code -*- lexical-binding: t; -*-
2 364d8905 2021-11-07 op
3 364d8905 2021-11-07 op ;; Copyright (C) 2011 Jose E. Marchesi
4 364d8905 2021-11-07 op ;; Copyright (C) 2021 Omar Polo <op@omarpolo.com>
5 364d8905 2021-11-07 op
6 364d8905 2021-11-07 op ;; Author: Jose E. Marchesi
7 364d8905 2021-11-07 op ;; Omar Polo <op@omarpolo.com>
8 364d8905 2021-11-07 op ;; Maintainer: Omar Polo
9 364d8905 2021-11-07 op ;; URL: https://git.omarpolo.com/a68-mode
10 364d8905 2021-11-07 op ;; Keywords: languages
11 364d8905 2021-11-07 op ;; Version: 0
12 364d8905 2021-11-07 op ;; Package-Requires: ((emacs "24.3"))
13 364d8905 2021-11-07 op
14 364d8905 2021-11-07 op ;; This file is NOT part of GNU Emacs.
15 364d8905 2021-11-07 op
16 364d8905 2021-11-07 op ;; This program is free software; you can redistribute it and/or modify
17 364d8905 2021-11-07 op ;; it under the terms of the GNU General Public License as published by
18 364d8905 2021-11-07 op ;; the Free Software Foundation; either version 3, or (at your option)
19 364d8905 2021-11-07 op ;; any later version.
20 364d8905 2021-11-07 op
21 364d8905 2021-11-07 op ;; This program is distributed in the hope that it will be useful,
22 364d8905 2021-11-07 op ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 364d8905 2021-11-07 op ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 364d8905 2021-11-07 op ;; GNU General Public License for more details.
25 364d8905 2021-11-07 op
26 364d8905 2021-11-07 op ;; You should have received a copy of the GNU General Public License
27 364d8905 2021-11-07 op ;; along with this program; see the file COPYING. If not, write to the
28 364d8905 2021-11-07 op ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 364d8905 2021-11-07 op ;; Boston, MA 02110-1301, USA.
30 364d8905 2021-11-07 op
31 364d8905 2021-11-07 op ;;; Commentary:
32 364d8905 2021-11-07 op
33 364d8905 2021-11-07 op ;; A major mode for editing Algol 68 code.
34 364d8905 2021-11-07 op ;;
35 bb4b3a62 2021-11-07 op ;; This is an improved and modernized version of the a68-mode written
36 bb4b3a62 2021-11-07 op ;; by Jose E. Marchesi. The original code was taken from
37 bb4b3a62 2021-11-07 op ;;
38 bb4b3a62 2021-11-07 op ;; https://github.com/lachrymology/me/blob/master/.emacs.d/extras/algol-mode.el
39 bb4b3a62 2021-11-07 op ;;
40 364d8905 2021-11-07 op ;; TODO: support quote and dot stropping.
41 364d8905 2021-11-07 op
42 364d8905 2021-11-07 op ;;; Code:
43 364d8905 2021-11-07 op
44 364d8905 2021-11-07 op (require 'font-lock)
45 61b0b383 2021-11-08 op (require 'smie)
46 61b0b383 2021-11-08 op (require 'syntax)
47 364d8905 2021-11-07 op
48 364d8905 2021-11-07 op (eval-when-compile
49 364d8905 2021-11-07 op (require 'rx))
50 364d8905 2021-11-07 op
51 caaad6ea 2021-11-07 op (defgroup a68 nil
52 caaad6ea 2021-11-07 op "Major mode for editing Algol68 code."
53 caaad6ea 2021-11-07 op :prefix "a68-"
54 caaad6ea 2021-11-07 op :group 'languages)
55 364d8905 2021-11-07 op
56 caaad6ea 2021-11-07 op (defcustom a68-indent-level 3
57 caaad6ea 2021-11-07 op "Indentation step for Algol 68."
58 caaad6ea 2021-11-07 op :type 'integer
59 caaad6ea 2021-11-07 op :safe #'integerp)
60 caaad6ea 2021-11-07 op
61 18be0e13 2021-11-07 op (defcustom a68-comment-style "#"
62 29b924fd 2021-11-07 op "Default comment style used by e.g. `comment-dwim'."
63 18be0e13 2021-11-07 op :type '(choice (const "#")
64 18be0e13 2021-11-07 op (const "CO")
65 18be0e13 2021-11-07 op (const "COMMENT"))
66 29b924fd 2021-11-07 op :safe #'consp)
67 29b924fd 2021-11-07 op
68 364d8905 2021-11-07 op (defvar a68-mode-hook '()
69 364d8905 2021-11-07 op "Hook run when entering Algol68 mode.")
70 364d8905 2021-11-07 op
71 364d8905 2021-11-07 op (defvar a68-mode-map
72 8cd9fb9c 2021-11-07 op (let ((map (make-sparse-keymap)))
73 364d8905 2021-11-07 op (define-key map (kbd "C-j") #'newline-and-indent)
74 61b0b383 2021-11-08 op ;; (define-key map (kbd "RET") #'a68-electric-terminate-line)
75 364d8905 2021-11-07 op map)
76 364d8905 2021-11-07 op "Keymap for Algol 68 major mode.")
77 364d8905 2021-11-07 op
78 364d8905 2021-11-07 op (defconst a68-font-lock-keywords
79 364d8905 2021-11-07 op (list
80 364d8905 2021-11-07 op (cons (rx word-start
81 364d8905 2021-11-07 op (or "DECS" "PROGRAM" "CONTEXT" "USE" "FINISH" "KEEP"
82 364d8905 2021-11-07 op "ALIEN"
83 364d8905 2021-11-07 op "MODE" "OP" "PRIO" "PROC"
84 364d8905 2021-11-07 op "OF" "AT" "IS" "ISNT" "EMPTY" "SKIP"
85 364d8905 2021-11-07 op "PR" "PRAGMAT"
86 364d8905 2021-11-07 op "CASE" "IN" "OUSE" "OUT" "ESAC"
87 364d8905 2021-11-07 op "FOR" "FORALL" "FROM" "TO" "BY" "WHILE" "DO" "OD"
88 364d8905 2021-11-07 op "IF" "THEN" "ELIF" "THEN" "ELSE" "FI"
89 364d8905 2021-11-07 op "PAR" "BEGIN" "END" "GOTO" "EXIT"
90 364d8905 2021-11-07 op "LWB" "UPB" "NOT" "ABS" "BIN" "REPR" "LENG"
91 364d8905 2021-11-07 op "SHORTEN" "ODD" "SIGN" "ROUND" "ENTIER" "AND" "OR"
92 364d8905 2021-11-07 op "DIV" "OVER" "MOD" "ELEM" "SHL" "SHR" "OVERAB" "DIVAB" "MODAB"
93 364d8905 2021-11-07 op "REF")
94 364d8905 2021-11-07 op word-end)
95 364d8905 2021-11-07 op 'font-lock-keyword-face)
96 364d8905 2021-11-07 op (cons (rx word-start
97 364d8905 2021-11-07 op (or "TRUE" "FALSE")
98 364d8905 2021-11-07 op word-end)
99 364d8905 2021-11-07 op 'font-lock-constant-face)
100 364d8905 2021-11-07 op ;; only valid for bold stropping
101 364d8905 2021-11-07 op (cons (concat "\\<[A-Z]+\\>") 'font-lock-type-face)
102 364d8905 2021-11-07 op (cons "\\('\\w*'\\)"
103 364d8905 2021-11-07 op 'font-lock-variable-name-face))
104 364d8905 2021-11-07 op "Highlighting expressions for Algol 68 mode.")
105 364d8905 2021-11-07 op
106 61b0b383 2021-11-08 op (defvar a68--keywords-regexp
107 b18a7d7e 2021-11-08 op (regexp-opt '("+" "*" ";" ">" "<" ":=" "=" "," ":")))
108 364d8905 2021-11-07 op
109 61b0b383 2021-11-08 op (defvar a68--smie-grammar
110 61b0b383 2021-11-08 op (smie-prec2->grammar
111 61b0b383 2021-11-08 op (smie-bnf->prec2 '((id)
112 1e3d4762 2021-11-18 op (ids (id "-anchor-" id))
113 1e3d4762 2021-11-18 op (fields (fields "," fields)
114 1e3d4762 2021-11-18 op (ids))
115 1e3d4762 2021-11-18 op (args ("(" fargs ")"))
116 1e3d4762 2021-11-18 op (fargs (fargs "," fargs)
117 1e3d4762 2021-11-18 op (exp))
118 1e3d4762 2021-11-18 op (exp (ids)
119 1e3d4762 2021-11-18 op (exp "OF" exp)
120 1e3d4762 2021-11-18 op (exp "[" exp "]")
121 1e3d4762 2021-11-18 op ("(" exp ")")
122 1e3d4762 2021-11-18 op ("BEGIN" exp "END"))
123 1e3d4762 2021-11-18 op (type-decl ("MODE" type-decl*))
124 1e3d4762 2021-11-18 op (type-decl* (type-decl* "," type-decl*)
125 1e3d4762 2021-11-18 op (id "=" type-decl**))
126 1e3d4762 2021-11-18 op (type-decl** ("STRUCT" args)
127 1e3d4762 2021-11-18 op ("UNION" args)
128 1e3d4762 2021-11-18 op ("PROC" args "-archor-" ids))
129 1e3d4762 2021-11-18 op (op-decl (op-decl "," op-decl)
130 1e3d4762 2021-11-18 op ("OP" ids "=" args ids ":" exp))
131 1e3d4762 2021-11-18 op (proc-decl (proc-decl "," proc-decl)
132 1e3d4762 2021-11-18 op ("OP" ids "=" args ids ":" exp)
133 1e3d4762 2021-11-18 op ("PROC" ids "=" ids ":" exp))
134 1e3d4762 2021-11-18 op ;; TODO: this don't cover all the loop
135 1e3d4762 2021-11-18 op ;; possibilities.
136 1e3d4762 2021-11-18 op (loop ("FOR" exp "FROM" exp "TO" exp "BY" exp
137 1e3d4762 2021-11-18 op "DO" exp "OD")
138 1e3d4762 2021-11-18 op ("FOR" exp "FROM" exp "TO" exp
139 1e3d4762 2021-11-18 op "DO" exp "OD")
140 1e3d4762 2021-11-18 op ("FOR" exp "BY" exp "TO" exp
141 1e3d4762 2021-11-18 op "DO" exp "OD")
142 1e3d4762 2021-11-18 op ("-to-" "TO" exp "DO" exp "OD")
143 1e3d4762 2021-11-18 op ("WHILE" exp "DO" exp "OD"))
144 1e3d4762 2021-11-18 op (insts (insts ";" insts)
145 1e3d4762 2021-11-18 op (id ":=" exp)
146 1e3d4762 2021-11-18 op ("IF" exp "THEN" insts "FI")
147 1e3d4762 2021-11-18 op ("IF" exp "THEN" insts "ELSE" insts "FI")
148 1e3d4762 2021-11-18 op ("IF" exp "THEN" insts
149 1e3d4762 2021-11-18 op "ELSIF" exp "THEN" insts "ELSE" insts "FI")
150 1e3d4762 2021-11-18 op ("IF" exp "THEN" insts
151 1e3d4762 2021-11-18 op "ELSIF" exp "THEN" insts
152 1e3d4762 2021-11-18 op "ELSIF" exp "THEN" insts "ELSE" insts "FI")
153 1e3d4762 2021-11-18 op ;; TODO OUSE for both case and conformity case
154 1e3d4762 2021-11-18 op ("CASE" exp "IN" fargs "ESAC")
155 1e3d4762 2021-11-18 op ("CASE" exp "IN" conformity-cases "ESAC")
156 1e3d4762 2021-11-18 op ("CASE" exp "IN" fargs "OUT" exp "ESAC")
157 1e3d4762 2021-11-18 op (op-decl)
158 1e3d4762 2021-11-18 op (type-decl)
159 1e3d4762 2021-11-18 op (proc-decl)
160 1e3d4762 2021-11-18 op (loop)))
161 1e3d4762 2021-11-18 op '((assoc "OF" "[")
162 1e3d4762 2021-11-18 op (assoc ";")
163 1e3d4762 2021-11-18 op (assoc "|" "|:")
164 1e3d4762 2021-11-18 op (assoc ","))
165 1e3d4762 2021-11-18 op '((assoc "=" "/" ":=" ":=:" ":/=:"
166 d3cc027d 2021-11-08 op "+" "-" "*" "/")))))
167 364d8905 2021-11-07 op
168 61b0b383 2021-11-08 op (defun a68--smie-rules (kind token)
169 61b0b383 2021-11-08 op (pcase (cons kind token)
170 61b0b383 2021-11-08 op (`(:elem . basic) a68-indent-level)
171 61b0b383 2021-11-08 op ;; (`(,_ . ",") (smie-rule-separator kind))
172 61b0b383 2021-11-08 op (`(,_ . ",") (smie-rule-separator kind))
173 61b0b383 2021-11-08 op (`(,_ . ";") (when (smie-rule-parent-p)
174 61b0b383 2021-11-08 op (smie-rule-parent)))
175 61b0b383 2021-11-08 op (`(:after . ":=") a68-indent-level)
176 61b0b383 2021-11-08 op (`(:after . "=") a68-indent-level)
177 61b0b383 2021-11-08 op (`(:before . ,(or `"BEGIN" '"(")) (when (smie-rule-hanging-p)
178 61b0b383 2021-11-08 op (smie-rule-parent)))
179 61b0b383 2021-11-08 op (`(:before . "IF")
180 61b0b383 2021-11-08 op (and (not (smie-rule-bolp))
181 61b0b383 2021-11-08 op (smie-rule-prev-p "ELSE")
182 61b0b383 2021-11-08 op (smie-rule-parent)))))
183 61b0b383 2021-11-08 op
184 61b0b383 2021-11-08 op (defun a68--smie-forward-token ()
185 61b0b383 2021-11-08 op (forward-comment (point-max))
186 61b0b383 2021-11-08 op (cond
187 61b0b383 2021-11-08 op ((looking-at a68--keywords-regexp)
188 61b0b383 2021-11-08 op (goto-char (match-end 0))
189 61b0b383 2021-11-08 op (match-string-no-properties 0))
190 61b0b383 2021-11-08 op (t (buffer-substring-no-properties (point)
191 61b0b383 2021-11-08 op (progn (skip-syntax-forward "w_")
192 61b0b383 2021-11-08 op (point))))))
193 61b0b383 2021-11-08 op
194 61b0b383 2021-11-08 op (defun a68--smie-backward-token ()
195 61b0b383 2021-11-08 op (forward-comment (- (point)))
196 61b0b383 2021-11-08 op (cond
197 61b0b383 2021-11-08 op ((looking-back a68--keywords-regexp (- (point) 2) t)
198 61b0b383 2021-11-08 op (goto-char (match-beginning 0))
199 61b0b383 2021-11-08 op (match-string-no-properties 0))
200 61b0b383 2021-11-08 op (t (buffer-substring-no-properties (point)
201 61b0b383 2021-11-08 op (progn (skip-syntax-backward "w_")
202 61b0b383 2021-11-08 op (point))))))
203 61b0b383 2021-11-08 op
204 364d8905 2021-11-07 op (defvar a68-mode-syntax-table
205 364d8905 2021-11-07 op (let ((st (make-syntax-table)))
206 364d8905 2021-11-07 op (modify-syntax-entry ?# "<" st)
207 364d8905 2021-11-07 op (modify-syntax-entry ?# ">" st)
208 364d8905 2021-11-07 op (modify-syntax-entry ?\\ "." st)
209 0effda17 2021-11-08 op (modify-syntax-entry ?, "." st)
210 b18a7d7e 2021-11-08 op (modify-syntax-entry ?: "." st)
211 364d8905 2021-11-07 op ;; define parentheses to match
212 364d8905 2021-11-07 op (modify-syntax-entry ?\( "()" st)
213 364d8905 2021-11-07 op (modify-syntax-entry ?\) ")(" st)
214 364d8905 2021-11-07 op st))
215 364d8905 2021-11-07 op
216 e9c672cf 2021-11-07 op (defvar a68-mode-abbrev-table nil
217 e9c672cf 2021-11-07 op "Abbreviation table used in `a68-mode' buffers.")
218 e9c672cf 2021-11-07 op
219 e9c672cf 2021-11-07 op (define-abbrev-table 'a68-mode-abbrev-table
220 e9c672cf 2021-11-07 op '())
221 e9c672cf 2021-11-07 op
222 364d8905 2021-11-07 op ;;;###autoload
223 364d8905 2021-11-07 op (define-derived-mode a68-mode prog-mode "Algol68"
224 364d8905 2021-11-07 op "Major mode for editing Alogl68 files."
225 e9c672cf 2021-11-07 op :abbrev-table a68-mode-abbrev-table
226 364d8905 2021-11-07 op (setq-local font-lock-defaults '(a68-font-lock-keywords))
227 61b0b383 2021-11-08 op (smie-setup a68--smie-grammar #'a68--smie-rules
228 61b0b383 2021-11-08 op :forward-token #'a68--smie-forward-token
229 61b0b383 2021-11-08 op :backward-token #'a68--smie-backward-token)
230 18be0e13 2021-11-07 op (setq-local comment-start a68-comment-style)
231 18be0e13 2021-11-07 op (setq-local comment-end a68-comment-style)
232 4fcb92ee 2021-11-07 op (setq-local syntax-propertize-function
233 5881861e 2021-11-14 op (syntax-propertize-rules
234 5881861e 2021-11-14 op ((rx (group bow "COMMENT" eow)
235 5881861e 2021-11-14 op (group (*? anychar))
236 5881861e 2021-11-14 op (group bow "COMMENT" eow))
237 5881861e 2021-11-14 op (1 "<")
238 5881861e 2021-11-14 op (3 ">"))
239 5881861e 2021-11-14 op ((rx (group bow "CO" eow)
240 5881861e 2021-11-14 op (group (*? anychar))
241 5881861e 2021-11-14 op (group bow "CO" eow))
242 5881861e 2021-11-14 op (1 "<")
243 5881861e 2021-11-14 op (3 ">"))
244 92d1f34c 2021-11-14 op ;; a comment is # ... #, but I don't want the
245 92d1f34c 2021-11-14 op ;; (eventual) shebang #! to be considered the start of
246 92d1f34c 2021-11-14 op ;; the comment.
247 92d1f34c 2021-11-14 op ((rx (group "#" (not "!"))
248 92d1f34c 2021-11-14 op (group (*? anychar))
249 92d1f34c 2021-11-14 op (group "#"))
250 92d1f34c 2021-11-14 op (1 "<")
251 92d1f34c 2021-11-14 op (3 ">")))))
252 364d8905 2021-11-07 op
253 364d8905 2021-11-07 op ;;;###autoload
254 364d8905 2021-11-07 op (add-to-list 'auto-mode-alist '("\\.a68\\'" . a68-mode))
255 364d8905 2021-11-07 op
256 48415058 2021-11-07 op (provide 'a68-mode)
257 48415058 2021-11-07 op ;;; a68-mode.el ends here