fpc/utils/pas2js/webidl2pas.pp
2025-03-04 17:54:47 +01:00

382 lines
11 KiB
ObjectPascal

{
This file is part of the Free Component Library
WEBIDL to pascal code converter program
Copyright (c) 2022 by Michael Van Canneyt michael@freepascal.org
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
program webidl2pas;
{$mode objfpc}{$H+}
uses
Classes, SysUtils, CustApp, webidlscanner, webidltopas, pascodegen, typinfo,
webidltopas2js, webidltowasmjob, webidltowasmstub;
type
TWebIDLToPasFormat = (
wifPas2js,
wifWasmJob,
wifWasmJobStub
);
const
WebIDLToPasFormatNames: array[TWebIDLToPasFormat] of string = (
'pas2js',
'wasmjob',
'wasmjobstub'
);
type
{ TWebIDLToPasApplication }
TWebIDLToPasApplication = class(TCustomApplication)
private
FOutputFormat: TWebIDLToPasFormat;
FWebIDLToPas: TBaseWebIDLToPas;
function CheckBaseOption(C: TBaseConversionOption;
const AShort: Char; const aLong: String): Boolean;
function CheckPas2jsOption(C: TPas2jsConversionOption;
const AShort: Char; const aLong: String): Boolean;
function ConfigWebIDLToPas: Boolean;
procedure DoConvertLog(Sender: TObject; {%H-}LogType: TCodegenLogType; const Msg: String);
function GetInputFileName: String;
function GetOutputFileName: String;
function GetUnitName: String;
procedure SetinputFileName(AValue: String);
procedure SetOutputFileName(AValue: String);
procedure SetunitName(AValue: String);
protected
procedure DoRun; override;
procedure InitWebIDLToPas; virtual;
Protected
Property WebIDLToPas : TBaseWebIDLToPas Read FWebIDLToPas;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure WriteHelp(Const Msg : string); virtual;
Property UnitName : String Read GetUnitName Write SetunitName;
property InputFileName : String Read GetInputFileName Write SetinputFileName;
property OutputFileName : String Read GetOutputFileName Write SetOutputFileName;
property OutputFormat: TWebIDLToPasFormat read FOutputFormat write FOutputFormat;
end;
{ TWebIDLToPasApplication }
function TWebIDLToPasApplication.GetInputFileName: String;
begin
Result:=FWebIDLToPas.InputFileName;
end;
procedure TWebIDLToPasApplication.DoConvertLog(Sender: TObject;
LogType: TCodegenLogType; const Msg: String);
begin
{AllowWriteln}
Writeln(Msg);
{AllowWriteln-}
end;
function TWebIDLToPasApplication.GetOutputFileName: String;
begin
Result:=FWebIDLToPas.OutputFileName
end;
function TWebIDLToPasApplication.GetUnitName: String;
begin
Result:=FWebIDLToPas.OutputUnitName;
end;
procedure TWebIDLToPasApplication.SetinputFileName(AValue: String);
begin
FWebIDLToPas.InputFileName:=aValue;
end;
procedure TWebIDLToPasApplication.SetOutputFileName(AValue: String);
begin
FWebIDLToPas.OutputFileName:=aValue;
end;
procedure TWebIDLToPasApplication.SetunitName(AValue: String);
begin
FWebIDLToPas.OutputUnitName:=aValue;
end;
function TWebIDLToPasApplication.CheckBaseOption(C: TBaseConversionOption;
const AShort: Char; const aLong: String): Boolean;
begin
Result:=HasOption(aShort,ALong);
if Result then
FWebIDLToPas.BaseOptions:=FWebIDLToPas.BaseOptions+[C];
end;
function TWebIDLToPasApplication.CheckPas2jsOption(C: TPas2jsConversionOption;
const AShort: Char; const aLong: String): Boolean;
begin
if not (FWebIDLToPas is TWebIDLToPas2js) then exit;
Result:=HasOption(aShort,ALong);
if Result then
TWebIDLToPas2js(FWebIDLToPas).Pas2jsOptions:=TWebIDLToPas2js(FWebIDLToPas).Pas2jsOptions+[C];
end;
// Return true if the configuration was OK.
function TWebIDLToPasApplication.ConfigWebIDLToPas : Boolean;
var
A: String;
I : Integer;
L : TStrings;
begin
Result:=True;
// set verbosity
FWebIDLToPas.Verbose:=HasOption('v','verbose');
// read other options
CheckPas2jsOption(p2jcoExternalConst,'c','constexternal');
if CheckBaseOption(coDictionaryAsClass,'d','dicttoclass') then
TWebIDLToPas2js(FWebIDLToPas).DictionaryClassParent:=GetOptionValue('d','dicttoclass');
CheckBaseOption(coExpandUnionTypeArgs,'e','expandunionargs');
CheckBaseOption(coChromeWindow,'r','chrome');
CheckBaseOption(coPrivateMethods,'a','private');
// -f ?
A:=GetOptionValue('g','globals');
if (Copy(A,1,1)='@') then
begin
Delete(A,1,1);
FWebIDLToPas.GlobalVars.LoadFromFile(A);
end
else
FWebIDLToPas.GlobalVars.CommaText:=A;
A:=GetOptionValue('b','banned');
if (Copy(A,1,1)='@') then
begin
Delete(A,1,1);
FWebIDLToPas.Banned.LoadFromFile(A);
end
else
FWebIDLToPas.Banned.CommaText:=A;
if HasOption('l','list') then
begin
L:=TStringList.Create;
try
A:=GetOptionValue('l','list');
if (Copy(A,1,1)='@') then
begin
Delete(A,1,1);
L.LoadFromFile(A);
end
else
L.CommaText:=A;
FWebIDLToPas.SetUsedList(L);
finally
L.free;
end;
end;
InputFileName:=GetOptionValue('i','input');
if (InputFileName='') then
begin
WriteHelp('Missing input filename');
Exit(False);
end;
if HasOption('m','implementation') then
FWebIDLToPas.IncludeImplementationCode.LoadFromFile(GetOptionValue('m','implementation'));
if HasOption('n','include') then
FWebIDLToPas.IncludeInterfaceCode.LoadFromFile(GetOptionValue('n','include'));
OutputFileName:=GetOptionValue('o','output');
CheckBaseOption(coAddOptionsToHeader,'p','optionsinheader');
A:=GetOptionValue('t','typealiases');
if (Copy(A,1,1)='@') then
begin
Delete(A,1,1);
FWebIDLToPas.TypeAliases.LoadFromFile(A);
end
else
FWebIDLToPas.TypeAliases.CommaText:=A;
UnitName:=GetOptionValue('u','unitname');
if UnitName='' then
UnitName:=ChangeFileExt(ExtractFileName(InputFileName),'');
if OutputFileName='' then
begin
if (UnitName<>'') then
OutputFileName:=ExtractFilePath(InputFileName)+UnitName+'.pas';
end;
if HasOption('w','webidlversion') then
begin
A:=GetOptionValue('w','webidlversion');
I:=GetEnumValue(TypeInfo(TWebIDLVersion),A);
if (I<>-1) then
FWebIDLToPas.WebIDLVersion:=TWebIDLVersion(I)
else
begin
WriteHelp('Invalid webidl version: "'+A+'"');
Exit(False);
end;
end;
FWebIDLToPas.ExtraUnits:=GetOptionValue('x','extra');
end;
procedure TWebIDLToPasApplication.DoRun;
const
Short = 'ced::f:g:hi:m:n:o:pt:u:vw:x:rl:ab';
Long : Array of string = (
'help',
'constexternal',
'dicttoclass::',
'expandunionargs',
'outputformat:',
'globals:',
'input:',
'implementation:',
'include:',
'output:',
'optionsinheader',
'typealiases:',
'unitname:',
'verbose',
'webidlversion:',
'extra:',
'chrome',
'list:',
'private',
'banned:'
);
var
A,ErrorMsg: String;
ok: Boolean;
f: TWebIDLToPasFormat;
begin
Terminate;
// quick check parameters
ErrorMsg:=CheckOptions(Short,Long);
if (ErrorMsg<>'') or HasOption('h','help') then
begin
ErrorMsg:='Missing input filename';
WriteHelp(ErrorMsg);
Exit();
end;
// first read outputformat and create FWebIDLToPas
if HasOption('f','outputformat') then
begin
A:=GetOptionValue('f','outputformat');
ok:=false;
for f in TWebIDLToPasFormat do
begin
if SameText(A,WebIDLToPasFormatNames[f]) then
begin
OutputFormat:=f;
ok:=true;
end;
end;
if not ok then
begin
WriteHelp('unknown outputformat "'+A+'"');
exit;
end;
end;
InitWebIDLToPas;
if ConfigWebIDLToPas then
FWebIDLToPas.Execute;
end;
procedure TWebIDLToPasApplication.InitWebIDLToPas;
begin
case OutputFormat of
wifWasmJob:
FWebIDLToPas:=TWebIDLToPasWasmJob.Create(Self);
wifWasmJobStub:
FWebIDLToPas:=TWebIDLToPasWasmJobStub.Create(Self);
else
FWebIDLToPas:=TWebIDLToPas2js.Create(Self);
end;
FWebIDLToPas.OnLog:=@DoConvertLog;
FWebIDLToPas.ClassPrefix:='TJS';
FWebIDLToPas.ClassSuffix:='';
FWebIDLToPas.KeywordSuffix:='_';
FWebIDLToPas.KeywordPrefix:='';
FWebIDLToPas.DottedUnitsSupport:=dusFull;
end;
constructor TWebIDLToPasApplication.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
StopOnException:=True;
ExceptionExitCode:=1;
end;
destructor TWebIDLToPasApplication.Destroy;
begin
FreeAndNil(FWebIDLToPas);
inherited Destroy;
end;
procedure TWebIDLToPasApplication.WriteHelp(const Msg: string);
begin
{AllowWriteln}
if (Msg<>'') then
Writeln(StdErr,'Error : ',Msg);
writeln(StdErr,'Usage: ', ExeName, ' [options]');
Writeln(StdErr,'Where option is one or more of');
Writeln(StdErr,'-h --help This help text.');
Writeln(StdErr,'-a --private Write getters/setters as private methods. Default is protected.');
Writeln(StdErr,'-c --constexternal Write consts as external const (no value).');
Writeln(StdErr,'-d --dicttoclass[=Parent] Write dictionaries as classes.');
Writeln(StdErr,'-e --expandunionargs Add overloads for all Union typed function arguments.');
Writeln(StdErr,'-f --outputformat=[pas2js|wasmjob] Output format, default ',WebIDLToPasFormatNames[OutputFormat],'.');
Writeln(StdErr,'-g --globals=list A comma separated list of global vars.');
Writeln(StdErr,' Use @filename to load the globals from file.');
Writeln(StdErr,' wasmjob: PasVarName=JSClassName,JOBRegisterName');
Writeln(StdErr,'-i --input=FileName Input webidl file.');
Writeln(StdErr,'-m --implementation=Filename include file as implementation.');
Writeln(StdErr,'-n --include=Filename Include file at end of interface.');
Writeln(StdErr,'-o --output=FileName Output file. Defaults to unit name with .pas extension appended.');
Writeln(StdErr,'-p --optionsinheader Add options to header of generated file.');
Writeln(StdErr,'-l --used=types A comma separated list of used IDL types. Only these types and necessary dependent types will be converted.');
Writeln(StdErr,' use @filename to load the globals from file.');
Writeln(StdErr,'-t --typealiases=alias A comma separated list of type aliases in Alias=Name form.');
Writeln(StdErr,' use @filename to load the aliases from file.');
Writeln(StdErr,'-u --unitname=Name name for unit. Defaults to input file without extension.');
Writeln(StdErr,'-v --verbose Output some diagnostic information.');
Writeln(StdErr,'-w --webidlversion=V Set web IDL version. Allowed values: v1 or v2.');
Writeln(StdErr,'-x --extra=units Extra units to put in uses clause (comma separated list).');
Writeln(StdErr,'-b --banned=list List of classes that may not be added to the final file (exclude e.g. window classes for workers)');
ExitCode:=Ord(Msg<>'');
{AllowWriteln-}
end;
var
Application: TWebIDLToPasApplication;
begin
Application:=TWebIDLToPasApplication.Create(nil);
Application.Title:='WebIDL To Pascal converter Application';
Application.Run;
Application.Free;
end.