]> code.delx.au - gnu-emacs-elpa/blob - packages/ada-mode/ada-wisi.el
ada-mode 5.1.3, wisi 1.0.4
[gnu-emacs-elpa] / packages / ada-mode / ada-wisi.el
1 ;;; An indentation engine for Ada mode, using the wisi generalized LALR parser
2 ;;
3 ;; [1] ISO/IEC 8652:2012(E); Ada 2012 reference manual
4 ;;
5 ;; Copyright (C) 2012 - 2014 Free Software Foundation, Inc.
6 ;;
7 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
8 ;;
9 ;; This file is part of GNU Emacs.
10 ;;
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.
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
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23 ;;
24 ;;; History:
25 ;;
26 ;; implementation started Jan 2013
27 ;;
28 ;;;;
29
30 (require 'ada-fix-error)
31 (require 'ada-grammar-wy)
32 (require 'ada-indent-user-options)
33 (require 'cl-lib)
34 (require 'wisi)
35
36 (defconst ada-wisi-class-list
37 '(
38 block-end
39 block-middle ;; not start of statement
40 block-start ;; start of block is start of statement
41 close-paren
42 list-break
43 name
44 name-paren ;; anything that looks like a procedure call, since the grammar can't distinguish most of them
45 open-paren
46 return
47 return-1
48 return-2
49 statement-end
50 statement-other
51 statement-start
52 type
53 ))
54
55 ;;;; indentation
56
57 (defun ada-wisi-current-indentation ()
58 "Return indentation of current line, incremented by 1 if starts with open-paren."
59 (if (not (ada-in-paren-p))
60 (current-indentation)
61
62 (save-excursion
63 (back-to-indentation)
64 (let ((cache (wisi-get-cache (point))))
65 (if (and cache
66 (eq 'open-paren (wisi-cache-class cache)))
67 (1+ (current-column))
68 (current-column))
69 ))))
70
71 (defun ada-wisi-indent-cache (offset cache)
72 "Return indentation of OFFSET plus indentation of line containing point. Point must be at CACHE."
73 (let ((indent (current-indentation)))
74 (cond
75 ;; special cases
76 ;;
77 ((eq 'LEFT_PAREN (wisi-cache-token cache))
78 ;; test/ada_mode-long_paren.adb
79 ;; (RT => RT,
80 ;; Monitor => True,
81 ;; RX_Enable =>
82 ;; (RX_Torque_Subaddress |
83 ;; indenting '(RX_'
84 ;;
85 ;; test/ada_mode-parens.adb
86 ;; return Float (
87 ;; Integer'Value
88 ;; (Local_6));
89 ;; indenting '(local_6)'; 'offset' = ada-indent - 1
90 (+ (current-column) 1 offset))
91
92 ((save-excursion
93 (let ((containing (wisi-goto-containing-paren cache)))
94 (and containing
95 ;; test/ada_mode-conditional_expressions.adb
96 ;; K2 : Integer := (if J > 42
97 ;; then -1
98 ;; indenting 'then'; offset = 0
99 ;;
100 ;; L1 : Integer := (case J is
101 ;; when 42 => -1,
102 ;;
103 ;; test/indent.ads
104 ;; C_S_Controls : constant
105 ;; CSCL_Type :=
106 ;; CSCL_Type'
107 ;; (
108 ;; 1 => -- Used to be aligned on "CSCL_Type'"
109 ;; -- aligned with previous comment.
110 ;; IO_CPU_Control_State_S_Pkg.CPU2_Fault_Status_Type'
111 ;; (Unused2 => 10, -- Used to be aligned on "1 =>"
112 ;; indenting '(Unused2'
113 (+ (current-column) offset)))))
114
115 ;; all other structures
116 (t
117 ;; current cache may be preceded by something on same
118 ;; line. Handle common cases nicely.
119 (while (and cache
120 (or
121 (not (= (current-column) indent))
122 (eq 'EQUAL_GREATER (wisi-cache-token cache))))
123 (when (and
124 (eq 'WHEN (wisi-cache-token cache))
125 (not (eq 'exit_statement (wisi-cache-nonterm cache))))
126 (setq offset (+ offset ada-indent-when)))
127 (setq cache (wisi-goto-containing cache))
128 (setq indent (current-indentation)))
129
130 (cond
131 ((null cache)
132 ;; test/ada_mode-opentoken.ads
133 ;; private package GDS.Commands.Add_Statement is
134 ;; type Instance is new Nonterminal.Instance with null record;
135 offset)
136
137 ((eq 'label_opt (wisi-cache-token cache))
138 (+ indent (- ada-indent-label) offset))
139
140 (t
141 ;; test/ada_mode-generic_instantiation.ads
142 ;; function Function_1 is new Instance.Generic_Function
143 ;; (Param_Type => Integer,
144 ;;
145 ;; test/ada_mode-nested_packages.adb
146 ;; function Create (Model : in Integer;
147 ;; Context : in String) return String is
148 ;; ...
149 ;; Cache : array (1 .. 10) of Boolean := (True, False, others => False);
150 (+ indent offset))
151 ))
152 )))
153
154 (defun ada-wisi-indent-containing (offset cache &optional before)
155 "Return indentation of OFFSET plus indentation of token containing CACHE.
156 BEFORE should be t when called from ada-wisi-before-cache, nil otherwise."
157 (save-excursion
158 (cond
159 ((markerp (wisi-cache-containing cache))
160 (ada-wisi-indent-cache offset (wisi-goto-containing cache)))
161
162 (t
163 (cond
164 ((ada-in-paren-p)
165 (ada-goto-open-paren 1)
166 (+ (current-column) offset))
167
168 (t
169 ;; at outermost containing statement. If called from
170 ;; ada-wisi-before-cache, we want to ignore OFFSET (indenting
171 ;; 'package' in a package spec). If called from
172 ;; ada-wisi-after-cache, we want to include offset (indenting
173 ;; first declaration in the package).
174 (if before 0 offset))
175 ))
176 )))
177
178 (defun ada-wisi-indent-list-break (cache prev-token)
179 "Return indentation for a token contained by CACHE, which must be a list-break.
180 point must be on CACHE. PREV-TOKEN is the token before the one being indented."
181 (let ((break-point (point))
182 (containing (wisi-goto-containing cache)))
183 (cl-ecase (wisi-cache-token containing)
184 (LEFT_PAREN
185 (if (equal break-point (cl-caddr prev-token))
186 ;; we are indenting the first token after the list-break; not hanging.
187 ;;
188 ;; test/parent.adb
189 ;; Append_To (Formals,
190 ;; Make_Parameter_Specification (Loc,
191 ;; indenting 'Make_...'
192 ;;
193 ;; test/ada_mode-generic_instantiation.ads
194 ;; function Function_1 is new Instance.Generic_Function
195 ;; (Param_Type => Integer,
196 ;; Result_Type => Boolean,
197 ;; Threshold => 2);
198 ;; indenting 'Result_Type'
199 (+ (current-column) 1)
200 ;; else hanging
201 ;;
202 ;; test/ada_mode-parens.adb
203 ;; A :=
204 ;; (1 |
205 ;; 2 => (1, 1, 1),
206 ;; 3 |
207 ;; 4 => (2, 2, 2));
208 ;; indenting '4 =>'
209 (+ (current-column) 1 ada-indent-broken)))
210
211 (IS
212 ;; test/ada_mode-conditional_expressions.adb
213 ;; L1 : Integer := (case J is
214 ;; when 42 => -1,
215 ;; -- comment aligned with 'when'
216 ;; indenting '-- comment'
217 (wisi-indent-paren (+ 1 ada-indent-when)))
218
219 (WITH
220 (cl-ecase (wisi-cache-nonterm containing)
221 (aggregate
222 ;; test/ada_mode-nominal-child.ads
223 ;; (Default_Parent with
224 ;; Child_Element_1 => 10,
225 ;; Child_Element_2 => 12.0,
226 ;; indenting 'Child_Element_2'
227 (wisi-indent-paren 1))
228
229 (aspect_specification_opt
230 ;; test/aspects.ads:
231 ;; type Vector is tagged private
232 ;; with
233 ;; Constant_Indexing => Constant_Reference,
234 ;; Variable_Indexing => Reference,
235 ;; indenting 'Variable_Indexing'
236 (+ (current-indentation) ada-indent-broken))
237 ))
238 )
239 ))
240
241 (defun ada-wisi-before-cache ()
242 "Point is at indentation, before a cached token. Return new indentation for point."
243 (let ((pos-0 (point))
244 (cache (wisi-get-cache (point)))
245 (prev-token (save-excursion (wisi-backward-token)))
246 )
247 (when cache
248 (cl-ecase (wisi-cache-class cache)
249 (block-start
250 (cl-case (wisi-cache-token cache)
251 (IS ;; subprogram body
252 (ada-wisi-indent-containing 0 cache t))
253
254 (RECORD
255 ;; test/ada_mode-nominal.ads; ada-indent-record-rel-type = 3
256 ;; type Private_Type_2 is abstract tagged limited
257 ;; record
258 ;; indenting 'record'
259 ;;
260 ;; type Limited_Derived_Type_1d is
261 ;; abstract limited new Private_Type_1 with
262 ;; record
263 ;; indenting 'record'
264 ;;
265 ;; for Record_Type_1 use
266 ;; record
267 ;; indenting 'record'
268 (let ((containing (wisi-goto-containing cache)))
269 (while (not (memq (wisi-cache-token containing) '(FOR TYPE)))
270 (setq containing (wisi-goto-containing containing)))
271 (+ (current-column) ada-indent-record-rel-type)))
272
273 (t ;; other
274 (ada-wisi-indent-containing ada-indent cache t))))
275
276 (block-end
277 (cl-case (wisi-cache-nonterm cache)
278 (record_definition
279 (save-excursion
280 (wisi-goto-containing cache);; now on 'record'
281 (current-indentation)))
282
283 (t
284 (ada-wisi-indent-containing 0 cache t))
285 ))
286
287 (block-middle
288 (cl-case (wisi-cache-token cache)
289 (WHEN
290 (ada-wisi-indent-containing ada-indent-when cache t))
291
292 (t
293 (ada-wisi-indent-containing 0 cache t))
294 ))
295
296 (close-paren (wisi-indent-paren 0))
297
298 (name
299 (cl-case (wisi-cache-nonterm cache)
300 ((procedure_specification subprogram_specification)
301 ;; test/ada_mode-nominal.ads
302 ;; not
303 ;; overriding
304 ;; procedure
305 ;; Procedure_1c (Item : in out Parent_Type_1);
306 ;; indenting 'Procedure_1c'
307 ;;
308 ;; not overriding function
309 ;; Function_2e (Param : in Parent_Type_1) return Float;
310 ;; indenting 'Function_2e'
311 (ada-wisi-indent-containing ada-indent-broken cache t))
312
313 (t
314 ;; defer to ada-wisi-after-cache, for consistency
315 nil)
316 ))
317
318 (name-paren
319 ;; defer to ada-wisi-after-cache, for consistency
320 nil)
321
322 (open-paren
323 (let ((containing (wisi-goto-containing cache)))
324 (cl-case (wisi-cache-token containing)
325 (COMMA
326 ;; test/ada_mode-parens.adb
327 ;; A : Matrix_Type :=
328 ;; ((1, 2, 3),
329 ;; (4, 5, 6),
330 ;; indenting (4
331 (ada-wisi-indent-containing 0 containing))
332
333 (EQUAL_GREATER
334 (setq containing (wisi-goto-containing containing))
335 (cl-ecase (wisi-cache-token containing)
336 (COMMA
337 ;; test/ada_mode-long_paren.adb
338 ;; (RT => RT,
339 ;; Monitor => True,
340 ;; RX_Enable =>
341 ;; (RX_Torque_Subaddress |
342 ;; indenting (RX_Torque
343 (ada-wisi-indent-containing ada-indent-broken containing t))
344 (LEFT_PAREN
345 ;; test/ada_mode-parens.adb
346 ;; (1 =>
347 ;; (1 => 12,
348 ;; indenting '(1 => 12'; containing is '=>'
349 (ada-wisi-indent-cache (1- ada-indent) containing))
350 (WHEN
351 ;; test/ada_mode-conditional_expressions.adb
352 ;; when 1 =>
353 ;; (if J > 42
354 ;; indenting '(if'; containing is '=>'
355 (+ (current-column) -1 ada-indent))
356 ))
357
358 ((FUNCTION PROCEDURE)
359 ;; test/ada_mode-nominal.adb
360 ;; function Function_Access_11
361 ;; (A_Param : in Float)
362 ;; -- EMACSCMD:(test-face "function" font-lock-keyword-face)
363 ;; return access function
364 ;; (A_Param : in Float)
365 ;; return
366 ;; Standard.Float -- Ada mode 4.01, GPS do this differently
367 ;; indenting second '(A_Param)
368 (+ (current-indentation) -1 ada-indent))
369
370 (LEFT_PAREN
371 ;; test/ada_mode-parens.adb
372 ;; or else ((B.all
373 ;; and then C)
374 ;; or else
375 ;; (D
376 ;; indenting (D
377 (+ (current-column) 1 ada-indent-broken))
378
379 (WHEN
380 ;; test/ada_mode-nominal.adb
381 ;;
382 ;; when Local_1 = 0 and not
383 ;; (Local_2 = 1)
384 ;; indenting (Local_2
385 ;;
386 ;; entry E3
387 ;; (X : Integer) when Local_1 = 0 and not
388 ;; (Local_2 = 1)
389 (+ (ada-wisi-current-indentation) ada-indent-broken))
390
391 (name
392 ;; test/indent.ads
393 ;; CSCL_Type'
394 ;; (
395 ;; identing (
396 ;;
397 ;; test/ada_mode-parens.adb
398 ;; Check
399 ;; ("foo bar",
400 ;; A
401 ;; (1),
402 ;; A(2));
403 ;; indenting (1)
404 ;;
405 ;; test/ada_mode-parens.adb
406 ;; Local_11 : Local_11_Type := Local_11_Type'
407 ;; (A => Integer
408 ;; (1.0),
409 ;; B => Integer
410 ;; (2.0));
411 (+ (ada-wisi-current-indentation) ada-indent-broken))
412
413 (t
414 (cond
415 ((memq (wisi-cache-class containing) '(block-start statement-start))
416 ;; test/ada_mode-nominal.adb
417 ;; entry E2
418 ;; (X : Integer)
419 ;; indenting (X
420 (ada-wisi-indent-cache ada-indent-broken containing))
421
422 (t
423 ;; Open paren in an expression.
424 ;;
425 ;; test/ada_mode-conditional_expressions.adb
426 ;; L0 : Integer :=
427 ;; (case J is when 42 => -1, when Integer'First .. 41 => 0, when others => 1);
428 ;; indenting (case
429 (ada-wisi-indent-containing ada-indent-broken containing t))
430 ))
431 )))
432
433 (return-1;; parameter list
434 (let ((return-pos (point)))
435 (wisi-goto-containing cache nil) ;; matching 'function'
436 (cond
437 ((<= ada-indent-return 0)
438 ;; indent relative to "("
439 (wisi-forward-find-class 'open-paren return-pos)
440 (+ (current-column) (- ada-indent-return)))
441
442 (t
443 (+ (current-column) ada-indent-return))
444 )))
445
446 (return-2;; no parameter list
447 (wisi-goto-containing cache nil) ;; matching 'function'
448 (+ (current-column) ada-indent-broken))
449
450 (statement-end
451 (ada-wisi-indent-containing ada-indent-broken cache t))
452
453 (statement-other
454 (let ((containing (wisi-goto-containing cache nil)))
455 (cl-case (wisi-cache-token cache)
456 (EQUAL_GREATER
457 (+ (current-column) ada-indent-broken))
458
459 (ELSIF
460 ;; test/g-comlin.adb
461 ;; elsif Current_Argument < CL.Argument_Count then
462 (ada-wisi-indent-cache 0 containing))
463
464 (RENAMES
465 (cl-ecase (wisi-cache-nonterm containing)
466 ((generic_renaming_declaration subprogram_renaming_declaration)
467 (wisi-forward-find-token '(FUNCTION PROCEDURE) pos-0)
468 (let ((pos-subprogram (point))
469 (has-params
470 ;; this is wrong for one return access
471 ;; function case: overriding function Foo
472 ;; return access Bar (...) renames ...;
473 (wisi-forward-find-token 'LEFT_PAREN pos-0 t)))
474 (if has-params
475 (if (<= ada-indent-renames 0)
476 ;; indent relative to paren
477 (+ (current-column) (- ada-indent-renames))
478 ;; else relative to line containing keyword
479 (goto-char pos-subprogram)
480 (+ (current-indentation) ada-indent-renames))
481
482 ;; no params
483 (goto-char pos-subprogram)
484 (+ (current-indentation) ada-indent-broken))
485 ))
486
487 (object_renaming_declaration
488 (+ (current-indentation) ada-indent-broken))
489 ))
490
491 (t
492 (while (not (wisi-cache-nonterm containing))
493 (setq containing (wisi-goto-containing containing)))
494
495 (cl-ecase (wisi-cache-nonterm containing)
496 (aggregate
497 ;; indenting 'with'
498 (+ (current-column) 1))
499
500 (association_opt
501 ;; test/indent.ads
502 ;; 1 => -- Used to be aligned on "CSCL_Type'"
503 ;; -- aligned with previous comment.
504 ;; IO_CPU_Control_State_S_Pkg.CPU2_Fault_Status_Type'
505 (ada-wisi-indent-cache ada-indent-broken containing))
506
507 (asynchronous_select
508 ;; indenting 'abort'
509 (+ (current-column) ada-indent-broken))
510
511 (component_declaration
512 ;; test/ada_mode-nominal.ads record_type_3
513 (+ (current-column) ada-indent-broken))
514
515 (entry_body
516 ;; indenting 'when'
517 (+ (current-column) ada-indent-broken))
518
519 (formal_package_declaration
520 ;; test/ada_mode-generic_package.ads
521 ;; with package A_Package_7 is
522 ;; new Ada.Text_IO.Integer_IO (Num => Formal_Signed_Integer_Type);
523 ;; indenting 'new'
524 (+ (current-column) ada-indent-broken))
525
526 (full_type_declaration
527 ;; test/ada_mode-nominal.ads
528 ;; type Unconstrained_Array_Type_3 is array (Integer range <>, Standard.Character range <>)
529 ;; of Object_Access_Type_1;
530 ;; indenting 'of'
531 ;;
532 ;; type Object_Access_Type_7
533 ;; is access all Integer;
534 ;; indenting 'is'
535 ;;
536 ;; type Limited_Derived_Type_1 is abstract limited new Private_Type_1 with
537 ;; record
538 ;; indenting 'record'
539 ;;
540 ;; type Limited_Derived_Type_3 is abstract limited new Private_Type_1
541 ;; with null record;
542 ;; indenting 'with'
543 ;;
544 ;; type Limited_Derived_Type_2a is abstract limited new Private_Type_1
545 ;; with record
546 ;; indenting 'with record'
547 (while (not (eq 'TYPE (wisi-cache-token containing)))
548 (setq containing (wisi-goto-containing containing)))
549
550 (cond
551 ((eq (wisi-cache-token cache) 'RECORD)
552 (+ (current-column) ada-indent-record-rel-type))
553
554 ((eq (wisi-cache-token cache) 'WITH)
555 (let ((type-col (current-column)))
556 (wisi-goto-end-1 cache)
557 (if (eq 'WITH (wisi-cache-token (wisi-backward-cache)))
558 ;; 'with null record;' or 'with private;'
559 (+ type-col ada-indent-broken)
560 (+ type-col ada-indent-record-rel-type))))
561
562 (t
563 (+ (current-column) ada-indent-broken))
564 ))
565
566 (generic_instantiation
567 ;; test/ada_mode-generic_instantiation.ads
568 ;; procedure Procedure_7 is
569 ;; new Instance.Generic_Procedure (Integer, Function_1);
570 ;; indenting 'new'
571 (+ (current-column) ada-indent-broken))
572
573 (generic_renaming_declaration
574 ;; indenting keyword following 'generic'
575 (current-column))
576
577 (object_declaration
578 (cl-ecase (wisi-cache-token containing)
579 (COLON
580 ;; test/ada_mode-nominal.ads
581 ;; Anon_Array_3 : array (1 .. 10)
582 ;; of Integer;
583 ;; indenting 'of'
584 (+ (current-indentation) ada-indent-broken))
585
586 (COLON_EQUAL
587 ;; test/indent.ads
588 ;; C_S_Controls : constant
589 ;; CSCL_Type :=
590 ;; CSCL_Type'
591 ;; indenting 'CSCL_Type'
592 (+ (current-indentation) ada-indent-broken))
593
594 (identifier_list
595 ;; test/ada_mode-nominal.adb
596 ;; Local_2 : constant Float
597 ;; := Local_1;
598 (+ (current-indentation) ada-indent-broken))
599 ))
600
601 (private_type_declaration
602 ;; test/aspects.ads
603 ;; type Vector is tagged private
604 ;; with
605 ;; indenting 'with'
606 (current-indentation))
607
608 (qualified_expression
609 ;; test/ada_mode-nominal-child.ads
610 ;; Child_Obj_5 : constant Child_Type_1 :=
611 ;; (Parent_Type_1'
612 ;; (Parent_Element_1 => 1,
613 (ada-wisi-indent-cache ada-indent-broken containing))
614
615 (statement
616 (cl-case (wisi-cache-token containing)
617 (label_opt
618 (- (current-column) ada-indent-label))
619
620 (t
621 ;; test/ada_mode-nominal.adb
622 ;; select
623 ;; delay 1.0;
624 ;; then
625 ;; -- ...
626 ;; abort
627 (ada-wisi-indent-cache ada-indent-broken cache))
628 ))
629
630 ((subprogram_body subprogram_declaration subprogram_specification null_procedure_declaration)
631 (cl-ecase (wisi-cache-token cache)
632 (OVERRIDING
633 ;; indenting 'overriding' following 'not'
634 (current-column))
635
636 ((PROCEDURE FUNCTION)
637 ;; indenting 'procedure' or 'function following 'overriding'
638 (current-column))
639
640 (WITH
641 ;; indenting aspect specification on subprogram declaration
642 ;; test/aspects.ads
643 ;; procedure Foo (X : Integer;
644 ;; Y : out Integer)
645 ;; with Pre => X > 10 and
646 ;; indenting 'with'
647 (current-column))
648 ))
649
650 (subtype_declaration
651 ;; test/adacore_9717_001.ads A_Long_Name
652 (+ (current-column) ada-indent-broken))
653
654 ))))) ;; end statement-other
655
656 (statement-start
657 (cond
658 ((eq 'label_opt (wisi-cache-token cache))
659 (ada-wisi-indent-containing (+ ada-indent-label ada-indent) cache t))
660
661 (t
662 (let ((containing-cache (wisi-get-containing-cache cache)))
663 (if (not containing-cache)
664 ;; at bob
665 0
666 ;; not at bob
667 (cl-case (wisi-cache-class containing-cache)
668 ((block-start block-middle)
669 (wisi-goto-containing cache)
670 (cl-case (wisi-cache-nonterm containing-cache)
671 (record_definition
672 (+ (current-indentation) ada-indent))
673
674 (t
675 (ada-wisi-indent-cache ada-indent containing-cache))
676 ))
677
678 (list-break
679 (ada-wisi-indent-list-break cache prev-token))
680
681 (statement-other
682 ;; defer to ada-wisi-after-cache
683 nil)
684 ))))
685 ))
686
687 (type
688 (ada-wisi-indent-containing ada-indent-broken cache t))
689 ))
690 ))
691
692 (defun ada-wisi-after-cache ()
693 "Point is at indentation, not before a cached token. Find previous
694 cached token, return new indentation for point."
695 (let ((start (point))
696 (prev-token (save-excursion (wisi-backward-token)))
697 (cache (wisi-backward-cache)))
698
699 (cond
700 ((not cache) ;; bob
701 0)
702
703 (t
704 (while (memq (wisi-cache-class cache) '(name name-paren type))
705 ;; not useful for indenting
706 (setq cache (wisi-backward-cache)))
707
708 (cl-ecase (wisi-cache-class cache)
709 (block-end
710 ;; indenting block/subprogram name after 'end'
711 (wisi-indent-current ada-indent-broken))
712
713 (block-middle
714 (cl-case (wisi-cache-token cache)
715 (IS
716 (cl-case (wisi-cache-nonterm cache)
717 (case_statement
718 ;; between 'case .. is' and first 'when'; most likely a comment
719 (ada-wisi-indent-containing 0 cache t))
720
721 (t
722 (+ (ada-wisi-indent-containing ada-indent cache t)))
723 ))
724
725 ((THEN ELSE)
726 (let ((indent
727 (cl-ecase (wisi-cache-nonterm (wisi-get-containing-cache cache))
728 ((statement if_statement elsif_statement_item) ada-indent)
729 ((if_expression elsif_expression_item) ada-indent-broken))))
730 (ada-wisi-indent-containing indent cache t)))
731
732 (WHEN
733 ;; between 'when' and '=>'
734 (+ (current-column) ada-indent-broken))
735
736 (t
737 ;; block-middle keyword may not be on separate line:
738 ;; function Create (Model : in Integer;
739 ;; Context : in String) return String is
740 (ada-wisi-indent-containing ada-indent cache nil))
741 ))
742
743 (block-start
744 (cl-case (wisi-cache-nonterm cache)
745 (exception_handler
746 ;; between 'when' and '=>'
747 (+ (current-column) ada-indent-broken))
748
749 (if_expression
750 (ada-wisi-indent-containing ada-indent-broken cache nil))
751
752 (select_alternative
753 (ada-wisi-indent-containing (+ ada-indent-when ada-indent-broken) cache nil))
754
755 (t ;; other; normal block statement
756 (ada-wisi-indent-cache ada-indent cache))
757 ))
758
759 (close-paren
760 ;; actual_parameter_part: test/ada_mode-nominal.adb
761 ;; return 1.0 +
762 ;; Foo (Bar) + -- multi-line expression that happens to have a cache at a line start
763 ;; 12;
764 ;; indenting '12'; don't indent relative to containing function name
765 ;;
766 ;; attribute_designator: test/ada_mode-nominal.adb
767 ;; raise Constraint_Error with Count'Image (Line (File)) &
768 ;; "foo";
769 ;; indenting '"foo"'; relative to raise
770 ;;
771 ;; test/ada_mode-slices.adb
772 ;; Put_Line(Day'Image(D1) & " - " & Day'Image(D2) & " = " &
773 ;; Integer'Image(N));
774 ;; indenting 'Integer'
775 (when (memq (wisi-cache-nonterm cache)
776 '(actual_parameter_part attribute_designator))
777 (setq cache (wisi-goto-containing cache)))
778 (ada-wisi-indent-containing ada-indent-broken cache nil))
779
780 (list-break
781 (ada-wisi-indent-list-break cache prev-token))
782
783 (open-paren
784 ;; 1) A parenthesized expression, or the first item in an aggregate:
785 ;;
786 ;; (foo +
787 ;; bar)
788 ;; (foo =>
789 ;; bar)
790 ;;
791 ;; we are indenting 'bar'
792 ;;
793 ;; 2) A parenthesized expression, or the first item in an
794 ;; aggregate, and there is whitespace between
795 ;; ( and the first token:
796 ;;
797 ;; test/ada_mode-parens.adb
798 ;; Local_9 : String := (
799 ;; "123"
800 ;;
801 ;; 3) A parenthesized expression, or the first item in an
802 ;; aggregate, and there is a comment between
803 ;; ( and the first token:
804 ;;
805 ;; test/ada_mode-nominal.adb
806 ;; A :=
807 ;; (
808 ;; -- a comment between paren and first association
809 ;; 1 =>
810 ;;
811 ;; test/ada_mode-parens.adb
812 ;; return Float (
813 ;; Integer'Value
814 ;; indenting 'Integer'
815 (let ((paren-column (current-column))
816 (start-is-comment (save-excursion (goto-char start) (looking-at comment-start-skip))))
817 (wisi-forward-token t); point is now after paren
818 (if start-is-comment
819 (skip-syntax-forward " >"); point is now on comment
820 (forward-comment (point-max)); point is now on first token
821 )
822 (if (= (point) start)
823 ;; case 2) or 3)
824 (1+ paren-column)
825 ;; 1)
826 (+ paren-column 1 ada-indent-broken))))
827
828 ((return-1 return-2)
829 ;; hanging. Intent relative to line containing matching 'function'
830 (ada-prev-statement-keyword)
831 (back-to-indentation)
832 (+ (current-column) ada-indent-broken))
833
834 (statement-end
835 (ada-wisi-indent-containing 0 cache nil))
836
837 (statement-other
838 (cl-ecase (wisi-cache-token cache)
839 (ABORT
840 ;; select
841 ;; Please_Abort;
842 ;; then
843 ;; abort
844 ;; -- 'abort' indented with ada-indent-broken, since this is part
845 ;; Titi;
846 (ada-wisi-indent-containing ada-indent cache))
847
848 ;; test/subdir/ada_mode-separate_task_body.adb
849 ((COLON COLON_EQUAL)
850 ;; Local_3 : constant Float :=
851 ;; Local_2;
852 (ada-wisi-indent-cache ada-indent-broken cache))
853
854 (COMMA
855 (cl-ecase (wisi-cache-nonterm cache)
856 (name_list
857 (cl-ecase (wisi-cache-nonterm (wisi-get-containing-cache cache))
858 (use_clause
859 ;; test/with_use1.adb
860 (ada-wisi-indent-containing ada-indent-use cache))
861
862 (with_clause
863 ;; test/ada_mode-nominal.ads
864 ;; limited private with Ada.Strings.Bounded,
865 ;; --EMACSCMD:(test-face "Ada.Containers" 'default)
866 ;; Ada.Containers;
867 ;;
868 ;; test/with_use1.adb
869 (ada-wisi-indent-containing ada-indent-with cache))
870 ))
871 ))
872
873 (ELSIF
874 ;; test/g-comlin.adb
875 ;; elsif Index_Switches + Max_Length <= Switches'Last
876 ;; and then Switches (Index_Switches + Max_Length) = '?'
877 (ada-wisi-indent-cache ada-indent-broken cache))
878
879 (EQUAL_GREATER
880 (let ((cache-col (current-column))
881 (cache-pos (point))
882 (line-end-pos (line-end-position))
883 (containing (wisi-goto-containing cache nil)))
884 (while (eq (wisi-cache-nonterm containing) 'association_list)
885 (setq containing (wisi-goto-containing containing nil)))
886
887 (cl-ecase (wisi-cache-nonterm containing)
888 ((actual_parameter_part aggregate)
889 ;; ada_mode-generic_package.ads
890 ;; with package A_Package_2 is new Ada.Text_IO.Integer_IO (Num =>
891 ;; Formal_Signed_Integer_Type);
892 ;; indenting 'Formal_Signed_...', point on '(Num'
893 ;;
894 ;; test/ada_mode-parens.adb
895 ;; (1 =>
896 ;; 1,
897 ;; 2 =>
898 ;; 1 + 2 * 3,
899 ;; indenting '1,' or '1 +'; point on '(1'
900 (+ (current-column) 1 ada-indent-broken))
901
902 (aspect_specification_opt
903 ;; test/aspects.ads
904 ;; with Pre => X > 10 and
905 ;; X < 50 and
906 ;; F (X),
907 ;; Post =>
908 ;; Y >= X and
909 ;; indenting 'X < 50' or 'Y >= X'; cache is '=>', point is on '=>'
910 ;; or indenting 'Post =>'; cache is ',', point is on 'with'
911 (cl-ecase (wisi-cache-token cache)
912 (COMMA
913 (+ (current-indentation) ada-indent-broken))
914
915 (EQUAL_GREATER
916 (if (= (+ 2 cache-pos) line-end-pos)
917 ;; Post =>
918 ;; Y >= X and
919 (progn
920 (goto-char cache-pos)
921 (+ (current-indentation) ada-indent-broken))
922 ;; with Pre => X > 10 and
923 ;; X < 50 and
924 (+ 3 cache-col)))
925 ))
926
927 (association_list
928 (cl-ecase (save-excursion (wisi-cache-token (wisi-goto-containing cache nil)))
929 (COMMA
930 (ada-wisi-indent-containing (* 2 ada-indent-broken) cache))
931 ))
932
933 ((case_expression_alternative case_statement_alternative exception_handler)
934 ;; containing is 'when'
935 (+ (current-column) ada-indent))
936
937 (generic_renaming_declaration
938 ;; not indenting keyword following 'generic'
939 (+ (current-column) ada-indent-broken))
940
941 (primary
942 ;; test/ada_mode-quantified_expressions.adb
943 ;; if (for some J in 1 .. 10 =>
944 ;; J/2 = 0)
945 (ada-wisi-indent-containing ada-indent-broken cache))
946
947
948 (select_alternative
949 ;; test/ada_mode-nominal.adb
950 ;; or when Started
951 ;; =>
952 ;; accept Finish;
953 ;; indenting 'accept'; point is on 'when'
954 (+ (current-column) ada-indent))
955
956 (variant
957 ;; test/generic_param.adb
958 ;; case Item_Type is
959 ;; when Fix | Airport =>
960 ;; null;
961 ;; indenting 'null'
962 (+ (current-column) ada-indent))
963
964 )))
965
966 (IS
967 (setq cache (wisi-goto-containing cache))
968 (cl-ecase (wisi-cache-nonterm cache)
969 (full_type_declaration
970 ;; ada_mode/nominal.ads
971 ;; type Limited_Derived_Type_1a is abstract limited new
972 ;; Private_Type_1 with record
973 ;; Component_1 : Integer;
974 ;; indenting 'Private_Type_1'; look for 'record'
975 (let ((type-column (current-column)))
976 (goto-char start)
977 (if (wisi-forward-find-token 'RECORD (line-end-position) t)
978 ;; 'record' on line being indented
979 (+ type-column ada-indent-record-rel-type)
980 ;; 'record' on later line
981 (+ type-column ada-indent-broken))))
982
983 ((formal_type_declaration
984 ;; test/ada_mode-generic_package.ads
985 ;; type Synchronized_Formal_Derived_Type is abstract synchronized new Formal_Private_Type and Interface_Type
986 ;; with private;
987
988 subtype_declaration)
989 ;; test/ada_mode-nominal.ads
990 ;; subtype Subtype_2 is Signed_Integer_Type range 10 ..
991 ;; 20;
992
993 (+ (current-column) ada-indent-broken))
994 ))
995
996 (LEFT_PAREN
997 ;; test/indent.ads
998 ;; C_S_Controls : constant
999 ;; CSCL_Type :=
1000 ;; CSCL_Type'
1001 ;; (
1002 ;; 1 =>
1003 (+ (current-column) 1))
1004
1005 (OF
1006 ;; ada_mode-nominal.ads
1007 ;; Anon_Array_2 : array (1 .. 10) of
1008 ;; Integer;
1009 (ada-wisi-indent-containing ada-indent-broken cache))
1010
1011 (NEW
1012 ;; ada_mode-nominal.ads
1013 ;; type Limited_Derived_Type_2 is abstract limited new Private_Type_1 with
1014 ;; private;
1015 ;;
1016 ;; test/ada_mode-generic_instantiation.ads
1017 ;; procedure Procedure_6 is new
1018 ;; Instance.Generic_Procedure (Integer, Function_1);
1019 ;; indenting 'Instance'; containing is 'new'
1020 (ada-wisi-indent-containing ada-indent-broken cache))
1021
1022 (WHEN
1023 ;; test/ada_mode-parens.adb
1024 ;; exit when A.all
1025 ;; or else B.all
1026 (ada-wisi-indent-containing ada-indent-broken cache))
1027
1028 (WITH
1029 (cl-case (wisi-cache-nonterm cache)
1030 (aggregate
1031 ;; test/ada_mode-nominal-child.ads
1032 ;; (Default_Parent with
1033 ;; 10, 12.0, True);
1034 ;; indenting '10'; containing is '('
1035 (ada-wisi-indent-containing 0 cache nil))
1036
1037 (aspect_specification_opt
1038 ;; test/aspects.ads
1039 ;; type Vector is tagged private
1040 ;; with
1041 ;; Constant_Indexing => Constant_Reference,
1042 ;; indenting 'Constant_Indexing'; point is on 'with'
1043 (+ (current-indentation) ada-indent-broken))
1044
1045 (raise_statement
1046 ;; raise_statement: test/ada_mode-nominal.adb
1047 ;; raise Constraint_Error with
1048 ;; "help!";
1049 (ada-wisi-indent-containing ada-indent-broken cache nil))
1050 ))
1051
1052 ;; otherwise just hanging
1053 ((ACCEPT FUNCTION PROCEDURE RENAMES)
1054 (back-to-indentation)
1055 (+ (current-column) ada-indent-broken))
1056
1057 ))
1058
1059 (statement-start
1060 (cl-case (wisi-cache-token cache)
1061 (WITH ;; with_clause
1062 (+ (current-column) ada-indent-with))
1063
1064 (label_opt
1065 ;; comment after label
1066 (+ (current-column) (- ada-indent-label)))
1067
1068 (t
1069 ;; procedure Procedure_8
1070 ;; is new Instance.Generic_Procedure (Integer, Function_1);
1071 ;; indenting 'is'; hanging
1072 ;; (+ (current-column) ada-indent-broken))
1073 (ada-wisi-indent-cache ada-indent-broken cache))
1074 ))
1075 )))
1076 ))
1077
1078 (defun ada-wisi-comment ()
1079 "Compute indentation of a comment. For `wisi-indent-functions'."
1080 ;; We know we are at the first token on a line. We check for comment
1081 ;; syntax, not comment-start, to accomodate gnatprep, skeleton
1082 ;; placeholders, etc.
1083 (when (and (not (= (point) (point-max))) ;; no char after EOB!
1084 (= 11 (syntax-class (syntax-after (point)))))
1085
1086 ;; We are at a comment; indent to previous code or comment.
1087 (cond
1088 ((and ada-indent-comment-col-0
1089 (= 0 (current-column)))
1090 0)
1091
1092 ((or
1093 (save-excursion (forward-line -1) (looking-at "\\s *$"))
1094 (save-excursion (forward-comment -1)(not (looking-at comment-start))))
1095 ;; comment is after a blank line or code; indent as if code
1096 ;;
1097 ;; ada-wisi-before-cache will find the keyword _after_ the
1098 ;; comment, which could be a block-middle or block-end, and that
1099 ;; would align the comment with the block-middle, which is wrong. So
1100 ;; we only call ada-wisi-after-cache.
1101
1102 ;; FIXME: need option to match gnat style check; change indentation to match (ie mod 3)
1103 (ada-wisi-after-cache))
1104
1105 (t
1106 ;; comment is after a comment
1107 (forward-comment -1)
1108 (current-column))
1109 )))
1110
1111 (defun ada-wisi-post-parse-fail ()
1112 "For `wisi-post-parse-fail-hook'."
1113 (save-excursion
1114 (let ((start-cache (wisi-goto-start (or (wisi-get-cache (point)) (wisi-backward-cache)))))
1115 (when start-cache
1116 ;; nil when in a comment at point-min
1117 (indent-region (point) (wisi-cache-end start-cache)))
1118 ))
1119 (back-to-indentation))
1120
1121 ;;;; ada-mode functions (alphabetical)
1122
1123 (defun ada-wisi-declarative-region-start-p (cache)
1124 "Return t if cache is a keyword starting a declarative region."
1125 (cl-case (wisi-cache-token cache)
1126 (DECLARE t)
1127 (IS
1128 (memq (wisi-cache-class cache) '(block-start block-middle)))
1129 (t nil)
1130 ))
1131
1132 (defun ada-wisi-context-clause ()
1133 "For `ada-fix-context-clause'."
1134 (wisi-validate-cache (point-max))
1135 (save-excursion
1136 (goto-char (point-min))
1137 (let ((begin nil)
1138 (end nil)
1139 cache)
1140
1141 (while (not end)
1142 (setq cache (wisi-forward-cache))
1143 (cl-case (wisi-cache-nonterm cache)
1144 (pragma nil)
1145 (use_clause nil)
1146 (with_clause
1147 (when (not begin)
1148 (setq begin (point-at-bol))))
1149 (t
1150 ;; start of compilation unit
1151 (setq end (point-at-bol))
1152 (unless begin
1153 (setq begin end)))
1154 ))
1155 (cons begin end)
1156 )))
1157
1158 (defun ada-wisi-goto-declaration-start ()
1159 "For `ada-goto-declaration-start', which see.
1160 Also return cache at start."
1161 (wisi-validate-cache (point))
1162 (let ((cache (wisi-get-cache (point)))
1163 (done nil))
1164 (unless cache
1165 (setq cache (wisi-backward-cache)))
1166 ;; cache is null at bob
1167 (while (not done)
1168 (if cache
1169 (progn
1170 (setq done
1171 (cl-case (wisi-cache-nonterm cache)
1172 ((generic_package_declaration generic_subprogram_declaration)
1173 (eq (wisi-cache-token cache) 'GENERIC))
1174
1175 ((package_body package_declaration)
1176 (eq (wisi-cache-token cache) 'PACKAGE))
1177
1178 ((protected_body protected_type_declaration single_protected_declaration)
1179 (eq (wisi-cache-token cache) 'PROTECTED))
1180
1181 ((subprogram_body subprogram_declaration null_procedure_declaration)
1182 (memq (wisi-cache-token cache) '(NOT OVERRIDING FUNCTION PROCEDURE)))
1183
1184 (task_type_declaration
1185 (eq (wisi-cache-token cache) 'TASK))
1186
1187 ))
1188 (unless done
1189 (setq cache (wisi-goto-containing cache nil))))
1190 (setq done t))
1191 )
1192 cache))
1193
1194 (defun ada-wisi-goto-declarative-region-start ()
1195 "For `ada-goto-declarative-region-start', which see."
1196 (wisi-validate-cache (point))
1197 (let ((done nil)
1198 (first t)
1199 (cache
1200 (or
1201 (wisi-get-cache (point))
1202 ;; we use forward-cache here, to handle the case where point is after a subprogram declaration:
1203 ;; declare
1204 ;; ...
1205 ;; function ... is ... end;
1206 ;; <point>
1207 ;; function ... is ... end;
1208 (wisi-forward-cache))))
1209 (while (not done)
1210 (if (ada-wisi-declarative-region-start-p cache)
1211 (progn
1212 (wisi-forward-token t)
1213 (setq done t))
1214 (cl-case (wisi-cache-class cache)
1215 ((block-middle block-end)
1216 (setq cache (wisi-prev-statement-cache cache)))
1217
1218 (statement-start
1219 ;; 1) test/ada_mode-nominal.adb
1220 ;; protected body Protected_1 is -- target 2
1221 ;; <point>
1222 ;; want target 2
1223 ;;
1224 ;; 2) test/ada_mode-nominal.adb
1225 ;; function Function_Access_1
1226 ;; (A_Param <point> : in Float)
1227 ;; return
1228 ;; Standard.Float
1229 ;; is -- target 1
1230 ;; want target 1
1231 ;;
1232 ;; 3) test/ada_mode-nominal-child.adb
1233 ;; overriding <point> function Function_2c (Param : in Child_Type_1)
1234 ;; return Float
1235 ;; is -- target Function_2c
1236 ;; want target
1237
1238 (if first
1239 ;; case 1
1240 (setq cache (wisi-goto-containing cache t))
1241 ;; case 2, 3
1242 (cl-case (wisi-cache-nonterm cache)
1243 (subprogram_body
1244 (while (not (eq 'IS (wisi-cache-token cache)))
1245 (setq cache (wisi-next-statement-cache cache))))
1246 (t
1247 (setq cache (wisi-goto-containing cache t)))
1248 )))
1249 (t
1250 (setq cache (wisi-goto-containing cache t)))
1251 ))
1252 (when first (setq first nil)))
1253 ))
1254
1255 (defun ada-wisi-in-paramlist-p ()
1256 "For `ada-in-paramlist-p'."
1257 (wisi-validate-cache (point))
1258 ;; (info "(elisp)Parser State" "*syntax-ppss*")
1259 (let* ((parse-result (syntax-ppss))
1260 cache)
1261 (and (> (nth 0 parse-result) 0)
1262 ;; cache is nil if the parse failed
1263 (setq cache (wisi-get-cache (nth 1 parse-result)))
1264 (eq 'formal_part (wisi-cache-nonterm cache)))
1265 ))
1266
1267 (defun ada-wisi-make-subprogram-body ()
1268 "For `ada-make-subprogram-body'."
1269 (wisi-validate-cache (point))
1270 (when wisi-parse-failed
1271 (error "syntax parse failed; cannot create body"))
1272
1273 (let* ((begin (point))
1274 (end (save-excursion (wisi-forward-find-class 'statement-end (point-max)) (point)))
1275 (cache (wisi-forward-find-class 'name end))
1276 (name (buffer-substring-no-properties
1277 (point)
1278 (+ (point) (wisi-cache-last cache)))))
1279 (goto-char end)
1280 (newline)
1281 (insert " is begin\nnull;\nend ");; legal syntax; parse does not fail
1282 (insert name)
1283 (forward-char 1)
1284
1285 ;; newline after body to separate from next body
1286 (newline-and-indent)
1287 (indent-region begin (point))
1288 (forward-line -2)
1289 (back-to-indentation); before 'null;'
1290 ))
1291
1292 (defun ada-wisi-scan-paramlist (begin end)
1293 "For `ada-scan-paramlist'."
1294 (wisi-validate-cache end)
1295 (goto-char begin)
1296 (let (token
1297 text
1298 identifiers
1299 (in-p nil)
1300 (out-p nil)
1301 (not-null-p nil)
1302 (access-p nil)
1303 (constant-p nil)
1304 (protected-p nil)
1305 (type nil)
1306 type-begin
1307 type-end
1308 (default nil)
1309 (default-begin nil)
1310 param
1311 paramlist
1312 (done nil))
1313 (while (not done)
1314 (let ((token-text (wisi-forward-token)))
1315 (setq token (nth 0 token-text))
1316 (setq text (nth 1 token-text)))
1317 (cond
1318 ((equal token 'COMMA) nil);; multiple identifiers
1319
1320 ((equal token 'COLON)
1321 ;; identifiers done. find type-begin; there may be no mode
1322 (skip-syntax-forward " ")
1323 (setq type-begin (point))
1324 (save-excursion
1325 (while (member (car (wisi-forward-token)) '(IN OUT NOT NULL ACCESS CONSTANT PROTECTED))
1326 (skip-syntax-forward " ")
1327 (setq type-begin (point)))))
1328
1329 ((equal token 'IN) (setq in-p t))
1330 ((equal token 'OUT) (setq out-p t))
1331 ((and (not type-end)
1332 (member token '(NOT NULL)))
1333 ;; "not", "null" could be part of the default expression
1334 (setq not-null-p t))
1335 ((equal token 'ACCESS) (setq access-p t))
1336 ((equal token 'CONSTANT) (setq constant-p t))
1337 ((equal token 'PROTECTED) (setq protected-p t))
1338
1339 ((equal token 'COLON_EQUAL)
1340 (setq type-end (save-excursion (backward-char 2) (skip-syntax-backward " ") (point)))
1341 (skip-syntax-forward " ")
1342 (setq default-begin (point))
1343 (wisi-forward-find-token 'SEMICOLON end t))
1344
1345 ((member token '(SEMICOLON RIGHT_PAREN))
1346 (if (equal token 'RIGHT_PAREN)
1347 ;; all done
1348 (progn
1349 (setq done t)
1350 (when (not type-end) (setq type-end (1- (point))))
1351 (when default-begin (setq default (buffer-substring-no-properties default-begin (1- (point)))))
1352 )
1353 ;; else semicolon - one param done
1354 (when (not type-end) (setq type-end (1- (point))))
1355 (when default-begin (setq default (buffer-substring-no-properties default-begin (1- (point)))))
1356 )
1357
1358 (setq type (buffer-substring-no-properties type-begin type-end))
1359 (setq param (list (reverse identifiers)
1360 in-p out-p not-null-p access-p constant-p protected-p
1361 type default))
1362 (if paramlist
1363 (add-to-list 'paramlist param)
1364 (setq paramlist (list param)))
1365 (setq identifiers nil
1366 in-p nil
1367 out-p nil
1368 not-null-p nil
1369 access-p nil
1370 constant-p nil
1371 protected-p nil
1372 type nil
1373 type-begin nil
1374 type-end nil
1375 default nil
1376 default-begin nil))
1377
1378 (t
1379 (when (not type-begin)
1380 (if identifiers
1381 (add-to-list 'identifiers text)
1382 (setq identifiers (list text)))))
1383 ))
1384 paramlist))
1385
1386 (defun ada-wisi-which-function-1 (keyword add-body)
1387 "used in `ada-wisi-which-function'."
1388 (let (region
1389 result
1390 (cache (wisi-forward-find-class 'name (point-max))))
1391
1392 (setq result (wisi-cache-text cache))
1393
1394 (when (not ff-function-name)
1395 (setq ff-function-name
1396 (concat
1397 keyword
1398 (when add-body "\\s-+body")
1399 "\\s-+"
1400 result
1401 ada-symbol-end)))
1402 result))
1403
1404 (defun ada-wisi-which-function ()
1405 "For `ada-which-function'."
1406 (wisi-validate-cache (point))
1407 (save-excursion
1408 (let ((result nil)
1409 (cache (ada-wisi-goto-declaration-start)))
1410 (if (null cache)
1411 ;; bob
1412 (setq result "")
1413
1414 (cl-case (wisi-cache-nonterm cache)
1415 ((generic_package_declaration generic_subprogram_declaration)
1416 ;; name is after next statement keyword
1417 (wisi-next-statement-cache cache)
1418 (setq cache (wisi-get-cache (point))))
1419 )
1420
1421 ;; add or delete 'body' as needed
1422 (cl-ecase (wisi-cache-nonterm cache)
1423 (package_body
1424 (setq result (ada-wisi-which-function-1 "package" nil)))
1425
1426 ((package_declaration
1427 generic_package_declaration) ;; after 'generic'
1428 (setq result (ada-wisi-which-function-1 "package" t)))
1429
1430 (protected_body
1431 (setq result (ada-wisi-which-function-1 "protected" nil)))
1432
1433 ((protected_type_declaration single_protected_declaration)
1434 (setq result (ada-wisi-which-function-1 "protected" t)))
1435
1436 ((subprogram_declaration
1437 subprogram_specification ;; after 'generic'
1438 null_procedure_declaration)
1439 (setq result (ada-wisi-which-function-1
1440 (wisi-cache-text (wisi-forward-find-token '(FUNCTION PROCEDURE) (point-max)))
1441 nil))) ;; no 'body' keyword in subprogram bodies
1442
1443 (subprogram_body
1444 (setq result (ada-wisi-which-function-1
1445 (wisi-cache-text (wisi-forward-find-token '(FUNCTION PROCEDURE) (point-max)))
1446 nil)))
1447
1448 (task_type_declaration
1449 (setq result (ada-wisi-which-function-1 "task" t)))
1450
1451 ))
1452 result)))
1453
1454 ;;;; debugging
1455 (defun ada-wisi-debug-keys ()
1456 "Add debug key definitions to `ada-mode-map'."
1457 (interactive)
1458 (define-key ada-mode-map "\M-e" 'wisi-show-parse-error)
1459 (define-key ada-mode-map "\M-h" 'wisi-show-containing-or-previous-cache)
1460 (define-key ada-mode-map "\M-i" 'wisi-goto-end)
1461 (define-key ada-mode-map "\M-j" 'wisi-show-cache)
1462 (define-key ada-mode-map "\M-k" 'wisi-show-token)
1463 )
1464
1465 (defun ada-wisi-setup ()
1466 "Set up a buffer for parsing Ada files with wisi."
1467 (wisi-setup '(ada-wisi-comment
1468 ada-wisi-before-cache
1469 ada-wisi-after-cache)
1470 'ada-wisi-post-parse-fail
1471 ada-wisi-class-list
1472 ada-grammar-wy--keyword-table
1473 ada-grammar-wy--token-table
1474 ada-grammar-wy--parse-table)
1475
1476 ;; Handle escaped quotes in strings
1477 (setq wisi-string-quote-escape-doubled t)
1478
1479 ;; Handle bracket notation for non-ascii characters in strings. This
1480 ;; is actually more forgiving than that; it will treat
1481 ;; '"foo["bar"]baz" as a single string. But that will be caught by
1482 ;; the compiler, so it's ok for us.
1483 (setq wisi-string-quote-escape '(?\" . ?\[ ))
1484
1485 (set (make-local-variable 'comment-indent-function) 'wisi-comment-indent)
1486
1487 (add-hook 'hack-local-variables-hook 'ada-wisi-post-local-vars nil t)
1488 )
1489
1490 (defun ada-wisi-post-local-vars ()
1491 ;; run after file local variables are read because font-lock-add-keywords
1492 ;; evaluates font-lock-defaults, which depends on ada-language-version.
1493 (font-lock-add-keywords 'ada-mode
1494 ;; use keyword cache to distinguish between 'function ... return <type>;' and 'return ...;'
1495 (list
1496 (list
1497 (concat
1498 "\\<\\("
1499 "return[ \t]+access[ \t]+constant\\|"
1500 "return[ \t]+access\\|"
1501 "return"
1502 "\\)\\>[ \t]*"
1503 ada-name-regexp "?")
1504 '(1 font-lock-keyword-face)
1505 '(2 (if (eq (when (not (ada-in-string-or-comment-p))
1506 (wisi-validate-cache (match-end 2))
1507 (and (wisi-get-cache (match-beginning 2))
1508 (wisi-cache-class (wisi-get-cache (match-beginning 2)))))
1509 'type)
1510 font-lock-type-face
1511 'default)
1512 nil t)
1513 )))
1514
1515 (when global-font-lock-mode
1516 ;; ensure the modified keywords are applied
1517 (font-lock-refresh-defaults))
1518 )
1519
1520 (add-hook 'ada-mode-hook 'ada-wisi-setup)
1521
1522 (setq ada-fix-context-clause 'ada-wisi-context-clause)
1523 (setq ada-goto-declaration-start 'ada-wisi-goto-declaration-start)
1524 (setq ada-goto-declarative-region-start 'ada-wisi-goto-declarative-region-start)
1525 (setq ada-goto-end 'wisi-goto-end)
1526 (setq ada-in-paramlist-p 'ada-wisi-in-paramlist-p)
1527 (setq ada-indent-statement 'wisi-indent-statement)
1528 (setq ada-make-subprogram-body 'ada-wisi-make-subprogram-body)
1529 (setq ada-next-statement-keyword 'wisi-forward-statement-keyword)
1530 (setq ada-prev-statement-keyword 'wisi-backward-statement-keyword)
1531 (setq ada-reset-parser 'wisi-invalidate-cache)
1532 (setq ada-scan-paramlist 'ada-wisi-scan-paramlist)
1533 (setq ada-show-parse-error 'wisi-show-parse-error)
1534 (setq ada-which-function 'ada-wisi-which-function)
1535
1536 (provide 'ada-wisi)
1537 (provide 'ada-indent-engine)
1538
1539 ;; end of file