
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
680 lines
17 KiB
ObjectPascal
680 lines
17 KiB
ObjectPascal
{ 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
|
|
objcparsing;
|
|
|
|
interface
|
|
|
|
{$ifdef fpc}{$mode delphi}{$h+}{$endif}
|
|
|
|
uses
|
|
Classes, SysUtils, cparsertypes;
|
|
|
|
const
|
|
objcend = '@end';
|
|
|
|
type
|
|
|
|
{ TObjCClasses }
|
|
|
|
TObjCClasses = class(TEntity)
|
|
ClassList : TStringList;
|
|
constructor Create(AOffset: Integer=-1); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TObjCMethod }
|
|
|
|
TObjCMethodArg = record
|
|
RetType : TEntity;
|
|
TypeName : TNamePart;
|
|
Name : AnsiString;
|
|
end;
|
|
|
|
TObjCMethodOpt = (mo_Required, mo_Optional);
|
|
|
|
TObjCMethod = class(TEntity)
|
|
public
|
|
isClassMethod : Boolean;
|
|
Name : TStringList;
|
|
RetType : TEntity;
|
|
RetName : TNamePart;
|
|
Args : array of TObjCMethodArg;
|
|
Option : TObjCMethodOpt;
|
|
VarParams : Boolean;
|
|
constructor Create(AOffset: Integer=-1); override;
|
|
destructor Destroy; override;
|
|
procedure AddArg(const ArgType: TEntity; ArgTypeName: TNamePart; const Name: AnsiString);
|
|
end;
|
|
|
|
TObjCScope = (os_Private, os_Protected, os_Public, os_Package);
|
|
|
|
{ TObjCInstVar }
|
|
|
|
TObjCInstVar = class(TEntity)
|
|
public
|
|
scope : TObjCScope;
|
|
v : TVarFuncEntity;
|
|
bits : TExpression;
|
|
isbitted : Boolean;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TObjCInterface }
|
|
|
|
TObjCInterface = class(TEntity)
|
|
public
|
|
Name : AnsiString;
|
|
SuperClass : AnsiString;
|
|
isCategory : Boolean;
|
|
Protocols : TStringList;
|
|
Vars : TList;
|
|
Methods : TList;
|
|
Entities : TList;
|
|
constructor Create(AOffset: Integer=-1); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TObjCProtocol }
|
|
|
|
TObjCProtocol = class(TEntity)
|
|
public
|
|
Names : TStringList;
|
|
isForward : Boolean;
|
|
Protocols : TStringList;
|
|
Methods : TList;
|
|
Entities : TList;
|
|
constructor Create(AOffset: Integer=-1); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TObjCProperty }
|
|
|
|
TObjCProperty = class(TEntity)
|
|
public
|
|
Name : TNamePart;
|
|
RetType : TEntity;
|
|
SetterName : AnsiString;
|
|
GetterName : AnsiString;
|
|
Props : TStringList;
|
|
constructor Create(AOffset: Integer=-1); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
function ParseClassList(AParser: TTextParser): TObjCClasses;
|
|
function ParseInterface(AParser: TTextParser): TObjCInterface;
|
|
function ParseMethod(AParser: TTextParser): TObjCMethod;
|
|
function ParseProperty(AParser: TTextParser): TObjCProperty;
|
|
function ParseMethods(AParser: TTextParser; MethodsList, OthersList: TList; const EndToken: AnsiString = objcend): Boolean;
|
|
function ParseProtocol(AParser: TTextParser): TEntity;
|
|
|
|
function ParseNextObjCEntity(AParser: TTextParser): TEntity;
|
|
|
|
function isObjCKeyword(const token: AnsiString): Boolean; inline;
|
|
function GetObjCKeyword(const token: AnsiString): AnsiString;
|
|
|
|
const
|
|
nk_Protocol = $1000;
|
|
|
|
implementation
|
|
|
|
function isObjCKeyword(const token: AnsiString): Boolean; inline;
|
|
begin
|
|
Result:=(token<>'') and (token[1]='@');
|
|
end;
|
|
|
|
function GetObjCKeyword(const token: AnsiString): AnsiString;
|
|
begin
|
|
if isObjCKeyword(token) then Result:=Copy(token, 2, length(token)-1)
|
|
else Result:=token;
|
|
end;
|
|
|
|
function ParseClassList(AParser: TTextParser): TObjCClasses;
|
|
var
|
|
cl : TObjCClasses;
|
|
begin
|
|
Result:=nil;
|
|
if AParser.Token<>'@class' then Exit;
|
|
try
|
|
cl:=TObjCClasses.Create(AParser.TokenPos);
|
|
AParser.NextToken;
|
|
while AParser.Token<>';' do begin
|
|
if AParser.TokenType<>tt_Ident then begin
|
|
ErrorExpect(AParser,'identifier');
|
|
cl.Free;
|
|
Exit;
|
|
end;
|
|
cl.ClassList.Add(AParser.Token);
|
|
AParser.NextToken;
|
|
if AParser.Token=',' then
|
|
AParser.NextToken
|
|
else if AParser.Token<>';' then begin
|
|
ErrorExpect(AParser,';');
|
|
cl.Free;
|
|
Exit;
|
|
end;
|
|
end;
|
|
if AParser.Token<>';' then ErrorExpect(AParser, ';');
|
|
Result:=cl;
|
|
finally
|
|
if not Assigned(Result) then cl.Free;
|
|
end;
|
|
end;
|
|
|
|
function ParseInstVars(AParser: TTextParser; Vars: TList): Boolean;
|
|
var
|
|
v : TVarFuncEntity;
|
|
iv : TObjCInstVar;
|
|
s : AnsiString;
|
|
scope : TObjCScope;
|
|
isbitted : Boolean;
|
|
bits : TExpression;
|
|
begin
|
|
Result:=True;
|
|
if AParser.Token<>'{' then Exit;
|
|
|
|
Result:=False;
|
|
AParser.NextToken;
|
|
|
|
scope:=os_Protected;
|
|
while AParser.Token<>'}' do begin
|
|
if isObjCKeyword(AParser.Token) then begin
|
|
s:=GetObjCKeyword(APArser.Token);
|
|
if s='protected' then scope:=os_Protected
|
|
else if s='private' then scope:=os_Private
|
|
else if s='public' then scope:=os_Public
|
|
else if s='package' then scope:=os_Package
|
|
else begin
|
|
ErrorExpect(AParser,'}');
|
|
Exit;
|
|
end;
|
|
AParser.NextToken;
|
|
end else begin
|
|
v:=TVarFuncEntity.Create(AParser.TokenPos);
|
|
if not ParseNames(AParser, v.RetType, v.Names, [';',':']) then Exit;
|
|
|
|
if AParser.Token=':' then begin
|
|
AParser.NextToken;
|
|
isbitted:=True;
|
|
bits:=ParseCExpr(AParser);
|
|
end else begin
|
|
isbitted:=false;
|
|
bits:=nil;
|
|
end;
|
|
iv:=TObjCInstVar.Create(v.Offset);
|
|
iv.v:=v;
|
|
iv.scope:=scope;
|
|
iv.isbitted:=isbitted;
|
|
iv.bits:=bits;
|
|
Vars.Add(iv);
|
|
if AParser.Token=';' then AParser.NextToken;
|
|
end;
|
|
end;
|
|
AParser.NextToken;
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
function ParseInterface(AParser: TTextParser): TObjCInterface;
|
|
var
|
|
itf : TObjCInterface;
|
|
i : Integer;
|
|
nm : AnsiString;
|
|
ent : TEntity;
|
|
begin
|
|
Result:=nil;
|
|
if AParser.Token<>'@interface' then Exit;
|
|
i:=AParser.TokenPos;
|
|
AParser.NextToken;
|
|
|
|
if not ConsumeIdentifier(AParser, nm) then Exit;
|
|
|
|
itf:=TObjCInterface.Create(i);
|
|
try
|
|
itf.isCategory:=AParser.Token='(';
|
|
if itf.isCategory then begin
|
|
itf.SuperClass:=nm;
|
|
AParser.NextToken;
|
|
if not (ConsumeIdentifier(AParser, itf.Name) and ConsumeToken(AParser, ')')) then
|
|
Exit;
|
|
end else begin
|
|
itf.Name:=nm;
|
|
// super-class
|
|
if AParser.Token=':' then begin
|
|
AParser.NextToken;
|
|
if not ConsumeIdentifier(AParser, itf.SuperClass) then Exit;
|
|
end;
|
|
end;
|
|
|
|
// 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);
|
|
|
|
Result:=itf;
|
|
finally
|
|
if not Assigned(Result) then itf.Free;
|
|
end;
|
|
end;
|
|
|
|
function ParseProtocol(AParser: TTextParser): TEntity;
|
|
var
|
|
p : TObjCProtocol;
|
|
nm : AnsiString;
|
|
begin
|
|
Result:=nil;
|
|
if AParser.Token<>'@protocol' then Exit;
|
|
p := TObjCProtocol.Create(AParser.TokenPos);
|
|
try
|
|
AParser.NextToken;
|
|
if not ConsumeIdentifier(AParser, nm) then Exit;
|
|
p.Names.Add(nm);
|
|
p.isForward:= (AParser.Token=';') or (AParser.Token=',');
|
|
if p.isForward then begin
|
|
while AParser.Token<>';' do begin
|
|
AParser.NextToken;
|
|
ConsumeIdentifier(AParser, nm);
|
|
p.Names.Add(nm);
|
|
end;
|
|
Result:=p;
|
|
if AParser.Token<>';' then ErrorExpect(AParser, ';');
|
|
Exit;
|
|
end;
|
|
|
|
if AParser.Token='<' then begin
|
|
AParser.NextToken;
|
|
while AParser.Token<>'>' do begin
|
|
if not ConsumeIdentifier(AParser, nm) then Exit;
|
|
p.Protocols.Add(nm);
|
|
if AParser.Token=',' then AParser.NextToken;
|
|
end;
|
|
if AParser.Token='>' then AParser.NextToken;
|
|
end;
|
|
|
|
if ParseMethods(AParser, p.Methods, p.Entities, objcend) then
|
|
Result:=p;
|
|
if AParser.Token<>objcend then ErrorExpect(AParser, objcend);
|
|
finally
|
|
if not Assigned(Result) then p.Free;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
PrevParseNextEntity : function (AParser: TTextParser): TEntity = nil;
|
|
PrevNamePart : function (AParser: TTextParser): TNamePart = nil;
|
|
|
|
function ParseNextObjCEntity(AParser: TTextParser): TEntity;
|
|
var
|
|
t : AnsiString;
|
|
begin
|
|
Result:=nil;
|
|
if (AParser.Token<>'') and (AParser.Token[1]='@') then begin
|
|
t:=GetObjCKeyword(AParser.Token);
|
|
if t='class' then Result:=ParseClassList(AParser)
|
|
else if t='interface' then Result:=ParseInterface(AParser)
|
|
else if t='protocol' then Result:=ParseProtocol(AParser);
|
|
end else begin
|
|
if Assigned(PrevParseNextEntity) then
|
|
Result:=PrevParseNextEntity(AParser)
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
end;
|
|
|
|
{ TObjCClasses }
|
|
|
|
constructor TObjCClasses.Create(AOffset:Integer);
|
|
begin
|
|
inherited Create(AOffset);
|
|
ClassList := TStringList.Create;
|
|
end;
|
|
|
|
destructor TObjCClasses.Destroy;
|
|
begin
|
|
ClassList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TObjCInterface }
|
|
|
|
constructor TObjCInterface.Create(AOffset:Integer);
|
|
begin
|
|
Vars := TList.Create;
|
|
Methods := TList.Create;
|
|
Entities := TList.Create;
|
|
Protocols := TStringList.Create;
|
|
inherited Create(AOffset);
|
|
end;
|
|
|
|
destructor TObjCInterface.Destroy;
|
|
var
|
|
i : Integer;
|
|
begin
|
|
for i:=0 to Vars.Count-1 do TObject(Vars[i]).Free;
|
|
Vars.Free;
|
|
for i:=0 to Methods.Count-1 do TObject(Methods[i]).Free;
|
|
Methods.Free;
|
|
for i:=0 to Entities.Count-1 do TObject(Entities[i]).Free;
|
|
Entities.Free;
|
|
Protocols.Free;
|
|
inherited Destroy;
|
|
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;
|
|
var
|
|
m : TObjCMethod;
|
|
nm : AnsiString;
|
|
atype : TEntity;
|
|
atname : TNamePart;
|
|
aname : Ansistring;
|
|
prm : Boolean;
|
|
begin
|
|
Result:=nil;
|
|
if (AParser.Token<>'+') and (AParser.Token<>'-') then Exit;
|
|
|
|
m:=TObjCMethod.Create(AParser.TokenPos);
|
|
try
|
|
m.isClassMethod:=AParser.Token='+';
|
|
AParser.NextToken;
|
|
|
|
if AParser.Token='(' then begin
|
|
AParser.NextToken;
|
|
if not ParseName(AParser, m.RetType, m.RetName,[')']) then Exit;
|
|
if not ConsumeToken(AParser, ')') then Exit;
|
|
end;
|
|
|
|
if not ConsumeIdentifier(AParser, nm) then Exit;
|
|
|
|
if (AParser.Token=':') then begin
|
|
m.Name.Add(nm+':');
|
|
AParser.NextToken;
|
|
|
|
while (AParser.Token<>';') and (AParser.Token<>',') do begin
|
|
if AParser.Token='(' then begin
|
|
prm:=ConsumeToken(AParser, '(');
|
|
if prm then begin
|
|
// 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
|
|
prm:=True;
|
|
atype:=nil;
|
|
atname:=nil;
|
|
end;
|
|
if not prm then Exit;
|
|
ConsumeIdentifier(AParser, aname);
|
|
m.AddArg(atype, atname, aname);
|
|
|
|
// the next name starts
|
|
if AParser.TokenType=tt_Ident then ConsumeIdentifier(AParser, nm) else nm:='';
|
|
if (AParser.Token<>';') and (AParser.Token<>',') then begin
|
|
if not ConsumeToken(AParser,':','parsing the objc method " '+Copy(Aparser.Buf, AParser.Index-30, 40)+'"') then Exit;
|
|
m.Name.Add(nm+':');
|
|
end;
|
|
end;
|
|
end else
|
|
m.Name.Add(nm);
|
|
|
|
if AParser.Token=',' then begin
|
|
AParser.NextToken;
|
|
if ConsumeToken(AParser,'...') then m.VarParams:=True
|
|
else ErrorExpect(AParser, '...');
|
|
end;
|
|
|
|
if not ConsumeToken(AParser, ';','parsing the end of objc method') then Exit;
|
|
|
|
Result:=m;
|
|
finally
|
|
if not Assigned(Result) then m.Free;
|
|
end;
|
|
end;
|
|
|
|
function ParseMethods(AParser: TTextParser; MethodsList, OthersList: TList; const EndToken: AnsiString): Boolean;
|
|
var
|
|
m : TObjCMethod;
|
|
p : TObjCProperty;
|
|
opt : TObjCMethodOpt;
|
|
s : AnsiString;
|
|
ent : TEntity;
|
|
begin
|
|
Result:=False;
|
|
if not Assigned(MethodsList) or not Assigned(AParser) then Exit;
|
|
opt:=mo_Required;
|
|
while (AParser.Token<>EndToken) and (AParser.Token<>'') do begin
|
|
|
|
if (AParser.Token[1] in ['+','-','@']) then begin
|
|
if isObjCKeyword(AParser.Token) then begin
|
|
s:=GetObjCKeyword(AParser.Token);
|
|
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
|
|
m:=ParseMethod(AParser);
|
|
if not Assigned(m) then Exit;
|
|
m.Option:=opt;
|
|
MethodsList.Add(m);
|
|
end;
|
|
end else begin
|
|
ent:=ParseNextCEntity(AParser, false);
|
|
AParser.NextToken;
|
|
end;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
{ TObjCMethod }
|
|
|
|
constructor TObjCMethod.Create(AOffset:Integer);
|
|
begin
|
|
inherited Create(AOffset);
|
|
Name := TStringList.Create;
|
|
end;
|
|
|
|
destructor TObjCMethod.Destroy;
|
|
var
|
|
i : Integer;
|
|
begin
|
|
Name.Free;
|
|
RetType.Free;
|
|
RetName.Free;
|
|
for i:=0 to length(Args)-1 do begin
|
|
Args[i].RetType.Free;
|
|
Args[i].TypeName.Free;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TObjCMethod.AddArg(const ArgType:TEntity;ArgTypeName:TNamePart;const Name:AnsiString);
|
|
var
|
|
i : Integer;
|
|
begin
|
|
i:=length(Args);
|
|
SetLength(Args, i+1);
|
|
Args[i].Name:=Name;
|
|
Args[i].RetType:=ArgType;
|
|
Args[i].TypeName:=ArgTypeName;
|
|
end;
|
|
|
|
{ TObjCInstVar }
|
|
|
|
|
|
destructor TObjCInstVar.Destroy;
|
|
begin
|
|
v.Free;
|
|
bits.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TObjCProtocol }
|
|
|
|
constructor TObjCProtocol.Create(AOffset:Integer);
|
|
begin
|
|
inherited Create(AOffset);
|
|
Protocols := TStringList.Create;
|
|
Methods := TList.Create;
|
|
Entities := TList.Create;
|
|
Names := TStringList.Create;
|
|
end;
|
|
|
|
destructor TObjCProtocol.Destroy;
|
|
var
|
|
i : Integer;
|
|
begin
|
|
for i:=0 to Methods.Count-1 do TObject(Methods[i]).Free;
|
|
Methods.Free;
|
|
for i:=0 to Entities.Count-1 do TObject(Entities[i]).Free;
|
|
Entities.Free;
|
|
Protocols.Free;
|
|
Names.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TObjCProperty }
|
|
|
|
constructor TObjCProperty.Create(AOffset:Integer);
|
|
begin
|
|
inherited Create(AOffset);
|
|
Props:=TStringList.Create;
|
|
end;
|
|
|
|
destructor TObjCProperty.Destroy;
|
|
begin
|
|
RetType.Free;
|
|
Name.Free;
|
|
Props.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function ParseProperty(AParser: TTextParser): TObjCProperty;
|
|
var
|
|
p : TObjCProperty;
|
|
s : AnsiString;
|
|
nm : AnsiString;
|
|
begin
|
|
Result:=nil;
|
|
if AParser.Token<>'@property' then Exit;
|
|
AParser.NextToken;
|
|
p := TObjCProperty.Create(AParser.TokenPos);
|
|
try
|
|
if AParser.Token='(' then begin
|
|
AParser.NextToken;
|
|
while AParser.Token<>')' do begin
|
|
s:=AParser.Token;
|
|
if (s='setter') or (s='getter') then begin
|
|
AParser.NextToken;
|
|
if not ConsumeToken(AParser, '=') then Exit;
|
|
if not ConsumeIdentifier(AParser, nm) then Exit;
|
|
while (AParser.TokenType=tt_Ident) or (APArser.Token=':') do begin
|
|
nm:=nm+AParser.Token;
|
|
AParser.NextToken;
|
|
end;
|
|
if s='setter' then p.SetterName:=nm
|
|
else p.GetterName:=nm;
|
|
end else begin
|
|
if APArser.TokenType=tt_Ident then p.Props.Add(AParser.Token);
|
|
AParser.NextToken;
|
|
end;
|
|
if AParser.Token=',' then AParser.NextToken;
|
|
end;
|
|
if AParser.Token=')' then
|
|
AParser.NextToken
|
|
else begin
|
|
ErrorExpect(AParser,')');
|
|
Exit;
|
|
end;
|
|
if ParseName(AParser, p.RetType, p.Name,[';']) then begin
|
|
Result:=p;
|
|
if AParser.Token=';' then AParser.NextToken;
|
|
end;
|
|
|
|
end;
|
|
|
|
finally
|
|
if not Assigned(Result) then p.Free;
|
|
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;
|
|
repeat
|
|
if not ConsumeIdentifier(AParser, p) then Exit;
|
|
if AParser.Token=',' then AParser.NextToken;
|
|
until AParser.Token='>';
|
|
|
|
if not ConsumeToken(AParser,'>') then Exit;
|
|
end;
|
|
Result:=PrevNamePart(AParser);
|
|
end;
|
|
|
|
initialization
|
|
PrevParseNextEntity:=_ParseNextEntity;
|
|
_ParseNextEntity:=@ParseNextObjCEntity;
|
|
|
|
PrevNamePart:=ParseNamePart;
|
|
ParseNamePart:=ParseObjCNamePart;
|
|
|
|
end.
|
|
|