chelper: improved objc support:

Categories now can have protocol support. 
Added parameter method direction modified (in, byref, inout .. etc)
Parsing of non-class entities (typedef, vars and funcs) within class declaration

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4004 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz
2015-03-08 02:29:00 +00:00
parent 7c169b576f
commit 9de53b2440

View File

@ -86,6 +86,7 @@ type
Protocols : TStringList; Protocols : TStringList;
Vars : TList; Vars : TList;
Methods : TList; Methods : TList;
Entities : TList;
constructor Create(AOffset: Integer=-1); override; constructor Create(AOffset: Integer=-1); override;
destructor Destroy; override; destructor Destroy; override;
end; end;
@ -98,6 +99,7 @@ type
isForward : Boolean; isForward : Boolean;
Protocols : TStringList; Protocols : TStringList;
Methods : TList; Methods : TList;
Entities : TList;
constructor Create(AOffset: Integer=-1); override; constructor Create(AOffset: Integer=-1); override;
destructor Destroy; override; destructor Destroy; override;
end; end;
@ -119,7 +121,7 @@ function ParseClassList(AParser: TTextParser): TObjCClasses;
function ParseInterface(AParser: TTextParser): TObjCInterface; function ParseInterface(AParser: TTextParser): TObjCInterface;
function ParseMethod(AParser: TTextParser): TObjCMethod; function ParseMethod(AParser: TTextParser): TObjCMethod;
function ParseProperty(AParser: TTextParser): TObjCProperty; function ParseProperty(AParser: TTextParser): TObjCProperty;
function ParseMethods(AParser: TTextParser; MethodsList: TList; const EndToken: AnsiString = objcend): Boolean; function ParseMethods(AParser: TTextParser; MethodsList, OthersList: TList; const EndToken: AnsiString = objcend): Boolean;
function ParseProtocol(AParser: TTextParser): TEntity; function ParseProtocol(AParser: TTextParser): TEntity;
function ParseNextObjCEntity(AParser: TTextParser): TEntity; function ParseNextObjCEntity(AParser: TTextParser): TEntity;
@ -258,34 +260,28 @@ begin
AParser.NextToken; AParser.NextToken;
if not ConsumeIdentifier(AParser, itf.SuperClass) then Exit; if not ConsumeIdentifier(AParser, itf.SuperClass) then Exit;
end; end;
// protocols
if AParser.Token='<' then begin
AParser.NextToken;
while AParser.Token<>'>' do begin
if not ConsumeIdentifier(AParser, nm) then Exit;
itf.Protocols.Add(nm);
if AParser.Token=',' then AParser.NextToken
else if AParser.Token<>'>' then begin
ErrorExpect(AParser, '>');
Exit;
end;
end;
AParser.NextToken;
end;
{ todo: typedef could be found within class
while APArser.Token='typedef' do begin
ent := ParseTypeDef(APArser );
if not Assigned(ent) then Exit;
itf.Vars.Add(ent);
end;
}
ParseInstVars(AParser, itf.Vars);
end; end;
if not ParseMethods(AParser, itf.Methods, objcend) then Exit; // protocols, also can be specified for categories
if AParser.Token='<' then begin
AParser.NextToken;
while AParser.Token<>'>' do begin
if not ConsumeIdentifier(AParser, nm) then Exit;
itf.Protocols.Add(nm);
if AParser.Token=',' then AParser.NextToken
else if AParser.Token<>'>' then begin
ErrorExpect(AParser, '>');
Exit;
end;
end;
AParser.NextToken;
end;
// categories cannot have instance variables
if not itf.isCategory then ParseInstVars(AParser, itf.Vars);
if not ParseMethods(AParser, itf.Methods, itf.Entities, objcend) then Exit;
if AParser.Token<>objcend then ErrorExpect(AParser, objcend); if AParser.Token<>objcend then ErrorExpect(AParser, objcend);
Result:=itf; Result:=itf;
@ -328,7 +324,7 @@ begin
if AParser.Token='>' then AParser.NextToken; if AParser.Token='>' then AParser.NextToken;
end; end;
if ParseMethods(AParser, p.Methods, objcend) then if ParseMethods(AParser, p.Methods, p.Entities, objcend) then
Result:=p; Result:=p;
if AParser.Token<>objcend then ErrorExpect(AParser, objcend); if AParser.Token<>objcend then ErrorExpect(AParser, objcend);
finally finally
@ -377,7 +373,8 @@ end;
constructor TObjCInterface.Create(AOffset:Integer); constructor TObjCInterface.Create(AOffset:Integer);
begin begin
Vars := TList.Create; Vars := TList.Create;
Methods := TList.Create; Methods := TList.Create;
Entities := TList.Create;
Protocols := TStringList.Create; Protocols := TStringList.Create;
inherited Create(AOffset); inherited Create(AOffset);
end; end;
@ -390,10 +387,26 @@ begin
Vars.Free; Vars.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;
for i:=0 to Entities.Count-1 do TObject(Entities[i]).Free;
Entities.Free;
Protocols.Free; Protocols.Free;
inherited Destroy; inherited Destroy;
end; end;
function isObjCParamMod(const t: string): Boolean;
begin
if t ='' then Result:=false
else begin
Result:=false;
case t[1] of
'c': if (t = 'const') then Result:=true;
'i': if (t = 'in') or (t = 'inout') then Result:=true;
'o': if (t = 'out') or (t='oneway') then Result:=true;
'b': if (t = 'bycopy') or (t='byref') then Result:=true;
end;
end;
end;
function ParseMethod(AParser: TTextParser): TObjCMethod; function ParseMethod(AParser: TTextParser): TObjCMethod;
var var
m : TObjCMethod; m : TObjCMethod;
@ -425,9 +438,15 @@ begin
while (AParser.Token<>';') and (AParser.Token<>',') do begin while (AParser.Token<>';') and (AParser.Token<>',') do begin
if AParser.Token='(' then begin if AParser.Token='(' then begin
prm:=ConsumeToken(AParser, '(') and prm:=ConsumeToken(AParser, '(');
ParseName(APArser, atype, atname,[')']) and if prm then begin
ConsumeToken(AParser, ')'); // todo: need to store them somewhere!
while isObjCParamMod(AParser.Token) do
AParser.NextToken;
prm:=ParseName(APArser, atype, atname,[')']) and
ConsumeToken(AParser, ')','parsing objc method paramter type');
end;
end else begin end else begin
prm:=True; prm:=True;
atype:=nil; atype:=nil;
@ -440,7 +459,7 @@ begin
// the next name starts // the next name starts
if AParser.TokenType=tt_Ident then ConsumeIdentifier(AParser, nm) else nm:=''; if AParser.TokenType=tt_Ident then ConsumeIdentifier(AParser, nm) else nm:='';
if (AParser.Token<>';') and (AParser.Token<>',') then begin if (AParser.Token<>';') and (AParser.Token<>',') then begin
if not ConsumeToken(AParser,':') then Exit; if not ConsumeToken(AParser,':','parsing the objc method " '+Copy(Aparser.Buf, AParser.Index-30, 40)+'"') then Exit;
m.Name.Add(nm+':'); m.Name.Add(nm+':');
end; end;
end; end;
@ -453,7 +472,7 @@ begin
else ErrorExpect(AParser, '...'); else ErrorExpect(AParser, '...');
end; end;
if not ConsumeToken(AParser, ';') then Exit; if not ConsumeToken(AParser, ';','parsing the end of objc method') then Exit;
Result:=m; Result:=m;
finally finally
@ -461,32 +480,39 @@ begin
end; end;
end; end;
function ParseMethods(AParser: TTextParser; MethodsList: TList; const EndToken: AnsiString): Boolean; function ParseMethods(AParser: TTextParser; MethodsList, OthersList: TList; const EndToken: AnsiString): Boolean;
var var
m : TObjCMethod; m : TObjCMethod;
p : TObjCProperty; p : TObjCProperty;
opt : TObjCMethodOpt; opt : TObjCMethodOpt;
s : AnsiString; s : AnsiString;
ent : TEntity;
begin begin
Result:=False; Result:=False;
if not Assigned(MethodsList) or not Assigned(AParser) then Exit; if not Assigned(MethodsList) or not Assigned(AParser) then Exit;
opt:=mo_Required; opt:=mo_Required;
while (AParser.Token<>EndToken) and (AParser.Token<>'') and (AParser.Token[1] in ['+','-','@']) do begin while (AParser.Token<>EndToken) and (AParser.Token<>'') do begin
if isObjCKeyword(AParser.Token) then begin
s:=GetObjCKeyword(AParser.Token); if (AParser.Token[1] in ['+','-','@']) then begin
if s='property' then begin if isObjCKeyword(AParser.Token) then begin
p:=ParseProperty(AParser); s:=GetObjCKeyword(AParser.Token);
MethodsList.Add(p); if s='property' then begin
p:=ParseProperty(AParser);
MethodsList.Add(p);
end else begin
if s='optional' then opt:=mo_Optional
else opt:=mo_Required;
AParser.NextToken;
end;
end else begin end else begin
if s='optional' then opt:=mo_Optional m:=ParseMethod(AParser);
else opt:=mo_Required; if not Assigned(m) then Exit;
AParser.NextToken; m.Option:=opt;
MethodsList.Add(m);
end; end;
end else begin end else begin
m:=ParseMethod(AParser); ent:=ParseNextCEntity(AParser, false);
if not Assigned(m) then Exit; AParser.NextToken;
m.Option:=opt;
MethodsList.Add(m);
end; end;
end; end;
Result:=True; Result:=True;
@ -542,6 +568,7 @@ begin
inherited Create(AOffset); inherited Create(AOffset);
Protocols := TStringList.Create; Protocols := TStringList.Create;
Methods := TList.Create; Methods := TList.Create;
Entities := TList.Create;
Names := TStringList.Create; Names := TStringList.Create;
end; end;
@ -551,6 +578,8 @@ var
begin begin
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;
for i:=0 to Entities.Count-1 do TObject(Entities[i]).Free;
Entities.Free;
Protocols.Free; Protocols.Free;
Names.Free; Names.Free;
inherited Destroy; inherited Destroy;