fpc/compiler/symbase.pas
Jonas Maebe 5a2ccfff52 --WARNING: start build process with FPC 2.2.4; won't work when
starting with a previous 2.3.1 or compiler built from the objc branch
  + added basic objcprotocol support (only for external protocols
    currently)
     o use in type declaration: "type xp = objcprotocol ... end;"
     o when defining a root class that implements it:
       "type yc = objcclass(xp) ... end" (note: no support yet
       for something like "objcclass(id,xp)" or so)
     o when defining a non-root class that implements a protocol:
       "type zc = objcclass(nsobject,xp) ... end"
     o includes support for "required" and "optional" sections
     o no support yet for the objcprotocol(<protocol>) expression
       that enables getting a class instance representing the
       protocol (e.g., for use with "conformsToProtocol:")
     o message names have to specified in protocol declarations,
       but if an objcclass implements a protocol, the message names do
       not have to be repeated (but if they are, they have to match;
       the same goes when overriding inherited methods)
  + allow specifying the external name of Objective-C classes and
    protocols, since classes and protocols can have the same name
    (and you cannot use the same Pascal identifier in such caseq)
  + added NSObject protocol, and make the NSObject class use it
  + added missing NSObject class methods that have the same name
    as instance methods (added "class" name prefix to avoid clashes)
  * fixed several cases where the compiler did not treat Objective-C
    classes/protocols the same as Object Pascal classes/interfaces
    (a.o., forward declarations, alignment, regvars, several type
     conversions, ...)
  * allow "override" directive in objcclass declarations, and print
    a hint if it's forgotten in an external declaration (because it
    doesn't really matter there, and may make automated header
    conversion harder than necessary) and an error if will be used in
    a non-external declaration (because it is not possible to start
    a new vmt entry-tree in Objective-C, you can only override parent
    methods)
  * reject objcclasses/protocols as parameters to typeof()
  * don't try to test VMT validity of objcclasses/protocols

git-svn-id: branches/objc@13375 -
2009-07-09 20:48:28 +00:00

