mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 14:08:09 +02:00
Switching from overloaded type symbol to unique symbol per generic.
Reasons for the "unique symbol" approach: - no special search operations for cross unit search needed (which is supported by Delphi) => less performance impact - no special care needed to really find the correct generic => less increase of parser complexity Currently all generic tests except tgeneric29.pp compile and inline specializations work as well. The changes in detail: * pdecl.pas/types_dec: - The variables used to hold the final name of the symbol are now prefixed with "gen". In case of non-generics the prefixed ones are equal to the non-prefixed ones (e.g. orgtypename=genorgtypename). In case of a generic symbol the "gen"-variants contain the type parameter count suffix (e.g. '$1' in case of 'TTest<T>') as well. - The unmodified pattern is used to insert and detect a dummy symbol with that name, so that type declarations and - more important - inline specializations can find that symbol. - In non-Delphi modes this symbol is also used to detect whether we have a type redefinition which is not allowed currently; its typedef points to the generic def. - In mode Delphi the def of that dummy symbol (which contains an undefineddef) is modified when a corresponding non-generic type is parsed, so that it contains the def of the real type. * pdecsub.pas/parse_proc_head - consume_generic_type_parameter now only parses the type parameters and picks the generic with the correct amount of parameters. The verification of the order and names of the parameters needs to be added again. - it also does not use "def" anymore, but it sets "srsym" - in parse_proc_head the symbol (srsym) is only searched if the symbol isn't assigned already; in case of a generic in mode FPC it will find the dummy symbol that points to the generic def * pexpr.pas - in factor_read_id there are three cases to handle: + the symbol is not assigned => error + a possible generic symbol (either an undefined def or the non-generic variant) => no error and no hints + a non-generic symbol => hints Point 1 is handled correctly, point 2 and 3 aren't currently and also they might be needed to be moved somewhere else - sub_expr: + a node can be a tloadvmtaddrnode as well if the non-generic variant of a generic symbol is a class + we can only check afterwards whether the specialization was successful * pgenutil.pas/generate_specialization using the count of the parsed types the correct symbol can be found easily git-svn-id: branches/svenbarth/generics@17535 -
This commit is contained in:
parent
bba6e0e73f
commit
8f0583ffb2
@ -345,7 +345,8 @@ implementation
|
||||
end;
|
||||
|
||||
var
|
||||
typename,orgtypename : TIDString;
|
||||
typename,orgtypename,
|
||||
gentypename,genorgtypename : TIDString;
|
||||
newtype : ttypesym;
|
||||
sym : tsym;
|
||||
hdef : tdef;
|
||||
@ -360,6 +361,7 @@ implementation
|
||||
generictokenbuf : tdynamicarray;
|
||||
vmtbuilder : TVMTBuilder;
|
||||
i : integer;
|
||||
s : shortstring;
|
||||
begin
|
||||
old_block_type:=block_type;
|
||||
{ save unit container of forward declarations -
|
||||
@ -393,8 +395,18 @@ implementation
|
||||
consume(_LSHARPBRACKET);
|
||||
generictypelist:=parse_generic_parameters;
|
||||
consume(_RSHARPBRACKET);
|
||||
|
||||
str(generictypelist.Count,s);
|
||||
gentypename:=typename+'$'+s;
|
||||
genorgtypename:=orgtypename+'$'+s;
|
||||
end
|
||||
else
|
||||
begin
|
||||
gentypename:=typename;
|
||||
genorgtypename:=orgtypename;
|
||||
end;
|
||||
|
||||
|
||||
consume(_EQ);
|
||||
|
||||
{ support 'ttype=type word' syntax }
|
||||
@ -416,25 +428,19 @@ implementation
|
||||
{ is the type already defined? -- must be in the current symtable,
|
||||
not in a nested symtable or one higher up the stack -> don't
|
||||
use searchsym & frinds! }
|
||||
sym:=tsym(symtablestack.top.find(typename));
|
||||
sym:=tsym(symtablestack.top.find(gentypename));
|
||||
newtype:=nil;
|
||||
{ found a symbol with this name? }
|
||||
if assigned(sym) then
|
||||
begin
|
||||
if (sym.typ=typesym) then
|
||||
if (sym.typ=typesym) and
|
||||
{ this should not be a symbol that was created by a generic
|
||||
that was declared earlier }
|
||||
not (
|
||||
(ttypesym(sym).typedef.typ=undefineddef) and
|
||||
not (sp_generic_para in sym.symoptions)
|
||||
) then
|
||||
begin
|
||||
if isgeneric then
|
||||
begin
|
||||
{ overloading types is only allowed in mode Delphi }
|
||||
if not (m_delphi in current_settings.modeswitches) then
|
||||
Message1(sym_e_duplicate_id,orgtypename);
|
||||
for i:=0 to ttypesym(sym).gendeflist.Count-1 do
|
||||
{ TODO : check whether the count of one of the defs is
|
||||
the same as that of the current declaration and
|
||||
print an error if so }
|
||||
;
|
||||
end
|
||||
else
|
||||
if ((token=_CLASS) or
|
||||
(token=_INTERFACE) or
|
||||
(token=_DISPINTERFACE) or
|
||||
@ -465,17 +471,12 @@ implementation
|
||||
end;
|
||||
consume(token);
|
||||
{ we can ignore the result, the definition is modified }
|
||||
object_dec(objecttype,orgtypename,nil,nil,tobjectdef(ttypesym(sym).typedef),ht_none);
|
||||
object_dec(objecttype,genorgtypename,nil,nil,tobjectdef(ttypesym(sym).typedef),ht_none);
|
||||
newtype:=ttypesym(sym);
|
||||
hdef:=newtype.typedef;
|
||||
end
|
||||
else
|
||||
if not (m_delphi in current_settings.modeswitches) and
|
||||
(ttypesym(sym).typedef.typ=undefineddef) and
|
||||
(ttypesym(sym).gendeflist.Count>0) then
|
||||
message1(sym_e_duplicate_id,orgtypename)
|
||||
else
|
||||
message1(parser_h_type_redef,orgtypename);
|
||||
message1(parser_h_type_redef,genorgtypename);
|
||||
end;
|
||||
end;
|
||||
{ no old type reused ? Then insert this new type }
|
||||
@ -488,32 +489,45 @@ implementation
|
||||
storetokenpos:=current_tokenpos;
|
||||
if isgeneric then
|
||||
begin
|
||||
if assigned(sym) then
|
||||
newtype:=ttypesym(sym)
|
||||
else
|
||||
{ for generics we need to check whether a non-generic type
|
||||
already exists and if not we need to insert a symbol with
|
||||
the non-generic name (available in (org)typename) that is a
|
||||
undefineddef, so that inline specializations can be used }
|
||||
sym:=tsym(symtablestack.top.Find(typename));
|
||||
if not assigned(sym) then
|
||||
begin
|
||||
{ add the symbol with a undefineddef, so typesym can point
|
||||
to this symbol }
|
||||
newtype:=ttypesym.create(orgtypename,tundefineddef.create);
|
||||
newtype.typedef.typesym:=newtype;
|
||||
newtype.visibility:=symtablestack.top.currentvisibility;
|
||||
symtablestack.top.insert(newtype);
|
||||
newtype.typedef.owner:=newtype.owner;
|
||||
end;
|
||||
sym:=ttypesym.create(orgtypename,tundefineddef.create);
|
||||
ttypesym(sym).typedef.typesym:=sym;
|
||||
sym.visibility:=symtablestack.top.currentvisibility;
|
||||
symtablestack.top.insert(sym);
|
||||
ttypesym(sym).typedef.owner:=sym.owner;
|
||||
end
|
||||
else
|
||||
{ this is not allowed in non-Delphi modes }
|
||||
if not (m_delphi in current_settings.modeswitches) then
|
||||
Message1(sym_e_duplicate_id,genorgtypename);
|
||||
end
|
||||
else
|
||||
if assigned(sym) then
|
||||
newtype:=ttypesym(sym)
|
||||
else
|
||||
if assigned(sym) and (sym.typ=typesym) and
|
||||
(ttypesym(sym).typedef.typ=undefineddef) and
|
||||
not (sp_generic_para in sym.symoptions) then
|
||||
begin
|
||||
newtype:=ttypesym.create(orgtypename,hdef);
|
||||
newtype.visibility:=symtablestack.top.currentvisibility;
|
||||
symtablestack.top.insert(newtype);
|
||||
{ this is a symbol that was added by an earlier generic
|
||||
declaration, reuse it }
|
||||
newtype:=ttypesym(sym);
|
||||
newtype.typedef:=hdef;
|
||||
end;
|
||||
{ insert a newtype if we don't reuse an existing symbol }
|
||||
if not assigned(newtype) then
|
||||
begin
|
||||
newtype:=ttypesym.create(genorgtypename,hdef);
|
||||
newtype.visibility:=symtablestack.top.currentvisibility;
|
||||
symtablestack.top.insert(newtype);
|
||||
end;
|
||||
current_tokenpos:=defpos;
|
||||
current_tokenpos:=storetokenpos;
|
||||
{ read the type definition }
|
||||
read_named_type(hdef,orgtypename,nil,generictypelist,false);
|
||||
read_named_type(hdef,genorgtypename,nil,generictypelist,false);
|
||||
{ update the definition of the type }
|
||||
if assigned(hdef) then
|
||||
begin
|
||||
@ -532,8 +546,8 @@ implementation
|
||||
begin
|
||||
stringdispose(objname);
|
||||
stringdispose(objrealname);
|
||||
objrealname:=stringdup(orgtypename);
|
||||
objname:=stringdup(upper(orgtypename));
|
||||
objrealname:=stringdup(genorgtypename);
|
||||
objname:=stringdup(upper(genorgtypename));
|
||||
end;
|
||||
|
||||
include(hdef.defoptions,df_unique);
|
||||
@ -544,14 +558,18 @@ implementation
|
||||
if not assigned(hdef.typesym) then
|
||||
hdef.typesym:=newtype;
|
||||
end;
|
||||
if isgeneric then begin
|
||||
newtype.Owner.includeoption(sto_has_generic);
|
||||
newtype.gendeflist.Add(hdef)
|
||||
end else
|
||||
newtype.typedef:=hdef;
|
||||
{ in non-Delphi modes we need a reference to the generic def
|
||||
without the generic suffix, so it can be found easily when
|
||||
parsing method implementations }
|
||||
if isgeneric and assigned(sym) and
|
||||
not (m_delphi in current_settings.modeswitches) and
|
||||
(ttypesym(sym).typedef.typ=undefineddef) then
|
||||
{ TODO : check whether the undefined def needs to be freed }
|
||||
ttypesym(sym).typedef:=hdef;
|
||||
newtype.typedef:=hdef;
|
||||
{ KAZ: handle TGUID declaration in system unit }
|
||||
if (cs_compilesystem in current_settings.moduleswitches) and not assigned(rec_tguid) and
|
||||
(typename='TGUID') and { name: TGUID and size=16 bytes that is 128 bits }
|
||||
(gentypename='TGUID') and { name: TGUID and size=16 bytes that is 128 bits }
|
||||
assigned(hdef) and (hdef.typ=recorddef) and (hdef.size=16) then
|
||||
rec_tguid:=trecorddef(hdef);
|
||||
end;
|
||||
|
@ -812,7 +812,6 @@ implementation
|
||||
old_current_genericdef,
|
||||
old_current_specializedef: tstoreddef;
|
||||
lasttoken,lastidtoken: ttoken;
|
||||
def : tdef;
|
||||
|
||||
procedure parse_operator_name;
|
||||
begin
|
||||
@ -911,108 +910,60 @@ implementation
|
||||
|
||||
function consume_generic_type_parameter:boolean;
|
||||
var
|
||||
i,
|
||||
j,
|
||||
declidx,
|
||||
idx : integer;
|
||||
found : boolean;
|
||||
sym:tsym;
|
||||
genparalistdecl : TFPHashList;
|
||||
genname : tidstring;
|
||||
s : shortstring;
|
||||
begin
|
||||
result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches);
|
||||
if result then
|
||||
begin
|
||||
{ is this an overloaded typesym? }
|
||||
srsym:=search_object_name(sp,false);
|
||||
if (srsym.typ=typesym) and
|
||||
(ttypesym(srsym).gendeflist.Count>0) then
|
||||
{ parse all parameters first so we can check whether we have
|
||||
the correct generic def available }
|
||||
genparalistdecl:=TFPHashList.Create;
|
||||
if try_to_consume(_LT) then
|
||||
begin
|
||||
{ parse all parameters first so we can check whether we have
|
||||
the correct generic def available }
|
||||
genparalistdecl:=TFPHashList.Create;
|
||||
if try_to_consume(_LT) then
|
||||
begin
|
||||
{ start with 1, so Find can return Nil (= 0) }
|
||||
idx:=1;
|
||||
repeat
|
||||
if token=_ID then
|
||||
begin
|
||||
genparalistdecl.Add(pattern, Pointer(PtrInt(idx)));
|
||||
consume(_ID);
|
||||
inc(idx);
|
||||
end
|
||||
else
|
||||
begin
|
||||
message2(scan_f_syn_expected,arraytokeninfo[_ID].str,arraytokeninfo[token].str);
|
||||
if token<>_COMMA then
|
||||
consume(token);
|
||||
end;
|
||||
until not try_to_consume(_COMMA);
|
||||
if not try_to_consume(_GT) then
|
||||
consume(_RSHARPBRACKET);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ no generic }
|
||||
srsym:=nil;
|
||||
exit;
|
||||
end;
|
||||
{ start with 1, so Find can return Nil (= 0) }
|
||||
idx:=1;
|
||||
repeat
|
||||
if token=_ID then
|
||||
begin
|
||||
genparalistdecl.Add(pattern, Pointer(PtrInt(idx)));
|
||||
consume(_ID);
|
||||
inc(idx);
|
||||
end
|
||||
else
|
||||
begin
|
||||
message2(scan_f_syn_expected,arraytokeninfo[_ID].str,arraytokeninfo[token].str);
|
||||
if token<>_COMMA then
|
||||
consume(token);
|
||||
end;
|
||||
until not try_to_consume(_COMMA);
|
||||
if not try_to_consume(_GT) then
|
||||
consume(_RSHARPBRACKET);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ no generic }
|
||||
srsym:=nil;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ now search the matching generic definition }
|
||||
found:=false;
|
||||
for i:=0 to ttypesym(srsym).gendeflist.Count-1 do
|
||||
begin
|
||||
def:=tdef(ttypesym(srsym).gendeflist[i]);
|
||||
{ for now generic overloads are only allowed for records
|
||||
and objects; later they'll also be allowed for
|
||||
procedures and functions }
|
||||
if not (def.typ in [objectdef,recorddef]) then
|
||||
continue;
|
||||
st:=def.getsymtable(gs_record);
|
||||
if not assigned(st) then
|
||||
InternalError(2011042901);
|
||||
idx:=1;
|
||||
{ check whether the generic parameters of the def have the
|
||||
same count and order as the ones just scanned, if so
|
||||
"found" is true }
|
||||
for j:=0 to st.SymList.Count-1 do
|
||||
begin
|
||||
sym:=tsym(st.SymList[j]);
|
||||
if sp_generic_para in sym.symoptions then
|
||||
begin
|
||||
if not (sym.typ=typesym) then
|
||||
internalerror(2011290402);
|
||||
{ too many parameters }
|
||||
if idx>genparalistdecl.Count then
|
||||
break;
|
||||
declidx:=PtrInt(genparalistdecl.Find(sym.prettyname));
|
||||
{ does the parameters' index match the current
|
||||
index value? }
|
||||
if (declidx=0) or (declidx<>idx) then
|
||||
break;
|
||||
inc(idx);
|
||||
end;
|
||||
if (j=st.SymList.Count-1) and (idx=genparalistdecl.Count+1) then
|
||||
found:=true;
|
||||
end;
|
||||
s:='';
|
||||
str(genparalistdecl.count,s);
|
||||
genname:=sp+'$'+s;
|
||||
|
||||
{ the first found matching generic def wins }
|
||||
if found then
|
||||
break;
|
||||
end;
|
||||
genparalistdecl.free;
|
||||
|
||||
genparalistdecl.free;
|
||||
|
||||
if not found then
|
||||
begin
|
||||
{ TODO : print a nicer typename that contains the parsed
|
||||
generic types }
|
||||
Message1(type_e_generic_declaration_does_not_match,sp);
|
||||
srsym:=nil;
|
||||
def:=nil;
|
||||
exit;
|
||||
end;
|
||||
srsym:=search_object_name(genname,false);
|
||||
|
||||
if not assigned(srsym) then
|
||||
begin
|
||||
{ TODO : print a nicer typename that contains the parsed
|
||||
generic types }
|
||||
Message1(type_e_generic_declaration_does_not_match,genname);
|
||||
srsym:=nil;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -1056,40 +1007,23 @@ implementation
|
||||
end;
|
||||
|
||||
{ method ? }
|
||||
def:=nil;
|
||||
srsym:=nil;
|
||||
if (consume_generic_type_parameter or not assigned(astruct)) and
|
||||
(symtablestack.top.symtablelevel=main_program_level) and
|
||||
try_to_consume(_POINT) then
|
||||
begin
|
||||
repeat
|
||||
searchagain:=false;
|
||||
if not assigned(astruct) then
|
||||
begin
|
||||
if not assigned(def) then
|
||||
begin
|
||||
srsym:=search_object_name(sp,true);
|
||||
{ in non-Delphi modes we can directly use the generic def if one
|
||||
exists }
|
||||
if (srsym.typ=typesym) then
|
||||
if (ttypesym(srsym).gendeflist.Count>0) and
|
||||
not (m_delphi in current_settings.modeswitches) then
|
||||
def:=tdef(ttypesym(srsym).gendeflist[0])
|
||||
else
|
||||
def:=ttypesym(srsym).typedef
|
||||
else
|
||||
def:=nil;
|
||||
end;
|
||||
end
|
||||
else
|
||||
def:=astruct;
|
||||
if not assigned(astruct) and not assigned(srsym) then
|
||||
srsym:=search_object_name(sp,true);
|
||||
{ consume proc name }
|
||||
procstartfilepos:=current_tokenpos;
|
||||
consume_proc_name;
|
||||
{ qualifier is class name ? }
|
||||
if (srsym.typ=typesym) and
|
||||
(def.typ in [objectdef,recorddef]) then
|
||||
(ttypesym(srsym).typedef.typ in [objectdef,recorddef]) then
|
||||
begin
|
||||
astruct:=tabstractrecorddef(def);
|
||||
astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
|
||||
if (token<>_POINT) then
|
||||
if (potype in [potype_class_constructor,potype_class_destructor]) then
|
||||
sp:=lower(sp)
|
||||
|
@ -1912,20 +1912,21 @@ implementation
|
||||
consume(_ASSIGNMENT);
|
||||
exit;
|
||||
end;
|
||||
{ if nothing found give error and return errorsym }
|
||||
{ TODO : adjust this check for inline specializations }
|
||||
|
||||
{ check hints if it is the final symbol that is used (e.g. in
|
||||
case of generics only the dummy symbol or the non-generic one
|
||||
is found here }
|
||||
if assigned(srsym) and
|
||||
not (
|
||||
{ in case of an overloaded generic symbol we need to
|
||||
generate an error if the non-generic symbol is still
|
||||
undefined and we're not doing a specialization }
|
||||
typeonly and (srsym.typ=typesym) and
|
||||
(ttypesym(srsym).typedef.typ=undefineddef) and
|
||||
(ttypesym(srsym).gendeflist.Count>0) and
|
||||
not (token in [_LT, _LSHARPBRACKET])
|
||||
not (sp_generic_para in srsym.symoptions) and
|
||||
(token in [_LT, _LSHARPBRACKET])
|
||||
) then
|
||||
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg)
|
||||
else
|
||||
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
|
||||
|
||||
{ if nothing found give error and return errorsym }
|
||||
if not assigned(srsym) then
|
||||
begin
|
||||
identifier_not_found(orgstoredpattern);
|
||||
srsym:=generrorsym;
|
||||
@ -2842,7 +2843,7 @@ implementation
|
||||
filepos : tfileposinfo;
|
||||
again,
|
||||
isgeneric : boolean;
|
||||
def : tdef;
|
||||
gendef,parseddef : tdef;
|
||||
begin
|
||||
if pred_level=highest_precedence then
|
||||
p1:=factor(false,typeonly)
|
||||
@ -2876,24 +2877,47 @@ implementation
|
||||
_LT :
|
||||
begin
|
||||
isgeneric:=false;
|
||||
if (p1.nodetype=typen) and (p2.nodetype=typen) and
|
||||
if (
|
||||
{ the left node needs to be a type node }
|
||||
(p1.nodetype=typen) or
|
||||
(
|
||||
(p1.nodetype=loadvmtaddrn) and
|
||||
(tloadvmtaddrnode(p1).left.nodetype=typen)
|
||||
)
|
||||
) and
|
||||
(
|
||||
{ the right node needs to be a type node }
|
||||
(p2.nodetype=typen) or
|
||||
(
|
||||
(p2.nodetype=loadvmtaddrn) and
|
||||
(tloadvmtaddrnode(p2).left.nodetype=typen)
|
||||
)
|
||||
) and
|
||||
(m_delphi in current_settings.modeswitches) and
|
||||
(token in [_GT,_RSHARPBRACKET,_COMMA]) then
|
||||
begin
|
||||
{ this is an inline specialization }
|
||||
if ttypenode(p1).typedef.typesym.typ<>typesym then
|
||||
Internalerror(2011050301);
|
||||
{ TODO : search for other generics with the same name
|
||||
in other units (if no unit identifier is
|
||||
given...) }
|
||||
if ttypesym(ttypenode(p1).typedef.typesym).gendeflist.Count>0 then
|
||||
begin
|
||||
def:=ttypenode(p1).typedef;
|
||||
generate_specialization(def,false,ttypenode(p2).typedef);
|
||||
isgeneric:=def<>generrordef;
|
||||
end
|
||||
|
||||
{ retrive the def of the left node }
|
||||
if p1.nodetype=typen then
|
||||
gendef:=ttypenode(p1).typedef
|
||||
else
|
||||
;
|
||||
gendef:=ttypenode(tloadvmtaddrnode(p1).left).typedef;
|
||||
|
||||
{ retrieve the right node }
|
||||
if p2.nodetype=typen then
|
||||
parseddef:=ttypenode(p2).typedef
|
||||
else
|
||||
parseddef:=ttypenode(tloadvmtaddrnode(p2).left).typedef;
|
||||
|
||||
if gendef.typesym.typ<>typesym then
|
||||
Internalerror(2011050301);
|
||||
if parseddef.typesym.typ<>typesym then
|
||||
Internalerror(2011051001);
|
||||
|
||||
{ generate the specialization }
|
||||
generate_specialization(gendef,false,parseddef);
|
||||
isgeneric:=gendef<>generrordef;
|
||||
end;
|
||||
|
||||
if not isgeneric then
|
||||
@ -2904,9 +2928,10 @@ implementation
|
||||
p1.Free;
|
||||
p2.Free;
|
||||
{ in case of a class this is always a classrefdef }
|
||||
if is_class_or_interface_or_object(def) or is_record(def) then
|
||||
def:=tclassrefdef.create(def);
|
||||
p1:=ctypenode.create(def);
|
||||
if is_class_or_interface_or_object(gendef) or
|
||||
is_record(gendef) then
|
||||
gendef:=tclassrefdef.create(gendef);
|
||||
p1:=ctypenode.create(gendef);
|
||||
again:=true;
|
||||
{ parse postfix operators }
|
||||
if postfixoperators(p1,again,false) then
|
||||
|
@ -59,13 +59,10 @@ uses
|
||||
st : TSymtable;
|
||||
srsym : tsym;
|
||||
pt2 : tnode;
|
||||
found,
|
||||
first,
|
||||
err : boolean;
|
||||
i,
|
||||
j,
|
||||
gencount : longint;
|
||||
sym : tsym;
|
||||
genericdef : tstoreddef;
|
||||
genericsym,
|
||||
generictype : ttypesym;
|
||||
@ -76,12 +73,11 @@ uses
|
||||
hmodule : tmodule;
|
||||
pu : tused_unit;
|
||||
uspecializename,
|
||||
specializename : string;
|
||||
countstr,genname,ugenname,specializename : string;
|
||||
vmtbuilder : TVMTBuilder;
|
||||
onlyparsepara : boolean;
|
||||
specializest : tsymtable;
|
||||
item: psymtablestackitem;
|
||||
def : tdef;
|
||||
begin
|
||||
{ retrieve generic def that we are going to replace }
|
||||
genericdef:=tstoreddef(tt);
|
||||
@ -93,13 +89,6 @@ uses
|
||||
internalerror(2011042701);
|
||||
|
||||
genericsym:=ttypesym(genericdef.typesym);
|
||||
if genericsym.gendeflist.Count=0 then
|
||||
begin
|
||||
{ TODO : search for other generics with the same name }
|
||||
Message(parser_e_special_onlygenerics);
|
||||
tt:=generrordef;
|
||||
onlyparsepara:=true;
|
||||
end;
|
||||
|
||||
{ only need to record the tokens, then we don't know the type yet ... }
|
||||
if parse_generic then
|
||||
@ -178,63 +167,68 @@ uses
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ check whether we have a generic with the correct amount of params }
|
||||
found:=false;
|
||||
for i:=0 to genericsym.gendeflist.Count-1 do begin
|
||||
def:=tdef(genericsym.gendeflist[i]);
|
||||
{ select the symtable containing the params }
|
||||
case def.typ of
|
||||
procdef:
|
||||
st:=def.GetSymtable(gs_para);
|
||||
objectdef,
|
||||
recorddef:
|
||||
st:=def.GetSymtable(gs_record);
|
||||
arraydef:
|
||||
st:=tarraydef(def).symtable;
|
||||
procvardef:
|
||||
st:=def.GetSymtable(gs_para);
|
||||
else
|
||||
internalerror(200511182);
|
||||
end;
|
||||
|
||||
gencount:=0;
|
||||
for j:=0 to st.SymList.Count-1 do
|
||||
begin
|
||||
if sp_generic_para in tsym(st.SymList[j]).symoptions then
|
||||
inc(gencount);
|
||||
end;
|
||||
|
||||
if gencount=genericdeflist.count then
|
||||
begin
|
||||
found:=true;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if not found then
|
||||
{ search a generic with the given count of params }
|
||||
countstr:='';
|
||||
str(genericdeflist.Count,countstr);
|
||||
{ use the name of the symbol as procvars return a user friendly version
|
||||
of the name }
|
||||
genname:=ttypesym(genericdef.typesym).realname;
|
||||
{ in case of non-Delphi mode the type name could already be a generic
|
||||
def (but maybe the wrong one) }
|
||||
if df_generic in genericdef.defoptions then
|
||||
begin
|
||||
identifier_not_found(genericdef.typename);
|
||||
tt:=generrordef;
|
||||
{ remove the type count suffix from the generic's name }
|
||||
for i:=Length(genname) downto 1 do
|
||||
if genname[i]='$' then
|
||||
begin
|
||||
genname:=copy(genname,1,i-1);
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
genname:=genname+'$'+countstr;
|
||||
ugenname:=upper(genname);
|
||||
|
||||
if not searchsym(ugenname,srsym,st)
|
||||
or (srsym.typ<>typesym) then
|
||||
begin
|
||||
identifier_not_found(genname);
|
||||
genericdeflist.Free;
|
||||
generictypelist.Free;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ we've found the correct def, so use it }
|
||||
genericdef:=tstoreddef(def);
|
||||
{ we've found the correct def }
|
||||
genericdef:=tstoreddef(ttypesym(srsym).typedef);
|
||||
|
||||
{ build the new type's name }
|
||||
specializename:=genericdef.typesym.realname+specializename;
|
||||
specializename:=genname+specializename;
|
||||
uspecializename:=upper(specializename);
|
||||
|
||||
{ select the symtable containing the params }
|
||||
case genericdef.typ of
|
||||
procdef:
|
||||
st:=genericdef.GetSymtable(gs_para);
|
||||
objectdef,
|
||||
recorddef:
|
||||
st:=genericdef.GetSymtable(gs_record);
|
||||
arraydef:
|
||||
st:=tarraydef(genericdef).symtable;
|
||||
procvardef:
|
||||
st:=genericdef.GetSymtable(gs_para);
|
||||
else
|
||||
internalerror(200511182);
|
||||
end;
|
||||
|
||||
{ build the list containing the types for the generic params }
|
||||
gencount:=0;
|
||||
for i:=0 to st.SymList.Count-1 do
|
||||
begin
|
||||
sym:=tsym(st.SymList[i]);
|
||||
if sp_generic_para in sym.symoptions then
|
||||
srsym:=tsym(st.SymList[i]);
|
||||
if sp_generic_para in srsym.symoptions then
|
||||
begin
|
||||
if gencount=genericdeflist.Count then
|
||||
internalerror(2011042702);
|
||||
generictype:=ttypesym.create(sym.realname,tdef(genericdeflist[gencount]));
|
||||
generictype:=ttypesym.create(srsym.realname,tdef(genericdeflist[gencount]));
|
||||
generictypelist.add(generictype);
|
||||
inc(gencount);
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user