Skip to content

Commit

Permalink
Fixed #793
Browse files Browse the repository at this point in the history
  • Loading branch information
pyscripter committed Sep 3, 2018
1 parent 3140e32 commit c68b36c
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 69 deletions.
10 changes: 5 additions & 5 deletions Source/cPySupportTypes.pas
Expand Up @@ -65,7 +65,7 @@ TRunConfiguration = class(TPersistent)
TPyRegExpr = class
class var BlockOpenerRE : TRegExpr;
class var BlockCloserRE : TRegExpr;
class var CommentLineRE : TRegExpr;
class var CodeCommentLineRE : TRegExpr;
class var NonExecutableLineRE : TRegExpr;
class constructor Create;
class destructor Destroy;
Expand Down Expand Up @@ -151,17 +151,17 @@ procedure TRunConfiguration.SetExternalRun(const Value: TExternalRun);
TPyRegExpr.BlockCloserRE.Expression := '\s*(return|break|continue|raise|pass)\b';
TPyRegExpr.NonExecutableLineRE := TRegExpr.Create;
TPyRegExpr.NonExecutableLineRE.Expression := '(^\s*(class|def)\b)|(^\s*#)|(^\s*$)';
TPyRegExpr.CommentLineRE := TRegExpr.Create;
TPyRegExpr.CommentLineRE.Expression := '^([ \t]*)##';
TPyRegExpr.CommentLineRE.ModifierM := True;
TPyRegExpr.CodeCommentLineRE := TRegExpr.Create;
TPyRegExpr.CodeCommentLineRE.Expression := '^([ \t]*)##';
TPyRegExpr.CodeCommentLineRE.ModifierM := True;
end;

class destructor TPyRegExpr.Destroy;
begin
TPyRegExpr.BlockOpenerRE.Free;
TPyRegExpr.BlockCloserRE.Free;
TPyRegExpr.NonExecutableLineRE.Free;
TPyRegExpr.CommentLineRE.Free;
TPyRegExpr.CodeCommentLineRE.Free;
end;

class function TPyRegExpr.IsBlockCloser(S: string): Boolean;
Expand Down
119 changes: 58 additions & 61 deletions Source/cPythonSourceScanner.pas
Expand Up @@ -163,6 +163,7 @@ TParsedFunction = class(TCodeElement)
constructor Create;
destructor Destroy; override;
function ArgumentsString : string; virtual;
function HasArgument(Name : string): Boolean;
procedure GetNameSpace(SList : TStringList); override;
property Arguments : TObjectList read fArguments;
property Locals : TObjectList read fLocals;
Expand Down Expand Up @@ -205,6 +206,7 @@ TPythonScanner = class
fGlobalRE : TRegExpr;
fAliasRE : TRegExpr;
fListRE : TRegExpr;
fCommentLineRE : TRegExpr;
protected
procedure DoScannerProgress(CharNo, NoOfChars : integer; var Stop : Boolean);
public
Expand Down Expand Up @@ -277,47 +279,24 @@ implementation
Const
MaskChar = WideChar(#96);

NoOfImplicitContinuationBraces = 3;
ImplicitContinuationBraces : array[0..NoOfImplicitContinuationBraces-1] of
array [0..1] of WideChar = (('(', ')'), ('[', ']'), ('{', '}'));

Type
ImplicitContinuationBracesCount = array [0..NoOfImplicitContinuationBraces-1] of integer;

Var
DocStringRE : TRegExpr;


procedure HangingBraces(S : string; OpenBrace, CloseBrace : WideChar; var Count : integer);
function HaveImplicitContinuation(S : string; var BracesCount : integer) : Boolean;
var
I: Integer;
begin
for I := 1 to Length(S) do
if S[I] = OpenBrace then
Inc(Count)
else if S[I] = CloseBrace then
Dec(Count);
end;

function HaveImplicitContinuation(S : string;
var CountArray : ImplicitContinuationBracesCount; InitCount : boolean = false) : boolean;
Var
i : integer;
begin
if InitCount then
for i := 0 to NoOfImplicitContinuationBraces - 1 do
CountArray[i] := 0;
for i := 0 to NoOfImplicitContinuationBraces - 1 do
HangingBraces(S, ImplicitContinuationBraces[i][0],
ImplicitContinuationBraces[i][1], CountArray[i]);
Result := False;
for i := 0 to NoOfImplicitContinuationBraces - 1 do
// Code would be incorrect if Count < 0 but we ignore it
if CountArray[i] > 0 then begin
Result := True;
break;
if (Ord(S[i]) < 128) then begin
if AnsiChar(S[i]) in ['(', '[', '{'] then
Inc(BracesCount)
else if AnsiChar(S[i]) in [')', ']', '}'] then
Dec(BracesCount);
end;
Result := BracesCount > 0;
end;


{ Code Ellement }

constructor TCodeElement.Create;
Expand Down Expand Up @@ -508,6 +487,8 @@ constructor TPythonScanner.Create;
[DottedIdentRE, IdentRE]));
fListRE :=
CompiledRegExpr('\[(.*)\]');
fCommentLineRE :=
CompiledRegExpr('^([ \t]*)#');
end;

