1 ;;; An indentation engine for gpr mode, using the wisent LALR parser
3 ;; [1] GNAT user guide (info "gnat_ugn")
5 ;; Copyright (C) 2013, 2014 Free Software Foundation, Inc.
7 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
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.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;;; History: first version Jan 2013
28 ;; I don't use 'pcase', because it gives _really_ confusing errors
29 ;; when I forget a ')' somewhere. Even worse, the error message is
30 ;; given when you use edebug on a defun, not when you eval it. This
31 ;; code is hard enough to debug!
35 ;; we reuse some stuff from ada-mode
36 (require 'ada-indent-user-options)
37 (require 'gpr-grammar-wy)
41 (defconst gpr-wisi-class-list
54 (defun gpr-wisi-indent-cache (offset cache)
55 "Return indentation of OFFSET relative to indentation of line containing CACHE
56 or containing ancestor of CACHE that is at a line beginning."
57 (let ((indent (current-indentation)))
59 (not (= (current-column) indent)))
60 (when (eq 'WHEN (wisi-cache-token cache))
61 (setq offset (+ offset ada-indent-when)))
62 (setq cache (wisi-goto-containing cache))
63 (setq indent (current-indentation)))
64 (+ (current-indentation) offset)
67 (defun gpr-wisi-indent-containing (offset cache)
68 "Return indentation of OFFSET relative to containing ancestor of CACHE that is at a line beginning."
69 (gpr-wisi-indent-cache offset (wisi-goto-containing cache)))
71 (defun gpr-wisi-before-cache ()
72 (let ((cache (wisi-get-cache (point))))
74 (cl-ecase (wisi-cache-class cache)
75 (block-start (wisi-indent-start ada-indent (wisi-backward-cache)))
76 (block-end (wisi-indent-start 0 cache))
79 (if (eq (wisi-cache-token cache) 'WHEN) ada-indent-when 0)
80 ;; FIXME (later): need test of ada-indent-when in gpr
82 (close-paren (wisi-indent-paren 0))
83 (open-paren nil); let after-keyword handle it
85 (if (not (wisi-get-containing-cache cache))
89 (gpr-wisi-indent-containing ada-indent cache)))
92 (gpr-wisi-indent-containing ada-indent-broken cache))
96 (defun gpr-wisi-after-cache ()
97 (let ((cache (wisi-backward-cache)))
101 (cl-ecase (wisi-cache-class cache)
103 (wisi-indent-current 0))
106 (cl-case (wisi-cache-token cache)
108 (gpr-wisi-indent-cache ada-indent-broken cache))
110 (gpr-wisi-indent-cache ada-indent cache))
114 (cl-case (wisi-cache-token cache)
116 (gpr-wisi-indent-containing ada-indent cache))
118 (gpr-wisi-indent-cache ada-indent cache))
122 ;; test/gpr/simple.gpr
123 ;; type GNAT_Version_Type
126 ;; "GPL-2012", "GPL-2011");
128 ;; for Source_Dirs use
130 ;; External ("GNAT_VERSION") & "/foo",
132 (wisi-goto-containing cache)
133 (1+ (current-column)))
136 (1+ (current-column)))
139 (wisi-indent-start 0 cache))
141 ((statement-other close-paren)
142 ;; test/gpr/simple.gpr
144 ;; & Standard_Common.Compiler'Default_Switches;
146 ;; for Source_Dirs use
148 (wisi-indent-start ada-indent-broken cache))
151 ;; test/gpr/simple.gpr
152 ;; type GNAT_Version_Type
155 (gpr-wisi-indent-cache ada-indent-broken cache))
159 (defun gpr-wisi-post-parse-fail ()
160 "For `wisi-post-parse-fail-hook'."
164 (defun gpr-wisi-which-function ()
165 "For `gpr-which-function'."
166 (wisi-validate-cache (point))
167 (let ((cache (wisi-backward-cache)))
170 (memq (wisi-cache-nonterm cache) '(package_spec simple_project_declaration))
171 (eq (wisi-cache-class cache) 'statement-start))))
172 (setq cache (wisi-goto-containing cache)))
174 (wisi-forward-token); package | project
175 (wisi-token-text (wisi-forward-token)); name
179 (defun gpr-wisi-debug-keys ()
180 "Add debug key definitions to `gpr-mode-map'."
182 (define-key gpr-mode-map "\M-h" 'wisi-show-containing-or-previous-cache)
183 (define-key gpr-mode-map "\M-j" 'wisi-show-cache)
184 (define-key gpr-mode-map "\M-k" 'wisi-show-token)
188 (defun gpr-wisi-setup ()
189 "Set up a buffer for parsing Ada files with wisi."
190 (wisi-setup '(gpr-wisi-before-cache
191 gpr-wisi-after-cache)
192 'gpr-wisi-post-parse-fail
194 gpr-grammar-wy--keyword-table
195 gpr-grammar-wy--token-table
196 gpr-grammar-wy--parse-table)
198 (setq gpr-indent-statement 'wisi-indent-statement)
199 (set (make-local-variable 'comment-indent-function) 'wisi-comment-indent)
202 (add-hook 'gpr-mode-hook 'gpr-wisi-setup)
204 (setq gpr-which-function 'gpr-wisi-which-function)
206 (setq gpr-show-parse-error 'wisi-show-parse-error)
209 (provide 'gpr-indent-engine)