1
// kate: space-indent on; indent-width 4; replace-tabs on; remove-trailing-spaces all;
2
// kate: syntax pascal; indent-mode pascal;
4
// these variables are understood by the pascal indenter ...
5
// kate: cfgIndentCase false; // indent elements in a case statement
6
// kate: cfgIndentBegin 2; // indent 'begin' this many spaces
7
// kate: debugMode false; // show how indent is determined
8
// kate: cfgAutoInsertStar true; // auto insert '*' in (* ... *)-comments
9
// kate: cfgSnapParen true; // snap ')' to '*)' in comments
11
(********************************************** // check: indent OK?
13
* Commment to test alignment *
16
**********************************************)
18
(*************************************************************************
21
Relative alignment should be kept ...
22
After indent, first character of this line should
23
still remain under the 'v' in relative
25
*************************************************************************)
39
type x = record a: real; c : char end;
41
// r = record ... vs unfinished typedef
42
rType = record // cr here ==> type def
43
a: aType; // this can be realigned manually
44
b: bType; // should follow line above
49
{ unfinished type declaration }
50
( red, // CHECK: everything should line up below this
51
orange, // this must follow line above
57
// CHECK: the comments should line up as well
58
// closing paren should align to list when it's left shifted
59
// to opening paren otherwise
62
otherTypeDef = integer;
64
// CHECK: next line should keep its relative alignment
66
ant = RECORD CASE F: BOOLEAN OF
69
); // parens should line up
75
END; // 'case' + 'record' share same 'end'
81
RW: ARRAY [AASY..ZZSY]
82
OF (*RESERVED WORDS*) PACKED ARRAY [1..RWLENGTH,
83
2..66 ] // CHECK: this line should be indented
84
OF CHAR; // CHECK: this line should be indented from array
86
RW: ARRAY [AASY..ZZSY] OF (*RESERVED WORDS*)
87
PACKED ARRAY [1..RWLENGTH] OF CHAR;
96
i: integer; // CHECK: can be aligned manually, but default indented from record
97
r: real; // should align with line immediately above
98
a: array[1..11] of char;
103
); // parens should line up
104
false: ( ted : array[
109
end; // 'case' + 'record' share same 'end'
111
tArray = array[0..17] of real; // should indent wrt 'type'
114
red, // CHECK: this line can be adjusted manually
115
orange, // this must follow line above
121
// CHECK: the comments should line up as well
122
// closing paren should align to list when it's left shifted
123
// to opening paren otherwise
126
blah = char; // should align after type
128
optionset = set of options;
133
r: real; // should line up with first member
134
a: array[0..7] of char;
135
end; // CHECK: end is outdented relative to first member
137
optionset : set of options;
139
options : ( crsupp,crbefore,blinbefore,
140
dindonkey,dindent,spbef,
142
inbytab, { indent current margin (was indent from symbol pos) }
144
finl { force symbol to follow on same line as previous symbol }
147
optionset = set of options;
149
aa: array[ 1..9, // should be indented after cr
151
of ( crsupp,crbefore,blinbefore,
152
dindonkey,dindent,spbef,
154
inbytab, { indent current margin (was indent from symbol pos) }
156
finl { force symbol to follow on same line as previous symbol }
162
of record // cr after here should indent from record
163
a: array[1..6] of char;
167
{ CHECK: following text should keep indent relative to open/close brace
168
when annotating, behavior of "external", "end" and possibly other keywords
169
depends on whether we are in procedure declaration,
170
item (var/const/type) declaration, or statements
171
NOTE: here we see why it's better to make the comment align with the
172
following line (ie the procedure call) rather than the preceding
173
line (ie the 'end'. Easy in theory, messy in practice.
177
procedure AVeryVeryLongFunctionName(const A : tRealArrayType;
179
var H : tRealArrayType); forward;
181
(*************************************************************************
182
CHECK: comment is correctly aligned with precedinging statement
187
N - longer description, but
188
still preserving relative format
191
H - other meaningful description
196
*************************************************************************)
198
var size : (small, medium, large);
201
var r : record i: integer; c: char end;
203
a: array[ 1..9, // should be indented after var
204
'a'..'z' // non-code, should line up with opening arg
207
begin (* AVeryVeryLongFunctionName *)
213
f(32); //CHECK: label forced to margin, statement is on new line with comment
223
begin s1; s2; s3 end;
225
for i := firstCh to lastCh do chtype[chr(i)] := none;
226
value['0'] := 0; value['1'] := 1; value['2'] := 2;
227
value['3'] := 3; value['4'] := 4; value['5'] := 5;
228
value['6'] := 6; value['7'] := 7; value['8'] := 8;
230
value['A'] := 10; value['B'] := 11; value['C'] := 12;
231
value['D'] := 13; value['E'] := 14; value['F'] := 15;
232
value['a'] := 10; value['b'] := 11; value['c'] := 12;
233
value['d'] := 13; value['e'] := 14; value['f'] := 15;
235
IF NOT (CH IN ['{','}']) THEN
237
BEGIN IF CH <= 'Z' THEN CMDCH := CH ELSE CMDCH := CHR(ORD(CH)-ORD('a')+ORD('A') );
241
ELSE IF CMDCH = 'T' THEN
243
ELSE IF CMDCH = 'I' THEN
245
ELSE IF CMDCH = 'Z' THEN
249
REPEAT commandIn UNTIL numRem = 0;
254
ELSE IF CMDCH = 'Q' THEN begin
256
end ELSE IF CMDCH = 'V' THEN
258
else if COMMAND.STRVAL = 'unknown' then
262
(numStr[1] IN ['+', '-', '0' .. '9', '?']) // CHECK: indent
264
Power.Supply := '"AC' ELSE Power.Supply := '"DC'
265
end else if CommandResult.Str = 'helpIamLost' then begin
266
Power.Supply := SetPowerSupplyCommands(Plus15V.Increase(Amps));
267
end else if (line = 'SHORT') OR (line = 'OPEN') THEN BEGIN
269
{*smoke billows out*}
276
(line = 'OPEN') OR (line = 'CLOSED') THEN
282
CircuitBreaker(wishfulThinking)
283
END else if cond then
285
END ELSE IF (line = 'PLUS') OR (line = 'MINUS') THEN Transform(RedPhase)
286
ELSE IF (line = 'RED') OR (line = 'BLACK') THEN Transform(BluePhase)
287
ELSE IF line = 'XX' THEN Transistor
288
ELSE IF line = 'YYYY' THEN SetCurrent(FiveAmps)
289
ELSE IF line = 'QQQQ' THEN SetPower(FiveWatts)
290
ELSE IF line = 'AAAAA' THEN Power(FiveAmps)
292
{* QWERTY COMMENT LLLLLLLLL ####### *}
295
actualphase := YellowPhase;
296
AdjustLinePhase(NewPhase);
299
line = 'Noisy' THEN Filter
300
ELSE IF line = 'BLUE' THEN
302
AdjustLinePhase(XPhase);
305
line = 'RED' THEN BEGIN Swap; Hope END
307
line = '415' THEN iNumPut415
309
// a statement like this has no chance of being correctly indented ...
310
// otoh, it shouldn't turn out catastrophically wrong.
311
line = 'REFL' THEN FOR i := 1 TO numLines DO
312
WriteLn('level=', powerLevel[i], ' ', name[i]+'='+power[i])
314
line = 'HIGH' THEN reduce
316
line = 'LOW' THEN increase
320
WHILE powerlevel[NumPowers] = level DO NumPowers := NumPowers-1;
327
Z := X*240.0 + i*Y*240;
330
ELSE IF line = 'HILD' THEN motor(induction)
331
ELSE IF (line = 'REV') THEN BEGIN
333
IF (NOT(v IN [#14..#240])) THEN
334
WriteLn(' POWER SUPPLY OUT OF SPEC') ELSE specValue := v;
337
ELSE IF (line = 'OK') THEN BEGIN
338
IncomingSupply := True; specValidate END
339
ELSE IF (line = 'NOK') THEN BEGIN IncomingSupply := False; specValidate END
341
GeneratedPowerLine.IncreasePower(
342
'Unknown input power "%s"', [SwitchPower.Current]); // CHECK: string should not cause problems
347
end (* AVeryVeryLongFunctionName *) ; // check that only necessary work is done to align
352
fred : integer; // should line up with alf
357
BEGIN s := do; WriteLn(s) END;
360
procedure getbyte; // CHECK: cr after this line is **not** indented
362
var // CHECK: cr after this line **is** indented
368
// if c then begin s1; s2 end; // strip these lines
369
// begin // normal case
370
// end // normal case
371
// end else if begin // should be OK since /end/ tested last
372
// need to consider ...
373
// if c1 then begin s1; s2 end
375
// <-- align this line
377
{ checking multi line statements }
380
while aaaaaaaaaaaaaaaaaaaaaaa
389
s5; // the ';' here links to the ';' after the 'case' below
402
1: s1; // CHECK: cr here should go to new case value!
413
1: s1; // CHECK: cr here should go to new case value!
428
writeln(' and lots');
435
writeln(' and lots');
439
begin // CHECK: should be indented after case value
454
begin // CKECK: should indent one level from case value
455
s3; // CHECK: should be indented another level
460
if c then begin // cr here is OK
468
s4; // incorrect code, indenter should expect a case value here
476
end; // stress test: else/end crossed over !!
484
and c2 then begin // can be aligned manually
485
a := 12; // should be indented one level from if statement
489
and c2 // can be aligned manually
492
a := 12; // should be indented one level from if statement
505
vvvvv // CHECK: indent lines with zzzzzzzzz
517
while not ( ((currchar.value = '*') and (nextchar.value = ')'))
518
or (currchar.value = '}') // args should line up inside parens
519
or (nextchar.name = endofline)
520
or ( sym^.length >= maxsymbolsize-2 )
521
or (nextchar.name = filemark)) do
522
storenextchar(sym^.length,sym^.value); // should be indented from while
524
while not (currchar.value = '*') and (nextchar.value = ')')
525
or (currchar.value = '}') // possible to realign first line manually
526
or (nextchar.name = endofline) // CHECK: other lines should follow first line // CHECK:: indents line up
527
or ( sym^.length >= maxsymbolsize-2 )
528
or (nextchar.name = filemark) do
529
storenextchar(sym^.length,sym^.value); // should be indented from while
531
while not (currchar.value = '*') and (nextchar.value = ')')
532
or (currchar.value = '}') // possible to realign first line manually
533
or (nextchar.name = endofline) // CHECK: other lines should follow first line // CHECK:: indents line up
534
or ( sym^.length >= maxsymbolsize-2 )
535
or (nextchar.name = filemark)
537
storenextchar(sym^.length,sym^.value); // should be indented from while
539
dblchar[becomes] := ':=';
540
dblchar[opencomment] := '(*'; // not start of comment!
541
sglchar[semicolon] := ';';
542
sglchar[colon] := ':';
543
sglchar[equals] := '=';
544
sglchar[openparen] := '(';
545
sglchar[closeparen] := ')';
546
sglchar[period] := '.';
547
sglchar[opencomment] := '{';
548
sglchar[closecomment] := '}';
554
if ch in ['0'..'9'] then
556
else if ch = '''' then begin
558
end else if (ch = blank) or (ch = chr(tab)) then
560
else name := otherchar
563
else if eoln(infile) then
567
if c1 then begin s1; s2 end
569
inlines := inlines + 1;
576
if ch in ['a'..'z','A'..'Z','_'] then
579
if ch in ['0'..'9'] then
581
else if ch = '''' then while c do
586
else if (ch = blank) or (ch = chr(tab)) then
588
else name := otherchar
592
# pp lines go to start of line, unless they are in a comment
597
cccccc; // CHECK: this aligns with code
598
# // CHECK: preprocessor lines go to start of line
601
if c2 then while c do
611
function f1( var z: integer;
613
t : boolean ) : integer; // indentation should line up
615
type tArray = array[0..17] of real;
617
r= record a: integer; c: char; end;
619
// nested variant record - too hard to get right. tough
623
1,2,8 : (Y : Longint;
625
3 : (Z : Longint); // CHECK: parens inside parens aligned correctly
629
commands = ( crsupp,crbefore,blinbefore,
630
dindonkey,dindent,spbef,
632
inbytab, { indent current margin (was indent from symbol pos) }
634
finl { force symbol to follow on same line as previous symbol }
638
i: integer; // should indent after record
640
a: array[1..11] of char;
646
fred : real; // should be indented after case value
653
moe: char; // should align to ''ted''
655
end; // end of case + end of record
657
commandset = set of commands; // should be aligned to 'record', not 'case'
660
case currsym^.name of
662
{ for procs, etc just record that we have one, wait for name }
663
progsym, procsym, funcsym: begin
664
symbol_seen := procsym;
665
proc_state := proc_header;
666
annotate_push( procsym );
668
s1; // coding error, a case value should be here
669
{ remember we are in the declaraions part }
670
varsym, typesym, constsym, labelsym:
671
proc_state := proc_declarations;
673
{ if it's a proc, there will be no begin/end ==> pop info we just saved
674
if it's an external var ==> do nothing }
675
forwardsym, externalsym:
676
if proc_state = proc_header then
679
tok := annotate_pop_tok;
680
if annotate_trace in traceFlags then
681
writeln( 'undo ', tok.val:tok.len );
684
{ if a proc has just occurred, this is its name
685
otherwise, remember it, just in case it's a record name }
688
if symbol_seen = procsym then begin
689
tok.val := currsym^.value;
690
tok.len := currsym^.length;
691
annotate_push_tok( tok );
692
symbol_seen := othersym;
695
annotate_temp_tok.val := currsym^.value;
696
annotate_temp_tok.len := currsym^.length;
700
{ we have the name, push it so the end symbol can get it back }
702
annotate_push_tok(annotate_temp_tok);
703
annotate_push( recordsym );
704
symbol_seen := recordsym;
707
{ we must remember these so they can pushed if the begin symbol occurs }
708
ifsym, forsym, whilesym, withsym:
710
symbol_seen := currsym^.name;
713
{ this is the second part of an if statement }
715
symbol_seen := ifsym;
717
{ if in a declaration ==> ignore
718
if in a statement (assume case statement) ==> prepare for possible begin following }
720
if proc_state = proc_statements then
721
symbol_seen := colon;
723
{ reset symbol_seen }
725
symbol_seen := semicolon;
727
{ could be the begin of a proc
728
==> get value, leaving it for the corresponding end symbol
729
or it could be part of an if, etc,
730
==> push the symbol so the end symbol knows what to do }
732
proc_state := proc_statements;
733
if symbol_seen in [ifsym, forsym, whilesym, withsym, elsesym, colon] then begin
734
annotate_push( symbol_seen );
737
sym := annotate_peek;
738
if sym = procsym then begin
739
{ this is a proc begin, add annotation }
740
annotate_pending_tok := true;
741
annotate_temp_tok := annotate_peek_tok;
745
if annotate_trace in traceFlags then
746
writeln( infilename,' line ', inlines, ': orphaned begin found' );
747
annotate_push( nosymbol );
752
{ push the symbol so the end symbol can get it back }
753
casesym: annotate_push( casesym );
755
{ end of proc, end of record ==> pop name
756
end of if, etc statement ==> pop symbol
757
end of case item (colon) ==> ignore
758
end of record ==> check if named record }
761
symbol_seen := endsym;
763
if sym = recordsym then begin
764
annotate_temp_tok := annotate_pop_tok;
765
if annotate_temp_tok.val[1] in ['A'..'Z','a'..'z'] then
766
annotate_pending_tok := true;
768
else if sym = procsym then
770
annotate_pending_tok := true;
771
annotate_temp_tok := annotate_pop_tok;
773
else if sym = ifsym then begin
774
{ if there's an else part, don't do an annotation here }
775
if nextsym^.name <> elsesym then
777
annotate_pending := true;
778
annotate_temp := sym;
781
else if sym in [forsym, whilesym, withsym, casesym] then begin
782
annotate_pending := true;
783
annotate_temp := sym;
785
else if sym = colon then
787
if annotate_trace in traceFlags then
788
writeln( 'case item not annotated' );
791
if annotate_trace in traceFlags then
792
writeln( infilename,' line: ', inlines, ' end symbol found but not handled' );
797
if annotate_pending then begin
798
if nextsym^.crsbefore > 0 then
800
{ rest of line is empty }
801
insert_annotation(annotate_temp);
802
annotate_pending := false;
803
end else if nextsym^.name in [opencomment,
806
{ there's another comment already on the same line }
807
if annotate_trace in traceFlags then
808
writeln( infilename,' line: ', inlines, ' annotate ', keyword[annotate_temp], ' abandoned' );
809
annotate_pending := false;
811
else if (nextsym^.name <> semicolon) then begin
812
insert_annotation(annotate_temp);
813
annotate_pending := false;
817
if annotate_pending_tok then
819
if nextsym^.crsbefore > 0 then begin
820
{ rest of line is empty }
821
insert_annotation_tok( annotate_temp_tok );
822
annotate_pending_tok := false;
824
else if nextsym^.name in [opencomment, closecomment] then begin
825
{ there's another comment already on the same line }
826
if annotate_trace in traceFlags then
829
' annotate ', annotate_temp_tok.val:annotate_temp_tok.len, ' abandoned'
831
annotate_pending_tok := false;
833
else if not (nextsym^.name in [semicolon, period]) then begin
834
insert_annotation_tok( annotate_temp_tok );
835
annotate_pending_tok := false;
841
function f2( p: boolean;
843
var x: ttype; // should line up with first param
859
begin name := ' '; id := nil; next := nil; floodleAddr := 0;
860
cow := grass + floodle // should be indented
864
1: s1; // CHECK: cr here should go to new case value!
878
writeln(' and lots');
887
a // should align with '12'
889
end; // this must be aligned to the 'if' statement
892
fredzarmplezzzzzzzzzzzz( arg1,
901
if (e111) + e2 then fffffffffffff( func0( func1( func2( f3( arg1,
910
a1, // should be aligned with arg f3, not '('
931
else if c1 then begin
948
and c2 then begin // this can be aligned manually
984
arg2 // this should line up with arg1
1054
until c1; // there is no matching repeat here
1059
begin {main program }
1061
if f1 > 0 then result := f1-1
1068
if eeeeeeeeeeeeeeeeee
1073
for iiiiiiiiiii := 12
1074
to 89 // CHECK 89 lines up with 12
1076
if very_long_expression
1077
or another_very_long_expression
1078
and yet_another_very_long_expression then
1087
or 75 // CHECK: follows first continue line
1093
3 + // CHECK 3 lines up with 24 above
1100
f32verylongfunctionnamezzzzzzzzzzzzzzz(
1101
z, // user can realign this anywhere
1102
a,b, // this should line up with 'z'''
1110
s3; // bad code, 'end' is missing
1111
//end; // missing end, so next few case values interpreted as labels
1115
s3; // code error - case value belongs here, not statement
1123
if c2 then begin s1; s2 end;
1128
s3 // no trailing semi, but it indents
1130
end; { ** bad code ** } // crossed begin/end - matches '3: begin' above
1135
and e3 do // CHECK: should indent beyond while
1145
s3 // no trailing semi in line above, but it indents correctly
1146
end; // need ';' to force alignment with new case value
1147
otherwise if a then b;
1152
write( // CHECK: deeply nested levels of parens
1154
'test', // should be aligned
1166
end else // statement unfinished
1167
otherwise // duplicate eotherwise
1170
end else if a1 then begin
1177
c; { CHECK: outdents only when 'c' is followed by ';' }
1193
# this is a pp line!! // bug! silly place to put a pp line
1205
end; { !!! classic error, shouldn't be a semi colon here }
1206
else if c3 then begin
1214
end else if c1 then begin // comment
1220
end; // spurious end
1227
else if c2 then begin // spurious else
1235
end else // this else has no statement
1236
end else begin { should still be in sync }
1257
writeln( 'this is a string ', n:1, ' ', ' ', r:10:2 );
1279
4,5,6..9: begin s1; end;
1290
e2 DO begin { comment }
1410
of:=2; // more bad code
1418
IF (e1) or (* comment *)
1421
begin // CHECK: the begin should follow 'if' line, not 'then' line
1423
if e then begin s end
1433
s2; ( // unattached parens
1436
s; // problem caused by unattached parens
1444
* CHECK: stars should line up
1462
1,2,3,4..6: writeln(
1468
88: writeln( 'zzzzzzzzzz',
1500
0: writeln( 'zzzzzzzzz',
1521
writeln( 'this is ',
1522
'multiline arg list'
1541
label: // this is a label, not case value
1546
writeln( 'strrrrrr', a:4 );
1554
ff( a, // this line aligns with 'end'
1555
b, // CHECK: keep relative indent
1560
end; // begin CHECK:
1576
b, { check indent after cr here }