commit 7f103319f41ca93eea4df9cb468bd2a00deffb4a from: Omar Polo date: Sat Nov 06 22:10:43 2021 UTC initial import commit - /dev/null commit + 7f103319f41ca93eea4df9cb468bd2a00deffb4a blob - /dev/null blob + b296b3d25f59f37b91fb20c077b9fa6cffe570cf (mode 644) --- /dev/null +++ README.md @@ -0,0 +1,4 @@ +# algol-mode + +This is an improved and modernised version of algol68 mode by Jose +E. Marchesi. blob - /dev/null blob + de67f24bf7bba3a77b2e2caeb4c6db3cb8ea8478 (mode 644) --- /dev/null +++ algol-mode.el @@ -0,0 +1,219 @@ +;;; a68-mode.el --- Major mode for editing Algol 68 code + +;; Copyright (C) 2011 Jose E. Marchesi + +;; Maintainer: Jose E. Marchesi + +;; This file is NOT part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; A major mode for editing Algol 68 code. +;; +;; TODO: support quote and dot stropping. + +;;; Code: + +(require 'syntax) +(require 'font-lock) + +(defvar a68-indent-step 3 + "Indentation step for Algol 68") + +(defvar a68-mode-hook nil) + +(defvar a68-mode-map + (let ((map (make-keymap))) + (define-key map "\C-j" 'newline-and-indent) + (define-key map "\r" 'electric-a68-terminate-line) + (define-key map "\t" 'electric-a68-tab) + map) + "Keymap for Algol 68 major mode") + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.a68\\'" . a68-mode)) + +(defconst a68-font-lock-keywords + (list + (cons (concat "\\<\\(" + "DECS\\|PROGRAM\\|CONTEXT\\|USE\\|FINISH\\|KEEP" + "\\|ALIEN" + "\\|MODE\\|OP\\|PRIO\\|PROC" + "\\|PROC" + "\\|OF\\|AT\\|IS\\|ISNT\\|EMPTY\\|SKIP" + "\\|PR\\|PRAGMAT" + "\\|CASE\\|IN\\|OUSE\\|OUT\\|ESAC\\|" + "\\|FOR\\|FORALL\\|FROM\\|TO\\|BY\\|WHILE\\|DO\\|OD" + "\\|IF\\|THEN\\|ELIF\\|THEN\\|ELSE\\|FI" + "\\|PAR\\|BEGIN\\|END\\|GOTO\\|EXIT" + "\\|LWB\\|UPB\\|NOT\\|ABS\\|BIN\\|REPR\\|LENG\\|SHORTEN\\|ODD\\|SIGN\\|ROUND\\ENTIER" + "\\|AND\\|OR\\|DIV\\|OVER\\|MOD\\|ELEM\\|SHL\\|SHR\\|IS\\|ISNT" + "\\|OVERAB\\|DIVAB\\|MODAB" + "\\|REF" + "\\)\\>") + 'font-lock-keyword-face) + (cons (concat "\\<\\(" + "TRUE\\|\\FALSE" + "\\)\\>") + 'font-lock-constant-face) + ;; Note that the following rule is only valid for bold stropping. + (cons (concat "\\<[A-Z]+\\>") 'font-lock-type-face) + + (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))) + +;; Indentation rules: +;; +;; - If we are at the beginning of the buffer, or looking at some +;; indent-0 content, indent to column 0. +;; +;; - If we are currently at an END, ), FI or OD, then de-indent +;; relative to the previous line. +;; +;; - If we first see and "end line" before our current line, +;; then we should indent our current line to the same indentation as +;; the end line. +;; +;; - If we first see a "start line" like IF, then we need to increase +;; our indentation relative to that start line. +;; +;; - If into a balanced expression, we should indent to the column +;; where the start of the innermost parenthetical group. +;; +;; - If none of the above apply, then do not indent at all. + +(defun a68-indent-line () + "Indent current line as Algol 68 code" + (interactive) + (let ((case-fold-search nil)) + (save-excursion + (beginning-of-line) + (if (nth 1 (syntax-ppss)) ; Check for rule 5 + (let ((offset (save-excursion (goto-char (+ (nth 1 (syntax-ppss)) 1)) + (current-column)))) + (indent-line-to offset)) + (if (or (bobp) ; Check for rule 1 + (looking-at "^[ \t]*\\<\\(KEEP\\|FINISH\\|DECS\\|USE\\|PROGRAM\\)\\>")) + (indent-line-to 0) + (let ((not-indented t) + (prev-indent (current-indentation)) + (begin-indent-re "^[ \t]*\\<\\(PAR\\|BEGIN\\|KEEP\\|IF\\|DO\\|ELSE\\|ELIF\\|THEN\\)") + (deindent-line-re "^[ \t]*\\<\\(END\\|FI\\|OD\\|ELSE\\|ELIF\\)\\>") + (eqindent-line-re "^[ \t]*\\<\\(THEN\\)\\>") + (end-line-re "^[ \t]*\\(END\\|FI\\|OD\\)") + cur-indent) + (if (looking-at eqindent-line-re) + (save-excursion + (forward-line -1) + (setq cur-indent (current-indentation))) + (if (looking-at deindent-line-re) ; Check for rule 2 + (progn + (save-excursion + (forward-line -1) + (setq cur-indent (- (current-indentation) a68-indent-step))) + (if (< cur-indent 0) + (setq cur-indent 0))) + (save-excursion + (while not-indented + (forward-line -1) + (if (looking-at end-line-re) ; Check for rule 3 + (progn + (setq cur-indent (current-indentation)) + (setq not-indented nil)) + ;; Check for rule 4 + (if (looking-at begin-indent-re) + (progn + (setq cur-indent (+ (current-indentation) a68-indent-step)) + (setq not-indented nil)) + (if (bobp) ; Check for rule 5 + (setq not-indented nil)))))))) + (if cur-indent + (indent-line-to cur-indent) + ;; If we didn't see an indentation hint, then allow no + ;; indentation. + (indent-line-to 0))))))) + (when (< (current-column) (current-indentation)) + (move-to-column (current-indentation)))) + +(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) +;; (modify-syntax-entry ?C "< 13" st) +;; (modify-syntax-entry ?O "> 24" st) + ;; define parentheses to match + (modify-syntax-entry ?\( "()" st) + (modify-syntax-entry ?\) ")(" st) + st)) + +;;; +;;; Electric functions +;;; + +(defconst a68-autoindent-lines-re + "\\<\\(BEGIN\\|END\\|ELSE\\|ELIF\\|DO\\|OD\\|CASE\\|ESAC\\|IN\\|OUT\\)\\>") + +(defun electric-a68-terminate-line () + "Terminate line and indent next line." + (interactive) + ;; First, check if current line should be indented + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (if (looking-at a68-autoindent-lines-re) + (a68-indent-line))) + (delete-horizontal-space) ; Removes triling whitespaces + ;; Indent next line if we are not in a string + (let ((in-string (a68-within-string))) + (newline) + (unless in-string + (a68-indent-line)))) + +(defun electric-a68-tab () + "Function called when TAB is pressed in Algol68 mode." + (interactive) + (unless (save-excursion + (beginning-of-line) + (a68-within-string)) + (a68-indent-line))) + +(defun algol-mode () + "Major mode for editing Algol 68 files." + (interactive) + (kill-all-local-variables) + (set-syntax-table a68-mode-syntax-table) + (use-local-map a68-mode-map) + (set (make-local-variable 'font-lock-defaults) + '(a68-font-lock-keywords)) + (set (make-local-variable 'indent-line-function) + 'a68-indent-line) + (setq major-mode 'a68-mode) + (setq mode-name "Algol68") + (run-hooks 'a68-mode-hooks)) + +(provide 'algol-mode)