1 {
2 ***************************************************************************
3 * *
4 * This source is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This code is distributed in the hope that it will be useful, but *
10 * WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * General Public License for more details. *
13 * *
14 * A copy of the GNU General Public License is available on the World *
15 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
16 * obtain it by writing to the Free Software Foundation, *
17 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
18 * *
19 ***************************************************************************
20
21 Author: Sérgio Marcelo S. Gomes <smace at smace.com.br>
22 Modified by Andrew Haines and Juha Manninen
23
24 Abstract: Invert Assignment Code.
25
26 Example: AValue := BValue -> BValue := AValue;
27 AValue := True -> AValue := False;
28
29 }
30 unit InvertAssignTool;
31
32 {$mode objfpc}{$H+}
33
34 interface
35
36 uses
37 Classes, SysUtils,
38 LazStringUtils;
39
InvertAssignmentnull40 function InvertAssignment(InText: string): string;
41
42 implementation
43
44
GetIndentnull45 function GetIndent(ALine: String):Integer;
46 begin
47 Result := Length(Aline) - Length(TrimLeft(ALine));
48 end;
49
50 procedure DivideLines(Lines: TStrings; var PreList, AList, BList, PostList: TStrings);
51 var
52 ALine, TrueFalse: String;
53 t, f: Boolean;
54 X, I, EqPos, SemiPos, WordEndPos, BracketCount: Integer;
55 begin
56 for X := 0 to Lines.Count-1 do begin
57 ALine := Trim(Lines[X]);
58 EqPos := Pos(':=', ALine);
59 if EqPos > 0 then begin
60 SemiPos := Pos(';', ALine);
61 if SemiPos = 0 then
62 SemiPos:=Length(ALine)+1;
63 I := EqPos-1;
64 while (I > 0) and (ALine[I] = ' ') do // Skip initial spaces
65 Dec(I);
66 WordEndPos := I+1;
67 BracketCount := 0;
68 // Get the word before :=
69 while I > 0 do begin
70 if ALine[I] = ']' then
71 Inc(BracketCount)
72 else if ALine[I] = '[' then
73 Dec(BracketCount);
74 if (BracketCount = 0) and (ALine[I] = ' ') then
75 Break;
76 Dec(I);
77 end;
78 // I points now at beginning of word - 1
79 Alist.Add(Copy(ALine, I+1, WordEndPos-(I+1)));
80 BList.Add(Trim(Copy(ALine, EqPos+2, SemiPos-EqPos-2)));
81 PreList.Add(Trim(Copy(ALine,1, I)));
82 PostList.Add(Trim(Copy(ALine, SemiPos, Length(ALine)-(SemiPos-1))));
83 if Length(PreList[X]) > 0 then
84 PreList[X] := PreList[X] + ' ';
85 end
86 else begin // not a valid line
87 PreList.Add('');
88 AList.Add(ALine);
89 Blist.Add('');
90 PostList.Add('');
91 end;
92 // Check if is being assigned true or false
93 t := CompareText(BList[X], 'True') = 0;
94 f := CompareText(BList[X], 'False') = 0;
95 if t or f then begin
96 TrueFalse := AList[X];
97 AList[X] := BoolToStr(not t, 'True', 'False');
98 BList[X] := TrueFalse;
99 end;
100 end;
101 end;
102
InvertLinenull103 function InvertLine(PreVar, VarA, VarB, PostVar: String; LineStart, EqualPosition: Integer): String;
104 var
105 fLength: Integer;
106 X: Integer;
107 begin
108 Result := '';
109 for X := 1 to LineStart do
110 Result := Result + ' ';
111 if Length(Trim(VarB)) = 0 then // is not a line with a ':='
112 Result := Result + VarA
113 else begin
114 Result := Result + PreVar + VarB;
115 fLength := Length(Trim(Result));
116 if fLength < EqualPosition then
117 for X := fLength+1 to EqualPosition do
118 Result := Result + ' ';
119 Result := Result + ' := ' + VarA + PostVar;
120 end;
121 end;
122
IsAWholeLinenull123 function IsAWholeLine(const ALine: String): Boolean;
124 begin
isnull125 // This function is useful for when the text is put back
126 // in the synedit, things like this don't happen:
127 // begin
128 // if CallSomeFunction > 0
129 // then
130 // DoThis
131 // else
132 // Exit;
133 // end;
134 //
135 // Would otherwise become this
136 //
137 // begin if CallSomeFunction > 0 then DoThis else exit;
138 // end;
139 Result := False;
140 if (Pos(';', ALine) > 0)
141 or (PosI('if ', ALine) > 0)
142 or (PosI('begin', ALine) > 0)
143 or (PosI('end', ALine) > 0)
144 or (PosI('then', ALine) > 0)
145 or (PosI('else', ALine) > 0)
146 or (PosI('and', ALine) > 0)
147 or (PosI('or', ALine) > 0)
148 or (Pos('//', ALine) > 0)
149 then Result := True;
150 end;
151
152
153 // This function inverts all Assignments operation.
154 // like valuea := valueb; to valueb := valuea;
155 // or valuea := False; to valuea := True;
156 function InvertAssignment(InText: string): string;
157 var
158 InLines, TempLines: TStringList;
159 PreList, AList, BList, PostList: TStrings;
160 ALine: String;
161 Indents: array of integer;
162 X, Y, EqPos: Integer;
163 HasLinefeed: Boolean;
164 begin
165 if InText = '' then
166 Exit('');
167 HasLinefeed := InText[Length(InText)] in [#10,#13];
168 InLines := TStringList.Create;
169 InLines.Text := InText;
170 SetLength(Indents, InLines.Count);
171 TempLines := TStringList.Create;
172
173 // Join many lines to one
174 ALine := '';
175 for X := 0 to InLines.Count-1 do begin
176 ALine := ALine + InLines[X];
177 if IsAWholeLine(ALine) then begin
178 Indents[TempLines.Add(ALine)] := GetIndent(ALine);
179 ALine := '';
180 end;
181 end;
182 if Length(ALine) > 0 then
183 Indents[TempLines.Add(ALine)] := GetIndent(ALine);
184
185 InLines.Clear;
186 PreList := TStringList.Create;
187 AList := TStringList.Create;
188 BList := TStringList.Create;
189 PostList := TStringList.Create;
190
191 DivideLines(TempLines, PreList, AList, BList, PostList);
192 TempLines.Free;
193
194 // Find where the ':=' should be
195 EqPos := 0;
196 for X := 0 to BList.Count-1 do begin
197 Y := Length(BList[X]);
198 if Y > EqPos then
199 EqPos := Y;
200 end;
201
202 for X := 0 to AList.Count-1 do
203 InLines.Add(InvertLine(PreList[X],Alist[X],BList[X],PostList[X],Indents[X],EqPos));
204 PreList.Free;
205 AList.Free;
206 BList.Free;
207 PostList.Free;
208 Result := InLines.Text;
209 InLines.Free;
210 if not HasLinefeed then begin
211 while Result[Length(Result)] in [#10,#13] do
212 SetLength(Result, Length(Result)-1);
213 end;
214 end;
215
216 end.
217
218