home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
CONTRIB
/
SATHER.EL
< prev
Wrap
Lisp/Scheme
|
1994-10-25
|
20KB
|
552 lines
;; .sather-mode.el -- Emacs mode for editing Sather 1.0 programs.
;;
;; Author: Stephen M. Omohundro <om@icsi.berkeley.edu>
;; Copyright (C) International Computer Science Institute, 1990
;; $Id: sather1.el,v 1.1 1994/08/08 18:39:11 gomes Exp $
;; COPYRIGHT NOTICE: This code is provided WITHOUT ANY WARRANTY
;; and is subject to the terms of the SATHER LIBRARY GENERAL PUBLIC
;; LICENSE contained in the file: sather/doc/license.txt of the
;; Sather distribution. The license is also available from ICSI,
;; 1947 Center St., Suite 600, Berkeley CA 94704, USA.
;;-----------------------------------------------------------------
;; Changes:
;; Aug 8 (gomes) Fixed syntax errors and updated error-message syntax
;;
;; (gomes) ;;;;;;;;;;;;; IMPORTANT PROBABLE ERROR ;;;;;;;;;;;;;;;;;;;;;
;; Added support for compilation mode. Had problems with the
;; standard compile.el (could not get it to handle the regexp for sather
;; error messages correctly - found a different one which worked much better.
;; Path is hard coded and WILL PROBABLY NEED TO BE RESET.
;; This should be the standard compile.el file, but it looks like there
;; is some problem at ICSI causing an older (epoch?) compile.el file to
;; be loaded.
;; If you have problems with the compilation mode - just delete the code
;; marked Compilation support (towards the end of this file)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Jun16 18:49 1994(gomes):Adding C-c C-w sather-which-class from hws
;; Jun 7 10:54 1994(gomes): Added old sather mode code to
;; document modifications. Doesn't work so well in lisp!
;; (gomes) Changed back copyright and end indentation (around line 228)
;; (gomes) Eliminated long copyright - should probably be put back....
;; (gomes) Added command to create type (in addition to create class)
;; (gomes) Jun 7: Changed the way end indents so that it lines up with the
;; rest of the block
;;
;; Major mode for editing Sather programs. (based on earlier Eiffel mode
;; including modifications made by Bob Weiner of Motorola.)
;;
;; The following two statements, placed in a .emacs file or site-init.el,
;; will cause this file to be autoloaded, and sather-mode invoked, when
;; visiting .sa files:
;;
;; (autoload 'sather-mode "sather.el" "Sather mode" t nil)
;; (setq auto-mode-alist
;; (append
;; (list (cons "\\.sa$" 'sather-mode))
;; auto-mode-alist))
(defvar sather-mode-map nil
"Keymap for Sather mode.")
(if sather-mode-map ()
(let ((map (make-sparse-keymap)))
(define-key map "\C-cw" 'sather-which-class)
(define-key map "\C-cc" 'sather-class)
(define-key map "\C-ct" 'sather-type)
(define-key map "\C-cm" 'doc-modification)
(define-key map "\t" 'sather-indent-line)
(define-key map [C-tab] 'sather-indent-line)
(define-key map "\r" 'sather-return)
(define-key map "\177" 'backward-delete-char-untabify)
(define-key map "\M-;" 'sather-comment)
(setq sather-mode-map map))
)
(defvar sather-mode-syntax-table nil
"Syntax table in use in Sather-mode buffers.")
(if sather-mode-syntax-table
()
(let ((table (make-syntax-table)))
(modify-syntax-entry ?\\ "\\" table)
(modify-syntax-entry ?/ ". 14" table)
(modify-syntax-entry ?* ". 23" table)
(modify-syntax-entry ?+ "." table)
(modify-syntax-entry ?- "." table)
(modify-syntax-entry ?= "." table)
(modify-syntax-entry ?% "." table)
(modify-syntax-entry ?< "." table)
(modify-syntax-entry ?> "." table)
(modify-syntax-entry ?& "." table)
(modify-syntax-entry ?| "." table)
(modify-syntax-entry ?\' "\"" table)
(setq sather-mode-syntax-table table)))
(defconst sather-indent 3
"*This variable gives the indentation in Sather-mode")
(defconst sather-comment-col 32
"*This variable gives the desired comment column for comments to the
right of text.")
(defvar sather-site "@icsi.berkeley.edu"
"*Mailing address of site where mode is being used. Should include
initial \@ sign. Use nil for none.")
(defvar sather-short-copyright
"-- Copyright (C) 1994, International Computer Science Institute\n"
"*Short copyright notice to be inserted in the header. Should be commented
and include trailing newline. Use nil for none.")
(defvar sather-long-copyright
"-- COPYRIGHT NOTICE: This code is provided WITHOUT ANY WARRANTY
-- and is subject to the terms of the SATHER LIBRARY GENERAL PUBLIC
-- LICENSE contained in the file: sather/doc/license.txt of the
-- Sather distribution. The license is also available from ICSI,
-- 1947 Center St., Suite 600, Berkeley CA 94704, USA. \n"
"*Long copyright notice to be inserted in the header. Should be commented
and have trailing newlines. Use nil for none.")
(defun sather-mode ()
"A major editing mode for the language Sather.
Comments are begun with --.
Paragraphs are separated by blank lines
Delete converts tabs to spaces as it moves back.
Tab anywhere on a line indents it according to Sather conventions.
M-; inserts and indents a comment on the line, or indents an existing
comment if there is one.
Return indents to the expected indentation for the new line. A class
skeleton is inserted (along with a file header if neccessary) with:
C-c c class
Variables controlling style:
sather-indent Indentation of Sather statements.
sather-comment-col Goal column for inline comments.
sather-site Mailing address of site for header.
sather-short-copyright Short copyright message for header.
sather-long-copyright Long copyright message for header.
Turning on Sather mode calls the value of the variable sather-mode-hook
with no args, if that value is non-nil."
(interactive)
(kill-all-local-variables)
(use-local-map sather-mode-map)
(setq major-mode 'sather-mode)
(setq mode-name "Sather")
(set-syntax-table sather-mode-syntax-table)
(make-local-variable 'indent-line-function)
(setq indent-line-function 'sather-indent-line)
(make-local-variable 'comment-start-skip)
(setq comment-start-skip "--+[ \t]*")
(make-local-variable 'comment-start)
(setq comment-start "--")
(make-local-variable 'paragraph-start)
(setq paragraph-start (concat "^$\\|" page-delimiter))
(make-local-variable 'paragraph-separate)
(setq paragraph-separate paragraph-start)
(make-local-variable 'paragraph-ignore-fill-prefix)
(setq paragraph-ignore-fill-prefix t)
(make-local-variable 'require-final-newline)
(setq require-final-newline t)
(run-hooks 'sather-mode-hook))
(defun sather-header ()
"Insert the file header at point."
(let ((header (read-string "File header: "
(concat "-- " (buffer-name) ": "))))
(insert header "\n"
"-- Author: " (user-full-name) " <" (user-login-name)
sather-site ">\n"
sather-short-copyright "-- $\Id$\n--\n" sather-long-copyright
"-------------------------------------------------------------------\n"
"-- Changes:\n"
"-------------------------------------------------------------------\n"
)))
;;(insert "-- Author: " (user-full-name) " <" (user-login-name) "> "
;; sather-short-copyright "-- $\Id$\n"
;;"-------------------------------------------------------------------\n"
;;"--Changes: \n"
;;"-------------------------------------------------------------------\n"
;;))
(defun sather-class ()
"Insert a 'class' template."
(interactive)
(if (not (s-empty-line-p))
(progn (end-of-line)(newline)))
(beginning-of-line)
(if (s-prev-class-p) nil (sather-header))
(let ((cname (read-string "Class: ")))
(insert
"class " (upcase cname) " is\n\n"
"end; -- class " (upcase cname) "\n\n"
"-------------------------------------------------------------------\n")
)
(re-search-backward "\nend")
(sather-indent-line))
(defun sather-type ()
"Insert a 'type' template."
(interactive)
(if (not (s-empty-line-p))
(progn (end-of-line)(newline)))
(beginning-of-line)
(if (s-prev-class-p) nil (sather-header))
(let ((cname (read-string "Type: ")))
(insert
"type " (upcase cname) " is\n\n"
"end; -- type " (upcase cname) "\n\n"
"-------------------------------------------------------------------\n")
)
(re-search-backward "\nend")
(sather-indent-line))
(defun s-prev-class-p ()
"True if there is a class definition before this one."
(interactive)
(save-excursion
(re-search-backward
"^[ \t]*\\(value class\\|abstract class\\|external class\\|class\\)\
[ \t\n]" nil t)))
(defun sather-return ()
"Return and Sather indent the new line."
(interactive)
(newline)
(sather-indent-line))
(defun sather-indent-line ()
"Indent the current line as Sather code."
(interactive)
(save-excursion
(beginning-of-line)
(delete-horizontal-space)
(indent-to (s-calc-indent)))
(skip-chars-forward " \t"))
;; A line is one of the following:
;; blank
;; just a comment
;; block-cont: starts with end, elsif, else, when, then, against
;; block-head: ends with is, or starts with if, loop, case, typecase,
;; assert, or protect.
;; none of the above
(defun s-calc-indent ()
"Return the appropriate indentation for this line as an int."
(cond
;; (
;; (s-starts-with-end-p)
;; (+ sather-indent (s-get-block-indent));Now end is in same col as block
;; )
((s-empty-line-p) ;an empty line
(+ sather-indent (s-get-block-indent))) ;go in one from block
((s-comment-line-p) ;a comment line
(s-comment-indent))
((s-starts-with-class-p) 0)
((s-starts-with-pre-p) (* 2 sather-indent))
((s-ends-with-is-p) sather-indent)
((s-block-cont-p) ;begins with block-cont keyword
(s-get-block-indent)) ;indent same as block
(t ;block-head or something else
(+ sather-indent (s-get-block-indent))))) ;go one in from block
(defun s-starts-with-class-p ()
"True if line starts with value class, type, external class or\
class."
(save-excursion
(beginning-of-line)
(looking-at "^[ \t]*\\(value class\\|type\\|external class\
\\|class\\)[ \t\n]")))
(defun s-starts-with-end-p ()
"True if line starts with keyword end"
(save-excursion
(beginning-of-line)
(looking-at "^[ \t]*end")))
(defun s-special-match-class-begin-p ()
"True if part of extended class beginning."
(interactive)
(save-excursion
(let ((pt0 (point))
(pt1
(re-search-backward "^[ \t]*\\(value class\\|type\\|external class\
\\|class\\)[ \t\n]"))
(pt2 (re-search-forward "\\( is\\)")))
(if (= pt0 (- pt2 2)) 1 nil))))
(defun s-starts-with-pre-p ()
"True if line starts with either pre or post."
(save-excursion
(beginning-of-line)
(looking-at "^[ \t]*\\(pre\\|post\\)[ \t\n]")))
(defun sather-comment ()
"Edit a comment on the line. If one exists, reindents it and moves to
it, otherwise creates one. Gets rid of trailing blanks, puts one space
between comment header comment text, leaves point at front of comment.
If comment is alone on a line it reindents relative to surrounding text.
If it is before any code, it is put at the line beginning. Uses the
variable sather-comment-col to set goal start on lines after text."
(interactive)
(cond ((s-comment-line-p) ;just a comment on the line
(beginning-of-line)
(delete-horizontal-space)
(indent-to (s-comment-indent))
(forward-char 2)(delete-horizontal-space)(insert " "))
((s-comment-on-line-p) ;comment already at end of line
(cond ((s-ends-with-end-p) ;end comments come immediately
(s-goto-comment-beg)(delete-horizontal-space)(insert " ")
(forward-char 2)(delete-horizontal-space)(insert " "))
(t
(s-goto-comment-beg)(delete-horizontal-space)
(if (< (current-column) sather-comment-col)
(indent-to sather-comment-col)
(insert " "))
(forward-char 2)
(delete-horizontal-space)
(insert " "))))
((s-empty-line-p) ;put just a comment on line
(beginning-of-line)
(delete-horizontal-space)
(indent-to (s-comment-indent))
(insert "-- "))
((s-ends-with-end-p) ;end comments come immediately
(end-of-line)(delete-horizontal-space)(insert " -- "))
(t ;put comment at end of line
(end-of-line)
(delete-horizontal-space)
(if (< (current-column) sather-comment-col)
(indent-to sather-comment-col)
(insert " "))
(insert "-- "))))
(defun s-ends-with-end-p ()
"t if line ends with 'end' or 'end;' and a comment."
(save-excursion
(beginning-of-line)
(looking-at "^\\(.*[ \t]+\\)?end;?[ \t]*\\($\\|--\\)")))
(defun s-empty-line-p ()
"True if current line is empty."
(save-excursion
(beginning-of-line)
(looking-at "^[ \t]*$")))
(defun s-comment-line-p ()
"t if current line is just a comment."
(save-excursion
(beginning-of-line)
(skip-chars-forward " \t")
(looking-at "--")))
(defun s-comment-on-line-p ()
"t if current line contains a comment."
(save-excursion
(beginning-of-line)
(looking-at "[^\n]*--")))
(defun s-in-comment-p ()
"t if point is in a comment."
(save-excursion
(and (/= (point) (point-max)) (forward-char 1))
(search-backward "--" (save-excursion (beginning-of-line)
(point)) t)))
(defun s-current-indentation ()
"Returns current line indentation."
(save-excursion
(beginning-of-line)
(skip-chars-forward " \t")
(current-indentation)))
(defun s-goto-comment-beg ()
"Point to beginning of comment on line. Assumes line contains a
comment."
(beginning-of-line)
(search-forward "--" nil t)
(backward-char 2))
(defun s-block-cont-p ()
"t if line continues the indentation of enclosing block. Begins with
end, elsif, else, when, then, or against."
(save-excursion
(beginning-of-line)
(looking-at "^[ \t]*\\(end\\|elsif\\|else\\|when\\|then\\|against\\)\
[ ;\t\n]")))
(defun s-ends-with-is-p ()
"t if current line ends with the keyword 'is' and an optional comment."
(save-excursion
(end-of-line)
(let ((end (point)))
(beginning-of-line)
(re-search-forward "\\(^\\|[ \t]\\)is[ \t]*\\($\\|--\\)" end t))))
(defun s-move-to-prev-non-comment ()
"Moves point to previous line excluding comment lines and blank lines.
Returns t if successful, nil if not."
(beginning-of-line)
(re-search-backward "^[ \t]*\\([^ \t---\n]\\|-[^---]\\)" nil t))
(defun s-move-to-prev-non-blank ()
"Moves point to previous line excluding blank lines.
Returns t if successful, nil if not."
(beginning-of-line)
(re-search-backward "^[ \t]*[^ \t\n]" nil t))
(defun s-comment-indent ()
"Return indentation for a comment line."
(save-excursion
(let ((in (s-get-block-indent))
(prev-is-blank
(save-excursion (and (= (forward-line -1) 0)
(s-empty-line-p)))))
(if (or (and prev-is-blank (= in 0))
;move to prev line if there is one
(not (s-move-to-prev-non-blank)))
0 ;early comments start to the left
(cond ((s-ends-with-is-p) ;line ends in 'is,' indent twice
(+ sather-indent (s-current-indentation)))
((s-comment-line-p) ;is a comment, same indentation
(s-current-indentation))
(t ;otherwise indent once
(+ sather-indent (s-current-indentation))))))))
(defun s-quoted-string-on-line-p ()
"t if a Sather quoted string begins, ends, or is continued on current
line."
(save-excursion
(beginning-of-line)
;; Line must either start with optional whitespace immediately
;; followed by a '\\' or include a '\"'. It must either end with a
;; '\\' character or must include a second '\"' character.
(looking-at "^\\([ \t]*\\\\\\|[^\"\n]*\"\\)[^\"\n]*\\(\\\\$\\|\"\\)")))
(defun s-in-quoted-string-p ()
"t if point is in a quoted string."
(let ((pt (point)) front)
(save-excursion
;; Line must either start with optional whitespace immediately
;; followed by a '\\' or include a '\"'.
(if (re-search-backward "\\(^[ \t]*\\\\\\|\"\\)"
(save-excursion (beginning-of-line)
(point)) t)
(progn (setq front (point))
(forward-char 1)
;; Line must either end with a '\\' character or must
;; include a second '\"' character.
(and (re-search-forward
"\\(\\\\$\\|\"\\)"
(save-excursion (end-of-line) (point)) t)
(>= (point) pt)
(<= front pt)
t)))
)))
(defun s-get-block-indent ()
"Return the outer indentation of the current block. Returns 0 or less
if it can't find one. Looks for first unpaired is, if, loop, case,
typecase, or protect."
(save-excursion
(let ((depth 1))
(while (and (> depth 0)
;; Search for start of keyword
(re-search-backward
"\\(^\\|[ \t]\\)\\(is[ \t]*\\($\\|--\\)\\|if \\|loop\
\\|case \\|typecase \\|protect\\|end\\)" nil t))
(goto-char (match-beginning 2))
(cond ((or (s-in-comment-p)
;;(s-in-quoted-string-p) leave out for now
)
nil) ;ignore it
((looking-at "end") ;end of block
(setq depth (1+ depth)))
((looking-at "is")
(cond ((s-special-match-class-begin-p) (setq depth -2))
((= depth 1)(setq depth -1))
(t (setq depth -2))))
(t ;head of block
(setq depth (1- depth)))))
(cond ((> depth 0) ;check whether we hit top of file
0)
((= depth -1) ;Hit an "is" in a routine def
sather-indent)
((= depth -2) ;Hit class def or outside rout
0)
(t (current-indentation))))))
(defun doc-modification (EXPLICIT)
"Insert a brief modification log at the top of the buffer. Looks for
an occurrence of the value of user variable doc-modifications-keyword
if non-nil."
(interactive "P")
(beginning-of-buffer)
(cond ((re-search-forward "Changes:") nil t)) (end-of-line)
(insert "\n--*" (brief-current-time-string) "("(user-login-name) "):")
)
(defun brief-current-time-string ()
(let ((decoded-time (get-decoded-time)))
(format "%s%s %s:%s %s"
(nth 4 decoded-time) ;month
(nth 3 decoded-time) ;date
(nth 2 decoded-time) ;hour
(nth 1 decoded-time) ;minute
(nth 5 decoded-time) ;year
)))
(defun get-decoded-time ()
"Return the current time as a list of strings representing:
second, minute, hour, date, month, year, day-of-week, and the
full time-string."
;;"Sat Jan 12 18:22:40 1991"
;; 012345678901234567890123
;; 1 2
(let ((time-string (current-time-string)))
(list (substring time-string 17 19)
(substring time-string 14 16)
(substring time-string 11 13)
(substring time-string 8 10)
(substring time-string 4 7)
(substring time-string 20 24)
(substring time-string 0 3)
time-string)))
(defun sather-which-class ()
(interactive)
(save-excursion
(re-search-backward "\\(class \\|type \\)")
(message (buffer-substring (point) (progn (end-of-line) (point))))
)
)
;;;;;;;;;;;;;;;;;;;;;;; Compilation Support ;;;;;;;;;;;;;;;;;;;;
;; May cause problems - Has not been used with the latest
;; version of the compiler. Will update it when I get around to
;; using it again!
;; Deleting this whole section should let the rest work fine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq compile-file "/usr/local/share/lib/emacs/19.25/lisp/compile.el")
(setq compile-sather "cs -com .commands")
(if (file-exists-p compile-file)
(progn
(load compile-file)
(setq sather-error-regexp '("Error in file: \\([^,]+\\), line: +\\([0-9]+\\), character no: \\([0-9]+\\)" 1 2 3))
(setq compilation-error-regexp-alist (cons sather-error-regexp compilation-error-regexp-alist))
(setq compile-command compile-sather)
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(provide 'sather-mode)