mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 16:09:31 +02:00
compiler: extend enumerator support for records:
- search GetEnumerator method in records too (while searching a enumerator for structure) - allow enumerator operator return type to be a record - copy/adapt enumerator helpers from tobjectdef to tabstractrecorddef + test git-svn-id: trunk@16807 -
This commit is contained in:
parent
8102c480d7
commit
a39733a0a2
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -9388,6 +9388,7 @@ tests/test/tforin21.pp svneol=native#text/pascal
|
||||
tests/test/tforin22.pp svneol=native#text/pascal
|
||||
tests/test/tforin23.pp svneol=native#text/pascal
|
||||
tests/test/tforin24.pp svneol=native#text/pascal
|
||||
tests/test/tforin25.pp svneol=native#text/pascal
|
||||
tests/test/tforin3.pp svneol=native#text/pascal
|
||||
tests/test/tforin4.pp svneol=native#text/pascal
|
||||
tests/test/tforin5.pp svneol=native#text/pascal
|
||||
|
@ -444,15 +444,16 @@ implementation
|
||||
if optoken=_OP_ENUMERATOR then
|
||||
begin
|
||||
result:=
|
||||
is_class_or_interface_or_object(pf.returndef);
|
||||
is_class_or_interface_or_object(pf.returndef) or
|
||||
is_record(pf.returndef);
|
||||
if result then
|
||||
begin
|
||||
if not assigned(tobjectdef(pf.returndef).search_enumerator_move) then
|
||||
if not assigned(tabstractrecorddef(pf.returndef).search_enumerator_move) then
|
||||
begin
|
||||
Message1(sym_e_no_enumerator_move, pf.returndef.typename);
|
||||
result:=false;
|
||||
end;
|
||||
if not assigned(tobjectdef(pf.returndef).search_enumerator_current) then
|
||||
if not assigned(tabstractrecorddef(pf.returndef).search_enumerator_current) then
|
||||
begin
|
||||
Message1(sym_e_no_enumerator_current,pf.returndef.typename);
|
||||
result:=false;
|
||||
|
@ -859,13 +859,13 @@ implementation
|
||||
begin
|
||||
// search for operator first
|
||||
pd:=search_enumerator_operator(expr.resultdef, hloopvar.resultdef);
|
||||
// if there is no operator then search for class/object enumerator method
|
||||
if (pd=nil) and (expr.resultdef.typ=objectdef) then
|
||||
pd:=tobjectdef(expr.resultdef).search_enumerator_get;
|
||||
// if there is no operator then search for class/object/record enumerator method
|
||||
if (pd=nil) and (expr.resultdef.typ in [objectdef,recorddef]) then
|
||||
pd:=tabstractrecorddef(expr.resultdef).search_enumerator_get;
|
||||
if pd<>nil then
|
||||
begin
|
||||
// seach movenext and current symbols
|
||||
movenext:=tobjectdef(pd.returndef).search_enumerator_move;
|
||||
movenext:=tabstractrecorddef(pd.returndef).search_enumerator_move;
|
||||
if movenext = nil then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
@ -875,7 +875,7 @@ implementation
|
||||
end
|
||||
else
|
||||
begin
|
||||
current:=tpropertysym(tobjectdef(pd.returndef).search_enumerator_current);
|
||||
current:=tpropertysym(tabstractrecorddef(pd.returndef).search_enumerator_current);
|
||||
if current = nil then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
|
@ -2472,7 +2472,7 @@ const
|
||||
mutexclpo : [po_public,po_exports,po_interrupt,po_assembler,po_inline]
|
||||
),(
|
||||
idtok:_ENUMERATOR;
|
||||
pd_flags : [pd_interface,pd_object];
|
||||
pd_flags : [pd_interface,pd_object,pd_record];
|
||||
handler : @pd_enumerator;
|
||||
pocall : pocall_none;
|
||||
pooption : [];
|
||||
|
@ -186,9 +186,13 @@ interface
|
||||
destructor destroy; override;
|
||||
procedure check_forwards; virtual;
|
||||
function find_procdef_bytype(pt:tproctypeoption): tprocdef;
|
||||
function GetSymtable(t:tGetSymtable):TSymtable;override;
|
||||
function GetSymtable(t:tGetSymtable):TSymtable;override;
|
||||
function is_packed:boolean;
|
||||
function RttiName: string;
|
||||
{ enumerator support }
|
||||
function search_enumerator_get: tprocdef; virtual;
|
||||
function search_enumerator_move: tprocdef; virtual;
|
||||
function search_enumerator_current: tsym; virtual;
|
||||
end;
|
||||
|
||||
trecorddef = class(tabstractrecorddef)
|
||||
@ -315,9 +319,9 @@ interface
|
||||
{ dispinterface support }
|
||||
function get_next_dispid: longint;
|
||||
{ enumerator support }
|
||||
function search_enumerator_get: tprocdef;
|
||||
function search_enumerator_move: tprocdef;
|
||||
function search_enumerator_current: tsym;
|
||||
function search_enumerator_get: tprocdef; override;
|
||||
function search_enumerator_move: tprocdef; override;
|
||||
function search_enumerator_current: tsym; override;
|
||||
{ WPO }
|
||||
procedure register_created_object_type;override;
|
||||
procedure register_maybe_created_object_type;
|
||||
@ -2681,6 +2685,101 @@ implementation
|
||||
until tmp=nil;
|
||||
end;
|
||||
|
||||
function tabstractrecorddef.search_enumerator_get: tprocdef;
|
||||
var
|
||||
sym : tsym;
|
||||
i : integer;
|
||||
pd : tprocdef;
|
||||
hashedid : THashedIDString;
|
||||
begin
|
||||
result:=nil;
|
||||
hashedid.id:='GETENUMERATOR';
|
||||
sym:=tsym(symtable.FindWithHash(hashedid));
|
||||
if assigned(sym) and (sym.typ=procsym) then
|
||||
begin
|
||||
for i := 0 to Tprocsym(sym).ProcdefList.Count - 1 do
|
||||
begin
|
||||
pd := tprocdef(Tprocsym(sym).ProcdefList[i]);
|
||||
if (pd.proctypeoption = potype_function) and
|
||||
(is_class_or_interface_or_object(pd.returndef) or is_record(pd.returndef)) and
|
||||
(pd.visibility >= vis_public) then
|
||||
begin
|
||||
result:=pd;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function tabstractrecorddef.search_enumerator_move: tprocdef;
|
||||
var
|
||||
sym : tsym;
|
||||
i : integer;
|
||||
pd : tprocdef;
|
||||
hashedid : THashedIDString;
|
||||
begin
|
||||
result:=nil;
|
||||
// first search for po_enumerator_movenext method modifier
|
||||
// then search for public function MoveNext: Boolean
|
||||
for i:=0 to symtable.SymList.Count-1 do
|
||||
begin
|
||||
sym:=TSym(symtable.SymList[i]);
|
||||
if (sym.typ=procsym) then
|
||||
begin
|
||||
pd:=Tprocsym(sym).find_procdef_byoptions([po_enumerator_movenext]);
|
||||
if assigned(pd) then
|
||||
begin
|
||||
result:=pd;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
hashedid.id:='MOVENEXT';
|
||||
sym:=tsym(symtable.FindWithHash(hashedid));
|
||||
if assigned(sym) and (sym.typ=procsym) then
|
||||
begin
|
||||
for i:=0 to Tprocsym(sym).ProcdefList.Count-1 do
|
||||
begin
|
||||
pd := tprocdef(Tprocsym(sym).ProcdefList[i]);
|
||||
if (pd.proctypeoption = potype_function) and
|
||||
is_boolean(pd.returndef) and
|
||||
(pd.minparacount = 0) and
|
||||
(pd.visibility >= vis_public) then
|
||||
begin
|
||||
result:=pd;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function tabstractrecorddef.search_enumerator_current: tsym;
|
||||
var
|
||||
sym: tsym;
|
||||
i: integer;
|
||||
hashedid : THashedIDString;
|
||||
begin
|
||||
result:=nil;
|
||||
// first search for ppo_enumerator_current property modifier
|
||||
// then search for public property Current
|
||||
for i:=0 to symtable.SymList.Count-1 do
|
||||
begin
|
||||
sym:=TSym(symtable.SymList[i]);
|
||||
if (sym.typ=propertysym) and (ppo_enumerator_current in tpropertysym(sym).propoptions) then
|
||||
begin
|
||||
result:=sym;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
hashedid.id:='CURRENT';
|
||||
sym:=tsym(symtable.FindWithHash(hashedid));
|
||||
if assigned(sym) and (sym.typ=propertysym) and
|
||||
(sym.visibility >= vis_public) and not tpropertysym(sym).propaccesslist[palt_read].empty then
|
||||
begin
|
||||
result:=sym;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
{***************************************************************************
|
||||
trecorddef
|
||||
@ -4834,7 +4933,7 @@ implementation
|
||||
begin
|
||||
pd := tprocdef(Tprocsym(sym).ProcdefList[i]);
|
||||
if (pd.proctypeoption = potype_function) and
|
||||
is_class_or_interface_or_object(pd.returndef) and
|
||||
(is_class_or_interface_or_object(pd.returndef) or is_record(pd.returndef)) and
|
||||
(pd.visibility >= vis_public) then
|
||||
begin
|
||||
result:=pd;
|
||||
|
@ -812,9 +812,9 @@ implementation
|
||||
pd:=tprocdef(ProcdefList[i]);
|
||||
if (pd.owner.symtabletype=staticsymtable) and not pd.owner.iscurrentunit then
|
||||
continue;
|
||||
if not is_class_or_interface_or_object(pd.returndef) then
|
||||
if not (is_class_or_interface_or_object(pd.returndef) or is_record(pd.returndef)) then
|
||||
continue;
|
||||
current := tpropertysym(tobjectdef(pd.returndef).search_enumerator_current);
|
||||
current := tpropertysym(tabstractrecorddef(pd.returndef).search_enumerator_current);
|
||||
if (current = nil) then
|
||||
continue;
|
||||
// compare current result def with the todef
|
||||
|
52
tests/test/tforin25.pp
Normal file
52
tests/test/tforin25.pp
Normal file
@ -0,0 +1,52 @@
|
||||
program tforin25;
|
||||
{$mode objfpc}
|
||||
{$modeswitch advancedrecords}
|
||||
|
||||
type
|
||||
TIntArray = array[0..3] of Integer;
|
||||
|
||||
TEnumerator = record
|
||||
private
|
||||
FIndex: Integer;
|
||||
FArray: TIntArray;
|
||||
function GetCurrent: Integer;
|
||||
public
|
||||
function MoveNext: Boolean;
|
||||
property Current: Integer read GetCurrent;
|
||||
end;
|
||||
|
||||
TMyArray = record
|
||||
F: array[0..3] of Integer;
|
||||
function GetEnumerator: TEnumerator;
|
||||
end;
|
||||
|
||||
function TEnumerator.MoveNext: Boolean;
|
||||
begin
|
||||
inc(FIndex);
|
||||
Result := FIndex < Length(FArray);
|
||||
end;
|
||||
|
||||
function TEnumerator.GetCurrent: Integer;
|
||||
begin
|
||||
Result := FArray[FIndex];
|
||||
end;
|
||||
|
||||
function TMyArray.GetEnumerator: TEnumerator;
|
||||
begin
|
||||
Result.FArray := F;
|
||||
Result.FIndex := -1;
|
||||
end;
|
||||
{ this will compile too
|
||||
operator Enumerator(const A: TMyArray): TEnumerator;
|
||||
begin
|
||||
Result.FArray := A.F;
|
||||
Result.FIndex := -1;
|
||||
end;
|
||||
}
|
||||
var
|
||||
Arr: TMyArray;
|
||||
I: Integer;
|
||||
begin
|
||||
for I in Arr do
|
||||
WriteLn(I);
|
||||
end.
|
Loading…
Reference in New Issue
Block a user