418 lines
11 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Florian Klaempfl, Pierre Muller
This unit handles the symbol tables
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit symbase;
{$i fpcdefs.inc}
interface
uses
{ common }
cutils,cclasses,
{ global }
globtype,globals,
{ symtable }
symconst
;
{************************************************
Needed forward pointers
************************************************}
type
TSymtable = class;
{ THashedIDString }
THashedIDString=object
private
FId : TIDString;
FHash : Longword;
procedure SetId(const s:TIDString);
public
property Id:TIDString read FId write SetId;
property Hash:longword read FHash;
end;
{************************************************
TDefEntry
************************************************}
TDefEntry = class
typ : tdeftyp;
defid : longint;
owner : TSymtable;
end;
{************************************************
TSymEntry
************************************************}
{ this object is the base for all symbol objects }
TSymEntry = class(TFPHashObject)
private
FRealName : pshortstring;
function GetRealname:shortstring;
procedure SetRealname(const ANewName:shortstring);
public
typ : tsymtyp;
SymId : longint;
Owner : TSymtable;
destructor destroy;override;
property RealName:shortstring read GetRealName write SetRealName;
end;
{************************************************
TSymtable
************************************************}
TSymtable = class
public
name : pshortstring;
realname : pshortstring;
DefList : TFPObjectList;
SymList : TFPHashObjectList;
defowner : TDefEntry; { for records and objects }
moduleid : longint;
refcount : smallint;
currentvisibility : tvisibility;
currentlyoptional : boolean;
{ level of symtable, used for nested procedures }
symtablelevel : byte;
symtabletype : TSymtabletype;
constructor Create(const s:string);
destructor destroy;override;
procedure freeinstance;override;
function getcopy:TSymtable;
procedure clear;virtual;
function checkduplicate(var s:THashedIDString;sym:TSymEntry):boolean;virtual;
procedure insert(sym:TSymEntry;checkdup:boolean=true);virtual;
procedure Delete(sym:TSymEntry);virtual;
function Find(const s:TIDString) : TSymEntry;
function FindWithHash(const s:THashedIDString) : TSymEntry;virtual;
procedure insertdef(def:TDefEntry);virtual;
procedure deletedef(def:TDefEntry);
function iscurrentunit:boolean;virtual;
end;
psymtablestackitem = ^TSymtablestackitem;
TSymtablestackitem = record
symtable : TSymtable;
next : psymtablestackitem;
end;
TSymtablestack = class
stack : psymtablestackitem;
constructor create;
destructor destroy;override;
procedure clear;
procedure push(st:TSymtable);
procedure pop(st:TSymtable);
function top:TSymtable;
end;
var
initialmacrosymtable: TSymtable; { macros initially defined by the compiler or
given on the command line. Is common
for all files compiled and do not change. }
macrosymtablestack,
symtablestack : TSymtablestack;
{$ifdef MEMDEBUG}
var
memrealnames : tmemdebug;
{$endif MEMDEBUG}
implementation
uses
verbose;
{****************************************************************************
THashedIDString
****************************************************************************}
procedure THashedIDString.SetId(const s:TIDString);
begin
FId:=s;
FHash:=FPHash(s);
end;
{****************************************************************************
TSymEntry
****************************************************************************}
destructor TSymEntry.destroy;
begin
{$ifdef MEMDEBUG}
memrealnames.start;
{$endif MEMDEBUG}
stringdispose(Frealname);
{$ifdef MEMDEBUG}
memrealnames.stop;
{$endif MEMDEBUG}
inherited destroy;
end;
function TSymEntry.GetRealname:shortstring;
begin
if not assigned(FRealname) then
internalerror(200611011);
result:=FRealname^;
end;
procedure TSymEntry.SetRealname(const ANewName:shortstring);
begin
stringdispose(FRealname);
FRealname:=stringdup(ANewName);
if Hash<>$ffffffff then
begin
if FRealname^[1]='$' then
Rename(Copy(FRealname^,2,255))
else
Rename(Upper(FRealname^));
end;
end;
{****************************************************************************
TSymtable
****************************************************************************}
constructor TSymtable.Create(const s:string);
begin
if s<>'' then
begin
name:=stringdup(upper(s));
realname:=stringdup(s);
end
else
begin
name:=nil;
realname:=nil;
end;
symtabletype:=abstractsymtable;
symtablelevel:=0;
defowner:=nil;
DefList:=TFPObjectList.Create(true);
SymList:=TFPHashObjectList.Create(true);
refcount:=1;
currentvisibility:=vis_public;
currentlyoptional:=false;
end;
destructor TSymtable.destroy;
begin
{ freeinstance decreases refcount }
if refcount>1 then
exit;
Clear;
DefList.Free;
{ SymList can already be disposed or set to nil for withsymtable, }
{ but in that case Free does nothing }
SymList.Free;
stringdispose(name);
stringdispose(realname);
end;
procedure TSymtable.freeinstance;
begin
dec(refcount);
if refcount=0 then
inherited freeinstance;
end;
function TSymtable.getcopy:TSymtable;
begin
inc(refcount);
result:=self;
end;
function TSymtable.iscurrentunit:boolean;
begin
result:=false;
end;
procedure TSymtable.clear;
var
i : integer;
begin
SymList.Clear;
{ Prevent recursive calls between TDef.destroy and TSymtable.Remove }
if DefList.OwnsObjects then
begin
for i := 0 to DefList.Count-1 do
TDefEntry(DefList[i]).Owner:=nil;
end;
DefList.Clear;
end;
function TSymtable.checkduplicate(var s:THashedIDString;sym:TSymEntry):boolean;
begin
result:=(FindWithHash(s)<>nil);
end;
procedure TSymtable.insert(sym:TSymEntry;checkdup:boolean=true);
var
hashedid : THashedIDString;
begin
if checkdup then
begin
if sym.realname[1]='$' then
hashedid.id:=Copy(sym.realname,2,255)
else
hashedid.id:=Upper(sym.realname);
{ First check for duplicates, this can change the symbol name
in case of a duplicate entry }
checkduplicate(hashedid,sym);
end;
{ Now we can insert the symbol, any duplicate entries
are renamed to an unique (and for users unaccessible) name }
if sym.realname[1]='$' then
sym.ChangeOwnerAndName(SymList,Copy(sym.realname,2,255))
else
sym.ChangeOwnerAndName(SymList,Upper(sym.realname));
sym.Owner:=self;
end;
procedure TSymtable.Delete(sym:TSymEntry);
begin
if sym.Owner<>self then
internalerror(200611121);
SymList.Remove(sym);
end;
procedure TSymtable.insertdef(def:TDefEntry);
begin
DefList.Add(def);
def.owner:=self;
end;
procedure TSymtable.deletedef(def:TDefEntry);
begin
if def.Owner<>self then
internalerror(200611122);
def.Owner:=nil;
DefList.Remove(def);
end;
function TSymtable.Find(const s : TIDString) : TSymEntry;
begin
result:=TSymEntry(SymList.Find(s));
end;
function TSymtable.FindWithHash(const s:THashedIDString) : TSymEntry;
begin
result:=TSymEntry(SymList.FindWithHash(s.id,s.hash));
end;
{****************************************************************************
Symtable Stack
****************************************************************************}
constructor TSymtablestack.create;
begin
stack:=nil;
end;
destructor TSymtablestack.destroy;
begin
clear;
end;
procedure TSymtablestack.clear;
var
hp : psymtablestackitem;
begin
while assigned(stack) do
begin
hp:=stack;
stack:=hp^.next;
dispose(hp);
end;
end;
procedure TSymtablestack.push(st:TSymtable);
var
hp : psymtablestackitem;
begin
new(hp);
hp^.symtable:=st;
hp^.next:=stack;
stack:=hp;
end;
procedure TSymtablestack.pop(st:TSymtable);
var
hp : psymtablestackitem;
begin
if not assigned(stack) then
internalerror(200601231);
if stack^.symtable<>st then
internalerror(200601232);
hp:=stack;
stack:=hp^.next;
dispose(hp);
end;
function TSymtablestack.top:TSymtable;
begin
if not assigned(stack) then
internalerror(200601233);
result:=stack^.symtable;
end;
{$ifdef MEMDEBUG}
initialization
memrealnames:=TMemDebug.create('Realnames');
memrealnames.stop;
finalization
memrealnames.free;
{$endif MEMDEBUG}
end.