Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;;;; -*- Mode: Lisp; lexical-binding: t; -*-
- ;;;; web68.el --- major mode for editing Web 68 source
- ;;;; This file contains Web 68 mode.
- ;;;; It is used to colourise Web 68 and Algol 68 files.
- ;;;; Copyright (C) 2014 Sian Mountbatten
- ;;;; Author: Sian Mountbatten <[email protected]>
- ;;;; Keywords: languages
- (defgroup web68 nil
- "Major mode for editing Web 68/Algol 68 source in Emacs."
- :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
- :group 'languages)
- (defvar web68-mode-abbrev-table nil
- "Abbrev table in use in Web68 mode buffers.")
- (define-abbrev-table 'web68-mode-abbrev-table ())
- (defvar web68-mode-map
- (let ((map (make-sparse-keymap)))
- map)
- "Keymap used in Web68 mode.")
- (defvar web68-imenu-generic-expression
- '((nil "^[ \t]*\\(PROC\\|OP\\)[ \t\n]+\\([a-zA-Z0-9_.:]+\\)" 2))
- "Imenu expression for Web68 mode. See `imenu-generic-expression'.")
- (defvar web68-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 ?$ "$" st)
- (modify-syntax-entry ?_ "_" st)
- st)
- "Syntax table in use in Web68-mode buffers.")
- ;;; Define the font lock colours
- (defface *web68-grey*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "#808080"))
- "Used for Web 68 text."
- :group 'web68)
- (defface *web68-red*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "red"))
- "Used for numbers."
- :group 'web68)
- (defface *web68-darkcyan*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "darkCyan"))
- "Used for punctuation."
- :group 'web68)
- (defface *web68-yellow*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "yellow"))
- "Used for strings."
- :group 'web68)
- (defface *web68-brown*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "brown"))
- "Used for comments."
- :group 'web68)
- (defface *web68-magenta*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "magenta"))
- "Used for operators."
- :group 'web68)
- (defface *web68-green*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "green"))
- "Used for dates/delimited text."
- :group 'web68)
- (defface *web68-cyan*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "cyan"))
- "Used for Algol 68 modes and Web 68 commands."
- :group 'web68)
- (defface *web68-blue*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "skyblue"))
- "Used for identifiers."
- :group 'web68)
- (defface *web68-white*
- '((((class color) (min-colors 88) (background dark))
- ;.
- :background "black" :foreground "white"))
- "Used for bold tags."
- :group 'web68)
- ;;;; The next data structure is used to identify a bold tag.
- ;;;; The length of the tag determines which sorted list is used.
- ;;;; The `chop' function then finds the actual position of the
- ;;;; bold tag and, consequently, its face property.
- ;;;;
- ;;;; Define which face is used for each bold tag
- (defconst *web68-bold-tags*
- '(nil
- (("I" *web68-magenta*)) ; length 1
- (("AT" *web68-white*) ; length 2
- ("BY" *web68-white*)
- ("CO" *web68-white*)
- ("DO" *web68-white*)
- ("EQ" *web68-magenta*)
- ("FI" *web68-white*)
- ("GE" *web68-magenta*)
- ("GT" *web68-magenta*)
- ("IF" *web68-white*)
- ("IM" *web68-magenta*)
- ("IN" *web68-white*)
- ("IS" *web68-white*)
- ("LE" *web68-magenta*)
- ("LT" *web68-magenta*)
- ("NE" *web68-magenta*)
- ("OD" *web68-white*)
- ("OF" *web68-white*)
- ("OP" *web68-white*)
- ("OR" *web68-magenta*)
- ("RE" *web68-magenta*)
- ("TO" *web68-white*)
- ("UP" *web68-magenta*))
- (("ABS" *web68-magenta*) ; length 3
- ("AND" *web68-magenta*)
- ("BIN" *web68-magenta*)
- ("DIV" *web68-magenta*)
- ("END" *web68-white*)
- ("FOR" *web68-white*)
- ("INT" *web68-cyan*)
- ("LOC" *web68-cyan*)
- ("LWB" *web68-magenta*)
- ("MOD" *web68-magenta*)
- ("NIL" *web68-red*)
- ("NOT" *web68-magenta*)
- ("OUT" *web68-white*)
- ("REF" *web68-cyan*)
- ("SHL" *web68-magenta*)
- ("SHR" *web68-magenta*)
- ("UPB" *web68-magenta*)
- ("USE" *web68-white*))
- (("BITS" *web68-cyan*) ; length 4
- ("BOOL" *web68-cyan*)
- ("CASE" *web68-white*)
- ("CHAR" *web68-cyan*)
- ("CONJ" *web68-magenta*)
- ("DECS" *web68-white*)
- ("DOWN" *web68-magenta*)
- ("ELEM" *web68-magenta*)
- ("ELIF" *web68-white*)
- ("ELSE" *web68-white*)
- ("ESAC" *web68-white*)
- ("EXIT" *web68-white*)
- ("FILE" *web68-cyan*)
- ("FLEX" *web68-cyan*)
- ("FROM" *web68-white*)
- ("GOTO" *web68-white*)
- ("HEAP" *web68-cyan*)
- ("ISNT" *web68-white*)
- ("KEEP" *web68-white*)
- ("LONG" *web68-cyan*)
- ("MODE" *web68-white*)
- ("OUSE" *web68-white*)
- ("OVER" *web68-magenta*)
- ("PRIO" *web68-white*)
- ("PROC" *web68-cyan*)
- ("REAL" *web68-cyan*)
- ("REPR" *web68-magenta*)
- ("SKIP" *web68-white*)
- ("THEN" *web68-white*)
- ("TRUE" *web68-red*)
- ("VOID" *web68-cyan*))
- (("BEGIN" *web68-white*) ; length 5
- ("COMPL" *web68-cyan*)
- ("DIVAB" *web68-magenta*)
- ("EMPTY" *web68-red*)
- ("FALSE" *web68-red*)
- ("MODAB" *web68-magenta*)
- ("SHORT" *web68-cyan*)
- ("UNION" *web68-cyan*)
- ("WHILE" *web68-white*))
- (("ENTIER" *web68-magenta*) ; length 6
- ("FINISH" *web68-white*)
- ("OVERAB" *web68-magenta*)
- ("PLUSAB" *web68-magenta*)
- ("PLUSTO" *web68-magenta*)
- ("STRING" *web68-cyan*)
- ("STRUCT" *web68-cyan*))
- (("CHANNEL" *web68-cyan*) ; length 7
- ("CONTEXT" *web68-white*)
- ("MINUSAB" *web68-magenta*)
- ("PROGRAM" *web68-white*)
- ("TIMESAB" *web68-magenta*))))
- (setq *web68-font-lock-keywords*
- (let ((ops "\\<\\(A\\(?:BS\\|ND\\)\\|BIN\\|CONJ\\|D\\(?:IV\\(?:AB\\)?\\|OWN\\)\\|E\\(?:LEM\\|NTIER\\|Q\\)\\|G[ET]\\|IM?\\|L\\(?:WB\\|[ET]\\)\\|M\\(?:INUSAB\\|OD\\(?:AB\\)?\\)\\|N\\(?:E\\|OT\\)\\|O\\(?:R\\|VER\\(?:AB\\)?\\)\\|PLUS\\(?:AB\\|TO\\)\\|RE\\(?:PR\\)?\\|SH[LR]\\|TIMESAB\\|UPB?\\)\\>")
- (bold-tags "\\<\\(AT\\|B\\(?:EGIN\\|Y\\)\\|C\\(?:ASE\\|ONTEXT\\)\\|D\\(?:ECS\\|O\\)\\|E\\(?:L\\(?:IF\\|SE\\)\\|ND\\|SAC\\|XIT\\)\\|F\\(?:I\\(?:NISH\\)?\\|OR\\|ROM\\)\\|GOTO\\|I\\(?:SNT\\|[FNS]\\)\\|KEEP\\|MODE\\|O\\(?:U\\(?:SE\\|T\\)\\|[DFP]\\)\\|PR\\(?:IO\\|OGRAM\\)\\|SKIP\\|T\\(?:HEN\\|O\\)\\|\\(?:US\\|WHIL\\)E\\)\\>")
- (modes "\\<\\(B\\(?:ITS\\|OOL\\)\\|C\\(?:HA\\(?:NNEL\\|R\\)\\|OMPL\\)\\|F\\(?:ILE\\|LEX\\)\\|HEAP\\|INT\\|LO\\(?:C\\|NG\\)\\|PROC\\|RE\\(?:AL\\|F\\)\\|S\\(?:HORT\\|TR\\(?:ING\\|UCT\\)\\)\\|UNION\\|VOID\\)\\>")
- (number-tags "\\<\\(EMPTY\\|FALSE\\|NIL\\|TRUE\\)\\>"))
- '((list (ops . *web68-magenta*))
- (list (bold-tags . *web68-white*))
- (list (modes . *web68-cyan*))
- (list (number-tags . *web68-red*)))))
- ; Keywords for Web 68 mode. Font-locking is performed by `web68-finite-state-machine'."
- (defun web68-chop
- (object sequence &optional key comp order)
- "Finds OBJECT in a sorted SEQUENCE.
- KEY -- function to extract the key from an element of
- SEQUENCE (default #'identity).
- COMP -- function to compare OBJECTs (default #'string=).
- ORDER -- function to order OBJECTs (default #'string<).
- CHOP returns a list containing two values:
- if (cadr return) = nil, OBJECT is not in SEQUENCE
- else (car return) gives its index in SEQUENCE."
- (let ((fkey (if key key 'identity))
- (fcomp (if comp comp 'string=))
- (forder (if order order 'string<))
- (l 0)
- (u (1- (length sequence)))
- m item)
- (while
- (if (<= l u)
- (progn
- (setf m (/ (+ l u) 2))
- (setf item (elt sequence m))
- (not (funcall fcomp object (funcall fkey item))))
- nil)
- (if (funcall forder object (funcall fkey item))
- (setf u (1- m))
- (setf l (1+ m))))
- (list (if (> l u) u m)
- (if (> l u) nil m))))
- (defvar *web68-tag* nil) ; set to tag by web68-finite-state-machine
- (defun web68-set-text-colour (leng face)
- "Set the colour of the chars at (POINT):(POINT+leng) to FACE."
- (put-text-property (point) (+ (point) leng) 'face face))
- (defun web68-find-bold-tag ()
- "Identify the tag in *web68-tag* and colourise it accordingly.
- If the tag is not identified, colourise it as a mode indicant."
- (let* ((lst (nth (length *web68-tag*) *web68-bold-tags*))
- (ret (web68-chop *web68-tag* lst)))
- (if (cadr ret)
- (web68-set-text-colour (length *web68-tag*)
- (cadr (nth (car ret) lst)))
- (web68-set-text-colour (length *web68-tag*) *web68-cyan*))))
- (defvar *states*
- '(;; ('face
- ;; (flags/nil matcher face/nil 'function/next-state))
- (*web68-darkcyan* ; default: punctuation [0] Algol 68
- (nil "COMMENT" *web68-white* 1) ; start of COMMENT comment
- (nil "#" *web68-white* 3) ; start of # comment
- (nil "{" *web68-white* 4) ; start of brace comment
- (nil "!" *web68-darkcyan* 9) ; end of snippet
- (?- "@[ 123adhim<^.!=\/,]" nil 9) ; Web 68 command
- (nil "@@" *web68-magenta* 0) ; AT operator
- (?- "[A-Z]" nil 5) ; start of a bold tag
- (?- "[a-z]" nil 6) ; start of an identifier
- (?- "[0-9]" nil 7) ; start of a number
- (?- "[.]" nil 7) ; start of a REAL
- (?- "[-<=>+*/%^]" nil 8) ; start of an operator
- (nil ":=:" *web68-magenta* 0)
- (nil ":/=:" *web68-magenta* 0)
- (nil ":=" *web68-darkcyan* 0))
- (*web68-brown* ; default: comment [1] COMMENT state
- (nil "COMMENT" *web68-white* 0))
- (*web68-brown* ; default: comment [2] CO state
- (nil "CO[^A-Z]" '*web68-white* 0))
- (*web68-brown* ; default: comment [3] # state
- (nil "#" *web68-white* 0)) ; end of # comment
- (*web68-brown* ; default: comment [4] { state
- (nil "}" *web68-white* 0))
- (*web68-white* ; default: bold tag [5]
- (?f "[A-Z][0-9A-Z]*" nil 'web68-find-bold-tag))
- (*web68-blue* ; default: identifier [6]
- (nil "[a-z][0-9a-z ]" *web68-blue* 0))
- (*web68-red* ; default: number [7]
- (nil "2r[01 ]+" *web68-red* 0) ; binary denotation
- (nil "4r[0-3 ]+" *web68-red* 0) ; base-4 "
- (nil "8r[0-7 ]+" *web68-red* 0) ; octal "
- (nil "16r[0-9a-f ]+" *web68-red* 0) ; hex "
- ;; reals with exponent: -1e+10 .1e+10 +1.2e+10
- (nil "[-+]?[0-9 ]+e[-+]?[0-9]+" *web68-red* 0)
- (nil "[-+]?\.[0-9 ]+e[-+]?[0-9]+" *web68-red* 0)
- (nil "[-+]?[0-9 ]+\.[0-9 ]+e[-+]?[0-9]+" *web68-red* 0)
- ;; reals without exponent: -1 .1 +1.2
- (nil "[-+]?[0-9 ]+" *web68-red* 0)
- (nil "[-+]?\.[0-9 ]+" *web68-red* 0)
- (nil "[-+]?[0-9 ]+\.[0-9 ]+" *web68-red* 0))
- (*web68-magenta* ; default: operator [8]
- (nil "[-+*/%]:=" *web68-magenta* 0)
- (nil "\\(%*:=\\|+=:\\|\*\*\\|/=\\)" *web68-magenta* 0)
- (nil "\\(<=\\|>=\\)" *web68-magenta* 0)
- (nil "[-+*/%^<>=]" *web68-magenta* 0)) ; simple operator
- (*web68-grey* ; default: Web 68 text [9]
- (nil "!" *web68-white* 0) ; start of snippet
- (nil "<" *web68-magenta* 11) ; start of HTML tag
- (nil "@[123 ]" *web68-cyan* 9) ; section command
- (nil "@[adm]" *web68-cyan* 0) ; to Algol 68 state
- (nil "@h" *web68-cyan* 12) ; HTML state
- (nil "@[i<.^]" *web68-cyan* 10) ; start of delimited text
- (nil "@[!\/,=]" '*web68-cyan* 0))
- (*web68-green* ; default: delimited text [10]
- (nil "@>=?" *web68-cyan* 0)) ; end of delimited text
- (*web68-magenta* ; default: HTML tag [11]
- (nil ">" *web68-magenta* 9)) ; end of HTML tag
- (*web68-grey* ; default: HTML state [12]
- (nil "@>" *web68-cyan* 9)))) ; end of HTML state
- (defmacro inc (var)
- (list 'setq var (list '1+ var)))
- (defun web68-finite-state-machine (start end &optional verbose)
- "Executes the transitions defined in STATES starting at START
- upto END. The elements of each transition have the following meanings:
- Element 0: flags:
- nil -- no flags
- - -- (point) should not be moved after the match
- f -- the 3rd element is a function instead of a face
- Element 1:
- matcher
- Element 2:
- face/function
- Element 3:
- next state."
- (let ((current-state-index 0)
- state
- default
- index
- transition
- flags
- regexp
- transition-setup)
- (fset 'transition-setup
- (lambda (inx stat)
- (setq transition (nth inx stat)
- flags (car transition)
- regexp (cadr transition))))
- (goto-char start)
- (while (< (point) end)
- (setq state (nth current-state-index *states*)
- default (car state)
- index 1)
- (while (< index (length state))
- ((symbol-function 'transition-setup) index state)
- ;; we need a function which computes transition, flags and regexp each
- ;; time index is incremented
- (while (not (looking-at regexp))
- ((symbol-function 'transition-setup) (inc index) state))
- (if (= index (length state))
- ;; no match
- (progn
- (web68-set-text-colour 1 default-face)
- (forward-char 1))
- ;; match
- (let ((matched (match-string 0)))
- (cond ((zerop (length flags)) ; no flags
- (web68-set-text-colour (length matched)
- (nth 2 transition))
- (forward-char (length matched)))
- ((char-equal ?f flags) ; Element 2 is a function
- (setq *web68-tag*
- (buffer-substring-no-properties
- (point) (+ (point) (length matched))))
- (funcall (nth 2 transition)) ; call the function
- (forward-char (length matched)))
- ((char-equal ?- flags) ; Don't move point
- (web68-set-text-colour (length matched)
- (nth 2 transition))))
- (setq current-state-index (nth 3 transition))))))))
- (defun web68-find-font-lock-region ()
- "Finds the region over which font-locking will occur.
- (1) Looks backward for a Web 68 sectioning command or the buffer beginning.
- (2) Looks forward for a Web 68 sectioning command or the buffer end.
- Due account is taken of the visible part of the text."
- (goto-char (window-start))
- (if (re-search-backward "@[123 ]" (point-min) t)
- (push-mark (point))
- (push-mark (point-min)))
- (goto-char (window-end))
- (if (re-search-forward "@[123 ]" (point-max) t)
- (beginning-of-line)
- (goto-char (point-max))))
- (defun web68-find-font-lock-buffer ()
- "Sets POINT and MARK to POINT-MIN and POINT-MAX respectively."
- (push-mark (point-max))
- (goto-char (point-min)))
- ;;;###autoload
- (define-derived-mode
- web68-mode prog-mode "Web 68"
- "Major mode for editing Web 68 code as well as displaying Algol 68 code."
- (setq-local case-fold-search nil)
- (setq-local blink-matching-paren-dont-ignore-comments t)
- ;; Font lock support
- (setq-local font-lock-defaults
- (list
- *web68-font-lock-keywords* t nil nil nil
- '(font-lock-fontify-region-function . web68-finite-state-machine)
- '(font-lock-fontify-buffer-function . web68-find-font-lock-buffer)))
- (add-hook 'web68-mode-hook 'web68-find-font-lock-region))
- (provide 'web68)
- ;;;; web68.el ends here
Advertisement