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 *)
212
16: f(32); //CHECK: label forced to margin, statement is on new line with comment
222
begin s1; s2; s3 end;
224
for i := firstCh to lastCh do chtype[chr(i)] := none;
225
value['0'] := 0; value['1'] := 1; value['2'] := 2;
226
value['3'] := 3; value['4'] := 4; value['5'] := 5;
227
value['6'] := 6; value['7'] := 7; value['8'] := 8;
229
value['A'] := 10; value['B'] := 11; value['C'] := 12;
230
value['D'] := 13; value['E'] := 14; value['F'] := 15;
231
value['a'] := 10; value['b'] := 11; value['c'] := 12;
232
value['d'] := 13; value['e'] := 14; value['f'] := 15;
234
IF NOT (CH IN ['{','}']) THEN
236
BEGIN IF CH <= 'Z' THEN CMDCH := CH ELSE CMDCH := CHR(ORD(CH)-ORD('a')+ORD('A') );
240
ELSE IF CMDCH = 'T' THEN
242
ELSE IF CMDCH = 'I' THEN
244
ELSE IF CMDCH = 'Z' THEN
248
REPEAT commandIn UNTIL numRem = 0;
253
ELSE IF CMDCH = 'Q' THEN begin
255
end ELSE IF CMDCH = 'V' THEN
257
else if COMMAND.STRVAL = 'unknown' then
261
(numStr[1] IN ['+', '-', '0' .. '9', '?']) // CHECK: indent
263
Power.Supply := '"AC' ELSE Power.Supply := '"DC'
264
end else if CommandResult.Str = 'helpIamLost' then begin
265
Power.Supply := SetPowerSupplyCommands(Plus15V.Increase(Amps));
266
end else if (line = 'SHORT') OR (line = 'OPEN') THEN BEGIN
268
{*smoke billows out*}
275
(line = 'OPEN') OR (line = 'CLOSED') THEN
281
CircuitBreaker(wishfulThinking)
282
END else if cond then
284
END ELSE IF (line = 'PLUS') OR (line = 'MINUS') THEN Transform(RedPhase)
285
ELSE IF (line = 'RED') OR (line = 'BLACK') THEN Transform(BluePhase)
286
ELSE IF line = 'XX' THEN Transistor
287
ELSE IF line = 'YYYY' THEN SetCurrent(FiveAmps)
288
ELSE IF line = 'QQQQ' THEN SetPower(FiveWatts)
289
ELSE IF line = 'AAAAA' THEN Power(FiveAmps)
291
{* QWERTY COMMENT LLLLLLLLL ####### *}
294
actualphase := YellowPhase;
295
AdjustLinePhase(NewPhase);
298
line = 'Noisy' THEN Filter
299
ELSE IF line = 'BLUE' THEN
301
AdjustLinePhase(XPhase);
304
line = 'RED' THEN BEGIN Swap; Hope END
306
line = '415' THEN iNumPut415
308
// a statement like this has no chance of being correctly indented ...
309
// otoh, it shouldn't turn out catastrophically wrong.
310
line = 'REFL' THEN FOR i := 1 TO numLines DO
311
WriteLn('level=', powerLevel[i], ' ', name[i]+'='+power[i])
313
line = 'HIGH' THEN reduce
315
line = 'LOW' THEN increase
319
WHILE powerlevel[NumPowers] = level DO NumPowers := NumPowers-1;
326
Z := X*240.0 + i*Y*240;
329
ELSE IF line = 'HILD' THEN motor(induction)
330
ELSE IF (line = 'REV') THEN BEGIN
332
IF (NOT(v IN [#14..#240])) THEN
333
WriteLn(' POWER SUPPLY OUT OF SPEC') ELSE specValue := v;
336
ELSE IF (line = 'OK') THEN BEGIN
337
IncomingSupply := True; specValidate END
338
ELSE IF (line = 'NOK') THEN BEGIN IncomingSupply := False; specValidate END
340
GeneratedPowerLine.IncreasePower(
341
'Unknown input power "%s"', [SwitchPower.Current]); // CHECK: string should not cause problems
346
end (* AVeryVeryLongFunctionName *) ; // check that only necessary work is done to align
351
fred : integer; // should line up with alf
356
BEGIN s := do; WriteLn(s) END;
359
procedure getbyte; // CHECK: cr after this line is **not** indented
361
var // CHECK: cr after this line **is** indented
367
// if c then begin s1; s2 end; // strip these lines
368
// begin // normal case
369
// end // normal case
370
// end else if begin // should be OK since /end/ tested last
371
// need to consider ...
372
// if c1 then begin s1; s2 end
374
// <-- align this line
376
{ checking multi line statements }
379
while aaaaaaaaaaaaaaaaaaaaaaa
388
s5; // the ';' here links to the ';' after the 'case' below
401
1: s1; // CHECK: cr here should go to new case value!
412
1: s1; // CHECK: cr here should go to new case value!
427
writeln(' and lots');
434
writeln(' and lots');
438
begin // CHECK: should be indented after case value
453
begin // CKECK: should indent one level from case value
454
s3; // CHECK: should be indented another level
459
if c then begin // cr here is OK
467
s4; // incorrect code, indenter should expect a case value here
475
end; // stress test: else/end crossed over !!
483
and c2 then begin // can be aligned manually
484
a := 12; // should be indented one level from if statement
488
and c2 // can be aligned manually
491
a := 12; // should be indented one level from if statement
504
vvvvv // CHECK: indent lines with zzzzzzzzz
516
while not ( ((currchar.value = '*') and (nextchar.value = ')'))
517
or (currchar.value = '}') // args should line up inside parens
518
or (nextchar.name = endofline)
519
or ( sym^.length >= maxsymbolsize-2 )
520
or (nextchar.name = filemark)) do
521
storenextchar(sym^.length,sym^.value); // should be indented from while
523
while not (currchar.value = '*') and (nextchar.value = ')')
524
or (currchar.value = '}') // possible to realign first line manually
525
or (nextchar.name = endofline) // CHECK: other lines should follow first line // CHECK:: indents line up
526
or ( sym^.length >= maxsymbolsize-2 )
527
or (nextchar.name = filemark) do
528
storenextchar(sym^.length,sym^.value); // should be indented from while
530
while not (currchar.value = '*') and (nextchar.value = ')')
531
or (currchar.value = '}') // possible to realign first line manually
532
or (nextchar.name = endofline) // CHECK: other lines should follow first line // CHECK:: indents line up
533
or ( sym^.length >= maxsymbolsize-2 )
534
or (nextchar.name = filemark)
536
storenextchar(sym^.length,sym^.value); // should be indented from while
538
dblchar[becomes] := ':=';
539
dblchar[opencomment] := '(*'; // not start of comment!
540
sglchar[semicolon] := ';';
541
sglchar[colon] := ':';
542
sglchar[equals] := '=';
543
sglchar[openparen] := '(';
544
sglchar[closeparen] := ')';
545
sglchar[period] := '.';
546
sglchar[opencomment] := '{';
547
sglchar[closecomment] := '}';
553
if ch in ['0'..'9'] then
555
else if ch = '''' then begin
557
end else if (ch = blank) or (ch = chr(tab)) then
559
else name := otherchar
562
else if eoln(infile) then
566
if c1 then begin s1; s2 end
568
inlines := inlines + 1;
575
if ch in ['a'..'z','A'..'Z','_'] then
578
if ch in ['0'..'9'] then
580
else if ch = '''' then while c do
585
else if (ch = blank) or (ch = chr(tab)) then
587
else name := otherchar
591
# pp lines go to start of line, unless they are in a comment
596
cccccc; // CHECK: this aligns with code
597
# // CHECK: preprocessor lines go to start of line
600
if c2 then while c do
610
function f1( var z: integer;
612
t : boolean ) : integer; // indentation should line up
614
type tArray = array[0..17] of real;
616
r= record a: integer; c: char; end;
618
// nested variant record - too hard to get right. tough
622
1,2,8 : (Y : Longint;
624
3 : (Z : Longint); // CHECK: parens inside parens aligned correctly
628
commands = ( crsupp,crbefore,blinbefore,
629
dindonkey,dindent,spbef,
631
inbytab, { indent current margin (was indent from symbol pos) }
633
finl { force symbol to follow on same line as previous symbol }
637
i: integer; // should indent after record
639
a: array[1..11] of char;
645
fred : real; // should be indented after case value
652
moe: char; // should align to ''ted''
654
end; // end of case + end of record
656
commandset = set of commands; // should be aligned to 'record', not 'case'
659
case currsym^.name of
661
{ for procs, etc just record that we have one, wait for name }
662
progsym, procsym, funcsym: begin
663
symbol_seen := procsym;
664
proc_state := proc_header;
665
annotate_push( procsym );
667
s1; // coding error, a case value should be here
668
{ remember we are in the declaraions part }
669
varsym, typesym, constsym, labelsym:
670
proc_state := proc_declarations;
672
{ if it's a proc, there will be no begin/end ==> pop info we just saved
673
if it's an external var ==> do nothing }
674
forwardsym, externalsym:
675
if proc_state = proc_header then
678
tok := annotate_pop_tok;
679
if annotate_trace in traceFlags then
680
writeln( 'undo ', tok.val:tok.len );
683
{ if a proc has just occurred, this is its name
684
otherwise, remember it, just in case it's a record name }
687
if symbol_seen = procsym then begin
688
tok.val := currsym^.value;
689
tok.len := currsym^.length;
690
annotate_push_tok( tok );
691
symbol_seen := othersym;
694
annotate_temp_tok.val := currsym^.value;
695
annotate_temp_tok.len := currsym^.length;
699
{ we have the name, push it so the end symbol can get it back }
701
annotate_push_tok(annotate_temp_tok);
702
annotate_push( recordsym );
703
symbol_seen := recordsym;
706
{ we must remember these so they can pushed if the begin symbol occurs }
707
ifsym, forsym, whilesym, withsym:
709
symbol_seen := currsym^.name;
712
{ this is the second part of an if statement }
714
symbol_seen := ifsym;
716
{ if in a declaration ==> ignore
717
if in a statement (assume case statement) ==> prepare for possible begin following }
719
if proc_state = proc_statements then
720
symbol_seen := colon;
722
{ reset symbol_seen }
724
symbol_seen := semicolon;
726
{ could be the begin of a proc
727
==> get value, leaving it for the corresponding end symbol
728
or it could be part of an if, etc,
729
==> push the symbol so the end symbol knows what to do }
731
proc_state := proc_statements;
732
if symbol_seen in [ifsym, forsym, whilesym, withsym, elsesym, colon] then begin
733
annotate_push( symbol_seen );
736
sym := annotate_peek;
737
if sym = procsym then begin
738
{ this is a proc begin, add annotation }
739
annotate_pending_tok := true;
740
annotate_temp_tok := annotate_peek_tok;
744
if annotate_trace in traceFlags then
745
writeln( infilename,' line ', inlines, ': orphaned begin found' );
746
annotate_push( nosymbol );
751
{ push the symbol so the end symbol can get it back }
752
casesym: annotate_push( casesym );
754
{ end of proc, end of record ==> pop name
755
end of if, etc statement ==> pop symbol
756
end of case item (colon) ==> ignore
757
end of record ==> check if named record }
760
symbol_seen := endsym;
762
if sym = recordsym then begin
763
annotate_temp_tok := annotate_pop_tok;
764
if annotate_temp_tok.val[1] in ['A'..'Z','a'..'z'] then
765
annotate_pending_tok := true;
767
else if sym = procsym then
769
annotate_pending_tok := true;
770
annotate_temp_tok := annotate_pop_tok;
772
else if sym = ifsym then begin
773
{ if there's an else part, don't do an annotation here }
774
if nextsym^.name <> elsesym then
776
annotate_pending := true;
777
annotate_temp := sym;
780
else if sym in [forsym, whilesym, withsym, casesym] then begin
781
annotate_pending := true;
782
annotate_temp := sym;
784
else if sym = colon then
786
if annotate_trace in traceFlags then
787
writeln( 'case item not annotated' );
790
if annotate_trace in traceFlags then
791
writeln( infilename,' line: ', inlines, ' end symbol found but not handled' );
796
if annotate_pending then begin
797
if nextsym^.crsbefore > 0 then
799
{ rest of line is empty }
800
insert_annotation(annotate_temp);
801
annotate_pending := false;
802
end else if nextsym^.name in [opencomment,
805
{ there's another comment already on the same line }
806
if annotate_trace in traceFlags then
807
writeln( infilename,' line: ', inlines, ' annotate ', keyword[annotate_temp], ' abandoned' );
808
annotate_pending := false;
810
else if (nextsym^.name <> semicolon) then begin
811
insert_annotation(annotate_temp);
812
annotate_pending := false;
816
if annotate_pending_tok then
818
if nextsym^.crsbefore > 0 then begin
819
{ rest of line is empty }
820
insert_annotation_tok( annotate_temp_tok );
821
annotate_pending_tok := false;
823
else if nextsym^.name in [opencomment, closecomment] then begin
824
{ there's another comment already on the same line }
825
if annotate_trace in traceFlags then
828
' annotate ', annotate_temp_tok.val:annotate_temp_tok.len, ' abandoned'
830
annotate_pending_tok := false;
832
else if not (nextsym^.name in [semicolon, period]) then begin
833
insert_annotation_tok( annotate_temp_tok );
834
annotate_pending_tok := false;
840
function f2( p: boolean;
842
var x: ttype; // should line up with first param
858
begin name := ' '; id := nil; next := nil; floodleAddr := 0;
859
cow := grass + floodle // should be indented
863
1: s1; // CHECK: cr here should go to new case value!
877
writeln(' and lots');
886
a // should align with '12'
888
end; // this must be aligned to the 'if' statement
891
fredzarmplezzzzzzzzzzzz( arg1,
900
if (e111) + e2 then fffffffffffff( func0( func1( func2( f3( arg1,
909
a1, // should be aligned with arg f3, not '('
930
else if c1 then begin
947
and c2 then begin // this can be aligned manually
983
arg2 // this should line up with arg1
1053
until c1; // there is no matching repeat here
1058
begin {main program }
1060
if f1 > 0 then result := f1-1
1067
if eeeeeeeeeeeeeeeeee
1072
for iiiiiiiiiii := 12
1073
to 89 // CHECK 89 lines up with 12
1075
if very_long_expression
1076
or another_very_long_expression
1077
and yet_another_very_long_expression then
1086
or 75 // CHECK: follows first continue line
1092
3 + // CHECK 3 lines up with 24 above
1099
f32verylongfunctionnamezzzzzzzzzzzzzzz(
1100
z, // user can realign this anywhere
1101
a,b, // this should line up with 'z'''
1109
s3; // bad code, 'end' is missing
1110
//end; // missing end, so next few case values interpreted as labels
1114
s3; // code error - case value belongs here, not statement
1122
if c2 then begin s1; s2 end;
1127
s3 // no trailing semi, but it indents
1129
end; { ** bad code ** } // crossed begin/end - matches '3: begin' above
1134
and e3 do // CHECK: should indent beyond while
1144
s3 // no trailing semi in line above, but it indents correctly
1145
end; // need ';' to force alignment with new case value
1146
otherwise if a then b;
1151
write( // CHECK: deeply nested levels of parens
1153
'test', // should be aligned
1165
end else // statement unfinished
1166
otherwise // duplicate eotherwise
1169
end else if a1 then begin
1176
c; { CHECK: outdents only when 'c' is followed by ';' }
1192
# this is a pp line!! // bug! silly place to put a pp line
1204
end; { !!! classic error, shouldn't be a semi colon here }
1205
else if c3 then begin
1213
end else if c1 then begin // comment
1219
end; // spurious end
1226
else if c2 then begin // spurious else
1234
end else // this else has no statement
1235
end else begin { should still be in sync }
1256
writeln( 'this is a string ', n:1, ' ', ' ', r:10:2 );
1278
4,5,6..9: begin s1; end;
1289
e2 DO begin { comment }
1409
of:=2; // more bad code
1417
IF (e1) or (* comment *)
1420
begin // CHECK: the begin should follow 'if' line, not 'then' line
1422
if e then begin s end
1432
s2; ( // unattached parens
1435
s; // problem caused by unattached parens
1443
* CHECK: stars should line up
1461
1,2,3,4..6: writeln(
1467
88: writeln( 'zzzzzzzzzz',
1499
0: writeln( 'zzzzzzzzz',
1520
writeln( 'this is ',
1521
'multiline arg list'
1540
label: // this is a label, not case value
1545
writeln( 'strrrrrr', a:4 );
1553
ff( a, // this line aligns with 'end'
1554
b, // CHECK: keep relative indent
1559
end; // begin CHECK:
1575
b, { check indent after cr here }