destructor TPythonScanner.Destroy;
Expand All @@ -526,6 +507,7 @@ destructor TPythonScanner.Destroy;
fGlobalRE.Free;
fAliasRE.Free;
fListRE.Free;
fCommentLineRE.Free;
inherited;
end;

Expand Down Expand Up @@ -604,15 +586,18 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
// Process continuation lines
var
ExplicitContinuation, ImplicitContinuation : boolean;
CountArray : ImplicitContinuationBracesCount;
NewLine : string;
TrimmedLine : string;
BracesCount : integer;
begin
BracesCount := 0;
LineStarts.Clear;
RemoveComment(Line);
ExplicitContinuation := fLineContinueRE.Exec(Line);
ImplicitContinuation := HaveImplicitContinuation(Line, CountArray, True);
ImplicitContinuation := not ExplicitContinuation and
HaveImplicitContinuation(Line, BracesCount);
Result := ExplicitContinuation or ImplicitContinuation;

while (ExplicitContinuation or ImplicitContinuation) and (P^ <> WideChar(#0)) do begin
if ExplicitContinuation then
// Drop the continuation char
Expand All @@ -628,7 +613,7 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
Line := Line + WideChar(' ') + NewLine;
ExplicitContinuation := fLineContinueRE.Exec(Line);
ImplicitContinuation := not ExplicitContinuation and
HaveImplicitContinuation(Line, CountArray, True);
HaveImplicitContinuation(NewLine, BracesCount);
end;
end;

Expand Down Expand Up @@ -746,7 +731,7 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
end;

var
P : PWideChar;
P, CodeStartP : PWideChar;
LineNo, Indent, Index, CharOffset, CharOffset2, LastLength : integer;
CodeStart : integer;
Line, Token, AsgnTargetList, S, SourceLine : string;
Expand Down Expand Up @@ -789,15 +774,21 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
LastCodeElement := Module;
while not Stop and (P^ <> #0) do begin
GetLine(P, Line, LineNo);
if (Length(Line) = 0) or fBlankLineRE.Exec(Line) then begin
// skip blank lines and comment lines
end else if fCodeRE.Exec(Line) then begin


// skip blank lines and comment lines
if (Length(Line) = 0) or fBlankLineRE.Exec(Line) then continue;
// skip comments
if fCommentLineRE.Exec(Line) then continue;

CodeStartP := P;
CodeStart := LineNo;
// Process continuation lines
ProcessLineContinuation(P, Line, LineNo, LineStarts);

if fCodeRE.Exec(Line) then begin
// found class or function definition
GlobalList.Clear;
CodeStart := LineNo;
// Process continuation lines
if ProcessLineContinuation(P, Line, LineNo, LineStarts) then
fCodeRE.Exec(Line); // reparse

S := StrReplaceChars(fCodeRE.Match[4], ['(', ')'], ' ');
if fCodeRE.Match[2] = 'class' then begin
Expand Down Expand Up @@ -894,9 +885,6 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
// search for imports
if fImportRE.Exec(Line) then begin
// Import statement
CodeStart := LineNo;
if ProcessLineContinuation(P, Line, LineNo, LineStarts) then
fImportRE.Exec(Line); // reparse
S := fImportRE.Match[1];
CharOffset := fImportRE.MatchPos[1];
LastLength := Length(S);
Expand All @@ -923,9 +911,6 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
end;
end else if fFromImportRE.Exec(Line) then begin
// From Import statement
CodeStart := LineNo;
if ProcessLineContinuation(P, Line, LineNo, LineStarts) then
fFromImportRE.Exec(Line); // reparse
ModuleImport := TModuleImport.Create(fFromImportRE.Match[2],
CodeBlock(CodeStart, LineNo));
ModuleImport.fPrefixDotCount := fFromImportRE.MatchLen[1];
Expand Down Expand Up @@ -991,8 +976,7 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
Variable := TVariable.Create;
Variable.Name := Token;
Variable.Parent := Klass;
Variable.fCodePos.LineNo := LineNo;
Variable.fCodePos.CharOffset := CharOffset;
CharOffsetToCodePos(CharOffset, CodeStart, LineStarts, Variable.fCodePos);
Klass.fAttributes.Add(Variable);
Inc(AsgnTargetCount);
end;
Expand All @@ -1001,19 +985,21 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
Variable := TVariable.Create;
Variable.Name := Token;
Variable.Parent := LastCodeElement;
Variable.fCodePos.LineNo := LineNo;
Variable.fCodePos.CharOffset := CharOffset;
if LastCodeElement.ClassType = TParsedFunction then
TParsedFunction(LastCodeElement).Locals.Add(Variable)
else if LastCodeElement.ClassType = TParsedClass then begin
CharOffsetToCodePos(CharOffset, CodeStart, LineStarts, Variable.fCodePos);
if LastCodeElement.ClassType = TParsedFunction then begin
if TParsedFunction(LastCodeElement).HasArgument(Variable.Name) then
FreeAndNil(Variable)
else
TParsedFunction(LastCodeElement).Locals.Add(Variable);
end else if LastCodeElement.ClassType = TParsedClass then begin
Include(Variable.Attributes, vaClassAttribute);
TParsedClass(LastCodeElement).Attributes.Add(Variable)
end else begin
Module.Globals.Add(Variable);
if Variable.Name = '__all__' then begin
Line := GetNthSourceLine(LineNo);
Line := GetNthSourceLine(CodeStart);
UseModifiedSource := False;
ProcessLineContinuation(P, Line, LineNo, LineStarts);
ProcessLineContinuation(CodeStartP, Line, CodeStart, LineStarts);
if fListRE.Exec(Line) then
Module.fAllExportsVar := fListRE.Match[1];
UseModifiedSource := True;
Expand All @@ -1023,7 +1009,7 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
end;
end;
// Variable Type if the assignment has a single target
if AsgnTargetCount = 1 then begin
if Assigned(Variable) and (AsgnTargetCount = 1) then begin
if fAssignmentRE.MatchLen[7] > 0 then begin
Variable.ObjType := fAssignmentRE.Match[7];
if fAssignmentRE.MatchLen[8] > 0 then //= '('
Expand Down Expand Up @@ -1051,8 +1037,7 @@ function TPythonScanner.ScanModule(Module : TParsedModule): boolean;
Variable := TVariable.Create;
Variable.Name := Token;
Variable.Parent := LastCodeElement;
Variable.fCodePos.LineNo := LineNo;
Variable.fCodePos.CharOffset := CharOffset;
CharOffsetToCodePos(CharOffset, CodeStart, LineStarts, Variable.fCodePos);
if LastCodeElement.ClassType = TParsedFunction then
TParsedFunction(LastCodeElement).Locals.Add(Variable)
else if LastCodeElement.ClassType = TParsedClass then begin
Expand Down Expand Up @@ -1415,6 +1400,18 @@ procedure TParsedFunction.GetNameSpace(SList: TStringList);
SList.AddObject(TVariable(fArguments[i]).Name, fArguments[i]);
end;

function TParsedFunction.HasArgument(Name: string): Boolean;
var
Variable : TObject;
begin
Result := False;
for Variable in fArguments do
if (Variable as TVariable).Name = Name then begin
Result := True;
Exit;
end;
end;

{ TParsedClass }

constructor TParsedClass.Create;
Expand Down
4 changes: 2 additions & 2 deletions Source/dmCommands.pas
Expand Up @@ -1424,13 +1424,13 @@ procedure TCommandsDataModule.actEditUncommentExecute(Sender: TObject);
OldBlockBegin := BufferCoord(1, OldBlockBegin.Line);
BlockBegin := OldBlockBegin;
BlockEnd := OldBlockEnd;
SelText := TPyRegExpr.CommentLineRE.Replace(SelText, '$1', True);
SelText := TPyRegExpr.CodeCommentLineRE.Replace(SelText, '$1', True);
BlockBegin := OldBlockBegin;
BlockEnd := BufferCoord(OldBlockEnd.Char - 2, OldBlockEnd.Line);
end else begin
BlockBegin := BufferCoord(1, CaretY);
BlockEnd := BufferCoord(Length(LineText)+1, CaretY);
SelText := TPyRegExpr.CommentLineRE.Replace(SelText, '$1', True);
SelText := TPyRegExpr.CodeCommentLineRE.Replace(SelText, '$1', True);
CaretXY := BufferCoord(OldBlockEnd.Char - 2, OldBlockEnd.Line);
end;
UpdateCaret;
Expand Down
2 changes: 1 addition & 1 deletion Source/frmPyIDEMain.pas
Expand Up @@ -431,7 +431,7 @@
Close All to he Right Editor command added (#866)
New editor parameter [$-CurLineNumber] (#864)
Issues addressed
#762, #879, #889, #890, #893, #896, #898, #899, #906
#762, #793, #879, #889, #890, #893, #896, #898, #899, #906
{ TODO : Issues 501, 667 }
{ TODO : Review Search and Replace }
Expand Down

0 comments on commit c68b36c

Please sign in to comment.