]> code.delx.au - gnu-emacs-elpa/blob - packages/ada-mode/ada-wisi.el
Merge commit '0cda39255827f283e7578cd469ae42daad9556a2' from js2-mode
[gnu-emacs-elpa] / packages / ada-mode / ada-wisi.el
1 ;;; ada-wisi.el --- Indentation engine for Ada mode, using the wisi generalized LALR parser -*- lexical-binding:t -*-
2 ;;
3 ;; [1] ISO/IEC 8652:2012(E); Ada 2012 reference manual
4 ;;
5 ;; Copyright (C) 2012 - 2016 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-with-params
48 return-without-params
49 statement-end
50 statement-other
51 statement-start
52 ))
53
54 ;;;; indentation
55
56 (defun ada-wisi-current-indentation ()
57 "Return indentation appropriate for point on current line:
58 if not in paren, beginning of line
59 if in paren, pos following paren."
60 (if (not (ada-in-paren-p))
61 (current-indentation)
62
63 (or
64 (save-excursion
65 (let ((line (line-number-at-pos)))
66 (ada-goto-open-paren 1)
67 (when (= line (line-number-at-pos))
68 (current-column))))
69 (save-excursion
70 (back-to-indentation)
71 (current-column)))
72 ))
73
74 (defun ada-wisi-indent-cache (offset cache)
75 "Return indentation of OFFSET plus indentation of line containing point. Point must be at CACHE."
76 (let ((indent (current-indentation)))
77 (cond
78 ;; special cases
79 ;;
80 ((eq 'LEFT_PAREN (wisi-cache-token cache))
81 ;; test/ada_mode-long_paren.adb
82 ;; (RT => RT,
83 ;; Monitor => True,
84 ;; RX_Enable =>
85 ;; (RX_Torque_Subaddress |
86 ;; indenting '(RX_'
87 ;;
88 ;; test/ada_mode-parens.adb
89 ;; return Float (
90 ;; Integer'Value
91 ;; (Local_6));
92 ;; indenting '(local_6)'; 'offset' = ada-indent - 1
93 (+ (current-column) 1 offset))
94
95 ((save-excursion
96 (let ((containing (wisi-goto-containing-paren cache)))
97 (and containing
98 ;; test/ada_mode-conditional_expressions.adb
99 ;; K2 : Integer := (if J > 42
100 ;; then -1
101 ;; indenting 'then'; offset = 0
102 ;;
103 ;; L1 : Integer := (case J is
104 ;; when 42 => -1,
105 ;;
106 ;; test/indent.ads
107 ;; C_S_Controls : constant
108 ;; CSCL_Type :=
109 ;; CSCL_Type'
110 ;; (
111 ;; 1 => -- Used to be aligned on "CSCL_Type'"
112 ;; -- aligned with previous comment.
113 ;; IO_CPU_Control_State_S_Pkg.CPU2_Fault_Status_Type'
114 ;; (Unused2 => 10, -- Used to be aligned on "1 =>"
115 ;; indenting '(Unused2'
116 (+ (current-column) offset)))))
117
118 ;; all other structures
119 (t
120 ;; current cache may be preceded by something on same
121 ;; line. Handle common cases nicely.
122 (while (and cache
123 (or
124 (not (= (current-column) indent))
125 (eq 'EQUAL_GREATER (wisi-cache-token cache))))
126 (when (and
127 (eq 'WHEN (wisi-cache-token cache))
128 (not (eq 'exit_statement (wisi-cache-nonterm cache))))
129 (setq offset (+ offset ada-indent-when)))
130 (setq cache (wisi-goto-containing cache))
131 (setq indent (current-indentation)))
132
133 (cond
134 ((null cache)
135 ;; test/ada_mode-opentoken.ads
136 ;; private package GDS.Commands.Add_Statement is
137 ;; type Instance is new Nonterminal.Instance with null record;
138 ;;
139 ;; test/ada_mode-nominal.adb
140 ;; return B : Integer :=
141 ;; (Local_Function);
142 (+ indent offset))
143
144 ((eq 'label_opt (wisi-cache-token cache))
145 (+ indent (- ada-indent-label) offset))
146
147 (t
148 ;; test/ada_mode-generic_instantiation.ads
149 ;; function Function_1 is new Instance.Generic_Function
150 ;; (Param_Type => Integer,
151 ;;
152 ;; test/ada_mode-nested_packages.adb
153 ;; function Create (Model : in Integer;
154 ;; Context : in String) return String is
155 ;; ...
156 ;; Cache : array (1 .. 10) of Boolean := (True, False, others => False);
157 (+ indent offset))
158 ))
159 )))
160
161 (defun ada-wisi-indent-containing (offset cache &optional before)
162 "Return indentation of OFFSET plus indentation of token containing CACHE.
163 BEFORE should be t when called from ada-wisi-before-cache, nil otherwise."
164 (save-excursion
165 (cond
166 ((markerp (wisi-cache-containing cache))
167 (ada-wisi-indent-cache offset (wisi-goto-containing cache)))
168
169 (t
170 (cond
171 ((ada-in-paren-p)
172 (ada-goto-open-paren 1)
173 (+ (current-column) offset))
174
175 (t
176 ;; at outermost containing statement. If called from
177 ;; ada-wisi-before-cache, we want to ignore OFFSET (indenting
178 ;; 'package' in a package spec). If called from
179 ;; ada-wisi-after-cache, we want to include offset (indenting
180 ;; first declaration in the package).
181 (if before 0 offset))
182 ))
183 )))
184
185 (defun ada-wisi-indent-list-break (cache prev-token)
186 "Return indentation for a token contained by CACHE, which must be a list-break.
187 point must be on CACHE. PREV-TOKEN is the token before the one being indented."
188 (let ((break-point (point))
189 (containing (wisi-goto-containing cache)))
190 (cl-ecase (wisi-cache-token containing)
191 (LEFT_PAREN
192 (if (equal break-point (cadr prev-token))
193 ;; we are indenting the first token after the list-break; not hanging.
194 ;;
195 ;; test/parent.adb
196 ;; Append_To (Formals,
197 ;; Make_Parameter_Specification (Loc,
198 ;; indenting 'Make_...'
199 ;;
200 ;; test/ada_mode-generic_instantiation.ads
201 ;; function Function_1 is new Instance.Generic_Function
202 ;; (Param_Type => Integer,
203 ;; Result_Type => Boolean,
204 ;; Threshold => 2);
205 ;; indenting 'Result_Type'
206 (+ (current-column) 1)
207 ;; else hanging
208 ;;
209 ;; test/ada_mode-parens.adb
210 ;; A :=
211 ;; (1 |
212 ;; 2 => (1, 1, 1),
213 ;; 3 |
214 ;; 4 => (2, 2, 2));
215 ;; indenting '4 =>'
216 (+ (current-column) 1 ada-indent-broken)))
217
218 (IS
219 ;; test/ada_mode-conditional_expressions.adb
220 ;; L1 : Integer := (case J is
221 ;; when 42 => -1,
222 ;; -- comment aligned with 'when'
223 ;; indenting '-- comment'
224 (wisi-indent-paren (+ 1 ada-indent-when)))
225
226 (WITH
227 (cl-ecase (wisi-cache-nonterm containing)
228 (aggregate
229 ;; test/ada_mode-nominal-child.ads
230 ;; (Default_Parent with
231 ;; Child_Element_1 => 10,
232 ;; Child_Element_2 => 12.0,
233 ;; indenting 'Child_Element_2'
234 (wisi-indent-paren 1))
235
236 (aspect_specification_opt
237 ;; test/aspects.ads:
238 ;; type Vector is tagged private
239 ;; with
240 ;; Constant_Indexing => Constant_Reference,
241 ;; Variable_Indexing => Reference,
242 ;; indenting 'Variable_Indexing'
243 (+ (current-indentation) ada-indent-broken))
244 ))
245 )
246 ))
247
248 (defun ada-wisi-before-cache ()
249 "Point is at indentation, before a cached token. Return new indentation for point."
250 (let ((pos-0 (point))
251 (cache (wisi-get-cache (point)))
252 (prev-token (save-excursion (wisi-backward-token)))
253 )
254 (when cache
255 (cl-ecase (wisi-cache-class cache)
256 (block-start
257 (cl-case (wisi-cache-token cache)
258 (IS ;; subprogram body
259 (ada-wisi-indent-containing 0 cache t))
260
261 (RECORD
262 ;; test/ada_mode-nominal.ads; ada-indent-record-rel-type = 3
263 ;; type Private_Type_2 is abstract tagged limited
264 ;; record
265 ;; indenting 'record'
266 ;;
267 ;; type Limited_Derived_Type_1d is
268 ;; abstract limited new Private_Type_1 with
269 ;; record
270 ;; indenting 'record'
271 ;;
272 ;; for Record_Type_1 use
273 ;; record
274 ;; indenting 'record'
275 (let ((containing (wisi-goto-containing cache)))
276 (while (not (memq (wisi-cache-token containing) '(FOR TYPE)))
277 (setq containing (wisi-goto-containing containing)))
278 (+ (current-column) ada-indent-record-rel-type)))
279
280 (t ;; other
281 (ada-wisi-indent-containing ada-indent cache t))))
282
283 (block-end
284 (cl-case (wisi-cache-nonterm cache)
285 (record_definition
286 (save-excursion
287 (wisi-goto-containing cache);; now on 'record'
288 (current-indentation)))
289
290 (t
291 (ada-wisi-indent-containing 0 cache t))
292 ))
293
294 (block-middle
295 (cl-case (wisi-cache-token cache)
296 (WHEN
297 (ada-wisi-indent-containing ada-indent-when cache t))
298
299 (t
300 (ada-wisi-indent-containing 0 cache t))
301 ))
302
303 (close-paren (wisi-indent-paren 0))
304
305 (keyword
306 ;; defer to after-cache)
307 nil)
308
309 (list-break
310 ;; test/ada_mode-parens.adb
311 ;; Foo (X
312 ;; , -- used to get an error here; don't care about the actual indentation
313 ;; indenting ','
314 ;;
315 ;; We don't actually care what the indentation is, since this
316 ;; should only occur while editing; defer to after-cache
317 ;; avoids an error and does something reasonable.
318 nil)
319
320 (name
321 (cond
322 ((let ((temp (save-excursion (wisi-goto-containing cache))))
323 (and temp
324 (memq (wisi-cache-nonterm temp) '(subprogram_body subprogram_declaration))))
325 ;; test/ada_mode-nominal.ads
326 ;; not
327 ;; overriding
328 ;; procedure
329 ;; Procedure_1c (Item : in out Parent_Type_1);
330 ;; indenting 'Procedure_1c'
331 ;;
332 ;; not overriding function
333 ;; Function_2e (Param : in Parent_Type_1) return Float;
334 ;; indenting 'Function_2e'
335 (ada-wisi-indent-containing ada-indent-broken cache t))
336
337 (t
338 ;; defer to ada-wisi-after-cache, for consistency
339 nil)
340 ))
341
342 (name-paren
343 ;; defer to ada-wisi-after-cache, for consistency
344 nil)
345
346 (open-paren
347 (let* ((containing (wisi-goto-containing cache))
348 (containing-pos (point)))
349 (cl-case (wisi-cache-token containing)
350 (COMMA
351 ;; test/ada_mode-parens.adb
352 ;; A : Matrix_Type :=
353 ;; ((1, 2, 3),
354 ;; (4, 5, 6),
355 ;; indenting (4; containing is '),' ; 0
356 ;;
357 ;; test/ada_mode-parens.adb
358 ;; Local_14 : Local_14_Type :=
359 ;; ("123",
360 ;; "456" &
361 ;; ("789"));
362 ;; indenting ("4"; contaning is '3",' ; ada-indent-broken
363
364 (ada-wisi-indent-containing
365 (if (= (nth 1 prev-token) containing-pos) 0 ada-indent-broken)
366 containing))
367
368 (EQUAL_GREATER
369 (setq containing (wisi-goto-containing containing))
370 (cl-ecase (wisi-cache-token containing)
371 (COMMA
372 ;; test/ada_mode-long_paren.adb
373 ;; (RT => RT,
374 ;; Monitor => True,
375 ;; RX_Enable =>
376 ;; (RX_Torque_Subaddress |
377 ;; indenting (RX_Torque
378 (ada-wisi-indent-containing ada-indent-broken containing t))
379 (LEFT_PAREN
380 ;; test/ada_mode-parens.adb
381 ;; (1 =>
382 ;; (1 => 12,
383 ;; indenting '(1 => 12'; containing is '=>'
384 (ada-wisi-indent-cache (1- ada-indent) containing))
385 (WHEN
386 ;; test/ada_mode-conditional_expressions.adb
387 ;; when 1 =>
388 ;; (if J > 42
389 ;; indenting '(if'; containing is '=>'
390 (+ (current-column) -1 ada-indent))
391 (WITH
392 ;; test/aspects.ads
393 ;; function Wuff return Boolean with Pre =>
394 ;; (for all x in U =>
395 ;; indenting '(for'; containing is '=>', 'with', 'function'
396 (ada-wisi-indent-cache (1- ada-indent) containing))
397 ))
398
399 ((FUNCTION PROCEDURE)
400 ;; test/ada_mode-nominal.adb
401 ;; function Function_Access_11
402 ;; (A_Param : in Float)
403 ;; -- EMACSCMD:(test-face "function" font-lock-keyword-face)
404 ;; return access function
405 ;; (A_Param : in Float)
406 ;; return
407 ;; Standard.Float -- Ada mode 4.01, GPS do this differently
408 ;; indenting second '(A_Param)
409 (+ (current-indentation) -1 ada-indent))
410
411 (LEFT_PAREN
412 ;; test/ada_mode-parens.adb
413 ;; or else ((B.all
414 ;; and then C)
415 ;; or else
416 ;; (D
417 ;; indenting (D
418 (+ (current-column) 1 ada-indent-broken))
419
420 (WHEN
421 ;; test/ada_mode-nominal.adb
422 ;;
423 ;; when Local_1 = 0 and not
424 ;; (Local_2 = 1)
425 ;; indenting (Local_2
426 ;;
427 ;; entry E3
428 ;; (X : Integer) when Local_1 = 0 and not
429 ;; (Local_2 = 1)
430 (+ (ada-wisi-current-indentation) ada-indent-broken))
431
432 ((IDENTIFIER selected_component name)
433 ;; test/indent.ads
434 ;; CSCL_Type'
435 ;; (
436 ;; identing (
437 ;;
438 ;; test/ada_mode-parens.adb
439 ;; Check
440 ;; ("foo bar",
441 ;; A
442 ;; (1),
443 ;; A(2));
444 ;; indenting (1)
445 ;;
446 ;; test/ada_mode-parens.adb
447 ;; Local_11 : Local_11_Type := Local_11_Type'
448 ;; (A => Integer
449 ;; (1.0),
450 ;; B => Integer
451 ;; (2.0));
452 ;;
453 ;; test/ada_mode-parens.adb
454 ;; Local_12 : Local_11_Type
455 ;; := Local_11_Type'(A => Integer
456 ;; (1.0),
457 ;; indenting (1.0)
458 (+ (ada-wisi-current-indentation) ada-indent-broken))
459
460 (t
461 (cond
462 ((memq (wisi-cache-class containing) '(block-start statement-start))
463 ;; test/ada_mode-nominal.adb
464 ;; entry E2
465 ;; (X : Integer)
466 ;; indenting (X
467 (ada-wisi-indent-cache ada-indent-broken containing))
468
469 (t
470 ;; Open paren in an expression.
471 ;;
472 ;; test/ada_mode-conditional_expressions.adb
473 ;; L0 : Integer :=
474 ;; (case J is when 42 => -1, when Integer'First .. 41 => 0, when others => 1);
475 ;; indenting (case
476 (ada-wisi-indent-containing ada-indent-broken containing t))
477 ))
478 )))
479
480 (return-with-params;; parameter list
481 (let ((return-pos (point)))
482 (wisi-goto-containing cache nil) ;; matching 'function'
483 (cond
484 ((<= ada-indent-return 0)
485 ;; indent relative to "("
486 (wisi-forward-find-class 'open-paren return-pos)
487 (+ (current-column) (- ada-indent-return)))
488
489 (t
490 (+ (current-column) ada-indent-return))
491 )))
492
493 (return-without-params;; no parameter list
494 (wisi-goto-containing cache nil) ;; matching 'function'
495 (+ (current-column) ada-indent-broken))
496
497 (statement-end
498 (ada-wisi-indent-containing ada-indent-broken cache t))
499
500 (statement-other
501 (save-excursion
502 (let ((containing (wisi-goto-containing cache nil)))
503 (while (not (wisi-cache-nonterm containing))
504 (setq containing (wisi-goto-containing containing)))
505
506 (cond
507 ;; cases to defer to after-cache
508 ((and
509 (eq (wisi-cache-nonterm cache) 'qualified_expression)
510 ;; test/ada_mode-parens.adb Local_13 Integer'
511 (not (eq (wisi-cache-token containing) 'COLON_EQUAL)))
512 ;; _not_ test/indent.ads CSCL_Type'
513 nil)
514
515 ;; handled here
516 (t
517 (cl-case (wisi-cache-token cache)
518 (EQUAL_GREATER
519 (+ (current-column) ada-indent-broken))
520
521 (ELSIF
522 ;; test/g-comlin.adb
523 ;; elsif Current_Argument < CL.Argument_Count then
524 (ada-wisi-indent-cache 0 containing))
525
526 (RENAMES
527 (cl-ecase (wisi-cache-nonterm containing)
528 ((generic_renaming_declaration subprogram_renaming_declaration)
529 (wisi-forward-find-token '(FUNCTION PROCEDURE) pos-0)
530 (let ((pos-subprogram (point))
531 (has-params
532 ;; this is wrong for one return access
533 ;; function case: overriding function Foo
534 ;; return access Bar (...) renames ...;
535 (wisi-forward-find-token 'LEFT_PAREN pos-0 t)))
536 (if has-params
537 (if (<= ada-indent-renames 0)
538 ;; indent relative to paren
539 (+ (current-column) (- ada-indent-renames))
540 ;; else relative to line containing keyword
541 (goto-char pos-subprogram)
542 (+ (current-indentation) ada-indent-renames))
543
544 ;; no params
545 (goto-char pos-subprogram)
546 (+ (current-indentation) ada-indent-broken))
547 ))
548
549 (object_renaming_declaration
550 (+ (current-indentation) ada-indent-broken))
551 ))
552
553 (t
554 (cl-ecase (wisi-cache-nonterm containing)
555 (aggregate
556 ;; test/ada_mode-nominal-child.adb
557 ;; return (Parent_Type_1
558 ;; with 1, 0.0, False);
559 ;; indenting 'with'; containing is '('
560 (+ (current-column) 1))
561
562 (component_declaration
563 ;; test/ada_mode-nominal.ads Record_Type_3 ':'
564 (+ (current-column) ada-indent-broken))
565
566 (entry_body
567 ;; test/ada_mode-nominal.adb
568 ;; entry E2
569 ;; (X : Integer)
570 ;; when Local_1 = 0 and not
571 ;; indenting 'when'; containing is 'entry'
572 (+ (current-column) ada-indent-broken))
573
574 (formal_package_declaration
575 ;; test/ada_mode-generic_package.ads
576 ;; with package A_Package_7 is
577 ;; new Ada.Text_IO.Integer_IO (Num => Formal_Signed_Integer_Type);
578 ;; indenting 'new'; containing is 'with'
579 (+ (current-column) ada-indent-broken))
580
581 ((full_type_declaration
582 protected_type_declaration
583 single_protected_declaration
584 single_task_declaration
585 subtype_declaration
586 task_type_declaration)
587
588 (while (not (memq (wisi-cache-token containing) '(PROTECTED SUBTYPE TASK TYPE)))
589 (setq containing (wisi-goto-containing containing)))
590
591 (cond
592 ((eq (wisi-cache-token cache) 'WITH)
593 (let ((type-col (current-column))
594 (null_private (save-excursion (wisi-goto-end-1 cache)
595 (eq 'WITH (wisi-cache-token (wisi-backward-cache))))))
596 (cond
597 ((eq 'aspect_specification_opt (wisi-cache-nonterm cache))
598 ;; test/aspects.ads
599 ;; subtype Integer_String is String
600 ;; with Dynamic_Predicate => Integer'Value (Integer_String) in Integer
601 ;; indenting 'with'
602 ;;
603 ;; test/ada_mode.ads
604 ;; protected Separate_Protected_Body
605 ;; with
606 ;; Priority => 5
607 ;; indenting 'with'
608 ;;
609 ;; test/ada_nominal.ads
610 ;; task type Task_Type_1 (Name : access String)
611 ;; with
612 ;; Storage_Size => 512 + 256
613 ;; indenting 'with'
614 type-col)
615
616 (null_private
617 ;; 'with null record;' or 'with private;'
618 ;; test/ada_mode-nominal.ads
619 ;; type Limited_Derived_Type_3 is abstract limited new Private_Type_1
620 ;; with null record;
621 ;; indenting 'with'; containing is 'is'
622 (+ type-col ada-indent-broken))
623
624 (t
625 ;; test/ada_mode-nominal.ads
626 ;; type Unconstrained_Array_Type_3 is array (Integer range <>, Standard.Character range <>)
627 ;; of Object_Access_Type_1;
628 ;; indenting 'of'; containing is 'is'
629 ;;
630 ;; type Object_Access_Type_7
631 ;; is access all Integer;
632 ;; indenting 'is'; containing is 'type'
633 (+ type-col ada-indent-record-rel-type)))))
634
635 (t
636 ;; test/ada_mode-nominal.ads
637 ;; type Limited_Derived_Type_2a is abstract limited new Private_Type_1
638 ;; with record
639 ;; indenting 'with record'
640 ;;
641 ;; test/access_in_record.ads
642 ;; type A
643 ;; is new Ada.Streams.Root_Stream_Type with record
644 ;;
645 ;; test/adacore_9717_001.ads A_Long_Name
646 ;; subtype A_Long_Name
647 ;; is Ada.Text_Io.Count;
648 ;; indenting 'is'
649 (+ (current-column) ada-indent-broken))
650 ))
651
652 (generic_instantiation
653 ;; test/ada_mode-generic_instantiation.ads
654 ;; procedure Procedure_7 is
655 ;; new Instance.Generic_Procedure (Integer, Function_1);
656 ;; indenting 'new'
657 (+ (current-column) ada-indent-broken))
658
659 (generic_renaming_declaration
660 ;; indenting keyword following 'generic'
661 (current-column))
662
663 (object_declaration
664 (cl-ecase (wisi-cache-token containing)
665 (COLON
666 ;; test/ada_mode-nominal.ads
667 ;; Anon_Array_3 : array (1 .. 10)
668 ;; of Integer;
669 ;; indenting 'of'
670 (+ (current-indentation) ada-indent-broken))
671
672 (COLON_EQUAL
673 ;; test/indent.ads
674 ;; C_S_Controls : constant
675 ;; CSCL_Type :=
676 ;; CSCL_Type'
677 ;; indenting 'CSCL_Type'
678 (+ (current-indentation) ada-indent-broken))
679
680 (identifier_list
681 ;; test/ada_mode-nominal.adb
682 ;; Local_2 : constant Float
683 ;; := Local_1;
684 (+ (current-indentation) ada-indent-broken))
685 ))
686
687 (private_extension_declaration
688 (cl-ecase (wisi-cache-token cache)
689 (WITH
690 ;; test/aspects.ads
691 ;; type Date_Set is tagged private
692 ;; with
693 ;; indenting 'with'
694 (current-indentation))
695
696 (t
697 ;; test/ada_mode-nominal.ads
698 ;; type Limited_Derived_Type_3 is abstract limited
699 ;; new Private_Type_1 with private;
700 ;; indenting 'new'
701 (+ (current-indentation) ada-indent-broken))
702 ))
703
704 (private_type_declaration
705 ;; test/aspects.ads
706 ;; type Vector is tagged private
707 ;; with
708 ;; indenting 'with'
709 (current-indentation))
710
711 (qualified_expression
712 ;; test/ada_mode-nominal-child.ads
713 ;; Child_Obj_5 : constant Child_Type_1 :=
714 ;; (Parent_Type_1'
715 ;; (Parent_Element_1 => 1,
716 (ada-wisi-indent-cache ada-indent-broken containing))
717
718 (statement
719 (cl-case (wisi-cache-token containing)
720 (label_opt
721 (- (current-column) ada-indent-label))
722
723 (t
724 ;; test/ada_mode-nominal.adb
725 ;; select
726 ;; delay 1.0;
727 ;; then
728 ;; -- ...
729 ;; abort
730 (ada-wisi-indent-cache ada-indent-broken cache))
731 ))
732
733 ((abstract_subprogram_declaration
734 expression_function_declaration
735 subprogram_body
736 subprogram_declaration
737 subprogram_specification
738 null_procedure_declaration)
739 (cl-ecase (wisi-cache-token cache)
740 (IS
741 ;; test/ada_mode-nominal.ads
742 ;; procedure Procedure_1d
743 ;; (Item : in out Parent_Type_1;
744 ;; Item_1 : in Character;
745 ;; Item_2 : out Character)
746 ;; is null;
747 ;; indenting 'is'
748 (+ (current-column) ada-indent-broken))
749
750 (OVERRIDING
751 ;; indenting 'overriding' following 'not'
752 (current-column))
753
754 ((PROCEDURE FUNCTION)
755 ;; indenting 'procedure' or 'function following 'overriding'
756 (current-column))
757
758 (WITH
759 ;; indenting aspect specification on subprogram declaration
760 ;; test/aspects.ads
761 ;; procedure Foo (X : Integer;
762 ;; Y : out Integer)
763 ;; with Pre => X > 10 and
764 ;; indenting 'with'
765 (current-column))
766 ))
767
768 ))))
769 )))) ;; end statement-other
770
771 (statement-start
772 (cond
773 ((eq 'label_opt (wisi-cache-token cache))
774 (ada-wisi-indent-containing (+ ada-indent-label ada-indent) cache t))
775
776 (t
777 (let ((containing-cache (wisi-get-containing-cache cache)))
778 (if (not containing-cache)
779 ;; at bob
780 0
781 ;; not at bob
782 (cl-case (wisi-cache-class containing-cache)
783 ((block-start block-middle)
784 (wisi-goto-containing cache)
785 (cl-case (wisi-cache-nonterm containing-cache)
786 (record_definition
787 (+ (current-indentation) ada-indent))
788
789 (t
790 (ada-wisi-indent-cache ada-indent containing-cache))
791 ))
792
793 (list-break
794 (ada-wisi-indent-list-break cache prev-token))
795
796 ))))
797 ))
798 ))
799 ))
800
801 (defun ada-wisi-after-cache ()
802 "Point is at indentation, not before a cached token. Find previous
803 cached token, return new indentation for point."
804 (save-excursion
805 (let ((start (point))
806 (prev-token (save-excursion (wisi-backward-token)))
807 (cache (wisi-backward-cache)))
808
809 (cond
810 ((not cache) ;; bob
811 0)
812
813 (t
814 (while (memq (wisi-cache-class cache) '(keyword name name-paren type))
815 ;; not useful for indenting
816 (setq cache (wisi-backward-cache)))
817
818 (cl-ecase (wisi-cache-class cache)
819 (block-end
820 ;; indenting block/subprogram name after 'end'
821 (wisi-indent-current ada-indent-broken))
822
823 (block-middle
824 (cl-case (wisi-cache-token cache)
825 (IS
826 (cl-case (wisi-cache-nonterm cache)
827 (case_statement
828 ;; between 'case .. is' and first 'when'; most likely a comment
829 (ada-wisi-indent-containing 0 cache t))
830
831 (t
832 (+ (ada-wisi-indent-containing ada-indent cache t)))
833 ))
834
835 ((THEN ELSE)
836 ;;
837 ;; test/ada_mode-conditional_expressions.adb
838 ;; K3 : Integer := (if
839 ;; J > 42
840 ;; then
841 ;; -1
842 ;; else
843 ;; +1);
844 ;; indenting -1, +1
845 (let ((indent
846 (cl-ecase (wisi-cache-nonterm (wisi-get-containing-cache cache))
847 ((statement if_statement elsif_statement_item) ada-indent)
848 ((if_expression elsif_expression_item) ada-indent-broken))))
849 (ada-wisi-indent-containing indent cache t)))
850
851 (WHEN
852 ;; between 'when' and '=>'
853 (+ (current-column) ada-indent-broken))
854
855 (t
856 ;; block-middle keyword may not be on separate line:
857 ;; function Create (Model : in Integer;
858 ;; Context : in String) return String is
859 (ada-wisi-indent-containing ada-indent cache nil))
860 ))
861
862 (block-start
863 (cl-case (wisi-cache-nonterm cache)
864 (exception_handler
865 ;; between 'when' and '=>'
866 (+ (current-column) ada-indent-broken))
867
868 (if_expression
869 (ada-wisi-indent-containing ada-indent-broken cache nil))
870
871 (select_alternative
872 (ada-wisi-indent-containing (+ ada-indent-when ada-indent-broken) cache nil))
873
874 (t ;; other; normal block statement
875 (ada-wisi-indent-cache ada-indent cache))
876 ))
877
878 (close-paren
879 ;; actual_parameter_part: test/ada_mode-nominal.adb
880 ;; return 1.0 +
881 ;; Foo (Bar) + -- multi-line expression that happens to have a cache at a line start
882 ;; 12;
883 ;; indenting '12'; don't indent relative to containing function name
884 ;;
885 ;; attribute_designator: test/ada_mode-nominal.adb
886 ;; raise Constraint_Error with Count'Image (Line (File)) &
887 ;; "foo";
888 ;; indenting '"foo"'; relative to raise
889 ;;
890 ;; test/ada_mode-slices.adb
891 ;; Put_Line(Day'Image(D1) & " - " & Day'Image(D2) & " = " &
892 ;; Integer'Image(N));
893 ;; indenting 'Integer'
894 (when (memq (wisi-cache-nonterm cache)
895 '(actual_parameter_part attribute_designator))
896 (setq cache (wisi-goto-containing cache)))
897 (ada-wisi-indent-containing ada-indent-broken cache nil))
898
899 (list-break
900 (ada-wisi-indent-list-break cache prev-token))
901
902 (open-paren
903 ;; 1) A parenthesized expression, or the first item in an aggregate:
904 ;;
905 ;; (foo +
906 ;; bar)
907 ;; (foo =>
908 ;; bar)
909 ;;
910 ;; we are indenting 'bar'
911 ;;
912 ;; 2) A parenthesized expression, or the first item in an
913 ;; aggregate, and there is whitespace between
914 ;; ( and the first token:
915 ;;
916 ;; test/ada_mode-parens.adb
917 ;; Local_9 : String := (
918 ;; "123"
919 ;;
920 ;; 3) A parenthesized expression, or the first item in an
921 ;; aggregate, and there is a comment between
922 ;; ( and the first token:
923 ;;
924 ;; test/ada_mode-nominal.adb
925 ;; A :=
926 ;; (
927 ;; -- a comment between paren and first association
928 ;; 1 =>
929 ;;
930 ;; test/ada_mode-parens.adb
931 ;; return Float (
932 ;; Integer'Value
933 ;; indenting 'Integer'
934 (let ((paren-column (current-column))
935 (start-is-comment (save-excursion (goto-char start) (looking-at comment-start-skip))))
936 (wisi-forward-token); point is now after paren
937 (if start-is-comment
938 (skip-syntax-forward " >"); point is now on comment
939 (forward-comment (point-max)); point is now on first token
940 )
941 (if (= (point) start)
942 ;; case 2) or 3)
943 (1+ paren-column)
944 ;; 1)
945 (+ paren-column 1 ada-indent-broken))))
946
947 ((return-with-params return-without-params)
948 ;; test/ada_mode-nominal.adb
949 ;; function Function_Access_1
950 ;; (A_Param : in Float)
951 ;; return
952 ;; Standard.Float
953 ;; indenting 'Standard.Float'
954 ;;
955 ;; test/ada_mode-expression_functions.ads
956 ;; function Square (A : in Float) return Float
957 ;; is (A * A);
958 ;; indenting 'is'
959 ;;
960 ;; test/ada_mode-nominal.ads
961 ;; function Function_2g
962 ;; (Param : in Private_Type_1)
963 ;; return Float
964 ;; is abstract;
965 ;; indenting 'is'
966 (back-to-indentation)
967 (+ (current-column) ada-indent-broken))
968
969 (statement-end
970 (ada-wisi-indent-containing 0 cache nil))
971
972 (statement-other
973 (cl-ecase (wisi-cache-token cache)
974 (ABORT
975 ;; select
976 ;; Please_Abort;
977 ;; then
978 ;; abort
979 ;; -- 'abort' indented with ada-indent-broken, since this is part
980 ;; Titi;
981 (ada-wisi-indent-containing ada-indent cache))
982
983 ;; test/subdir/ada_mode-separate_task_body.adb
984 ((COLON COLON_EQUAL)
985 ;; Local_3 : constant Float :=
986 ;; Local_2;
987 ;;
988 ;; test/ada_mode-nominal.ads
989 ;; type Record_Type_3 (Discriminant_1 : access Integer) is tagged record
990 ;; Component_1 : Integer; -- end 2
991 ;; Component_2 :
992 ;; Integer;
993 ;; indenting 'Integer'; containing is ';'
994 (ada-wisi-indent-cache ada-indent-broken cache))
995
996 (COMMA
997 (cl-ecase (wisi-cache-nonterm cache)
998 (name_list
999 (cl-ecase (wisi-cache-nonterm (wisi-get-containing-cache cache))
1000 (use_clause
1001 ;; test/with_use1.adb
1002 (ada-wisi-indent-containing ada-indent-use cache))
1003
1004 (with_clause
1005 ;; test/ada_mode-nominal.ads
1006 ;; limited private with Ada.Strings.Bounded,
1007 ;; --EMACSCMD:(test-face "Ada.Containers" 'default)
1008 ;; Ada.Containers;
1009 ;;
1010 ;; test/with_use1.adb
1011 (ada-wisi-indent-containing ada-indent-with cache))
1012 ))
1013 ))
1014
1015 (ELSIF
1016 ;; test/g-comlin.adb
1017 ;; elsif Index_Switches + Max_Length <= Switches'Last
1018 ;; and then Switches (Index_Switches + Max_Length) = '?'
1019 (ada-wisi-indent-cache ada-indent-broken cache))
1020
1021 (EQUAL_GREATER
1022 (let ((cache-col (current-column))
1023 (cache-pos (point))
1024 (line-end-pos (line-end-position))
1025 (containing (wisi-goto-containing cache nil)))
1026 (while (eq (wisi-cache-nonterm containing) 'association_list)
1027 (setq containing (wisi-goto-containing containing nil)))
1028
1029 (cl-ecase (wisi-cache-nonterm containing)
1030 ((actual_parameter_part aggregate)
1031 ;; ada_mode-generic_package.ads
1032 ;; with package A_Package_2 is new Ada.Text_IO.Integer_IO (Num =>
1033 ;; Formal_Signed_Integer_Type);
1034 ;; indenting 'Formal_Signed_...', point on '(Num'
1035 ;;
1036 ;; test/ada_mode-parens.adb
1037 ;; (1 =>
1038 ;; 1,
1039 ;; 2 =>
1040 ;; 1 + 2 * 3,
1041 ;; indenting '1,' or '1 +'; point on '(1'
1042 ;;
1043 ;; test/ada_mode-parens.adb
1044 ;; Local_13 : Local_11_Type
1045 ;; := (Integer'(1),
1046 ;; Integer'(2));
1047 ;; indenting 'Integer'; point on '(Integer'
1048 (+ (current-column) 1 ada-indent-broken))
1049
1050 (aspect_specification_opt
1051 ;; test/aspects.ads
1052 ;; with Pre => X > 10 and
1053 ;; X < 50 and
1054 ;; F (X),
1055 ;; Post =>
1056 ;; Y >= X and
1057 ;; indenting 'X < 50' or 'Y >= X'; cache is '=>', point is on '=>'
1058 ;; or indenting 'Post =>'; cache is ',', point is on 'with'
1059 (cl-ecase (wisi-cache-token cache)
1060 (COMMA
1061 (+ (current-indentation) ada-indent-broken))
1062
1063 (EQUAL_GREATER
1064 (if (= (+ 2 cache-pos) line-end-pos)
1065 ;; Post =>
1066 ;; Y >= X and
1067 (progn
1068 (goto-char cache-pos)
1069 (+ (current-indentation) ada-indent-broken))
1070 ;; with Pre => X > 10 and
1071 ;; X < 50 and
1072 (+ 3 cache-col)))
1073 ))
1074
1075 (association_list
1076 (cl-ecase (save-excursion (wisi-cache-token (wisi-goto-containing cache nil)))
1077 (COMMA
1078 (ada-wisi-indent-containing (* 2 ada-indent-broken) cache))
1079 ))
1080
1081 ((case_expression_alternative case_statement_alternative exception_handler)
1082 ;; containing is 'when'
1083 (+ (current-column) ada-indent))
1084
1085 (generic_renaming_declaration
1086 ;; not indenting keyword following 'generic'
1087 (+ (current-column) ada-indent-broken))
1088
1089 (primary
1090 ;; test/ada_mode-quantified_expressions.adb
1091 ;; if (for some J in 1 .. 10 =>
1092 ;; J/2 = 0)
1093 (ada-wisi-indent-containing ada-indent-broken cache))
1094
1095
1096 (select_alternative
1097 ;; test/ada_mode-nominal.adb
1098 ;; or when Started
1099 ;; =>
1100 ;; accept Finish;
1101 ;; indenting 'accept'; point is on 'when'
1102 (+ (current-column) ada-indent))
1103
1104 (variant
1105 ;; test/generic_param.adb
1106 ;; case Item_Type is
1107 ;; when Fix | Airport =>
1108 ;; null;
1109 ;; indenting 'null'
1110 (+ (current-column) ada-indent))
1111
1112 )))
1113
1114 (IS
1115 (setq cache (wisi-goto-containing cache))
1116 (cl-ecase (wisi-cache-nonterm cache)
1117 (full_type_declaration
1118 ;; ada_mode/nominal.ads
1119 ;; type Limited_Derived_Type_1a is abstract limited new
1120 ;; Private_Type_1 with record
1121 ;; Component_1 : Integer;
1122 ;; indenting 'Private_Type_1'; look for 'record'
1123 (let ((type-column (current-column)))
1124 (goto-char start)
1125 (if (wisi-forward-find-token 'RECORD (line-end-position) t)
1126 ;; 'record' on line being indented
1127 (+ type-column ada-indent-record-rel-type)
1128 ;; 'record' on later line
1129 (+ type-column ada-indent-broken))))
1130
1131 ((formal_type_declaration
1132 ;; test/ada_mode-generic_package.ads
1133 ;; type Synchronized_Formal_Derived_Type is abstract synchronized new Formal_Private_Type and Interface_Type
1134 ;; with private;
1135
1136 subtype_declaration
1137 ;; test/ada_mode-nominal.ads
1138 ;; subtype Subtype_2 is Signed_Integer_Type range 10 ..
1139 ;; 20;
1140
1141 private_type_declaration
1142 ;; type Private_Type_2 is abstract tagged limited
1143 ;; private;
1144 )
1145 (+ (current-column) ada-indent-broken))
1146
1147 (null_procedure_declaration
1148 ;; ada_mode-nominal.ads
1149 ;; procedure Procedure_3b is
1150 ;; null;
1151 ;; indenting null
1152 (+ (current-column) ada-indent-broken))
1153
1154 ))
1155
1156 (LEFT_PAREN
1157 ;; test/indent.ads
1158 ;; C_S_Controls : constant
1159 ;; CSCL_Type :=
1160 ;; CSCL_Type'
1161 ;; (
1162 ;; 1 =>
1163 (+ (current-column) 1))
1164
1165 (NEW
1166 ;; ada_mode-nominal.ads
1167 ;; type Limited_Derived_Type_2 is abstract limited new Private_Type_1 with
1168 ;; private;
1169 ;;
1170 ;; test/ada_mode-generic_instantiation.ads
1171 ;; procedure Procedure_6 is new
1172 ;; Instance.Generic_Procedure (Integer, Function_1);
1173 ;; indenting 'Instance'; containing is 'new'
1174 (ada-wisi-indent-containing ada-indent-broken cache))
1175
1176 (OF
1177 ;; ada_mode-nominal.ads
1178 ;; Anon_Array_2 : array (1 .. 10) of
1179 ;; Integer;
1180 (ada-wisi-indent-containing ada-indent-broken cache))
1181
1182 (WHEN
1183 ;; test/ada_mode-parens.adb
1184 ;; exit when A.all
1185 ;; or else B.all
1186 (ada-wisi-indent-containing ada-indent-broken cache))
1187
1188 (WITH
1189 (cl-ecase (wisi-cache-nonterm cache)
1190 (aggregate
1191 ;; test/ada_mode-nominal-child.ads
1192 ;; (Default_Parent with
1193 ;; 10, 12.0, True);
1194 ;; indenting '10'; containing is '('
1195 (ada-wisi-indent-containing 0 cache nil))
1196
1197 (aspect_specification_opt
1198 ;; test/aspects.ads
1199 ;; type Vector is tagged private
1200 ;; with
1201 ;; Constant_Indexing => Constant_Reference,
1202 ;; indenting 'Constant_Indexing'; point is on 'with'
1203 (+ (current-indentation) ada-indent-broken))
1204 ))
1205
1206 ;; otherwise just hanging
1207 ((ACCEPT FUNCTION PROCEDURE RENAMES)
1208 (back-to-indentation)
1209 (+ (current-column) ada-indent-broken))
1210
1211 ))
1212
1213 (statement-start
1214 (cl-case (wisi-cache-token cache)
1215 (WITH ;; with_clause
1216 (+ (current-column) ada-indent-with))
1217
1218 (label_opt
1219 ;; comment after label
1220 (+ (current-column) (- ada-indent-label)))
1221
1222 (t
1223 ;; procedure Procedure_8
1224 ;; is new Instance.Generic_Procedure (Integer, Function_1);
1225 ;; indenting 'is'; hanging
1226 ;;
1227 ;; test/ada_mode-conditional_expressions.adb
1228 ;; K3 : Integer := (if
1229 ;; J > 42
1230 ;; then
1231 ;; -1
1232 ;; else
1233 ;; +1);
1234 ;; indenting J
1235 (ada-wisi-indent-cache ada-indent-broken cache))
1236 ))
1237 )))
1238 )))
1239
1240 (defun ada-wisi-comment ()
1241 "Compute indentation of a comment. For `wisi-indent-calculate-functions'."
1242 ;; We know we are at the first token on a line. We check for comment
1243 ;; syntax, not comment-start, to accomodate gnatprep, skeleton
1244 ;; placeholders, etc.
1245 (when (and (not (= (point) (point-max))) ;; no char after EOB!
1246 (= 11 (syntax-class (syntax-after (point)))))
1247
1248 ;; We are at a comment; indent to previous code or comment.
1249 (cond
1250 ((and ada-indent-comment-col-0
1251 (= 0 (current-column)))
1252 0)
1253
1254 ((or
1255 (save-excursion (forward-line -1) (looking-at "\\s *$"))
1256 (save-excursion (forward-comment -1)(not (looking-at comment-start))))
1257 ;; comment is after a blank line or code; indent as if code
1258 ;;
1259 ;; ada-wisi-before-cache will find the keyword _after_ the
1260 ;; comment, which could be a block-middle or block-end, and that
1261 ;; would align the comment with the block-middle, which is wrong. So
1262 ;; we only call ada-wisi-after-cache.
1263
1264 (let ((indent (ada-wisi-after-cache))
1265 prev-indent next-indent)
1266 (if ada-indent-comment-gnat
1267 ;; match the gnat comment indent style check; comments must
1268 ;; be aligned to one of:
1269 ;;
1270 ;; - multiple of ada-indent
1271 ;; - next non-blank line
1272 ;; - previous non-blank line
1273 ;;
1274 ;; Note that we must indent the prev and next lines, in case
1275 ;; they are not currently correct.
1276 (cond
1277 ((= 0 (% indent ada-indent))
1278 ;; this will handle comments at bob and eob, so we don't
1279 ;; need to worry about those positions in the next checks.
1280 indent)
1281
1282 ((and (setq prev-indent
1283 (save-excursion (forward-line -1)(indent-according-to-mode)(current-indentation)))
1284 (= indent prev-indent))
1285 indent)
1286
1287 ((and (setq next-indent
1288 ;; we use forward-comment here, instead of
1289 ;; forward-line, because consecutive comment
1290 ;; lines are indented to the current one, which
1291 ;; we don't know yet.
1292 (save-excursion (forward-comment (point-max))(indent-according-to-mode)(current-indentation)))
1293 (= indent next-indent))
1294 indent)
1295
1296 (t
1297 (or
1298 prev-indent
1299 next-indent
1300 (floor indent ada-indent)))
1301 )
1302
1303 ;; not forcing gnat style
1304 indent)))
1305
1306 (t
1307 ;; comment is after a comment
1308 (forward-comment -1)
1309 (current-column))
1310 )))
1311
1312 (defun ada-wisi-post-parse-fail ()
1313 "For `wisi-post-parse-fail-hook'."
1314 (save-excursion
1315 (let ((start-cache (wisi-goto-start (or (wisi-get-cache (point)) (wisi-backward-cache)))))
1316 (when start-cache
1317 ;; nil when in a comment at point-min
1318 (indent-region (point) (wisi-cache-end start-cache)))
1319 ))
1320 (back-to-indentation))
1321
1322 ;;;; ada-mode functions (alphabetical)
1323
1324 (defun ada-wisi-declarative-region-start-p (cache)
1325 "Return t if cache is a keyword starting a declarative region."
1326 (cl-case (wisi-cache-token cache)
1327 (DECLARE t)
1328 (IS
1329 (memq (wisi-cache-class cache) '(block-start block-middle)))
1330 (t nil)
1331 ))
1332
1333 (defun ada-wisi-context-clause ()
1334 "For `ada-fix-context-clause'."
1335 (wisi-validate-cache (point-max))
1336 (save-excursion
1337 (goto-char (point-min))
1338 (let ((begin nil)
1339 (end nil)
1340 cache)
1341
1342 (while (not end)
1343 (setq cache (wisi-forward-cache))
1344 (cl-case (wisi-cache-nonterm cache)
1345 (pragma (wisi-goto-end-1 cache))
1346 (use_clause (wisi-goto-end-1 cache))
1347 (with_clause
1348 (when (not begin)
1349 (setq begin (point-at-bol)))
1350 (wisi-goto-end-1 cache))
1351 (t
1352 ;; start of compilation unit
1353 (setq end (point-at-bol))
1354 (unless begin
1355 (setq begin end)))
1356 ))
1357 (cons begin end)
1358 )))
1359
1360 (defun ada-wisi-on-context-clause ()
1361 "For `ada-on-context-clause'."
1362 (let (cache)
1363 (save-excursion
1364 ;; Don't require parse of large file just for ada-find-other-file
1365 (and (< (point-max) wisi-size-threshold)
1366 (setq cache (wisi-goto-statement-start))
1367 (memq (wisi-cache-nonterm cache) '(use_clause with_clause))
1368 ))))
1369
1370 (defun ada-wisi-in-case-expression ()
1371 "For `ada-in-case-expression'."
1372 (save-excursion
1373 ;; Used by ada-align, which does indent, which will require parse
1374 ;; We know we are in a paren.
1375 (ada-goto-open-paren 1)
1376 (let ((cache (wisi-get-cache (point))))
1377 (and cache
1378 (eq (wisi-cache-nonterm cache) 'case_expression)))
1379 ))
1380
1381 (defun ada-wisi-goto-subunit-name ()
1382 "For `ada-goto-subunit-name'."
1383 (wisi-validate-cache (point-max))
1384 (if (not (> wisi-cache-max (point)))
1385 (progn
1386 (message "parse failed; can't goto subunit name")
1387 nil)
1388
1389 (let ((end nil)
1390 cache
1391 (name-pos nil))
1392 (save-excursion
1393 ;; move to top declaration
1394 (goto-char (point-min))
1395 (setq cache (or (wisi-get-cache (point))
1396 (wisi-forward-cache)))
1397 (while (not end)
1398 (cl-case (wisi-cache-nonterm cache)
1399 ((pragma use_clause with_clause)
1400 (wisi-goto-end-1 cache)
1401 (setq cache (wisi-forward-cache)))
1402 (t
1403 ;; start of compilation unit
1404 (setq end t))
1405 ))
1406 (when (eq (wisi-cache-nonterm cache) 'subunit)
1407 (wisi-forward-find-class 'name (point-max)) ;; parent name
1408 (wisi-forward-token)
1409 (wisi-forward-find-class 'name (point-max)) ;; subunit name
1410 (setq name-pos (point)))
1411 )
1412 (when name-pos
1413 (goto-char name-pos))
1414 )))
1415
1416 (defun ada-wisi-goto-declaration-start ()
1417 "For `ada-goto-declaration-start', which see.
1418 Also return cache at start."
1419 (wisi-validate-cache (point))
1420 (unless (> wisi-cache-max (point))
1421 (error "parse failed; can't goto declarative-region-start"))
1422
1423 (let ((cache (wisi-get-cache (point)))
1424 (done nil))
1425 (unless cache
1426 (setq cache (wisi-backward-cache)))
1427 ;; cache is null at bob
1428 (while (not done)
1429 (if cache
1430 (progn
1431 (setq done
1432 (cl-case (wisi-cache-nonterm cache)
1433 ((generic_package_declaration generic_subprogram_declaration)
1434 (eq (wisi-cache-token cache) 'GENERIC))
1435
1436 ((package_body package_declaration)
1437 (eq (wisi-cache-token cache) 'PACKAGE))
1438
1439 ((protected_body protected_type_declaration single_protected_declaration)
1440 (eq (wisi-cache-token cache) 'PROTECTED))
1441
1442 ((abstract_subprogram_declaration
1443 subprogram_body
1444 subprogram_declaration
1445 null_procedure_declaration)
1446 (memq (wisi-cache-token cache) '(NOT OVERRIDING FUNCTION PROCEDURE)))
1447
1448 (task_type_declaration
1449 (eq (wisi-cache-token cache) 'TASK))
1450
1451 ))
1452 (unless done
1453 (setq cache (wisi-goto-containing cache nil))))
1454 (setq done t))
1455 )
1456 cache))
1457
1458 (defun ada-wisi-goto-declaration-end ()
1459 "For `ada-goto-declaration-end', which see."
1460 ;; first goto-declaration-start, so we get the right end, not just
1461 ;; the current statement end.
1462 (wisi-goto-end-1 (ada-wisi-goto-declaration-start)))
1463
1464 (defun ada-wisi-goto-declarative-region-start ()
1465 "For `ada-goto-declarative-region-start', which see."
1466 (wisi-validate-cache (point))
1467 (unless (> wisi-cache-max (point))
1468 (error "parse failed; can't goto declarative-region-start"))
1469
1470 (let ((done nil)
1471 (first t)
1472 (cache
1473 (or
1474 (wisi-get-cache (point))
1475 ;; we use forward-cache here, to handle the case where point is after a subprogram declaration:
1476 ;; declare
1477 ;; ...
1478 ;; function ... is ... end;
1479 ;; <point>
1480 ;; function ... is ... end;
1481 (wisi-forward-cache))))
1482 (while (not done)
1483 (if (ada-wisi-declarative-region-start-p cache)
1484 (progn
1485 (wisi-forward-token)
1486 (setq done t))
1487 (cl-case (wisi-cache-class cache)
1488 ((block-middle block-end)
1489 (setq cache (wisi-prev-statement-cache cache)))
1490
1491 (statement-start
1492 ;; 1) test/ada_mode-nominal.adb
1493 ;; protected body Protected_1 is -- target 2
1494 ;; <point>
1495 ;; want target 2
1496 ;;
1497 ;; 2) test/ada_mode-nominal.adb
1498 ;; function Function_Access_1
1499 ;; (A_Param <point> : in Float)
1500 ;; return
1501 ;; Standard.Float
1502 ;; is -- target 1
1503 ;; want target 1
1504 ;;
1505 ;; 3) test/ada_mode-nominal-child.adb
1506 ;; overriding <point> function Function_2c (Param : in Child_Type_1)
1507 ;; return Float
1508 ;; is -- target Function_2c
1509 ;; want target
1510
1511 (if first
1512 ;; case 1
1513 (setq cache (wisi-goto-containing cache t))
1514 ;; case 2, 3
1515 (cl-case (wisi-cache-nonterm cache)
1516 (subprogram_body
1517 (while (not (eq 'IS (wisi-cache-token cache)))
1518 (setq cache (wisi-next-statement-cache cache))))
1519 (t
1520 (setq cache (wisi-goto-containing cache t)))
1521 )))
1522 (t
1523 (setq cache (wisi-goto-containing cache t)))
1524 ))
1525 (when first (setq first nil)))
1526 ))
1527
1528 (defun ada-wisi-in-paramlist-p (&optional parse-result)
1529 "For `ada-in-paramlist-p'."
1530 (wisi-validate-cache (point))
1531 ;; (info "(elisp)Parser State" "*syntax-ppss*")
1532 (let ((parse-result (or parse-result (syntax-ppss)))
1533 cache)
1534 (and (> (nth 0 parse-result) 0)
1535 ;; cache is nil if the parse failed
1536 (setq cache (wisi-get-cache (nth 1 parse-result)))
1537 (eq 'formal_part (wisi-cache-nonterm cache)))
1538 ))
1539
1540 (defun ada-wisi-make-subprogram-body ()
1541 "For `ada-make-subprogram-body'."
1542 (wisi-validate-cache (point))
1543 (when wisi-parse-failed
1544 (error "syntax parse failed; cannot create body"))
1545
1546 (let* ((begin (point))
1547 (end (save-excursion (wisi-forward-find-class 'statement-end (point-max)) (point)))
1548 (cache (wisi-forward-find-class 'name end))
1549 (name (buffer-substring-no-properties
1550 (point)
1551 (+ (point) (wisi-cache-last cache)))))
1552 (goto-char end)
1553 (newline)
1554 (insert " is begin\nnull;\nend ");; legal syntax; parse does not fail
1555 (insert name)
1556 (forward-char 1)
1557
1558 ;; newline after body to separate from next body
1559 (newline-and-indent)
1560 (indent-region begin (point))
1561 (forward-line -2)
1562 (back-to-indentation); before 'null;'
1563 ))
1564
1565 (defun ada-wisi-scan-paramlist (begin end)
1566 "For `ada-scan-paramlist'."
1567 (wisi-validate-cache end)
1568 (when (< wisi-cache-max end)
1569 (error "parse failed; can't scan paramlist"))
1570
1571 (goto-char begin)
1572 (let (token
1573 text
1574 identifiers
1575 (aliased-p nil)
1576 (in-p nil)
1577 (out-p nil)
1578 (not-null-p nil)
1579 (access-p nil)
1580 (constant-p nil)
1581 (protected-p nil)
1582 (type nil)
1583 type-begin
1584 type-end
1585 (default nil)
1586 (default-begin nil)
1587 param
1588 paramlist
1589 (done nil))
1590 (while (not done)
1591 (let ((token-text (wisi-forward-token)))
1592 (setq token (nth 0 token-text))
1593 (setq text (wisi-token-text token-text)))
1594 (cond
1595 ((equal token 'COMMA) nil);; multiple identifiers
1596
1597 ((equal token 'COLON)
1598 ;; identifiers done. find type-begin; there may be no mode
1599 (skip-syntax-forward " ")
1600 (setq type-begin (point))
1601 (save-excursion
1602 (while (member (car (wisi-forward-token)) '(ALIASED IN OUT NOT NULL ACCESS CONSTANT PROTECTED))
1603 (skip-syntax-forward " ")
1604 (setq type-begin (point)))))
1605
1606 ((equal token 'ALIASED) (setq aliased-p t))
1607 ((equal token 'IN) (setq in-p t))
1608 ((equal token 'OUT) (setq out-p t))
1609 ((and (not type-end)
1610 (member token '(NOT NULL)))
1611 ;; "not", "null" could be part of the default expression
1612 (setq not-null-p t))
1613 ((equal token 'ACCESS) (setq access-p t))
1614 ((equal token 'CONSTANT) (setq constant-p t))
1615 ((equal token 'PROTECTED) (setq protected-p t))
1616
1617 ((equal token 'COLON_EQUAL)
1618 (setq type-end (save-excursion (backward-char 2) (skip-syntax-backward " ") (point)))
1619 (skip-syntax-forward " ")
1620 (setq default-begin (point))
1621 (wisi-forward-find-token 'SEMICOLON end t))
1622
1623 ((equal token 'LEFT_PAREN)
1624 ;; anonymous access procedure type
1625 (goto-char (scan-sexps (1- (point)) 1)))
1626
1627 ((member token '(SEMICOLON RIGHT_PAREN))
1628 (when (not type-end)
1629 (setq type-end (save-excursion (backward-char 1) (skip-syntax-backward " ") (point))))
1630
1631 (setq type (buffer-substring-no-properties type-begin type-end))
1632
1633 (when default-begin
1634 (setq default (buffer-substring-no-properties default-begin (1- (point)))))
1635
1636 (when (equal token 'RIGHT_PAREN)
1637 (setq done t))
1638
1639 (setq param (list (reverse identifiers)
1640 aliased-p in-p out-p not-null-p access-p constant-p protected-p
1641 type default))
1642 (cl-pushnew param paramlist :test #'equal)
1643 (setq identifiers nil
1644 aliased-p nil
1645 in-p nil
1646 out-p nil
1647 not-null-p nil
1648 access-p nil
1649 constant-p nil
1650 protected-p nil
1651 type nil
1652 type-begin nil
1653 type-end nil
1654 default nil
1655 default-begin nil))
1656
1657 (t
1658 (when (not type-begin)
1659 (cl-pushnew text identifiers :test #'equal)))
1660 ))
1661 paramlist))
1662
1663 (defun ada-wisi-which-function-1 (keyword add-body)
1664 "Used in `ada-wisi-which-function'."
1665 (let* ((cache (wisi-forward-find-class 'name (point-max)))
1666 (result (wisi-cache-text cache)))
1667
1668 ;; See comment at ada-mode.el on why we don't overwrite ff-function-name.
1669 (when (not ff-function-name)
1670 (setq ff-function-name
1671 (concat
1672 keyword
1673 (when add-body "\\s-+body")
1674 "\\s-+"
1675 result
1676 ada-symbol-end)))
1677 result))
1678
1679 (defun ada-wisi-which-function ()
1680 "For `ada-which-function'."
1681 (wisi-validate-cache (point))
1682 (save-excursion
1683 (let ((result nil)
1684 (cache (condition-case nil (ada-wisi-goto-declaration-start) (error nil))))
1685 (if (null cache)
1686 ;; bob or failed parse
1687 (setq result "")
1688
1689 (when (memq (wisi-cache-nonterm cache)
1690 '(generic_package_declaration generic_subprogram_declaration))
1691 ;; name is after next statement keyword
1692 (wisi-next-statement-cache cache)
1693 (setq cache (wisi-get-cache (point))))
1694
1695 ;; add or delete 'body' as needed
1696 (cl-ecase (wisi-cache-nonterm cache)
1697 (package_body
1698 (setq result (ada-wisi-which-function-1 "package" nil)))
1699
1700 ((package_declaration
1701 generic_package_declaration) ;; after 'generic'
1702 (setq result (ada-wisi-which-function-1 "package" t)))
1703
1704 (protected_body
1705 (setq result (ada-wisi-which-function-1 "protected" nil)))
1706
1707 ((protected_type_declaration single_protected_declaration)
1708 (setq result (ada-wisi-which-function-1 "protected" t)))
1709
1710 ((abstract_subprogram_declaration
1711 subprogram_declaration
1712 generic_subprogram_declaration ;; after 'generic'
1713 null_procedure_declaration)
1714 (setq result (ada-wisi-which-function-1
1715 (wisi-cache-text (wisi-forward-find-token '(FUNCTION PROCEDURE) (point-max)))
1716 nil))) ;; no 'body' keyword in subprogram bodies
1717
1718 (subprogram_body
1719 (setq result (ada-wisi-which-function-1
1720 (wisi-cache-text (wisi-forward-find-token '(FUNCTION PROCEDURE) (point-max)))
1721 nil)))
1722
1723 (task_type_declaration
1724 (setq result (ada-wisi-which-function-1 "task" t)))
1725
1726 ))
1727 result)))
1728
1729 ;;;; debugging
1730 (defun ada-wisi-debug-keys ()
1731 "Add debug key definitions to `ada-mode-map'."
1732 (interactive)
1733 (define-key ada-mode-map "\M-e" 'wisi-show-parse-error)
1734 (define-key ada-mode-map "\M-h" 'wisi-show-containing-or-previous-cache)
1735 (define-key ada-mode-map "\M-i" 'wisi-goto-statement-end)
1736 (define-key ada-mode-map "\M-j" 'wisi-show-cache)
1737 (define-key ada-mode-map "\M-k" 'wisi-show-token)
1738 )
1739
1740 (defun ada-wisi-number-p (token-text)
1741 "Return t if TOKEN-TEXT plus text after point matches the
1742 syntax for a real literal; otherwise nil. point is after
1743 TOKEN-TEXT; move point to just past token."
1744 ;; test in test/wisi/ada-number-literal.input
1745 ;;
1746 ;; starts with a simple integer
1747 (let ((end (point)))
1748 ;; this first test must be very fast; it is executed for every token
1749 (when (and (memq (aref token-text 0) '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
1750 (string-match "^[0-9_]+$" token-text))
1751 (cond
1752 ((= (char-after) ?#)
1753 ;; based number
1754 (forward-char 1)
1755 (if (not (looking-at "[0-9a-fA-F_]+"))
1756 (progn (goto-char end) nil)
1757
1758 (goto-char (match-end 0))
1759 (cond
1760 ((= (char-after) ?#)
1761 ;; based integer
1762 (forward-char 1)
1763 t)
1764
1765 ((= (char-after) ?.)
1766 ;; based real?
1767 (forward-char 1)
1768 (if (not (looking-at "[0-9a-fA-F]+"))
1769 (progn (goto-char end) nil)
1770
1771 (goto-char (match-end 0))
1772
1773 (if (not (= (char-after) ?#))
1774 (progn (goto-char end) nil)
1775
1776 (forward-char 1)
1777 (setq end (point))
1778
1779 (if (not (memq (char-after) '(?e ?E)))
1780 ;; based real, no exponent
1781 t
1782
1783 ;; exponent?
1784 (forward-char 1)
1785 (if (not (looking-at "[+-]?[0-9]+"))
1786 (progn (goto-char end) t)
1787
1788 (goto-char (match-end 0))
1789 t
1790 )))))
1791
1792 (t
1793 ;; missing trailing #
1794 (goto-char end) nil)
1795 )))
1796
1797 ((= (char-after) ?.)
1798 ;; decimal real number?
1799 (forward-char 1)
1800 (if (not (looking-at "[0-9_]+"))
1801 ;; decimal integer
1802 (progn (goto-char end) t)
1803
1804 (setq end (goto-char (match-end 0)))
1805
1806 (if (not (memq (char-after) '(?e ?E)))
1807 ;; decimal real, no exponent
1808 t
1809
1810 ;; exponent?
1811 (forward-char 1)
1812 (if (not (looking-at "[+-]?[0-9]+"))
1813 (progn (goto-char end) t)
1814
1815 (goto-char (match-end 0))
1816 t
1817 ))))
1818
1819 (t
1820 ;; just an integer
1821 t)
1822 ))
1823 ))
1824
1825 (defun ada-wisi-setup ()
1826 "Set up a buffer for parsing Ada files with wisi."
1827 (wisi-setup '(ada-wisi-comment
1828 ada-wisi-before-cache
1829 ada-wisi-after-cache)
1830 'ada-wisi-post-parse-fail
1831 ada-wisi-class-list
1832 ada-grammar-wy--keyword-table
1833 ada-grammar-wy--token-table
1834 ada-grammar-wy--parse-table)
1835
1836 ;; Handle escaped quotes in strings
1837 (setq wisi-string-quote-escape-doubled t)
1838
1839 (set (make-local-variable 'comment-indent-function) 'wisi-comment-indent)
1840 )
1841
1842 (add-hook 'ada-mode-hook 'ada-wisi-setup)
1843
1844 (setq ada-fix-context-clause 'ada-wisi-context-clause)
1845 (setq ada-goto-declaration-end 'ada-wisi-goto-declaration-end)
1846 (setq ada-goto-declaration-start 'ada-wisi-goto-declaration-start)
1847 (setq ada-goto-declarative-region-start 'ada-wisi-goto-declarative-region-start)
1848 (setq ada-goto-end 'wisi-goto-statement-end)
1849 (setq ada-goto-subunit-name 'ada-wisi-goto-subunit-name)
1850 (setq ada-in-paramlist-p 'ada-wisi-in-paramlist-p)
1851 (setq ada-indent-statement 'wisi-indent-statement)
1852 (setq ada-make-subprogram-body 'ada-wisi-make-subprogram-body)
1853 (setq ada-next-statement-keyword 'wisi-forward-statement-keyword)
1854 (setq ada-on-context-clause 'ada-wisi-on-context-clause)
1855 (setq ada-in-case-expression 'ada-wisi-in-case-expression)
1856 (setq ada-prev-statement-keyword 'wisi-backward-statement-keyword)
1857 (setq ada-reset-parser 'wisi-invalidate-cache)
1858 (setq ada-scan-paramlist 'ada-wisi-scan-paramlist)
1859 (setq ada-show-parse-error 'wisi-show-parse-error)
1860 (setq ada-which-function 'ada-wisi-which-function)
1861
1862 (provide 'ada-wisi)
1863 (provide 'ada-indent-engine)
1864
1865 ;; end of file