From da031e7514342f4a6352a1b1daeb74b4ecea14a8 Mon Sep 17 00:00:00 2001 From: drewski207 Date: Thu, 22 Sep 2011 00:15:42 +0000 Subject: [PATCH] Added gobject introspection converter. Can be used to convert .gir files into pascal units. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1982 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../gobject-introspection/gir2pascal.ico | Bin 0 -> 137040 bytes .../gobject-introspection/gir2pascal.lpi | 108 + .../gobject-introspection/gir2pascal.lpr | 248 +++ .../gobject-introspection/gir2pascal.res | Bin 0 -> 138128 bytes .../girctypesmapping.pas | 117 ++ .../gobject-introspection/girerrors.pas | 79 + .../gobject-introspection/girfiles.pas | 149 ++ .../gobject-introspection/girnamespaces.pas | 539 +++++ .../gobject-introspection/girobjects.pas | 1048 ++++++++++ .../gobject-introspection/girparser.pas | 18 + .../gobject-introspection/girpascalwriter.pas | 1791 +++++++++++++++++ .../gobject-introspection/girtokens.pas | 90 + 12 files changed, 4187 insertions(+) create mode 100644 applications/gobject-introspection/gir2pascal.ico create mode 100644 applications/gobject-introspection/gir2pascal.lpi create mode 100644 applications/gobject-introspection/gir2pascal.lpr create mode 100644 applications/gobject-introspection/gir2pascal.res create mode 100644 applications/gobject-introspection/girctypesmapping.pas create mode 100644 applications/gobject-introspection/girerrors.pas create mode 100644 applications/gobject-introspection/girfiles.pas create mode 100644 applications/gobject-introspection/girnamespaces.pas create mode 100644 applications/gobject-introspection/girobjects.pas create mode 100644 applications/gobject-introspection/girparser.pas create mode 100644 applications/gobject-introspection/girpascalwriter.pas create mode 100644 applications/gobject-introspection/girtokens.pas diff --git a/applications/gobject-introspection/gir2pascal.ico b/applications/gobject-introspection/gir2pascal.ico new file mode 100644 index 0000000000000000000000000000000000000000..0341321b5d952e1662a3d9444a73cf9f42a7db37 GIT binary patch literal 137040 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 G`+orYGy**U literal 0 HcmV?d00001 diff --git a/applications/gobject-introspection/gir2pascal.lpi b/applications/gobject-introspection/gir2pascal.lpi new file mode 100644 index 000000000..b33d625e1 --- /dev/null +++ b/applications/gobject-introspection/gir2pascal.lpi @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/gobject-introspection/gir2pascal.lpr b/applications/gobject-introspection/gir2pascal.lpr new file mode 100644 index 000000000..6d38deb85 --- /dev/null +++ b/applications/gobject-introspection/gir2pascal.lpr @@ -0,0 +1,248 @@ +{ +gir2pascal.lpr +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +program gir2pascal; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + Classes, SysUtils, CustApp, DOM, XMLRead, girNameSpaces, girFiles, + girpascalwriter, girErrors, girCTypesMapping, girTokens, girObjects; + +type + + { TGirConsoleConverter } + + TGirConsoleConverter = class(TCustomApplication) + private + FWriteCount: Integer; + FPaths: TStringList; + FOutPutDirectory : String; + FFileToConvert: String; + FOverWriteFiles: Boolean; + procedure AddDefaultPaths; + procedure AddPaths(APaths: String); + procedure VerifyOptions; + procedure Convert; + + //callbacks + function NeedGirFile(AGirFile: TObject; NamespaceName: String) : TXMLDocument; + procedure WritePascalFile(Sender: TObject; AUnitName: String; AStream: TStringStream); + protected + procedure DoRun; override; + public + constructor Create(TheOwner: TComponent); override; + destructor Destroy; override; + procedure WriteHelp; virtual; + end; + +{ TGirConsoleConverter } + +procedure TGirConsoleConverter.AddDefaultPaths; +begin + FPaths.Add('/usr/share/gir-1.0/'); +end; + +procedure TGirConsoleConverter.AddPaths(APaths: String); +var + Strs: TStringList; + Str: String; +begin + Strs := TStringList.Create; + Strs.Delimiter:=':'; + Strs.StrictDelimiter:=True; + Strs.DelimitedText:=APaths; + + // so we can add the delimiter + for Str in Strs do + FPaths.Add(IncludeTrailingPathDelimiter(Str)); + + Strs.Free; +end; + +procedure TGirConsoleConverter.VerifyOptions; +begin + if not DirectoryExists(FOutPutDirectory) then + begin + WriteLn(Format('Output directory "%s" does not exist!', [FOutPutDirectory])); + Terminate; + end; + if FFileToConvert = '' then + begin + WriteLn('No input file specified! See -h for options.'); + Terminate; + Halt; + end; +end; + +function TGirConsoleConverter.NeedGirFile(AGirFile: TObject; NamespaceName: String): TXMLDocument; +var + Sr: TSearchRec; + Path: String; +begin + Result := nil; + for Path in FPaths do + begin + if FindFirst(Path+NamespaceName+'.gir', faAnyFile, Sr) = 0 then + begin + ReadXMLFile(Result, Path+Sr.Name); + Exit; + end; + FindClose(Sr); + end; +end; + +procedure TGirConsoleConverter.WritePascalFile(Sender: TObject; + AUnitName: String; AStream: TStringStream); +var + SStream: TFileStream; + OutFileName: String; +begin + Inc(FWriteCount); + OutFileName:=FOutPutDirectory+LowerCase(AUnitName)+'.pas'; + if not FileExists(OutFileName) + or (FileExists(OutFileName) and FOverWriteFiles) then + begin + WriteLn(Format('Writing: %s', [OutFileName])); + AStream.Position:=0; + ForceDirectories(FOutPutDirectory); + SStream := TFileStream.Create(OutFileName, fmCreate or fmOpenReadWrite); + SStream.CopyFrom(AStream,AStream.Size); + SStream.Free; + AStream.Free; + end + else + begin + WriteLn(Format('File %s already exists! Stopping.', [OutFileName])); + Terminate; + Halt; + end; +end; + +procedure TGirConsoleConverter.Convert; +var + Doc: TXMLDocument; + girFile: TgirFile; + Writer: TgirPascalWriter; + StartTime, EndTime:TDateTime; +begin + StartTime := Now; + ReadXMLFile(Doc, FFileToConvert); + + girFile := TgirFile.Create(nil); + girFile.OnNeedGirFile:=@NeedGirFile; + girFile.ParseXMLDocument(Doc); + Doc.Free; + + Writer := TgirPascalWriter.Create(girFile.NameSpaces); + Writer.OnUnitWriteEvent:= @WritePascalFile; + Writer.GenerateUnits; + + Writer.Free; + EndTime := Now; + + EndTime := EndTime-StartTime; + WriteLn(Format('Converted %d file(s) in %f seconds',[FWriteCount, DateTimeToTimeStamp(EndTime).Time / 1000])); +end; + +procedure TGirConsoleConverter.DoRun; +var + ErrorMsg: String; +begin + // quick check parameters + ErrorMsg:=CheckOptions('hnp:o:i:w',['help','no-default','paths','output-directory', 'input', 'overwrite-files']); + if ErrorMsg<>'' then begin + ShowException(Exception.Create(ErrorMsg)); + Terminate; + Exit; + end; + + // parse parameters + if HasOption('h','help') then begin + WriteHelp; + Terminate; + Exit; + end; + + if not HasOption('n', 'no-default') then + AddDefaultPaths; + + if HasOption('o', 'output-directory') then + FOutPutDirectory:=IncludeTrailingPathDelimiter(GetOptionValue('o', 'output-directory')) + else + FOutPutDirectory:=IncludeTrailingPathDelimiter(GetCurrentDir); + + FFileToConvert:=GetOptionValue('i','input'); + + if HasOption('p', 'paths') then + AddPaths(GetOptionValue('p', 'paths')); + + if HasOption('w', 'overwrite-files') then + FOverWriteFiles:=True; + + VerifyOptions; + + // does all the heavy lifting + Convert; + + // stop program loop + Terminate; +end; + +constructor TGirConsoleConverter.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + FPaths := TStringList.Create; +end; + +destructor TGirConsoleConverter.Destroy; +begin + FPaths.Free; + inherited Destroy; +end; + +procedure TGirConsoleConverter.WriteHelp; +begin + Writeln(''); + writeln(' Usage: ',ExtractFileName(ExeName),' [options] -i filename'); + Writeln(''); + Writeln(''); + Writeln(' -i --input= .gir filename to convert.'); + Writeln(' -o --output-directory= Directory to write the resulting .pas files to. If not'); + Writeln(' specified then the current working directory is used.'); + Writeln(' -w --overwrite-files If the output .pas file(s) already exists then overwrite them.'); + Writeln(' -n --no-default /usr/share/gir-1.0 is not added as a search location for '); + Writeln(' needed .gir files.'); + Writeln(' -p --paths= List of paths seperated by ":" to search for needed .gir files.'); + Writeln(''); +end; + +var + Application: TGirConsoleConverter; + +{$R *.res} + +begin + Application:=TGirConsoleConverter.Create(nil); + Application.Run; + Application.Free; +end. + diff --git a/applications/gobject-introspection/gir2pascal.res b/applications/gobject-introspection/gir2pascal.res new file mode 100644 index 0000000000000000000000000000000000000000..7c6cf3e4be6fa881cb2f2caa9bda693328155c28 GIT binary patch literal 138128 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 S)M$%T8;H+2FPFK8vi}DltTdMZ literal 0 HcmV?d00001 diff --git a/applications/gobject-introspection/girctypesmapping.pas b/applications/gobject-introspection/girctypesmapping.pas new file mode 100644 index 000000000..9660193a4 --- /dev/null +++ b/applications/gobject-introspection/girctypesmapping.pas @@ -0,0 +1,117 @@ +{ +ctypesmapping.pas +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +unit girCTypesMapping; + +{$mode objfpc}{$H+} + +interface + +const + CTypesMax = 31; +var + + TypesPascalCTypes: array [0..CTypesMax-1] of string = + ( + 'pointer', + 'cint', + 'cint', + 'cuint', + 'cuint8', + 'cuint16', + 'cuint32', + 'cuint64', + 'cint8', + 'cint16', + 'cint32', + 'cint64', + 'csize_t', + 'clong', + 'culong', + 'cushort', + 'char', + 'Boolean32', + 'PtrInt', + 'csize_t', + 'gpointer', + 'cfloat', + 'cdouble', + 'cdouble', + 'char', + 'Int64', + 'Extended', + 'guint32', + 'guint32', + 'file', + 'qword' + + ); + TypesGTypes: array [0..CTypesMax-1] of string = + ( + 'gpointer', + 'int', + 'gint', + 'guint', + 'guint8', + 'guint16', + 'guint32', + 'guint64', + 'gint8', + 'gint16', + 'gint32', + 'gint64', + 'gsize', + 'glong', + 'gulong', + 'gushort', + 'gchar', + 'gboolean', + 'gssize', + 'size_t' , + 'gconstpointer', + 'gfloat', + 'gdouble', + 'double', + 'char', + 'goffset', + 'long double', + 'gunichar', + 'gunichar2', + 'file', + 'unsigned long long' + ); + + function LookupGTypeToCType(AName: String): String; + + + +implementation + +function LookupGTypeToCType(AName: String): String; +var + i: Integer; +begin + //WriteLn('Looking up: ', AName); + for i := 0 to CTypesMax-1 do + if AName = TypesGTypes[i] then + Exit(TypesPascalCTypes[i]); + Result := ''; +end; + +end. + diff --git a/applications/gobject-introspection/girerrors.pas b/applications/gobject-introspection/girerrors.pas new file mode 100644 index 000000000..099b2f040 --- /dev/null +++ b/applications/gobject-introspection/girerrors.pas @@ -0,0 +1,79 @@ +{ +girerrors.pas +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +unit girErrors; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils; + +type + TGirError = (geError, geWarn, geInfo, geDebug, geFatal, geFuzzy); + + TgirErrorFunc = procedure(UserData: Pointer; AType: TgirError; AMsg: String); + + const + geUnhandledNode = 'Unhandled node [%s] "%s"'; + geUnexpectedNodeType = 'Unexpected node [%s] type: found "%s" expected "%s"'; + geMissingNode = '[%s] Could not find child node "%s" while looking in node "%s"'; + + var + girErrorName: array[TGirError] of String =( + 'Error', + 'Warning', + 'Info', + 'Debug', + 'Fatal', + 'Fuzzy' + ); + procedure girError(AType: TgirError; AMsg: String); + + //returns old handler + function girSetErrorHandler(AHandler: TgirErrorFunc; AUserData: Pointer): TgirErrorFunc; + +implementation + +var + UserData: Pointer; + InternalHandler: TgirErrorFunc; + +procedure girError(AType: TgirError; AMsg: String); +begin + if InternalHandler <> nil then + begin + InternalHandler(UserData, AType, AMsg); + Exit; + end; + // if AType = geDebug then + //WriteLn(girErrorName[AType],': ', AMsg); + +end; + +function girSetErrorHandler(AHandler: TgirErrorFunc; AUserData: Pointer + ): TgirErrorFunc; +begin + Result := InternalHandler; + InternalHandler:=AHandler; + UserData:=AUserData; +end; + +end. + diff --git a/applications/gobject-introspection/girfiles.pas b/applications/gobject-introspection/girfiles.pas new file mode 100644 index 000000000..36d404441 --- /dev/null +++ b/applications/gobject-introspection/girfiles.pas @@ -0,0 +1,149 @@ +{ +girfiles.pas +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +unit girFiles; + +{$mode objfpc}{$H+} +{$INTERFACES CORBA} + +interface + +uses + Classes, SysUtils, XMLRead, DOM, girNameSpaces, girParser; + +type + + { TgirFile } + + TgirFile = class(IgirParser) + private + FNameSpaces: TgirNamespaces; + FOnNeedGirFile: TgirNeedGirFileEvent; + FOwner: TObject; + procedure ParseNode(ANode: TDomNode); + procedure SetOnNeedGirFile(AValue: TgirNeedGirFileEvent); + procedure SetOwner(const AValue: TObject); + procedure ParseIncludeNode(ANode: TDomNode; AIncludes: TList); + public + constructor Create(AOwner: TObject); + destructor Destroy; override; + procedure ParseXMLDocument(AXML: TXMLDocument); + property NameSpaces: TgirNamespaces read FNameSpaces; + property Owner: TObject read FOwner write SetOwner; + property OnNeedGirFile: TgirNeedGirFileEvent read FOnNeedGirFile write SetOnNeedGirFile; + + end; + +implementation +uses girErrors, girTokens; + +{ TgirFile } + + +{ TgirFile } + +procedure TgirFile.ParseNode(ANode: TDomNode); +var + NS: TgirNamespace; + Includes: TList; +begin + if ANode.NodeName <> 'repository' then + girError(geError, 'Not a Valid Document Type!'); + + ANode := Anode.FirstChild; + Ns := nil; + Includes := TList.Create; + + while ANode <> nil do begin + case GirTokenNameToToken(ANode.NodeName) of + gtInclude: ParseIncludeNode(ANode, Includes); + gtNameSpace: + begin + NS := TgirNamespace.CreateFromNamespaceNode(NameSpaces, ANode, Includes); + girError(geDebug, 'Adding Namespace '+NS.NameSpace+' to NameSpaces'); + FNameSpaces.Add(NS); + girError(geDebug, 'Added Namespace '+NS.NameSpace); + NS.ParseNode(ANode); + end; + gtPackage, gtCInclude: ;// ignore for now + else + girError(geDebug, 'Unknown Node Type for Reposiotory: '+ Anode.NodeName); + end; + ANode := ANode.NextSibling; + end; + + + + {ANode := ANode.FindNode('namespace'); + if ANode = nil then + girError(geError, 'namespace node not found') + else + begin + + end;} +end; + +procedure TgirFile.SetOnNeedGirFile(AValue: TgirNeedGirFileEvent); +begin + FNameSpaces.OnNeedGirFile:=AValue; + if FOnNeedGirFile=AValue then Exit; + FOnNeedGirFile:=AValue; +end; + +procedure TgirFile.SetOwner(const AValue: TObject); +begin + if FOwner=AValue then exit; + FOwner:=AValue; +end; + +procedure TgirFile.ParseIncludeNode(ANode: TDomNode; AIncludes: TList); +var + NS: TgirNamespace; + NSName, NSVersion: String; +begin + NSName := TDOMElement(ANode).GetAttribute('name'); + NSVersion := TDOMElement(ANode).GetAttribute('version'); + NS := FNameSpaces.FindNameSpace(NSName, NSVersion); + if NS <> nil then + begin + AIncludes.Add(NS); + end; +end; + + +constructor TgirFile.Create(AOwner: TObject); +begin + Owner := AOwner; + FNameSpaces := TgirNamespaces.Create(Self); +end; + +destructor TgirFile.Destroy; +begin + FNameSpaces.Free; + inherited Destroy; +end; + +procedure TgirFile.ParseXMLDocument(AXML: TXMLDocument); +begin + Self.ParseNode(AXML.DocumentElement); +end; + + + +end. + diff --git a/applications/gobject-introspection/girnamespaces.pas b/applications/gobject-introspection/girnamespaces.pas new file mode 100644 index 000000000..f67ca91c9 --- /dev/null +++ b/applications/gobject-introspection/girnamespaces.pas @@ -0,0 +1,539 @@ +{ +girnamespaces.pas +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +unit girNameSpaces; + +{$mode objfpc}{$H+} +{$INTERFACES CORBA} + +interface + +uses + Classes, DOM, girParser, girTokens, girObjects, contnrs; + +type + + TgirNeedGirFileEvent = function (AGirFile: TObject; BaseNamespaceName: String) : TXMLDocument of object; + + { TgirNamespace } + + TgirNamespace = class(IgirParser) + private + FConstants: TList; + FFunctions: TList; + FNameSpace: String; + FOnlyImplied: Boolean; + FOnNeedGirFile: TgirNeedGirFileEvent; + FOwner: TObject; + FRequiredNameSpaces: TList; + FSharedLibrary: String; + FTypes: TFPHashObjectList; + FUnresolvedTypes: TList; + FVersion: String; + procedure SetOnNeedGirFile(AValue: TgirNeedGirFileEvent); + protected + function AddFuzzyType(AName: String; ACType: String): TGirBaseType; + procedure HandleAlias(ANode: TDomNode); + procedure HandleConstant(ANode: TDomNode); + procedure HandleEnumeration(ANode: TDomNode); + procedure HandleBitField(ANode: TDomNode); + procedure HandleCallback(ANode: TDOMNode); + procedure HandleFunction(ANode: TDOMNode); + procedure HandleUnion(ANode: TDOMNode); + { + Some 'records' have methods these corelate to pascal 'object' + GType extends this 'object' type to have a sort of vmt + GObject and subclasses extend gtype and adds more vmt method entries and method entries to the instance itself. + } + procedure HandleRecord(ANode: TDomNode); //could be struct, object, gtype, gobject, or gobject descendant + procedure HandlePlainObject(ANode: TDomNode); // is a record/object with methods but no gtype + procedure HandleGType(ANode: TDomNode); // one step above plain object + procedure HandleClassStruct(ANode: TDomNode); // one step above GType. Is the 'Virtual' part of an object (VMT) + procedure HandleClass(ANode: TDomNode); // one step above GType. Is the object structure and it's methods. ClassStruct is like the VMT + procedure HandleInterface(ANode: TDomNode); + procedure AddGLibBaseTypes; + public + function LookupTypeByName(AName: String; const ACType: String; const SearchOnly: Boolean = False): TGirBaseType; + function ResolveFuzzyType(AFuzzyType: TgirFuzzyType): TGirBaseType; + function UsesGLib: Boolean; + procedure ResolveFuzzyTypes; // called after done + procedure ParseNode(ANode: TDomNode); + procedure ParseSubNode(ANode: TDomNode); // generally do not use outside of TgirNameSpace + constructor Create(AOwner:TObject; AImpliedNamespace: String); + constructor CreateFromNamespaceNode(AOwner:TObject; ANode: TDOMNode; AIncludes: TList); + destructor Destroy; override; + property NameSpace: String read FNameSpace; + property RequiredNameSpaces: TList Read FRequiredNameSpaces; + property SharedLibrary: String read FSharedLibrary; + property Version: String read FVersion; + property OnlyImplied: Boolean read FOnlyImplied; + property Owner: TObject Read FOwner; + + // has all types in it (records classes classstructs bitfields callbacks gtypes unions etc) does not contain consts or functions + property Types: TFPHashObjectList read FTypes; + + property Functions: TList read FFunctions; + property Constants: TList read FConstants; + property UnresolvedTypes: TList read FUnresolvedTypes write FUnresolvedTypes; + end; + + { TgirNamespaces } + + TgirNamespaces = class(TList) + private + FOnNeedGirFile: TgirNeedGirFileEvent; + FOwner: TObject; + function GetNameSpace(AIndex: Integer): TgirNamespace; + procedure SetNameSpace(AIndex: Integer; const AValue: TgirNamespace); + procedure SetOnNeedGirFile(AValue: TgirNeedGirFileEvent); + public + constructor Create(AOwner: TObject); + function FindNameSpace(AName: String; Version: String = ''): TgirNamespace; + property NameSpace[AIndex: Integer]: TgirNamespace read GetNameSpace write SetNameSpace; + property Owner: TObject read FOwner; + property OnNeedGirFile: TgirNeedGirFileEvent read FOnNeedGirFile write SetOnNeedGirFile; + end; + +implementation +uses + girErrors, SysUtils, girCTypesMapping; + +{ TgirNamespaces } + +function TgirNamespaces.GetNameSpace(AIndex: Integer): TgirNamespace; +begin + Result := TgirNamespace(Items[AIndex]); +end; + +procedure TgirNamespaces.SetNameSpace(AIndex: Integer; + const AValue: TgirNamespace); +begin + Items[AIndex] := AValue; +end; + +procedure TgirNamespaces.SetOnNeedGirFile(AValue: TgirNeedGirFileEvent); +begin + if FOnNeedGirFile=AValue then Exit; + FOnNeedGirFile:=AValue; +end; + +constructor TgirNamespaces.Create(AOwner: TObject); +begin + FOwner := AOwner; + inherited Create; +end; + +function TgirNamespaces.FindNameSpace(AName: String; Version: String=''): TgirNamespace; +var + i: Integer; + NameSpaceSearchedFor: Boolean; + Doc: TXMLDocument; +begin + Result := nil; + NameSpaceSearchedFor := False; + while Result = nil do + begin + for i := 0 to Count-1 do + begin + if NameSpace[i].NameSpace = AName then + Exit(NameSpace[i]); + end; + + if NameSpaceSearchedFor then + Exit; + NameSpaceSearchedFor := True; + if Assigned(FOnNeedGirFile) then + begin + Doc := FOnNeedGirFile(Owner, AName+'-'+Version); + if Doc <> nil then + begin + (Owner as IgirParser).ParseNode(Doc.DocumentElement); + Doc.Free; + end; + end; + end; +end; + +{ TgirNamespace } + +procedure TgirNamespace.ParseNode(ANode: TDomNode); + +begin + ANode := ANode.FirstChild; + while ANode <> nil do + begin + //girError(geDebug, 'Parsing Node "'+ANode.NodeName+'"'); + ParseSubNode(ANode); + ANode := ANode.NextSibling; + end; +end; + +procedure TgirNamespace.SetOnNeedGirFile(AValue: TgirNeedGirFileEvent); +begin + if FOnNeedGirFile=AValue then Exit; + FOnNeedGirFile:=AValue; +end; + +function TgirNamespace.AddFuzzyType(AName: String; ACType: String + ): TGirBaseType; +begin + Result := TgirFuzzyType.Create(Self, AName, ACType); + FTypes.Add(AName, Result); + FUnresolvedTypes.Add(Result); +end; + +procedure TgirNamespace.HandleAlias(ANode: TDomNode); +var + Item: TgirAlias; +begin + Item := TgirAlias.Create(Self, ANode); + Types.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleConstant(ANode: TDomNode); +var + Item: TgirConstant; +begin + Item := TgirConstant.Create(Self, ANode); + FConstants.Add(Item); +end; + +procedure TgirNamespace.HandleEnumeration(ANode: TDomNode); +var + Item : TgirEnumeration; +begin + Item := TgirEnumeration.Create(Self, ANode); + Types.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleBitField(ANode: TDomNode); +var + Item : TgirBitField; +begin + Item := TgirBitField.Create(Self, ANode); + Types.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleCallback(ANode: TDOMNode); +var + Item: TgirCallback; +begin + Item := TgirCallback.Create(Self, ANode); + Types.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleFunction(ANode: TDOMNode); +var + Item: TgirFunction; +begin + Item := TgirFunction.Create(Self, ANode); + Functions.Add(Item); +end; + +procedure TgirNamespace.HandleUnion(ANode: TDOMNode); +var + Item: TgirUnion; +begin + Item := TgirUnion.Create(Self, ANode); + Types.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleRecord(ANode: TDomNode); +var + Item: tgirRecord; +begin + if TDOMElement(ANode).GetAttribute('glib:is-gtype-struct-for') <> '' then // is gobject class + begin + HandleClassStruct(ANode); + end + else if TDOMElement(ANode).GetAttribute('glib:get-type') <> '' then // is GType + HandleGType(ANode) + else if (ANode.FindNode('method') <> nil) or (ANode.FindNode('constructor') <> nil) or (ANode.FindNode('function') <> nil) then // is Plain object that is not gtype + HandlePlainObject(ANode) + else + begin + Item := tgirRecord.Create(Self, ANode); + Types.Add(Item.Name, Item); + end; + +end; + +procedure TgirNamespace.HandlePlainObject(ANode: TDomNode); +var + Item: TgirObject; +begin + Item := TgirObject.Create(Self, ANode); + Types.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleGType(ANode: TDomNode); +var + Item: TgirGType; +begin + Item := TgirGType.Create(Self, ANode); + Types.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleClassStruct(ANode: TDomNode); +var + Item: TgirClassStruct; +begin + Item := TgirClassStruct.Create(Self, ANode); + FTypes.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleClass(ANode: TDomNode); +var + Item: TgirClass; +begin + Item := TgirClass.Create(Self, ANode); + FTypes.Add(Item.Name, Item); +end; + +procedure TgirNamespace.HandleInterface(ANode: TDomNode); +var + Item: TgirInterface; +begin + Item := TgirInterface.Create(Self, ANode); + FTypes.Add(Item.Name, Item); +end; + +procedure TgirNamespace.AddGLibBaseTypes; + procedure AddNativeTypeDef(GType: String; PascalCName: String); + var + NativeType: TgirNativeTypeDef; + begin + NativeType:= TgirNativeTypeDef.Create(Self, GType, PascalCName); + Types.Add(NativeType.Name, NativeType); + end; +var + i: Integer; +begin + for i := 0 to CTypesMax-1 do + AddNativeTypeDef(TypesGTypes[i], TypesPascalCTypes[i]); +end; + +procedure TgirNamespace.ResolveFuzzyTypes; +var + i: Integer; + FuzzyI: Integer; + Fuzzy: TgirFuzzyType; + Tmp: TGirBaseType; +begin + i:= 0; + FuzzyI := 0; + Fuzzy := nil; + while (i < FTypes.Count) or (Fuzzy <> nil) do + begin + // make our loop safe + if i >= FTypes.Count then + begin + i := FuzzyI+1; + Fuzzy := nil; + continue; + end; + + Tmp := TGirBaseType(FTypes.Items[i]); + + if Fuzzy <> nil then + begin + if {(Tmp.CType = Fuzzy.CType) or} (Tmp.Name = Fuzzy.Name) then + begin + Fuzzy.ResolvedType := Tmp; + Tmp.ImpliedPointerLevel:=Fuzzy.ImpliedPointerLevel; + i := FuzzyI+1; + Fuzzy := nil; + //WriteLn('Resolved Fuzzy Type: ', Tmp.CType); + continue; + end; + end; + + if (Fuzzy = nil) and (Tmp.ObjectType = otFuzzyType) and (TgirFuzzyType(Tmp).ResolvedType = nil) then + begin + if i >= FTypes.Count then + break; + FuzzyI:=i; + Fuzzy := TgirFuzzyType(Tmp); + //WriteLn('Looking For: ',Fuzzy.CType); + end; + inc(i); + end; + +end; + +procedure TgirNamespace.ParseSubNode(ANode: TDomNode); +begin + case GirTokenNameToToken(ANode.NodeName) of + gtAlias: HandleAlias(ANode); + gtConstant: HandleConstant(ANode); + gtRecord: HandleRecord(ANode); + gtBitField: HandleBitField(ANode); + gtEnumeration: HandleEnumeration(ANode); + gtCallback: HandleCallback(ANode); + gtUnion: HandleUnion(ANode); + gtFunction: HandleFunction(ANode); + gtClass: HandleClass(ANode); + gtInterface: HandleInterface(ANode); + gtMethod: HandleFunction(ANode); + else + girError(geError, 'Unknown NodeType: '+ANode.NodeName); + end; + ResolveFuzzyTypes; +end; + +function TgirNamespace.LookupTypeByName(AName: String; const ACType: String; const SearchOnly: Boolean = False): TGirBaseType; + function StripPointers(ACPointeredType: String; PtrLevel: PInteger = nil): String; + var + i: Integer; + begin + for i := Length(ACPointeredType) downto 1 do + if ACPointeredType[i] = '*' then + begin + Delete(ACPointeredType, i, 1); + end; + if PtrLevel <> nil then + Inc(PtrLevel^); + Result := ACPointeredType; + end; + +var + ReqNS, + NS: TgirNamespace; + NSString: String; + FPos: Integer; + i: Integer; + Current: TGirBaseType; + PointerLevel: Integer = 0; + PlainCType: String; +begin + Result := nil; + NS := Self; + FPos := Pos('.', AName); + PlainCType:=StringReplace(StripPointers(ACType, @PointerLevel), ' ', '_', [rfReplaceAll]); + + if FPos > 0 then // type includes namespace "NameSpace.Type" + begin + NSString:=Copy(AName,1,FPos-1); + NS := (Owner As TgirNamespaces).FindNameSpace(NSString); + if NS = nil then + girError(geError, 'Referenced Namespace "'+NSString+'" not found while looking for '+AName); + AName := Copy(AName, FPos+1, Length(AName)); + end; + + // some basic fixes + if PlainCType = 'gchar' then + AName := 'utf8'; + + if PlainCType = 'GType' then + AName := 'Type'; + + Result := TGirBaseType(NS.Types.Find(AName)); + if (Result <> nil) and (Result.ObjectType = otFuzzyType) and (TgirFuzzyType(Result).ResolvedType <> nil) then + Result := TgirFuzzyType(Result).ResolvedType; + + if (Result = nil) and not SearchOnly then + begin + for i := 0 to NS.RequiredNameSpaces.Count-1 do + begin + ReqNS := TgirNamespace(NS.RequiredNameSpaces.Items[i]); + Current := ReqNS.LookupTypeByName(AName, ACType, True); + if Current <> nil then + begin + if (Current.ObjectType = otFuzzyType) and (TgirFuzzyType(Current).ResolvedType <> nil) then + Current := TgirFuzzyType(Current).ResolvedType; + Result := Current; + Break; + end; + end; + if Result = nil then + Result := NS.AddFuzzyType(AName, ACType); + end; + if Result <> nil then + Result.ImpliedPointerLevel:=PointerLevel; +end; + +function TgirNamespace.ResolveFuzzyType(AFuzzyType: TgirFuzzyType): TGirBaseType; +var + i: Integer; +begin + for i := 0 to FTypes.Count-1 do + begin + if (TGirBaseType(FTypes[i]) <> AFuzzyType) and (TGirBaseType(FTypes[i]).Name = AFuzzyType.Name) then + Exit(TGirBaseType(FTypes[i])); + end; +end; + +function TgirNamespace.UsesGLib: Boolean; +var + Tmp: Pointer; + NS: TgirNamespace absolute Tmp; +begin + Result := False; + if Pos('glib', LowerCase(NameSpace)) = 1 then + Exit(True); + for Tmp in RequiredNameSpaces do + if Pos('glib',LowerCase(NS.NameSpace)) = 1 then + Exit(True); +end; + +constructor TgirNamespace.Create(AOwner:TObject; AImpliedNamespace: String); +begin + Fowner:=AOwner; + FOnlyImplied:=True; + FNameSpace:=AImpliedNamespace; + girError(geDebug, 'Creating Stub for namespace: '+ AImpliedNamespace); +end; + +constructor TgirNamespace.CreateFromNamespaceNode(AOwner:TObject; ANode: TDOMNode; AIncludes: TList); +var + Node: TDOMElement absolute ANode; +begin + FOwner := AOwner; + if ANode = nil then + girError(geError, 'expected namespace got nil'); + if ANode.NodeName <> 'namespace' then + girError(geError, 'expected namespace got '+ANode.NodeName); + FNameSpace:=Node.GetAttribute('name'); + FRequiredNameSpaces := AIncludes; + FSharedLibrary:=Node.GetAttribute('shared-library'); + FVersion:=Node.GetAttribute('version'); + girError(geDebug, Format('Creating namespace=%s Version=%s LibName=%s',[FNameSpace, FVersion, FSharedLibrary])); + + FConstants := TList.Create; + FFunctions := TList.Create; + FTypes := TFPHashObjectList.Create(True); + FUnresolvedTypes := TList.Create; + + if FNameSpace = 'GLib' then + AddGLibBaseTypes; +end; + +destructor TgirNamespace.Destroy; +begin + FConstants.Free; + FFunctions.Free; + FTypes.Free; + FUnresolvedTypes.Free; + if Assigned(FRequiredNameSpaces) then + FRequiredNameSpaces.Free; + + inherited Destroy; +end; + +end. + diff --git a/applications/gobject-introspection/girobjects.pas b/applications/gobject-introspection/girobjects.pas new file mode 100644 index 000000000..e3270911c --- /dev/null +++ b/applications/gobject-introspection/girobjects.pas @@ -0,0 +1,1048 @@ +{ +girobjects.pas +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +unit girObjects; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, DOM, girTokens; + +type + + TGirModeState = (msNone, msWriting, msWritten); + + TGirObjectType = (otBaseType, otAlias, otArray, otBitfield, otCallback, otClass, + otClassStruct, otConstant, otConstructor, otEnumeration, otFunction, + otFunctionReturn, otFunctionParam, otFuzzyType, otGlibSignal, + otGType, otInterface, otMethod, otNativeType, otObject, otProperty, + otRecord, otTypeParam, otUnion, otVirtualMethod); + + { TGirBaseType } + + TGirBaseType = class + private + FBits: Integer; + FCType: String; + FDoc: String; + FForwardDefinitionWritten: Boolean; + FImpliedPointerLevel: Integer; + FName: String; + FObjectType: TGirObjectType; + FOwner: TObject; + FTranslatedName: String; + FVersion: String; + FWriting: TGirModeState; + procedure SetImpliedPointerLevel(AValue: Integer); + public + constructor Create(AOwner: TObject; ANode: TDomNode); virtual; + property CType: String read FCType write FCType; + property Name: String read FName; + property TranslatedName: String read FTranslatedName write FTranslatedName; + property ImpliedPointerLevel: Integer read FImpliedPointerLevel write SetImpliedPointerLevel; // only grows + property Owner: TObject Read FOwner; // TgirNameSpace + property Doc: String read FDoc; + property Bits: Integer read FBits; + property Version: String read FVersion; + property ForwardDefinitionWritten: Boolean read FForwardDefinitionWritten write FForwardDefinitionWritten; + property Writing: TGirModeState read FWriting write FWriting; + property ObjectType: TGirObjectType read FObjectType; + end; + + { TgirNativeTypeDef } + + TgirNativeTypeDef = class(TGirBaseType) + private + FPAs: String; + FPascalName: String; + public + constructor Create(AOwner:TObject; AGType: String; APascalCTypeName: String); + property PascalName: String read FPascalName write FPascalName; + end; + + { TgirFuzzyType } + + TgirFuzzyType = class(TGirBaseType) + private + FResolvedType: TGirBaseType; + function GetResolvedType: TGirBaseType; + procedure SetResolvedType(const AValue: TGirBaseType); + public + constructor Create(AOwner: TObject; AName: String; ACtype: String); + property ResolvedType: TGirBaseType read GetResolvedType write SetResolvedType; + end; + + { TgirAlias } + + TgirAlias = class(TGirBaseType) + private + FForType: TGirBaseType; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + property ForType: TGirBaseType read FForType; + end; + + { TgirTypeParam } + + TgirTypeParam = class(TGirBaseType) + private + FVarType: TGirBaseType; + FPointerLevel: Integer; + function GetPointerLevel: Integer; + function GetType: TGirBaseType; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + property VarType: TGirBaseType read GetType; + property PointerLevel: Integer read GetPointerLevel; + end; + + { TgirProperty } + + TgirProperty = class(TgirBaseType) + private + FIsArray: Boolean; + FPropType: TgirBaseType; + FWriteable: Boolean; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + property PropType: TgirBaseType read FPropType; + property Writable: Boolean read FWriteable; + property IsArray: Boolean read FIsArray; + end; + + { TgirArray } + + TgirArray = class(TgirTypeParam) + private + FFixedSize: Integer; + FParentFieldName: String; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + property FixedSize: Integer read FFixedSize; + property ParentFieldName: String read FParentFieldName; + end; + + { TgirConstant } + + TgirConstant = class(TGirBaseType) + private + FIsString: Boolean; + FTypeDecl: TGirBaseType; + FValue: String; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + property TypeDecl: TGirBaseType read FTypeDecl; + property Value: String read FValue; + property IsString: Boolean read FIsString; + end; + + { TgirEnumeration } + PgirEnumMember = ^TgirEnumMember; + TgirEnumMember = record + Name: String; + Value: String; + CIdentifier: String; + end; + + { TgirEnumList } + + TgirEnumList = class(TList) + private + function GetMember(AIndex: Integer): PgirEnumMember; + public + procedure Delete(Index: Integer); + property Member[AIndex: Integer]: PgirEnumMember read GetMember; + end; + + + TgirEnumeration = class(TGirBaseType) + private + FMembers: TgirEnumList; + procedure AddMember(AName, AValue, ACIdentifier: String); + procedure HandleFunction(ANode: TDomNode); + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + destructor Destroy; override; + property Members: TgirEnumList read FMembers; + end; + + { TgirBitField } + + TgirBitField = class(TgirEnumeration) + constructor Create(AOwner: TObject; ANode: TDomNode); override; + + end; + + { TGirFunctionParam } + + TGirFunctionParam = class(TgirTypeParam) + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + end; + + { TgirFunctionReturn } + + TgirFunctionReturn = class(TgirTypeParam) + constructor Create(AOwner: TObject; ANode: TDomNode); override; + end; + + { TgirParamList } + + TgirParamList= class (TList) + private + function GetParam(AIndex: Integer): TGirFunctionParam; + public + property Param[AIndex: Integer]: TGirFunctionParam read GetParam; + end; + + { TgirFunction } + + TgirFunction = class(TGirBaseType) + private + FCIdentifier: String; + FDeprecated: Boolean; + FDeprecatedVersion: String; + FParams: TgirParamList; + FReturns: TgirFunctionReturn; + publiC + constructor Create(AOwner: TObject; ANode: TDomNode); override; + destructor Destroy; override; + property Params: TgirParamList read FParams; + property Returns: TgirFunctionReturn read FReturns; + property CIdentifier: String read FCIdentifier; + property Deprecated: Boolean read FDeprecated; + property DeprecatedVersion: String read FDeprecatedVersion; + end; + + { TgirMethod } + + TgirMethod = class(TgirFunction) + constructor Create(AOwner: TObject; ANode:TDOMNode); override; + end; + + { TgirGlibSignal } + + TgirGlibSignal = class(TgirFunction) + constructor Create(AOwner: TObject; ANode:TDOMNode); override; + + end; + + { TgirVirtualMethod } + + TgirVirtualMethod = class(TgirMethod) + constructor Create(AOwner: TObject; ANode:TDOMNode); override; + end; + + { TgirCallback } + + TgirCallback = class(TgirFunction) + constructor Create(AOwner: TObject; ANode: TDomNode); override; + //property OwnsResult: Boolean; + end; + + { TgirConstructor } + + TgirConstructor = class(TgirFunction) + constructor Create(AOwner: TObject; ANode:TDOMNode); override; + end; + + { TgirFieldsList } + + TgirFieldsList = class(TFPList) + private + function GetField(AIndex: Integer): TGirBaseType; + public + property Field[AIndex: Integer]: TGirBaseType read GetField; + end; + + { tgirRecord } + + TgirRecord = class(TGirBaseType) + private + FFields: TgirFieldsList; + protected + procedure HandleUnion(ANode: TDomNode); + procedure HandleField(ANode: TDomNode); + procedure ParseNode(ANode: TDomNode; ANodeType: TGirToken); virtual; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + destructor Destroy; override; + property Fields: TgirFieldsList read FFields; + end; + + { TgirUnion } + + TgirUnion = class(TgirRecord) + constructor Create(AOwner: TObject; ANode: TDomNode); override; + procedure ParseNode(ANode: TDomNode; ANodeType: TGirToken); override; + end; + + + { TgirObject } + + TgirObject = class(TgirRecord) + protected + procedure ParseNode(ANode: TDomNode; ANodeType: TGirToken); override; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + end; + + { TgirGType } + + TgirGType = class(TgirObject) + private + FGetTypeFunction: String; + protected + procedure ParseNode(ANode: TDomNode; ANodeType: TGirToken); override; + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + property GetTypeFunction: String read FGetTypeFunction; + end; + + { TgirClass } + + { TgirClassStruct } + + TgirClassStruct = class(TgirGType) + constructor Create(AOwner: TObject; ANode: TDomNode); override; + + end; + + TgirClass = class(TgirGType) + private + FClassStruct: TgirClassStruct; + FInterfaces: TList; + FParentClass: TgirClass; + function GetParentClass: TgirClass; + protected + procedure ParseNode(ANode: TDomNode; ANodeType: TGirToken); override; + procedure AddInterface(ANode: TDomNode); + public + constructor Create(AOwner: TObject; ANode: TDomNode); override; + destructor Destroy; override; + property Interfaces: TList read FInterfaces; + property ParentClass: TgirClass read GetParentClass; + property ClassStruct: TgirClassStruct read FClassStruct; + + end; + + { TgirInterface } + + TgirInterface = class(TgirClass) + protected + constructor Create(AOwner: TObject; ANode: TDomNode); override; + procedure ParseNode(ANode: TDomNode; ANodeType: TGirToken); override; + end; + + + + + + +implementation +uses girNameSpaces, girErrors; + +{ TgirClassStruct } + +constructor TgirClassStruct.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otClassStruct; +end; + +{ TgirConstructor } + +constructor TgirConstructor.Create(AOwner: TObject; ANode: TDOMNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otConstructor; +end; + +{ TgirCallback } + +constructor TgirCallback.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otCallback; +end; + +{ TgirVirtualMethod } + +constructor TgirVirtualMethod.Create(AOwner: TObject; ANode: TDOMNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otVirtualMethod; +end; + +{ TgirGlibSignal } + +constructor TgirGlibSignal.Create(AOwner: TObject; ANode: TDOMNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otGlibSignal; +end; + +{ TgirMethod } + +constructor TgirMethod.Create(AOwner: TObject; ANode: TDOMNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otMethod; +end; + +{ TgirBitField } + +constructor TgirBitField.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otBitfield; +end; + +{ TgirFieldsList } + +function TgirFieldsList.GetField(AIndex: Integer): TGirBaseType; +begin + Result := TGirBaseType(Items[AIndex]); +end; + +{ TgirParamList } + +function TgirParamList.GetParam(AIndex: Integer): TGirFunctionParam; +begin + Result := TGirFunctionParam(Items[AIndex]); +end; + +constructor TgirNativeTypeDef.Create(AOwner:TObject; AGType: String; APascalCTypeName: String); +begin + FOwner := AOwner; + FCType:=AGType; + FName:=AGType; // used by LookupName in namespace + //now some fixups :( + if FName = 'gchar' then + FName := 'utf8'; + FTranslatedName:=AGType; + FPascalName:=APascalCTypeName; + //to create PPType + FImpliedPointerLevel:=2; + FObjectType:=otNativeType; +end; + +{ TgirNativeTypeDef } + + +{ TgirInterface } + +constructor TgirInterface.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otInterface; +end; + +procedure TgirInterface.ParseNode(ANode: TDomNode; ANodeType: TGirToken); +begin + case ANodeType of + gtPrerequisite:; // ignore for now since these are bindings. + //The interface expects the implementing object to be a descendant of the prerequisite + else + inherited ParseNode(ANode, ANodeType); + + end; +end; + +{ TgirProperty } + +constructor TgirProperty.Create(AOwner: TObject; ANode: TDomNode); +var + Node: TDOMElement; +begin + inherited Create(AOwner, ANode); + FWriteable := (TDOMElement(ANode).GetAttribute('writable') = '1'); + Node := TDomElement(ANode.FirstChild); + while Node <> nil do + begin + case GirTokenNameToToken(Node.NodeName) of + gtDoc:; // ignore + gtType: FPropType := TgirNamespace(Owner).LookupTypeByName(Node.GetAttribute('name'), Node.GetAttribute('c:type')); + gtArray: + begin + FIsArray:=True; + FPropType := TgirNamespace(Owner).LookupTypeByName(TDomElement(Node.FindNode('type')).GetAttribute('name'), Node.GetAttribute('c:type')); + end + else + WriteLn('Unknown Node Type for property : ', Node.NodeName); + halt(1); + end; + Node := TDOMElement(Node.NextSibling); + end; + FObjectType:=otProperty; +end; + +{ TgirClass } + +function TgirClass.GetParentClass: TgirClass; +begin + if (FParentClass <> nil) and (FParentClass.InheritsFrom(TgirFuzzyType)) and (TgirFuzzyType(FParentClass).ResolvedType <> nil) then + FParentClass := TgirClass(TgirFuzzyType(FParentClass).ResolvedType); + Result := FParentClass; +end; + +procedure TgirClass.ParseNode(ANode: TDomNode; ANodeType: TGirToken); +begin + case ANodeType of + gtProperty: Fields.Add(TgirProperty.Create(Owner, ANode)); + gtVirtualMethod: Fields.Add(TgirVirtualMethod.Create(Owner, ANode)); + gtGlibSignal: Fields.Add(TgirGlibSignal.Create(Owner, ANode)); + gtImplements: AddInterface(ANode) + else + inherited ParseNode(ANode, ANodeType); + end; +end; + +procedure TgirClass.AddInterface(ANode: TDomNode); +var + Intf: TGirBaseType; + Node: TDOMElement absolute ANode; +begin + Intf := TgirNamespace(Owner).LookupTypeByName(Node.GetAttribute('name'), ''); + FInterfaces.Add(Intf); +end; + +constructor TgirClass.Create(AOwner: TObject; ANode: TDomNode); +var + Parent: String; +begin + FInterfaces := TList.Create; // must be before inherited else list does not exist when ParseNeode is called + inherited Create(AOwner, ANode); + Parent := TDOMElement(ANode).GetAttribute('parent'); + FParentClass := TgirClass(TgirNamespace(Owner).LookupTypeByName(Parent, '', True)); + if CType = '' then + CType := TDOMElement(ANode).GetAttribute('glib:type-name'); + FObjectType:=otClass; +end; + +destructor TgirClass.Destroy; +begin + FInterfaces.Free; + inherited Destroy; +end; + +{ TgirUnion } + +constructor TgirUnion.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otUnion; +end; + +procedure TgirUnion.ParseNode(ANode: TDomNode; ANodeType: TGirToken); +begin + case ANodeType of + gtRecord: Fields.Add(TgirRecord.Create(Owner, ANode)); + gtMethod: Fields.Add(TgirMethod.Create(Owner, ANode)); + gtConstructor: Fields.Add(TgirConstructor.Create(Owner, ANode)); + else + inherited ParseNode(ANode, ANodeType); + end; +end; + +{ TgirGType } + +procedure TgirGType.ParseNode(ANode: TDomNode; ANodeType: TGirToken); +begin + case ANodeType of + gtConstructor: Fields.Add(TgirConstructor.Create(Owner, ANode)); + //gtFunction: Fields.Add(TgirFunction.Create(Owner, ANode)); + else + inherited ParseNode(ANode, ANodeType); + end; +end; + +constructor TgirGType.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FGetTypeFunction := TDOMElement(ANode).GetAttribute('glib:get-type'); + FObjectType:=otGType; +end; + +{ TgirArray } + +constructor TgirArray.Create(AOwner: TObject; ANode: TDomNode); +var + Node: TDomELement; + Tmp: String; +begin + inherited Create(AOwner, ANode); + Node := TDomElement(ANode.FindNode('type')); + if Node <> nil then + begin + FVarType := TgirNamespace(Owner).LookupTypeByName(Node.GetAttribute('name'), CType); + TryStrToInt(TDomElement(ANode).GetAttribute('fixed-size'), FFixedSize); + end; + + Node := TDOMElement(ANode.ParentNode); + FParentFieldName := Node.GetAttribute('name'); + if FName = '' then + FName := FParentFieldName; + FObjectType:=otArray; +end; + +{ TgirObject } + +procedure TgirObject.ParseNode(ANode: TDomNode; ANodeType: TGirToken); +begin + case ANodeType of + //gtMethod: (Owner as TgirNamespace).ParseSubNode(ANode); + gtMethod: Fields.Add(TgirMethod.Create(Owner, ANode)); + else + inherited ParseNode(ANode, ANodeType); + end; +end; + +constructor TgirObject.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otObject; +end; + +{ tgirRecord } + + + + +procedure TgirRecord.HandleUnion(ANode: TDomNode); +var + Item: TgirUnion; +begin + Item := TgirUnion.Create(Owner, ANode); + FFields.Add(Item); +end; + +procedure TgirRecord.HandleField(ANode: TDomNode); +var + Node: TDOMNode; + attr: TDomNode; + Attrs: TDOMNamedNodeMap; + Item: TGirBaseType; +begin + Node := ANode.FirstChild; + while Node <> nil do + begin + Attrs := ANode.Attributes; + case GirTokenNameToToken(Node.NodeName) of + gtDoc:; + gtType: FFields.Add(TgirTypeParam.Create(Owner, ANode)); + gtCallback: FFields.Add(TgirCallback.Create(Owner, Node)); + gtArray: Fields.Add(TgirArray.Create(Owner, Node)); + else + girError(geError ,Format(geUnhandledNode,[ClassName, Node.NodeName])); + halt; + end; + Node := Node.NextSibling; + end; + +end; + +procedure tgirRecord.ParseNode(ANode: TDomNode; ANodeType: TGirToken); +var + NameStr: String; +begin + case ANodeType of + gtDoc:; + gtField : HandleField(ANode); + gtUnion: HandleUnion(ANode); + gtFunction: begin + //(Owner as TgirNamespace).ParseSubNode(ANode); + //we'll add it for now since it may be interesting to make this into an object later + Fields.Add(TgirFunction.Create(Owner, ANode)); + end + else + NameStr := TDOMElement(ANode).GetAttribute('name'); + girError(geWarn,Format(geUnhandledNode,[ClassName, ANode.ParentNode.Attributes.Item[0].NodeValue +' : >> '+ ANode.NodeName+' << '+ NameStr])); + end; +end; + +constructor tgirRecord.Create(AOwner: TObject; ANode: TDomNode); +var + Node: TDomNode; +begin + inherited Create(AOwner, ANode); + FFields := TgirFieldsList.Create; + {$warning not implemented} + Node := ANode.FirstChild; + while Node <> nil do + begin + ParseNode(Node, GirTokenNameToToken(Node.NodeName)); + Node := Node.NextSibling; + end; + FObjectType:=otRecord; +end; + +destructor tgirRecord.Destroy; +begin + FFields.Free; + inherited Destroy; +end; + +{ TgirFunctionReturn } + +constructor TgirFunctionReturn.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otFunctionReturn; +end; + +{ TGirFunctionParam } + +constructor TGirFunctionParam.Create(AOwner: TObject; ANode: TDomNode); +begin + inherited Create(AOwner, ANode); + FObjectType:=otFunctionParam; +end; + +{ TgirTypeParam } + +function TgirTypeParam.GetType: TGirBaseType; +begin + if (FVarType <> nil) and (FVarType.ClassType = TgirFuzzyType) and (TgirFuzzyType(FVarType).ResolvedType <> nil) then + begin + TgirFuzzyType(FVarType).ResolvedType.ImpliedPointerLevel:=FVarType.ImpliedPointerLevel; + FVarType := TgirFuzzyType(FVarType).ResolvedType; + end; + Result := FVarType; +end; + +function TgirTypeParam.GetPointerLevel: Integer; +var + i: Integer; +begin + Result := FPointerLevel; +end; + +procedure NodeURL(ANode: TDomNode); +var + URL: String = ''; +begin + while ANode <> nil do + begin + try + Url := '/'+ANode.NodeName+':'+TDOMElement(ANode).GetAttribute('name')+Url; + ANode := ANode.ParentNode; + + except + ANode := nil + end; + end; + WriteLn(URL); +end; + +constructor TgirTypeParam.Create(AOwner: TObject; ANode: TDomNode); + function PointerLevelFromVarName(AName: String): Integer; + var + C: Char; + begin + Result := 0; + for C in AName do + if C = '*' then + Inc(Result); + end; + +var + Node: TDOMElement; + C_Type: String; + Tmp: String; + Token: TGirToken; + VarTypeName: String; +begin + inherited Create(AOwner, ANode); + //NodeURL(ANode); + //Node := TDomELement(ANode.FindNode('type')); + Node := TDOMElement(ANode.FirstChild); + while Node <> nil do + begin + // it's one or the other + Token := GirTokenNameToToken(Node.NodeName); + case Token of + gtDoc:; + gtType: begin + C_Type := Node.GetAttribute('c:type'); + VarTypeName:=Node.GetAttribute('name'); + if VarTypeName = '' then + VarTypeName:= StringReplace(C_Type, '*', '', [rfReplaceAll]); + FVarType := TgirNamespace(Owner).LookupTypeByName(VarTypeName, C_Type); + end; + gtArray: begin + C_Type := Node.GetAttribute('c:type'); + FVarType := TgirNamespace(Owner).LookupTypeByName(TDOMElement(Node.FirstChild).GetAttribute('name'), C_Type); + Tmp := Node.GetAttribute('length'); + if Tmp <> '' then + FVarType.ImpliedPointerLevel:=StrToInt(Tmp); + end; + gtVarArgs: begin + FVarType := nil + end + else + girError(geError, Format(geUnexpectedNodeType,[ClassName, Node.NodeName, GirTokenName[gtParameter]])); + end; + Node := TDOMElement(Node.NextSibling); + end; + + + + FPointerLevel := PointerLevelFromVarName(C_Type); + + if (FVarType <> nil) {and (GirTokenNameToToken(ANode.NodeName) = gtArray)} then + FVarType.ImpliedPointerLevel := PointerLevelFromVarName(CType); + + if Token <> gtVarArgs then + FVarType.ImpliedPointerLevel:=PointerLevel; //only will grow + FObjectType:=otTypeParam; +end; + +{ TgirFunction } + +constructor TgirFunction.Create(AOwner: TObject; ANode: TDomNode); +var + Node: TDOMNode; + NodeToken: TGirToken; + + procedure CreateParameters(ANode: TDomNode); + var + PNode: TDomNode; + Param: TGirFunctionParam; + begin + PNode := ANode.FirstChild; + while PNode <> nil do + begin + case GirTokenNameToToken(PNode.NodeName) of + gtDoc:; + gtParameter: + begin + Param := TGirFunctionParam.Create(AOwner, PNode); + FParams.Add(Param); + end; + else + girError(geError, Format(geUnexpectedNodeType,[ClassName, PNode.NodeName, GirTokenName[gtParameter]])); + end; + PNode := PNode.NextSibling; + end; + end; + +begin + inherited Create(AOwner, ANode); + FParams := TgirParamList.Create; + FCIdentifier:=TDOMElement(ANode).GetAttribute('c:identifier'); + if FName = '' then FName:=FCIdentifier; + if FName = '' then FName:=StringReplace(FCType, '*', '', [rfReplaceAll]); + + NodeToken := GirTokenNameToToken(ANode.NodeName); + if not (NodeToken in [gtFunction, gtMethod, gtCallback, gtConstructor, gtVirtualMethod, gtGlibSignal]) then + begin + girError(geError, Format(geUnexpectedNodeType,[ClassName,ANode.NodeName, GirTokenName[gtFunction]+'", "'+ GirTokenName[gtMethod]+'", "'+ + GirTokenName[gtCallback]+'", "'+ GirTokenName[gtConstructor]+'", "'+ + GirTokenName[gtVirtualMethod]+'", "'+ GirTokenName[gtGlibSignal] ])); + Halt; + end; + + Node := ANode.FirstChild; + while Node <> nil do + begin + case GirTokenNameToToken(Node.NodeName) of + gtDoc:; + gtReturnValue: FReturns := TgirFunctionReturn.Create(AOwner, Node); + gtParameters: CreateParameters(Node); + else + girError(geWarn, Format(geUnhandledNode,[ClassName, Node.NodeName])); + end; + Node := Node.NextSibling; + end; + if FReturns = nil then + begin + WriteLn('Return value not defined for: ', Name); + Halt + end; + FDeprecated:=TDOMElement(ANode).GetAttribute('deprecated') <> ''; + if FDeprecated then + FDeprecatedVersion:=TDOMElement(ANode).GetAttribute('deprecated-version'); + FObjectType:=otFunction; +end; + +destructor TgirFunction.Destroy; +begin + FParams.Free; + inherited Destroy; +end; + +{ TgirEnumList } + +function TgirEnumList.GetMember(AIndex: Integer): PgirEnumMember; +begin + Result:= PgirEnumMember(Items[AIndex]); +end; + +procedure TgirEnumList.Delete(Index: Integer); +begin + Dispose(Member[Index]); + TList(Self).Delete(Index); +end; + +{ TgirEnumeration } + +procedure TgirEnumeration.AddMember(AName, AValue, ACIdentifier: String); +var + Member: PgirEnumMember; +begin + if ACIdentifier = 'GDK_DRAG_MOTION' then ACIdentifier := 'GDK_DRAG_MOTION_'; + if ACIdentifier = 'GDK_DRAG_STATUS' then ACIdentifier := 'GDK_DRAG_STATUS_'; + if ACIdentifier = 'GDK_PROPERTY_DELETE' then ACIdentifier := 'GDK_PROPERTY_DELETE_'; + + + New(Member); + Member^.Name:=AName; + Member^.Value:=AValue; + Member^.CIdentifier:=ACIdentifier; + FMembers.Add(Member); + //girError(geDebug, Format('Added Enum [%s] Member "%s" with value "%s"',[Name, AName, AValue])); +end; + +procedure TgirEnumeration.HandleFunction(ANode: TDomNode); +var + NS: TgirNamespace; +begin + NS := TgirNamespace(FOwner); + NS.ParseSubNode(ANode); + +end; + +constructor TgirEnumeration.Create(AOwner: TObject; ANode: TDomNode); +var + Node: TDOMElement; + NameStr: DOMString; +begin + inherited Create(AOwner, ANode); + FMembers := TgirEnumList.Create; + Node := TDOMElement(ANode.FirstChild); + while Node <> nil do + begin + case GirTokenNameToToken(Node.NodeName) of + gtDoc:; + gtMember: AddMember(Node.GetAttribute('name'), Node.GetAttribute('value'),Node.GetAttribute('c:identifier')); + // some enumerations seem to have functions part of them. They are only functions directly related to the enumeration and cannot be part of the enum + gtFunction: HandleFunction(Node); + else + NameStr := TDOMElement(Node).GetAttribute('name'); + girError(geWarn,Format(geUnhandledNode,[ClassName, Node.ParentNode.Attributes.Item[0].NodeValue +' : >> '+ Node.NodeName+' << '+ NameStr])); + //girError(geWarn,Format(geUnhandledNode, [ClassName, Node.NodeName])); + end; + Node := TDOMElement(Node.NextSibling); + end; + FObjectType:=otEnumeration; +end; + +destructor TgirEnumeration.Destroy; +begin + FMembers.Free; + inherited Destroy; +end; + +{ TgirConstant } + +constructor TgirConstant.Create(AOwner: TObject; ANode: TDomNode); +var + Node: TDOMElement; +begin + inherited Create(AOwner, ANode); + Node := TDomELement(ANode.FindNode('type')); + FTypeDecl := TgirNamespace(Owner).LookupTypeByName(Node.GetAttribute('name'), Node.GetAttribute('c:type')); + FValue:= TDOMElement(ANode).GetAttribute('value'); + FIsString:=Node.GetAttribute('c:type') = 'gchar*'; + //girError(geDebug, Format('Added constant "%s" with value "%s" of type "%s"',[Name, Value, FTypeDecl.Name])); + FObjectType:=otConstant; +end; + +{ TgirFuzzyType } + +function TgirFuzzyType.GetResolvedType: TGirBaseType; +begin + Result := FResolvedType; +end; + +procedure TgirFuzzyType.SetResolvedType(const AValue: TGirBaseType); +begin + if AValue = FResolvedType then + Exit; + FResolvedType := AValue; + //girError(geDebug, 'Resolved FuzzyType '+AValue.Name); +end; + +constructor TgirFuzzyType.Create(AOwner: TObject; AName: String; ACtype: String); +begin + FName:=AName; + FOwner := AOwner; + FCType:=ACtype; + FObjectType:=otFuzzyType; + //girError(geFuzzy, 'Creating Fuzzy Type "'+AName+'/'+ACtype+'"'); +end; + +{ TgirAlias } + +constructor TgirAlias.Create(AOwner: TObject; ANode: TDomNode); +var + Node: TDOMElement; +begin + inherited Create(AOwner, ANode); + Node := TDomELement(ANode.FindNode('type')); + FForType := TgirNamespace(Owner).LookupTypeByName(Node.GetAttribute('name'), Node.GetAttribute('c:type')); + FObjectType:=otAlias; +end; + +{ TGirBaseType } + +procedure TGirBaseType.SetImpliedPointerLevel(AValue: Integer); +begin + if FImpliedPointerLevel '' then + FBits := StrToInt(AttrValue); + Node := ANode.FindNode('doc'); + if Node <> nil then + FDoc := Node.FirstChild.TextContent; + ImpliedPointerLevel:=2; + FObjectType:=otBaseType; +end; + +end. + diff --git a/applications/gobject-introspection/girparser.pas b/applications/gobject-introspection/girparser.pas new file mode 100644 index 000000000..943ca8867 --- /dev/null +++ b/applications/gobject-introspection/girparser.pas @@ -0,0 +1,18 @@ +unit girParser; + +{$mode objfpc}{$H+} +{$INTERFACES CORBA} +interface + +uses + Classes, SysUtils, Dom; + +type + IgirParser = interface + procedure ParseNode(ANode: TDomNode); + end; + +implementation + +end. + diff --git a/applications/gobject-introspection/girpascalwriter.pas b/applications/gobject-introspection/girpascalwriter.pas new file mode 100644 index 000000000..1fb0550b5 --- /dev/null +++ b/applications/gobject-introspection/girpascalwriter.pas @@ -0,0 +1,1791 @@ +{ +girpascalwriter.pas +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +unit girpascalwriter; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, girNameSpaces, girObjects, girTokens, contnrs; + +type + TUnitWriteEvent = procedure (Sender: TObject; AUnitName: AnsiString; AStream: TStringStream) of object; + + { TgirPascalWriter } + + TgirPascalWriter = class + private + FOnUnitWriteEvent: TUnitWriteEvent; + FNameSpaces: TgirNamespaces; + FUnits: TList; + public + constructor Create(ANameSpaces: TgirNamespaces); + procedure GenerateUnits; + property OnUnitWriteEvent: TUnitWriteEvent read FOnUnitWriteEvent write FOnUnitWriteEvent; + end; + + +implementation +uses girCTypesMapping; + +type + TPDeclaration = class + function AsString: String; virtual; abstract; + end; + + { TPDeclarationWithLines } + + TPDeclarationWithLines = class(TPDeclaration) + Lines: TStringList; + constructor Create; virtual; + destructor Destroy; override; + function AsString: String; override; + end; + + { TPDeclarationType } + + TPDeclarationType = class(TPDeclarationWithLines) + function AsString: String; override; + end; + + { TPDeclarationConst } + + TPDeclarationConst = class(TPDeclarationWithLines) + function AsString: String; override; + end; + + { TPDeclarationVar } + + TPDeclarationVar = class(TPDeclarationWithLines) + function AsString: String; override; + end; + + { TPDeclarationFunctions } + + TPDeclarationFunctions = class(TPDeclarationWithLines) + constructor Create; override; + // nothing special for this one + end; + + { TPCodeText } + + TPCodeText = class(TPDeclaration) + private + FContent: String; + public + function AsString: String; override; + property Content: String read FContent write FContent; + + end; + + { TPUses } + + TPUses = class(TPDeclaration) + Units: TStringList; + constructor Create; + destructor Destroy; override; + function AsString: String; override; + end; + + + + { TPDeclarationList } + + TPDeclarationList = class(TList) + private + function GetDeclarations(AIndex: Integer): TPDeclaration; + public + function AsString: String; + property Declarations[AIndex: Integer]: TPDeclaration read GetDeclarations; + end; + + { TPUnitPart } + + TPUnitPart = class + FOwner: TObject; + constructor Create(AOwner: TObject); virtual; + function AsString: String; virtual ; abstract; + end; + + { TPCommonSections } + + TPCommonSections = class(TPUnitPart) + private + FDeclarations: TPDeclarationList; + public + constructor Create(AOwner: TObject); override; + destructor Destroy; override; + property Declarations: TPDeclarationList read FDeclarations; + end; + + { TPInterface } + + TPInterface = class(TPCommonSections) + private + FConstSection: TPDeclarationConst; + FFunctionSection: TPDeclarationFunctions; + FUsesSection: TPUses; + public + constructor Create(AOwner: TObject; AUses: TPUses); + destructor Destroy; override; + function AsString: String; override; + property UsesSection: TPUses read FUsesSection; + property ConstSection: TPDeclarationConst read FConstSection; + property FunctionSection: TPDeclarationFunctions read FFunctionSection; + end; + + { TPImplementation } + + TPImplementation = class(TPCommonSections) + function AsString: String; override; + end; + + { TPInitialize } + + TPInitialize = class(TPCommonSections) + function AsString: String; override; + end; + + { TPFinialization } + + TPFinialization = class(TPCommonSections) + function AsString: String; override; + end; + + { TPascalUnit } + + TPascalUnit = class + private + FLinkDynamic: Boolean; + FFinalizeSection: TPFinialization; + FImplementationSection: TPImplementation; + FInitializeSection: TPInitialize; + FInterfaceSection: TPInterface; + FLibName: String; + FNameSpace: TgirNamespace; + ProcessLevel: Integer; //used to know if to write forward definitions + function GetUnitName: String; + + // functions to ensure the type is being written in the correct declaration + function WantTypeSection: TPDeclarationType; + function WantConstSection: TPDeclarationConst; + function WantFunctionSection: TPDeclarationFunctions; + // function WantVarSection: TPDeclarationVar; + + // to process main language types + procedure HandleNativeType(AItem: TgirNativeTypeDef); + procedure HandleAlias(AItem: TgirAlias); + procedure HandleCallback(AItem: TgirCallback); + procedure HandleEnum(AItem: TgirEnumeration; ADeclareType: Boolean = True); + procedure HandleBitfield(AItem: TgirBitField); + procedure HandleRecord(AItem: TgirRecord); + procedure HandleOpaqueType(AItem: TgirFuzzyType); + procedure HandleFunction(AItem: TgirFunction); + procedure HandleObject(AItem: TgirObject; AObjectType: TGirToken); + procedure HandleUnion(AItem: TgirUnion); + + procedure WriteForwardDefinition(AType: TGirBaseType); + + + //functions to write reused parts of types + procedure WriteWrapperForObject(ARoutineType, AObjectName, AObjectFunctionName: String; AParams:TgirParamList; AFunctionReturns: String; AFlatFunctionName: String; AWantSelf: Boolean); + function WriteCallBack(AItem: TgirFunction; IsInObject: Boolean; AExistingUsedNames: TStringList = nil): String; + procedure WriteFunctionTypeAndReturnType(AItem: TgirFunction; out AFunctionType, AFunctionReturnType: String); + function WriteFunctionParams(AParams: TgirParamList; AArgs: PString = nil): String; + function WriteFunction(AFunction: TgirFunction; AItem: TGirBaseType; AIsMethod: Boolean; AWantWrapperForObject: Boolean; AFunctionList: TStrings; AExistingUsedNames: TStringList = nil): String; + function WriteParamAsString(AParam: TgirTypeParam; AIndex: Integer; AFirstParam: PString = nil; AExistingUsedNames: TStringList = nil): String; + function WriteRecord(ARecord: TgirRecord; ABaseIndent: Integer = 0; AIsUnion: Boolean = False): String; + function WriteUnion(AUnion: TgirUnion; ASkipRecordName: Boolean; ABaseIndent: Integer = 0): String; + function ParenParams(const AParams: String; const AForceParens: Boolean = False): String; + + // methods for dealing with type names + function SanitizeName(AName: String; AExistingUsedNames: TStringList = nil): String; + procedure WritePointerTypesForType(AItem: TGirBaseType; ATypeName: String; APointerLevel: Integer; ALines: TStrings); + function TypeAsString(AType: TGirBaseType; APointerLevel: Integer; ACTypeAsBackup: String = ''): String; + procedure AssembleUsedFieldNamesFromParent(const AParent: TgirClass; var AUsedNamesList: TStringList); + + procedure ResolveTypeTranslation(ABaseType: TGirBaseType); + function MakePascalTypeFromCType(CName: String; PointerLevel: Integer = MaxInt; Trim_T_IfExists: Boolean =True): String; + + function EscapeSingleQuote(AString: String): String; + + procedure AddGLibSupportCode; + + procedure ProcessType(AType: TGirBaseType; AForceWrite: Boolean = False); + procedure ResolveFuzzyTypes; + public + constructor Create(ANameSpace: TgirNamespace; ALinkDynamic: Boolean); + procedure ProcessConsts(AList:TList); // of TgirBaseType descandants + procedure ProcessTypes(AList:TFPHashObjectList); // of TgirBaseType descandants + procedure ProcessFunctions(AList:TList);// of TgirFunction + procedure GenerateUnit; + function AsStream: TStringStream; + + property InterfaceSection: TPInterface read FInterfaceSection; + property ImplementationSection: TPImplementation read FImplementationSection; + property InitializeSection: TPInitialize read FInitializeSection; + property FinalizeSection: TPFinialization read FFinalizeSection; + property UnitName: String read GetUnitName; + property LibName: String read FLibName write FLibName; + property NameSpace: TgirNamespace read FNameSpace; + end; + +function IndentText(const AText: String; Spaces: Integer = 0; LineEndingCount: Integer = 1): String; +begin + SetLength(Result, Spaces); + FillChar(Result[1], Spaces, ' '); + Result := Result+AText; + if LineEndingCount > 0 then + begin + SetLength(Result, Length(Result)+Length(LineEnding)*LineEndingCount); + FillChar(Result[Length(AText)+Spaces+1], LineEndingCount, LineEnding); + end; +end; + +function MakePointerTypesForType(const AName: String; PointerLevel: Integer): TStringList; +var + //Chars: String; + BaseName: String; + i: Integer; +begin + Result := TStringList.Create; + if AName = '' then + Exit; + BaseName:=AName; + // check if it's already prefixed + if AName[1] = 'T' then + BaseName:=Copy(AName,2, Length(AName)); + + for i := 0 to PointerLevel-1 do + begin + BaseName := 'P'+BaseName; + Result.Add(BaseName); + end; +end; + +function CalculateUnitName(ANameSpace: String; AVersion: String): String; +var + Version: String; +begin + if ANameSpace[Length(ANameSpace)] in ['0'..'9'] then + ANameSpace := ANameSpace + '_'; + Version := StringReplace(AVersion,'.','_',[rfReplaceAll]); + Version := StringReplace(Version,'_0','',[rfReplaceAll]); + Result := ANameSpace+Version; +end; + +constructor TPDeclarationFunctions.Create; +begin + inherited Create; + Lines.Duplicates:=dupIgnore; + Lines.Sorted:=True; +end; + +{ TPDeclarationVar } + +function TPDeclarationVar.AsString: String; +begin + Result:= IndentText('var') + Lines.Text; +end; + +{ TPDeclarationWithLines } + +constructor TPDeclarationWithLines.Create; +begin + Lines := TStringList.Create; +end; + +destructor TPDeclarationWithLines.Destroy; +begin + Lines.Free; + inherited Destroy; +end; + +function TPDeclarationWithLines.AsString: String; +begin + Result:=Lines.Text; +end; + + +function TPCodeText.AsString: String; +begin + Result := Content; +end; + +{ TPDeclarationType } + +function TPDeclarationType.AsString: String; +begin + Result:= IndentText('type') + Lines.Text; +end; + +{ TPDeclarationConst } + +function TPDeclarationConst.AsString: String; +begin + Result:= IndentText('const') + Lines.Text; +end; + +{ TPUses } + +constructor TPUses.Create; +begin + Units := TStringList.Create; + Units.StrictDelimiter:=True; + Units.Delimiter:=','; + Units.Add('CTypes'); +end; + +destructor TPUses.Destroy; +begin + Units.Free; + inherited Destroy; +end; + +function TPUses.AsString: String; +begin + Result := ''; + + if Units.Count>0 then + Result := IndentText('uses') + IndentText(Units.DelimitedText+';', 2)+LineEnding; +end; + +{ TPFinialization } + +function TPFinialization.AsString: String; +begin + Result := 'finalization'+LineEnding+FDeclarations.AsString; +end; + +{ TPInitialize } + +function TPInitialize.AsString: String; +begin + Result := 'initialization'+LineEnding+FDeclarations.AsString; +end; + +function TPImplementation.AsString: String; +begin + Result := IndentText('implementation')+FDeclarations.AsString; +end; + +{ TPCommonSections } + +constructor TPCommonSections.Create(AOwner: TObject); +begin + inherited Create(AOwner); + FDeclarations := TPDeclarationList.Create; +end; + +destructor TPCommonSections.Destroy; +begin + FDeclarations.Free; + inherited Destroy; +end; + +constructor TPInterface.Create(AOwner: TObject; AUses: TPUses); +begin + inherited Create(AOwner); + FUsesSection := AUses; + FConstSection := TPDeclarationConst.Create; + FFunctionSection := TPDeclarationFunctions.Create; +end; + +destructor TPInterface.Destroy; +begin + FConstSection.Free; + FFunctionSection.Free; + FUsesSection.Free; + inherited Destroy; + +end; + +function TPInterface.AsString: String; +begin + Result := IndentText('interface')+ + FUsesSection.AsString+ + FConstSection.AsString+ + FDeclarations.AsString+ + FFunctionSection.AsString; +end; + +{ TPUnitPart } + +constructor TPUnitPart.Create(AOwner: TObject); +begin + FOwner := AOwner; +end; + +{ TPascalUnit } + +function TPascalUnit.GetUnitName: String; +begin + Result := CalculateUnitName(FNameSpace.NameSpace, FNameSpace.Version); +end; + +function TPascalUnit.MakePascalTypeFromCType(CName: String; PointerLevel: Integer = MaxInt; Trim_T_IfExists: Boolean =True): String; +var + C: Integer = 0; + i: Integer = 0; + Prefix: String; +begin + Result := ''; + + repeat + i := Pos('*', CName); + if i > 0 then + begin + Inc(C); + Delete(CName, i,1); + end; + until i = 0; + + if Trim_T_IfExists and (Length(CName) > 0) and (CName[1] = 'T') then + Delete(CName,1,1); + + case PointerLevel of + MaxInt:; // C remains the same + -1: ; + 0: C := 0; + else + C := PointerLevel; + end; + + if C = -1 then + Prefix := '' + else if C = 0 then + Prefix := 'T' + else + begin + SetLength(Prefix, C); + FillChar(Prefix[1], C, 'P'); + end; + Result := Trim(Prefix+Trim(CName)); +end; + +function TPascalUnit.EscapeSingleQuote(AString: String): String; +var + i: Integer; +begin + Result := AString; + for i := Length(Result) downto 1 do + if Result[i] = '''' then + Insert('''', Result, i); +end; + +procedure TPascalUnit.AddGLibSupportCode; +const + BitFRecord = + ' TBitObject32 = object' +LineEnding+ + ' protected' +LineEnding+ + ' procedure SetBit(AMask: Integer; AValue: DWord);' +LineEnding+ + ' function GetBit(AMask: Integer): DWord;' +LineEnding+ + ' public' +LineEnding+ + ' Flags0: DWord;' +LineEnding+ + ' procedure Init(AFlags: DWord);' +LineEnding+ + ' end;'; + + BFRecordImpl :AnsiString = + 'procedure TBitObject32.Init(AFlags: DWord);' +LineEnding+ + 'begin' +LineEnding+ + ' Flags0 := AFlags;' +LineEnding+ + 'end;' +LineEnding+ + '' +LineEnding+ + 'procedure TBitObject32.SetBit(AMask: Integer; AValue: DWord);'+LineEnding+ + 'begin' +LineEnding+ + ' if AValue <> 0 then' +LineEnding+ + ' begin' +LineEnding+ + ' if (Flags0 and AMask) = 0 then' +LineEnding+ + ' Flags0 := Flags0 or AMask' +LineEnding+ + ' end' +LineEnding+ + ' else begin' +LineEnding+ + ' if (Flags0 and AMask) <> 0 then' +LineEnding+ + ' Flags0 := Flags0 xor AMask;' +LineEnding+ + ' end;' +LineEnding+ + 'end;' +LineEnding+ + '' +LineEnding+ + 'function TBitObject32.GetBit(AMask: Integer): DWord;' +LineEnding+ + 'begin' +LineEnding+ + ' Result := Flags0 and AMask;' +LineEnding+ + ' if Result > 1 then' +LineEnding+ + ' Result := 1;' +LineEnding+ + 'end;'; +var + CodeText: TPCodeText; + TypeSect: TPDeclarationType; + i: Integer; +begin + WantTypeSection.Lines.Add(BitFRecord); + CodeText := TPCodeText.Create; + CodeText.Content:=BFRecordImpl; + ImplementationSection.Declarations.Add(CodeText); + + TypeSect := WantTypeSection; + for i := 1 to 31 do + begin + if i in [8,16,32] then + continue; + TypeSect.Lines.Add(Format(' guint%d = 0..(1 shl %d-1);',[i,i])); + end; +end; + + +procedure TPascalUnit.ProcessType(AType: TGirBaseType; AForceWrite: Boolean = False); +begin + if (AType = nil) or (AType.Owner <> NameSpace) then + Exit; // it's written in another Namespace + + if (AType.ObjectType = otFuzzyType) and (TgirFuzzyType(AType).ResolvedType <> nil) then + begin + TgirFuzzyType(AType).ResolvedType.ImpliedPointerLevel := AType.ImpliedPointerLevel; + AType := TgirFuzzyType(AType).ResolvedType; + end; + + if (AType.CType = '') then //(AType.Name = '') then + begin + WriteLn('WARNING: Type.Ctype undefined! : ', Atype.Name); + //Halt; + + end; + if ProcessLevel > 0 then + begin + WriteForwardDefinition(AType); + if AType.InheritsFrom(TgirCallback) or AType.InheritsFrom(TgirBitField) then + AForceWrite:=True; + if not AForceWrite then + Exit; + end; + if (AType.Writing = msWritten) or ((AType.Writing = msWriting) {and not AForceWrite}) then + begin + //WriteLn('Already Written Type Used: ', AType.TranslatedName); + Exit; + end; + + //if AForceWrite then + // WriteLn('ForceWriting: ', AType.CType); + + Inc(ProcessLevel); + AType.Writing := msWriting; + + case AType.ObjectType of + otAlias: HandleAlias(TgirAlias(AType)); + otCallback: HandleCallback(TgirCallback(AType)); + otEnumeration: HandleEnum(TgirEnumeration(AType)); + otBitfield: HandleBitfield(TgirBitField(AType)); + otRecord: HandleRecord(TgirRecord(AType)); + otFunction: HandleFunction(TgirFunction(AType)); + otGType: HandleObject(TgirGType(AType), gtGType); + otObject: HandleObject(TgirObject(AType), gtObject); + otClass: HandleObject(TgirObject(AType), gtClass); + otClassStruct: HandleObject(TgirObject(AType), gtClassStruct); + otNativeType: HandleNativeType(TgirNativeTypeDef(AType)); // not called but the items are added to the list... where are they? + otInterface: HandleObject(TgirInterface(AType), gtInterface); + otUnion: HandleUnion(TgirUnion(AType)); + otFuzzyType: + begin + if TgirFuzzyType(AType).ResolvedType = nil then + HandleOpaqueType(TgirFuzzyType(AType)) + else + begin + Dec(ProcessLevel); // it should be level 0 + ProcessType(TgirFuzzyType(AType).ResolvedType); + Inc(ProcessLevel); + end; + end; + else + //WantTypeSection.Lines.Add(IndentText(AType.ClassName + ' ' +AType.Name + ' ' + AType.CType ,2)); + WriteLn('Unknown Type: ', AType.ClassName); + Halt; + end; // case + + AType.Writing:=msWritten; + Dec(ProcessLevel); +end; + +procedure TPascalUnit.ResolveFuzzyTypes; +var + BaseType: TGirBaseType; + FuzzyType : TgirFuzzyType absolute BaseType; + i: Integer; + CTypesType: String; +begin + // here we wil try to find unresolved types that have compatible types in pascal. + // for instance xlib uses guint but does not depend on glib where that is defined, we will try to replace those with cuint from ctypes + for i := 0 to NameSpace.Types.Count-1 do + begin + BaseType := TGirBaseType(NameSpace.Types.Items[i]); + if BaseType.InheritsFrom(TgirFuzzyType) and (FuzzyType.ResolvedType = nil) then + begin + CTypesType := LookupGTypeToCType(FuzzyType.CType); + if CTypesType <> '' then + begin + FuzzyType.TranslatedName:= CTypesType; + FuzzyType.Writing := msWritten; + end; + end; + end; +end; + +function TPascalUnit.WantTypeSection: TPDeclarationType; +begin + if (InterfaceSection.Declarations.Count = 0) + or (InterfaceSection.Declarations.Declarations[InterfaceSection.Declarations.Count-1].ClassType <> TPDeclarationType.ClassType) + then + begin + Result := TPDeclarationType.Create; + InterfaceSection.Declarations.Add(Result); + end + else + Result := TPDeclarationType(InterfaceSection.Declarations.Declarations[InterfaceSection.Declarations.Count-1]); +end; + +function TPascalUnit.WantConstSection: TPDeclarationConst; +begin + Result := InterfaceSection.ConstSection; +end; + +function TPascalUnit.WantFunctionSection: TPDeclarationFunctions; +begin + Result := InterfaceSection.FunctionSection; +end; + +procedure TPascalUnit.WritePointerTypesForType(AItem: TGirBaseType; ATypeName: String; APointerLevel: Integer; ALines: TStrings); +var + PTypes: TStrings; + i: Integer; +begin + if AItem.ForwardDefinitionWritten then + WriteLn('Warning: Forwards definitions already written for : ', Aitem.TranslatedName); + AItem.ForwardDefinitionWritten := True; + PTypes := MakePointerTypesForType(ATypeName, APointerLevel); + PTypes.Insert(0, ATypeName); + for i := PTypes.Count-1 downto 1 do + ALines.Add(IndentText(PTypes[i]+ ' = ^'+PTypes[i-1]+';',2,0)); + PTypes.Free; +end; + +procedure TPascalUnit.HandleNativeType(AItem: TgirNativeTypeDef); +var + TypeSect: TPDeclarationType; +begin + if (AItem.PascalName = AItem.CType) and (AItem.Name <> 'file') then + Exit; // is a native pascal type plus a = a doesn't fly with the compiler + + + if AItem.CType <> 'file' then + AItem.CType:=SanitizeName(AItem.CType); + + TypeSect := WantTypeSection; + AItem.TranslatedName:=AItem.CType; + //WritePointerTypesForType(Aitem, AItem.CType, AItem.ImpliedPointerLevel, TypeSect.Lines); + if AItem.Name <> 'file' then + TypeSect.Lines.Add(IndentText(SanitizeName(AItem.CType)+ ' = '+ AItem.PascalName+';', 2,0)); +end; + +procedure TPascalUnit.HandleAlias(AItem: TgirAlias); +var + ResolvedForName: String; + CType: TGirBaseType; +begin + ResolveTypeTranslation(AItem); + ResolveTypeTranslation(AItem.ForType); + + // some aliases are just for the parser to connect a name to an alias + if AItem.CType = '' then + Exit; + ResolvedForName := aItem.ForType.TranslatedName; + if ResolvedForName = '' then + begin + + CType := NameSpace.LookupTypeByName('', AItem.ForType.CType); + if CType <> nil then + ResolvedForName := CType.TranslatedName; + + if ResolvedForName <> '' then + aItem.ForType.TranslatedName := ResolvedForName + else + ResolvedForName := AItem.ForType.CType; + end; + + WriteForwardDefinition(AItem); + + if AItem.Writing < msWritten then + WantTypeSection.Lines.Add(IndentText(MakePascalTypeFromCType(AItem.CType)+' = '+ ResolvedForName+';' ,2,0)); +end; + +procedure TPascalUnit.HandleCallback(AItem: TgirCallback); +var + TypeSect: TPDeclarationType; + CB: String; +begin + + TypeSect := WantTypeSection; + + CB := WriteCallBack(AItem, False); + + if AItem.Writing < msWritten then + TypeSect.Lines.Add(IndentText(CB,2,0)) +end; + +procedure TPascalUnit.HandleEnum(AItem: TgirEnumeration; ADeclareType: Boolean = True); +var + ConstSection: TPDeclarationConst; + Entry: String; + i: Integer; + CName: String; + TypeName: String; +begin + ResolveTypeTranslation(AItem); + + ConstSection := WantConstSection; + ConstSection.Lines.Add(''); + //ATK_HYPERLINK_IS_INLINE_ + if ADeclareType then + begin + // forces forward declarations to be written + ProcessType(AItem); + + TypeName := ': '+AItem.TranslatedName; + + // yes we cheat a little here using the const section to write type info + ConstSection.Lines.Add('type'); + ConstSection.Lines.Add(IndentText(AItem.TranslatedName+' = Integer;', 2,0)); + ConstSection.Lines.Add('const'); + end + else + TypeName:=''; + ConstSection.Lines.Add(IndentText('{ '+ AItem.CType + ' }',2,0)); + + for i := 0 to AItem.Members.Count-1 do + begin + CName := AItem.Members.Member[i]^.CIdentifier; + if CName = 'ATK_HYPERLINK_IS_INLINE' then + CName :='ATK_HYPERLINK_IS_INLINE_'; + Entry := CName + TypeName+ ' = ' + AItem.Members.Member[i]^.Value+';'; + ConstSection.Lines.Add(IndentText(Entry,2,0)); + end; + AItem.Writing:=msWritten; +end; + +procedure TPascalUnit.HandleBitfield(AItem: TgirBitField); +const + TemplateLongWord = + '%s = packed object(TBitObject32)'+LineEnding+ + '%s'+LineEnding+ + 'end'; +var + Intf: TPDeclarationType; + CodeText: TPCodeText; + Code: TStringList; + PName: String; + Entry: String; + i: Integer; + VarType: String; + +begin + Intf := WantTypeSection; + CodeText := TPCodeText.Create; + ImplementationSection.Declarations.Add(CodeText); + Code := TStringList.Create; + + PName:=MakePascalTypeFromCType(AItem.CType); + + {case AItem.Bits of + //1..8: VarType:='Byte'; + //9..16: VarType:='Word'; + //0:; + //17..32: VarType:='LongWord'; + //33..64: VarType:='QWord'; + else + WriteLn('Bitfield <> 16bits'); + Halt; + end;} + + HandleEnum(AItem, False); + + VarType:='DWord'; + + Intf.Lines.Add(IndentText(PName+ ' = packed object(TBitObject32)',2,0)); + Intf.Lines.Add(IndentText('public',2,0)); + for i := 0 to AItem.Members.Count-1 do + begin + Entry := 'property '+ SanitizeName(AItem.Members.Member[i]^.Name) +': '+VarType+' index '+AItem.Members.Member[i]^.Value+' read GetBit write SetBit;'; + Intf.Lines.Add(IndentText(Entry, 4,0)); + end; + Intf.Lines.Add(IndentText('end;',2,0)); + Intf.Lines.Add(''); + + CodeText.Content:=Code.Text; + Code.Free; + +end; + +procedure TPascalUnit.HandleRecord(AItem: TgirRecord); + begin + ResolveTypeTranslation(AItem); + AItem.ImpliedPointerLevel:=1; // will not be decreased only will grow + + WriteForwardDefinition(AItem); + + WantTypeSection.Lines.Add(WriteRecord(AItem)); + +end; + +procedure TPascalUnit.HandleOpaqueType(AItem: TgirFuzzyType); +var + TypeSect: TPDeclarationType; + Plain: String; +begin + if AItem.CType = '' then + Exit; + TypeSect := WantTypeSection; + Plain := StringReplace(AItem.CType, '*', '', [rfReplaceAll]); + AItem.TranslatedName:=MakePascalTypeFromCType(Plain, 0); + + TypeSect.Lines.Add(''); + TypeSect.Lines.Add(' { '+ AItem.CType+' }'); + TypeSect.Lines.Add(IndentText(AItem.TranslatedName +' = record',2,0)); + TypeSect.Lines.Add(IndentText('{ opaque type }',4,0)); + TypeSect.Lines.Add(IndentText('Unknown: Pointer;',4,0)); // to prevent crashes of the compiler + + TypeSect.Lines.Add(IndentText('end;',2,1)); + +end; + +procedure TPascalUnit.HandleFunction(AItem: TgirFunction); +var + RoutineType: String; + Returns: String; + Params: String; + FuncSect: TPDeclarationFunctions; + Postfix: String; +begin + WriteFunctionTypeAndReturnType(AItem, RoutineType, Returns); + Params := WriteFunctionParams(AItem.Params); + Postfix := ' external;';// '+UnitName+'_library;'; + FuncSect := WantFunctionSection; + FuncSect.Lines.Add(RoutineType +' '+ AItem.CIdentifier+ParenParams(Params)+Returns+Postfix); +end; + +function TPascalUnit.WriteFunction(AFunction: TgirFunction; AItem: TGirBaseType; AIsMethod: Boolean; AWantWrapperForObject: Boolean; AFunctionList: TStrings; AExistingUsedNames: TStringList = nil): String; +var + Prefix: String = ''; + RoutineType: String; + Returns: String; + Params: String; + Postfix: String; + Entry: String; + InLineS: String = ''; +begin + Result := ''; + // we skip deprecated functions + if AFunction.Deprecated and (CompareStr(AFunction.DeprecatedVersion, NameSpace.Version) >= 0) then + Exit; + + // some abstract functions that are to be implemented by a module and shouldn't be declared. There is no indicator in the gir file that this is so :( + if (AFunction.CIdentifier = 'g_io_module_query') + or (AFunction.CIdentifier = 'g_io_module_load') + or (AFunction.CIdentifier = 'g_io_module_unload') + then + Exit; // they are functions to be implemented by a runtime loadable module, they are not actually functions in glib/gmodule/gio + + if AWantWrapperForObject then + InLineS:=' inline;'; + + // this fills in the values for procedure/function and the return type + WriteFunctionTypeAndReturnType(AFunction, RoutineType, Returns); + + // check if it is a constructor + if AFunction.InheritsFrom(TgirConstructor) then + Returns := ': '+MakePascalTypeFromCType(AItem.TranslatedName ,1)+'; cdecl;'; + + Params := WriteFunctionParams(AFunction.Params); + if Pos('array of const', Params) + Pos('va_list', Params) > 0 then + Prefix:='//'; + Postfix := ' external;';// '+UnitName+'_library;'; + + // first wrapper proc + Entry := Prefix + RoutineType +' '+ SanitizeName(AFunction.Name, AExistingUsedNames)+ParenParams(Params)+Returns+InLineS; + + // no need to pass self that will not be used + if (not AIsMethod) and AWantWrapperForObject then + Entry := Entry + ' static;'; + + // result will be written in the object declaration + Result := Entry; + + // now make sure the flat proc has all the params it needs + if AIsMethod then + begin + // methods do not include the first param for it's type so we have to add it + if Params <> '' then + Params := SanitizeName('A'+AItem.Name) +': '+TypeAsString(AItem, 1)+'; ' + Params + else + Params := SanitizeName('A'+AItem.Name) +': '+TypeAsString(AItem, 1); + end; + + // this is the flat c procedure that a wrapper would call + Entry := RoutineType +' '+ AFunction.CIdentifier+ParenParams(Params)+Returns; + + // takes care of duplicates + AFunctionList.Add(Entry+Postfix); + + //RoutineType, AObjectName, AObjectFunctionName, AParams, AFunctionReturns, AFlatFunctionName, AWantSelf + // writes the implementation of what we declared in the object + if AWantWrapperForObject and (Prefix = '') then + WriteWrapperForObject(RoutineType, AItem.TranslatedName, SanitizeName(AFunction.Name), AFunction.Params, Returns, AFunction.CIdentifier, AIsMethod); +end; + +procedure TPascalUnit.HandleObject(AItem: TgirObject; AObjectType: TGirToken); +var + TypeDecl: TStringList; + i: Integer; + UnitFuncs, + TypeFuncs: TStrings; + ParentType: String =''; + UsedNames: TStringList; + + function GetTypeForProperty(AProperty: TgirProperty; out SetFound: Boolean): String; + var + i,j: Integer; + FoundPos: Integer; + LookingForGet, + LookingForSet: String; + Line: String; + GetFound: Boolean; + begin + GetFound := False; + SetFound := False; + Result := 'UNABLE_TO_FIND_TYPE_FOR_PROPERTY'; + LookingForGet:=SanitizeName('get_'+AProperty.Name); + LookingForSet:=SanitizeName('set_'+AProperty.Name); + for i := TypeFuncs.Count-1 downto 0 do + begin + Line := TypeFuncs.Strings[i]; + + if not GetFound then + begin + FoundPos:= Pos(LookingForGet+':', Line); + //if FoundPos = 0 then + // FoundPos:=Pos(LookingForGet+'(', Line); // we do not yet support properties with parameters :( + end; + if (FoundPos > 0) and not GetFound then + begin + GetFound := True; + for j := Length(Line) downto 1 do + if Line[j] = ':' then + begin + Line := Copy(Line, j+1, Length(Line)); + break; + end; + FoundPos:=Pos(';', Line); + Result := Copy(Line, 1,FoundPos-1); + Exit; + end + else + if not SetFound then + begin + SetFound := Pos(LookingForSet+':', Line) > 0; + SetFound := SetFound or (Pos(LookingForSet+'(', Line) > 0); + // pascal properties cannot use functions for the set 'procedure' + SetFound := SetFound and (Pos('proecedure ', Line) > 0); + end; + if SetFound and GetFound then + Exit; + end; + + + end; + function WriteMethodProperty(AProperty: TgirProperty; AType: String; SetFound: Boolean): String; + const + Prop = '%sproperty %s: %s %s %s;'; + var + ReadFunc, + WriteProc: String; + Comment: String=''; + begin + ReadFunc:= 'read '+SanitizeName('get_'+ AProperty.Name); + if AProperty.Writable then + begin + if SetFound then + WriteProc := 'write '+ SanitizeName('set_'+AProperty.Name) + else + WriteProc := ' { property is writeable but setter not declared } '; + end; + if AType = 'UNABLE_TO_FIND_TYPE_FOR_PROPERTY' then + Comment := '//'; + + Result := Format(Prop, [Comment, SanitizeName(AProperty.Name, UsedNames), AType, ReadFunc, WriteProc ]); + end; + + procedure AddField(AParam: TgirTypeParam); + var + Param: String; + begin + ResolveTypeTranslation(AParam.VarType); + if (ParentType <> '') and (ParenParams(AParam.VarType.TranslatedName) = ParentType) then + begin + Exit; + end; + Param := WriteParamAsString(AParam,i, nil, UsedNames); + //if Pos('destroy_:', Param) > 0 then + // Param := StringReplace(Param, 'destroy_', 'destroy_f', [rfReplaceAll]); + TypeDecl.Add(IndentText(Param+';',4,0)) + + end; + + procedure HandleFieldType(Field: TGirBaseType; AFirstPass: Boolean); + var + SetFound: Boolean; + begin + // FIRST PASS + if AFirstPass then + begin + case Field.ObjectType of + otVirtualMethod: ; // ignore. may be usefull if we wrap this in pascal classes instead of objects. Is already written in the class struct + otCallback, + otArray, + otTypeParam, + otUnion: ; // these will be done on the second pass. this is to make the field names different if they are the same as some function or property. giving the function priority of the original name + + + otGlibSignal : if AObjectType <> gtClass then TypeDecl.Add(IndentText(WriteCallBack(TgirCallback(Field),True, UsedNames),4,0)); // classes do not have signals They are in the class *struct* + + //WriteFunction(AFunction, AItem, AIsMethod, AWantWrapperForObject, AFunctionList): String; + otFunction : TypeFuncs.Add(IndentText(WriteFunction(TgirFunction(Field), AItem, False, True, UnitFuncs, UsedNames),4,0)); + otMethod : TypeFuncs.Add(IndentText(WriteFunction(TgirFunction(Field), AItem, True, True, UnitFuncs, UsedNames),4,0)); + otConstructor:TypeFuncs.Add(IndentText(WriteFunction(TgirConstructor(Field), AItem, False, True, UnitFuncs, UsedNames),4,0)); + otProperty : TypeFuncs.Add(IndentText(WriteMethodProperty(TgirProperty(Field), GetTypeForProperty(TgirProperty(Field), SetFound), SetFound),4,0)); + else // case < + WriteLn('Unknown Field Type : ', Field.ClassName); + Halt; + end; + end; + + // SECOND PASS + if not AFirstPass then + begin + case Field.ObjectType of + otArray, + otTypeParam: AddField(TgirTypeParam(Field)); + otCallback : TypeDecl.Add(IndentText(WriteCallBack(TgirCallback(Field),True, UsedNames),4,0)); + otUnion : + begin + // we have to create a union outside the object and include it as a field + Field.CType := AItem.CType+'_union_'+Field.Name; + ResolveTypeTranslation(Field); + HandleUnion(TgirUnion(Field)); + TypeDecl.Add(IndentText(SanitizeName(Field.Name, UsedNames)+': '+ Field.TranslatedName+'; //union extracted from object and named '''+Field.TranslatedName+'''',4,0)); + end + end; + end; + + end; + function GetParentType(AClass: TgirClass): String; + begin + Result := ''; + AssembleUsedFieldNamesFromParent(AClass.ParentClass, UsedNames); + if AClass.ParentClass = nil then + Exit; + if AClass.ParentClass.Writing < msWritten then + ProcessType(AClass.ParentClass, True); // this type must be first + + Result := AClass.ParentClass.TranslatedName; + if Result = '' then + begin + WriteLn('Class has parent but name is empty! : ', AClass.CType); + WriteLn('Parent Name = ', AClass.ParentClass.Name); + WriteLn('Parent CType = ', AClass.ParentClass.CType); + WriteLn('Parent Translated Name = ', AClass.ParentClass.TranslatedName); + Halt + end; + end; + procedure AddGetTypeProc(AObj: TgirGType); + const + GetTypeTemplate = 'function %s: %s; cdecl; external;'; + var + AType: String; + begin + AType:='TGType'; + if AObj.GetTypeFunction = '' then + Exit; + if not NameSpace.UsesGLib then + AType := 'csize_t { TGType }'; + + UnitFuncs.Add(Format(GetTypeTemplate, [AObj.GetTypeFunction, AType])); + end; + +var + TypeSect: TPDeclarationType; +begin + if AItem.CType = '' then + Exit; + // if any params use a type that is not written we must write it before we use it!! + TypeDecl := TStringList.Create; + UsedNAmes := TStringList.Create; + UsedNames.Sorted:=True; + UsedNames.Duplicates:=dupError; + ResolveTypeTranslation(AItem); + AItem.ImpliedPointerLevel:=1; //will only grow + + // forces it to write forward declarations if they are not yet. + ProcessType(AItem); + + UnitFuncs := TStringList.Create; + TypeFuncs := TStringList.Create; + + case AObjectType of + gtObject :; // do nothing + gtClass : ParentType:=ParenParams(GetParentType(TgirClass(AItem))); + gtClassStruct : ;// do nothing; + gtInterface: ; + gtGType: ; + else + WriteLn('Got Object Type I don''t understand: ', GirTokenName[AObjectType]); + end; + + if AItem.InheritsFrom(TgirGType) then + begin + AddGetTypeProc(TgirGType(AItem)); + end; + TypeDecl.Add(IndentText(AItem.TranslatedName +' = object'+ParentType,2,0)); + // two passes to process the fields last for naming reasons + for i := 0 to Aitem.Fields.Count-1 do + HandleFieldType(AItem.Fields.Field[i], True); + for i := 0 to Aitem.Fields.Count-1 do + HandleFieldType(AItem.Fields.Field[i], False); + + + if TypeFuncs.Count > 0 then + TypeDecl.AddStrings(TypeFuncs); + + TypeDecl.Add(' end;'); + + TypeSect := WantTypeSection; + + TypeSect.Lines.AddStrings(TypeDecl); + TypeDecl.Free; + UsedNames.Free; + + if UnitFuncs.Count > 0 then + WantFunctionSection.Lines.AddStrings(UnitFuncs); + UnitFuncs.Free; + TypeFuncs.Free; + +end; + +procedure TPascalUnit.HandleUnion(AItem: TgirUnion); +begin + ResolveTypeTranslation(AItem); + WantTypeSection.Lines.Add(WriteUnion(AItem, False, 2)); + +end; + +procedure TPascalUnit.WriteForwardDefinition(AType: TGirBaseType); + procedure WriteForward; + var + TypeSect: TPDeclarationType; + begin + TypeSect := WantTypeSection; + ResolveTypeTranslation(AType); + AType.ImpliedPointerLevel := 1; // will only grow + TypeSect.Lines.Add(''); + //TypeSect.Lines.Add(' { forward declaration for '+AType.TranslatedName+'}'); + WritePointerTypesForType(AType, AType.TranslatedName, AType.ImpliedPointerLevel, TypeSect.Lines); + end; + +begin + if AType.InheritsFrom(TgirFuzzyType) and (TgirFuzzyType(AType).ResolvedType <> nil) then + begin + TgirFuzzyType(AType).ResolvedType.ImpliedPointerLevel := AType.ImpliedPointerLevel; + AType := TgirFuzzyType(AType).ResolvedType; + end; + + if AType.ForwardDefinitionWritten then + Exit; + + WriteForward; + case AType.ObjectType of + otObject, + otGType, + otClass, + otClassStruct: ; + + otAlias: ProcessType(AType, True); + otCallback: ProcessType(AType, True); + otEnumeration: ; + otBitfield: ; + otRecord: ; + otFunction: ; + otNativeType : ; + otInterface: ; + end; + Atype.ForwardDefinitionWritten:=True; +end; + +procedure TPascalUnit.WriteWrapperForObject(ARoutineType, AObjectName, + AObjectFunctionName: String; AParams: TgirParamList; AFunctionReturns: String; AFlatFunctionName: String; AWantSelf: Boolean); +const + Decl = '%s %s.%s%s%s'+LineEnding; + Body = 'begin'+LineEnding+ + ' %s%s(%s);'+LineEnding+ + 'end;'+LineEnding; +var + Params: String; + CallParams: String; + Code: TPCodeText; + ResultStr: String = ''; + Args: String; +begin + if AWantSelf then + begin + if AParams.Count = 0 then + CallParams:='@self' + else + CallParams:='@self, '; + end + else + CallParams:=''; + if (ARoutineType = 'function') or (ARoutineType='constructor') then + ResultStr := 'Result := '; + Params:=WriteFunctionParams(AParams, @Args); + CallParams:=CallParams+Args; + Code := TPCodeText.Create; + Code.Content := Format(Decl, [ARoutineType, AObjectName, AObjectFunctionName, ParenParams(Params), AFunctionReturns])+ + Format(Body, [ResultStr, Self.UnitName+'.'+AFlatFunctionName, CallParams]); + ImplementationSection.Declarations.Add(Code); + + +end; + +function TPascalUnit.WriteCallBack(AItem: TgirFunction; IsInObject: Boolean; AExistingUsedNames: TStringList = nil): String; +var + RoutineType: String; + Returns: String; + CBName: String; + Symbol: String; + Params: String; +begin + WriteFunctionTypeAndReturnType(AItem, RoutineType, Returns); + + if IsInObject then + begin + CBName:=SanitizeName(AItem.Name, AExistingUsedNames); + Symbol := ': '; + end + else + begin + CBName:=MakePascalTypeFromCType(AItem.CType); + Symbol := ' = '; + end; + + Params := WriteFunctionParams(AItem.Params); + + Result := CBName+Symbol+RoutineType+ParenParams(Params)+Returns; + +end; + +procedure TPascalUnit.WriteFunctionTypeAndReturnType(AItem: TgirFunction; + out AFunctionType, AFunctionReturnType: String); +begin + ResolveTypeTranslation(AItem.Returns.VarType); + if (AItem.Returns.VarType.CType = 'void') and (AItem.Returns.PointerLevel = 0) then + begin + AFunctionType:='procedure'; + AFunctionReturnType := '; cdecl;'; + end + else + begin + AFunctionType:='function'; + AFunctionReturnType:= ': '+TypeAsString(AItem.Returns.VarType, AItem.Returns.PointerLevel)+'; cdecl;' ; + + // will skip if written + ProcessType(AItem.Returns.VarType); + end; +end; + +function TPascalUnit.WriteFunctionParams(AParams: TgirParamList; AArgs: PString = nil): String; +var + i: Integer; + ArgName: String; +begin + Result := ''; + if AArgs <> nil then + AArgs^ := ''; + for i := 0 to AParams.Count-1 do + begin + Result := Result+WriteParamAsString(AParams.Param[i], i, @ArgName); + if i < AParams.Count-1 then + begin + Result := Result +'; '; + if AArgs <> nil then + AArgs^:=AArgs^+ArgName+', '; + end + else + if AArgs <> nil then + AArgs^:=AArgs^+ArgName; + end; +end; + +function TPascalUnit.TypeAsString(AType: TGirBaseType; APointerLevel: Integer; ACTypeAsBackup: String = ''): String; +var + BackupNoPointers: String; +begin + ResolveTypeTranslation(AType); + + BackupNoPointers := StringReplace(ACTypeAsBackup, '*', '', [rfReplaceAll]); + + if APointerLevel = 0 then + begin + Result := AType.TranslatedName; + if Result = '' then + Result := NameSpace.LookupTypeByName(BackupNoPointers, '').TranslatedName; + end + else + begin + if AType.CType = '' then + AType.CType:=ACTypeAsBackup; + Result := MakePascalTypeFromCType(AType.CType, APointerLevel); + end; + if APointerLevel > AType.ImpliedPointerLevel then + begin + WriteLn('Trying to use a pointerlevel > written level!'); + Halt; + end; +end; + +procedure TPascalUnit.AssembleUsedFieldNamesFromParent(const AParent: TgirClass; var AUsedNamesList: TStringList); +var + Field: TGirBaseType; + i: Integer; +begin + if AParent = nil then + Exit; + + AssembleUsedFieldNamesFromParent(AParent.ParentClass, AUsedNamesList); + for i := 0 to AParent.Fields.Count-1 do + begin + Field := AParent.Fields.Field[i]; + case Field.ObjectType of + otArray, + otTypeParam, + otCallback, + otProperty: + begin + // adds name to list + SanitizeName(Field.Name, AUsedNamesList); + end; + end; + end; +end; + +function TPascalUnit.WriteParamAsString(AParam: TgirTypeParam; AIndex: Integer; AFirstParam: PString = nil; AExistingUsedNames: TStringList = nil): String; +var + PT: String; + PN: String; + IsArray: Boolean; + AnArray: TgirArray absolute AParam; +begin + if AParam.VarType = nil then + begin + // is a varargs param + Result := 'args: array of const';// 'args: varargs'; // varargs must be append to the function definition also this is more clear to the user + exit; + end; + + + IsArray := AParam.InheritsFrom(TgirArray) ; + + //if Length(AParam.VarType.Name) < 1 then + //begin + //WriteLn('AParam.VarType.Name is empty. AParam.Name = ', AParam.Name,' AParam.CType = ', AParam.CType, ' AParam.VarType.CType = ',AParam.VarType.CType); + //end; + PT := ''; + if IsArray and (AnArray.FixedSize > 0) then + PT := 'array [0..'+IntToStr(TgirArray(AParam).FixedSize-1)+'] of ' ; + PT := PT+ TypeAsString(AParam.VarType, AParam.PointerLevel, AParam.CType); + + if IsArray and (AnArray.FixedSize = 0) then + PN := AnArray.ParentFieldName + else + PN := AParam.Name; + + + if PN = '' then + PN := 'param'+IntToStr(AIndex); + PN := SanitizeName(PN, AExistingUsedNames); + + if AFirstParam <> nil then + AFirstParam^:=PN; + + if AParam.Bits > 0 then + begin + case AParam.Bits of + //16: PT := 'guint16 { changed from '+PT+' to accomodate 16 bitsize requirement }'; + //32: PT := 'guint32 { changed from '+PT+' to accomodate 32 bitsize requirement }'; + 1..32: + PT := Format('guint%d { changed from %s to accomodate %d bitsize requirement }',[AParam.Bits, PT, AParam.Bits]); + else + WriteLn('WARNING: Bits are Set to [ ',AParam.Bits,' ]for: ' ,PN+': '+PT); + PT +=' { ERROR : Bits are Set to [ '+IntToStr(AParam.Bits)+' ] }'; + end; + + end; + Result := PN +': '+PT; + + + + + + ProcessType(AParam.VarType, AParam.PointerLevel = 0); // will skip if written +end; + +function TPascalUnit.WriteRecord(ARecord: TgirRecord; ABaseIndent: Integer = 0; AIsUnion: Boolean = False): String; +var + TypeDecl: TStringList; + i: Integer; + Field: TGirBaseType; + UseName: String; + Symbol: String; +begin + TypeDecl := TStringList.Create; + TypeDecl.Add(''); + if Not AIsUnion then + begin + UseName:=ARecord.TranslatedName; + Symbol := ' = '; + end + else + begin + UseName:=ARecord.Name; + Symbol:= ' : '; + end; + TypeDecl.Add(IndentText(UseName +Symbol+ 'record',ABaseIndent+2,0)); + + // If a type size = 0 then this can cause problems for the compiler! bug 20265 + if ARecord.Fields.Count = 0 then + TypeDecl.Add(IndentText('Unknown: Pointer;', ABaseIndent+4,0)); + + for i := 0 to ARecord.Fields.Count-1 do + begin + Field := ARecord.Fields.Field[i]; + case Field.ObjectType of + otArray, + otTypeParam: TypeDecl.Add(IndentText(WriteParamAsString(TgirTypeParam(Field),i)+';',ABaseIndent+4,0)); + otCallback : TypeDecl.Add(IndentText(WriteCallBack(TgirCallback(Field),True),ABaseIndent+4,0)); + otUnion: TypeDecl.Add(IndentText(WriteUnion(TgirUnion(Field), True, ABaseIndent),ABaseIndent+4)); + else + TypeDecl.Add(IndentText(Field.Name+ ' ' + Field.ClassName,4,0)); // this of course will make the compiler barf + end; + + end; + TypeDecl.Add(IndentText('end;',ABaseIndent+2,1)); + Result := TypeDecl.Text; +end; + +function TPascalUnit.WriteUnion(AUnion: TgirUnion; ASkipRecordName: Boolean; ABaseIndent: Integer + ): String; +var + Union: TStringList; + i: Integer; + Field: TGirBaseType; +begin + Union := TStringList.Create; + + if not ASkipRecordName then + Union.Add(IndentText(AUnion.TranslatedName+' = record', ABaseIndent,0)); + if AUnion.Fields.Count > 0 then + Union.Add(IndentText('case longint of',ABaseIndent+2,0)); + for i := 0 to AUnion.Fields.Count-1 do + begin + Field := AUnion.Fields.Field[i]; + case Field.ObjectType of + otArray, + otTypeParam : Union.Add(IndentText(IntToStr(i)+ ' : ' +ParenParams(WriteParamAsString(TgirTypeParam(Field),i))+';',ABaseIndent+ 4,0)); + otCallback : Union.Add(IndentText(IntToStr(i)+ ' : ' +ParenParams(WriteCallBack(TgirCallback(Field),True)),ABaseIndent+4,0)); + otRecord : Union.Add(IndentText(IntToStr(i)+ ' : ' +ParenParams(WriteRecord(TgirRecord(Field),6, True))+';',ABaseIndent+4,0)); + //WriteFunction(AFunction, AItem, AIsMethod, AWantWrapperForObject, AFunctionList): String; + otConstructor, + otFunction : Union.Add(IndentText('//'+WriteFunction(TgirFunction(Field), AUnion, False, False, WantFunctionSection.Lines), ABaseIndent+2,0)); + otMethod : Union.Add(IndentText('//'+WriteFunction(TgirFunction(Field), AUnion, True, False, WantFunctionSection.Lines), ABaseIndent+2,0)); + else + Union.Add('// Unhandled type for Union: '+ Field.ClassName); // this won't compile obviously + WriteLn('Unhandled type for Union: ', Field.ClassName); + end; + + end; + if not ASkipRecordName then + Union.Add(IndentText('end;', ABaseIndent)); + REsult := Union.Text; + Union.Free; + +end; + +function TPascalUnit.ParenParams(const AParams: String; const AForceParens: Boolean = False): String; +begin + Result := ''; + if (AParams <> '') or AForceParens then + Result := '('+AParams+')'; +end; + +function TPascalUnit.SanitizeName(AName: String; AExistingUsedNames: TStringList = nil): String; +var + PascalReservedWords : array[0..30] of String = + ('begin', 'end', 'type', 'of', 'in', 'out', 'function', 'string','file', 'default', + 'procedure', 'string', 'boolean', 'array', 'set', 'destructor', 'destroy', 'program', + 'property', 'object', 'private', 'constructor', 'inline', 'result', 'interface', + 'const', 'raise', 'unit', 'label', 'xor', 'implementation'); + Name: String; + Sanity: Integer = 0; + Sucess: Boolean; + TestName: String; +begin + for Name in PascalReservedWords do + if Name = LowerCase(AName) then + Result := Aname+'_'; + If Result = '' then + Result := AName; + if AName = 'CSET_A_2_Z' then + Result := 'CSET_A_2_Z_UPPER'; + if AName = 'CSET_a_2_z' then + Result := 'CSET_a_2_z_lower'; + Result := StringReplace(Result, '-','_',[rfReplaceAll]); + Result := StringReplace(Result, ' ','_',[rfReplaceAll]); + + if AExistingUsedNames <> nil then + begin + // AExistingUsedNames must be set to sorted and duplucate strings caues an error; + TestName:=Result; + repeat + Inc(Sanity); + try + AExistingUsedNames.Add(TestName); + Result := TestName; + Sucess := True; + except + TestName := Result + IntToStr(Sanity); + Sucess := False; + end; + + until Sucess or (Sanity > 300); + end; + +end; + +procedure TPascalUnit.ResolveTypeTranslation(ABaseType: TGirBaseType); +begin + if ABaseType.TranslatedName = '' then + ABaseType.TranslatedName:=MakePascalTypeFromCType(ABaseType.CType, 0); +end; + +constructor TPascalUnit.Create(ANameSpace: TgirNamespace; ALinkDynamic: Boolean); +begin + ProcessLevel:=0; + FLinkDynamic := ALinkDynamic; + FFinalizeSection := TPFinialization.Create(Self); + FImplementationSection := TPImplementation.Create(Self); + FInitializeSection := TPInitialize.Create(Self); + FInterfaceSection := TPInterface.Create(Self, TPUses.Create); + FNameSpace := ANameSpace; + ResolveFuzzyTypes; + GenerateUnit; +end; + +procedure TPascalUnit.ProcessConsts(AList: TList); + function WriteConst(AConst: TgirConstant; Suffix: String = ''): String; + begin + if AConst.IsString then + Result := SanitizeName(AConst.Name) + Suffix+' = '+QuotedStr(AConst.Value)+';' + else + Result := SanitizeName(AConst.Name) + Suffix+' = '+AConst.Value+';'; + end; + +var + NewConst: TPDeclarationConst; + Item: TgirConstant; + i: Integer; + Consts: TStringList; // this is to check for duplicates + Entry: String; + Suffix: String; + Sanity: Integer; +begin + NewConst := WantConstSection; + Consts := TStringList.Create; + Consts.Sorted:=True; + Consts.Duplicates:=dupError; + + + for i := 0 to AList.Count-1 do + begin + Sanity := 0; + Suffix := ''; + Item := TgirConstant(AList.Items[i]); + //if Item.ClassType <> TgirConstant then ; // raise error + Entry := LowerCase(SanitizeName(Item.Name)); + + repeat + try + Consts.AddObject(Entry, TObject(PtrUInt(NewConst.Lines.Count))); + break; + except + Suffix := '__'+IntToStr(Sanity); + Entry := LowerCase(SanitizeName(Item.Name))+Suffix; + end; + Inc(Sanity); + until Sanity > 10; + + NewConst.Lines.AddObject(IndentText(WriteConst(Item, Suffix), 2,0), Item); + end; +end; + +procedure TPascalUnit.ProcessTypes(AList: TFPHashObjectList); + +var + BaseType: TGirBaseType; + i: Integer; +begin + if AList.Count = 0 then + Exit; + + for i := 0 to AList.Count-1 do + begin + BaseType := TGirBaseType(AList.Items[i]); + ProcessType(BaseType); + end; + +end; + +procedure TPascalUnit.ProcessFunctions(AList: TList); +var + i: Integer; + Func: TgirFunction; +begin + for i := 0 to AList.Count-1 do + begin + Func := TgirFunction(AList.Items[i]); + HandleFunction(Func); + end; +end; + +procedure TPascalUnit.GenerateUnit; +var + i: Integer; + NS: TgirNamespace; +begin + for i := 0 to FNameSpace.RequiredNameSpaces.Count-1 do + begin + NS := TgirNamespace(FNameSpace.RequiredNameSpaces.Items[i]); + InterfaceSection.UsesSection.Units.Add(' '+CalculateUnitName(NS.NameSpace,NS.Version)); + end; + + i := Pos(',',NameSpace.SharedLibrary); + if i > 0 then + LibName:=Copy(NameSpace.SharedLibrary,1,i-1) + else + LibName:=NameSpace.SharedLibrary; + WantConstSection.Lines.Add(IndentText(UnitName+'_library = '''+LibName+''';', 2)); + if NameSpace.NameSpace = 'GLib' then + AddGLibSupportCode; + +end; + +function TPascalUnit.AsStream: TStringStream; +var + Str: TStringStream absolute Result; + Libs: TStringList; + i: Integer; +begin + Libs := TStringList.Create; + Libs.Delimiter:=','; + Libs.StrictDelimiter:= True; + Libs.CommaText:=NameSpace.SharedLibrary; + + Result := TStringStream.Create(''); + Str.WriteString(IndentText('unit '+ UnitName+';',0,2)); + Str.WriteString(IndentText('{$MODE OBJFPC}{$H+}',0,2)); + Str.WriteString(IndentText('{$PACKRECORDS C}',0,1)); + Str.WriteString(IndentText('{$BITPACKING ON}',0,1)); + //Str.WriteString(IndentText('{$CALLING CDECL}',0,2)); + Str.WriteString(IndentText('{$MODESWITCH DUPLICATELOCALS+}',0,2)); + + for i := 0 to Libs.Count-1 do + Str.WriteString(IndentText('{$LINKLIB '+Libs.Strings[i]+'}',0,1)); + + Libs.Free; + + Str.WriteString(InterfaceSection.AsString); + Str.WriteString(ImplementationSection.AsString); + + if InitializeSection.Declarations.Count > 0 then + Str.WriteString(InitializeSection.AsString); + + if FinalizeSection.Declarations.Count > 0 then + Str.WriteString(FinalizeSection.AsString); + + Str.WriteString('end.'); + + Result.Position:=0; +end; + +{ TPDeclarationList } + +function TPDeclarationList.GetDeclarations(AIndex: Integer): TPDeclaration; +begin + Result := TPDeclaration(Items[AIndex]); +end; + +function TPDeclarationList.AsString: String; +var + i: Integer; +begin + for i := 0 to Count-1 do + begin + Result := Result+Declarations[i].AsString+LineEnding; + end; +end; + +{ TgirPascalWriter } + +constructor TgirPascalWriter.Create(ANameSpaces: TgirNamespaces); +begin + FNameSpaces := ANameSpaces; + FUnits := TList.Create; +end; + +procedure TgirPascalWriter.GenerateUnits; +var + i: Integer; + FUnit: TPascalUnit; + +begin + for i := 0 to FNameSpaces.Count-1 do + begin + WriteLn(Format('Converting %s', [FNameSpaces.NameSpace[i].NameSpace])); + FUnit := TPascalUnit.Create(FNameSpaces.NameSpace[i], False); + FUnit.ProcessConsts(FNameSpaces.NameSpace[i].Constants); + FUnit.ProcessTypes(FNameSpaces.NameSpace[i].Types); + FUnit.ProcessFunctions(FNameSpaces.NameSpace[i].Functions); + FUnits.Add(FUnit); + FOnUnitWriteEvent(Self, FUnit.UnitName, FUnit.AsStream); + end; +end; + +end. + diff --git a/applications/gobject-introspection/girtokens.pas b/applications/gobject-introspection/girtokens.pas new file mode 100644 index 000000000..6bd381d67 --- /dev/null +++ b/applications/gobject-introspection/girtokens.pas @@ -0,0 +1,90 @@ +{ +girtokens.pas +Copyright (C) 2011 Andrew Haines andrewd207@aol.com + +This program 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 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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} +unit girTokens; + +{$mode objfpc}{$H+} + +interface + +uses + Classes; + +type + TGirToken = (gtInvalid, gtAlias, gtConstant, gtRecord, gtBitField, gtEnumeration, + gtCallback, gtUnion, gtFunction, gtReturnValue, gtType, + gtParameters, gtParameter, gtMember, gtField, gtMethod, gtArray, + gtDoc, gtConstructor, gtRepository, gtInclude, gtNameSpace, gtPackage, + gtCInclude, gtClass, gtProperty, gtVirtualMethod, gtInterface, + gtGlibSignal, gtImplements, gtPrerequisite,gtVarArgs, gtObject, gtClassStruct, gtGType); + + + +var + GirTokenName: array[TGirToken] of String = ( + 'Invalid Name', + 'alias', + 'constant', + 'record', + 'bitfield', + 'enumeration', + 'callback', + 'union', + 'function', + 'return-value', + 'type', + 'parameters', + 'parameter', + 'member', + 'field', + 'method', + 'array', + 'doc', + 'constructor', + 'repository', + 'include', + 'namespace', + 'package', + 'c:include', + 'class', + 'property', + 'virtual-method', + 'interface', + 'glib:signal', + 'implements', + 'prerequisite', + 'varargs', + 'object', + 'classstruct', + 'gtype' + ); + + function GirTokenNameToToken(AName: String): TGirToken; + +implementation + +function GirTokenNameToToken(AName: String): TGirToken; +begin + for Result in TGirToken do + if GirTokenName[Result] = AName then + Exit; + Result := gtInvalid; +end; + +end. +