branch: externals/a68-mode
commit a7882c0331c9d879fcdc3453899a3fb8571566ec
Author: Jose E. Marchesi <[email protected]>
Commit: Jose E. Marchesi <[email protected]>
Initial support for LAME stropping
---
a68-mode.el | 364 +++++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 277 insertions(+), 87 deletions(-)
diff --git a/a68-mode.el b/a68-mode.el
index fdc27af8ce..c7189d9d86 100644
--- a/a68-mode.el
+++ b/a68-mode.el
@@ -25,13 +25,6 @@
;;; Commentary:
;; A major mode for editing Algol 68 code.
-;;
-;; This is an improved and modernized version of the a68-mode written
-;; by Jose E. Marchesi. The original code was taken from
-;;
-;; https://github.com/lachrymology/me/blob/master/.emacs.d/extras/algol-mode.el
-;;
-;; TODO: support quote and dot stropping.
;;; Code:
@@ -59,6 +52,8 @@
(const "COMMENT"))
:safe #'consp)
+;;;; Stuff common to all stroppings
+
(defvar a68-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-j") #'newline-and-indent)
@@ -67,15 +62,85 @@
map)
"Keymap for Algol 68 major mode.")
-(eval-and-compile
- ;; Both of those vars are used during macroexpansion (and hence compilation).
+(defun a68-within-string ()
+ (nth 3 (syntax-ppss)))
+
+(defun a68-within-comment ()
+ (nth 4 (syntax-ppss)))
+
+(defun a68-within-string-or-comment ()
+ (nth 8 (syntax-ppss)))
+
+(defvar a68--keywords-regexp
+ (regexp-opt '("+" "*" ";" ">" "<" ":=" "=" "," ":")))
+
+(defun a68--smie-forward-token ()
+ (forward-comment (point-max))
+ (cond
+ ((looking-at a68--keywords-regexp)
+ (goto-char (match-end 0))
+ (match-string-no-properties 0))
+ (t (buffer-substring-no-properties (point)
+ (progn (skip-syntax-forward "w_")
+ (point))))))
+
+(defun a68--smie-backward-token ()
+ (forward-comment (- (point)))
+ (cond
+ ((looking-back a68--keywords-regexp (- (point) 2) t)
+ (goto-char (match-beginning 0))
+ (match-string-no-properties 0))
+ (t (buffer-substring-no-properties (point)
+ (progn (skip-syntax-backward "w_")
+ (point))))))
+
+(defvar a68-mode-syntax-table
+ (let ((st (make-syntax-table)))
+ (modify-syntax-entry ?# "<" st)
+ (modify-syntax-entry ?# ">" st)
+ (modify-syntax-entry ?\\ "." st)
+ (modify-syntax-entry ?, "." st)
+ (modify-syntax-entry ?: "." st)
+ ;; define parentheses to match
+ (modify-syntax-entry ?\( "()" st)
+ (modify-syntax-entry ?\) ")(" st)
+ st))
+
+(defvar a68-mode-abbrev-table nil
+ "Abbreviation table used in `a68-mode' buffers.")
+
+(define-abbrev-table 'a68-mode-abbrev-table
+ '())
+
+(defun a68-comment-hash ()
+ "Smart insert a # ... # style comment."
+ (interactive)
+ (if (a68-within-comment)
+ (insert "#")
+ (save-excursion
+ (insert "# #"))
+ (goto-char (+ (point) 2))))
+
+(defun a68--figure-out-stropping-regime ()
+ (save-excursion
+ (goto-char (point-min))
+ (if (let ((case-fold-search nil))
+ (and (re-search-forward "PR LAME PR" nil t)
+ (not (a68-within-comment))
+ (not (a68-within-string))))
+ 'lame
+ 'upper)))
- (defconst a68-std-modes
+;;;; UPPER stropping
+
+(eval-and-compile
+ ;; Those vars are used during macroexpansion (and hence compilation).
+ (defconst a68-std-modes-upper
'("SHORT" "LONG" "INT" "REAL" "BITS" "BYTES"
"COMPL" "STRING" "REF" "FLEX" "VOID")
- "List of Algol 68 standard modes and shortety.")
+ "List of Algol 68 standard modes and shortety in UPPER stropping.")
- (defconst a68-keywords
+ (defconst a68-keywords-upper
'("DECS" "PROGRAM" "CONTEXT" "USE" "KEEP"
"ALIEN" "RE" "IM"
"MODE" "OP" "PRIO" "PROC"
@@ -95,43 +160,30 @@
"NIL" "TRUE" "FALSE"
"MODULE" "DEF" "FED" "POSTLUDE" "ACCESS" "PUB"
"UNSAFE")
- "List of Algol 68 keywords."))
+ "List of Algol 68 keywords in UPPER stropping."))
-(defconst a68-font-lock-keywords
+(defconst a68-font-lock-keywords-upper
(list
(cons (rx word-start
- (eval `(or ,@a68-keywords))
+ (eval `(or ,@a68-keywords-upper))
word-end)
''font-lock-keyword-face)
(cons (rx word-start
- (eval `(or ,@a68-std-modes))
+ (eval `(or ,@a68-std-modes-upper))
word-end)
''font-lock-type-face)
(cons (rx word-start
(or "TRUE" "FALSE")
word-end)
''font-lock-constant-face)
- ;; only valid for bold stropping
'("\\<\\([A-Z]+[A-Z_]*\\>\\)\\(_+\\)?"
(1 'font-lock-type-face)
(2 'font-lock-warning-face nil t))
(cons "\\('\\w*'\\)"
''font-lock-variable-name-face))
- "Highlighting expressions for Algol 68 mode.")
-
-(defun a68-within-string ()
- (nth 3 (syntax-ppss)))
-
-(defun a68-within-comment ()
- (nth 4 (syntax-ppss)))
-
-(defun a68-within-string-or-comment ()
- (nth 8 (syntax-ppss)))
-
-(defvar a68--keywords-regexp
- (regexp-opt '("+" "*" ";" ">" "<" ":=" "=" "," ":")))
+ "Highlighting expressions for Algol 68 mode in UPPER stropping.")
-(defvar a68--smie-grammar
+(defvar a68--smie-grammar-upper
(smie-prec2->grammar
(smie-bnf->prec2 '((id)
(ids (id "-anchor-" id))
@@ -195,7 +247,7 @@
'((assoc "=" "/" ":=" ":=:" ":/=:"
"+" "-" "*" "/")))))
-(defun a68--smie-rules (kind token)
+(defun a68--smie-rules-upper (kind token)
(pcase (cons kind token)
(`(:elem . basic) a68-indent-level)
;; (`(,_ . ",") (smie-rule-separator kind))
@@ -224,67 +276,190 @@
(smie-rule-prev-p "ELSE")
(smie-rule-parent)))))
-(defun a68--smie-forward-token ()
- (forward-comment (point-max))
- (cond
- ((looking-at a68--keywords-regexp)
- (goto-char (match-end 0))
- (match-string-no-properties 0))
- (t (buffer-substring-no-properties (point)
- (progn (skip-syntax-forward "w_")
- (point))))))
+(defun a68-beginning-of-defun-upper (&optional count)
+ "Algol 68 specific `beginning-of-defun-function'."
+ (let ((count (or count 1))
+ (case-fold-search nil)
+ res)
+ (while (> count 0)
+ (goto-char (save-excursion
+ (while (and (re-search-backward (rx bow (or "PROC" "OP")
eow) nil t)
+ (a68-within-string-or-comment)))
+ (setq res (point))))
+ (setq count (1- count )))
+ res))
-(defun a68--smie-backward-token ()
- (forward-comment (- (point)))
- (cond
- ((looking-back a68--keywords-regexp (- (point) 2) t)
- (goto-char (match-beginning 0))
- (match-string-no-properties 0))
- (t (buffer-substring-no-properties (point)
- (progn (skip-syntax-backward "w_")
- (point))))))
+(defun a68-syntax-propertize-function-upper (start end)
+ (let ((case-fold-search nil))
+ (goto-char start)
+ (funcall
+ (syntax-propertize-rules
+ ;; a comment is # ... #, but I don't want the
+ ;; (eventual) shebang #! to be considered the start of
+ ;; the comment.
+ ((rx (group "#" (not "!"))
+ (group (*? anychar))
+ (group "#"))
+ (1 "<")
+ (3 ">"))
+ ((rx bow (group "C") "OMMENT" eow
+ (*? anychar)
+ bow "COMMEN" (group "T") eow)
+ (1 "< b")
+ (2 "> b"))
+ ((rx bow (group "C") "O" eow
+ (*? anychar)
+ bow "C" (group "O") eow)
+ (1 "< c")
+ (2 "> c")))
+ (point) end)))
-(defvar a68-mode-syntax-table
- (let ((st (make-syntax-table)))
- (modify-syntax-entry ?# "<" st)
- (modify-syntax-entry ?# ">" st)
- (modify-syntax-entry ?\\ "." st)
- (modify-syntax-entry ?, "." st)
- (modify-syntax-entry ?: "." st)
- ;; define parentheses to match
- (modify-syntax-entry ?\( "()" st)
- (modify-syntax-entry ?\) ")(" st)
- st))
+;;;; LAME stropping.
-(defvar a68-mode-abbrev-table nil
- "Abbreviation table used in `a68-mode' buffers.")
+(eval-and-compile
+ ;; Those vars are used during macroexpansion (and hence compilation).
+ (defconst a68-std-modes-lame
+ '("int" "real" "bool" "char" "format" "void"
+ "compl" "bits" "bytes" "string" "sema" "file" "channel")
+ "List of Algol 68 standard modes in LAME stropping.")
+
+ (defconst a68-keywords-lame
+ '("true" "false" "empty"
+ "long" "short" "ref" "loc" "heap" "struct" "flex" "proc"
+ "union" "op" "prio" "mode" "begin" "end" "exit" "par" "if"
+ "then" "elif" "else" "fi" "case" "in" "ouse" "out" "esac"
+ "nil" "of" "goto" "skip" "for" "from" "by" "to" "while"
+ "do" "od")
+ "List of Algol 68 keywords in LAME stropping."))
+
+(defconst a68-font-lock-keywords-lame
+ (list
+ (cons (rx word-start
+ (eval `(or ,@a68-keywords-lame))
+ word-end)
+ ''font-lock-keyword-face)
+ (cons (rx word-start
+ (eval `(or ,@a68-std-modes-lame))
+ word-end)
+ ''font-lock-type-face)
+ (cons (rx word-start
+ (or "TRUE" "FALSE")
+ word-end)
+ ''font-lock-constant-face)
+ '("\\<\\([A-Z]+[A-Za-z_]*\\>\\)\\(_+\\)?"
+ (1 'font-lock-type-face)
+ (2 'font-lock-warning-face nil t))
+ (cons "\\('\\w*'\\)"
+ ''font-lock-variable-name-face))
+ "Highlighting expressions for Algol 68 mode in LAME stropping.")
-(define-abbrev-table 'a68-mode-abbrev-table
- '())
+(defvar a68--smie-grammar-lame
+ (smie-prec2->grammar
+ (smie-bnf->prec2 '((id)
+ (ids (id "-anchor-" id))
+ (fields (fields "," fields)
+ (ids))
+ (args ("(" fargs ")"))
+ (fargs (fargs "," fargs)
+ (exp))
+ (conformity-cases)
+ (exp (ids)
+ (exp "of" exp)
+ (exp "[" exp "]")
+ ("(" exp ")")
+ ("begin" exp "end")
+ ("module" exp "def" exp "fed")
+ ("module" exp "def" exp "postlude" exp "fed"))
+ (type-decl ("mode" type-decl*))
+ (type-decl* (type-decl* "," type-decl*)
+ (id "=" type-decl**))
+ (type-decl** ("struct" args)
+ ("union" args)
+ ("proc" args "-archor-" ids))
+ (op-decl (op-decl "," op-decl)
+ ("op" ids "=" args ids ":" exp))
+ (proc-decl (proc-decl "," proc-decl)
+ ("op" ids "=" args ids ":" exp)
+ ("proc" ids "=" ids ":" exp))
+ (program ("program" exp))
+ ;; TODO: this don't cover all the loop
+ ;; possibilities.
+ (loop ("-do-" "do" exp "od")
+ ("for" exp "from" exp "to" exp "by" exp
+ "do" exp "od")
+ ("for" exp "from" exp "to" exp
+ "do" exp "od")
+ ("for" exp "by" exp "to" exp
+ "do" exp "od")
+ ("-to-" "to" exp "do" exp "od")
+ ("while" exp "do" exp "od"))
+ (insts (insts ";" insts)
+ (id ":=" exp)
+ ("if" exp "then" insts "fi")
+ ("if" exp "then" insts "else" insts "fi")
+ ("if" exp "then" insts
+ "elif" exp "then" insts "else" insts "fi")
+ ("if" exp "then" insts
+ "elif" exp "then" insts
+ "elif" exp "then" insts "else" insts "fi")
+ ;; TODO OUSE for both case and conformity case
+ ("case" exp "in" fargs "esac")
+ ("case" exp "in" conformity-cases "esac")
+ ("case" exp "in" fargs "out" exp "esac")
+ (op-decl)
+ (type-decl)
+ (proc-decl)
+ (loop)))
+ '((assoc "of" "[")
+ (assoc ";")
+ (assoc "|" "|:")
+ (assoc ","))
+ '((assoc "=" "/" ":=" ":=:" ":/=:"
+ "+" "-" "*" "/")))))
-(defun a68-comment-hash ()
- "Smart insert a # ... # style comment."
- (interactive)
- (if (a68-within-comment)
- (insert "#")
- (save-excursion
- (insert "# #"))
- (goto-char (+ (point) 2))))
+(defun a68--smie-rules-lame (kind token)
+ (pcase (cons kind token)
+ (`(:elem . basic) a68-indent-level)
+ ;; (`(,_ . ",") (smie-rule-separator kind))
+ (`(,_ . ",") (smie-rule-separator kind))
+ (`(,_ . ";") (when (smie-rule-parent-p)
+ (smie-rule-parent)))
+ (`(:after . ":=") a68-indent-level)
+ (`(:after . "=") a68-indent-level)
+ (`(:before . "begin")
+ (when (or (smie-rule-hanging-p)
+ (or
+ (and (or (smie-rule-parent-p "proc")
+ (smie-rule-parent-p "op"))
+ (smie-rule-prev-p ":"))
+ (smie-rule-parent-p "program")))
+ (smie-rule-parent)))
+ (`(:before . "then")
+ (when (or (smie-rule-hanging-p)
+ (smie-rule-parent-p "if"))
+ (smie-rule-parent)))
+ (`(:before . "(")
+ (when (smie-rule-hanging-p)
+ (smie-rule-parent)))
+ (`(:before . "if")
+ (and (not (smie-rule-bolp))
+ (smie-rule-prev-p "else")
+ (smie-rule-parent)))))
-(defun a68-beginning-of-defun (&optional count)
+(defun a68-beginning-of-defun-lame (&optional count)
"Algol 68 specific `beginning-of-defun-function'."
(let ((count (or count 1))
(case-fold-search nil)
res)
(while (> count 0)
(goto-char (save-excursion
- (while (and (re-search-backward (rx bow (or "PROC" "OP")
eow) nil t)
+ (while (and (re-search-backward (rx bow (or "proc" "op")
eow) nil t)
(a68-within-string-or-comment)))
(setq res (point))))
(setq count (1- count )))
res))
-(defun a68-syntax-propertize-function (start end)
+(defun a68-syntax-propertize-function-lame (start end)
(let ((case-fold-search nil))
(goto-char start)
(funcall
@@ -297,31 +472,46 @@
(group "#"))
(1 "<")
(3 ">"))
- ((rx bow (group "C") "OMMENT" eow
+ ((rx bow (group "c") "omment" eow
(*? anychar)
- bow "COMMEN" (group "T") eow)
+ bow "commen" (group "t") eow)
(1 "< b")
(2 "> b"))
- ((rx bow (group "C") "O" eow
+ ((rx bow (group "c") "o" eow
(*? anychar)
- bow "C" (group "O") eow)
+ bow "c" (group "o") eow)
(1 "< c")
(2 "> c")))
(point) end)))
+;;;; The major mode.
+
;;;###autoload
(define-derived-mode a68-mode prog-mode "Algol68"
"Major mode for editing Alogl68 files."
:abbrev-table a68-mode-abbrev-table
- (setq-local font-lock-defaults '(a68-font-lock-keywords))
- (smie-setup a68--smie-grammar #'a68--smie-rules
- :forward-token #'a68--smie-forward-token
- :backward-token #'a68--smie-backward-token)
+ ;; First determine the stropping regime
+ (setq-local a68--stropping-regime
+ (a68--figure-out-stropping-regime))
+ (if (equal a68--stropping-regime 'lame)
+ ;; LAME stropping.
+ (progn
+ (setq-local font-lock-defaults '(a68-font-lock-keywords-lame))
+ (smie-setup a68--smie-grammar-lame #'a68--smie-rules-lame
+ :forward-token #'a68--smie-forward-token
+ :backward-token #'a68--smie-backward-token)
+ (setq-local beginning-of-defun-function #'a68-beginning-of-defun-lame)
+ (setq-local syntax-propertize-function
#'a68-syntax-propertize-function-lame))
+ ;; UPPER stropping, the default.
+ (setq-local font-lock-defaults '(a68-font-lock-keywords-upper))
+ (smie-setup a68--smie-grammar-upper #'a68--smie-rules-upper
+ :forward-token #'a68--smie-forward-token
+ :backward-token #'a68--smie-backward-token)
+ (setq-local beginning-of-defun-function #'a68-beginning-of-defun-upper)
+ (setq-local syntax-propertize-function
#'a68-syntax-propertize-function-upper))
(add-hook 'after-change-functions #'a68--after-change-function nil t)
(setq-local comment-start a68-comment-style)
- (setq-local comment-end a68-comment-style)
- (setq-local beginning-of-defun-function #'a68-beginning-of-defun)
- (setq-local syntax-propertize-function #'a68-syntax-propertize-function))
+ (setq-local comment-end a68-comment-style))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.a68\\'" . a68-mode))