chelper: fix for objc methods, protocols parsing and writting

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1288 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz 2010-08-16 13:23:30 +00:00
parent e3d745b988
commit dd80a33837
3 changed files with 247 additions and 171 deletions

View File

@ -226,9 +226,69 @@ type
_Params : AnsiString; _Params : AnsiString;
end; end;
// parsing function type
{ TSimpleType }
TSimpleType = class(TEntity)
public
Name : AnsiString;
end;
{ TExpression }
TExpPart = record
Token : AnsiString;
TokenType : TTokenType;
end;
TExpression = class(TEntity)
function DoParse(AParser: TTextParser): Boolean; override;
public
Tokens : array of TExpPart;
Count : Integer;
procedure PushToken(const AToken: AnsiString; ATokenType: TTokenType);
end;
const
nk_Ident = 0;
nk_Ref = 1;
nk_Array = 2;
nk_Func = 3;
type
TNameKind = Integer;
type
TNamePart = class;
TFuncParam = record
prmtype : TEntity;
name : TNamePart;
end;
{ TNamePart }
TNamePart = class(TObject)
private
fChild : TNamePart;
fOwner : TNamePart;
public
Kind : TNameKind;
RefCount : Integer;
Id : AnsiString;
arrayexp : array of TExpression;
params : array of TFuncParam;
constructor Create(AKind: TNameKind);
procedure AddParam(prmtype: TEntity; prmname: TNamePart);
procedure AddArrayExpr(expr: TExpression);
property child: TNamePart read fchild write fChild; // int (*p)[10]; "[10]" is child of (*p)
property owner: TNamePart read fowner write fOwner;
end;
var var
ParseNextEntity: function (AParser: TTextParser): TEntity = nil; ParseNextEntity: function (AParser: TTextParser): TEntity = nil;
ParseNamePart : function (Parser: TTextParser): TNamePart = nil;
function ParseNextCEntity(AParser: TTextParser): TEntity; function ParseNextCEntity(AParser: TTextParser): TEntity;
@ -254,64 +314,12 @@ function CreateCParser(const CHeaderText: AnsiString;
type type
TCustomEntityProc = function (Parent: TEntity; Parser: TTextParser): TEntity; TCustomEntityProc = function (Parent: TEntity; Parser: TTextParser): TEntity;
type
{ TSimpleType }
TSimpleType = class(TEntity)
public
Name : AnsiString;
end;
{ TExpression }
TExpPart = record
Token : AnsiString;
TokenType : TTokenType;
end;
TExpression = class(TEntity)
function DoParse(AParser: TTextParser): Boolean; override;
public
Tokens : array of TExpPart;
Count : Integer;
procedure PushToken(const AToken: AnsiString; ATokenType: TTokenType);
end;
procedure ErrorExpect(Parser: TTextParser; const Expect: AnsiString); procedure ErrorExpect(Parser: TTextParser; const Expect: AnsiString);
function ConsumeToken(Parser: TTextParser; const Token: AnsiString): Boolean; function ConsumeToken(Parser: TTextParser; const Token: AnsiString): Boolean;
function ConsumeIdentifier(Parser: TTextParser; var Id: AnsiString): Boolean; function ConsumeIdentifier(Parser: TTextParser; var Id: AnsiString): Boolean;
function ParseCType(Parser: TTextParser): TEntity; function ParseCType(Parser: TTextParser): TEntity;
type
TNamePart = class;
TFuncParam = record
prmtype : TEntity;
name : TNamePart;
end;
TNameKind = (nk_Ident, nk_Ref, nk_Array, nk_Func);
{ TNamePart }
TNamePart = class(TObject)
private
fChild : TNamePart;
fOwner : TNamePart;
public
Kind : TNameKind;
RefCount : Integer;
Id : AnsiString;
arrayexp : array of TExpression;
params : array of TFuncParam;
constructor Create(AKind: TNameKind);
procedure AddParam(prmtype: TEntity; prmname: TNamePart);
procedure AddArrayExpr(expr: TExpression);
property child: TNamePart read fchild write fChild; // int (*p)[10]; "[10]" is child of (*p)
property owner: TNamePart read fowner write fOwner;
end;
function ParseNames(Parser: TTextParser; var NameType: TEntity; Names: TList; AllowMultipleNames: Boolean=True): Boolean; function ParseNames(Parser: TTextParser; var NameType: TEntity; Names: TList; AllowMultipleNames: Boolean=True): Boolean;
function ParseName(Parser: TTextParser; var NameType: TEntity; var name: TNamePart): Boolean; function ParseName(Parser: TTextParser; var NameType: TEntity; var name: TNamePart): Boolean;
@ -1458,8 +1466,6 @@ end;
function ParseNextCEntity(AParser: TTextParser): TEntity; function ParseNextCEntity(AParser: TTextParser): TEntity;
var var
s : AnsiString; s : AnsiString;
tt : TTokenType;
tp : TEntity; tp : TEntity;
nm : TNamePart; nm : TNamePart;
v : TVarFuncEntity; v : TVarFuncEntity;
@ -1493,6 +1499,8 @@ begin
end else end else
Result:=v; Result:=v;
end; end;
if AParser.Token<>';' then ErrorExpect(AParser,';');
end; end;
procedure ErrorExpect(Parser:TTextParser;const Expect:AnsiString); procedure ErrorExpect(Parser:TTextParser;const Expect:AnsiString);
@ -1644,7 +1652,7 @@ begin
Parser.NextToken; Parser.NextToken;
end; end;
function ParseNamePart(Parser: TTextParser): TNamePart; function ParseCNamePart(Parser: TTextParser): TNamePart;
var var
prefix : TNamePart; prefix : TNamePart;
id : TNamePart; id : TNamePart;
@ -2023,6 +2031,7 @@ end;
initialization initialization
ParseNextEntity:=@ParseNextCEntity; ParseNextEntity:=@ParseNextCEntity;
ParseNamePart:=@ParseCNamePart;
end. end.

View File

@ -81,6 +81,23 @@ function isNumberExp(x: TExpression; var v: Int64): Boolean;
// int a[MAXCONST] -> a: array [0..MAXCONST-1] of Integer; // int a[MAXCONST] -> a: array [0..MAXCONST-1] of Integer;
function PasArrayLimit(x: TExpression): AnsiString; function PasArrayLimit(x: TExpression): AnsiString;
type
{ TStopComment }
TStopComment = class(TObject)
public
FirstComment : boolean;
CommentFound : boolean;
CommentEnd : Integer;
Precomp : TEntity;
PrecompEnd : Integer;
procedure OnComment(Sender: TObject; const Str: ansistring);
procedure OnPrecompiler(Sender: TTextParser; PrecompEntity: TObject);
procedure Clear;
end;
implementation implementation
type type
@ -114,7 +131,6 @@ type
CmtList : TList; CmtList : TList;
Breaker : TLineBreaker; Breaker : TLineBreaker;
LastOffset : Integer; LastOffset : Integer;
function FindCommentForLine(ln: Integer): TComment;
protected protected
fWriters : TList; fWriters : TList;
AuxTypeCounter : Integer; AuxTypeCounter : Integer;
@ -140,7 +156,7 @@ type
procedure WriteEnumAsConst(en: TEnumType; FinishWithInteger: Boolean=True); procedure WriteEnumAsConst(en: TEnumType; FinishWithInteger: Boolean=True);
procedure WriteUnion(st: TUnionType); procedure WriteUnion(st: TUnionType);
procedure WriteStruct(st: TStructType); procedure WriteStruct(st: TStructType);
procedure WriteCommentToPas(cent: TComment); procedure WriteCommentToPas(cent: TComment; NeedLineBreak: Boolean);
procedure WriteExp(x: TExpression); procedure WriteExp(x: TExpression);
procedure WritePreprocessor(cent: TCPrepDefine); procedure WritePreprocessor(cent: TCPrepDefine);
@ -239,22 +255,8 @@ begin
end; end;
type
{ TStopComment } { TStopComment }
TStopComment = class(TObject)
public
FirstComment : boolean;
CommentFound : boolean;
CommentEnd : Integer;
Precomp : TEntity;
PrecompEnd : Integer;
procedure OnComment(Sender: TObject; const Str: ansistring);
procedure OnPrecompiler(Sender: TTextParser; PrecompEntity: TObject);
end;
procedure TStopComment.OnComment(Sender: TObject; const Str: ansistring); procedure TStopComment.OnComment(Sender: TObject; const Str: ansistring);
var var
parser: TTextParser; parser: TTextParser;
@ -278,20 +280,22 @@ begin
end; end;
end; end;
function ParseNextEntityOrComment(AParser: TTextParser): TEntity; procedure TStopComment.Clear;
begin
FirstComment:=False;
CommentFound:=False;
Precomp:=nil;
CommentEnd:=-1;
PrecompEnd:=-1;
end;
function ParseNextEntityOrComment(AParser: TTextParser; cmt: TStopComment): TEntity;
var var
cmt : TStopComment;
ent : TEntity; ent : TEntity;
entidx : Integer; entidx : Integer;
begin begin
cmt := TStopComment.Create;
AParser.UseCommentEntities := True;
AParser.OnComment := @cmt.OnComment;
AParser.OnPrecompile:=@cmt.OnPrecompiler;
Result:=nil; Result:=nil;
AParser.NextToken;
ent := ParseNextEntity(AParser); ent := ParseNextEntity(AParser);
entidx := AParser.Index; entidx := AParser.Index;
@ -306,11 +310,11 @@ begin
end; end;
end; end;
cmt.Free;
if (not Assigned(Result)) or (Assigned(ent) and (ent.Offset<Result.Offset)) then begin if (not Assigned(Result)) or (Assigned(ent) and (ent.Offset<Result.Offset)) then begin
Result:=ent; Result:=ent;
AParser.Index:=entidx; AParser.Index:=entidx;
end; end else
AParser.NextToken;
end; end;
function GetRefAsterix(const AstCount: integer): ansistring; function GetRefAsterix(const AstCount: integer): ansistring;
@ -343,7 +347,6 @@ begin
Result:=PasExp(x) + '-1'; Result:=PasExp(x) + '-1';
end; end;
procedure WriteArray(arr: TNamePart; wr: TCodeWriter); procedure WriteArray(arr: TNamePart; wr: TCodeWriter);
var var
i : Integer; i : Integer;
@ -353,7 +356,6 @@ begin
wr.W(' of '); wr.W(' of ');
end; end;
type type
TMacrosMaker = class(TObject) TMacrosMaker = class(TObject)
public public
@ -436,6 +438,7 @@ var
owncfg : Boolean; owncfg : Boolean;
lastsec : AnsiString; // last code section lastsec : AnsiString; // last code section
ofs : Integer; ofs : Integer;
cmt : TStopComment;
begin begin
Result:=''; Result:='';
ent:=nil; ent:=nil;
@ -447,13 +450,19 @@ begin
if cfg.CustomDefines<>'' then PrepareMacros(cfg.CustomDefines, macros); if cfg.CustomDefines<>'' then PrepareMacros(cfg.CustomDefines, macros);
cmt := TStopComment.Create;
p := CreateCParser(t); p := CreateCParser(t);
p.MacroHandler:=macros; p.MacroHandler:=macros;
p.UseCommentEntities := True;
p.OnComment := @cmt.OnComment;
p.OnPrecompile:=@cmt.OnPrecompiler;
try try
repeat repeat
try try
ofs := p.Index; ofs := p.Index;
ent := ParseNextEntityOrComment(p); p.NextToken;
ent := ParseNextEntityOrComment(p, cmt);
except except
ent:=nil; ent:=nil;
end; end;
@ -473,7 +482,7 @@ begin
end; end;
end; end;
cnv.WriteCtoPas(ent, p.Comments, t); cnv.WriteCtoPas(ent, p.Comments, p.Buf);
lastsec:=cnv.wr.Section; lastsec:=cnv.wr.Section;
except except
@ -495,15 +504,14 @@ begin
while i < p.Index do begin while i < p.Index do begin
Inc(endPoint.Y); Inc(endPoint.Y);
le := i; le := i;
SkipLine(t, i); SkipLine(p.Buf, i);
end; end;
endPoint.X := p.Index - le + 1 + p.MacrosDelta; endPoint.X := p.Index - le + 1 + p.MacrosDelta;
finally finally
p.Free; p.Free;
macros.Free; macros.Free;
cmt.Free;
end; end;
except except
on e: Exception do Result:=Result+LineEnding+' internal error: '+ e.Message; on e: Exception do Result:=Result+LineEnding+' internal error: '+ e.Message;
@ -533,7 +541,7 @@ begin
inherited Destroy; inherited Destroy;
end; end;
procedure TCodeConvertor.WriteCommentToPas(cent: TComment); procedure TCodeConvertor.WriteCommentToPas(cent: TComment; NeedLineBreak: Boolean);
var var
u: ansistring; u: ansistring;
begin begin
@ -541,12 +549,13 @@ begin
if cent.CommenType = ctBlock then if cent.CommenType = ctBlock then
begin begin
u := StringReplace(u, '*)', '* )', [rfReplaceAll]); u := StringReplace(u, '*)', '* )', [rfReplaceAll]);
wr.Wln('(*' + u + ' *)'); wr.W('(*' + u + ' *)');
end end
else else
begin begin
wr.Wln('//' + u); wr.W('//' + u);
end; end;
if NeedLineBreak then wr.Wln;
end; end;
procedure TCodeConvertor.WriteExp(x:TExpression); procedure TCodeConvertor.WriteExp(x:TExpression);
@ -625,6 +634,9 @@ begin
if m.Args[i].Name='' if m.Args[i].Name=''
then PNames[i]:=cfg.ParamPrefix+IntToStr(i) then PNames[i]:=cfg.ParamPrefix+IntToStr(i)
else PNames[i]:=m.Args[i].Name; else PNames[i]:=m.Args[i].Name;
if not Assigned(m.Args[i].RetType) then
PTypes[i]:='id'
else
PTypes[i]:=GetPasTypeName(m.Args[i].RetType, m.Args[i].TypeName); PTypes[i]:=GetPasTypeName(m.Args[i].RetType, m.Args[i].TypeName);
end; end;
@ -662,7 +674,6 @@ begin
wr.W('procedure '+nm+'(AValue: '+tp+'); message '''+mtd+''';'); wr.W('procedure '+nm+'(AValue: '+tp+'); message '''+mtd+''';');
end; end;
end; end;
end; end;
@ -675,14 +686,17 @@ begin
for i:=0 to list.Count-1 do begin for i:=0 to list.Count-1 do begin
ent:=TEntity(list[i]); ent:=TEntity(list[i]);
if not Assigned(ent) then Continue; if not Assigned(ent) then Continue;
WriteLnCommentsBeforeOffset(ent.Offset); WriteLnCommentsBeforeOffset(ent.Offset);
if ent is TObjCMethod then if ent is TObjCMethod then
WriteObjCMethod(TObjCMethod(ent)) WriteObjCMethod(TObjCMethod(ent))
else if ent is TObjCProperty then begin else if ent is TObjCProperty then begin
WriteObjCProperty(TObjCProperty(ent)); WriteObjCProperty(TObjCProperty(ent));
end; end;
WriteLnCommentForOffset(ent.Offset); WriteLnCommentForOffset(ent.Offset);
end; end;
end; end;
procedure TCodeConvertor.WriteObjCInterface(cent:TObjCInterface); procedure TCodeConvertor.WriteObjCInterface(cent:TObjCInterface);
@ -696,7 +710,9 @@ const
begin begin
SetPasSection(wr, 'type'); SetPasSection(wr, 'type');
if cent.isCategory then begin if cent.isCategory then begin
wr.W(cent.Name + ' = objccategory') wr.W(cent.Name + ' = objccategory');
if cent.SuperClass<>'' then wr.W('('+cent.SuperClass+')');
wr.Wln;
end else begin end else begin
wr.W(cent.Name + ' = objcclass'); wr.W(cent.Name + ' = objcclass');
if cent.SuperClass<>'' then wr.W('('+cent.SuperClass); if cent.SuperClass<>'' then wr.W('('+cent.SuperClass);
@ -730,7 +746,7 @@ begin
WriteObjCMethods(cent.Methods); WriteObjCMethods(cent.Methods);
wr.DecIdent; wr.DecIdent;
end; end;
wr.Wln('end external;') wr.Wln('end external;');
end; end;
procedure TCodeConvertor.WriteObjCProtocol(cent:TObjCProtocol); procedure TCodeConvertor.WriteObjCProtocol(cent:TObjCProtocol);
@ -738,7 +754,8 @@ var
i : Integer; i : Integer;
begin begin
SetPasSection(wr, 'type'); SetPasSection(wr, 'type');
wr.W(cent.Name+'Protocol = objcprotocol'); if cent.Names.Count=1 then begin
wr.W(cent.Names[0]+'Protocol = objcprotocol');
if cent.Protocols.Count>0 then begin if cent.Protocols.Count>0 then begin
wr.W('('); wr.W('(');
@ -750,7 +767,11 @@ begin
WriteObjCMethods(cent.Methods); WriteObjCMethods(cent.Methods);
wr.DecIdent; wr.DecIdent;
wr.W('end; '); wr.W('end; ');
wr.Wln(' external name '''+cent.Name+''';'); wr.Wln(' external name '''+cent.Names[0]+''';');
end else begin
for i:=0 to cent.Names.Count-1 do
wr.Wln(cent.Names[i]+'Protocol = objcprotocol; external name '''+cent.Names[i]+''';');
end;
end; end;
procedure TCodeConvertor.PushWriter; procedure TCodeConvertor.PushWriter;
@ -808,13 +829,24 @@ end;
procedure TCodeConvertor.WriteLnCommentForOffset(AOffset:Integer; NeedOffset: Boolean); procedure TCodeConvertor.WriteLnCommentForOffset(AOffset:Integer; NeedOffset: Boolean);
var var
cmt : TComment; cmt : TComment;
ln : Integer;
c : Integer;
i : Integer;
begin begin
cmt:=FindCommentForLine( Breaker.LineNumber(AOffset)); ln:= Breaker.LineNumber(AOffset);
if Assigned(cmt) then begin c:=0;
for i:=0 to CmtList.Count-1 do begin
cmt:=TComment(CmtList[i]);
if Breaker.LineNumber(TComment(CmtList[i]).Offset)=ln then begin
if NeedOffset then begin
wr.W(' ');
NeedOffset:=False;
end;
WriteCommentToPas(cmt, false);
LastOffset:=cmt.Offset; LastOffset:=cmt.Offset;
if NeedOffset then wr.W(' '); inc(c);
WriteCommentToPas(cmt); end;
end else end;
wr.Wln; wr.Wln;
end; end;
@ -1078,7 +1110,7 @@ begin
wr.Wln(';'); wr.Wln(';');
end; end;
end else if cent is TComment then end else if cent is TComment then
WriteCommentToPas(cent as TComment) WriteCommentToPas(cent as TComment, True)
else if cent is TCPrepDefine then else if cent is TCPrepDefine then
WritePreprocessor(cent as TCPrepDefine) WritePreprocessor(cent as TCPrepDefine)
else if cent is TObjCInterface then else if cent is TObjCInterface then
@ -1332,20 +1364,7 @@ begin
wr.W(PasTypeName + ' = ');} wr.W(PasTypeName + ' = ');}
wr.W('todo: '+TypeEntity.ClassName); wr.W('todo: '+TypeEntity.ClassName);
end; end;
//todo: ... //todo: ...parse any Entity
end;
function TCodeConvertor.FindCommentForLine(ln:Integer):TComment;
var
i : Integer;
begin
Result:=nil;
if not Assigned(CmtList) then Exit;
for i:=0 to CmtList.Count-1 do
if Breaker.LineNumber(TComment(CmtList[i]).Offset)=ln then begin
Result:=TComment(CmtList[i]);
Exit;
end;
end; end;
procedure TCodeConvertor.DefFuncWrite(wr:TCodeWriter;const FuncName,FuncRetType:AnsiString; procedure TCodeConvertor.DefFuncWrite(wr:TCodeWriter;const FuncName,FuncRetType:AnsiString;

View File

@ -26,6 +26,9 @@ interface
uses uses
Classes, SysUtils, cparsertypes; Classes, SysUtils, cparsertypes;
const
objcend = '@end';
type type
{ TObjCClasses } { TObjCClasses }
@ -54,6 +57,7 @@ type
RetName : TNamePart; RetName : TNamePart;
Args : array of TObjCMethodArg; Args : array of TObjCMethodArg;
Option : TObjCMethodOpt; Option : TObjCMethodOpt;
VarParams : Boolean;
constructor Create(AOffset: Integer=-1); override; constructor Create(AOffset: Integer=-1); override;
destructor Destroy; override; destructor Destroy; override;
procedure AddArg(const ArgType: TEntity; ArgTypeName: TNamePart; const Name: AnsiString); procedure AddArg(const ArgType: TEntity; ArgTypeName: TNamePart; const Name: AnsiString);
@ -88,7 +92,7 @@ type
TObjCProtocol = class(TEntity) TObjCProtocol = class(TEntity)
public public
Name : AnsiString; Names : TStringList;
isForward : Boolean; isForward : Boolean;
Protocols : TStringList; Protocols : TStringList;
Methods : TList; Methods : TList;
@ -113,7 +117,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): Boolean; function ParseMethods(AParser: TTextParser; MethodsList: 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;
@ -121,6 +125,9 @@ function ParseNextObjCEntity(AParser: TTextParser): TEntity;
function isObjCKeyword(const token: AnsiString): Boolean; inline; function isObjCKeyword(const token: AnsiString): Boolean; inline;
function GetObjCKeyword(const token: AnsiString): AnsiString; function GetObjCKeyword(const token: AnsiString): AnsiString;
const
nk_Protocol = $1000;
implementation implementation
function isObjCKeyword(const token: AnsiString): Boolean; inline; function isObjCKeyword(const token: AnsiString): Boolean; inline;
@ -140,6 +147,7 @@ var
begin begin
Result:=nil; Result:=nil;
if AParser.Token<>'@class' then Exit; if AParser.Token<>'@class' then Exit;
try
cl:=TObjCClasses.Create(AParser.TokenPos); cl:=TObjCClasses.Create(AParser.TokenPos);
AParser.NextToken; AParser.NextToken;
while AParser.Token<>';' do begin while AParser.Token<>';' do begin
@ -158,7 +166,11 @@ begin
Exit; Exit;
end; end;
end; end;
if AParser.Token<>';' then ErrorExpect(AParser, ';');
Result:=cl; Result:=cl;
finally
if not Assigned(Result) then cl.Free;
end;
end; end;
function ParseInstVars(AParser: TTextParser; Vars: TList): Boolean; function ParseInstVars(AParser: TTextParser; Vars: TList): Boolean;
@ -217,14 +229,14 @@ begin
itf:=TObjCInterface.Create(i); itf:=TObjCInterface.Create(i);
try try
itf.Name:=nm;
itf.isCategory:=AParser.Token='('; itf.isCategory:=AParser.Token='(';
if itf.isCategory then begin if itf.isCategory then begin
itf.SuperClass:=nm;
AParser.NextToken; AParser.NextToken;
if not ConsumeIdentifier(AParser, itf.SuperClass) and ConsumeToken(AParser, ')') then if not (ConsumeIdentifier(AParser, itf.Name) and ConsumeToken(AParser, ')')) then
Exit; Exit;
end else begin end else begin
itf.Name:=nm;
// super-class // super-class
if AParser.Token=':' then begin if AParser.Token=':' then begin
AParser.NextToken; AParser.NextToken;
@ -249,8 +261,8 @@ begin
ParseInstVars(AParser, itf.Vars); ParseInstVars(AParser, itf.Vars);
end; end;
if not ParseMethods(AParser, itf.Methods, '@end') then Exit; if not ParseMethods(AParser, itf.Methods, objcend) then Exit;
if AParser.Token='@end' then AParser.NextToken; if AParser.Token<>objcend then ErrorExpect(AParser, objcend);
Result:=itf; Result:=itf;
finally finally
@ -268,11 +280,17 @@ begin
p := TObjCProtocol.Create(AParser.TokenPos); p := TObjCProtocol.Create(AParser.TokenPos);
try try
AParser.NextToken; AParser.NextToken;
if not ConsumeIdentifier(AParser, p.Name) then Exit; if not ConsumeIdentifier(AParser, nm) then Exit;
p.isForward:= AParser.Token=';'; p.Names.Add(nm);
p.isForward:= (AParser.Token=';') or (AParser.Token=',');
if p.isForward then begin if p.isForward then begin
Result:=p; while AParser.Token<>';' do begin
AParser.NextToken; AParser.NextToken;
ConsumeIdentifier(AParser, nm);
p.Names.Add(nm);
end;
Result:=p;
if AParser.Token<>';' then ErrorExpect(AParser, ';');
Exit; Exit;
end; end;
@ -286,8 +304,8 @@ begin
if AParser.Token='>' then AParser.NextToken; if AParser.Token='>' then AParser.NextToken;
end; end;
if ParseMethods(AParser, p.Methods, '@end') then Result:=p; if ParseMethods(AParser, p.Methods, objcend) then Result:=p;
if AParser.Token='@end' then AParser.NextToken; if AParser.Token<>objcend then ErrorExpect(AParser, objcend);
finally finally
if not Assigned(Result) then p.Free; if not Assigned(Result) then p.Free;
end; end;
@ -295,6 +313,7 @@ end;
var var
PrevParseNextEntity : function (AParser: TTextParser): TEntity = nil; PrevParseNextEntity : function (AParser: TTextParser): TEntity = nil;
PrevNamePart : function (AParser: TTextParser): TNamePart = nil;
function ParseNextObjCEntity(AParser: TTextParser): TEntity; function ParseNextObjCEntity(AParser: TTextParser): TEntity;
var var
@ -377,25 +396,36 @@ begin
m.Name.Add(nm+':'); m.Name.Add(nm+':');
AParser.NextToken; AParser.NextToken;
while AParser.Token<>';' do begin while (AParser.Token<>';') and (AParser.Token<>',') do begin
if AParser.Token='(' then begin
prm:=ConsumeToken(AParser, '(') and prm:=ConsumeToken(AParser, '(') and
ParseName(APArser, atype, atname) and ParseName(APArser, atype, atname) and
ConsumeToken(AParser, ')') and ConsumeToken(AParser, ')');
ConsumeIdentifier(AParser, aname); end else begin
prm:=True;
atype:=nil;
atname:=nil;
end;
if not prm then Exit; if not prm then Exit;
ConsumeIdentifier(AParser, aname);
m.AddArg(atype, atname, aname); m.AddArg(atype, atname, aname);
// 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<>';' then begin if (AParser.Token<>';') and (AParser.Token<>',') then begin
if not ConsumeToken(AParser,':') then Exit; if not ConsumeToken(AParser,':') then Exit;
m.Name.Add(nm+':'); m.Name.Add(nm+':');
end; end;
end; end;
AParser.NextToken; end else
end else begin
m.Name.Add(nm); m.Name.Add(nm);
if not ConsumeToken(AParser, ';') then Exit;
if AParser.Token=',' then begin
AParser.NextToken;
if ConsumeToken(AParser,'...') then m.VarParams:=True
else ErrorExpect(AParser, '...');
end; end;
if not ConsumeToken(AParser, ';') then Exit;
Result:=m; Result:=m;
finally finally
@ -403,7 +433,7 @@ begin
end; end;
end; end;
function ParseMethods(AParser: TTextParser; MethodsList: TList; const EndToken: AnsiString = '@end'): Boolean; function ParseMethods(AParser: TTextParser; MethodsList: TList; const EndToken: AnsiString): Boolean;
var var
m : TObjCMethod; m : TObjCMethod;
p : TObjCProperty; p : TObjCProperty;
@ -484,6 +514,7 @@ begin
inherited Create(AOffset); inherited Create(AOffset);
Protocols := TStringList.Create; Protocols := TStringList.Create;
Methods := TList.Create; Methods := TList.Create;
Names := TStringList.Create;
end; end;
destructor TObjCProtocol.Destroy; destructor TObjCProtocol.Destroy;
@ -493,6 +524,7 @@ 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;
Protocols.Free; Protocols.Free;
Names.Free;
inherited Destroy; inherited Destroy;
end; end;
@ -521,7 +553,7 @@ begin
Result:=nil; Result:=nil;
if AParser.Token<>'@property' then Exit; if AParser.Token<>'@property' then Exit;
AParser.NextToken; AParser.NextToken;
p := TObjCProperty.Create; p := TObjCProperty.Create(AParser.TokenPos);
try try
if AParser.Token='(' then begin if AParser.Token='(' then begin
AParser.NextToken; AParser.NextToken;
@ -556,9 +588,25 @@ begin
end; end;
end; end;
function ParseObjCNamePart(AParser: TTextParser): TNamePart;
var
p : AnsiString;
begin
// skipping protocol adopted type definition
if AParser.Token='<' then begin
Result:=nil;
AParser.NextToken;
if not (ConsumeIdentifier(AParser, p) and ConsumeToken(AParser,'>')) then Exit;
end;
Result:=PrevNamePart(AParser);
end;
initialization initialization
PrevParseNextEntity:=ParseNextEntity; PrevParseNextEntity:=ParseNextEntity;
ParseNextEntity:=ParseNextObjCEntity; ParseNextEntity:=ParseNextObjCEntity;
PrevNamePart:=ParseNamePart;
ParseNamePart:=ParseObjCNamePart;
end. end.