123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- {
- Automatic XML-RPC wrapper generator
- Copyright (c) 2003 by
- Areca Systems GmbH / Sebastian Guenther, [email protected]
- 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 MkXMLRPC;
- {$mode objfpc}
- {$H+}
- uses SysUtils, Classes, PParser, PasTree, PasWrite;
- resourcestring
- SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
- SNoServerClassNameProvided =
- 'No server class name provided (use --serverclass=<name>)';
- SNoUnitNameProvided =
- 'No name for generated unit provided (use --unitname=<name>)';
- type
- TParserEngine = class(TPasTreeContainer)
- protected
- Modules, UsedModules: TList;
- CurModule: TPasModule;
- public
- constructor Create;
- destructor Destroy; override;
- function CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility;
- const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
- override;
- function FindElement(const AName: String): TPasElement; override;
- function FindModule(const AName: String): TPasModule; override;
- end;
- TServerClass = class
- Element: TPasClassType;
- ImplName: String;
- end;
- TRPCList = class
- ServerClasses: TList;
- UsedModules: TStringList;
- constructor Create;
- destructor Destroy; override;
- procedure AddServerClass(const AClassName: String);
- end;
- var
- Engine: TParserEngine;
- constructor TParserEngine.Create;
- begin
- inherited Create;
- Modules := TList.Create;
- UsedModules := TList.Create;
- end;
- destructor TParserEngine.Destroy;
- begin
- UsedModules.Free;
- Modules.Free;
- inherited Destroy;
- end;
- function TParserEngine.CreateElement(AClass: TPTreeElement; const AName: String;
- AParent: TPasElement; AVisibility: TPasMemberVisibility;
- const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
- begin
- Result := AClass.Create(AName, AParent);
- Result.Visibility := AVisibility;
- if AClass.InheritsFrom(TPasModule) then
- begin
- Modules.Add(Result);
- CurModule := TPasModule(Result);
- end;
- end;
- function TParserEngine.FindElement(const AName: String): TPasElement;
- function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
- var
- l: TList;
- i, j: Integer;
- Found: Boolean;
- begin
- l := AModule.InterfaceSection.Declarations;
- for i := 0 to l.Count - 1 do
- begin
- Result := TPasElement(l[i]);
- if CompareText(Result.Name, LocalName) = 0 then
- begin
- Found := False;
- for j := 0 to UsedModules.Count - 1 do
- if CompareText(TPasModule(UsedModules[j]).Name, AModule.Name) = 0 then
- begin
- Found := True;
- break;
- end;
- if not Found then
- UsedModules.Add(AModule);
- exit;
- end;
- end;
- Result := nil;
- end;
- var
- i: Integer;
- //ModuleName, LocalName: String;
- Module: TPasElement;
- begin
- {!!!: Don't know if we ever will have to use the following:
- i := Pos('.', AName);
- if i <> 0 then
- begin
- WriteLn('Dot found in name: ', AName);
- Result := nil;
- end else
- begin}
- Result := FindInModule(CurModule, AName);
- if not Assigned(Result) then
- for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
- begin
- Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
- if Module.ClassType = TPasModule then
- begin
- Result := FindInModule(TPasModule(Module), AName);
- if Assigned(Result) then
- exit;
- end;
- end;
- {end;}
- end;
- function TParserEngine.FindModule(const AName: String): TPasModule;
- var
- i: Integer;
- begin
- for i := Modules.Count - 1 downto 0 do
- begin
- Result := TPasModule(Modules[i]);
- if CompareText(Result.Name, AName) = 0 then
- exit;
- end;
- Result := nil;
- end;
- constructor TRPCList.Create;
- begin
- ServerClasses := TList.Create;
- UsedModules := TStringList.Create;
- end;
- destructor TRPCList.Destroy;
- var
- i: Integer;
- begin
- UsedModules.Free;
- for i := 0 to ServerClasses.Count - 1 do
- TServerClass(ServerClasses[i]).Free;
- ServerClasses.Free;
- end;
- procedure TRPCList.AddServerClass(const AClassName: String);
- var
- Element: TPasClassType;
- ServerClass: TServerClass;
- begin
- Element := TPasClassType(Engine.FindElement(AClassName));
- if not Assigned(Element) then
- begin
- WriteLn(StdErr, 'Server class "', AClassName, '" not found!');
- Halt(3);
- end;
- if (not Element.InheritsFrom(TPasClassType)) or
- (Element.ObjKind <> okClass) then
- begin
- WriteLn('"', AClassName, '" is not a class!');
- Halt(4);
- end;
- ServerClass := TServerClass.Create;
- ServerClasses.Add(ServerClass);
- ServerClass.Element := Element;
- ServerClass.ImplName := Copy(Element.Name, 2, Length(Element.Name));
- UsedModules.Add(Element.GetModule.Name);
- end;
- var
- OutputFilename, UnitName: String;
- RPCList: TRPCList;
- procedure WriteClassServerSource(ServerClass: TPasClassType;
- ImplementationSection: TPasSection; Method, ProcImpl: TPasProcedureImpl;
- const MethodPrefix: String; NestingLevel: Integer);
- { Method: Main server method
- ProcImpl: Current procedure (may be identical with Method) }
- type
- TConversionInfo = record
- ConverterName, TypecastFunction: String;
- ArgIsParent: Boolean;
- end;
- function MakeStructConverter(AClass: TPasClassType;
- Referrer: TPasProcedureImpl): TPasProcedureImpl; forward;
- function MakeArrayConverter(Member, ArraySizeProp: TPasProperty;
- ProcessProc, Referrer: TPasProcedureImpl): TPasProcedureImpl; forward;
- function FindArraySizeProperty(AArrayProp: TPasProperty): TPasProperty;
- var
- i: Integer;
- Name: String;
- begin
- Name := Copy(AArrayProp.Name, 1, Length(AArrayProp.Name) - 1) + 'Count';
- for i := 0 to TPasClassType(AArrayProp.Parent).Members.Count - 1 do
- begin
- Result := TPasProperty(TPasClassType(AArrayProp.Parent).Members[i]);
- if (Result.ClassType = TPasProperty) and (Result.Visibility = visPublic)
- and (CompareStr(Result.Name, Name) = 0) then
- exit;
- end;
- Name := AArrayProp.Name + 'Count';
- for i := 0 to TPasClassType(AArrayProp.Parent).Members.Count - 1 do
- begin
- Result := TPasProperty(TPasClassType(AArrayProp.Parent).Members[i]);
- if (Result.ClassType = TPasProperty) and (Result.Visibility = visPublic)
- and (CompareStr(Result.Name, Name) = 0) then
- exit;
- end;
- Result := nil;
- end;
- function GetConversionInfo(Element: TPasElement;
- Referrer: TPasProcedureImpl): TConversionInfo;
- var
- s: String;
- ArraySizeProp: TPasProperty;
- begin
- FillChar(Result, SizeOf(Result), 0);
- Result.ArgIsParent := False;
- if Element.ClassType = TPasProperty then
- begin
- ArraySizeProp := FindArraySizeProperty(TPasProperty(Element));
- if Assigned(ArraySizeProp) then
- begin
- Result.ConverterName := MakeArrayConverter(TPasProperty(Element),
- ArraySizeProp, ProcImpl, Referrer).Name;
- Result.ArgIsParent := True;
- exit;
- end else
- Element := TPasProperty(Element).VarType;
- end;
- if Element.ClassType = TPasUnresolvedTypeRef then
- begin
- s := UpperCase(Element.Name);
- if (s = 'BYTE') or (s = 'SHORTINT') or (S = 'SMALLINT') or
- (s = 'INTEGER') or (s = 'LONGINT') or (s = 'CARDINAL') or
- (s = 'INT64') or (s = 'QUADWORD') then
- Result.ConverterName := 'AWriter.CreateIntValue'
- else if (s = 'BOOLEAN') or (s = 'WORDBOOL') or (s = 'LONGBOOL') then
- Result.ConverterName := 'AWriter.CreateBooleanValue'
- else if s = 'STRING' then
- Result.ConverterName := 'AWriter.CreateStringValue'
- else if (s = 'FLOAT') or (s = 'SINGLE') or (s = 'DOUBLE') or
- (s = 'EXTENDED') then
- Result.ConverterName := 'AWriter.CreateDoubleValue'
- else if s = 'TDATETIME' then
- Result.ConverterName := 'AWriter.CreateDateTimeValue';
- end else if Element.ClassType = TPasClassType then
- Result.ConverterName := MakeStructConverter(TPasClassType(Element), Referrer).Name
- else if Element.ClassType = TPasEnumType then
- begin
- Result.ConverterName := 'AWriter.CreateIntValue';
- Result.TypecastFunction := 'Ord';
- end;
- if Length(Result.ConverterName) = 0 then
- raise Exception.Create('Result type not supported: ' + Element.ClassName +
- ' ' + Element.Name);
- end;
- function MakeAccessor(ConversionInfo: TConversionInfo;
- const DataSource, ArrayIndex: String): String;
- begin
- Result := ConversionInfo.ConverterName + '(';
- if ConversionInfo.TypecastFunction <> '' then
- Result := Result + ConversionInfo.TypecastFunction + '(';
- Result := Result + DataSource;
- if ConversionInfo.TypecastFunction <> '' then
- Result := Result + ')';
- if ArrayIndex <> '' then
- Result := Result + '[' + ArrayIndex + ']';
- Result := Result + ')';
- end;
- function GetParseValueFnName(PasType: TPasElement): String;
- var
- s: String;
- begin
- SetLength(Result, 0);
- if PasType.ClassType = TPasArgument then
- begin
- if TPasArgument(PasType).Access = argVar then
- raise Exception.Create('"var" arguments are not allowed');
- PasType := TPasArgument(PasType).ArgType;
- end;
- if PasType.ClassType = TPasUnresolvedTypeRef then
- begin
- s := UpperCase(PasType.Name);
- if (s = 'BYTE') or (s = 'SHORTINT') or (S = 'SMALLINT') or
- (s = 'INTEGER') or (s = 'LONGINT') or (s = 'CARDINAL') or
- (s = 'INT64') or (s = 'QUADWORD') then
- Result := 'Int'
- else if (s = 'BOOLEAN') or (s = 'WORDBOOL') or (s = 'LONGBOOL') then
- Result := 'Boolean'
- else if s = 'STRING' then
- Result := 'String'
- else if (s = 'FLOAT') or (s = 'SINGLE') or (s = 'DOUBLE') or
- (s = 'EXTENDED') then
- Result := 'Double'
- else if s = 'TDATETIME' then
- Result := 'DateTime';
- end;
- if Length(Result) = 0 then
- raise Exception.Create('Argument type not supported: ' +
- PasType.ClassName + ' ' + PasType.Name);
- end;
- function NeedLocalProc(const ProcName: String;
- Referrer: TPasProcedureImpl): TPasProcedureImpl;
- var
- i, j: Integer;
- begin
- for i := 0 to Method.Locals.Count - 1 do
- begin
- Result := TPasProcedureImpl(Method.Locals[i]);
- if Result.Name = ProcName then
- begin
- j := Method.Locals.IndexOf(Referrer);
- if (j >= 0) and (i >= j) then
- begin
- // Move existing converter to the top and exit
- Method.Locals.Delete(i);
- j := Method.Locals.IndexOf(ProcImpl);
- if j < 0 then
- j := 0;
- Method.Locals.Insert(j, Result);
- end;
- exit;
- end;
- end;
- Result := nil;
- end;
- function MakeStructConverter(AClass: TPasClassType;
- Referrer: TPasProcedureImpl): TPasProcedureImpl;
- var
- ConverterName, s: String;
- Commands: TPasImplCommands;
- i: Integer;
- LocalMember: TPasElement;
- ConversionInfo: TConversionInfo;
- begin
- ConverterName := 'Convert' + AClass.Name;
- Result := NeedLocalProc(ConverterName, Referrer);
- if Assigned(Result) then
- exit;
- Result := TPasProcedureImpl.Create(ConverterName, Method);
- i := Method.Locals.IndexOf(Referrer);
- if i < 0 then
- i := 0;
- Method.Locals.Insert(i, Result);
- Result.ProcType := TPasFunctionType.Create('', Result);
- Result.ProcType.CreateArgument('Inst', AClass.Name);
- TPasFunctionType(Result.ProcType).ResultEl :=
- TPasResultElement.Create('', Result);
- TPasFunctionType(Result.ProcType).ResultEl.ResultType :=
- TPasUnresolvedTypeRef.Create('TXMLRPCStruct', Result);
- Result.Body := TPasImplBlock.Create('', Result);
- Commands := Result.Body.AddCommands;
- Commands.Commands.Add('Result := AWriter.CreateStruct');
- for i := 0 to AClass.Members.Count - 1 do
- begin
- LocalMember := TPasElement(AClass.Members[i]);
- if LocalMember.ClassType = TPasProperty then
- begin
- ConversionInfo := GetConversionInfo(LocalMember, Result);
- if ConversionInfo.ArgIsParent then
- s := 'Inst'
- else
- s := 'Inst.' + LocalMember.Name;
- s := 'AWriter.AddStructMember(Result, ''' + LocalMember.Name + ''', ' +
- MakeAccessor(ConversionInfo, s, '') + ')';
- Commands.Commands.Add(s);
- end;
- end;
- end;
- function MakeArrayConverter(Member, ArraySizeProp: TPasProperty;
- ProcessProc, Referrer: TPasProcedureImpl): TPasProcedureImpl;
- var
- i: Integer;
- ConverterName, s: String;
- Commands: TPasImplCommands;
- VarMember: TPasVariable;
- ForLoop: TPasImplForLoop;
- ConversionInfo: TConversionInfo;
- begin
- ConverterName := 'Convert' + Member.Parent.Name + '_' + Member.Name;
- Result := NeedLocalProc(ConverterName, Referrer);
- if Assigned(Result) then
- exit;
- Result := TPasProcedureImpl.Create(ConverterName, Method);
- i := Method.Locals.IndexOf(Referrer);
- if i < 0 then
- i := 0;
- Method.Locals.Insert(i, Result);
- Result.ProcType := TPasFunctionType.Create('', Result);
- Result.ProcType.CreateArgument('Inst', Member.Parent.Name);
- TPasFunctionType(Result.ProcType).ResultEl :=
- TPasResultElement.Create('', Result);
- TPasFunctionType(Result.ProcType).ResultEl.ResultType :=
- TPasUnresolvedTypeRef.Create('TXMLRPCArray', Result);
- Result.Body := TPasImplBlock.Create('', Result);
- Commands := Result.Body.AddCommands;
- Commands.Commands.Add('Result := AWriter.CreateArray');
- VarMember := TPasVariable.Create('i', Result);
- Result.Locals.Add(VarMember);
- VarMember.VarType := TPasUnresolvedTypeRef.Create('Integer', VarMember);
- ForLoop := Result.Body.AddForLoop(TPasVariable.Create('i', Result),
- '0', MethodPrefix + ArraySizeProp.Name + ' - 1');
- ForLoop.Body := TPasImplCommand.Create('', ForLoop);
- ConversionInfo := GetConversionInfo(Member.VarType, Result);
- if ConversionInfo.ArgIsParent then
- s := 'Inst'
- else
- s := 'Inst.' + Member.Name + '[i]';
- s := 'AWriter.AddArrayElement(Result, ' +
- MakeAccessor(ConversionInfo, s, '') + ')';
- TPasImplCommand(ForLoop.Body).Command := s;
- end;
- function CreateDispatcher(VarType: TPasClassType;
- Referrer: TPasProcedureImpl): TPasProcedureImpl;
- var
- DispatcherName: String;
- begin
- DispatcherName := 'Dispatch' + VarType.Name;
- Result := NeedLocalProc(DispatcherName, Referrer);
- if Assigned(Result) then
- exit;
- // Create new dispatcher method
- Result := TPasProcedureImpl.Create(DispatcherName, Method);
- if ProcImpl = Method then
- Method.Locals.Insert(0, Result)
- else
- Method.Locals.Insert(Method.Locals.IndexOf(Referrer), Result);
- Result.ProcType := TPasProcedureType.Create('', Result);
- Result.ProcType.CreateArgument('Inst', VarType.Name);
- Result.ProcType.CreateArgument('Level', 'Integer');
- WriteClassServerSource(VarType,
- ImplementationSection, Method, Result, 'Inst.', NestingLevel + 1);
- end;
- var
- IfElse, ParentIfElse: TPasImplIfElse;
- procedure CreateBranch(const MethodName: String);
- begin
- if Assigned(ParentIfElse) then
- begin
- IfElse := TPasImplIfElse.Create('', ParentIfElse);
- ParentIfElse.ElseBranch := IfElse;
- end else
- begin
- IfElse := TPasImplIfElse.Create('', ProcImpl.Body);
- ProcImpl.Body.Elements.Add(IfElse);
- end;
- ParentIfElse := IfElse;
- IfElse.Condition := 's = ''' + UpperCase(MethodName) + '''';
- end;
- procedure ProcessMethodCall(Member: TPasProcedure);
- function MakeProcArgs(Args: TList): String;
- var
- i: Integer;
- begin
- if (not Assigned(Args)) or (Args.Count = 0) then
- Result := ''
- else
- begin
- Result := '(';
- for i := 0 to Args.Count - 1 do
- begin
- if i > 0 then
- Result := Result + ', ';
- Result := Result + 'AParser.GetPrev' + GetParseValueFnName(TPasType(Args[i]));
- end;
- Result := Result + ')';
- end;
- end;
- var
- Commands: TPasImplCommands;
- s: String;
- begin
- CreateBranch(Member.Name);
- Commands := TPasImplCommands.Create('', IfElse);
- IfElse.IfBranch := Commands;
- if TPasProcedure(Member).ProcType.Args.Count > 0 then
- Commands.Commands.Add('AParser.ResetValueCursor');
- if Member.ClassType = TPasProcedure then
- begin
- Commands.Commands.Add(MethodPrefix + Member.Name +
- MakeProcArgs(TPasProcedure(Member).ProcType.Args));
- Commands.Commands.Add('AWriter.WriteResponse(nil)');
- end else
- begin
- // function
- s := MethodPrefix + Member.Name +
- MakeProcArgs(TPasProcedure(Member).ProcType.Args);
- Commands.Commands.Add('AWriter.WriteResponse(' +
- MakeAccessor(GetConversionInfo(TPasFunctionType(TPasFunction(Member).
- ProcType).ResultEl.ResultType, ProcImpl), s, '') + ')');
- end;
- end;
- procedure ProcessProperty(Member: TPasProperty);
- var
- LocalIfElse: TPasImplIfElse;
- IsArray, IsStruct: Boolean;
- s, s2: String;
- Commands: TPasImplCommands;
- Command: TPasImplCommand;
- ConversionInfo: TConversionInfo;
- begin
- if Member.ReadAccessorName <> '' then
- begin
- CreateBranch('Get' + Member.Name);
- IsArray := (Member.Args.Count = 1) and
- Assigned(FindArraySizeProperty(Member));
- IsStruct := Member.VarType.ClassType = TPasClassType;
- if IsStruct then
- s := CreateDispatcher(TPasClassType(Member.VarType), ProcImpl).Name +
- '(' + MethodPrefix + Member.Name;
- if NestingLevel = 0 then
- s2 := '1'
- else
- s2 := 'Level + 1';
- if IsArray or (IsStruct and (Member.Args.Count = 0)) then
- begin
- LocalIfElse := TPasImplIfElse.Create('', IfElse);
- IfElse.IfBranch := LocalIfElse;
- LocalIfElse.Condition := 'APath.Count <= ' + s2;
- end;
- if IsStruct then
- if IsArray then
- begin
- LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
- TPasImplCommand(LocalIfElse.IfBranch).Command :=
- 'AWriter.WriteResponse(' +
- MakeAccessor(GetConversionInfo(Member, ProcImpl),
- Copy(MethodPrefix, 1, Length(MethodPrefix) - 1), '') + ')';
- LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
- TPasImplCommand(LocalIfElse.ElseBranch).Command :=
- s + '[AParser.GetNext' +
- GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType) + '], ' +
- s2 + ')';
- end else
- begin
- if Member.Args.Count = 0 then
- begin
- LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
- TPasImplCommand(LocalIfElse.IfBranch).Command :=
- 'AWriter.WriteResponse(' +
- MakeAccessor(GetConversionInfo(Member, ProcImpl),
- MethodPrefix + Member.Name, '') + ')';
- LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
- TPasImplCommand(LocalIfElse.ElseBranch).Command := s + ', ' + s2 + ')';
- end else
- begin
- IfElse.IfBranch := TPasImplCommand.Create('', IfElse);
- TPasImplCommand(IfElse.IfBranch).Command := s + '[AParser.GetNext' +
- GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType) + '], ' +
- s2 + ')';
- end;
- end
- else if IsArray then
- begin
- LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
- TPasImplCommand(LocalIfElse.IfBranch).Command :=
- 'AWriter.WriteResponse(' +
- MakeAccessor(GetConversionInfo(Member, ProcImpl),
- Copy(MethodPrefix, 1, Length(MethodPrefix) - 1), '') + ')';
- LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
- TPasImplCommand(LocalIfElse.ElseBranch).Command :=
- 'AWriter.WriteResponse(' +
- MakeAccessor(GetConversionInfo(Member.VarType, ProcImpl),
- MethodPrefix + Member.Name, 'AParser.GetNext' +
- GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType)) + ')';
- end else
- begin
- IfElse.IfBranch := TPasImplCommand.Create('', IfElse);
- TPasImplCommand(IfElse.IfBranch).Command := 'AWriter.WriteResponse(' +
- MakeAccessor(GetConversionInfo(Member.VarType, ProcImpl),
- MethodPrefix + Member.Name, '') + ')';
- end;
- end;
- if Member.WriteAccessorName <> '' then
- begin
- CreateBranch('Set' + Member.Name);
- Commands := TPasImplCommands.Create('', IfElse);
- IfElse.IfBranch := Commands;
- Commands.Commands.Add('// Not supported by mkxmlrpc yet');
- end;
- end;
- var
- VarMember: TPasVariable;
- i: Integer;
- Command: TPasImplCommand;
- Member: TPasElement;
- begin
- VarMember := TPasVariable.Create('s', ProcImpl);
- ProcImpl.Locals.Add(VarMember);
- VarMember.VarType := TPasUnresolvedTypeRef.Create('String', VarMember);
- ProcImpl.Body := TPasImplBlock.Create('', ProcImpl);
- if NestingLevel = 0 then
- ProcImpl.Body.AddCommand('s := APath[' + IntToStr(NestingLevel) + ']')
- else
- ProcImpl.Body.AddCommand('s := APath[Level]');
- ParentIfElse := nil;
- for i := 0 to ServerClass.Members.Count - 1 do
- begin
- Member := TPasElement(ServerClass.Members[i]);
- if Member.Visibility <> visPublic then
- continue;
- if (Member.ClassType = TPasProcedure) or (Member.ClassType = TPasFunction)
- then
- ProcessMethodCall(TPasProcedure(Member))
- else if Member.ClassType = TPasProperty then
- ProcessProperty(TPasProperty(Member))
- else if (Member.ClassType <> TPasConstructor) and
- (Member.ClassType <> TPasDestructor) then
- WriteLn('Warning: Unsupportet member type: ', Member.ElementTypeName);
- end;
- if Assigned(ParentIfElse) then
- begin
- Command := TPasImplCommand.Create('', ParentIfElse);
- ParentIfElse.ElseBranch := Command;
- end else
- begin
- Command := TPasImplCommand.Create('', ProcImpl.Body);
- ProcImpl.Body.Elements.Add(Command);
- end;
- Command.Command := 'AWriter.WriteFaultResponse(2, ''Invalid method name'')';
- end;
- procedure WriteFPCServerSource;
- var
- i, j: Integer;
- Module: TPasModule;
- InterfaceSection, ImplementationSection: TPasSection;
- VarMember: TPasVariable;
- PropertyMember: TPasProperty;
- ProcMember: TPasProcedure;
- Arg: TPasArgument;
- ServerClass: TPasClassType;
- Stream: TStream;
- ProcImpl: TPasProcedureImpl;
- Found: Boolean;
- begin
- Module := TPasModule.Create(UnitName, nil);
- try
- InterfaceSection := TPasSection.Create('', Module);
- Module.InterfaceSection := InterfaceSection;
- ImplementationSection := TPasSection.Create('', Module);
- Module.ImplementationSection := ImplementationSection;
- InterfaceSection.AddUnitToUsesList('Classes');
- InterfaceSection.AddUnitToUsesList('XMLRPC');
- for i := 0 to RPCList.UsedModules.Count - 1 do
- InterfaceSection.AddUnitToUsesList(RPCList.UsedModules[i]);
- for i := 0 to RPCList.ServerClasses.Count - 1 do
- with TServerClass(RPCList.ServerClasses[i]) do
- begin
- ServerClass := TPasClassType.Create('T' + ImplName + 'XMLRPCServlet',
- InterfaceSection);
- InterfaceSection.Declarations.Add(ServerClass);
- ServerClass.ObjKind := okClass;
- ServerClass.AncestorType :=
- TPasUnresolvedTypeRef.Create('TXMLRPCServlet', ServerClass);
- // Create private field which holds the implementation instance
- VarMember := TPasVariable.Create('F' + ImplName, ServerClass);
- VarMember.Visibility := visPrivate;
- VarMember.VarType := TPasUnresolvedTypeRef.Create(Element.Name, VarMember);
- ServerClass.Members.Add(VarMember);
- // Create dispatcher method
- ProcMember := TPasProcedure.Create('Dispatch', ServerClass);
- ProcMember.Visibility := visProtected;
- ProcMember.AddModifier(pmOverride);
- ProcMember.ProcType := TPasProcedureType.Create('', ProcMember);
- ProcMember.ProcType.CreateArgument('AParser', 'TXMLRPCParser').
- Visibility := visPublic;
- ProcMember.ProcType.CreateArgument('AWriter', 'TXMLRPCWriter').
- Visibility := visPublic;
- ProcMember.ProcType.CreateArgument('APath', 'TStrings').
- Visibility := visPublic;
- ServerClass.Members.Add(ProcMember);
- // Create published property for implementation instance
- PropertyMember := TPasProperty.Create(ImplName, ServerClass);
- PropertyMember.Visibility := visPublished;
- PropertyMember.VarType := VarMember.VarType;
- VarMember.VarType.AddRef;
- PropertyMember.ReadAccessorName := 'F' + ImplName;
- PropertyMember.WriteAccessorName := 'F' + ImplName;
- ServerClass.Members.Add(PropertyMember);
- // Create dispatcher implementation
- ProcImpl := TPasProcedureImpl.Create('Dispatch', ServerClass);
- ImplementationSection.Declarations.Add(ProcImpl);
- ProcImpl.ProcType := ProcMember.ProcType;
- ProcMember.ProcType.AddRef;
- ProcImpl.ProcType.AddRef;
- WriteClassServerSource(Element, ImplementationSection, ProcImpl,
- ProcImpl, ImplName + '.', 0);
- end;
- for i := 0 to Engine.UsedModules.Count - 1 do
- begin
- Found := False;
- for j := 0 to RPCList.UsedModules.Count - 1 do
- if CompareText(RPCList.UsedModules[j],
- TPasModule(Engine.UsedModules[i]).Name) = 0 then
- begin
- Found := True;
- break;
- end;
- if not Found then
- ImplementationSection.AddUnitToUsesList(
- TPasModule(Engine.UsedModules[i]).Name);
- end;
- Stream := THandleStream.Create(StdOutputHandle);
- try
- WritePasFile(Module, Stream);
- finally
- Stream.Free;
- end;
- Stream := TFileStream.Create(OutputFilename, fmCreate);
- try
- WritePasFile(Module, Stream);
- finally
- Stream.Free;
- end;
- finally
- Module.Free;
- end;
- end;
- var
- i, j: Integer;
- s, Cmd, Arg: String;
- InputFiles, ClassList: TStringList;
- begin
- InputFiles := TStringList.Create;
- ClassList := TStringList.Create;
- try
- for i := 1 to ParamCount do
- begin
- s := ParamStr(i);
- j := Pos('=', s);
- if j > 0 then
- begin
- Cmd := Copy(s, 1, j - 1);
- Arg := Copy(s, j + 1, Length(s));
- end else
- begin
- Cmd := s;
- SetLength(Arg, 0);
- end;
- if (Cmd = '-i') or (Cmd = '--input') then
- InputFiles.Add(Arg)
- else if Cmd = '--output' then
- OutputFilename := Arg
- else if Cmd = '--unitname' then
- UnitName := Arg
- else if Cmd = '--serverclass' then
- ClassList.Add(Arg)
- else
- WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
- end;
- if ClassList.Count = 0 then
- begin
- WriteLn(StdErr, SNoServerClassNameProvided);
- Halt(2);
- end;
- if UnitName = '' then
- begin
- WriteLn(StdErr, SNoUnitNameProvided);
- Halt(2);
- end;
- Engine := TParserEngine.Create;
- try
- // Engine.SetPackageName('XMLRPC');
- for i := 0 to InputFiles.Count - 1 do
- ParseSource(Engine, InputFiles[i], '', '');
- RPCList := TRPCList.Create;
- try
- for i := 0 to ClassList.Count - 1 do
- RPCList.AddServerClass(ClassList[i]);
- WriteFPCServerSource;
- finally
- RPCList.Free;
- end;
- finally
- Engine.Free;
- end;
- finally
- InputFiles.Free;
- ClassList.Free;
- end;
- end.
|