lazarus/components/jcf2/Process/Obfuscate/RemoveUnneededWhiteSpace.pas
paul 75d3718f7d jcf: update to r803 revision of main repository:
- support for c-style fpc operators

git-svn-id: trunk@19236 -
2009-04-06 02:19:13 +00:00

223 lines
5.4 KiB
ObjectPascal

unit RemoveUnneededWhiteSpace;
{(*}
(*------------------------------------------------------------------------------
Delphi Code formatter source code
The Original Code is RemoveUnneededWhiteSpace, released May 2003.
The Initial Developer of the Original Code is Anthony Steele.
Portions created by Anthony Steele are Copyright (C) 1999-2008 Anthony Steele.
All Rights Reserved.
Contributor(s): Anthony Steele.
The contents of this file are subject to the Mozilla Public License Version 1.1
(the "License"). you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied.
See the License for the specific language governing rights and limitations
under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 2 or later (the "GPL")
See http://www.gnu.org/licenses/gpl.html
------------------------------------------------------------------------------*)
{*)}
{$I JcfGlobal.inc}
interface
{ AFS 29 December 2002
Obfuscation visitor
This is to completely remove white space
when it is not needed, e.g. turn "a := a + 1 ;" to "a:=a+1;"
}
uses SwitchableVisitor;
type
TRemoveUnneededWhiteSpace = class(TSwitchableVisitor)
protected
function EnabledVisitSourceToken(const pcNode: TObject): Boolean; override;
public
constructor Create; override;
end;
implementation
uses
{ local }
SourceToken, Tokens, ParseTreeNodeType,
JcfUnicode,
FormatFlags, TokenUtils;
function TextOrNumberString(const str: WideString): boolean;
var
liLoop: integer;
ch: WideChar;
begin
Result := True;
for liLoop := 1 to Length(str) do
begin
ch := str[liLoop];
if not (WideCharIsAlphaNum(ch) or (ch = '_') or (ch = '.')) then
begin
Result := False;
break;
end;
end;
end;
const
MiscUnspacedTokens: TTokenTypeSet = [
ttQuotedLiteralString, ttSemiColon, ttColon, ttComma,
ttDot, ttDoubleDot, ttAssign, ttReturn, ttPlusAssign, ttMinusAssign, ttTimesAssign, ttFloatDivAssign];
DoNotConcat = [ttGreaterThan, ttLessThan, ttEquals];
function NeedSpaceBetween(const pt1, pt2: TSourceToken): boolean;
const
SPACED_ASM_TOKENS = [ttAtSign, ttAmpersand];
var
lcLast: TSourceToken;
begin
Result := True;
if ((pt1 = nil) or (pt2 = nil)) then
begin
Result := False;
exit;
end;
if (pt1.TokenType in DoNotConcat) and (pt2.TokenType in DoNotConcat) then
begin
exit;
end;
{ can loose everything after the final end }
if (pt1.TokenType = ttDot) then
begin
lcLast := pt1.PriorSolidToken;
if (lcLast.TokenType = ttEnd) and (pt1.HasParentNode(TopOfFileSection, 1)) then
begin
Result := False;
exit;
end;
end;
{ need to keep space before Asm @@ and '&' thingy}
if (pt2.TokenType in SPACED_ASM_TOKENS) and pt2.HasParentNode(nAsmStatement) then
exit;
{ never need a space next to a bracket }
if (pt1.TokenType in BracketTokens) or (pt2.TokenType in BracketTokens) then
begin
Result := False;
exit;
end;
{ never need space around semicolon }
if (pt1.TokenType = ttSemiColon) or (pt2.TokenType = ttSemiColon) then
begin
Result := False;
exit;
end;
{ or dot or comma etc }
if (pt1.TokenType in MiscUnspacedTokens) or (pt2.TokenType in MiscUnspacedTokens) then
begin
Result := False;
exit;
end;
{ before a comment. Comments are removed by another process (except for compiler directives) }
if (pt2.TokenType = ttComment) then
begin
Result := False;
exit;
end;
{ similartly, after a comment unless it starts with '//' }
if (pt1.TokenType = ttComment) and (pt1.CommentStyle <> eDoubleSlash) then
begin
Result := False;
exit;
end;
if (pt1.TokenType in TextOrNumberTokens) and (pt2.TokenType = ttAtSign) and
(pt1.HasParentnode(nAsm)) then
begin
Result := False;
exit;
end;
{ if one token is text or number, and the other not, don't need white space
for this numbers count as text, for e.g.
"for liLoop := 0to3do" is not valid, neither is "for liLoop := 0 to3 do",
must be for liLoop := 0 to 3 do
}
if TextOrNumberString(pt1.SourceCode) and TextOrNumberString(pt2.SourceCode) then
begin
{ always space between two text/number tokens }
Result := True;
exit;
end;
{ if one token is a number, even a number like "$000080FF",
must space them }
if TextOrNumberString(pt1.SourceCode) and (pt2.TokenType = ttNumber) then
begin
Result := True;
exit;
end;
if (pt1.TokenType = ttNumber) and TextOrNumberString(pt2.SourceCode) then
begin
Result := True;
exit;
end;
Result := False;
end;
constructor TRemoveUnneededWhiteSpace.Create;
begin
inherited;
FormatFlags := FormatFlags + [eObfuscate];
end;
function TRemoveUnneededWhiteSpace.EnabledVisitSourceToken(const pcNode: TObject): Boolean;
var
lcSpace, lcBefore, lcAfter: TSourceToken;
begin
Result := False;
{ this visitor needs to operate on the white space token
depending on what comes before and after it
}
lcSpace := TSourceToken(pcNode);
if lcSpace.TokenType <> ttWhiteSpace then
exit;
lcBefore := lcSpace.PriorToken;
if lcBefore = nil then
exit;
lcAfter := lcSpace.NextToken;
if lcAfter = nil then
exit;
if not NeedSpaceBetween(lcBefore, lcAfter) then
BlankToken(lcSpace);
end;
end.