(delphi-token-at): Give newlines precedence over literal tokens when
[bpt/emacs.git] / lisp / progmodes / prolog.el
CommitLineData
6594deb0
ER
1;;; prolog.el --- major mode for editing and running Prolog under Emacs
2
1ba983e8 3;; Copyright (C) 1986, 1987, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
114f9c96 4;; 2008, 2009, 2010 Free Software Foundation, Inc.
9750e079 5
0acdb863 6;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
d7b4d18f 7;; Keywords: languages
e5167999 8
d8025917 9;; This file is part of GNU Emacs.
10
b1fc2b50 11;; GNU Emacs is free software: you can redistribute it and/or modify
d8025917 12;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
d8025917 15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b1fc2b50 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
d8025917 23
edbd2f74
ER
24;;; Commentary:
25
26;; This package provides a major mode for editing Prolog. It knows
27;; about Prolog syntax and comments, and can send regions to an inferior
f614a1ae 28;; Prolog interpreter process. Font locking is tuned towards GNU Prolog.
edbd2f74 29
e5167999
ER
30;;; Code:
31
3cd79f62
DN
32(defvar comint-prompt-regexp)
33(defvar comint-process-echoes)
5d8fe0ba 34(defvar smie-indent-basic)
4e186ad5 35
c5292bc8 36(defgroup prolog nil
73efac49 37 "Major mode for editing and running Prolog under Emacs."
8ec3bce0 38 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
c5292bc8
RS
39 :group 'languages)
40
f614a1ae 41
6cfd4f3a 42(defcustom prolog-program-name
d364dee6 43 (let ((names '("prolog" "gprolog" "swipl")))
6cfd4f3a
SM
44 (while (and names
45 (not (executable-find (car names))))
46 (setq names (cdr names)))
47 (or (car names) "prolog"))
d364dee6 48 "Program name for invoking an inferior Prolog with `run-prolog'."
c5292bc8
RS
49 :type 'string
50 :group 'prolog)
d8025917 51
c5292bc8 52(defcustom prolog-consult-string "reconsult(user).\n"
d364dee6 53 "(Re)Consult mode (for C-Prolog and Quintus Prolog). "
c5292bc8
RS
54 :type 'string
55 :group 'prolog)
d8025917 56
c5292bc8 57(defcustom prolog-compile-string "compile(user).\n"
d364dee6 58 "Compile mode (for Quintus Prolog)."
c5292bc8
RS
59 :type 'string
60 :group 'prolog)
d8025917 61
c5292bc8 62(defcustom prolog-eof-string "end_of_file.\n"
d364dee6 63 "String that represents end of file for Prolog.
c6c5714e 64When nil, send actual operating system end of file."
c5292bc8
RS
65 :type 'string
66 :group 'prolog)
d8025917 67
c5292bc8
RS
68(defcustom prolog-indent-width 4
69 "Level of indentation in Prolog buffers."
70 :type 'integer
71 :group 'prolog)
d8025917 72
f614a1ae
TTN
73(defvar prolog-font-lock-keywords
74 '(("\\(#[<=]=>\\|:-\\)\\|\\(#=\\)\\|\\(#[#<>\\/][=\\/]*\\|!\\)"
75 0 font-lock-keyword-face)
76 ("\\<\\(is\\|write\\|nl\\|read_\\sw+\\)\\>"
77 1 font-lock-keyword-face)
78 ("^\\(\\sw+\\)\\s-*\\((\\(.+\\))\\)*"
79 (1 font-lock-function-name-face)
80 (3 font-lock-variable-name-face)))
81 "Font-lock keywords for Prolog mode.")
82
6cfd4f3a 83(defvar prolog-mode-syntax-table
d8025917 84 (let ((table (make-syntax-table)))
85 (modify-syntax-entry ?_ "w" table)
86 (modify-syntax-entry ?\\ "\\" table)
f614a1ae
TTN
87 (modify-syntax-entry ?/ ". 14" table)
88 (modify-syntax-entry ?* ". 23" table)
d8025917 89 (modify-syntax-entry ?+ "." table)
90 (modify-syntax-entry ?- "." table)
91 (modify-syntax-entry ?= "." table)
92 (modify-syntax-entry ?% "<" table)
673f4fc6 93 (modify-syntax-entry ?\n ">" table)
d8025917 94 (modify-syntax-entry ?< "." table)
95 (modify-syntax-entry ?> "." table)
96 (modify-syntax-entry ?\' "\"" table)
6cfd4f3a 97 table))
d8025917 98
6cfd4f3a 99(defvar prolog-mode-abbrev-table nil)
d8025917 100(define-abbrev-table 'prolog-mode-abbrev-table ())
101
5ad4bef5
SM
102(defconst prolog-smie-op-levels
103 ;; Rather than construct the operator levels table from the BNF,
104 ;; we directly provide the operator precedences from GNU Prolog's
105 ;; manual. The only problem is that GNU Prolog's manual uses
106 ;; precedence levels in the opposite sense (higher numbers bind less
107 ;; tightly) than SMIE, so we use negative numbers.
108 '(("." -10000 -10000)
109 (":-" -1200 -1200)
110 ("-->" -1200 -1200)
111 (";" -1100 -1100)
112 ("->" -1050 -1050)
113 ("," -1000 -1000)
114 ("\\+" -900 -900)
115 ("=" -700 -700)
116 ("\\=" -700 -700)
117 ("=.." -700 -700)
118 ("==" -700 -700)
119 ("\\==" -700 -700)
120 ("@<" -700 -700)
121 ("@=<" -700 -700)
122 ("@>" -700 -700)
123 ("@>=" -700 -700)
124 ("is" -700 -700)
125 ("=:=" -700 -700)
126 ("=\\=" -700 -700)
127 ("<" -700 -700)
128 ("=<" -700 -700)
129 (">" -700 -700)
130 (">=" -700 -700)
131 (":" -600 -600)
132 ("+" -500 -500)
133 ("-" -500 -500)
134 ("/\\" -500 -500)
135 ("\\/" -500 -500)
136 ("*" -400 -400)
137 ("/" -400 -400)
138 ("//" -400 -400)
139 ("rem" -400 -400)
140 ("mod" -400 -400)
141 ("<<" -400 -400)
142 (">>" -400 -400)
143 ("**" -200 -200)
144 ("^" -200 -200)
145 ;; Prefix
146 ;; ("+" 200 200)
147 ;; ("-" 200 200)
148 ;; ("\\" 200 200)
149 )
150 "Precedence levels of infix operators.")
151
152(defconst prolog-smie-indent-rules
153 '((":-")
154 ("->"))
155 "Prolog indentation rules.")
156
d8025917 157(defun prolog-mode-variables ()
d8025917 158 (make-local-variable 'paragraph-separate)
6cfd4f3a 159 (setq paragraph-separate (concat "%%\\|$\\|" page-delimiter)) ;'%%..'
d8025917 160 (make-local-variable 'paragraph-ignore-fill-prefix)
161 (setq paragraph-ignore-fill-prefix t)
2c239c80 162 (make-local-variable 'imenu-generic-expression)
d8059b03 163 (setq imenu-generic-expression '((nil "^\\sw+" 0)))
5ad4bef5
SM
164 (smie-setup prolog-smie-op-levels prolog-smie-indent-rules)
165 (set (make-local-variable 'forward-sexp-function)
166 'smie-forward-sexp-command)
167 (set (make-local-variable 'smie-indent-basic) prolog-indent-width)
d8025917 168 (make-local-variable 'comment-start)
169 (setq comment-start "%")
170 (make-local-variable 'comment-start-skip)
6cfd4f3a
SM
171 (setq comment-start-skip "\\(?:%+\\|/\\*+\\)[ \t]*")
172 (make-local-variable 'comment-end-skip)
173 (setq comment-end-skip "[ \t]*\\(\n\\|\\*+/\\)")
d8025917 174 (make-local-variable 'comment-column)
6cfd4f3a 175 (setq comment-column 48))
d8025917 176
6cfd4f3a
SM
177(defvar prolog-mode-map
178 (let ((map (make-sparse-keymap)))
179 (define-key map "\e\C-x" 'prolog-consult-region)
d364dee6
SM
180 (define-key map "\C-c\C-l" 'inferior-prolog-load-file)
181 (define-key map "\C-c\C-z" 'switch-to-prolog)
6cfd4f3a 182 map))
5d8fe0ba 183
d364dee6
SM
184(easy-menu-define prolog-mode-menu prolog-mode-map "Menu for Prolog mode."
185 ;; Mostly copied from scheme-mode's menu.
186 ;; Not tremendously useful, but it's a start.
187 '("Prolog"
188 ["Indent line" indent-according-to-mode t]
189 ["Indent region" indent-region t]
190 ["Comment region" comment-region t]
191 ["Uncomment region" uncomment-region t]
192 "--"
193 ["Run interactive Prolog session" run-prolog t]
194 ))
d8025917 195
f9f9507e 196;;;###autoload
13973643 197(define-derived-mode prolog-mode prog-mode "Prolog"
d8025917 198 "Major mode for editing Prolog code for Prologs.
199Blank lines and `%%...' separate paragraphs. `%'s start comments.
200Commands:
201\\{prolog-mode-map}
573f9b32 202Entry to this mode calls the value of `prolog-mode-hook'
d8025917 203if that value is non-nil."
d8025917 204 (prolog-mode-variables)
d364dee6 205 (set (make-local-variable 'comment-add) 1)
f614a1ae
TTN
206 (setq font-lock-defaults '(prolog-font-lock-keywords
207 nil nil nil
13973643 208 beginning-of-line)))
d8025917 209
d8025917 210(defun end-of-prolog-clause ()
211 "Go to end of clause in this line."
212 (beginning-of-line 1)
213 (let* ((eolpos (save-excursion (end-of-line) (point))))
214 (if (re-search-forward comment-start-skip eolpos 'move)
215 (goto-char (match-beginning 0)))
216 (skip-chars-backward " \t")))
d8025917 217\f
218;;;
219;;; Inferior prolog mode
220;;;
6cfd4f3a
SM
221(defvar inferior-prolog-mode-map
222 (let ((map (make-sparse-keymap)))
223 ;; This map will inherit from `comint-mode-map' when entering
224 ;; inferior-prolog-mode.
23f2d048
SM
225 (define-key map [remap self-insert-command]
226 'inferior-prolog-self-insert-command)
6cfd4f3a
SM
227 map))
228
229(defvar inferior-prolog-mode-syntax-table prolog-mode-syntax-table)
230(defvar inferior-prolog-mode-abbrev-table prolog-mode-abbrev-table)
d8025917 231
28930e39
SM
232(defvar inferior-prolog-error-regexp-alist
233 ;; GNU Prolog used to not follow the GNU standard format.
234 '(("^\\(.*?\\):\\([0-9]+\\) error: .*(char:\\([0-9]+\\)" 1 2 3)
235 gnu))
236
5cec3056
GM
237(declare-function comint-mode "comint")
238(declare-function comint-send-string "comint" (process string))
239(declare-function comint-send-region "comint" (process start end))
240(declare-function comint-send-eof "comint" ())
a569b480 241(defvar compilation-error-regexp-alist)
153ef845 242
6cfd4f3a 243(define-derived-mode inferior-prolog-mode comint-mode "Inferior Prolog"
d8025917 244 "Major mode for interacting with an inferior Prolog process.
245
246The following commands are available:
247\\{inferior-prolog-mode-map}
248
573f9b32
RS
249Entry to this mode calls the value of `prolog-mode-hook' with no arguments,
250if that value is non-nil. Likewise with the value of `comint-mode-hook'.
251`prolog-mode-hook' is called after `comint-mode-hook'.
d8025917 252
c647adda
JB
253You can send text to the inferior Prolog from other buffers using the commands
254`process-send-region', `process-send-string' and \\[prolog-consult-region].
d8025917 255
256Commands:
257Tab indents for Prolog; with argument, shifts rest
258 of expression rigidly with the current line.
573f9b32
RS
259Paragraphs are separated only by blank lines and '%%'.
260'%'s start comments.
d8025917 261
262Return at end of buffer sends line as input.
263Return not at end copies rest of line to end and sends it.
264\\[comint-kill-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing.
265\\[comint-interrupt-subjob] interrupts the shell or its current subjob if any.
266\\[comint-stop-subjob] stops. \\[comint-quit-subjob] sends quit signal."
6cfd4f3a 267 (setq comint-prompt-regexp "^| [ ?][- ] *")
28930e39
SM
268 (set (make-local-variable 'compilation-error-regexp-alist)
269 inferior-prolog-error-regexp-alist)
270 (compilation-shell-minor-mode)
6cfd4f3a 271 (prolog-mode-variables))
d8025917 272
d364dee6
SM
273(defvar inferior-prolog-buffer nil)
274
7caf6803
DN
275(defvar inferior-prolog-flavor 'unknown
276 "Either a symbol or a buffer position offset by one.
277If a buffer position, the flavor has not been determined yet and
278it is expected that the process's output has been or will
279be inserted at that position plus one.")
280
d364dee6
SM
281(defun inferior-prolog-run (&optional name)
282 (with-current-buffer (make-comint "prolog" (or name prolog-program-name))
283 (inferior-prolog-mode)
284 (setq-default inferior-prolog-buffer (current-buffer))
285 (make-local-variable 'inferior-prolog-buffer)
286 (when (and name (not (equal name prolog-program-name)))
287 (set (make-local-variable 'prolog-program-name) name))
288 (set (make-local-variable 'inferior-prolog-flavor)
289 ;; Force re-detection.
290 (let* ((proc (get-buffer-process (current-buffer)))
291 (pmark (and proc (marker-position (process-mark proc)))))
292 (cond
293 ((null pmark) (1- (point-min)))
294 ;; The use of insert-before-markers in comint.el together with
295 ;; the potential use of comint-truncate-buffer in the output
296 ;; filter, means that it's difficult to reliably keep track of
297 ;; the buffer position where the process's output started.
298 ;; If possible we use a marker at "start - 1", so that
299 ;; insert-before-marker at `start' won't shift it. And if not,
300 ;; we fall back on using a plain integer.
301 ((> pmark (point-min)) (copy-marker (1- pmark)))
302 (t (1- pmark)))))
303 (add-hook 'comint-output-filter-functions
304 'inferior-prolog-guess-flavor nil t)))
305
306(defun inferior-prolog-process (&optional dontstart)
307 (or (and (buffer-live-p inferior-prolog-buffer)
308 (get-buffer-process inferior-prolog-buffer))
309 (unless dontstart
310 (inferior-prolog-run)
311 ;; Try again.
312 (inferior-prolog-process))))
313
23f2d048
SM
314(defun inferior-prolog-guess-flavor (&optional ignored)
315 (save-excursion
316 (goto-char (1+ inferior-prolog-flavor))
317 (setq inferior-prolog-flavor
318 (cond
319 ((looking-at "GNU Prolog") 'gnu)
320 ((looking-at "Welcome to SWI-Prolog") 'swi)
321 ((looking-at ".*\n") 'unknown) ;There's at least one line.
322 (t inferior-prolog-flavor))))
323 (when (symbolp inferior-prolog-flavor)
324 (remove-hook 'comint-output-filter-functions
325 'inferior-prolog-guess-flavor t)
326 (if (eq inferior-prolog-flavor 'gnu)
327 (set (make-local-variable 'comint-process-echoes) t))))
328
f9f9507e 329;;;###autoload
d364dee6
SM
330(defalias 'run-prolog 'switch-to-prolog)
331;;;###autoload
332(defun switch-to-prolog (&optional name)
333 "Run an inferior Prolog process, input and output via buffer *prolog*.
334With prefix argument \\[universal-prefix], prompt for the program to use."
335 (interactive
336 (list (when current-prefix-arg
337 (let ((proc (inferior-prolog-process 'dontstart)))
338 (if proc
339 (if (yes-or-no-p "Kill current process before starting new one? ")
340 (kill-process proc)
341 (error "Abort")))
342 (read-string "Run Prolog: " prolog-program-name)))))
343 (unless (inferior-prolog-process 'dontstart)
344 (inferior-prolog-run name))
345 (pop-to-buffer inferior-prolog-buffer))
d8025917 346
23f2d048
SM
347(defun inferior-prolog-self-insert-command ()
348 "Insert the char in the buffer or pass it directly to the process."
349 (interactive)
350 (let* ((proc (get-buffer-process (current-buffer)))
351 (pmark (and proc (marker-position (process-mark proc)))))
352 (if (and (eq inferior-prolog-flavor 'gnu)
353 pmark
354 (null current-prefix-arg)
355 (eobp)
356 (eq (point) pmark)
357 (save-excursion
358 (goto-char (- pmark 3))
359 (looking-at " \\? ")))
28930e39
SM
360 ;; This is GNU prolog waiting to know whether you want more answers
361 ;; or not (or abort, etc...). The answer is a single char, not
362 ;; a line, so pass this char directly rather than wait for RET to
363 ;; send a whole line.
1ba983e8 364 (comint-send-string proc (string last-command-event))
23f2d048
SM
365 (call-interactively 'self-insert-command))))
366
d8025917 367(defun prolog-consult-region (compile beg end)
573f9b32
RS
368 "Send the region to the Prolog process made by \"M-x run-prolog\".
369If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
d8025917 370 (interactive "P\nr")
d364dee6
SM
371 (let ((proc (inferior-prolog-process)))
372 (comint-send-string proc
373 (if compile prolog-compile-string
374 prolog-consult-string))
375 (comint-send-region proc beg end)
376 (comint-send-string proc "\n") ;May be unnecessary
d8025917 377 (if prolog-eof-string
d364dee6
SM
378 (comint-send-string proc prolog-eof-string)
379 (with-current-buffer (process-buffer proc)
380 (comint-send-eof))))) ;Send eof to prolog process.
d8025917 381
382(defun prolog-consult-region-and-go (compile beg end)
383 "Send the region to the inferior Prolog, and switch to *prolog* buffer.
573f9b32 384If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
d8025917 385 (interactive "P\nr")
386 (prolog-consult-region compile beg end)
23f2d048 387 (pop-to-buffer inferior-prolog-buffer))
6594deb0 388
a569b480
GM
389;; inferior-prolog-mode uses the autoloaded compilation-shell-minor-mode.
390(declare-function compilation-forget-errors "compile" ())
391
d364dee6
SM
392(defun inferior-prolog-load-file ()
393 "Pass the current buffer's file to the inferior prolog process."
394 (interactive)
395 (save-buffer)
396 (let ((file buffer-file-name)
397 (proc (inferior-prolog-process)))
398 (with-current-buffer (process-buffer proc)
28930e39 399 (compilation-forget-errors)
d364dee6
SM
400 (comint-send-string proc (concat "['" (file-relative-name file) "'].\n"))
401 (pop-to-buffer (current-buffer)))))
402
896546cd
RS
403(provide 'prolog)
404
d364dee6 405;; arch-tag: f3ec6748-1272-4ab6-8826-c50cb1607636
6594deb0 406;;; prolog.el ends here