mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-26 18:43:50 +02:00
1141 lines
32 KiB
ObjectPascal
1141 lines
32 KiB
ObjectPascal
{
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
***************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
A TCodeTree is the product of a code tool. Every TCodeTreeNode describes a
|
|
logical block in the code (e.g. a class, a procedure or an identifier).
|
|
|
|
This unit defines also all valid CodeTree-Node-Descriptors, constants for
|
|
TCodeTreeNode types.
|
|
|
|
}
|
|
unit CodeTree;
|
|
|
|
{$ifdef FPC}{$mode objfpc}{$endif}{$H+}
|
|
|
|
interface
|
|
|
|
{$I codetools.inc}
|
|
|
|
uses
|
|
{$IFDEF MEM_CHECK}
|
|
MemCheck,
|
|
{$ENDIF}
|
|
Classes, SysUtils, FileProcs, CodeToolsStructs, BasicCodeTools,
|
|
AVL_Tree, CodeToolMemManager;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
type
|
|
TCodeTreeNodeDesc = word;
|
|
TCodeTreeNodeSubDesc = word;
|
|
|
|
const
|
|
// CodeTreeNodeDescriptors
|
|
ctnNone = 0;
|
|
|
|
ctnProgram = 1;
|
|
ctnPackage = 2;
|
|
ctnLibrary = 3;
|
|
ctnUnit = 4;
|
|
ctnInterface = 5;
|
|
ctnImplementation = 6;
|
|
ctnInitialization = 7;
|
|
ctnFinalization = 8;
|
|
ctnEndPoint = 9;
|
|
|
|
ctnTypeSection = 10;
|
|
ctnVarSection = 11;
|
|
ctnConstSection = 12;
|
|
ctnResStrSection = 13;
|
|
ctnLabelSection = 14;
|
|
ctnPropertySection = 15;
|
|
ctnUsesSection = 16;
|
|
ctnRequiresSection = 17;
|
|
ctnContainsSection = 18;
|
|
ctnExportsSection = 19;
|
|
|
|
ctnTypeDefinition = 20;
|
|
ctnVarDefinition = 21;
|
|
ctnConstDefinition = 22;
|
|
ctnGlobalProperty = 23;
|
|
ctnUseUnit = 24;
|
|
|
|
ctnClass = 30;
|
|
ctnClassInterface = 31;
|
|
ctnObject = 32;
|
|
ctnObjCClass = 33;
|
|
ctnObjCCategory = 34;
|
|
ctnObjCProtocol = 35;
|
|
ctnCPPClass = 36;
|
|
ctnDispinterface = 37;
|
|
|
|
ctnClassAbstract = 40;
|
|
ctnClassSealed = 41;
|
|
ctnClassInheritance = 42;
|
|
ctnClassGUID = 43;
|
|
ctnClassTypePrivate = 44;
|
|
ctnClassTypeProtected = 45;
|
|
ctnClassTypePublic = 46;
|
|
ctnClassTypePublished = 47;
|
|
ctnClassVarPrivate = 48;
|
|
ctnClassVarProtected = 49;
|
|
ctnClassVarPublic = 50;
|
|
ctnClassVarPublished = 51;
|
|
ctnClassPrivate = 52;
|
|
ctnClassProtected = 53;
|
|
ctnClassPublic = 54;
|
|
ctnClassPublished = 55;
|
|
ctnProperty = 56;
|
|
ctnMethodMap = 57;
|
|
|
|
ctnProcedure = 60; // childs: ctnProcedureHead, sections, ctnBeginBlock/ctnAsmBlock
|
|
ctnProcedureHead = 61; // childs: ctnParameterList, operator: ctnVarDefinition, operator/function: ctnResultType
|
|
ctnParameterList = 62; // childs: ctnVarDefinition
|
|
|
|
ctnIdentifier = 70;
|
|
ctnRangedArrayType = 71;
|
|
ctnOpenArrayType = 72;
|
|
ctnOfConstType = 73;
|
|
ctnRecordType = 74;
|
|
ctnRecordCase = 75;
|
|
ctnRecordVariant = 76;
|
|
ctnProcedureType = 77;
|
|
ctnSetType = 78;
|
|
ctnRangeType = 79;
|
|
ctnEnumerationType = 80;
|
|
ctnEnumIdentifier = 81;
|
|
ctnLabelType = 82;
|
|
ctnTypeType = 83;
|
|
ctnFileType = 84;
|
|
ctnPointerType = 85;
|
|
ctnClassOfType = 86;
|
|
ctnVariantType = 87;
|
|
ctnSpecialize = 88;
|
|
ctnSpecializeType = 89;
|
|
ctnSpecializeParams = 90;
|
|
ctnGenericType = 91;// 1. child = ctnGenericName, 2. child = ctnGenericParams, 3. child = type
|
|
ctnGenericName = 92;
|
|
ctnGenericParams = 93;
|
|
ctnGenericParameter = 94;
|
|
ctnConstant = 95;
|
|
|
|
ctnBeginBlock =100;
|
|
ctnAsmBlock =101;
|
|
|
|
ctnWithVariable =110;
|
|
ctnWithStatement =111;
|
|
ctnOnBlock =112;
|
|
ctnOnIdentifier =113;// e.g. on E: Exception
|
|
ctnOnStatement =114;
|
|
|
|
// combined values
|
|
AllSourceTypes =
|
|
[ctnProgram,ctnPackage,ctnLibrary,ctnUnit];
|
|
AllUsableSourceTypes =
|
|
[ctnUnit];
|
|
AllCodeSections = AllSourceTypes
|
|
+ [ctnInterface, ctnImplementation, ctnInitialization, ctnFinalization];
|
|
AllClassBaseSections =
|
|
[ctnClassPublic,ctnClassPublished,ctnClassPrivate,ctnClassProtected];
|
|
AllClassTypeSections =
|
|
[ctnClassTypePublic,ctnClassTypePublished,ctnClassTypePrivate,
|
|
ctnClassTypeProtected];
|
|
AllClassVarSections =
|
|
[ctnClassVarPublic,ctnClassVarPublished,ctnClassVarPrivate,
|
|
ctnClassVarProtected];
|
|
AllClassSections =
|
|
AllClassBaseSections+AllClassTypeSections+AllClassVarSections;
|
|
AllClasses =
|
|
[ctnClass,ctnClassInterface,ctnDispinterface,ctnObject,
|
|
ctnObjCClass,ctnObjCCategory,ctnObjCProtocol,
|
|
ctnCPPClass];
|
|
AllClassInterfaces = [ctnClassInterface,ctnDispinterface,ctnObjCProtocol];
|
|
AllClassObjects = [ctnClass,ctnObject,ctnObjCClass,ctnObjCCategory,ctnCPPClass];
|
|
AllClassModifiers = [ctnClassAbstract, ctnClassSealed];
|
|
AllDefinitionSections =
|
|
[ctnTypeSection,ctnVarSection,ctnConstSection,ctnResStrSection,
|
|
ctnLabelSection];
|
|
AllIdentifierDefinitions =
|
|
[ctnTypeDefinition,ctnVarDefinition,ctnConstDefinition,ctnGenericType];
|
|
AllSimpleIdentifierDefinitions =
|
|
[ctnTypeDefinition,ctnVarDefinition,ctnConstDefinition];
|
|
AllPascalTypes =
|
|
AllClasses+
|
|
[ctnGenericType,ctnSpecialize,
|
|
ctnIdentifier,ctnOpenArrayType,ctnRangedArrayType,ctnRecordType,
|
|
ctnRecordCase,ctnRecordVariant,
|
|
ctnProcedureType,ctnSetType,ctnRangeType,ctnEnumerationType,
|
|
ctnEnumIdentifier,ctnLabelType,ctnTypeType,ctnFileType,ctnPointerType,
|
|
ctnClassOfType,ctnVariantType,ctnConstant];
|
|
AllPascalStatements = [ctnBeginBlock,ctnWithStatement,ctnWithVariable,
|
|
ctnOnBlock,ctnOnIdentifier,ctnOnStatement];
|
|
AllFindContextDescs = AllIdentifierDefinitions + AllCodeSections + AllClasses +
|
|
[ctnProcedure];
|
|
AllPointContexts = AllClasses+AllSourceTypes+[ctnRecordType,ctnEnumerationType];
|
|
|
|
|
|
// CodeTreeNodeSubDescriptors
|
|
ctnsNone = 0;
|
|
ctnsForwardDeclaration = 1 shl 0;
|
|
ctnsNeedJITParsing = 1 shl 1;
|
|
ctnsHasParseError = 1 shl 2;
|
|
ctnsHasDefaultValue = 1 shl 3;
|
|
|
|
ClassSectionNodeType: array[TPascalClassSection] of TCodeTreeNodeDesc = (
|
|
ctnClassPrivate,
|
|
ctnClassProtected,
|
|
ctnClassPublic,
|
|
ctnClassPublished
|
|
);
|
|
|
|
|
|
type
|
|
// Procedure Specifiers
|
|
TProcedureSpecifier = (
|
|
psSTDCALL, psREGISTER, psPOPSTACK, psVIRTUAL, psABSTRACT, psDYNAMIC,
|
|
psOVERLOAD, psOVERRIDE, psREINTRODUCE, psCDECL, psINLINE, psMESSAGE,
|
|
psEXTERNAL, psFORWARD, psPASCAL, psASSEMBLER, psSAVEREGISTERS,
|
|
psFAR, psNEAR, psFINAL, psEdgedBracket);
|
|
TAllProcedureSpecifiers = set of TProcedureSpecifier;
|
|
|
|
const
|
|
ProcedureSpecifierNames: array[TProcedureSpecifier] of shortstring = (
|
|
'STDCALL', 'REGISTER', 'POPSTACK', 'VIRTUAL', 'ABSTRACT', 'DYNAMIC',
|
|
'OVERLOAD', 'OVERRIDE', 'REINTRODUCE', 'CDECL', 'INLINE', 'MESSAGE',
|
|
'EXTERNAL', 'FORWARD', 'PASCAL', 'ASSEMBLER', 'SAVEREGISTERS',
|
|
'FAR', 'NEAR', 'FINAL', '['
|
|
);
|
|
|
|
|
|
type
|
|
|
|
{ TCodeTreeNode }
|
|
|
|
TCodeTreeNode = class
|
|
public
|
|
Desc: TCodeTreeNodeDesc;
|
|
SubDesc: TCodeTreeNodeSubDesc;
|
|
Parent, NextBrother, PriorBrother, FirstChild, LastChild: TCodeTreeNode;
|
|
StartPos, EndPos: integer;
|
|
Cache: TObject;
|
|
function Next: TCodeTreeNode;
|
|
function NextSkipChilds: TCodeTreeNode;
|
|
function Prior: TCodeTreeNode;
|
|
function HasAsParent(Node: TCodeTreeNode): boolean;
|
|
function HasAsChild(Node: TCodeTreeNode): boolean;
|
|
function HasParentOfType(ParentDesc: TCodeTreeNodeDesc): boolean;
|
|
function HasAsRoot(RootNode: TCodeTreeNode): boolean;
|
|
function GetNodeOfType(ADesc: TCodeTreeNodeDesc): TCodeTreeNode;
|
|
function GetNodeOfTypes(Descriptors: array of TCodeTreeNodeDesc): TCodeTreeNode;
|
|
function GetFindContextParent: TCodeTreeNode;
|
|
function GetLevel: integer;
|
|
function DescAsString: string;
|
|
function GetRoot: TCodeTreeNode;
|
|
function ChildCount: integer;
|
|
function FindOwner: TObject;
|
|
procedure Clear;
|
|
constructor Create;
|
|
procedure ConsistencyCheck;
|
|
procedure WriteDebugReport(const Prefix: string; WithChilds: boolean);
|
|
end;
|
|
|
|
{ TCodeTree }
|
|
|
|
TCodeTree = class
|
|
private
|
|
FNodeCount: integer;
|
|
public
|
|
Root: TCodeTreeNode;
|
|
property NodeCount: integer read FNodeCount;
|
|
procedure DeleteNode(ANode: TCodeTreeNode);
|
|
procedure AddNodeAsLastChild(ParentNode, ANode: TCodeTreeNode);
|
|
procedure AddNodeInFrontOf(NextBrotherNode, ANode: TCodeTreeNode);
|
|
function FindFirstPosition: integer;
|
|
function FindLastPosition: integer;
|
|
function ContainsNode(ANode: TCodeTreeNode): boolean;
|
|
procedure Clear;
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure ConsistencyCheck;
|
|
procedure WriteDebugReport(WithChilds: boolean);
|
|
end;
|
|
|
|
|
|
{ TCodeTreeNodeExtension }
|
|
|
|
TCodeTreeNodeExtension = class
|
|
public
|
|
Node: TCodeTreeNode;
|
|
Txt: string;
|
|
ExtTxt1, ExtTxt2, ExtTxt3: string;
|
|
Position: integer;
|
|
Data: Pointer;
|
|
Flags: cardinal;
|
|
Next: TCodeTreeNodeExtension;
|
|
procedure Clear;
|
|
constructor Create;
|
|
function ConsistencyCheck: integer; // 0 = ok
|
|
procedure WriteDebugReport;
|
|
function CalcMemSize: PtrUInt;
|
|
end;
|
|
|
|
|
|
{ TCodeTreeNodeMemManager - memory system for TCodeTreeNode(s) }
|
|
|
|
TCodeTreeNodeMemManager = class(TCodeToolMemManager)
|
|
protected
|
|
procedure FreeFirstItem; override;
|
|
public
|
|
procedure DisposeNode(ANode: TCodeTreeNode);
|
|
function NewNode: TCodeTreeNode;
|
|
end;
|
|
|
|
|
|
{ TCodeTreeNodeExtMemManager - memory system for TCodeTreeNodeExtension(s) }
|
|
|
|
TCodeTreeNodeExtMemManager = class(TCodeToolMemManager)
|
|
protected
|
|
procedure FreeFirstItem; override;
|
|
public
|
|
procedure DisposeNode(ANode: TCodeTreeNodeExtension);
|
|
procedure DisposeAVLTree(TheTree: TAVLTree);
|
|
function NewNode: TCodeTreeNodeExtension;
|
|
end;
|
|
|
|
|
|
var
|
|
NodeExtMemManager: TCodeTreeNodeExtMemManager;
|
|
NodeMemManager: TCodeTreeNodeMemManager;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// useful functions
|
|
function NodeDescriptionAsString(Desc: TCodeTreeNodeDesc): string;
|
|
procedure WriteNodeExtTree(Tree: TAVLTree);
|
|
function FindCodeTreeNodeExt(Tree: TAVLTree; const Txt: string
|
|
): TCodeTreeNodeExtension;
|
|
function FindCodeTreeNodeExtAVLNode(Tree: TAVLTree; const Txt: string
|
|
): TAVLTreeNode;
|
|
function FindCodeTreeNodeExtWithIdentifier(Tree: TAVLTree; Identifier: PChar
|
|
): TCodeTreeNodeExtension;
|
|
function FindCodeTreeNodeExtAVLNodeWithIdentifier(Tree: TAVLTree;
|
|
Identifier: PChar): TAVLTreeNode;
|
|
function CompareTxtWithCodeTreeNodeExt(p: Pointer;
|
|
NodeData: pointer): integer;
|
|
function CompareIdentifierWithCodeTreeNodeExt(p: Pointer;
|
|
NodeData: pointer): integer;
|
|
function CompareCodeTreeNodeExt(NodeData1, NodeData2: pointer): integer;
|
|
function CompareCodeTreeNodeExtWithPos(NodeData1, NodeData2: pointer): integer;
|
|
function CompareCodeTreeNodeExtWithNodeStartPos(
|
|
NodeData1, NodeData2: pointer): integer;
|
|
function CompareCodeTreeNodeExtWithNode(NodeData1, NodeData2: pointer): integer;
|
|
function ComparePointerWithCodeTreeNodeExtNode(p: Pointer;
|
|
NodeExt: pointer): integer;
|
|
|
|
type
|
|
TOnFindOwnerOfCodeTreeNode = function (ANode: TCodeTreeNode): TObject;
|
|
|
|
var
|
|
OnFindOwnerOfCodeTreeNode: TOnFindOwnerOfCodeTreeNode;
|
|
|
|
function FindOwnerOfCodeTreeNode(ANode: TCodeTreeNode): TObject;
|
|
|
|
|
|
implementation
|
|
|
|
|
|
function NodeDescriptionAsString(Desc: TCodeTreeNodeDesc): string;
|
|
begin
|
|
case Desc of
|
|
ctnNone: Result:='None';
|
|
|
|
ctnClass: Result:='Class';
|
|
ctnClassInterface: Result:='Class Interface';
|
|
ctnDispinterface: Result:='Dispinterface';
|
|
ctnObject: Result:='Object';
|
|
ctnObjCClass: Result:='ObjCClass';
|
|
ctnObjCCategory: Result:='ObjCCategory';
|
|
ctnObjCProtocol: Result:='ObjCProtocol';
|
|
ctnCPPClass: Result:='CPPClass';
|
|
|
|
ctnClassInheritance: Result:='Class inheritance';
|
|
ctnClassGUID: Result:='GUID';
|
|
ctnClassPublished: Result:='Published';
|
|
ctnClassPrivate: Result:='Private';
|
|
ctnClassProtected: Result:='Protected';
|
|
ctnClassPublic: Result:='Public';
|
|
ctnClassTypePublished: Result:='Type Published';
|
|
ctnClassTypePrivate: Result:='Type Private';
|
|
ctnClassTypeProtected: Result:='Type Protected';
|
|
ctnClassTypePublic: Result:='Type Public';
|
|
ctnClassVarPublished: Result:='Var Published';
|
|
ctnClassVarPrivate: Result:='Var Private';
|
|
ctnClassVarProtected: Result:='Var Protected';
|
|
ctnClassVarPublic: Result:='Var Public';
|
|
ctnClassAbstract: Result:='abstract';
|
|
ctnClassSealed: Result:='sealed';
|
|
|
|
ctnProcedure: Result:='Procedure';
|
|
ctnProcedureHead: Result:='ProcedureHead';
|
|
ctnParameterList: Result:='ParameterList';
|
|
|
|
ctnBeginBlock: Result:='BeginBlock';
|
|
ctnAsmBlock: Result:='AsmBlock';
|
|
|
|
ctnProgram: Result:='Program';
|
|
ctnPackage: Result:='Package';
|
|
ctnLibrary: Result:='Library';
|
|
ctnUnit: Result:='Unit';
|
|
ctnInterface: Result:='Interface Section';
|
|
ctnImplementation: Result:='Implementation';
|
|
ctnInitialization: Result:='Initialization';
|
|
ctnFinalization: Result:='Finalization';
|
|
ctnEndPoint: Result:='End.';
|
|
|
|
ctnTypeSection: Result:='Type Section';
|
|
ctnVarSection: Result:='Var Section';
|
|
ctnConstSection: Result:='Const Section';
|
|
ctnResStrSection: Result:='Resource String Section';
|
|
ctnPropertySection: Result:='Property Section';
|
|
ctnUsesSection: Result:='Uses Section';
|
|
ctnRequiresSection: Result:='Requires Section';
|
|
ctnContainsSection: Result:='Contains Section';
|
|
ctnExportsSection: Result:='Exports Section';
|
|
|
|
ctnTypeDefinition: Result:='Type';
|
|
ctnVarDefinition: Result:='Var';
|
|
ctnConstDefinition: Result:='Const';
|
|
ctnGlobalProperty: Result:='Global Property';
|
|
ctnUseUnit: Result:='use unit';
|
|
|
|
ctnProperty: Result:='Property'; // can start with 'class property'
|
|
ctnMethodMap: Result:='Method Map';
|
|
|
|
ctnIdentifier: Result:='Identifier';
|
|
ctnOpenArrayType: Result:='Open Array Type';
|
|
ctnOfConstType: Result:='Of Const';
|
|
ctnRangedArrayType: Result:='Ranged Array Type';
|
|
ctnRecordType: Result:='Record Type';
|
|
ctnRecordCase: Result:='Record Case';
|
|
ctnRecordVariant: Result:='Record Variant';
|
|
ctnProcedureType: Result:='Procedure Type';
|
|
ctnSetType: Result:='Set Type';
|
|
ctnRangeType: Result:='Subrange Type';
|
|
ctnEnumerationType: Result:='Enumeration Type';
|
|
ctnEnumIdentifier: Result:='Enumeration Identifier';
|
|
ctnLabelType: Result:='Label Type';
|
|
ctnTypeType: Result:='''Type'' Type';
|
|
ctnFileType: Result:='File Type';
|
|
ctnPointerType: Result:='Pointer ^ Type';
|
|
ctnClassOfType: Result:='Class Of Type';
|
|
ctnVariantType: Result:='Variant Type';
|
|
ctnSpecialize: Result:='Specialize Type';
|
|
ctnSpecializeType: Result:='Specialize Typename';
|
|
ctnSpecializeParams: Result:='Specialize Parameterlist';
|
|
ctnGenericType: Result:='Generic Type';
|
|
ctnGenericName: Result:='Generic Type Name';
|
|
ctnGenericParams: Result:='Generic Type Params';
|
|
ctnGenericParameter: Result:='Generic Type Parameter';
|
|
ctnConstant: Result:='Constant';
|
|
|
|
ctnWithVariable: Result:='With Variable';
|
|
ctnWithStatement: Result:='With Statement';
|
|
ctnOnBlock: Result:='On Block';
|
|
ctnOnIdentifier: Result:='On Identifier';
|
|
ctnOnStatement: Result:='On Statement';
|
|
|
|
else
|
|
Result:='invalid descriptor ('+IntToStr(Desc)+')';
|
|
end;
|
|
end;
|
|
|
|
procedure WriteNodeExtTree(Tree: TAVLTree);
|
|
var
|
|
Node: TAVLTreeNode;
|
|
NodeExt: TCodeTreeNodeExtension;
|
|
begin
|
|
if Tree=nil then begin
|
|
DebugLn(['WriteNodeExtTree Tree=nil']);
|
|
exit;
|
|
end;
|
|
DebugLn(['WriteNodeExtTree ']);
|
|
Node:=Tree.FindLowest;
|
|
while Node<>nil do begin
|
|
NodeExt:=TCodeTreeNodeExtension(Node.Data);
|
|
if NodeExt=nil then
|
|
DebugLn([' NodeExt=nil'])
|
|
else
|
|
NodeExt.WriteDebugReport;
|
|
Node:=Tree.FindSuccessor(Node);
|
|
end;
|
|
end;
|
|
|
|
function FindCodeTreeNodeExt(Tree: TAVLTree; const Txt: string
|
|
): TCodeTreeNodeExtension;
|
|
var
|
|
AVLNode: TAVLTreeNode;
|
|
begin
|
|
AVLNode:=FindCodeTreeNodeExtAVLNode(Tree,Txt);
|
|
if AVLNode<>nil then
|
|
Result:=TCodeTreeNodeExtension(AVLNode.Data)
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function FindCodeTreeNodeExtAVLNode(Tree: TAVLTree; const Txt: string
|
|
): TAVLTreeNode;
|
|
begin
|
|
Result:=Tree.FindKey(@Txt,@CompareTxtWithCodeTreeNodeExt);
|
|
end;
|
|
|
|
function FindCodeTreeNodeExtWithIdentifier(Tree: TAVLTree; Identifier: PChar
|
|
): TCodeTreeNodeExtension;
|
|
var
|
|
AVLNode: TAVLTreeNode;
|
|
begin
|
|
AVLNode:=FindCodeTreeNodeExtAVLNodeWithIdentifier(Tree,Identifier);
|
|
if AVLNode<>nil then
|
|
Result:=TCodeTreeNodeExtension(AVLNode.Data)
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function FindCodeTreeNodeExtAVLNodeWithIdentifier(Tree: TAVLTree;
|
|
Identifier: PChar): TAVLTreeNode;
|
|
begin
|
|
Result:=Tree.FindKey(Identifier,@CompareIdentifierWithCodeTreeNodeExt);
|
|
end;
|
|
|
|
function CompareTxtWithCodeTreeNodeExt(p: Pointer; NodeData: pointer
|
|
): integer;
|
|
var
|
|
s: String;
|
|
NodeExt: TCodeTreeNodeExtension;
|
|
begin
|
|
NodeExt:=TCodeTreeNodeExtension(NodeData);
|
|
s:=PAnsistring(p)^;
|
|
Result:=CompareTextIgnoringSpace(s,NodeExt.Txt,false);
|
|
//debugln('CompareTxtWithCodeTreeNodeExt ',NodeExt.Txt,' ',s,' ',dbgs(Result));
|
|
end;
|
|
|
|
function CompareIdentifierWithCodeTreeNodeExt(p: Pointer; NodeData: pointer
|
|
): integer;
|
|
var
|
|
NodeExt: TCodeTreeNodeExtension;
|
|
begin
|
|
NodeExt:=TCodeTreeNodeExtension(NodeData);
|
|
Result:=CompareIdentifierPtrs(p,Pointer(NodeExt.Txt));
|
|
end;
|
|
|
|
function CompareCodeTreeNodeExt(NodeData1, NodeData2: pointer): integer;
|
|
var NodeExt1, NodeExt2: TCodeTreeNodeExtension;
|
|
begin
|
|
NodeExt1:=TCodeTreeNodeExtension(NodeData1);
|
|
NodeExt2:=TCodeTreeNodeExtension(NodeData2);
|
|
Result:=CompareTextIgnoringSpace(NodeExt1.Txt,NodeExt2.Txt,false);
|
|
end;
|
|
|
|
function CompareCodeTreeNodeExtWithPos(NodeData1, NodeData2: pointer): integer;
|
|
var NodeExt1Pos, NodeExt2Pos: integer;
|
|
begin
|
|
NodeExt1Pos:=TCodeTreeNodeExtension(NodeData1).Position;
|
|
NodeExt2Pos:=TCodeTreeNodeExtension(NodeData2).Position;
|
|
if NodeExt1Pos<NodeExt2Pos then
|
|
Result:=1
|
|
else if NodeExt1Pos>NodeExt2Pos then
|
|
Result:=-1
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function CompareCodeTreeNodeExtWithNodeStartPos(
|
|
NodeData1, NodeData2: pointer): integer;
|
|
var NodeExt1Pos, NodeExt2Pos: integer;
|
|
begin
|
|
NodeExt1Pos:=TCodeTreeNodeExtension(NodeData1).Node.StartPos;
|
|
NodeExt2Pos:=TCodeTreeNodeExtension(NodeData2).Node.StartPos;
|
|
if NodeExt1Pos<NodeExt2Pos then
|
|
Result:=1
|
|
else if NodeExt1Pos>NodeExt2Pos then
|
|
Result:=-1
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function CompareCodeTreeNodeExtWithNode(NodeData1, NodeData2: pointer): integer;
|
|
var
|
|
Node1: TCodeTreeNode;
|
|
Node2: TCodeTreeNode;
|
|
begin
|
|
Node1:=TCodeTreeNodeExtension(NodeData1).Node;
|
|
Node2:=TCodeTreeNodeExtension(NodeData2).Node;
|
|
if Pointer(Node1)>Pointer(Node2) then
|
|
Result:=1
|
|
else if Pointer(Node1)<Pointer(Node2) then
|
|
Result:=-1
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function ComparePointerWithCodeTreeNodeExtNode(p: Pointer; NodeExt: pointer
|
|
): integer;
|
|
var
|
|
Node: TCodeTreeNode;
|
|
begin
|
|
Node:=TCodeTreeNodeExtension(NodeExt).Node;
|
|
if p>Pointer(Node) then
|
|
Result:=1
|
|
else if p<Pointer(Node) then
|
|
Result:=-1
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function FindOwnerOfCodeTreeNode(ANode: TCodeTreeNode): TObject;
|
|
begin
|
|
if Assigned(OnFindOwnerOfCodeTreeNode) then
|
|
Result:=OnFindOwnerOfCodeTreeNode(ANode)
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
{ TCodeTreeNode }
|
|
|
|
constructor TCodeTreeNode.Create;
|
|
begin
|
|
StartPos:=-1;
|
|
EndPos:=-1;
|
|
end;
|
|
|
|
procedure TCodeTreeNode.Clear;
|
|
begin
|
|
Desc:=ctnNone;
|
|
SubDesc:=ctnsNone;
|
|
Parent:=nil;
|
|
NextBrother:=nil;
|
|
PriorBrother:=nil;
|
|
FirstChild:=nil;
|
|
LastChild:=nil;
|
|
StartPos:=-1;
|
|
EndPos:=-1;
|
|
Cache:=nil;
|
|
end;
|
|
|
|
function TCodeTreeNode.Next: TCodeTreeNode;
|
|
begin
|
|
if FirstChild<>nil then begin
|
|
Result:=FirstChild;
|
|
end else begin
|
|
Result:=Self;
|
|
while (Result<>nil) and (Result.NextBrother=nil) do
|
|
Result:=Result.Parent;
|
|
if Result<>nil then Result:=Result.NextBrother;
|
|
end;
|
|
end;
|
|
|
|
function TCodeTreeNode.NextSkipChilds: TCodeTreeNode;
|
|
begin
|
|
Result:=Self;
|
|
while (Result<>nil) and (Result.NextBrother=nil) do
|
|
Result:=Result.Parent;
|
|
if Result<>nil then Result:=Result.NextBrother;
|
|
end;
|
|
|
|
function TCodeTreeNode.Prior: TCodeTreeNode;
|
|
begin
|
|
if PriorBrother<>nil then begin
|
|
Result:=PriorBrother;
|
|
while Result.LastChild<>nil do
|
|
Result:=Result.LastChild;
|
|
end else
|
|
Result:=Parent;
|
|
end;
|
|
|
|
procedure TCodeTreeNode.ConsistencyCheck;
|
|
begin
|
|
if (EndPos>0) and (StartPos>EndPos) then
|
|
raise Exception.Create('');
|
|
if (Parent<>nil) then begin
|
|
if (PriorBrother=nil) and (Parent.FirstChild<>Self) then
|
|
raise Exception.Create('');
|
|
if (NextBrother=nil) and (Parent.LastChild<>Self) then
|
|
raise Exception.Create('');
|
|
end;
|
|
if (NextBrother<>nil) and (NextBrother.Parent<>Parent) then
|
|
raise Exception.Create('');
|
|
if (PriorBrother<>nil) and (PriorBrother.Parent<>Parent) then
|
|
raise Exception.Create('');
|
|
if (FirstChild<>nil) and (FirstChild.Parent<>Self) then
|
|
raise Exception.Create('');
|
|
if (FirstChild=nil) <> (LastChild=nil) then
|
|
raise Exception.Create('');
|
|
if (NextBrother<>nil) and (NextBrother.PriorBrother<>Self) then
|
|
raise Exception.Create('');
|
|
if (PriorBrother<>nil) and (PriorBrother.NextBrother<>Self) then
|
|
raise Exception.Create('');
|
|
if (FirstChild<>nil) then
|
|
FirstChild.ConsistencyCheck;
|
|
if NextBrother<>nil then
|
|
NextBrother.ConsistencyCheck;
|
|
end;
|
|
|
|
procedure TCodeTreeNode.WriteDebugReport(const Prefix: string;
|
|
WithChilds: boolean);
|
|
var
|
|
Node: TCodeTreeNode;
|
|
begin
|
|
DebugLn([Prefix,DescAsString,' Range=',StartPos,'..',EndPos,' Cache=',DbgSName(Cache)]);
|
|
if WithChilds then begin
|
|
Node:=FirstChild;
|
|
while Node<>nil do begin
|
|
Node.WriteDebugReport(Prefix+' ',true);
|
|
Node:=Node.NextBrother;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCodeTreeNode.HasAsParent(Node: TCodeTreeNode): boolean;
|
|
var CurNode: TCodeTreeNode;
|
|
begin
|
|
Result:=false;
|
|
if Node=nil then exit;
|
|
CurNode:=Parent;
|
|
while (CurNode<>nil) do begin
|
|
if CurNode=Node then begin
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
CurNode:=CurNode.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TCodeTreeNode.HasAsChild(Node: TCodeTreeNode): boolean;
|
|
begin
|
|
Result:=false;
|
|
if Node=nil then exit;
|
|
Result:=Node.HasAsParent(Self);
|
|
end;
|
|
|
|
function TCodeTreeNode.HasParentOfType(ParentDesc: TCodeTreeNodeDesc): boolean;
|
|
var ANode: TCodeTreeNode;
|
|
begin
|
|
ANode:=Parent;
|
|
while (ANode<>nil) and (ANode.Desc<>ParentDesc) do
|
|
ANode:=ANode.Parent;
|
|
Result:=ANode<>nil;
|
|
end;
|
|
|
|
function TCodeTreeNode.HasAsRoot(RootNode: TCodeTreeNode): boolean;
|
|
begin
|
|
Result:=(RootNode<>nil) and (RootNode=GetRoot);
|
|
end;
|
|
|
|
function TCodeTreeNode.GetNodeOfType(ADesc: TCodeTreeNodeDesc
|
|
): TCodeTreeNode;
|
|
begin
|
|
Result:=Self;
|
|
while (Result<>nil) and (Result.Desc<>ADesc) do
|
|
Result:=Result.Parent;
|
|
end;
|
|
|
|
function TCodeTreeNode.GetNodeOfTypes(Descriptors: array of TCodeTreeNodeDesc
|
|
): TCodeTreeNode;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=Self;
|
|
while (Result<>nil) do begin
|
|
for i:=Low(Descriptors) to High(Descriptors) do
|
|
if Result.Desc=Descriptors[i] then exit;
|
|
Result:=Result.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TCodeTreeNode.GetFindContextParent: TCodeTreeNode;
|
|
begin
|
|
Result:=Parent;
|
|
while (Result<>nil) and (not (Result.Desc in AllFindContextDescs)) do
|
|
Result:=Result.Parent;
|
|
end;
|
|
|
|
function TCodeTreeNode.GetLevel: integer;
|
|
var ANode: TCodeTreeNode;
|
|
begin
|
|
Result:=0;
|
|
ANode:=Parent;
|
|
while ANode<>nil do begin
|
|
inc(Result);
|
|
ANode:=ANode.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TCodeTreeNode.DescAsString: string;
|
|
begin
|
|
if Self=nil then
|
|
Result:='nil'
|
|
else
|
|
Result:=NodeDescriptionAsString(Desc);
|
|
end;
|
|
|
|
function TCodeTreeNode.GetRoot: TCodeTreeNode;
|
|
begin
|
|
Result:=Self;
|
|
while (Result.Parent<>nil) do Result:=Result.Parent;
|
|
while (Result.PriorBrother<>nil) do Result:=Result.PriorBrother;
|
|
end;
|
|
|
|
function TCodeTreeNode.ChildCount: integer;
|
|
var
|
|
Node: TCodeTreeNode;
|
|
begin
|
|
Result:=0;
|
|
Node:=FirstChild;
|
|
while Node<>nil do begin
|
|
inc(Result);
|
|
Node:=Node.NextBrother;
|
|
end;
|
|
end;
|
|
|
|
function TCodeTreeNode.FindOwner: TObject;
|
|
begin
|
|
Result:=FindOwnerOfCodeTreeNode(Self);
|
|
end;
|
|
|
|
{ TCodeTree }
|
|
|
|
constructor TCodeTree.Create;
|
|
begin
|
|
Root:=nil;
|
|
FNodeCount:=0;
|
|
end;
|
|
|
|
destructor TCodeTree.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TCodeTree.Clear;
|
|
var ANode: TCodeTreeNode;
|
|
begin
|
|
while Root<>nil do begin
|
|
ANode:=Root;
|
|
Root:=ANode.NextBrother;
|
|
DeleteNode(ANode);
|
|
end;
|
|
end;
|
|
|
|
procedure TCodeTree.DeleteNode(ANode: TCodeTreeNode);
|
|
begin
|
|
if ANode=nil then exit;
|
|
while (ANode.FirstChild<>nil) do DeleteNode(ANode.FirstChild);
|
|
with ANode do begin
|
|
if (Parent<>nil) then begin
|
|
if (Parent.FirstChild=ANode) then
|
|
Parent.FirstChild:=NextBrother;
|
|
if (Parent.LastChild=ANode) then
|
|
Parent.LastChild:=PriorBrother;
|
|
Parent:=nil;
|
|
end;
|
|
if NextBrother<>nil then NextBrother.PriorBrother:=PriorBrother;
|
|
if PriorBrother<>nil then PriorBrother.NextBrother:=NextBrother;
|
|
NextBrother:=nil;
|
|
PriorBrother:=nil;
|
|
end;
|
|
if ANode=Root then Root:=nil;
|
|
dec(FNodeCount);
|
|
NodeMemManager.DisposeNode(ANode);
|
|
end;
|
|
|
|
procedure TCodeTree.AddNodeAsLastChild(ParentNode, ANode: TCodeTreeNode);
|
|
var TopNode: TCodeTreeNode;
|
|
begin
|
|
ANode.Parent:=ParentNode;
|
|
if Root=nil then begin
|
|
// set as root
|
|
Root:=ANode;
|
|
while Root.Parent<>nil do Root:=Root.Parent;
|
|
end else if ParentNode<>nil then begin
|
|
if ParentNode.FirstChild=nil then begin
|
|
// add as first child
|
|
ParentNode.FirstChild:=ANode;
|
|
ParentNode.LastChild:=ANode;
|
|
end else begin
|
|
// add as last child
|
|
ANode.PriorBrother:=ParentNode.LastChild;
|
|
ParentNode.LastChild:=ANode;
|
|
if ANode.PriorBrother<>nil then ANode.PriorBrother.NextBrother:=ANode;
|
|
end;
|
|
end else begin
|
|
// add as last brother of top nodes
|
|
TopNode:=Root;
|
|
while (TopNode.NextBrother<>nil) do TopNode:=TopNode.NextBrother;
|
|
ANode.PriorBrother:=TopNode;
|
|
ANode.PriorBrother.NextBrother:=ANode;
|
|
end;
|
|
inc(FNodeCount);
|
|
end;
|
|
|
|
procedure TCodeTree.AddNodeInFrontOf(NextBrotherNode, ANode: TCodeTreeNode);
|
|
begin
|
|
ANode.Parent:=NextBrotherNode.Parent;
|
|
ANode.NextBrother:=NextBrotherNode;
|
|
ANode.PriorBrother:=NextBrotherNode.PriorBrother;
|
|
NextBrotherNode.PriorBrother:=ANode;
|
|
if ANode.PriorBrother<>nil then
|
|
ANode.PriorBrother.NextBrother:=ANode;
|
|
end;
|
|
|
|
function TCodeTree.FindFirstPosition: integer;
|
|
begin
|
|
Result:=-1;
|
|
if Root=nil then exit;
|
|
Result:=Root.StartPos;
|
|
end;
|
|
|
|
function TCodeTree.FindLastPosition: integer;
|
|
var
|
|
ANode: TCodeTreeNode;
|
|
begin
|
|
Result:=-1;
|
|
if Root=nil then exit;
|
|
ANode:=Root;
|
|
while (ANode.NextBrother<>nil) do ANode:=ANode.NextBrother;
|
|
//debugln('TCodeTree.FindLastPosition A ',Anode.DescAsString,' ANode.StartPos=',dbgs(ANode.StartPos),' ANode.EndPos=',dbgs(ANode.EndPos));
|
|
Result:=ANode.EndPos;
|
|
end;
|
|
|
|
function TCodeTree.ContainsNode(ANode: TCodeTreeNode): boolean;
|
|
begin
|
|
if ANode=nil then exit(false);
|
|
while ANode.Parent<>nil do ANode:=ANode.Parent;
|
|
while ANode.PriorBrother<>nil do ANode:=ANode.PriorBrother;
|
|
Result:=ANode=Root;
|
|
end;
|
|
|
|
procedure TCodeTree.ConsistencyCheck;
|
|
var RealNodeCount: integer;
|
|
|
|
procedure CountNodes(ANode: TCodeTreeNode);
|
|
begin
|
|
if ANode=nil then exit;
|
|
inc(RealNodeCount);
|
|
CountNodes(ANode.FirstChild);
|
|
CountNodes(ANode.NextBrother);
|
|
end;
|
|
|
|
begin
|
|
if Root<>nil then begin
|
|
if Root.Parent<>nil then
|
|
raise Exception.Create('');
|
|
Root.ConsistencyCheck;
|
|
end;
|
|
RealNodeCount:=0;
|
|
CountNodes(Root);
|
|
if RealNodeCount<>FNodeCount then
|
|
raise Exception.Create('');
|
|
end;
|
|
|
|
procedure TCodeTree.WriteDebugReport(WithChilds: boolean);
|
|
begin
|
|
DebugLn('[TCodeTree.WriteDebugReport] Root=',dbgs(Root<>nil));
|
|
if Root<>nil then
|
|
Root.WriteDebugReport(' ',true);
|
|
end;
|
|
|
|
{ TCodeTreeNodeExtension }
|
|
|
|
procedure TCodeTreeNodeExtension.Clear;
|
|
begin
|
|
Next:=nil;
|
|
Txt:='';
|
|
ExtTxt1:='';
|
|
ExtTxt2:='';
|
|
ExtTxt3:='';
|
|
Node:=nil;
|
|
Position:=-1;
|
|
Data:=nil;
|
|
Flags:=0;
|
|
end;
|
|
|
|
constructor TCodeTreeNodeExtension.Create;
|
|
begin
|
|
Position:=-1;
|
|
end;
|
|
|
|
function TCodeTreeNodeExtension.ConsistencyCheck: integer;
|
|
// 0 = ok
|
|
begin
|
|
Result:=0;
|
|
end;
|
|
|
|
procedure TCodeTreeNodeExtension.WriteDebugReport;
|
|
begin
|
|
// nothing special
|
|
DbgOut(' ');
|
|
if Node<>nil then
|
|
DbgOut('Node=',NodeDescriptionAsString(Node.Desc))
|
|
else
|
|
DbgOut('Node=nil');
|
|
DbgOut(' Position=',dbgs(Position),' Txt="'+Txt+'" ExtTxt1="'+ExtTxt1+'" ExtTxt2="'+ExtTxt2+'" ExtTxt3="'+ExtTxt3+'"');
|
|
debugln;
|
|
end;
|
|
|
|
function TCodeTreeNodeExtension.CalcMemSize: PtrUInt;
|
|
begin
|
|
Result:=PtrUInt(InstanceSize)
|
|
+MemSizeString(Txt)
|
|
+MemSizeString(ExtTxt1)
|
|
+MemSizeString(ExtTxt2)
|
|
+MemSizeString(ExtTxt3);
|
|
end;
|
|
|
|
{ TCodeTreeNodeMemManager }
|
|
|
|
function TCodeTreeNodeMemManager.NewNode: TCodeTreeNode;
|
|
begin
|
|
if FFirstFree<>nil then begin
|
|
// take from free list
|
|
Result:=TCodeTreeNode(FFirstFree);
|
|
TCodeTreeNode(FFirstFree):=Result.NextBrother;
|
|
Result.NextBrother:=nil;
|
|
dec(FFreeCount);
|
|
end else begin
|
|
// free list empty -> create new node
|
|
Result:=TCodeTreeNode.Create;
|
|
{$IFDEF DebugCTMemManager}
|
|
inc(FAllocatedCount);
|
|
{$ENDIF}
|
|
end;
|
|
inc(FCount);
|
|
end;
|
|
|
|
procedure TCodeTreeNodeMemManager.DisposeNode(ANode: TCodeTreeNode);
|
|
begin
|
|
if (FFreeCount<FMinFree) or (FFreeCount<((FCount shr 3)*FMaxFreeRatio)) then
|
|
begin
|
|
// add ANode to Free list
|
|
ANode.Clear;
|
|
ANode.NextBrother:=TCodeTreeNode(FFirstFree);
|
|
TCodeTreeNode(FFirstFree):=ANode;
|
|
inc(FFreeCount);
|
|
end else begin
|
|
// free list full -> free the ANode
|
|
ANode.Clear;// clear the node, so that dangling pointers can be spotted early
|
|
ANode.Free;
|
|
{$IFDEF DebugCTMemManager}
|
|
inc(FFreedCount);
|
|
{$ENDIF}
|
|
end;
|
|
dec(FCount);
|
|
end;
|
|
|
|
procedure TCodeTreeNodeMemManager.FreeFirstItem;
|
|
var ANode: TCodeTreeNode;
|
|
begin
|
|
ANode:=TCodeTreeNode(FFirstFree);
|
|
TCodeTreeNode(FFirstFree):=ANode.NextBrother;
|
|
ANode.Free;
|
|
end;
|
|
|
|
{ TCodeTreeNodeExtMemManager }
|
|
|
|
function TCodeTreeNodeExtMemManager.NewNode: TCodeTreeNodeExtension;
|
|
begin
|
|
if FFirstFree<>nil then begin
|
|
// take from free list
|
|
Result:=TCodeTreeNodeExtension(FFirstFree);
|
|
TCodeTreeNodeExtension(FFirstFree):=Result.Next;
|
|
Result.Next:=nil;
|
|
end else begin
|
|
// free list empty -> create new node
|
|
Result:=TCodeTreeNodeExtension.Create;
|
|
end;
|
|
inc(FCount);
|
|
end;
|
|
|
|
procedure TCodeTreeNodeExtMemManager.DisposeNode(ANode: TCodeTreeNodeExtension);
|
|
begin
|
|
if (FFreeCount<FMinFree) or (FFreeCount<((FCount shr 3)*FMaxFreeRatio)) then
|
|
begin
|
|
// add ANode to Free list
|
|
ANode.Clear;
|
|
ANode.Next:=TCodeTreeNodeExtension(FFirstFree);
|
|
TCodeTreeNodeExtension(FFirstFree):=ANode;
|
|
inc(FFreeCount);
|
|
end else begin
|
|
// free list full -> free the ANode
|
|
ANode.Free;
|
|
end;
|
|
dec(FCount);
|
|
end;
|
|
|
|
procedure TCodeTreeNodeExtMemManager.DisposeAVLTree(TheTree: TAVLTree);
|
|
var ANode: TAVLTreeNode;
|
|
begin
|
|
if TheTree=nil then exit;
|
|
ANode:=TheTree.FindLowest;
|
|
while ANode<>nil do begin
|
|
DisposeNode(TCodeTreeNodeExtension(ANode.Data));
|
|
ANode:=TheTree.FindSuccessor(ANode);
|
|
end;
|
|
TheTree.Free;
|
|
end;
|
|
|
|
procedure TCodeTreeNodeExtMemManager.FreeFirstItem;
|
|
var ANode: TCodeTreeNodeExtension;
|
|
begin
|
|
ANode:=TCodeTreeNodeExtension(FFirstFree);
|
|
TCodeTreeNodeExtension(FFirstFree):=ANode.Next;
|
|
ANode.Free;
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
procedure InternalInit;
|
|
begin
|
|
NodeMemManager:=TCodeTreeNodeMemManager.Create;
|
|
NodeExtMemManager:=TCodeTreeNodeExtMemManager.Create;
|
|
end;
|
|
|
|
procedure InternalFinal;
|
|
begin
|
|
FreeAndNil(NodeExtMemManager);
|
|
FreeAndNil(NodeMemManager);
|
|
end;
|
|
|
|
|
|
initialization
|
|
InternalInit;
|
|
|
|
finalization
|
|
{$IFDEF CTDEBUG}
|
|
DebugLn('codetree.pp - finalization');
|
|
{$ENDIF}
|
|
{$IFDEF MEM_CHECK}
|
|
CheckHeap(IntToStr(MemCheck_GetMem_Cnt));
|
|
{$ENDIF}
|
|
InternalFinal;
|
|
|
|
end.
|
|
|