// kate: space-indent on; indent-width 3; replace-tabs on; remove-trailing-spaces all;
// kate: syntax pascal; indent-mode pascal;

// these variables are understood by the pascal indenter ...
// kate: cfgIndentCase true;          // indent elements in a case statement
// kate: cfgIndentBegin 2;            // indent 'begin' this many spaces
// kate: debugMode false;              // show how indent is determined
// kate: cfgAutoInsertStar true;      // auto insert '*' in (* ... *)-comments
// kate: cfgSnapParen true;           // snap ')' to '*)' in comments


function f1( var z: integer;
             var p,q : real;
             t : boolean	   ) : integer; // indentation should line up

type   tArray = array[0..17] of real;

   r= record a: integer; c: char; end;

   // nested variant record - too hard to get right. tough
   MyRec = Record
              X : Longint;
              Case byte of
                 1,2,8 : (Y : Longint;
                          case byte of
                          3 : (Z : Longint);   // CHECK: parens inside parens aligned correctly
                         );
           end;

   commands = (    crsupp,crbefore,blinbefore,
                   dindonkey,dindent,spbef,
                   spaft,gobsym,
                   inbytab,   { indent current margin (was indent from symbol pos) }
                   crafter,
                   finl            { force symbol to follow on same line as previous symbol }
              );

   tR = record
           i: integer;  // should indent after record
           r: real;
           a: array[1..11] of char;

           case boolean of
              true:( a: int);
              dontKnow:
                 (z: real;
                  fred : real;       // should be indented after case value
                  joe  : integer;
                 );
              false:
                 (  ted : array[
                                   1..16
                               ] of boolean;
                    moe: char; // should align to ''ted''
                 );
        end; // end of case + end of record

   commandset = set of commands;       // should be aligned to 'record', not 'case'

