Birothilu

web68.el

Dec 21st, 2014
759
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 16.48 KB | None | 0 0
  1. ;;;; -*- Mode: Lisp; lexical-binding: t; -*-
  2. ;;;; web68.el --- major mode for editing Web 68 source
  3. ;;;; This file contains Web 68 mode.
  4. ;;;; It is used to colourise Web 68 and Algol 68 files.
  5. ;;;; Copyright (C) 2014 Sian Mountbatten
  6. ;;;; Author: Sian Mountbatten <[email protected]>
  7. ;;;; Keywords: languages
  8.  
  9. (defgroup web68 nil
  10.   "Major mode for editing Web 68/Algol 68 source in Emacs."
  11.   :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
  12.   :group 'languages)
  13.  
  14. (defvar web68-mode-abbrev-table nil
  15.   "Abbrev table in use in Web68 mode buffers.")
  16. (define-abbrev-table 'web68-mode-abbrev-table ())
  17.  
  18. (defvar web68-mode-map
  19.   (let ((map (make-sparse-keymap)))
  20.     map)
  21.   "Keymap used in Web68 mode.")
  22.  
  23. (defvar web68-imenu-generic-expression
  24.   '((nil "^[ \t]*\\(PROC\\|OP\\)[ \t\n]+\\([a-zA-Z0-9_.:]+\\)" 2))
  25.   "Imenu expression for Web68 mode. See `imenu-generic-expression'.")
  26.  
  27. (defvar web68-mode-syntax-table
  28.   (let ((st (make-syntax-table)))
  29.     (modify-syntax-entry ?\( "()" st)
  30.     (modify-syntax-entry ?\) ")(" st)
  31.     (modify-syntax-entry ?#  "$"  st)
  32.     (modify-syntax-entry ?{  "<"  st)
  33.     (modify-syntax-entry ?}  ">"  st)
  34.     (modify-syntax-entry ?$  "$"  st)
  35.     (modify-syntax-entry ?_  "_"  st)
  36.     st)
  37.   "Syntax table in use in Web68-mode buffers.")
  38.    
  39. ;;; Define the font lock colours
  40. (defface *web68-grey*
  41.     '((((class color) (min-colors 88) (background dark))
  42.        ;.
  43.        :background "black" :foreground "#808080"))
  44.   "Used for Web 68 text."
  45.   :group 'web68)
  46.  
  47. (defface *web68-red*
  48.     '((((class color) (min-colors 88) (background dark))
  49.        ;.
  50.        :background "black" :foreground "red"))
  51.   "Used for numbers."
  52.   :group 'web68)
  53.  
  54. (defface *web68-darkcyan*
  55.     '((((class color) (min-colors 88) (background dark))
  56.        ;.
  57.        :background "black" :foreground "darkCyan"))
  58.   "Used for punctuation."
  59.   :group 'web68)
  60.  
  61. (defface *web68-yellow*
  62.     '((((class color) (min-colors 88) (background dark))
  63.        ;.
  64.        :background "black" :foreground "yellow"))
  65.   "Used for strings."
  66.   :group 'web68)
  67.  
  68. (defface *web68-brown*
  69.     '((((class color) (min-colors 88) (background dark))
  70.        ;.
  71.        :background "black" :foreground "brown"))
  72.   "Used for comments."
  73.   :group 'web68)
  74.  
  75. (defface *web68-magenta*
  76.     '((((class color) (min-colors 88) (background dark))
  77.        ;.
  78.      :background "black" :foreground "magenta"))
  79.   "Used for operators."
  80.   :group 'web68)
  81.  
  82. (defface *web68-green*
  83.     '((((class color) (min-colors 88) (background dark))
  84.        ;.
  85.        :background "black" :foreground "green"))
  86.   "Used for dates/delimited text."
  87.   :group 'web68)
  88.  
  89. (defface *web68-cyan*
  90.     '((((class color) (min-colors 88) (background dark))
  91.        ;.
  92.        :background "black" :foreground "cyan"))
  93.   "Used for Algol 68 modes and Web 68 commands."
  94.   :group 'web68)
  95.  
  96. (defface *web68-blue*
  97.     '((((class color) (min-colors 88) (background dark))
  98.        ;.
  99.        :background "black" :foreground "skyblue"))
  100.   "Used for identifiers."
  101.   :group 'web68)
  102.  
  103. (defface *web68-white*
  104.     '((((class color) (min-colors 88) (background dark))
  105.        ;.
  106.        :background "black" :foreground "white"))
  107.   "Used for bold tags."
  108.   :group 'web68)
  109.  
  110. ;;;; The next data structure is used to identify a bold tag.
  111. ;;;; The length of the tag determines which sorted list is used.
  112. ;;;; The `chop' function then finds the actual position of the
  113. ;;;; bold tag and, consequently, its face property.
  114. ;;;;
  115. ;;;; Define which face is used for each bold tag
  116. (defconst *web68-bold-tags*
  117.   '(nil
  118.     (("I" *web68-magenta*))         ; length 1
  119.     (("AT" *web68-white*)           ; length 2
  120.      ("BY" *web68-white*)
  121.      ("CO" *web68-white*)
  122.      ("DO" *web68-white*)
  123.      ("EQ" *web68-magenta*)
  124.      ("FI" *web68-white*)
  125.      ("GE" *web68-magenta*)
  126.      ("GT" *web68-magenta*)
  127.      ("IF" *web68-white*)
  128.      ("IM" *web68-magenta*)
  129.      ("IN" *web68-white*)
  130.      ("IS" *web68-white*)
  131.      ("LE" *web68-magenta*)
  132.      ("LT" *web68-magenta*)
  133.      ("NE" *web68-magenta*)
  134.      ("OD" *web68-white*)
  135.      ("OF" *web68-white*)
  136.      ("OP" *web68-white*)
  137.      ("OR" *web68-magenta*)
  138.      ("RE" *web68-magenta*)
  139.      ("TO" *web68-white*)
  140.      ("UP" *web68-magenta*))
  141.     (("ABS" *web68-magenta*)        ; length 3
  142.      ("AND" *web68-magenta*)
  143.      ("BIN" *web68-magenta*)
  144.      ("DIV" *web68-magenta*)
  145.      ("END" *web68-white*)
  146.      ("FOR" *web68-white*)
  147.      ("INT" *web68-cyan*)
  148.      ("LOC" *web68-cyan*)
  149.      ("LWB" *web68-magenta*)
  150.      ("MOD" *web68-magenta*)
  151.      ("NIL" *web68-red*)
  152.      ("NOT" *web68-magenta*)
  153.      ("OUT" *web68-white*)
  154.      ("REF" *web68-cyan*)
  155.      ("SHL" *web68-magenta*)
  156.      ("SHR" *web68-magenta*)
  157.      ("UPB" *web68-magenta*)
  158.      ("USE" *web68-white*))
  159.     (("BITS" *web68-cyan*)          ; length 4
  160.      ("BOOL" *web68-cyan*)
  161.      ("CASE" *web68-white*)
  162.      ("CHAR" *web68-cyan*)
  163.      ("CONJ" *web68-magenta*)
  164.      ("DECS" *web68-white*)
  165.      ("DOWN" *web68-magenta*)
  166.      ("ELEM" *web68-magenta*)
  167.      ("ELIF" *web68-white*)
  168.      ("ELSE" *web68-white*)
  169.      ("ESAC" *web68-white*)
  170.      ("EXIT" *web68-white*)
  171.      ("FILE" *web68-cyan*)
  172.      ("FLEX" *web68-cyan*)
  173.      ("FROM" *web68-white*)
  174.      ("GOTO" *web68-white*)
  175.      ("HEAP" *web68-cyan*)
  176.      ("ISNT" *web68-white*)
  177.      ("KEEP" *web68-white*)
  178.      ("LONG" *web68-cyan*)
  179.      ("MODE" *web68-white*)
  180.      ("OUSE" *web68-white*)
  181.      ("OVER" *web68-magenta*)
  182.      ("PRIO" *web68-white*)
  183.      ("PROC" *web68-cyan*)
  184.      ("REAL" *web68-cyan*)
  185.      ("REPR" *web68-magenta*)
  186.      ("SKIP" *web68-white*)
  187.      ("THEN" *web68-white*)
  188.      ("TRUE" *web68-red*)
  189.      ("VOID" *web68-cyan*))
  190.     (("BEGIN" *web68-white*)        ; length 5
  191.      ("COMPL" *web68-cyan*)
  192.      ("DIVAB" *web68-magenta*)
  193.      ("EMPTY" *web68-red*)
  194.      ("FALSE" *web68-red*)
  195.      ("MODAB" *web68-magenta*)
  196.      ("SHORT" *web68-cyan*)
  197.      ("UNION" *web68-cyan*)
  198.      ("WHILE" *web68-white*))
  199.     (("ENTIER" *web68-magenta*)     ; length 6
  200.      ("FINISH" *web68-white*)
  201.      ("OVERAB" *web68-magenta*)
  202.      ("PLUSAB" *web68-magenta*)
  203.      ("PLUSTO" *web68-magenta*)
  204.      ("STRING" *web68-cyan*)
  205.      ("STRUCT" *web68-cyan*))
  206.     (("CHANNEL" *web68-cyan*)       ; length 7
  207.      ("CONTEXT" *web68-white*)
  208.      ("MINUSAB" *web68-magenta*)
  209.      ("PROGRAM" *web68-white*)
  210.      ("TIMESAB" *web68-magenta*))))
  211.  
  212. (setq *web68-font-lock-keywords*
  213.   (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?\\)\\>")
  214.         (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\\)\\>")
  215.         (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\\)\\>")
  216.         (number-tags "\\<\\(EMPTY\\|FALSE\\|NIL\\|TRUE\\)\\>"))
  217.      '((list (ops . *web68-magenta*))
  218.        (list (bold-tags . *web68-white*))
  219.        (list (modes . *web68-cyan*))
  220.        (list (number-tags . *web68-red*)))))
  221. ; Keywords for Web 68 mode. Font-locking is performed by `web68-finite-state-machine'."
  222.  
  223. (defun web68-chop
  224.     (object sequence &optional key comp order)
  225.   "Finds OBJECT in a sorted SEQUENCE.
  226. KEY   -- function to extract the key from an element of
  227.         SEQUENCE (default #'identity).
  228. COMP  -- function to compare OBJECTs (default #'string=).
  229. ORDER -- function to order OBJECTs (default #'string<).
  230. CHOP returns a list containing two values:
  231.  if (cadr return) = nil, OBJECT is not in SEQUENCE
  232.  else (car return) gives its index in SEQUENCE."
  233.   (let ((fkey (if key key 'identity))
  234.         (fcomp (if comp comp 'string=))
  235.         (forder (if order order 'string<))
  236.         (l 0)
  237.         (u (1- (length sequence)))
  238.         m item)
  239.     (while
  240.         (if (<= l u)
  241.             (progn
  242.               (setf m (/ (+ l u) 2))
  243.               (setf item (elt sequence m))
  244.               (not (funcall fcomp object (funcall fkey item))))
  245.             nil)
  246.       (if (funcall forder object (funcall fkey item))
  247.           (setf u (1- m))
  248.           (setf l (1+ m))))
  249.     (list (if (> l u) u m)
  250.           (if (> l u) nil m))))
  251.  
  252. (defvar *web68-tag* nil)  ; set to tag by web68-finite-state-machine
  253.  
  254. (defun web68-set-text-colour (leng face)
  255.   "Set the colour of the chars at (POINT):(POINT+leng) to FACE."
  256.   (put-text-property (point) (+ (point) leng) 'face face))
  257.  
  258. (defun web68-find-bold-tag ()
  259.   "Identify the tag in *web68-tag* and colourise it accordingly.
  260. If the tag is not identified, colourise it as a mode indicant."
  261.   (let* ((lst (nth (length *web68-tag*) *web68-bold-tags*))
  262.          (ret (web68-chop *web68-tag* lst)))
  263.     (if (cadr ret)
  264.         (web68-set-text-colour (length *web68-tag*)
  265.                                (cadr (nth (car ret) lst)))
  266.         (web68-set-text-colour (length *web68-tag*) *web68-cyan*))))
  267.  
  268. (defvar *states*
  269.   '(;; ('face
  270.     ;;  (flags/nil matcher face/nil 'function/next-state))
  271.     (*web68-darkcyan*                 ; default: punctuation [0] Algol 68
  272.      (nil "COMMENT" *web68-white* 1)  ; start of COMMENT comment
  273.      (nil "#" *web68-white* 3)        ; start of # comment
  274.      (nil "{" *web68-white* 4)        ; start of brace comment
  275.      (nil "!" *web68-darkcyan* 9)     ; end of snippet
  276.      (?-  "@[ 123adhim<^.!=\/,]" nil 9)    ; Web 68 command
  277.      (nil "@@" *web68-magenta* 0)     ; AT operator
  278.      (?-  "[A-Z]" nil 5)                   ; start of a bold tag
  279.      (?-  "[a-z]" nil 6)                   ; start of an identifier
  280.      (?-  "[0-9]" nil 7)                   ; start of a number
  281.      (?-  "[.]" nil 7)                     ; start of a REAL
  282.      (?-  "[-<=>+*/%^]" nil 8)             ; start of an operator
  283.      (nil ":=:"  *web68-magenta* 0)
  284.      (nil ":/=:" *web68-magenta* 0)
  285.      (nil ":="   *web68-darkcyan* 0))
  286.  
  287.     (*web68-brown*                    ; default: comment [1] COMMENT state
  288.      (nil "COMMENT" *web68-white* 0))
  289.  
  290.     (*web68-brown*                    ; default: comment [2] CO state
  291.      (nil "CO[^A-Z]" '*web68-white* 0))
  292.  
  293.     (*web68-brown*                    ; default: comment [3] # state
  294.      (nil "#" *web68-white* 0))       ; end of # comment
  295.  
  296.     (*web68-brown*                    ; default: comment [4] { state
  297.      (nil "}" *web68-white* 0))
  298.    
  299.     (*web68-white*                    ; default: bold tag [5]
  300.      (?f "[A-Z][0-9A-Z]*" nil 'web68-find-bold-tag))
  301.  
  302.     (*web68-blue*                     ; default: identifier [6]
  303.      (nil "[a-z][0-9a-z ]" *web68-blue* 0))
  304.  
  305.     (*web68-red*                      ; default: number [7]
  306.      (nil "2r[01 ]+" *web68-red* 0)                ; binary denotation
  307.      (nil "4r[0-3 ]+" *web68-red* 0)               ; base-4     "
  308.      (nil "8r[0-7 ]+" *web68-red* 0)               ; octal      "
  309.      (nil "16r[0-9a-f ]+" *web68-red* 0)           ; hex        "
  310.      ;; reals with exponent: -1e+10 .1e+10 +1.2e+10
  311.      (nil "[-+]?[0-9 ]+e[-+]?[0-9]+" *web68-red* 0)
  312.      (nil "[-+]?\.[0-9 ]+e[-+]?[0-9]+" *web68-red* 0)
  313.      (nil "[-+]?[0-9 ]+\.[0-9 ]+e[-+]?[0-9]+" *web68-red* 0)
  314.      ;; reals without exponent: -1 .1 +1.2
  315.      (nil "[-+]?[0-9 ]+" *web68-red* 0)
  316.      (nil "[-+]?\.[0-9 ]+" *web68-red* 0)
  317.      (nil "[-+]?[0-9 ]+\.[0-9 ]+" *web68-red* 0))
  318.      
  319.     (*web68-magenta*                  ; default: operator [8]
  320.      (nil "[-+*/%]:="     *web68-magenta* 0)
  321.      (nil "\\(%*:=\\|+=:\\|\*\*\\|/=\\)" *web68-magenta* 0)
  322.      (nil "\\(<=\\|>=\\)" *web68-magenta* 0)
  323.      (nil "[-+*/%^<>=]"   *web68-magenta* 0))  ; simple operator
  324.    
  325.     (*web68-grey*                      ; default: Web 68 text [9]
  326.      (nil "!" *web68-white* 0)         ; start of snippet
  327.      (nil "<" *web68-magenta* 11)      ; start of HTML tag
  328.      (nil "@[123 ]" *web68-cyan* 9)    ; section command
  329.      (nil "@[adm]"  *web68-cyan* 0)    ; to Algol 68 state
  330.      (nil "@h"      *web68-cyan* 12)   ; HTML state
  331.      (nil "@[i<.^]" *web68-cyan* 10)   ; start of delimited text
  332.      (nil "@[!\/,=]" '*web68-cyan* 0))
  333.      
  334.     (*web68-green*                     ; default: delimited text [10]
  335.      (nil "@>=?"  *web68-cyan* 0))     ; end of delimited text
  336.  
  337.     (*web68-magenta*                   ; default: HTML tag [11]
  338.      (nil ">" *web68-magenta* 9))      ; end of HTML tag
  339.  
  340.     (*web68-grey*                      ; default: HTML state [12]
  341.      (nil "@>" *web68-cyan* 9))))      ; end of HTML state
  342.  
  343. (defmacro inc (var)
  344.   (list 'setq var (list '1+ var)))
  345.  
  346. (defun web68-finite-state-machine (start end &optional verbose)
  347.   "Executes the transitions defined in STATES starting at START
  348. upto END. The elements of each transition have the following meanings:
  349. Element 0: flags:
  350.  nil   -- no flags
  351.  -     -- (point) should not be moved after the match
  352.  f     -- the 3rd element is a function instead of a face
  353. Element 1:
  354.  matcher
  355. Element 2:
  356.  face/function
  357. Element 3:
  358.  next state."
  359.   (let ((current-state-index 0)
  360.         state
  361.         default
  362.         index
  363.         transition
  364.         flags
  365.         regexp
  366.         transition-setup)
  367.     (fset 'transition-setup
  368.           (lambda (inx stat)
  369.             (setq transition (nth inx stat)
  370.                   flags  (car transition)
  371.                   regexp (cadr transition))))
  372.     (goto-char start)
  373.     (while (< (point) end)
  374.       (setq state (nth current-state-index *states*)
  375.             default (car state)
  376.             index 1)
  377.       (while (< index (length state))
  378.         ((symbol-function 'transition-setup) index state)
  379.         ;; we need a function which computes transition, flags and regexp each
  380.         ;; time index is incremented
  381.         (while (not (looking-at regexp))
  382.           ((symbol-function 'transition-setup) (inc index) state))
  383.         (if (= index (length state))
  384.             ;; no match
  385.             (progn
  386.               (web68-set-text-colour 1 default-face)
  387.               (forward-char 1))
  388.             ;; match
  389.             (let ((matched (match-string 0)))
  390.               (cond ((zerop (length flags)) ; no flags
  391.                      (web68-set-text-colour (length matched)
  392.                                             (nth 2 transition))
  393.                      (forward-char (length matched)))
  394.                     ((char-equal ?f flags) ; Element 2 is a function
  395.                      (setq *web68-tag*
  396.                            (buffer-substring-no-properties
  397.                             (point) (+ (point) (length matched))))
  398.                      (funcall (nth 2 transition))   ; call the function
  399.                      (forward-char (length matched)))
  400.                     ((char-equal ?- flags) ; Don't move point
  401.                      (web68-set-text-colour (length matched)
  402.                                             (nth 2 transition))))
  403.               (setq current-state-index (nth 3 transition))))))))
  404.  
  405. (defun web68-find-font-lock-region ()
  406.   "Finds the region over which font-locking will occur.
  407. (1) Looks backward for a Web 68 sectioning command or the buffer beginning.
  408. (2) Looks forward for a Web 68 sectioning command or the buffer end.
  409. Due account is taken of the visible part of the text."
  410.   (goto-char (window-start))
  411.   (if (re-search-backward "@[123 ]" (point-min) t)
  412.       (push-mark (point))
  413.     (push-mark (point-min)))
  414.   (goto-char (window-end))
  415.   (if (re-search-forward "@[123 ]" (point-max) t)
  416.       (beginning-of-line)
  417.     (goto-char (point-max))))
  418.  
  419. (defun web68-find-font-lock-buffer ()
  420.   "Sets POINT and MARK to POINT-MIN and POINT-MAX respectively."
  421.   (push-mark (point-max))
  422.   (goto-char (point-min)))
  423.  
  424. ;;;###autoload
  425. (define-derived-mode
  426.     web68-mode prog-mode "Web 68"
  427.     "Major mode for editing Web 68 code as well as displaying Algol 68 code."
  428.     (setq-local case-fold-search nil)
  429.     (setq-local blink-matching-paren-dont-ignore-comments t)
  430.     ;; Font lock support
  431.     (setq-local font-lock-defaults
  432.                 (list
  433.                  *web68-font-lock-keywords* t nil nil nil
  434.                  '(font-lock-fontify-region-function . web68-finite-state-machine)
  435.                  '(font-lock-fontify-buffer-function . web68-find-font-lock-buffer)))
  436.     (add-hook 'web68-mode-hook 'web68-find-font-lock-region))
  437.  
  438. (provide 'web68)
  439.  
  440. ;;;; web68.el ends here
Advertisement