chelper: improved objc interface parsing and code generation

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1284 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz
2010-08-15 11:53:16 +00:00
parent 2a5f151adc
commit 838a446e4a
2 changed files with 107 additions and 57 deletions

View File

@ -18,7 +18,6 @@
} }
unit ctopasconvert; unit ctopasconvert;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
interface interface
@ -50,6 +49,8 @@ type
CustomDefines : AnsiString; CustomDefines : AnsiString;
// obj-c
RemoveLastUnderscores : Boolean;
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
@ -142,7 +143,7 @@ type
procedure WriteExp(x: TExpression); procedure WriteExp(x: TExpression);
procedure WritePreprocessor(cent: TCPrepDefine); procedure WritePreprocessor(cent: TCPrepDefine);
function GetObjCMethodName(names: TStrings): AnsiString; function GetPasObjCMethodName(names: TStrings): AnsiString;
procedure WriteObjCMethod(m: TObjCMethod); procedure WriteObjCMethod(m: TObjCMethod);
procedure WriteObjCInterface(cent: TObjCInterface); procedure WriteObjCInterface(cent: TObjCInterface);
@ -590,40 +591,40 @@ begin
end; end;
end; end;
function TCodeConvertor.GetObjCMethodName(names:TStrings):AnsiString; function TCodeConvertor.GetPasObjCMethodName(names:TStrings):AnsiString;
var var
i : Integer; i : Integer;
begin begin
Result:=''; Result:='';
for i:=0 to names.Count-1 do Result:=Result+names[i]; for i:=0 to names.Count-1 do Result:=Result+names[i];
for i:=1 to length(Result) do if Result[i]=':' then Result[i]:='_'; for i:=1 to length(Result) do if Result[i]=':' then Result[i]:='_';
if cfg.RemoveLastUnderscores then begin
i:=length(Result);
while (i>0) and (Result[i]='_') do dec(i);
Result:=Copy(Result, 1, i);
end;
end; end;
procedure TCodeConvertor.WriteObjCMethod(m: TObjCMethod); procedure TCodeConvertor.WriteObjCMethod(m: TObjCMethod);
var var
ret : AnsiString; ret : AnsiString;
i : INteger; i : Integer;
PNames : array of AnsiString;
PTypes : array of AnsiString;
begin begin
if m.RetType=nil then ret:='id' else ret:=GetPasTypeName(m.RetType, m.RetName); if m.RetType=nil then ret:='id' else ret:=GetPasTypeName(m.RetType, m.RetName);
if ret='' then wr.W('procedure ') SetLength(PNames, length(m.Args));
else wr.W('function '); SetLength(PTypes, length(m.Args));
wr.W( GetObjCMethodName(m.Name) ); if length(m.Args)>0 then
if length(m.Args)>0 then begin
wr.W('(');
for i:=0 to length(m.Args)-1 do begin for i:=0 to length(m.Args)-1 do begin
if m.Args[i].Name='' then wr.W(cfg.ParamPrefix+IntToStr(i)) if m.Args[i].Name=''
else wr.W(m.Args[i].Name); then PNames[i]:=cfg.ParamPrefix+IntToStr(i)
wr.W(': '); else PNames[i]:=m.Args[i].Name;
wr.W(GetPasTypeName(m.Args[i].RetType, m.Args[i].TypeName)); PTypes[i]:=GetPasTypeName(m.Args[i].RetType, m.Args[i].TypeName);
if i<length(m.Args)-1 then wr.W('; ');
end; end;
wr.W(')');
end;
if ret<>'' then wr.W(': '+ ret); DefFuncWrite(wr, GetPasObjCMethodName(m.Name), ret, PNames, PTypes);
wr.W(';'); wr.W(';');
wr.W(' message '''); wr.W(' message ''');
for i:=0 to m.Name.Count-1 do wr.W(m.Name[i]); for i:=0 to m.Name.Count-1 do wr.W(m.Name[i]);
wr.Wln(''';'); wr.Wln(''';');
@ -633,6 +634,11 @@ procedure TCodeConvertor.WriteObjCInterface(cent:TObjCInterface);
var var
i : Integer; i : Integer;
m : TObjCMethod; m : TObjCMethod;
sc : TObjCScope;
v : TObjCInstVar;
sect : AnsiString;
const
sectname : array [TObjCScope] of AnsiString = ('private', 'protected', 'public', 'protected');
begin begin
SetPasSection(wr, 'type'); SetPasSection(wr, 'type');
if cent.isCategory then begin if cent.isCategory then begin
@ -647,16 +653,33 @@ begin
wr.W(cent.Protocols[cent.Protocols.Count-1]); wr.W(cent.Protocols[cent.Protocols.Count-1]);
end; end;
if (cent.SuperClass<>'') or (cent.Protocols.Count>0) then wr.Wln(')'); if (cent.SuperClass<>'') or (cent.Protocols.Count>0) then wr.Wln(')');
sect:='';
sc:=os_Public;
for i:=0 to cent.Vars.Count-1 do begin
v:=TObjCInstVar(cent.Vars[i]);
if (sect='') or (v.scope<>sc) then begin
if sect<>'' then wr.DecIdent;
sc:=v.scope;
sect:=sectname[sc];
wr.Wln(sect);
wr.IncIdent;
end;
WriteFuncOrVar(v.v, false, true);
end;
if sect<>'' then wr.DecIdent;
end; end;
wr.Wln('public'); if cent.Methods.Count>0 then begin
wr.IncIdent; wr.Wln('public');
for i:=0 to cent.Methods.Count-1 do begin wr.IncIdent;
m:=TObjCMethod(cent.Methods[i]); for i:=0 to cent.Methods.Count-1 do begin
WriteObjCMethod(m) m:=TObjCMethod(cent.Methods[i]);
WriteObjCMethod(m)
end;
wr.DecIdent;
wr.Wln('end;')
end; end;
wr.DecIdent;
wr.Wln('end;')
end; end;
procedure TCodeConvertor.PushWriter; procedure TCodeConvertor.PushWriter;

View File

@ -1,3 +1,21 @@
{ The unit is part of Lazarus Chelper package
Copyright (C) 2010 Dmitry Boyarintsev skalogryz dot lists at gmail.com
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library 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 Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
}
unit unit
objcparsing; objcparsing;
@ -38,6 +56,17 @@ type
procedure AddArg(const ArgType: TEntity; ArgTypeName: TNamePart; const Name: AnsiString); procedure AddArg(const ArgType: TEntity; ArgTypeName: TNamePart; const Name: AnsiString);
end; end;
TObjCScope = (os_Private, os_Protected, os_Public, os_Package);
{ TObjCInstVar }
TObjCInstVar = class(TEntity)
public
scope : TObjCScope;
v : TVarFuncEntity;
destructor Destroy; override;
end;
{ TObjCInterface } { TObjCInterface }
TObjCInterface = class(TEntity) TObjCInterface = class(TEntity)
@ -46,10 +75,7 @@ type
SuperClass : AnsiString; SuperClass : AnsiString;
isCategory : Boolean; isCategory : Boolean;
Protocols : TStringList; Protocols : TStringList;
ProtVars : TList; Vars : TList;
PrivVars : TList;
PubVars : TList;
PackVars : TList;
Methods : TList; Methods : TList;
constructor Create(AOffset: Integer=-1); override; constructor Create(AOffset: Integer=-1); override;
destructor Destroy; override; destructor Destroy; override;
@ -106,37 +132,40 @@ begin
Result:=cl; Result:=cl;
end; end;
function ParseInstVars(AParser: TTextParser; itf: TObjCInterface): Boolean; function ParseInstVars(AParser: TTextParser; Vars: TList): Boolean;
var var
vars : TList;
v : TVarFuncEntity; v : TVarFuncEntity;
iv : TObjCInstVar;
s : AnsiString; s : AnsiString;
scope : TObjCScope;
begin begin
Result:=True; Result:=True;
if AParser.Token<>'{' then Exit; if AParser.Token<>'{' then Exit;
Result:=False; Result:=False;
AParser.NextToken; AParser.NextToken;
vars:=itf.ProtVars;
scope:=os_Protected;
while AParser.Token<>'}' do begin while AParser.Token<>'}' do begin
if isObjCKeyword(AParser.Token) then begin if isObjCKeyword(AParser.Token) then begin
s:=GetObjCKeyword(APArser.Token); s:=GetObjCKeyword(APArser.Token);
if s='protected' then vars:=itf.ProtVars if s='protected' then scope:=os_Protected
else if s='private' then vars:=itf.PrivVars else if s='private' then scope:=os_Private
else if s='public' then vars:=itf.PubVars else if s='public' then scope:=os_Public
else if s='package' then vars:=itf.PackVars else if s='package' then scope:=os_Package
else begin else begin
ErrorExpect(AParser,'}'); ErrorExpect(AParser,'}');
Exit; Exit;
end; end;
AParser.NextToken; AParser.NextToken;
end else begin end else begin
v:=TVarFuncEntity.Create(APArser.TokenPos); v:=TVarFuncEntity.Create(AParser.TokenPos);
if not ParseNames(AParser, v.RetType, v.Names) then Exit; if not ParseNames(AParser, v.RetType, v.Names) then Exit;
vars.Add(v); iv:=TObjCInstVar.Create(v.Offset);
if AParser.Token=';' then iv.v:=v;
AParser.NextToken; iv.scope:=scope;
Vars.Add(iv);
if AParser.Token=';' then AParser.NextToken;
end; end;
end; end;
AParser.NextToken; AParser.NextToken;
@ -191,7 +220,7 @@ begin
end; end;
//writeln('parsing vars1 ', AParser.Token); //writeln('parsing vars1 ', AParser.Token);
ParseInstVars(AParser, itf); ParseInstVars(AParser, itf.Vars);
//writeln('parsing vars2 ', AParser.Token); //writeln('parsing vars2 ', AParser.Token);
end; end;
@ -250,10 +279,7 @@ end;
constructor TObjCInterface.Create(AOffset:Integer); constructor TObjCInterface.Create(AOffset:Integer);
begin begin
ProtVars := TList.Create; Vars := TList.Create;
PrivVars := TList.Create;
PubVars := TList.Create;
PackVars := TList.Create;
Methods := TList.Create; Methods := TList.Create;
Protocols := TStringList.Create; Protocols := TStringList.Create;
inherited Create(AOffset); inherited Create(AOffset);
@ -263,18 +289,10 @@ destructor TObjCInterface.Destroy;
var var
i : Integer; i : Integer;
begin begin
for i:=0 to ProtVars.Count-1 do TObject(ProtVars[i]).Free; for i:=0 to Vars.Count-1 do TObject(Vars[i]).Free;
for i:=0 to PrivVars.Count-1 do TObject(PrivVars[i]).Free; Vars.Free;
for i:=0 to PubVars.Count-1 do TObject(PubVars[i]).Free;
for i:=0 to PackVars.Count-1 do TObject(PubVars[i]).Free;
PrivVars.Free;
PubVars.Free;
ProtVars.Free;
PackVars.Free;
for i:=0 to Methods.Count-1 do TObject(Methods[i]).Free; for i:=0 to Methods.Count-1 do TObject(Methods[i]).Free;
Methods.Free; Methods.Free;
Protocols.Free; Protocols.Free;
inherited Destroy; inherited Destroy;
end; end;
@ -388,6 +406,15 @@ begin
Args[i].TypeName:=ArgTypeName; Args[i].TypeName:=ArgTypeName;
end; end;
{ TObjCInstVar }
destructor TObjCInstVar.Destroy;
begin
v.Free;
inherited Destroy;
end;
initialization initialization
PrevParseNextEntity:=ParseNextEntity; PrevParseNextEntity:=ParseNextEntity;
ParseNextEntity:=ParseNextObjCEntity; ParseNextEntity:=ParseNextObjCEntity;