1 unit SingleSpaceBefore;
2
3 {(*}
4 (*------------------------------------------------------------------------------
5 Delphi Code formatter source code
6
7 The Original Code is SingleSpaceBefore, released May 2003.
8 The Initial Developer of the Original Code is Anthony Steele.
9 Portions created by Anthony Steele are Copyright (C) 1999-2008 Anthony Steele.
10 All Rights Reserved.
11 Contributor(s): Anthony Steele.
12
13 The contents of this file are subject to the Mozilla Public License Version 1.1
14 (the "License"). you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at http://www.mozilla.org/NPL/
16
17 Software distributed under the License is distributed on an "AS IS" basis,
18 WITHOUT WARRANTY OF ANY KIND, either express or implied.
19 See the License for the specific language governing rights and limitations
20 under the License.
21
22 Alternatively, the contents of this file may be used under the terms of
23 the GNU General Public License Version 2 or later (the "GPL")
24 See http://www.gnu.org/licenses/gpl.html
25 ------------------------------------------------------------------------------*)
26 {*)}
27
28 {$I JcfGlobal.inc}
29
30 interface
31
32
33 { AFS 7 Dec 1999
34 single space before certain tokens (e.g. ':='
35
36 This process and SingleSpaceAfter must be carefull with directives:
37 words like "read" and "write" must be single-spaced in property defs
38 but in normal code these are valid procedure names, and
39 converting "Result := myObject.Read;" to
40 "Result := myObject. read ;" compiles, but looks all wrong
41 }
42
43 uses SwitchableVisitor;
44
45 type
46 TSingleSpaceBefore = class(TSwitchableVisitor)
47 private
48 protected
EnabledVisitSourceTokennull49 function EnabledVisitSourceToken(const pcNode: TObject): boolean; override;
50 public
51 constructor Create; override;
52
IsIncludedInSettingsnull53 function IsIncludedInSettings: boolean; override;
54 end;
55
56
57 implementation
58
59 uses
60 { local }
61 JcfStringUtils,
62 SourceToken, Tokens, ParseTreeNodeType, JcfSettings,
63 FormatFlags, TokenUtils, SettingsTypes;
64
65 const
66 // space before all operators
67 SingleSpaceBeforeWords: TTokenTypeSet = [ttEquals, ttThen, ttOf, ttDo,
68 ttTo, ttDownTo];
69
70 NoSpaceAfterTokens: TTokenTypeSet = [ttOpenBracket, ttOpenSquareBracket];
71
NeedsSpaceBeforenull72 function NeedsSpaceBefore(const pt: TSourceToken): boolean;
73 var
74 lcPrev: TSourceToken;
75 begin
76 Result := False;
77
78 if pt = nil then
79 exit;
80
81 if pt.HasParentNode(nGeneric, 1) then
82 exit;
83
84 if pt.TokenType = ttCloseBracket then
85 begin
86 if FormattingSettings.Spaces.SpaceBeforeCloseBrackets then
87 begin
88 Result := true;
89 exit;
90 end;
91 end;
92
93 if (pt.TokenType = ttOpenBracket) then
94 begin
95 if FormattingSettings.Spaces.SpaceBeforeOpenBracketsInFunctionDeclaration then
96 begin
97 if pt.HasParentNode(nFormalParams, 1) then
98 begin
99 Result := true;
100 exit;
101 end;
102 end;
103
104 if FormattingSettings.Spaces.SpaceBeforeOpenBracketsInFunctionCall then
105 begin
106 if pt.HasParentNode(nActualParams, 1) then
107 begin
108 Result := true;
109 exit;
110 end;
111 end;
112
113 end
114 else if (pt.TokenType = ttOpenSquareBracket) then
115 begin
116 if FormattingSettings.Spaces.SpaceBeforeOpenSquareBracketsInExpression then
117 begin
118 if pt.HasParentNode(nExpression) then
119 begin
120 Result := true;
121 exit;
122 end;
123 end;
124 end;
125
126
127 if pt.HasParentNode(nLiteralString) then
128 begin
129 Result := False;
130 exit;
131 end;
132
133 if IsClassHelperWords(pt) then
134 begin
135 Result := True;
136 exit;
137 end;
138
139 { not in Asm block }
140 if pt.HasParentNode(nAsm) then
141 exit;
142
143 if (pt.TokenType in AssignmentDirectives) then
144 begin
145 Result := True;
146 exit;
147 end;
148
149 if IsHintDirective(pt) then
150 begin
151 Result := True;
152 exit;
153 end;
154
155
156 if (pt.TokenType in AllDirectives) and (pt.HasParentNode(DirectiveNodes)) then
157 begin
158 Result := True;
159 exit;
160 end;
161
162 if (pt.TokenType in SingleSpaceBeforeWords) then
163 begin
164 Result := True;
165 exit;
166 end;
167
168 if FormattingSettings.Spaces.SpaceForOperator = eAlways then
169 begin
170 if (pt.TokenType in SingleSpaceOperators) then
171 begin
172 Result := True;
173 end;
174
175 { 'a := --3;' and 'lc := ptr^;'
176 are the only exceptions to the rule of a space before an operator }
177 if (pt.TokenType in Operators) then
178 begin
179 if (pt.TokenType = ttHat) or
180 (IsUnaryOperator(pt) and IsUnaryOperator(pt.PriorSolidToken)) then
181 Result := False
182 else
183 Result := True;
184
185 exit;
186 end;
187
188 end;
189
190 { 'in' in the uses clause }
191 if ((pt.TokenType = ttIn) and (pt.HasParentNode(nUses))) then
192 begin
193 Result := True;
194 exit;
195 end;
196
197 { comment just after uses clause, unless it's a compiler directive }
198 if (pt.TokenType = ttComment) and (pt.CommentStyle <> eCompilerDirective) then
199 begin
200 lcPrev := pt.PriorSolidToken;
201 if (lcPrev <> nil) and (lcPrev.TokenType = ttUses) then
202 begin
203 Result := True;
204 exit;
205 end;
206 end;
207
208 { 'absolute' as a var directive }
209 if (pt.TokenType = ttAbsolute) and pt.HasParentNode(nAbsoluteVar) then
210 begin
211 Result := True;
212 exit;
213 end;
214
215 { any token that starts a literal string }
216 if StartsLiteralString(pt) then
217 begin
218 Result := True;
219 exit;
220 end;
221
222 if (pt.TokenType = ttDefault) and pt.HasParentNode(nPropertySpecifier) then
223 begin
224 Result := True;
225 exit;
226 end;
227
228 { signle space before read, write etc in property }
229 if pt.HasParentNode(nProperty) then
230 begin
231 if (pt.TokenType in [ttProperty, ttRead, ttWrite, ttDefault,
232 ttStored, ttNoDefault, ttImplements]) then
233 begin
234 Result := True;
235 exit;
236 end;
237 end;
238
239
240 { program uses clauses has a form link comment }
241 if InFilesUses(pt) then
242 begin
243 if ((pt.TokenType = ttComment) and (pt.CommentStyle in CURLY_COMMENTS)) and
244 pt.IsOnRightOf(nUses, ttUses) then
245 begin
246 Result := True;
247 exit;
248 end;
249 end;
250
251 end;
252
253
254 constructor TSingleSpaceBefore.Create;
255 begin
256 inherited;
257 FormatFlags := FormatFlags + [eAddSpace, eRemoveSpace, eRemoveReturn];
258 end;
259
EnabledVisitSourceTokennull260 function TSingleSpaceBefore.EnabledVisitSourceToken(const pcNode: TObject): boolean;
261 var
262 lcSourceToken, lcNext, lcNew: TSourceToken;
263 begin
264 Result := False;
265 lcSourceToken := TSourceToken(pcNode);
266 lcNext := lcSourceToken.NextToken;
267
268 if lcNext = nil then
269 exit;
270
271 // suspend this rule after open brackets
272 // e.g. if there's a space before a '-' minus sign
273 // this applies to "x - 1" but not "(-1 + x)"
274 if lcSourceToken.TokenType in NoSpaceAfterTokens then
275 begin
276 exit;
277 end;
278
279 if NeedsSpaceBefore(lcNext) then
280 begin
281 if (lcSourceToken.TokenType = ttWhiteSpace) then
282 begin
283 { one space }
284 lcSourceToken.SourceCode := NativeSpace;
285
286 { empty any preceeding whitespace }
287 repeat
288 lcSourceToken := lcSourceToken.PriorToken;
289 if lcSourceToken.TokenType = ttWhiteSpace then
290 lcSourceToken.SourceCode := '';
291 until lcSourceToken.TokenType <> ttWhiteSpace;
292 end
293 else
294 begin
295 lcNew := TSourceToken.Create;
296 lcNew.TokenType := ttWhiteSpace;
297 lcNew.SourceCode := NativeSpace;
298
299 InsertTokenAfter(lcSourceToken, lcNew);
300 end;
301 end;
302
303 end;
304
IsIncludedInSettingsnull305 function TSingleSpaceBefore.IsIncludedInSettings: boolean;
306 begin
307 Result := FormattingSettings.Spaces.FixSpacing;
308 end;
309
310 end.
311