branch: externals/a68-mode
commit a7882c0331c9d879fcdc3453899a3fb8571566ec
Author: Jose E. Marchesi <jose.march...@oracle.com>
Commit: Jose E. Marchesi <jose.march...@oracle.com>

    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))

Reply via email to