;;; tiger.el --- Mode for editing programs written in Appel's Tiger language. ;; Copyright (C) 2001, 2007 Edward O'Connor ;; Author: Edward O'Connor ;; Keywords: languages ;; Maintainers : ;; Jerome Bana ;; Benoit Perrot ;; Roland Levillain ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of version 2 of the GNU General Public License ;; as published by the Free Software Foundation. ;; This file 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. ;; I'm sure you already have many copies of the GPL on your machine. ;; If you're using GNU Emacs, try typing C-h C-c to bring it up. If ;; you're using XEmacs, C-h C-l does this. ;;; Commentary: ;; This mode only supports font-locking, unfortunately. If you'd like ;; to add functionality, please do so! :) You'll want to add something ;; like this to your .emacs file: ;; (autoload 'tiger-mode "tiger" "Load tiger-mode" t) ;; (add-to-list 'auto-mode-alist '("\\.ti[gh]$" . tiger-mode)) ;;; History: ;; In the Compilers class I took in college[0], we used Appel's ;; _Modern Compiler Implementation in Java_ text[1], in which he uses ;; the Tiger language. After a few weeks of our final project (which ;; was to write a Tiger compiler), I got sick of looking at ;; #c0c0c0-on-black Tiger text, and decided to hack up (at least) some ;; font-lock support for the language. Hence this file. I would have ;; added indenting stuff too, but the term ended and I graduated. :) ;; If you add functionality or whatever, please send me the changes; ;; I'll gladly maintain the code base or whatever. The latest version ;; can be found here: ;; ;; -- Ted ;; ;; 0. ;; 1. ;;; Declare Tiger mode. (defgroup tiger nil "Tiger code editing commands for Emacs." :prefix "tiger-" :group 'languages) (defcustom tiger-mode-hook nil "*Hook called by `tiger-mode'." :type 'hook :group 'tiger) ;;; Define Tiger syntax table. (defvar tiger-mode-syntax-table nil "Syntax table used in Tiger mode.") (when (not tiger-mode-syntax-table) (setq tiger-mode-syntax-table (make-syntax-table)) ;; Declare the underscore character '_' as being a valid part of a word. (modify-syntax-entry ?_ "w" tiger-mode-syntax-table) ;; Comment (n for nested works only with emacs-21) (modify-syntax-entry ?/ ". 14n" tiger-mode-syntax-table) (modify-syntax-entry ?* ". 23" tiger-mode-syntax-table) ) ;;; Highlight Syntax. (defconst tiger-font-lock-keywords `( ;; Tiger keywords: ("\\<\\(array\\|break\\|do\\|e\\(?:lse\\|nd\\)\\|f\\(?:or\\|unction\\)\\|i\\(?:f\\|mport\\|n\\)\\|let\\|nil\\|of\\|primitive\\|t\\(?:hen\\|o\\|ype\\)\\|var\\|while\\)\\>" (1 font-lock-keyword-face)) ;; Reserved keywords (only valid in Leopard): ("\\<\\(class\\|extends\\|method\\|new\\)\\>" (1 font-lock-warning-face)) ;; Reserved identifiers: ("\\<\\(_\\w*\\)\\>" (1 font-lock-warning-face)) ;; Variable declarations: ("\\" (1 font-lock-type-face)) ;; Builtin types: ("\\<\\(boolean\\|int\\|string\\)\\>" (1 font-lock-type-face)) ;; _t and _type: ("\\<\\([a-zA-Z]\\w*_t\\(ype\\)?\\)\\>" (1 font-lock-type-face)) ;; Function declarations: ("\\" (1 font-lock-function-name-face)) (":\\s *\\([a-zA-Z]\\w*\\)\\>" (1 font-lock-type-face)) ;; Builtin functions: ("\\<\\(c\\(?:hr\\|oncat\\)\\|exit\\|flush\\|getchar\\|not\\|ord\\|print\\(?:_err\\|_int\\)?\\|s\\(?:ize\\|ubstring\\|tr\\(?:cmp\\|eq\\)\\)\\)\\>" (1 font-lock-builtin-face)) ) "Expressions to highlight in Tiger modes.") ;;; Indent Tiger code. (defvar tiger-indent 2 "Indentation of Tiger statements.") (defun tiger-search-block-backward (re re-start re-end) "Search backward for the opening of a code block." (setq found-p t) (let ((depth 1) (comment-level 0)) (setq re (concat re "\\|/\\*\\|\\*/")) (while (< 0 depth) (if (not (re-search-backward re nil t)) (setq depth 0 comment-level -1 found-p nil)) (cond ;; nested comment ((looking-at "/\\*") (setq comment-level (1+ comment-level))) ((looking-at "\\*/") (setq comment-level (1- comment-level))) ;; sentry ((< 0 comment-level) (setq depth 0)) ;; ((= 0 comment-level) (cond ((looking-at re-start) (setq depth (1+ depth))) ((looking-at re-end) (setq depth (1- depth))) ((= depth 1) (setq depth 0)) )) ) ) ) found-p ) (defun tiger-block-indentation () "Return block indentation." (setq indent-inc 0) (let ((re "") (re-start "") (re-end "")) (cond ((looking-at "\\s *end\\>") (setq re "\\<\\(in\\|end\\)\\>" re-start "\\" re-end "\\")) ((looking-at "\\s *in\\>") (setq re "\\<\\(let\\|in\\)\\>" re-start "\\" re-end "\\")) ((looking-at "\\s *then\\>") (setq re "\\<\\(if\\|then\\)\\>" re-start "\\" re-end "\\")) ((looking-at "\\s *else\\>") (setq re "\\<\\(then\\|else\\)\\>" re-start "\\" re-end "\\")) ((looking-at "\\s *\\(var\\|type\\|function\\)\\>") (setq re "\\<\\(let\\|end\\)\\>" re-start "\\" re-end "\\" indent-inc tiger-indent)) ((looking-at "\\s *[])}]") (setq re "[][(){}]" re-start "[])}]" re-end "[[({]")) ;; default (t (setq re "\\<\\(let\\|in\\|end\\|if\\|then\\|else\\|do\\|function\\|type\\)\\>\\|[][(){};]" re-start "\\\\|[])}]" re-end "\\\\|[[({]" indent-inc tiger-indent) ) ) (if (not (tiger-search-block-backward re re-start re-end)) (setq indent-inc 0)) ) (if (looking-at ";") (tiger-search-block-backward "\\<\\(let\\|in\\|end\\|if\\|then\\)\\>\\|[][(){}]" "[])}]\\|then\\|end" "[[({]\\|if\\|let")) (cond ;; handle opening parenthesis ((looking-at "[[(]") (+ (current-column) (if (not (looking-at "[[(]\\s *$")) (min 1 indent-inc) indent-inc))) ;; handle "then" single on line ((looking-at "then") (+ (current-indentation) indent-inc)) ;; default (t (+ (current-column) indent-inc)) ) ) (defun tiger-indent-line () "Indent current line as Tiger code." (interactive) (if (bobp) ;; Do not indent first line (indent-line-to 0) ;;; (if nil (progn (beginning-of-line) (tiger-block-indentation)) ;;; (let ((indent-level 0) (move-to-indentation-p (<= (current-column) (current-indentation)))) (save-excursion (save-excursion (beginning-of-line) (setq indent-level (tiger-block-indentation))) (indent-line-to indent-level) ) (if move-to-indentation-p (back-to-indentation)) ) ;;; ) ;;; ) ) ;(defun tiger-indent-region (start end) ; "From start to end, indent each line." ; ) ;;; Tiger mode entry function. (defun tiger-mode () "Major mode for editing Tiger programs. The following keys are bound: \\{tiger-mode-map}" (interactive) ;; Set up local variables (kill-all-local-variables) (make-local-variable 'font-lock-defaults) (make-local-variable 'comment-start) (make-local-variable 'comment-end) (make-local-variable 'indent-line-function) ;; (set-syntax-table tiger-mode-syntax-table) (setq major-mode 'tiger-mode mode-name "Tiger" font-lock-defaults '(tiger-font-lock-keywords) comment-start "/*" comment-end "*/" indent-line-function 'tiger-indent-line ) (setq tiger-mode-map (make-sparse-keymap)) (use-local-map tiger-mode-map) ;; Run the Tiger mode hook (run-hooks 'tiger-mode-hook)) (provide 'tiger) ;;; tiger.el ends here