begin { f1 }
   case currsym^.name of

      { for procs, etc just record that we have one, wait for name }
      progsym, procsym, funcsym: begin
          symbol_seen := procsym;
          proc_state := proc_header;
          annotate_push( procsym );
         end;
      s1;                   // coding error, a case value should be here
         { remember we are in the declaraions part }
      varsym, typesym, constsym, labelsym:
         proc_state := proc_declarations;

         { if it's a proc, there will be no begin/end ==> pop info we just saved
         if it's an external var ==> do nothing  }
      forwardsym, externalsym:
         if proc_state = proc_header then begin
            sym := annotate_pop;
            tok := annotate_pop_tok;
            if annotate_trace in traceFlags then
               writeln( 'undo ', tok.val:tok.len );
         end;

         { if a proc has just occurred, this is its name
         otherwise, remember it, just in case it's a record name }
      othersym: begin
          if symbol_seen = procsym then begin
             tok.val := currsym^.value;
             tok.len := currsym^.length;
             annotate_push_tok( tok );
             symbol_seen := othersym;
          end
          else begin
             annotate_temp_tok.val := currsym^.value;
             annotate_temp_tok.len := currsym^.length;
          end;
         end;

         { we have the name, push it so the end symbol can get it back }
      recordsym: begin
          annotate_push_tok(annotate_temp_tok);
          annotate_push( recordsym );
          symbol_seen := recordsym;
         end;

         { we must remember these so they can pushed if the begin symbol occurs }
      ifsym, forsym, whilesym, withsym: begin
          symbol_seen := currsym^.name;
         end;

         { this is the second part of an if statement }
      elsesym:
         symbol_seen := ifsym;

         { if in a declaration ==> ignore
         if in a statement (assume case statement) ==> prepare for possible begin following }
      colon:
         if proc_state = proc_statements then
            symbol_seen := colon;

         { reset symbol_seen }
      semicolon:
         symbol_seen := semicolon;

         { could be the begin of a proc
         ==> get value, leaving it for the corresponding end symbol
         or it could be part of an if, etc,
         ==> push the symbol so the end symbol knows what to do  }
      beginsym: begin
          proc_state := proc_statements;
          if symbol_seen in [ifsym, forsym, whilesym, withsym, elsesym, colon] then begin
             annotate_push( symbol_seen );
          end
          else begin
             sym := annotate_peek;
             if sym = procsym then begin
                { this is a proc begin, add annotation }
                annotate_pending_tok := true;
                annotate_temp_tok := annotate_peek_tok;
             end
             else begin
                if annotate_trace in traceFlags then
                   writeln( infilename,' line ', inlines, ': orphaned begin found' );
                annotate_push( nosymbol );
             end
          end;
         end;

         { push the symbol so the end symbol can get it back }
      casesym: annotate_push( casesym );

         { end of proc, end of record  ==> pop name
         end of if, etc statement    ==> pop symbol
         end of case item (colon)    ==> ignore
         end of record ==> check if named record  }
      endsym: begin
          symbol_seen := endsym;
          sym := annotate_pop;
          if sym = recordsym then begin
             annotate_temp_tok := annotate_pop_tok;
             if annotate_temp_tok.val[1] in ['A'..'Z','a'..'z'] then
                annotate_pending_tok := true;
          end
          else if sym = procsym then begin
             annotate_pending_tok := true;
             annotate_temp_tok := annotate_pop_tok;
          end
          else if sym = ifsym then begin
             { if there's an else part, don't do an annotation here }
             if nextsym^.name <> elsesym then begin
                annotate_pending := true;
                annotate_temp := sym;
             end
          end
          else if sym in [forsym, whilesym, withsym, casesym] then begin
             annotate_pending := true;
             annotate_temp := sym;
          end
          else if sym = colon then begin
             if annotate_trace in traceFlags then
                writeln( 'case item not annotated' );
          end
          else begin
             if annotate_trace in traceFlags then
                writeln( infilename,' line: ', inlines, ' end symbol found but not handled' );
          end;
         end;
   end; { case }

   if annotate_pending then begin
      if nextsym^.crsbefore > 0 then begin
         { rest of line is empty }
         insert_annotation(annotate_temp);
         annotate_pending := false;
      end else if nextsym^.name in [opencomment, closecomment] then begin
         { there's another comment already on the same line }
         if annotate_trace in traceFlags then
            writeln( infilename,' line: ', inlines, ' annotate ', keyword[annotate_temp], ' abandoned' );
         annotate_pending := false;
      end
      else if (nextsym^.name <> semicolon) then begin
         insert_annotation(annotate_temp);
         annotate_pending := false;
      end;
   end;

   if annotate_pending_tok then begin
      if nextsym^.crsbefore > 0 then begin
         { rest of line is empty }
         insert_annotation_tok( annotate_temp_tok );
         annotate_pending_tok := false;
      end
      else if nextsym^.name in [opencomment, closecomment] then begin
         { there's another comment already on the same line }
         if annotate_trace in traceFlags then
            writeln( infilename,
                     ' line: ', inlines,
                     ' annotate ', annotate_temp_tok.val:annotate_temp_tok.len, ' abandoned'
                   );
         annotate_pending_tok := false;
      end
      else if not (nextsym^.name in [semicolon, period]) then begin
         insert_annotation_tok( annotate_temp_tok );
         annotate_pending_tok := false;
      end;
   end;
end; { f1 }


function f2( p: boolean;
             var q: real;
             var x: ttype;              // should line up with first param
             var c: char;

             var i1, i2: integer;

             ch: char;
             z: boolean
           ) : real;

var
   a: integer;
   b: boolean;

begin { f2 }

   with floodlePtr^ do
     begin name := '        '; id := nil; next := nil; floodleAddr := 0;
      cow := grass + floodle  // should be indented
     end;

   case e of
      1: s1;   // CHECK: cr here should go to new case value!
      88:
         s3;

      2:  begin
          s2;
          s3;
         end;

      3: s3;
      4,5,6..9: s6;

      otherwise
         writeln('lots');
         writeln(' and lots');
   end; {case}

   if c then begin
      s1;
      a := func( 12,
                 fffff( 89,
                        t
                      ),
                 a // should align with '12'
               );
   end; // this must be aligned to the 'if' statement


   fredzarmplezzzzzzzzzzzz(       arg1,
                                  arg1,
                                  arg2,
                                  arg3
                          );

   x := f(a) + f(b);


   if (e111) + e2 then fffffffffffff(    func0(  func1(    func2( f3(       arg1,


                                                                            arg2,
                                                                            arg3,
                                                                            arg4
                                                                    ),


                                                                  a1,  // should be aligned with arg f3, not '('
                                                                  a2,
                                                                  a3,
                                                                  a4
                                                                ),

                                                           aa2,
                                                           aa3,
                                                           aa4,
                                                           aa5
                                                      ),
                                                 bb1,
                                                 bb2,
                                                 bb3,
                                                 bb4
                                              ),
                                         cc1,
                                         cc2,
                                         cc3,
                                         cc4
                                    )
   else if c1 then begin
      s1;
   end;

   nextStmt := 13;

   while c1 do
      if q then
         s1
      else if qq then begin
         s2;
         s3
      end;


   if c1
         and c2 then begin // this can be aligned manually
      a := 12;
      s1;
      f(x)
   end;

   if cc1 then
      while c2 do
         f(x);

   while c1 do f(  arg1,
                   arg2  // this should line up with arg1
                );

   if c4 then f( arg1,
                 arg2
               );

   f1        ( arg1,
               arg2
             );
   fred      (  arg1,
                arg2
                arg3
                arg4,

                arg5
             );

   ff( arg1,
       arg2
     );

   a[1] := 13;
   repeat
      s1;
      while c3 do begin
         s3;
         while c2 do begin
            s4;
            while c4 do begin
               if c3 then
                 begin
                  s1;
                  s2;
                 end else
                    s3;
               if c3 then begin
                  s1
               end else

                  if a then b
                  else
                     if c then d
                     else

                        s2;
               if c3 then
                  if c4 then
                     s5;

               s3
            end;
         end
      end
   until c3;


   s5;

   s3;
   while c7 do begin
      s3;
      s4
   end;

   s4
end;

s2
until c1;  // there is no matching repeat here

end;  { f2 }
