mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-15 20:59:06 +02:00
MG: find declaration for pointers, with statements, forward classes, as operator
git-svn-id: trunk@599 -
This commit is contained in:
parent
a29a5959a2
commit
ce24bd7399
@ -940,9 +940,7 @@ begin
|
|||||||
// in a class or in a forward proc?
|
// in a class or in a forward proc?
|
||||||
BuildTreeAndGetCleanPos(false,CursorPos, CleanCursorPos);
|
BuildTreeAndGetCleanPos(false,CursorPos, CleanCursorPos);
|
||||||
// find CodeTreeNode at cursor
|
// find CodeTreeNode at cursor
|
||||||
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos);
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
if CursorNode=nil then
|
|
||||||
RaiseException('no valid node found at cursor');
|
|
||||||
ASourceChangeCache:=SourceChangeCache;
|
ASourceChangeCache:=SourceChangeCache;
|
||||||
SourceChangeCache.MainScanner:=Scanner;
|
SourceChangeCache.MainScanner:=Scanner;
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
@ -1032,9 +1030,7 @@ writeln('TCodeCompletionCodeTool.CompleteCode Jump to new proc body ... ');
|
|||||||
if (Dummy<>0) and (Dummy<>-1) then
|
if (Dummy<>0) and (Dummy<>-1) then
|
||||||
RaiseException('cursor pos outside of code');
|
RaiseException('cursor pos outside of code');
|
||||||
// find CodeTreeNode at cursor
|
// find CodeTreeNode at cursor
|
||||||
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos);
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
if CursorNode=nil then
|
|
||||||
RaiseException('no valid node found at cursor');
|
|
||||||
|
|
||||||
ClassNode:=CursorNode;
|
ClassNode:=CursorNode;
|
||||||
while (ClassNode<>nil) and (ClassNode.Desc<>ctnClass) do
|
while (ClassNode<>nil) and (ClassNode.Desc<>ctnClass) do
|
||||||
|
@ -76,7 +76,8 @@ type
|
|||||||
|
|
||||||
property Scanner: TLinkScanner read FScanner write SetScanner;
|
property Scanner: TLinkScanner read FScanner write SetScanner;
|
||||||
|
|
||||||
function FindDeepestNodeAtPos(P: integer): TCodeTreeNode;
|
function FindDeepestNodeAtPos(P: integer;
|
||||||
|
ExceptionOnNotFound: boolean): TCodeTreeNode;
|
||||||
function CaretToCleanPos(Caret: TCodeXYPosition;
|
function CaretToCleanPos(Caret: TCodeXYPosition;
|
||||||
var CleanPos: integer): integer; // 0=valid CleanPos
|
var CleanPos: integer): integer; // 0=valid CleanPos
|
||||||
//-1=CursorPos was skipped, CleanPos between two links
|
//-1=CursorPos was skipped, CleanPos between two links
|
||||||
@ -1078,7 +1079,8 @@ begin
|
|||||||
WriteSubTree(Tree.Root,' ');
|
WriteSubTree(Tree.Root,' ');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomCodeTool.FindDeepestNodeAtPos(P: integer): TCodeTreeNode;
|
function TCustomCodeTool.FindDeepestNodeAtPos(P: integer;
|
||||||
|
ExceptionOnNotFound: boolean): TCodeTreeNode;
|
||||||
|
|
||||||
function SearchInNode(ANode: TCodeTreeNode): TCodeTreeNode;
|
function SearchInNode(ANode: TCodeTreeNode): TCodeTreeNode;
|
||||||
begin
|
begin
|
||||||
@ -1103,6 +1105,10 @@ function TCustomCodeTool.FindDeepestNodeAtPos(P: integer): TCodeTreeNode;
|
|||||||
// TCustomCodeTool.FindDeepestNodeAtPos
|
// TCustomCodeTool.FindDeepestNodeAtPos
|
||||||
begin
|
begin
|
||||||
Result:=SearchInNode(Tree.Root);
|
Result:=SearchInNode(Tree.Root);
|
||||||
|
if (Result=nil) and ExceptionOnNotFound then begin
|
||||||
|
MoveCursorToCleanPos(P);
|
||||||
|
RaiseException('no node found at cursor');
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomCodeTool.CaretToCleanPos(Caret: TCodeXYPosition;
|
function TCustomCodeTool.CaretToCleanPos(Caret: TCodeXYPosition;
|
||||||
|
@ -63,7 +63,7 @@ interface
|
|||||||
|
|
||||||
{$I codetools.inc}
|
{$I codetools.inc}
|
||||||
|
|
||||||
{$DEFINE CTDEBUG}
|
{ $DEFINE CTDEBUG}
|
||||||
|
|
||||||
uses
|
uses
|
||||||
{$IFDEF MEM_CHECK}
|
{$IFDEF MEM_CHECK}
|
||||||
@ -77,8 +77,16 @@ type
|
|||||||
// searchpath delimiter is semicolon
|
// searchpath delimiter is semicolon
|
||||||
TOnGetSearchPath = function(Sender: TObject): string;
|
TOnGetSearchPath = function(Sender: TObject): string;
|
||||||
|
|
||||||
TFindDeclarationFlag = (fdfSearchInParentNodes,fdfSearchInAncestors,
|
TFindDeclarationFlag = (
|
||||||
fdfIgnoreCurContextNode,
|
fdfSearchInParentNodes, // if identifier not found in current context,
|
||||||
|
// proceed in prior nodes on same lvl and parents
|
||||||
|
fdfSearchInAncestors, // if context is a class, search also in
|
||||||
|
// ancestors/interfaces
|
||||||
|
fdfIgnoreCurContextNode,// skip context and proceed in prior/parent context
|
||||||
|
fdfExceptionOnNotFound, // raise exception if identifier not found
|
||||||
|
fdfIgnoreUsedUnits, // stay in current source
|
||||||
|
fdfSearchForward, // instead of searching in prior nodes, search in
|
||||||
|
// next nodes (successors)
|
||||||
fdfClassPublished,fdfClassPublic,fdfClassProtected,fdfClassPrivate);
|
fdfClassPublished,fdfClassPublic,fdfClassProtected,fdfClassPrivate);
|
||||||
TFindDeclarationFlags = set of TFindDeclarationFlag;
|
TFindDeclarationFlags = set of TFindDeclarationFlag;
|
||||||
|
|
||||||
@ -114,6 +122,11 @@ type
|
|||||||
TFindDeclarationTool = class(TPascalParserTool)
|
TFindDeclarationTool = class(TPascalParserTool)
|
||||||
private
|
private
|
||||||
FOnGetUnitSourceSearchPath: TOnGetSearchPath;
|
FOnGetUnitSourceSearchPath: TOnGetSearchPath;
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
DebugPrefix: string;
|
||||||
|
procedure IncPrefix;
|
||||||
|
procedure DecPrefix;
|
||||||
|
{$ENDIF}
|
||||||
function FindDeclarationInUsesSection(UsesNode: TCodeTreeNode;
|
function FindDeclarationInUsesSection(UsesNode: TCodeTreeNode;
|
||||||
CleanPos: integer;
|
CleanPos: integer;
|
||||||
var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean;
|
var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean;
|
||||||
@ -128,8 +141,12 @@ type
|
|||||||
Node: TCodeTreeNode): TCodeTreeNode;
|
Node: TCodeTreeNode): TCodeTreeNode;
|
||||||
function FindIdentifierInProcContext(ProcContextNode: TCodeTreeNode;
|
function FindIdentifierInProcContext(ProcContextNode: TCodeTreeNode;
|
||||||
Params: TFindDeclarationParams): boolean;
|
Params: TFindDeclarationParams): boolean;
|
||||||
|
function FindIdentifierInWithVarContext(WithVarNode: TCodeTreeNode;
|
||||||
|
Params: TFindDeclarationParams): boolean;
|
||||||
function FindClassOfMethod(ProcNode: TCodeTreeNode;
|
function FindClassOfMethod(ProcNode: TCodeTreeNode;
|
||||||
Params: TFindDeclarationParams; FindClassContext: boolean): boolean;
|
Params: TFindDeclarationParams; FindClassContext: boolean): boolean;
|
||||||
|
function FindForwardIdentifier(Params: TFindDeclarationParams;
|
||||||
|
var IsForward: boolean): boolean;
|
||||||
public
|
public
|
||||||
function FindDeclaration(CursorPos: TCodeXYPosition;
|
function FindDeclaration(CursorPos: TCodeXYPosition;
|
||||||
var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean;
|
var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean;
|
||||||
@ -146,6 +163,7 @@ implementation
|
|||||||
const
|
const
|
||||||
fdfAllClassVisibilities = [fdfClassPublished,fdfClassPublic,fdfClassProtected,
|
fdfAllClassVisibilities = [fdfClassPublished,fdfClassPublic,fdfClassProtected,
|
||||||
fdfClassPrivate];
|
fdfClassPrivate];
|
||||||
|
fdfGlobals = [fdfExceptionOnNotFound, fdfIgnoreUsedUnits];
|
||||||
|
|
||||||
{ TFindDeclarationTool }
|
{ TFindDeclarationTool }
|
||||||
|
|
||||||
@ -158,16 +176,14 @@ begin
|
|||||||
Result:=false;
|
Result:=false;
|
||||||
// build code tree
|
// build code tree
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln('TFindDeclarationTool.FindDeclaration A CursorPos=',CursorPos.X,',',CursorPos.Y);
|
writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration A CursorPos=',CursorPos.X,',',CursorPos.Y);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
BuildTreeAndGetCleanPos(false,CursorPos,CleanCursorPos);
|
BuildTreeAndGetCleanPos(false,CursorPos,CleanCursorPos);
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln('TFindDeclarationTool.FindDeclaration C CleanCursorPos=',CleanCursorPos);
|
writeln(DebugPrefix,'TFindDeclarationTool.FindDeclaration C CleanCursorPos=',CleanCursorPos);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
// find CodeTreeNode at cursor
|
// find CodeTreeNode at cursor
|
||||||
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos);
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
if CursorNode=nil then
|
|
||||||
RaiseException('no node found at cursor');
|
|
||||||
if IsIncludeDirectiveAtPos(CleanCursorPos,CursorNode.StartPos,NewPos.Code)
|
if IsIncludeDirectiveAtPos(CleanCursorPos,CursorNode.StartPos,NewPos.Code)
|
||||||
then begin
|
then begin
|
||||||
NewPos.X:=1;
|
NewPos.X:=1;
|
||||||
@ -193,10 +209,13 @@ writeln('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsSt
|
|||||||
if ClassNode.SubDesc<>ctnsForwardDeclaration then begin
|
if ClassNode.SubDesc<>ctnsForwardDeclaration then begin
|
||||||
// parse class and build CodeTreeNodes for all properties/methods
|
// parse class and build CodeTreeNodes for all properties/methods
|
||||||
BuildSubTreeForClass(ClassNode);
|
BuildSubTreeForClass(ClassNode);
|
||||||
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
if CursorNode.Desc=ctnBeginBlock then
|
if CursorNode.Desc=ctnBeginBlock then begin
|
||||||
BuildSubTreeForBeginBlock(CursorNode);
|
BuildSubTreeForBeginBlock(CursorNode);
|
||||||
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
|
end;
|
||||||
MoveCursorToCleanPos(CleanCursorPos);
|
MoveCursorToCleanPos(CleanCursorPos);
|
||||||
while (CurPos.StartPos>1) and (IsIdentChar[Src[CurPos.StartPos-1]]) do
|
while (CurPos.StartPos>1) and (IsIdentChar[Src[CurPos.StartPos-1]]) do
|
||||||
dec(CurPos.StartPos);
|
dec(CurPos.StartPos);
|
||||||
@ -211,7 +230,8 @@ writeln('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsSt
|
|||||||
Params.ContextNode:=CursorNode;
|
Params.ContextNode:=CursorNode;
|
||||||
Params.IdentifierStartPos:=CurPos.StartPos;
|
Params.IdentifierStartPos:=CurPos.StartPos;
|
||||||
Params.IdentifierEndPos:=CurPos.EndPos;
|
Params.IdentifierEndPos:=CurPos.EndPos;
|
||||||
Params.Flags:=[fdfSearchInAncestors,fdfSearchInParentNodes];
|
Params.Flags:=[fdfSearchInAncestors,fdfSearchInParentNodes,
|
||||||
|
fdfExceptionOnNotFound];
|
||||||
Result:=FindDeclarationOfIdentifier(Params);
|
Result:=FindDeclarationOfIdentifier(Params);
|
||||||
if Result then begin
|
if Result then begin
|
||||||
Params.ConvertResultCleanPosToCaretPos;
|
Params.ConvertResultCleanPosToCaretPos;
|
||||||
@ -506,9 +526,17 @@ writeln('[TFindDeclarationTool.FindDeclarationOfIdentifier] Identifier=',
|
|||||||
MoveCursorToCleanPos(Params.IdentifierStartPos);
|
MoveCursorToCleanPos(Params.IdentifierStartPos);
|
||||||
OldContextNode:=Params.ContextNode;
|
OldContextNode:=Params.ContextNode;
|
||||||
NewContextNode:=FindContextNodeAtCursor(Params);
|
NewContextNode:=FindContextNodeAtCursor(Params);
|
||||||
Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities;
|
Params.Flags:=[fdfSearchInAncestors,fdfIgnoreCurContextNode]
|
||||||
|
+fdfAllClassVisibilities+(fdfGlobals*Params.Flags);
|
||||||
if NewContextNode=OldContextNode then
|
if NewContextNode=OldContextNode then
|
||||||
Include(Params.Flags,fdfSearchInParentNodes);
|
Include(Params.Flags,fdfSearchInParentNodes);
|
||||||
|
if (OldContextNode.Desc=ctnTypeDefinition)
|
||||||
|
and (OldContextNode.FirstChild<>nil)
|
||||||
|
and (OldContextNode.FirstChild.Desc=ctnClass)
|
||||||
|
and (OldContextNode.FirstChild.SubDesc=ctnsForwardDeclaration)
|
||||||
|
then
|
||||||
|
Include(Params.Flags,fdfSearchForward);
|
||||||
|
|
||||||
Params.ContextNode:=NewContextNode;
|
Params.ContextNode:=NewContextNode;
|
||||||
Result:=FindIdentifierInContext(Params);
|
Result:=FindIdentifierInContext(Params);
|
||||||
end;
|
end;
|
||||||
@ -526,6 +554,7 @@ function TFindDeclarationTool.FindIdentifierInContext(
|
|||||||
true, if NewPos+NewTopLine valid
|
true, if NewPos+NewTopLine valid
|
||||||
}
|
}
|
||||||
var LastContextNode, StartContextNode, ContextNode: TCodeTreeNode;
|
var LastContextNode, StartContextNode, ContextNode: TCodeTreeNode;
|
||||||
|
IsForward: boolean;
|
||||||
begin
|
begin
|
||||||
ContextNode:=Params.ContextNode;
|
ContextNode:=Params.ContextNode;
|
||||||
StartContextNode:=ContextNode;
|
StartContextNode:=ContextNode;
|
||||||
@ -535,7 +564,7 @@ begin
|
|||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln('[TFindDeclarationTool.FindIdentifierInContext] A Ident=',
|
writeln('[TFindDeclarationTool.FindIdentifierInContext] A Ident=',
|
||||||
copy(Src,Params.IdentifierStartPos,Params.IdentifierEndPos-Params.IdentifierStartPos),
|
copy(Src,Params.IdentifierStartPos,Params.IdentifierEndPos-Params.IdentifierStartPos),
|
||||||
' Context=',ContextNode.DescAsString,
|
' Context=',ContextNode.DescAsString,' ',
|
||||||
' ParentsAllowed=',fdfSearchInParentNodes in Params.Flags,
|
' ParentsAllowed=',fdfSearchInParentNodes in Params.Flags,
|
||||||
' AncestorsAllowed=',fdfSearchInAncestors in Params.Flags
|
' AncestorsAllowed=',fdfSearchInAncestors in Params.Flags
|
||||||
);
|
);
|
||||||
@ -551,8 +580,12 @@ if (ContextNode.Desc=ctnClass) then
|
|||||||
ctnClassPublic, ctnClassPrivate, ctnClassProtected, ctnClassPublished,
|
ctnClassPublic, ctnClassPrivate, ctnClassProtected, ctnClassPublished,
|
||||||
ctnClass,
|
ctnClass,
|
||||||
ctnRecordType, ctnRecordCase, ctnRecordVariant:
|
ctnRecordType, ctnRecordCase, ctnRecordVariant:
|
||||||
if ContextNode.LastChild<>nil then
|
if (ContextNode.LastChild<>nil) then begin
|
||||||
ContextNode:=ContextNode.LastChild;
|
if not (fdfSearchForward in Params.Flags) then
|
||||||
|
ContextNode:=ContextNode.LastChild
|
||||||
|
else
|
||||||
|
ContextNode:=ContextNode.FirstChild;
|
||||||
|
end;
|
||||||
|
|
||||||
ctnTypeDefinition, ctnVarDefinition, ctnConstDefinition, ctnEnumType:
|
ctnTypeDefinition, ctnVarDefinition, ctnConstDefinition, ctnEnumType:
|
||||||
begin
|
begin
|
||||||
@ -618,9 +651,16 @@ writeln(' Definition Identifier found=',copy(Src,ContextNode.StartPos,Params.Id
|
|||||||
|
|
||||||
ctnWithVariable:
|
ctnWithVariable:
|
||||||
begin
|
begin
|
||||||
|
Result:=FindIdentifierInWithVarContext(ContextNode,Params);
|
||||||
|
if Result then exit;
|
||||||
|
end;
|
||||||
|
|
||||||
// ToDo:
|
ctnPointerType:
|
||||||
|
begin
|
||||||
|
// pointer types can be forward definitions
|
||||||
|
Params.ContextNode:=ContextNode.Parent;
|
||||||
|
Result:=FindForwardIdentifier(Params,IsForward);
|
||||||
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -653,10 +693,17 @@ writeln('[TFindDeclarationTool.FindIdentifierInContext] no prior node accessible
|
|||||||
repeat
|
repeat
|
||||||
// search for prior node
|
// search for prior node
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching prior node of ',ContextNode.DescAsString);
|
//writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching prior node of ',ContextNode.DescAsString);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
if ContextNode.PriorBrother<>nil then begin
|
if ((not (fdfSearchForward in Params.Flags))
|
||||||
ContextNode:=ContextNode.PriorBrother;
|
and (ContextNode.PriorBrother<>nil))
|
||||||
|
or ((fdfSearchForward in Params.Flags)
|
||||||
|
and (ContextNode.NextBrother<>nil)) then
|
||||||
|
begin
|
||||||
|
if not (fdfSearchForward in Params.Flags) then
|
||||||
|
ContextNode:=ContextNode.PriorBrother
|
||||||
|
else
|
||||||
|
ContextNode:=ContextNode.NextBrother;
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching in PriorBrother ContextNode=',ContextNode.DescAsString);
|
writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching in PriorBrother ContextNode=',ContextNode.DescAsString);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@ -714,6 +761,11 @@ writeln('[TFindDeclarationTool.FindIdentifierInContext] Searching in Parent Con
|
|||||||
end else begin
|
end else begin
|
||||||
// DeepestNode=nil -> ignore
|
// DeepestNode=nil -> ignore
|
||||||
end;
|
end;
|
||||||
|
if fdfExceptionOnNotFound in Params.Flags then begin
|
||||||
|
MoveCursorToCleanPos(Params.IdentifierStartPos);
|
||||||
|
RaiseException('Identifier not found '+copy(Src,Params.IdentifierStartPos,
|
||||||
|
Params.IdentifierEndPos-Params.IdentifierStartPos));
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TFindDeclarationTool.FindEnumInContext(
|
function TFindDeclarationTool.FindEnumInContext(
|
||||||
@ -733,6 +785,8 @@ begin
|
|||||||
if Params.ContextNode=nil then exit;
|
if Params.ContextNode=nil then exit;
|
||||||
OldContextNode:=Params.ContextNode;
|
OldContextNode:=Params.ContextNode;
|
||||||
try
|
try
|
||||||
|
if Params.ContextNode.Desc=ctnClass then
|
||||||
|
BuildSubTreeForClass(Params.ContextNode);
|
||||||
Params.ContextNode:=Params.ContextNode.FirstChild;
|
Params.ContextNode:=Params.ContextNode.FirstChild;
|
||||||
while Params.ContextNode<>nil do begin
|
while Params.ContextNode<>nil do begin
|
||||||
if (Params.ContextNode.Desc in [ctnEnumType])
|
if (Params.ContextNode.Desc in [ctnEnumType])
|
||||||
@ -838,6 +892,7 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
Result:=FindContextNodeAtCursor(Params);
|
Result:=FindContextNodeAtCursor(Params);
|
||||||
|
if Result=nil then exit;
|
||||||
|
|
||||||
// coming back the left side has been parsed and
|
// coming back the left side has been parsed and
|
||||||
// now the parsing goes from left to right
|
// now the parsing goes from left to right
|
||||||
@ -857,11 +912,11 @@ writeln('');
|
|||||||
|
|
||||||
atIdentifier:
|
atIdentifier:
|
||||||
begin
|
begin
|
||||||
|
// for example 'AnObject[3]'
|
||||||
if not (NextAtomType in [atSpace,atPoint,atUp,atAS,atRoundBracketOpen,
|
if not (NextAtomType in [atSpace,atPoint,atUp,atAS,atRoundBracketOpen,
|
||||||
atEdgedBracketOpen]) then
|
atEdgedBracketOpen]) then
|
||||||
begin
|
begin
|
||||||
MoveCursorToCleanPos(NextAtom.StartPos);
|
MoveCursorToCleanPos(NextAtom.StartPos);
|
||||||
ReadNextAtom;
|
|
||||||
RaiseException('syntax error: "'+GetAtom+'" found');
|
RaiseException('syntax error: "'+GetAtom+'" found');
|
||||||
end;
|
end;
|
||||||
if (Result=Params.ContextNode)
|
if (Result=Params.ContextNode)
|
||||||
@ -880,9 +935,13 @@ writeln('');
|
|||||||
ProcNode:=ProcNode.Parent;
|
ProcNode:=ProcNode.Parent;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
// find identifier
|
||||||
Params.Save(OldInput);
|
Params.Save(OldInput);
|
||||||
try
|
try
|
||||||
Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities;
|
Params.Flags:=[fdfSearchInAncestors,fdfIgnoreCurContextNode]
|
||||||
|
+fdfAllClassVisibilities
|
||||||
|
+(fdfGlobals*Params.Flags)
|
||||||
|
+[fdfExceptionOnNotFound];
|
||||||
//writeln(' ',Result=Params.ContextNode,' ',Result.DescAsString,',',Params.ContextNode.DescAsString);
|
//writeln(' ',Result=Params.ContextNode,' ',Result.DescAsString,',',Params.ContextNode.DescAsString);
|
||||||
if Result=Params.ContextNode then begin
|
if Result=Params.ContextNode then begin
|
||||||
// there is no special context -> also search in parent contexts
|
// there is no special context -> also search in parent contexts
|
||||||
@ -891,10 +950,8 @@ writeln('');
|
|||||||
Params.ContextNode:=Result;
|
Params.ContextNode:=Result;
|
||||||
Params.IdentifierStartPos:=CurAtom.StartPos;
|
Params.IdentifierStartPos:=CurAtom.StartPos;
|
||||||
Params.IdentifierEndPos:=CurAtom.EndPos;
|
Params.IdentifierEndPos:=CurAtom.EndPos;
|
||||||
if FindIdentifierInContext(Params) then
|
FindIdentifierInContext(Params);
|
||||||
Result:=Params.NewNode
|
Result:=Params.NewNode;
|
||||||
else
|
|
||||||
Result:=nil;
|
|
||||||
finally
|
finally
|
||||||
Params.Load(OldInput);
|
Params.Load(OldInput);
|
||||||
end;
|
end;
|
||||||
@ -902,18 +959,66 @@ writeln('');
|
|||||||
|
|
||||||
atPoint:
|
atPoint:
|
||||||
begin
|
begin
|
||||||
|
// for example 'A.B'
|
||||||
if (not (NextAtomType in [atSpace,atIdentifier])) then begin
|
if (not (NextAtomType in [atSpace,atIdentifier])) then begin
|
||||||
MoveCursorToCleanPos(NextAtom.StartPos);
|
MoveCursorToCleanPos(NextAtom.StartPos);
|
||||||
ReadNextAtom;
|
|
||||||
RaiseException('syntax error: identifier expected, but '
|
RaiseException('syntax error: identifier expected, but '
|
||||||
+GetAtom+' found');
|
+GetAtom+' found');
|
||||||
end;
|
end;
|
||||||
|
// there is nothing special to do here, because the '.' will only change
|
||||||
|
// from an identifier to its type context. But this is always done.
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ToDo: atAS, atINHERITED, atUp, atRoundBracketClose, atEdgedBracketClose
|
atAS:
|
||||||
|
begin
|
||||||
|
// for example 'A as B'
|
||||||
|
if (not (NextAtomType in [atSpace,atIdentifier])) then begin
|
||||||
|
MoveCursorToCleanPos(NextAtom.StartPos);
|
||||||
|
RaiseException('syntax error: identifier expected, but '
|
||||||
|
+GetAtom+' found');
|
||||||
|
end;
|
||||||
|
// 'as' is a type cast, so the left side is irrelevant
|
||||||
|
// -> context is default context
|
||||||
|
Result:=Params.ContextNode;
|
||||||
|
end;
|
||||||
|
|
||||||
|
atUP:
|
||||||
|
begin
|
||||||
|
// for example:
|
||||||
|
// 1. 'PInt = ^integer' pointer type
|
||||||
|
// 2. a^ dereferencing
|
||||||
|
if Result<>Params.ContextNode then begin
|
||||||
|
// left side of expression has defined a special context
|
||||||
|
// => this '^' is a dereference
|
||||||
|
if (not (NextAtomType in [atSpace,atPoint,atAS,atUP])) then begin
|
||||||
|
MoveCursorToCleanPos(NextAtom.StartPos);
|
||||||
|
RaiseException('syntax error: . expected, but '+GetAtom+' found');
|
||||||
|
end;
|
||||||
|
if Result.Desc<>ctnPointerType then begin
|
||||||
|
MoveCursorToCleanPos(CurAtom.StartPos);
|
||||||
|
RaiseException('illegal qualifier ^');
|
||||||
|
end;
|
||||||
|
Result:=Result.FirstChild;
|
||||||
|
end else if NodeHasParentOfType(Result,ctnPointerType) then begin
|
||||||
|
// this is a pointer type definition
|
||||||
|
// -> the default context is ok
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
// ToDo: atINHERITED, atRoundBracketClose, atEdgedBracketClose
|
||||||
|
|
||||||
else
|
else
|
||||||
Result:=Params.ContextNode;
|
begin
|
||||||
|
if (not (NextAtomType in [atSpace,atIdentifier,atRoundBracketOpen,
|
||||||
|
atEdgedBracketOpen])) then
|
||||||
|
begin
|
||||||
|
MoveCursorToCleanPos(NextAtom.StartPos);
|
||||||
|
RaiseException('syntax error: identifier expected, but '
|
||||||
|
+GetAtom+' found');
|
||||||
|
end;
|
||||||
|
Result:=Params.ContextNode;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// try to get the base type of the found context
|
// try to get the base type of the found context
|
||||||
@ -931,6 +1036,7 @@ end;
|
|||||||
function TFindDeclarationTool.FindBaseTypeOfNode(Params: TFindDeclarationParams;
|
function TFindDeclarationTool.FindBaseTypeOfNode(Params: TFindDeclarationParams;
|
||||||
Node: TCodeTreeNode): TCodeTreeNode;
|
Node: TCodeTreeNode): TCodeTreeNode;
|
||||||
var OldInput: TFindDeclarationInput;
|
var OldInput: TFindDeclarationInput;
|
||||||
|
ClassIdentNode: TCodeTreeNode;
|
||||||
begin
|
begin
|
||||||
Result:=Node;
|
Result:=Node;
|
||||||
while (Result<>nil) do begin
|
while (Result<>nil) do begin
|
||||||
@ -941,9 +1047,31 @@ begin
|
|||||||
if (Result.Desc=ctnClass) and (Result.SubDesc=ctnsForwardDeclaration) then
|
if (Result.Desc=ctnClass) and (Result.SubDesc=ctnsForwardDeclaration) then
|
||||||
begin
|
begin
|
||||||
// search the real class
|
// search the real class
|
||||||
|
ClassIdentNode:=Result.Parent;
|
||||||
// ToDo
|
if (ClassIdentNode=nil) or (not (ClassIdentNode.Desc=ctnTypeDefinition))
|
||||||
|
then begin
|
||||||
|
MoveCursorToCleanPos(Result.StartPos);
|
||||||
|
RaiseException('[TFindDeclarationTool.FindBaseTypeOfNode] '
|
||||||
|
+'forward class node without name');
|
||||||
|
end;
|
||||||
|
Params.Save(OldInput);
|
||||||
|
try
|
||||||
|
Params.IdentifierStartPos:=ClassIdentNode.StartPos;
|
||||||
|
Params.IdentifierEndPos:=ClassIdentNode.EndPos;
|
||||||
|
Params.Flags:=[fdfSearchInParentNodes,fdfSearchForward]
|
||||||
|
+(fdfGlobals*Params.Flags)
|
||||||
|
+[fdfExceptionOnNotFound];
|
||||||
|
Params.ContextNode:=ClassIdentNode;
|
||||||
|
FindIdentifierInContext(Params);
|
||||||
|
if Params.NewNode.Desc<>ctnTypeDefinition then begin
|
||||||
|
MoveCursorToCleanPos(Result.StartPos);
|
||||||
|
RaiseException('Forward class definition not resolved: '
|
||||||
|
+copy(Src,ClassIdentNode.StartPos,
|
||||||
|
ClassIdentNode.EndPos-ClassIdentNode.StartPos));
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Params.Load(OldInput);
|
||||||
|
end;
|
||||||
end else
|
end else
|
||||||
if (Result.Desc=ctnTypeType) then begin
|
if (Result.Desc=ctnTypeType) then begin
|
||||||
// a TypeType is for example 'MyInt = type integer;'
|
// a TypeType is for example 'MyInt = type integer;'
|
||||||
@ -959,7 +1087,8 @@ begin
|
|||||||
try
|
try
|
||||||
Params.IdentifierStartPos:=Result.StartPos;
|
Params.IdentifierStartPos:=Result.StartPos;
|
||||||
Params.IdentifierEndPos:=Result.EndPos;
|
Params.IdentifierEndPos:=Result.EndPos;
|
||||||
Params.Flags:=[fdfSearchInParentNodes];
|
Params.Flags:=[fdfSearchInParentNodes]+(fdfGlobals*Params.Flags)
|
||||||
|
-[fdfExceptionOnNotFound];
|
||||||
Params.ContextNode:=Result.Parent;
|
Params.ContextNode:=Result.Parent;
|
||||||
if FindIdentifierInContext(Params) then begin
|
if FindIdentifierInContext(Params) then begin
|
||||||
if Result.HasAsParent(Params.NewNode) then
|
if Result.HasAsParent(Params.NewNode) then
|
||||||
@ -1010,37 +1139,35 @@ begin
|
|||||||
// 1. search the class
|
// 1. search the class
|
||||||
Params.Save(OldInput);
|
Params.Save(OldInput);
|
||||||
try
|
try
|
||||||
Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes];
|
Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes]
|
||||||
|
+(fdfGlobals*Params.Flags)
|
||||||
|
+[fdfExceptionOnNotFound];
|
||||||
Params.ContextNode:=ProcContextNode;
|
Params.ContextNode:=ProcContextNode;
|
||||||
Params.IdentifierStartPos:=ClassNameAtom.StartPos;
|
Params.IdentifierStartPos:=ClassNameAtom.StartPos;
|
||||||
Params.IdentifierEndPos:=ClassNameAtom.EndPos;
|
Params.IdentifierEndPos:=ClassNameAtom.EndPos;
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos,ClassNameAtom.EndPos-ClassNameAtom.StartPos),'"');
|
writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos,ClassNameAtom.EndPos-ClassNameAtom.StartPos),'"');
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
if FindIdentifierInContext(Params) then begin
|
FindIdentifierInContext(Params);
|
||||||
ClassContextNode:=FindBaseTypeOfNode(Params,Params.NewNode);
|
ClassContextNode:=FindBaseTypeOfNode(Params,Params.NewNode);
|
||||||
if (ClassContextNode=nil)
|
if (ClassContextNode=nil)
|
||||||
or (ClassContextNode.Desc<>ctnClass) then begin
|
or (ClassContextNode.Desc<>ctnClass) then begin
|
||||||
MoveCursorToCleanPos(ClassNameAtom.StartPos);
|
MoveCursorToCleanPos(ClassNameAtom.StartPos);
|
||||||
RaiseException('class identifier expected');
|
RaiseException('class identifier expected');
|
||||||
end;
|
end;
|
||||||
// class of method found
|
// class of method found
|
||||||
BuildSubTreeForClass(ClassContextNode);
|
BuildSubTreeForClass(ClassContextNode);
|
||||||
// class context found -> search identifier
|
// class context found -> search identifier
|
||||||
Params.Load(OldInput);
|
Params.Load(OldInput);
|
||||||
Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities;
|
Params.Flags:=[fdfSearchInAncestors]+fdfAllClassVisibilities
|
||||||
Params.ContextNode:=ClassContextNode;
|
+(fdfGlobals*Params.Flags)
|
||||||
|
-[fdfExceptionOnNotFound];
|
||||||
|
Params.ContextNode:=ClassContextNode;
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln(' searching identifier in class of method');
|
writeln(' searching identifier in class of method');
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
Result:=FindIdentifierInContext(Params);
|
Result:=FindIdentifierInContext(Params);
|
||||||
if Result then exit;
|
if Result then exit;
|
||||||
end else begin
|
|
||||||
// class not found -> cancel the search
|
|
||||||
MoveCursorToCleanPos(ClassNameAtom.StartPos);
|
|
||||||
RaiseException('class not found');
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
finally
|
finally
|
||||||
Params.Load(OldInput);
|
Params.Load(OldInput);
|
||||||
end;
|
end;
|
||||||
@ -1080,33 +1207,29 @@ writeln('[TFindDeclarationTool.FindClassOfMethod] A');
|
|||||||
// -> search the class
|
// -> search the class
|
||||||
Params.Save(OldInput);
|
Params.Save(OldInput);
|
||||||
try
|
try
|
||||||
Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes];
|
Params.Flags:=[fdfIgnoreCurContextNode,fdfSearchInParentNodes]
|
||||||
|
+(fdfGlobals*Params.Flags)
|
||||||
|
-[fdfExceptionOnNotFound];
|
||||||
Params.ContextNode:=ProcNode;
|
Params.ContextNode:=ProcNode;
|
||||||
Params.IdentifierStartPos:=ClassNameAtom.StartPos;
|
Params.IdentifierStartPos:=ClassNameAtom.StartPos;
|
||||||
Params.IdentifierEndPos:=ClassNameAtom.EndPos;
|
Params.IdentifierEndPos:=ClassNameAtom.EndPos;
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos,ClassNameAtom.EndPos-ClassNameAtom.StartPos),'"');
|
writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos,ClassNameAtom.EndPos-ClassNameAtom.StartPos),'"');
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
if FindIdentifierInContext(Params) then begin
|
FindIdentifierInContext(Params);
|
||||||
if FindClassContext then begin
|
if FindClassContext then begin
|
||||||
// parse class and return class node
|
// parse class and return class node
|
||||||
Params.NewNode:=FindBaseTypeOfNode(Params,Params.NewNode);
|
Params.NewNode:=FindBaseTypeOfNode(Params,Params.NewNode);
|
||||||
if (Params.NewNode=nil)
|
if (Params.NewNode=nil)
|
||||||
or (Params.NewNode.Desc<>ctnClass) then begin
|
or (Params.NewNode.Desc<>ctnClass) then begin
|
||||||
MoveCursorToCleanPos(ClassNameAtom.StartPos);
|
MoveCursorToCleanPos(ClassNameAtom.StartPos);
|
||||||
RaiseException('class identifier expected');
|
RaiseException('class identifier expected');
|
||||||
end;
|
|
||||||
// class of method found
|
|
||||||
// parse class and return class node
|
|
||||||
BuildSubTreeForClass(Params.NewNode);
|
|
||||||
end;
|
end;
|
||||||
Result:=true;
|
// class of method found
|
||||||
end else begin
|
// parse class and return class node
|
||||||
// class not found -> cancel the search
|
BuildSubTreeForClass(Params.NewNode);
|
||||||
MoveCursorToCleanPos(ClassNameAtom.StartPos);
|
|
||||||
RaiseException('class not found');
|
|
||||||
exit;
|
|
||||||
end;
|
end;
|
||||||
|
Result:=true;
|
||||||
finally
|
finally
|
||||||
Params.Load(OldInput);
|
Params.Load(OldInput);
|
||||||
end;
|
end;
|
||||||
@ -1115,6 +1238,89 @@ writeln(' searching class of method class="',copy(Src,ClassNameAtom.StartPos,
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFindDeclarationTool.FindForwardIdentifier(
|
||||||
|
Params: TFindDeclarationParams; var IsForward: boolean): boolean;
|
||||||
|
{ first search the identifier in the normal way via FindIdentifierInContext
|
||||||
|
then search the other direction }
|
||||||
|
var
|
||||||
|
OldInput: TFindDeclarationInput;
|
||||||
|
begin
|
||||||
|
Params.Save(OldInput);
|
||||||
|
try
|
||||||
|
Exclude(Params.Flags,fdfExceptionOnNotFound);
|
||||||
|
Result:=FindIdentifierInContext(Params);
|
||||||
|
if not Result then begin
|
||||||
|
Params.Load(OldInput);
|
||||||
|
Include(Params.Flags,fdfSearchForward);
|
||||||
|
Result:=FindIdentifierInContext(Params);
|
||||||
|
IsForward:=true;
|
||||||
|
end else
|
||||||
|
IsForward:=false;
|
||||||
|
finally
|
||||||
|
Params.Load(OldInput);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFindDeclarationTool.FindIdentifierInWithVarContext(
|
||||||
|
WithVarNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean;
|
||||||
|
{ this function is internally used by FindIdentifierInContext
|
||||||
|
}
|
||||||
|
var
|
||||||
|
WithVarContextNode: TCodeTreeNode;
|
||||||
|
OldInput: TFindDeclarationInput;
|
||||||
|
begin
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
writeln('[TFindDeclarationTool.FindIdentifierInWithVarContext] ',
|
||||||
|
copy(Src,Params.IdentifierStartPos,Params.IdentifierEndPos-Params.IdentifierStartPos)
|
||||||
|
);
|
||||||
|
{$ENDIF}
|
||||||
|
Result:=false;
|
||||||
|
// find the base type of the with variable
|
||||||
|
// move cursor to end of with-expression
|
||||||
|
if (WithVarNode.FirstChild<>nil) then begin
|
||||||
|
// this is the last with-variable
|
||||||
|
MoveCursorToCleanPos(WithVarNode.FirstChild.StartPos);
|
||||||
|
ReadPriorAtom; // read 'do'
|
||||||
|
CurPos.EndPos:=CurPos.StartPos; // make the 'do' unread,
|
||||||
|
// because 'do' is not part of the expr
|
||||||
|
end else begin
|
||||||
|
// this is not the last with variable, so the expr end is equal to node end
|
||||||
|
MoveCursorToCleanPos(WithVarNode.EndPos);
|
||||||
|
end;
|
||||||
|
Params.Save(OldInput);
|
||||||
|
try
|
||||||
|
Params.ContextNode:=WithVarNode;
|
||||||
|
Include(Params.Flags,fdfExceptionOnNotFound);
|
||||||
|
WithVarContextNode:=FindContextNodeAtCursor(Params);
|
||||||
|
if (WithVarContextNode=nil) or (WithVarContextNode=OldInput.ContextNode)
|
||||||
|
or (not (WithVarContextNode.Desc in [ctnClass,ctnRecordType])) then begin
|
||||||
|
MoveCursorToCleanPos(WithVarNode.StartPos);
|
||||||
|
RaiseException('expression type must be class or record type');
|
||||||
|
end;
|
||||||
|
// search identifier in with context
|
||||||
|
Params.Load(OldInput);
|
||||||
|
Exclude(Params.Flags,fdfExceptionOnNotFound);
|
||||||
|
Params.ContextNode:=WithVarContextNode;
|
||||||
|
if FindIdentifierInContext(Params) then begin
|
||||||
|
// identifier found in with context
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Params.Load(OldInput);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
procedure TFindDeclarationTool.DecPrefix;
|
||||||
|
begin
|
||||||
|
DebugPrefix:=copy(DebugPrefix,1,length(DebugPrefix)-2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFindDeclarationTool.IncPrefix;
|
||||||
|
begin
|
||||||
|
DebugPrefix:=DebugPrefix+' ';
|
||||||
|
end;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
|
||||||
{ TFindDeclarationParams }
|
{ TFindDeclarationParams }
|
||||||
|
@ -180,9 +180,7 @@ writeln('TMethodJumpingCodeTool.FindJumpPoint B');
|
|||||||
if CleanCursorPos<FirstAtomStart then CleanCursorPos:=FirstAtomStart;
|
if CleanCursorPos<FirstAtomStart then CleanCursorPos:=FirstAtomStart;
|
||||||
if CleanCursorPos>=LastAtomEnd then CleanCursorPos:=LastAtomEnd-1;
|
if CleanCursorPos>=LastAtomEnd then CleanCursorPos:=LastAtomEnd-1;
|
||||||
// find CodeTreeNode at cursor
|
// find CodeTreeNode at cursor
|
||||||
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos);
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
if CursorNode=nil then
|
|
||||||
RaiseException('no node found at cursor');
|
|
||||||
{$IFDEF CTDEBUG}
|
{$IFDEF CTDEBUG}
|
||||||
writeln('TMethodJumpingCodeTool.FindJumpPoint C ',NodeDescriptionAsString(CursorNode.Desc));
|
writeln('TMethodJumpingCodeTool.FindJumpPoint C ',NodeDescriptionAsString(CursorNode.Desc));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@ -208,7 +206,7 @@ writeln('TMethodJumpingCodeTool.FindJumpPoint D ',CleanCursorPos,', |',copy(Src,
|
|||||||
and (TypeSectionNode.Parent.Desc=ctnTypeSection) then
|
and (TypeSectionNode.Parent.Desc=ctnTypeSection) then
|
||||||
TypeSectionNode:=TypeSectionNode.Parent;
|
TypeSectionNode:=TypeSectionNode.Parent;
|
||||||
// search the method node under the cursor
|
// search the method node under the cursor
|
||||||
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos);
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,false);
|
||||||
if (CursorNode=nil)
|
if (CursorNode=nil)
|
||||||
or (not (CursorNode.Desc in [ctnProcedureHead,ctnProcedure])) then
|
or (not (CursorNode.Desc in [ctnProcedureHead,ctnProcedure])) then
|
||||||
exit;
|
exit;
|
||||||
|
@ -609,6 +609,10 @@ begin
|
|||||||
if BeginNode=nil then
|
if BeginNode=nil then
|
||||||
RaiseException(
|
RaiseException(
|
||||||
'TPascalParserTool.BuildSubTreeForBeginBlock: BeginNode=nil');
|
'TPascalParserTool.BuildSubTreeForBeginBlock: BeginNode=nil');
|
||||||
|
if BeginNode.Desc<>ctnBeginBlock then
|
||||||
|
RaiseException(
|
||||||
|
'TPascalParserTool.BuildSubTreeForBeginBlock: BeginNode.Desc='
|
||||||
|
+BeginNode.DescAsString);
|
||||||
if BeginNode.FirstChild<>nil then
|
if BeginNode.FirstChild<>nil then
|
||||||
// block already parsed
|
// block already parsed
|
||||||
exit;
|
exit;
|
||||||
|
Loading…
Reference in New Issue
Block a user