mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-04 14:24:25 +02:00
676 lines
19 KiB
ObjectPascal
676 lines
19 KiB
ObjectPascal
unit JSClassXMLRead;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileProcs, OtherIdentifierTree, XMLRead, XMLCfg, DOM,
|
|
avl_tree;
|
|
|
|
type
|
|
TJSIdentifier = class(TOtherIdentifierTreeNode)
|
|
public
|
|
JSName: string;
|
|
PascalName: string;
|
|
end;
|
|
|
|
TJSIUnresolvedIdentifier = class(TJSIdentifier)
|
|
public
|
|
Resolved: TJSIdentifier;
|
|
end;
|
|
|
|
TJSIAlias = class(TJSIdentifier)
|
|
public
|
|
PointsTo: TJSIdentifier;
|
|
end;
|
|
|
|
TJSIClass = class;
|
|
|
|
TJSIParameter = class(TJSIdentifier)
|
|
public
|
|
Typ: TJSIdentifier;
|
|
Optional: boolean;
|
|
end;
|
|
|
|
TJSIMethodFlag = (
|
|
jsimStatic,
|
|
jsimOverload
|
|
);
|
|
TJSIMethodFlags = set of TJSIMethodFlag;
|
|
|
|
{ TJSIMethod }
|
|
|
|
TJSIMethod = class(TJSIdentifier)
|
|
public
|
|
Flags: TJSIMethodFlags;
|
|
JSIClass: TJSIClass;
|
|
Params: TFPList; // list of TJSIParameter
|
|
ReturnType: TJSIdentifier;
|
|
destructor Destroy; override;
|
|
procedure ClearParams;
|
|
procedure AddParameter(aParam: TJSIParameter);
|
|
end;
|
|
|
|
TJSIPropertyFlag = (
|
|
jsipEnum,
|
|
jsipConfig,
|
|
jsipStatic,
|
|
jsipDefault
|
|
);
|
|
TJSIPropertyFlags = set of TJSIPropertyFlag;
|
|
|
|
TJSIProperty = class(TJSIdentifier)
|
|
public
|
|
Flags: TJSIPropertyFlags;
|
|
Typ: TJSIdentifier;
|
|
end;
|
|
|
|
TJSIClassFlag = (
|
|
jsicAutoCreated
|
|
);
|
|
TJSIClassFlags = set of TJSIClassFlag;
|
|
|
|
{ TJSIClass }
|
|
|
|
TJSIClass = class(TJSIdentifier)
|
|
public
|
|
Flags: TJSIClassFlags;
|
|
ParentClass: TJSIdentifier;
|
|
Unit_name: TJSIdentifier;
|
|
Simplename: TJSIdentifier;
|
|
Methods: TFPList; // list of TJSIMethod
|
|
Properties: TFPList; // list TJSIProperty
|
|
Classes: TFPList; // list of TJSIClass
|
|
destructor Destroy; override;
|
|
procedure ClearMethods;
|
|
procedure ClearProperties;
|
|
procedure ClearClasses;
|
|
function FindIdentifier(const AJSName: string): TJSIdentifier;
|
|
procedure AddClass(AClass: TJSIClass);
|
|
procedure AddMethod(AMethod: TJSIMethod);
|
|
procedure AddProperty(AProperty: TJSIProperty);
|
|
end;
|
|
|
|
{ TJavascriptIdentifierTree }
|
|
|
|
TJavascriptIdentifierTree = class(TOtherIdentifierTree)
|
|
private
|
|
function FindNode(Doc: TXMLDocument; const APath: String; PathHasValue: boolean): TDomNode;
|
|
function Escape(const s: String): String;
|
|
procedure ReadExtJSNodes(Node: TDOMNode);
|
|
procedure ReadExtJSUnits(UnitsNode: TDOMNode);
|
|
procedure ReadExtJSClasses(ClassesNode: TDOMNode);
|
|
procedure ReadExtJSMethods(ClassNode: TDOMNode; JSIClass: TJSIClass);
|
|
procedure ReadExtJSProperties(ClassNode: TDOMNode; JSIClass: TJSIClass);
|
|
function CreateClass(const Path: string; CreateLast: boolean): TJSIClass;
|
|
function CreateAlias(const Path: string): TJSIAlias;
|
|
function FindGlobal(const aJSName: string): TAVLTreeNode;
|
|
function CreateUnresolved(const aPath: string): TJSIUnresolvedIdentifier;
|
|
public
|
|
Globals: TAVLTree;
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure LoadFromFile(Filename: string);
|
|
procedure ClearGlobals;
|
|
end;
|
|
|
|
function CompareJSIdentifiers(Data1, Data2: Pointer): integer;
|
|
function CompareJSNameWithJSIdentifier(Key, Data: Pointer): integer;
|
|
function IsValidJSName(const Name: string): boolean;
|
|
|
|
implementation
|
|
|
|
function CompareJSIdentifiers(Data1, Data2: Pointer): integer;
|
|
var
|
|
Ident1: TJSIdentifier absolute Data1;
|
|
Ident2: TJSIdentifier absolute Data2;
|
|
begin
|
|
Result:=CompareStr(Ident1.JSName,Ident2.JSName);
|
|
end;
|
|
|
|
function CompareJSNameWithJSIdentifier(Key, Data: Pointer): integer;
|
|
var
|
|
Ident: TJSIdentifier absolute Data;
|
|
s: String;
|
|
begin
|
|
s:=AnsiString(Key);
|
|
Result:=CompareStr(s,Ident.JSName);
|
|
end;
|
|
|
|
function IsValidJSName(const Name: string): boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=false;
|
|
if Name='' then exit;
|
|
if length(Name)>255 then exit;
|
|
if not (Name[1] in ['a'..'z','A'..'Z','_']) then exit;
|
|
for i:=1 to Length(Name) do
|
|
if not (Name[i] in ['a'..'z','A'..'Z','_','0'..'9']) then exit;
|
|
Result:=true;
|
|
end;
|
|
|
|
{ TJavascriptIdentifierTree }
|
|
|
|
function TJavascriptIdentifierTree.FindNode(Doc: TXMLDocument;
|
|
const APath: String; PathHasValue: boolean): TDomNode;
|
|
var
|
|
NodePath: String;
|
|
StartPos, EndPos: integer;
|
|
PathLen: integer;
|
|
begin
|
|
Result := Doc.DocumentElement;
|
|
debugln(['TJavascriptIdentifierTree.FindNode ',Result.NodeName]);
|
|
PathLen := Length(APath);
|
|
StartPos := 1;
|
|
while Assigned(Result) do
|
|
begin
|
|
EndPos := StartPos;
|
|
while (EndPos <= PathLen) and (APath[EndPos] <> '/') do
|
|
Inc(EndPos);
|
|
if (EndPos > PathLen) and PathHasValue then
|
|
exit;
|
|
if EndPos = StartPos then
|
|
break;
|
|
SetLength(NodePath, EndPos - StartPos);
|
|
Move(APath[StartPos], NodePath[1], Length(NodePath));
|
|
NodePath:=Escape(NodePath);
|
|
debugln(['TJavascriptIdentifierTree.FindNode ',NodePath]);
|
|
Result := Result.FindNode(NodePath);
|
|
StartPos := EndPos + 1;
|
|
if StartPos > PathLen then
|
|
exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TJavascriptIdentifierTree.Escape(const s: String): String;
|
|
const
|
|
AllowedChars = ['A'..'Z', 'a'..'z', '0'..'9', '.', '-', '_'];
|
|
var
|
|
EscapingNecessary: Boolean;
|
|
i: Integer;
|
|
begin
|
|
if Length(s) < 1 then
|
|
raise EXMLConfigError.Create(SMissingPathName);
|
|
|
|
if not (s[1] in ['A'..'Z', 'a'..'z', '_']) then
|
|
EscapingNecessary := True
|
|
else
|
|
begin
|
|
EscapingNecessary := False;
|
|
for i := 2 to Length(s) do
|
|
if not (s[i] in AllowedChars) then
|
|
begin
|
|
EscapingNecessary := True;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if EscapingNecessary then
|
|
begin
|
|
Result := '_';
|
|
for i := 1 to Length(s) do
|
|
if s[i] in (AllowedChars - ['_']) then
|
|
Result := Result + s[i]
|
|
else
|
|
Result := Result + '_' + IntToHex(Ord(s[i]), 2);
|
|
end
|
|
else // No escaping necessary
|
|
Result := s;
|
|
end;
|
|
|
|
procedure TJavascriptIdentifierTree.ReadExtJSNodes(Node: TDOMNode);
|
|
var
|
|
UnitsNode: TDOMNode;
|
|
ClassesNode: TDOMNode;
|
|
begin
|
|
debugln(['TJavascriptIdentifierTree.ReadExtJSClasses ',DbgSName(Node)]);
|
|
|
|
UnitsNode:=Node.FindNode('units');
|
|
if UnitsNode=nil then begin
|
|
debugln(['TJavascriptIdentifierTree.ReadExtJSClasses no units found']);
|
|
exit;
|
|
end;
|
|
ReadExtJSUnits(UnitsNode);
|
|
|
|
ClassesNode:=Node.FindNode('classes');
|
|
if UnitsNode=nil then begin
|
|
debugln(['TJavascriptIdentifierTree.ReadExtJSClasses no classes found']);
|
|
exit;
|
|
end;
|
|
ReadExtJSClasses(ClassesNode);
|
|
end;
|
|
|
|
procedure TJavascriptIdentifierTree.ReadExtJSUnits(UnitsNode: TDOMNode);
|
|
var
|
|
Node: TDOMNode;
|
|
ClassesNode: TDOMNode;
|
|
ClassNode: TDOMNode;
|
|
CurUnitName, PascalClassname: widestring;
|
|
begin
|
|
Node:=UnitsNode.FirstChild;
|
|
while Node<>nil do begin
|
|
if (Node.NodeName='unit') and (Node is TDOMElement) then begin
|
|
CurUnitName:=TDOMElement(Node).GetAttribute('name');
|
|
ClassesNode:=Node.FindNode('classes');
|
|
if (ClassesNode<>nil) and (CurUnitName<>'') then begin
|
|
ClassNode:=ClassesNode.FirstChild;
|
|
while ClassNode<>nil do begin
|
|
if ClassNode.NodeName='class' then begin
|
|
if ClassNode is TDOMElement then begin
|
|
PascalClassname:=TDOMElement(ClassNode).GetAttribute('name');
|
|
if PascalClassname<>'' then ;
|
|
//debugln(['TJavascriptIdentifierTree.ReadExtJSUnits ',CurUnitName,' ',PascalClassname]);
|
|
end;
|
|
end;
|
|
ClassNode:=ClassNode.NextSibling;
|
|
end;
|
|
end;
|
|
end;
|
|
Node:=Node.NextSibling;
|
|
end;
|
|
end;
|
|
|
|
procedure TJavascriptIdentifierTree.ReadExtJSClasses(ClassesNode: TDOMNode);
|
|
var
|
|
Node: TDOMNode;
|
|
ClassNode: TDOMElement;
|
|
NewClass: TJSIClass;
|
|
JSName: WideString;
|
|
SimpleName: WideString;
|
|
Alias: TJSIAlias;
|
|
begin
|
|
Node:=ClassesNode.FirstChild;
|
|
while Node<>nil do begin
|
|
if (Node.NodeName='class') and (Node is TDOMElement) then begin
|
|
ClassNode:=TDOMElement(Node);
|
|
JSName:=ClassNode.GetAttribute('jsname');
|
|
if JSName<>'' then begin
|
|
if JSName='Object' then begin
|
|
debugln(['TJavascriptIdentifierTree.ReadExtJSClasses SKIPPING jsname=Object pasname=',ClassNode.GetAttribute('name')]);
|
|
end else begin
|
|
debugln(['TJavascriptIdentifierTree.ReadExtJSClasses class=',JSName]);
|
|
// create new class
|
|
NewClass:=CreateClass(JSName,true);
|
|
if not (jsicAutoCreated in NewClass.Flags) then
|
|
raise Exception.Create('class redefined: '+JSName);
|
|
Exclude(NewClass.Flags,jsicAutoCreated);
|
|
// pascalname
|
|
NewClass.PascalName:=ClassNode.GetAttribute('name');
|
|
// simplename
|
|
SimpleName:=ClassNode.GetAttribute('simplename');
|
|
if (SimpleName<>'') and (SimpleName<>JSName) then begin
|
|
Alias:=CreateAlias(SimpleName);
|
|
if (Alias.PointsTo<>nil) and (Alias.PointsTo<>NewClass) then
|
|
raise Exception.Create('class simplename redefined: '+JSName+' '+SimpleName);
|
|
NewClass.Simplename:=Alias;
|
|
end;
|
|
// methods
|
|
ReadExtJSMethods(ClassNode,NewClass);
|
|
// properties
|
|
ReadExtJSProperties(ClassNode,NewClass);
|
|
end;
|
|
end;
|
|
end;
|
|
Node:=Node.NextSibling;
|
|
end;
|
|
end;
|
|
|
|
procedure TJavascriptIdentifierTree.ReadExtJSMethods(ClassNode: TDOMNode;
|
|
JSIClass: TJSIClass);
|
|
var
|
|
MethodsNode: TDOMNode;
|
|
Node: TDOMNode;
|
|
MethodNode: TDOMElement;
|
|
JSName: WideString;
|
|
NewMethod: TJSIMethod;
|
|
ParamsNode: TDOMNode;
|
|
SubNode: TDOMNode;
|
|
NewParam: TJSIParameter;
|
|
ParamNode: TDOMElement;
|
|
ParamJSName: WideString;
|
|
ReturnType: Widestring;
|
|
begin
|
|
MethodsNode:=ClassNode.FindNode('methods');
|
|
if MethodsNode=nil then exit;
|
|
Node:=MethodsNode.FirstChild;
|
|
while Node<>nil do begin
|
|
if (Node.NodeName='method') and (Node is TDOMElement) then begin
|
|
MethodNode:=TDOMElement(Node);
|
|
JSName:=MethodNode.GetAttribute('jsname');
|
|
if copy(JSName,1,length(JSIClass.JSName)+1)=JSIClass.JSName+'.' then
|
|
JSName:=copy(JSName,length(JSIClass.JSName)+2,length(JSName));
|
|
if not IsValidJSName(JSName) then
|
|
raise Exception.Create('invalid method name '+JSName);
|
|
NewMethod:=TJSIMethod.Create;
|
|
NewMethod.JSName:=JSName;
|
|
JSIClass.AddMethod(NewMethod);
|
|
NewMethod.PascalName:=MethodNode.GetAttribute('name');
|
|
if MethodNode.GetAttribute('static')='1' then
|
|
Include(NewMethod.Flags,jsimStatic);
|
|
if MethodNode.GetAttribute('overload')='1' then
|
|
Include(NewMethod.Flags,jsimOverload);
|
|
// return type
|
|
ReturnType:=MethodNode.GetAttribute('return');
|
|
if ReturnType<>'' then
|
|
NewMethod.ReturnType:=CreateUnresolved(ReturnType);
|
|
// parameters
|
|
ParamsNode:=MethodNode.FindNode('params');
|
|
if ParamsNode<>nil then begin
|
|
SubNode:=ParamsNode.FirstChild;
|
|
while SubNode<>nil do begin
|
|
if (SubNode is TDOMElement) and (SubNode.NodeName='param') then begin
|
|
ParamNode:=TDOMElement(SubNode);
|
|
ParamJSName:=ParamNode.GetAttribute('name');
|
|
if not IsValidJSName(ParamJSName) then
|
|
raise Exception.Create('invalid param name '+ParamJSName);
|
|
NewParam:=TJSIParameter.Create;
|
|
NewParam.JSName:=ParamJSName;
|
|
NewParam.PascalName:=ParamJSName;
|
|
NewParam.Optional:=ParamNode.GetAttribute('optional')='1';
|
|
NewParam.Typ:=CreateUnresolved(ParamNode.GetAttribute('type'));
|
|
NewMethod.AddParameter(NewParam);
|
|
end;
|
|
SubNode:=SubNode.NextSibling;
|
|
end;
|
|
end;
|
|
end;
|
|
Node:=Node.NextSibling;
|
|
end;
|
|
end;
|
|
|
|
procedure TJavascriptIdentifierTree.ReadExtJSProperties(ClassNode: TDOMNode;
|
|
JSIClass: TJSIClass);
|
|
var
|
|
PropertiesNode: TDOMNode;
|
|
PropertyNode: TDOMElement;
|
|
PropertyJSName: WideString;
|
|
NewProperty: TJSIProperty;
|
|
Node: TDOMNode;
|
|
TypeName: WideString;
|
|
begin
|
|
// properties
|
|
PropertiesNode:=ClassNode.FindNode('properties');
|
|
if PropertiesNode=nil then exit;
|
|
Node:=PropertiesNode.FirstChild;
|
|
while Node<>nil do begin
|
|
if (Node is TDOMElement) and (Node.NodeName='property') then begin
|
|
PropertyNode:=TDOMElement(Node);
|
|
PropertyJSName:=PropertyNode.GetAttribute('jsname');
|
|
if not IsValidJSName(PropertyJSName) then
|
|
raise Exception.Create('invalid property name '+PropertyJSName);
|
|
NewProperty:=TJSIProperty.Create;
|
|
NewProperty.JSName:=PropertyJSName;
|
|
NewProperty.PascalName:=PropertyNode.GetAttribute('name');
|
|
if PropertyNode.GetAttribute('enum')='1' then
|
|
Include(NewProperty.Flags,jsipEnum);
|
|
if PropertyNode.GetAttribute('config')='1' then
|
|
Include(NewProperty.Flags,jsipConfig);
|
|
if PropertyNode.GetAttribute('static')='1' then
|
|
Include(NewProperty.Flags,jsipStatic);
|
|
if PropertyNode.GetAttribute('default')='1' then
|
|
Include(NewProperty.Flags,jsipDefault);
|
|
TypeName:=PropertyNode.GetAttribute('type');
|
|
if (jsipEnum in NewProperty.Flags) and (TypeName[1]='(') then
|
|
TypeName:='';
|
|
if TypeName<>'' then
|
|
NewProperty.Typ:=CreateUnresolved(TypeName);
|
|
JSIClass.AddProperty(NewProperty);
|
|
end;
|
|
Node:=Node.NextSibling;
|
|
end;
|
|
end;
|
|
|
|
function TJavascriptIdentifierTree.CreateClass(const Path: string; CreateLast: boolean
|
|
): TJSIClass;
|
|
var
|
|
p: Integer;
|
|
StartPos: Integer;
|
|
AName: String;
|
|
AVLNode: TAVLTreeNode;
|
|
Identifier: TJSIdentifier;
|
|
Parent: TJSIClass;
|
|
IsLast: Boolean;
|
|
PropType: TJSIdentifier;
|
|
begin
|
|
Result:=nil;
|
|
p:=1;
|
|
repeat
|
|
StartPos:=p;
|
|
while (p<=length(Path)) and (Path[p]<>'.') do inc(p);
|
|
AName:=copy(Path,StartPos,p-StartPos);
|
|
if not IsValidJSName(AName) then
|
|
raise Exception.Create('invalid javascript class path: '+Path);
|
|
IsLast:=p>Length(Path);
|
|
if IsLast and not CreateLast then exit;
|
|
// search class
|
|
if Result=nil then begin
|
|
AVLNode:=FindGlobal(AName);
|
|
if AVLNode=nil then begin
|
|
// create new global class
|
|
debugln(['TJavascriptIdentifierTree.CreateClass new global class: ',AName]);
|
|
Result:=TJSIClass.Create;
|
|
Include(Result.Flags,jsicAutoCreated);
|
|
Result.JSName:=AName;
|
|
Globals.Add(Result);
|
|
end else begin
|
|
// class already exists
|
|
if not (TObject(AVLNode.Data) is TJSIClass) then
|
|
raise Exception.Create('path is not class: '+AName);
|
|
Result:=TJSIClass(AVLNode.Data);
|
|
end;
|
|
end else begin
|
|
Identifier:=Result.FindIdentifier(AName);
|
|
if Identifier=nil then begin
|
|
// create new sub class
|
|
debugln(['TJavascriptIdentifierTree.CreateClass new sub class: ',AName,' of ',Result.JSName]);
|
|
Parent:=Result;
|
|
Result:=TJSIClass.Create;
|
|
Include(Result.Flags,jsicAutoCreated);
|
|
Result.JSName:=AName;
|
|
Result.ParentClass:=Parent;
|
|
Parent.AddClass(Result);
|
|
end else if Identifier is TJSIClass then begin
|
|
// sub class already exists
|
|
Result:=TJSIClass(Identifier);
|
|
end else if Identifier is TJSIProperty then begin
|
|
// resolve property
|
|
PropType:=TJSIProperty(Identifier).Typ;
|
|
if PropType is TJSIClass then
|
|
Result:=TJSIClass(PropType)
|
|
else
|
|
raise Exception.Create('path is not class: '+AName+' is '+Identifier.ClassName);
|
|
end else begin
|
|
raise Exception.Create('path is not class: '+AName+' is '+Identifier.ClassName);
|
|
end;
|
|
end;
|
|
// skip point
|
|
inc(p);
|
|
until p>Length(Path);
|
|
end;
|
|
|
|
function TJavascriptIdentifierTree.CreateAlias(const Path: string): TJSIAlias;
|
|
var
|
|
Context: TJSIClass;
|
|
AVLNode: TAVLTreeNode;
|
|
JSName: String;
|
|
begin
|
|
Context:=CreateClass(Path,false);
|
|
if Context<>nil then
|
|
raise Exception.Create('nested alias not spported yet: '+Path);
|
|
JSName:=Path;
|
|
AVLNode:=FindGlobal(JSName);
|
|
if AVLNode=nil then begin
|
|
// create new alias
|
|
debugln(['TJavascriptIdentifierTree.CreateAlias new alias: ',JSName]);
|
|
Result:=TJSIAlias.Create;
|
|
Result.JSName:=JSName;
|
|
end else begin
|
|
// alias already exists
|
|
if not (TObject(AVLNode.Data) is TJSIAlias) then
|
|
raise Exception.Create('path not an alias: '+Path);
|
|
Result:=TJSIAlias(AVLNode.Data);
|
|
end;
|
|
end;
|
|
|
|
function TJavascriptIdentifierTree.FindGlobal(const aJSName: string
|
|
): TAVLTreeNode;
|
|
begin
|
|
Result:=Globals.FindKey(Pointer(aJSName),@CompareJSNameWithJSIdentifier);
|
|
end;
|
|
|
|
function TJavascriptIdentifierTree.CreateUnresolved(const aPath: string
|
|
): TJSIUnresolvedIdentifier;
|
|
begin
|
|
if not IsValidJSName(aPath) then
|
|
raise Exception.Create('invalid type name '+aPath);
|
|
Result:=TJSIUnresolvedIdentifier.Create;
|
|
Result.JSName:=aPath;
|
|
end;
|
|
|
|
constructor TJavascriptIdentifierTree.Create;
|
|
begin
|
|
inherited Create;
|
|
Globals:=TAVLTree.Create(@CompareJSIdentifiers);
|
|
end;
|
|
|
|
destructor TJavascriptIdentifierTree.Destroy;
|
|
begin
|
|
ClearGlobals;
|
|
FreeAndNil(Globals);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJavascriptIdentifierTree.LoadFromFile(Filename: string);
|
|
var
|
|
Doc: TXMLDocument;
|
|
begin
|
|
debugln(['TJavascriptIdentifierTree.LoadFromFile ',Filename]);
|
|
ClearNodes;
|
|
Doc:=nil;
|
|
try
|
|
ReadXMLFile(Doc,Filename);
|
|
if (Doc.DocumentElement<>nil) and (Doc.DocumentElement.NodeName='ExtJSClasses') then
|
|
ReadExtJSNodes(Doc.DocumentElement)
|
|
else
|
|
raise Exception.Create('ExtJSClasses not found in file '+Filename);
|
|
finally
|
|
Doc.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TJavascriptIdentifierTree.ClearGlobals;
|
|
begin
|
|
Globals.FreeAndClear;
|
|
end;
|
|
|
|
{ TJSIMethod }
|
|
|
|
destructor TJSIMethod.Destroy;
|
|
begin
|
|
ClearParams;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJSIMethod.ClearParams;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Params<>nil then
|
|
for i:=0 to Params.Count-1 do TObject(Params[i]).Free;
|
|
FreeAndNil(Params);
|
|
end;
|
|
|
|
procedure TJSIMethod.AddParameter(aParam: TJSIParameter);
|
|
begin
|
|
if Params=nil then
|
|
Params:=TFPList.Create;
|
|
Params.Add(aParam);
|
|
end;
|
|
|
|
{ TJSIClass }
|
|
|
|
destructor TJSIClass.Destroy;
|
|
begin
|
|
ClearClasses;
|
|
ClearMethods;
|
|
ClearProperties;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJSIClass.ClearMethods;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Methods<>nil then
|
|
for i:=0 to Methods.Count-1 do TObject(Methods[i]).Free;
|
|
FreeAndNil(Methods);
|
|
end;
|
|
|
|
procedure TJSIClass.ClearProperties;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Properties<>nil then
|
|
for i:=0 to Properties.Count-1 do TObject(Properties[i]).Free;
|
|
FreeAndNil(Properties);
|
|
end;
|
|
|
|
procedure TJSIClass.ClearClasses;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Classes<>nil then
|
|
for i:=0 to Classes.Count-1 do TObject(Classes[i]).Free;
|
|
FreeAndNil(Classes);
|
|
end;
|
|
|
|
function TJSIClass.FindIdentifier(const AJSName: string): TJSIdentifier;
|
|
|
|
function Find(List: TFPList): TJSIdentifier;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if List=nil then exit(nil);
|
|
for i:=0 to List.Count-1 do begin
|
|
Result:=TJSIdentifier(List[i]);
|
|
if CompareStr(AJSName,Result.JSName)=0 then exit;
|
|
end;
|
|
Result:=nil;
|
|
end;
|
|
|
|
begin
|
|
Result:=Find(Classes);
|
|
if Result<>nil then exit;
|
|
Result:=Find(Properties);
|
|
if Result<>nil then exit;
|
|
Result:=Find(Methods);
|
|
if Result<>nil then exit;
|
|
end;
|
|
|
|
procedure TJSIClass.AddClass(AClass: TJSIClass);
|
|
begin
|
|
if Classes=nil then
|
|
Classes:=TFPList.Create;
|
|
Classes.Add(AClass);
|
|
end;
|
|
|
|
procedure TJSIClass.AddMethod(AMethod: TJSIMethod);
|
|
begin
|
|
if Methods=nil then
|
|
Methods:=TFPList.Create;
|
|
Methods.Add(AMethod);
|
|
end;
|
|
|
|
procedure TJSIClass.AddProperty(AProperty: TJSIProperty);
|
|
begin
|
|
if Properties=nil then
|
|
Properties:=TFPList.Create;
|
|
Properties.Add(AProperty);
|
|
end;
|
|
|
|
end.
|
|
|