Repository URL to install this package:
|
Version:
3.2.0 ▾
|
{
This file is part of the Free Component Library
WEBIDL to pascal code converter
Copyright (c) 2018 by Michael Van Canneyt michael@freepascal.org
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program 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.
**********************************************************************}
unit webidltopas;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, contnrs, WebIDLParser, WebIDLScanner, WebIDLDefs, pascodegen;
Type
{ TWebIDLToPas }
{ TPasData }
TPasData = Class(TObject)
private
FPasName: String;
Public
Constructor Create(APasName : String);
Property PasName : String read FPasName;
end;
TConversionOption = (coDictionaryAsClass,coUseNativeTypeAliases,coExternalConst,coExpandUnionTypeArgs,coaddOptionsToheader);
TConversionOptions = Set of TConversionOption;
TWebIDLToPas = Class(TPascalCodeGenerator)
private
FClassPrefix: String;
FClassSuffix: String;
FContext: TWebIDLContext;
FDictionaryClassParent: String;
FFieldPrefix: String;
FIncludeImplementationCode: TStrings;
FIncludeInterfaceCode: TStrings;
FInputFileName: String;
FOptions: TConversionOptions;
FOutputFileName: String;
FTypeAliases: TStrings;
FVerbose: Boolean;
FWebIDLVersion: TWebIDLVersion;
FPasNameList : TFPObjectList;
FAutoTypes : TStrings;
procedure SetIncludeImplementationCode(AValue: TStrings);
procedure SetIncludeInterfaceCode(AValue: TStrings);
procedure SetTypeAliases(AValue: TStrings);
Protected
procedure AddOptionsToHeader;
Procedure Parse; virtual;
Procedure WritePascal; virtual;
function CreateParser(aContext: TWebIDLContext; S: TWebIDLScanner): TWebIDLParser; virtual;
function CreateScanner(S: TStream): TWebIDLScanner;virtual;
Function CreateContext : TWebIDLContext; virtual;
Function BaseUnits : String; override;
// Auxiliary routines
procedure Getoptions(L: TStrings); virtual;
procedure ProcessDefinitions; virtual;
function CreatePasName(aName: String): TPasData;virtual;
procedure AllocatePasNames(aList: TIDLDefinitionList; ParentName: String='');virtual;
Function AllocatePasName(D: TIDLDefinition; ParentName: String='') : TPasData;virtual;
procedure EnsureUniqueNames(ML: TIDLDefinitionList);virtual;
function WriteFunctionImplicitTypes(aList: TIDLDefinitionList): Integer;virtual;
function WriteAttributeImplicitTypes(aList: TIDLDefinitionList): Integer;virtual;
function WriteDictionaryMemberImplicitTypes(aList: TIDLDefinitionList): Integer;virtual;
function AddSequenceDef(ST: TIDLSequenceTypeDefDefinition): Boolean; virtual;
function GetName(ADef: TIDLDefinition): String;virtual;
function GetTypeName(Const aTypeName: String; ForTypeDef: Boolean=False): String;virtual;
function GetTypeName(aTypeDef: TIDLTypeDefDefinition; ForTypeDef: Boolean=False): String;virtual;
function CheckUnionTypeDefinition(D: TIDLDefinition): TIDLUnionTypeDefDefinition;virtual;
procedure AddArgumentToOverloads(aList: TFPObjectlist; AName, ATypeName: String);virtual;
procedure AddUnionOverloads(aList: TFPObjectlist; AName: String; UT: TIDLUnionTypeDefDefinition);virtual;
procedure AddArgumentToOverloads(aList: TFPObjectlist; adef: TIDLArgumentDefinition);virtual;
procedure AddOverloads(aList: TFPObjectlist; adef: TIDLFunctionDefinition; aIdx: Integer);virtual;
function CloneNonPartialArgumentList(aList: TFPObjectlist; ADest: TFPObjectlist= Nil; AsPartial: Boolean=True): integer;virtual;
function GetOverloads(aDef: TIDLFunctionDefinition): TFPObjectlist;virtual;
function GetArguments(aList: TIDLDefinitionList; ForceBrackets: Boolean): String;virtual;
function HaveConsts(aList: TIDLDefinitionList): Boolean;virtual;
// Actual code generation routines
// Lists. Return the number of actually written defs.
function WriteCallBackDefs(aList: TIDLDefinitionList): Integer; virtual;
Function WriteDictionaryDefs(aList: TIDLDefinitionList) : Integer;virtual;
Function WriteForwardClassDefs(aList: TIDLDefinitionList) : Integer;virtual;
Function WriteInterfaceDefs(aList: TIDLDefinitionList) : Integer;virtual;
Function WriteMethodDefs(aList: TIDLDefinitionList) : Integer;virtual;
Function WriteTypeDefs(aList: TIDLDefinitionList) : Integer;virtual;
Function WriteEnumDefs(aList: TIDLDefinitionList) : Integer;virtual;
function WriteConsts(aList: TIDLDefinitionList): Integer;virtual;
function WriteProperties(aList: TIDLDefinitionList): Integer;
function WritePlainFields(aList: TIDLDefinitionList): Integer;virtual;
function WriteDictionaryFields(aList: TIDLDefinitionList): Integer;virtual;
function WritePrivateReadOnlyFields(aList: TIDLDefinitionList): Integer;virtual;
// Actual definitions. Return true if a definition was written.
Function WriteForwardClassDef(D: TIDLStructuredDefinition) : Boolean;virtual;
function WriteFunctionTypeDefinition(aDef: TIDLFunctionDefinition): Boolean;virtual;
function WriteFunctionDefinition(aDef: TIDLFunctionDefinition): Boolean;virtual;
function WriteTypeDef(aDef: TIDLTypeDefDefinition): Boolean; virtual;
function WriteRecordDef(aDef: TIDLRecordDefinition): Boolean; virtual;
function WriteEnumDef(aDef: TIDLEnumDefinition): Boolean; virtual;
function WriteDictionaryField(aField: TIDLDictionaryMemberDefinition): Boolean;virtual;
Function WritePrivateReadOnlyField(aAttr: TIDLAttributeDefinition) : Boolean;virtual;
Function WriteField(aAttr: TIDLAttributeDefinition) : Boolean;virtual;
Function WriteReadonlyProperty(aAttr: TIDLAttributeDefinition) : Boolean;virtual;
Function WriteConst(aConst: TIDLConstDefinition) : Boolean ;virtual;
function WriteInterfaceDef(Intf: TIDLInterfaceDefinition): Boolean; virtual;
function WriteDictionaryDef(aDict: TIDLDictionaryDefinition): Boolean; virtual;
// Additional
procedure WriteAliasTypeDef(aDef: TIDLTypeDefDefinition);virtual;
procedure WritePromiseDef(aDef: TIDLPromiseTypeDefDefinition);virtual;
procedure WriteSequenceDef(aDef: TIDLSequenceTypeDefDefinition);virtual;
procedure WriteUnionDef(aDef: TIDLUnionTypeDefDefinition);virtual;
// Extra interface/Implementation code.
procedure WriteImplementation; virtual;
procedure WriteIncludeInterfaceCode; virtual;
Property Context : TWebIDLContext Read FContext;
Public
Constructor Create(Aowner : TComponent); override;
Destructor Destroy; override;
Procedure Execute;
Published
Property InputFileName : String Read FInputFileName Write FInputFileName;
Property OutputFileName : String Read FOutputFileName Write FOutputFileName;
Property Verbose : Boolean Read FVerbose Write FVerbose;
Property FieldPrefix : String Read FFieldPrefix Write FFieldPrefix;
Property ClassPrefix : String Read FClassPrefix Write FClassPrefix;
Property ClassSuffix : String Read FClassSuffix Write FClassSuffix;
Property Options : TConversionOptions Read FOptions Write FOptions;
Property WebIDLVersion : TWebIDLVersion Read FWebIDLVersion Write FWebIDLVersion;
Property TypeAliases : TStrings Read FTypeAliases Write SetTypeAliases;
Property IncludeInterfaceCode : TStrings Read FIncludeInterfaceCode Write SetIncludeInterfaceCode;
Property IncludeImplementationCode : TStrings Read FIncludeImplementationCode Write SetIncludeImplementationCode;
Property DictionaryClassParent : String Read FDictionaryClassParent Write FDictionaryClassParent;
end;
implementation
uses typinfo;
{ TPasData }
constructor TPasData.Create(APasName: String);
begin
FPasName:=APasName;
end;
{ TWebIDLToPas }
function TWebIDLToPas.CreateContext: TWebIDLContext;
begin
Result:=TWebIDLContext.Create(True);
end;
function TWebIDLToPas.CreateScanner(S : TStream) : TWebIDLScanner;
begin
Result:=TWebIDLScanner.Create(S);
end;
function TWebIDLToPas.CreateParser(aContext : TWebIDLContext;S : TWebIDLScanner) : TWebIDLParser;
begin
Result:=TWebIDLParser.Create(aContext,S);
Result.Version:=FWebIDLVersion;
end;
procedure TWebIDLToPas.Parse;
Var
F : TFileStream;
S : TWebIDLScanner;
P : TWebIDLParser;
begin
P:=Nil;
F:=TFileStream.Create(InputFileName,fmOpenRead or fmShareDenyWrite);
try
S:=CreateScanner(F);
P:=CreateParser(Context,S);
P.Parse;
finally
P.Free;
S.Free;
F.Free;
end;
end;
function TWebIDLToPas.GetName(ADef: TIDLDefinition): String;
begin
If Assigned(ADef) and (TObject(ADef.Data) is TPasData) then
Result:=TPasData(ADef.Data).PasName
else
Result:=ADef.Name;
end;
function TWebIDLToPas.HaveConsts(aList: TIDLDefinitionList): Boolean;
Var
D : TIDLDefinition;
begin
Result:=False;
For D in aList do
if D is TIDLConstDefinition then
Exit(True);
end;
function TWebIDLToPas.WritePrivateReadOnlyFields(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
A : TIDLAttributeDefinition absolute D;
begin
Result:=0;
For D in aList do
if (D is TIDLAttributeDefinition) then
if (aoReadOnly in A.Options) then
if WritePrivateReadOnlyField(A) then
Inc(Result);
end;
function TWebIDLToPas.WriteProperties(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
A : TIDLAttributeDefinition absolute D;
begin
Result:=0;
For D in aList do
if (D is TIDLAttributeDefinition) then
if (aoReadOnly in A.Options) then
if WriteReadOnlyProperty(A) then
Inc(Result);
end;
function TWebIDLToPas.WriteConst(aConst: TIDLConstDefinition): Boolean;
Const
ConstTypes : Array[TConstType] of String =
('Double','NativeInt','Boolean','JSValue','JSValue','JSValue','JSValue','String','JSValue');
Var
S : String;
begin
Result:=True;
// Consts cannot be strings
if coExternalConst in Options then
begin
S:=ConstTypes[aConst.ConstType];
Addln('%s : %s;',[GetName(aConst),S])
end
else
begin
S:=aConst.Value;
if aConst.ConstType=ctInteger then
S:=StringReplace(S,'0x','$',[]);
Addln('%s = %s;',[GetName(aConst),S])
end;
end;
function TWebIDLToPas.WriteConsts(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
begin
EnsureSection(csConst);
Indent;
Result:=0;
For D in aList do
if D is TIDLConstDefinition then
if WriteConst(D as TIDLConstDefinition) then
Inc(Result);
Undent;
end;
function TWebIDLToPas.WritePlainFields(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
A : TIDLAttributeDefinition absolute D;
begin
EnsureSection(csDeclaration);
Indent;
Result:=0;
For D in aList do
if D is TIDLAttributeDefinition then
if Not (aoReadOnly in A.Options) then
if WriteField(A) then
Inc(Result);
Undent;
end;
function TWebIDLToPas.WriteDictionaryField(
aField: TIDLDictionaryMemberDefinition): Boolean;
Var
Def,N,TN : String;
begin
Result:=True;
N:=GetName(aField);
TN:=GetTypeName(aField.MemberType);
if TN='record' then
TN:='TJSObject';
if SameText(N,TN) then
N:='_'+N;
Def:=Format('%s : %s;',[N,TN]);
if (N<>aField.Name) then
Def:=Def+Format('external name ''%s'';',[aField.Name]);
AddLn(Def);
end;
function TWebIDLToPas.WriteDictionaryFields(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
M : TIDLDictionaryMemberDefinition absolute D;
begin
Indent;
Result:=0;
For D in aList do
if D is TIDLDictionaryMemberDefinition then
if WriteDictionaryField(M) then
Inc(Result);
Undent;
end;
function TWebIDLToPas.WriteMethodDefs(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
FD : TIDLFunctionDefinition absolute D;
begin
Result:=0;
for D in aList do
if D is TIDLFunctionDefinition then
if Not (foCallBack in FD.Options) then
if WriteFunctionDefinition(FD) then
Inc(Result);
end;
function TWebIDLToPas.AddSequenceDef(ST: TIDLSequenceTypeDefDefinition
): Boolean;
var
TN : String;
begin
TN:=GetTypeName(ST);
Result:=FAutoTypes.IndexOf(TN)=-1;
if Result then
begin
FAutoTypes.Add(TN);
DoLog('Automatically adding %s sequence definition.',[TN]);
AddLn('%s = Array of %s;',[TN,GetTypeName(ST.ElementType)]);
ST.Data:=CreatePasName(TN);
end;
end;
function TWebIDLToPas.WriteFunctionImplicitTypes(aList: TIDLDefinitionList): Integer;
Var
D,D2,D3 : TIDLDefinition;
FD : TIDLFunctionDefinition absolute D;
DA : TIDLArgumentDefinition absolute D2;
UT : TIDLUnionTypeDefDefinition;
begin
Result:=0;
for D in aList do
if D is TIDLFunctionDefinition then
if Not (foCallBack in FD.Options) then
begin
if (FD.ReturnType is TIDLSequenceTypeDefDefinition) then
if AddSequenceDef(FD.ReturnType as TIDLSequenceTypeDefDefinition) then
Inc(Result);
For D2 in FD.Arguments do
if (DA.ArgumentType is TIDLSequenceTypeDefDefinition) then
begin
if AddSequenceDef(DA.ArgumentType as TIDLSequenceTypeDefDefinition) then
Inc(Result);
end
else
begin
UT:=CheckUnionTypeDefinition(DA.ArgumentType);
if Assigned(UT) then
For D3 in UT.Union do
if (D3 is TIDLSequenceTypeDefDefinition) then
if AddSequenceDef(D3 as TIDLSequenceTypeDefDefinition) then
Inc(Result);
end;
end;
if Result>0 then
AddLn('');
end;
function TWebIDLToPas.WriteAttributeImplicitTypes(aList: TIDLDefinitionList
): Integer;
Var
D : TIDLDefinition;
FA : TIDLAttributeDefinition absolute D;
begin
Result:=0;
for D in aList do
if D is TIDLAttributeDefinition then
if (FA.AttributeType is TIDLSequenceTypeDefDefinition) then
if AddSequenceDef(FA.AttributeType as TIDLSequenceTypeDefDefinition) then
Inc(Result);
end;
function TWebIDLToPas.WriteDictionaryMemberImplicitTypes(
aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
FD : TIDLDictionaryMemberDefinition absolute D;
begin
Result:=0;
for D in aList do
if D is TIDLDictionaryMemberDefinition then
if (FD.MemberType is TIDLSequenceTypeDefDefinition) then
if AddSequenceDef(FD.MemberType as TIDLSequenceTypeDefDefinition) then
Inc(Result);
end;
procedure TWebIDLToPas.EnsureUniqueNames(ML : TIDLDefinitionList);
Var
L : TFPObjectHashTable;
Procedure CheckRename(aD : TIDLDefinition);
var
I : integer;
P : TPasData;
NOrig,N,N2 : String;
isDup : Boolean;
D2 : TIDLDefinition;
begin
NOrig:=GetName(aD);
N:=LowerCase(NOrig);
N2:=N;
I:=0;
isDup:=False;
Repeat
D2:=TIDLDefinition(L.Items[N2]);
if (D2<>Nil) then
// Overloads
begin
isDup:=((D2 is TIDLFunctionDefinition) and (ad is TIDLFunctionDefinition));
if IsDup then
D2:=Nil
else
begin
inc(I);
N2:=KeywordPrefix+N+KeywordSuffix;
Norig:=KeywordPrefix+NOrig+KeywordSuffix;
end;
end;
Until (D2=Nil);
if (N<>N2) then
begin
N:=GetName(aD);
DoLog('Renaming duplicate identifier (%s) %s to %s',[aD.ClassName,N,Norig]);
// Original TPasName is in list, will be freed automatically
aD.Data:=CreatePasName(NOrig);
end;
if not IsDup then
L.Add(N2,aD);
end;
var
D : TIDLDefinition;
begin
L:=TFPObjectHashTable.Create(False);
try
For D in ML Do
if not (D is TIDLConstDefinition) then
CheckRename(D);
For D in ML Do
if (D is TIDLConstDefinition) then
CheckRename(D);
finally
L.Free;
end;
end;
function TWebIDLToPas.WriteInterfaceDef(Intf: TIDLInterfaceDefinition): Boolean;
Var
CN,PN : String;
Decl : String;
ML : TIDLDefinitionList;
begin
Result:=True;
ML:=TIDLDefinitionList.Create(Nil,False);
try
Intf.GetFullMemberList(ML);
EnsureUniqueNames(ML);
CN:=GetName(Intf);
ClassHeader(CN);
WriteFunctionImplicitTypes(ML);
WriteAttributeImplicitTypes(ML);
Decl:=Format('%s = class external name %s ',[CN,MakePascalString(Intf.Name,True)]);
if Assigned(Intf.ParentInterface) then
PN:=GetName(Intf.ParentInterface)
else
PN:=GetTypeName(Intf.ParentName);
if PN<>'' then
Decl:=Decl+Format(' (%s)',[PN]);
AddLn(Decl);
AddLn('Private');
Indent;
WritePrivateReadOnlyFields(ML);
Undent;
AddLn('Public');
if HaveConsts(ML) then
begin
Indent;
PushSection(csUnknown);
WriteConsts(ML);
PopSection;
Undent;
AddLn('Public');
end;
Indent;
WritePlainFields(ML);
WriteMethodDefs(ML);
WriteProperties(ML);
Undent;
AddLn('end;');
finally
ML.Free;
end;
end;
function TWebIDLToPas.WriteDictionaryDef(aDict: TIDLDictionaryDefinition
): Boolean;
Var
CN,CP : String;
ML : TIDLDefinitionList;
PD: TIDLDictionaryDefinition;
begin
Result:=True;
ML:=TIDLDefinitionList.Create(Nil,False);
try
PD:=aDict;
While PD<>Nil do
begin
PD.GetFullMemberList(ML);
PD:=PD.ParentDictionary;
end;
CN:=GetName(aDict);
CP:=DictionaryClassParent;
if CP='' then
CP:='TJSObject';
ClassHeader(CN);
WriteDictionaryMemberImplicitTypes(ML);
if (coDictionaryAsClass in Options) then
Addln('%s = class(%s)',[CN,CP])
else
Addln('%s = record',[CN]);
WriteDictionaryFields(ML);
AddLn('end;');
finally
ML.Free;
end;
end;
constructor TWebIDLToPas.Create(Aowner: TComponent);
begin
inherited Create(Aowner);
WebIDLVersion:=v2;
FieldPrefix:='F';
ClassPrefix:='T';
ClassSuffix:='';
Switches.Add('modeswitch externalclass');
FTypeAliases:=TStringList.Create;
FPasNameList:=TFPObjectList.Create(True);
FAutoTypes:=TStringList.Create;
FIncludeInterfaceCode:=TStringList.Create;
FIncludeImplementationCode:=TStringList.Create;
end;
destructor TWebIDLToPas.Destroy;
begin
FreeAndNil(FIncludeInterfaceCode);
FreeAndNil(FIncludeImplementationCode);
FreeAndNil(FAutoTypes);
FreeAndNil(FTypeAliases);
FreeAndNil(FPasNameList);
inherited Destroy;
end;
procedure TWebIDLToPas.WriteImplementation;
Var
S : String;
begin
Addln('');
For S in FIncludeImplementationCode do
Addln(S);
Addln('');
end;
function TWebIDLToPas.GetTypeName(aTypeDef : TIDLTypeDefDefinition; ForTypeDef : Boolean = False): String;
begin
if ATypeDef is TIDLSequenceTypeDefDefinition then
begin
if Assigned(aTypeDef.Data) then
Result:=GetName(aTypeDef)
else
begin
Result:=GetTypeName(TIDLSequenceTypeDefDefinition(aTypeDef).ElementType,ForTypeDef);
Result:='T'+Result+'DynArray';
end
end
else
Result:=GetTypeName(aTypeDef.TypeName,ForTypeDef);
end;
function TWebIDLToPas.GetTypeName(const aTypeName: String; ForTypeDef: Boolean
): String;
Function UsePascalType(Const aPascalType : string) : String;
begin
if (coUseNativeTypeAliases in Options) and ForTypeDef then
Result:=StringReplace(aTypeName,' ','',[rfReplaceAll])
else
Result:=aPascalType;
end;
Var
A,TN : UTF8String;
D : TIDLDefinition;
begin
Case aTypeName of
'union': TN:='JSValue';
'short': TN:=UsePascalType('Integer');
'long': TN:=UsePascalType('Integer');
'long long': TN:=UsePascalType('NativeInt');
'unsigned short': TN:=UsePascalType('Cardinal');
'unrestricted float': TN:=UsePascalType('Double');
'unsigned long': TN:=UsePascalType('NativeInt');
'unsigned long long': TN:=UsePascalType('NativeInt');
'octet': TN:=UsePascalType('Byte');
'any' : TN:=UsePascalType('JSValue');
'float' : TN:=UsePascalType('Double');
'double' : TN:=UsePascalType('Double');
'DOMString',
'USVString',
'ByteString' : TN:=UsePascalType('String');
'object' : TN:=UsePascalType('TJSObject');
'Error' : TN:=UsePascalType('TJSError');
'DOMException' : TN:=UsePascalType('TJSError');
'ArrayBuffer',
'DataView',
'Int8Array',
'Int16Array',
'Int32Array',
'Uint8Array',
'Uint16Array',
'Uint32Array',
'Uint8ClampedArray',
'Float32Array',
'Float64Array' : TN:='TJS'+aTypeName;
else
TN:=aTypeName;
D:=FContext.FindDefinition(TN);
if D<>Nil then
TN:=GetName(D)
else
begin
A:=FTypeAliases.Values[TN];
If (A<>'') then
TN:=A;
end;
end;
Result:=TN;
end;
function TWebIDLToPas.WritePrivateReadOnlyField(aAttr: TIDLAttributeDefinition
): Boolean;
begin
AddLn('%s%s : %s; external name ''%s''; ',[FieldPrefix,GetName(aAttr),GetTypeName(aAttr.AttributeType),aAttr.Name]);
end;
function TWebIDLToPas.WriteField(aAttr: TIDLAttributeDefinition): Boolean;
Var
Def,TN,N : String;
begin
Result:=True;
N:=GetName(aAttr);
TN:=GetTypeName(aAttr.AttributeType);
if TN='record' then
TN:='TJSObject';
if SameText(N,TN) then
N:='_'+N;
Def:=Format('%s : %s;',[N,TN]);
if (N<>aAttr.Name) then
Def:=Def+Format('external name ''%s'';',[aAttr.Name]);
AddLn(Def);
end;
function TWebIDLToPas.WriteReadonlyProperty(aAttr: TIDLAttributeDefinition
): Boolean;
Var
TN,N,PN : String;
begin
Result:=True;
N:=GetName(aAttr);
PN:=N;
TN:=GetTypeName(aAttr.AttributeType);
if SameText(PN,TN) then
PN:='_'+PN;
AddLn('Property %s : %s Read %s%s; ',[PN,TN,FieldPrefix,N]);
end;
function TWebIDLToPas.WriteForwardClassDef(D: TIDLStructuredDefinition): Boolean;
begin
Result:=not D.IsPartial;
if Result then
AddLn('%s = Class;',[GetName(D)]);
end;
function TWebIDLToPas.WriteForwardClassDefs(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
begin
Result:=0;
Comment('Forward class definitions');
For D in aList do
if D is TIDLInterfaceDefinition then
if WriteForwardClassDef(D as TIDLInterfaceDefinition) then
Inc(Result);
if coDictionaryAsClass in Options then
For D in aList do
if D is TIDLDictionaryDefinition then
if WriteForwardClassDef(D as TIDLDictionaryDefinition) then
Inc(Result);
end;
procedure TWebIDLToPas.WriteSequenceDef(aDef : TIDLSequenceTypeDefDefinition);
begin
Addln('%s = array of %s;',[GetName(aDef),GetTypeName(aDef.ElementType)])
end;
procedure TWebIDLToPas.WriteUnionDef(aDef : TIDLUnionTypeDefDefinition);
Var
S : UTF8String;
D : TIDLDefinition;
begin
S:='';
For D in adef.Union do
begin
if (S<>'') then
S:=S+', ';
S:=S+(D as TIDLTypeDefDefinition).TypeName;
end;
Comment('Union of '+S);
AddLn('%s = JSValue; ',[GetName(aDef)])
end;
procedure TWebIDLToPas.WritePromiseDef(aDef : TIDLPromiseTypeDefDefinition);
begin
AddLn('%s = TJSPromise;',[GetName(aDef)]);
end;
procedure TWebIDLToPas.WriteAliasTypeDef(aDef : TIDLTypeDefDefinition);
Var
TN : String;
begin
TN:=GetTypeName(aDef,True);
AddLn('%s = %s;',[GetName(aDef),TN]);
end;
function TWebIDLToPas.WriteTypeDef(aDef: TIDLTypeDefDefinition): Boolean;
begin
Result:=True;
if ADef is TIDLSequenceTypeDefDefinition then
WriteSequenceDef(aDef as TIDLSequenceTypeDefDefinition)
else if ADef is TIDLUnionTypeDefDefinition then
WriteUnionDef(aDef as TIDLUnionTypeDefDefinition)
else if ADef is TIDLPromiseTypeDefDefinition then
WritePromiseDef(aDef as TIDLPromiseTypeDefDefinition)
else if ADef is TIDLRecordDefinition then
WriteRecordDef(aDef as TIDLRecordDefinition)
else
WriteAliasTypeDef(aDef);
end;
function TWebIDLToPas.WriteRecordDef(aDef: TIDLRecordDefinition): Boolean;
Var
KT,VT : String;
begin
Result:=True;
KT:=GetTypeName(aDef.KeyType);
VT:=GetTypeName(aDef.ValueType);
AddLn('%s = Class(TJSObject)',[GetName(aDef)]);
AddLn('private');
Indent;
AddLn('function GetValue(aKey: %s): %s; external name ''[]'';',[KT,VT]);
AddLn('procedure SetValue(aKey: %s; const AValue: %s); external name ''[]'';',[KT,VT]);
undent;
AddLn('public');
Indent;
AddLn('property Values[Name: %s]: %s read GetProperties write SetProperties; default;',[KT,VT]);
undent;
AddLn('end;');
end;
function TWebIDLToPas.WriteTypeDefs(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
TD : TIDLTypeDefDefinition absolute D;
begin
Result:=0;
EnsureSection(csType);
for D in aList do
if D is TIDLTypeDefDefinition then
if WriteTypeDef(TD) then
Inc(Result);
end;
function TWebIDLToPas.WriteEnumDef(aDef: TIDLEnumDefinition): Boolean;
begin
Result:=True;
AddLn('%s = String;',[GetName(aDef)]);
end;
function TWebIDLToPas.WriteEnumDefs(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
ED : TIDLEnumDefinition absolute D;
begin
Result:=0;
EnsureSection(csType);
for D in aList do
if D is TIDLEnumDefinition then
if WriteEnumDef(ED) then
Inc(Result);
end;
function TWebIDLToPas.GetArguments(aList: TIDLDefinitionList;
ForceBrackets: Boolean): String;
Var
I : TIDLDefinition;
A : TIDLArgumentDefinition absolute I;
Arg : string;
begin
Result:='';
For I in aList do
begin
Arg:=GetName(A);
Arg:=Arg+' : '+GetTypeName(A.ArgumentType);
if Result<>'' then
Result:=Result+'; ';
Result:=Result+Arg;
end;
if (Result<>'') or ForceBrackets then
Result:='('+Result+')';
end;
Type
// A partial argument list is a list which has been generated for a optional argument.
// Additional arguments can never be added to a partial list...
TIDLPartialDefinitionList = Class(TIDLDefinitionList);
function TWebIDLToPas.CloneNonPartialArgumentList(aList: TFPObjectlist;
ADest: TFPObjectlist; AsPartial: Boolean): integer;
Var
I,J : Integer;
CD : TIDLDefinition;
DL,CL : TIDLDefinitionList;
begin
Result:=0;
if ADest=Nil then
ADest:=aList;
I:=aList.Count-1;
While (I>=0) do
begin
DL:=TIDLDefinitionList(alist[i]);
if Not (DL is TIDLPartialDefinitionList) then
begin
Inc(Result);
if AsPartial then
CL:=TIDLPartialDefinitionList.Create(Nil,True)
else
CL:=TIDLDefinitionList.Create(Nil,True);
aDest.Add(CL);
For J:=0 to DL.Count-1 do
begin
CD:=(DL.Definitions[J] as TIDLArgumentDefinition).Clone(Nil);
CL.Add(CD);
AllocatePasName(CD);
end;
end;
Dec(I);
end;
end;
procedure TWebIDLToPas.AddArgumentToOverloads(aList: TFPObjectlist; AName,ATypeName : String);
Var
I : Integer;
CD : TIDLArgumentDefinition;
DL : TIDLDefinitionList;
begin
For I:=0 to aList.Count-1 do
begin
DL:=TIDLDefinitionList(alist[i]);
if Not (DL is TIDLPartialDefinitionList) then
begin
CD:=TIDLArgumentDefinition.Create(Nil,aName);
CD.ArgumentType:=TIDLTypeDefDefinition.Create(CD,'');
CD.ArgumentType.TypeName:=aTypeName;
DL.Add(CD);
AllocatePasName(cd,'');
end;
end;
end;
procedure TWebIDLToPas.AddArgumentToOverloads(aList: TFPObjectlist; adef: TIDLArgumentDefinition);
Var
I : Integer;
CD : TIDLDefinition;
DL : TIDLDefinitionList;
begin
For I:=0 to aList.Count-1 do
begin
DL:=TIDLDefinitionList(alist[i]);
if Not (DL is TIDLPartialDefinitionList) then
begin
CD:=aDef.Clone(Nil);
DL.Add(CD);
if aDef.Data<>Nil then
CD.Data:=CreatePasName(TPasData(aDef.Data).PasName)
else
AllocatePasName(cd,'');
end;
end;
end;
procedure TWebIDLToPas.AddUnionOverloads(aList: TFPObjectlist; AName : String; UT : TIDLUnionTypeDefDefinition);
Var
L,L2 : TFPObjectList;
I,J : Integer;
D : TIDLDefinitionList;
Dups : TStringList;
begin
L2:=Nil;
Dups:=TStringList.Create;
Dups.Sorted:=True;
Dups.Duplicates:=dupIgnore;
L:=TFPObjectList.Create(False);
try
L2:=TFPObjectList.Create(False);
// Collect non partial argument lists
for I:=0 to AList.Count-1 do
begin
D:=TIDLDefinitionList(alist[i]);
if Not (D is TIDLPartialDefinitionList) then
L.Add(D);
end;
// Collect unique pascal types. Note that this can reduce the list to 1 element...
For I:=0 to UT.Union.Count-1 do
Dups.AddObject(GetTypeName(UT.Union[I] as TIDLTypeDefDefinition),UT.Union[I]);
// First, clone list and add argument to cloned lists
For I:=1 to Dups.Count-1 do
begin
// Clone list
CloneNonPartialArgumentList(L,L2,False);
// Add argument to cloned list
AddArgumentToOverloads(L2,aName,Dups[i]);
// Add overloads to original list
For J:=0 to L2.Count-1 do
aList.Add(L2[J]);
L2.Clear;
end;
// Add first Union to original list
AddArgumentToOverloads(L,aName,Dups[0]);
finally
Dups.Free;
L2.Free;
L.Free;
end;
end;
function TWebIDLToPas.CheckUnionTypeDefinition(D: TIDLDefinition
): TIDLUnionTypeDefDefinition;
begin
Result:=Nil;
If (D is TIDLUnionTypeDefDefinition) then
Result:=D as TIDLUnionTypeDefDefinition
else
begin
D:=Context.FindDefinition((D as TIDLTypeDefDefinition).TypeName);
if (D is TIDLUnionTypeDefDefinition) then
Result:=D as TIDLUnionTypeDefDefinition
end
end;
procedure TWebIDLToPas.AddOverloads(aList: TFPObjectlist;
adef: TIDLFunctionDefinition; aIdx: Integer);
Var
Arg : TIDLArgumentDefinition;
D : TIDLDefinition;
UT : TIDLUnionTypeDefDefinition;
begin
if aIdx>=ADef.Arguments.Count then
exit;
Arg:=ADef.Argument[aIdx];
if Arg.IsOptional then
CloneNonPartialArgumentList(aList);
// Add current to list.
D:=Arg.ArgumentType;
UT:=Nil;
if coExpandUnionTypeArgs in Options then
UT:=CheckUnionTypeDefinition(D);
if UT=Nil then
AddArgumentToOverloads(aList,Arg)
else
AddUnionOverLoads(aList,Arg.Name,UT);
AddOverloads(aList,aDef,aIdx+1);
end;
function TWebIDLToPas.GetOverloads(aDef: TIDLFunctionDefinition): TFPObjectlist;
begin
Result:=TFPObjectList.Create;
try
Result.Add(TIDLDefinitionList.Create(Nil,True));
AddOverloads(Result,adef,0);
except
Result.Free;
Raise;
end;
end;
function TWebIDLToPas.WriteFunctionTypeDefinition(aDef: TIDLFunctionDefinition): Boolean;
Var
FN,RT,Args : String;
begin
Result:=True;
FN:=GetName(aDef);
RT:=GetTypeName(aDef.ReturnType,False);
if (RT='void') then
RT:='';
Args:=GetArguments(aDef.Arguments,False);
if (RT='') then
AddLn('%s = Procedure %s;',[FN,Args])
else
AddLn('%s = function %s: %s;',[FN,Args,RT])
end;
function TWebIDLToPas.WriteFunctionDefinition(aDef: TIDLFunctionDefinition): Boolean;
Var
FN,RT,Suff,Args : String;
Overloads : TFPObjectList;
I : Integer;
begin
Result:=True;
FN:=GetName(aDef);
if FN<>aDef.Name then
Suff:=Format('; external name ''%s''',[aDef.Name]);
RT:=GetTypeName(aDef.ReturnType,False);
if (RT='void') then
RT:='';
Overloads:=GetOverloads(ADef);
try
if Overloads.Count>1 then
Suff:=Suff+'; overload';
For I:=0 to Overloads.Count-1 do
begin
Args:=GetArguments(TIDLDefinitionList(Overloads[i]),False);
if (RT='') then
AddLn('Procedure %s%s%s;',[FN,Args,Suff])
else
AddLn('function %s%s: %s%s;',[FN,Args,RT,Suff])
end;
finally
Overloads.Free;
end;
end;
function TWebIDLToPas.WriteCallBackDefs(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
FD : TIDLFunctionDefinition absolute D;
begin
Result:=0;
EnsureSection(csType);
for D in aList do
if D is TIDLFunctionDefinition then
if (foCallBack in FD.Options) then
if WriteFunctionTypeDefinition(FD) then
Inc(Result);
end;
function TWebIDLToPas.WriteDictionaryDefs(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
DD : TIDLDictionaryDefinition absolute D;
begin
Result:=0;
EnsureSection(csType);
for D in aList do
if D is TIDLDictionaryDefinition then
if WriteDictionaryDef(DD) then
Inc(Result);
end;
function TWebIDLToPas.WriteInterfaceDefs(aList: TIDLDefinitionList): Integer;
Var
D : TIDLDefinition;
ID : TIDLInterfaceDefinition absolute D;
begin
Result:=0;
EnsureSection(csType);
for D in aList do
if D is TIDLInterfaceDefinition then
if WriteInterfaceDef(ID) then
Inc(Result);
end;
procedure TWebIDLToPas.Getoptions(L : TStrings);
Var
S : String;
I : Integer;
begin
L.Add('Automatically generated file by '+ClassName+' on '+FormatDateTime('yyyy-mm-dd hh:nn:ss',Now));
L.Add('');
L.Add('Used command-line options : ');
For I:=1 to ParamCount do
L.Add(ParamStr(i));
L.Add('');
L.Add('Command-line options translate to: ');
L.Add('');
S:=SetToString(PtypeInfo(TypeInfo(TConversionOptions)),Integer(OPtions),True);
L.Add('Options : '+S);
L.Add('Keyword prefix : '+KeywordPrefix);
L.Add('Keyword suffix : '+KeywordSuffix);
L.Add('Class prefix : '+ClassPrefix);
L.Add('Class suffix : '+ClassSuffix);
L.Add('Field prefix : '+FieldPrefix);
Str(WebIDLversion,S);
L.Add('WEBIDLversion : '+S);
if TypeAliases.Count>0 then
begin
L.Add('Type aliases:');
L.AddStrings(Self.TypeAliases);
end;
end;
procedure TWebIDLToPas.AddOptionsToHeader;
Var
L : TStrings;
begin
L:=TStringList.Create;
try
GetOptions(L);
Comment(L);
finally
L.Free;
end;
end;
procedure TWebIDLToPas.WriteIncludeInterfaceCode;
Var
S : String;
begin
For S in IncludeInterfaceCode do
Addln(S);
end;
procedure TWebIDLToPas.WritePascal;
begin
CreateUnitClause;
CreateHeader;
if coaddOptionsToheader in Options then
AddOptionsToHeader;
EnsureSection(csType);
Indent;
WriteForwardClassDefs(Context.Definitions);
WriteEnumDefs(Context.Definitions);
WriteTypeDefs(Context.Definitions);
WriteCallbackDefs(Context.Definitions);
WriteDictionaryDefs(Context.Definitions);
WriteInterfaceDefs(Context.Definitions);
Undent;
WriteIncludeInterfaceCode;
Addln('');
AddLn('implementation');
WriteImplementation;
AddLn('end.');
Source.SaveToFile(OutputFileName);
end;
function TWebIDLToPas.BaseUnits: String;
begin
Result:='SysUtils, JS'
end;
function TWebIDLToPas.CreatePasName(aName: String): TPasData;
begin
Result:=TPasData.Create(EscapeKeyWord(aName));
FPasNameList.Add(Result);
end;
function TWebIDLToPas.AllocatePasName(D: TIDLDefinition; ParentName: String): TPasData;
Var
CN : String;
begin
if D Is TIDLInterfaceDefinition then
begin
CN:=ClassPrefix+D.Name+ClassSuffix;
Result:=CreatePasname(CN);
D.Data:=Result;
AllocatePasNames((D as TIDLInterfaceDefinition).members,D.Name);
end
else if D Is TIDLDictionaryDefinition then
begin
CN:=D.Name;
if coDictionaryAsClass in Options then
CN:=ClassPrefix+CN+ClassSuffix;
Result:=CreatePasname(EscapeKeyWord(CN));
D.Data:=Result;
AllocatePasNames((D as TIDLDictionaryDefinition).members,D.Name);
end
else
begin
Result:=CreatePasName(D.Name);
D.Data:=Result;
if D Is TIDLFunctionDefinition then
AllocatePasNames((D as TIDLFunctionDefinition).Arguments,D.Name);
end;
if Verbose and (TPasData(D.Data).PasName<>D.Name) then
begin
if (ParentName<>'') then
ParentName:=ParentName+'.';
DoLog('Renamed %s to %s',[ParentName+D.Name,TPasData(D.Data).PasName]);
end;
end;
procedure TWebIDLToPas.SetTypeAliases(AValue: TStrings);
begin
if FTypeAliases=AValue then Exit;
FTypeAliases.Assign(AValue);
end;
procedure TWebIDLToPas.SetIncludeInterfaceCode(AValue: TStrings);
begin
if FIncludeInterfaceCode=AValue then Exit;
FIncludeInterfaceCode.Assign(AValue);
end;
procedure TWebIDLToPas.SetIncludeImplementationCode(AValue: TStrings);
begin
if FIncludeImplementationCode=AValue then Exit;
FIncludeImplementationCode.Assign(AValue);
end;
procedure TWebIDLToPas.AllocatePasNames(aList : TIDLDefinitionList; ParentName: String = '');
var
D : TIDLDefinition;
begin
For D in aList do
AllocatePasName(D,ParentName);
end;
procedure TWebIDLToPas.ProcessDefinitions;
begin
FContext.AppendPartials;
FContext.AppendIncludes;
AllocatePasNames(FContext.Definitions);
end;
procedure TWebIDLToPas.Execute;
begin
FContext:=CreateContext;
try
FContext.Aliases:=Self.TypeAliases;
Parse;
if Verbose then
DoLog('Parsed %d definitions.',[Context.Definitions.Count]);
ProcessDefinitions;
WritePascal;
finally
FreeAndNil(FContext);
end;
end;
end.