mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-08 23:49:30 +01:00
* fixed indentation of for-in code
git-svn-id: trunk@15449 -
This commit is contained in:
parent
45d60dbb97
commit
df525d98a3
@ -241,426 +241,429 @@ implementation
|
|||||||
|
|
||||||
// for-in loop helpers
|
// for-in loop helpers
|
||||||
|
|
||||||
function create_type_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
function create_type_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||||
begin
|
|
||||||
result:=cfornode.create(hloopvar,
|
|
||||||
cinlinenode.create(in_low_x,false,expr.getcopy),
|
|
||||||
cinlinenode.create(in_high_x,false,expr.getcopy),
|
|
||||||
hloopbody,
|
|
||||||
false);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function create_string_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
||||||
var
|
|
||||||
loopstatement, loopbodystatement: tstatementnode;
|
|
||||||
loopvar, stringvar: ttempcreatenode;
|
|
||||||
stringindex, loopbody, forloopnode: tnode;
|
|
||||||
begin
|
|
||||||
{ result is a block of statements }
|
|
||||||
result:=internalstatements(loopstatement);
|
|
||||||
|
|
||||||
{ create a temp variable for expression }
|
|
||||||
stringvar := ctempcreatenode.create(
|
|
||||||
expr.resultdef,
|
|
||||||
expr.resultdef.size,
|
|
||||||
tt_persistent,true);
|
|
||||||
|
|
||||||
addstatement(loopstatement,stringvar);
|
|
||||||
addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(stringvar),expr.getcopy));
|
|
||||||
|
|
||||||
{ create a loop counter: signed integer with size of string length }
|
|
||||||
loopvar := ctempcreatenode.create(
|
|
||||||
sinttype,
|
|
||||||
sinttype.size,
|
|
||||||
tt_persistent,true);
|
|
||||||
|
|
||||||
addstatement(loopstatement,loopvar);
|
|
||||||
|
|
||||||
stringindex:=ctemprefnode.create(loopvar);
|
|
||||||
|
|
||||||
loopbody:=internalstatements(loopbodystatement);
|
|
||||||
// for-in loop variable := string_expression[index]
|
|
||||||
addstatement(loopbodystatement,
|
|
||||||
cassignmentnode.create(hloopvar, cvecnode.create(ctemprefnode.create(stringvar),stringindex)));
|
|
||||||
|
|
||||||
{ add the actual statement to the loop }
|
|
||||||
addstatement(loopbodystatement,hloopbody);
|
|
||||||
|
|
||||||
forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
|
||||||
genintconstnode(1),
|
|
||||||
cinlinenode.create(in_length_x,false,ctemprefnode.create(stringvar)),
|
|
||||||
loopbody,
|
|
||||||
false);
|
|
||||||
|
|
||||||
addstatement(loopstatement,forloopnode);
|
|
||||||
{ free the loop counter }
|
|
||||||
addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
|
||||||
{ free the temp variable for expression }
|
|
||||||
addstatement(loopstatement,ctempdeletenode.create(stringvar));
|
|
||||||
end;
|
|
||||||
|
|
||||||
function create_array_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
||||||
var
|
|
||||||
loopstatement, loopbodystatement: tstatementnode;
|
|
||||||
loopvar, arrayvar: ttempcreatenode;
|
|
||||||
arrayindex, lowbound, highbound, loopbody, forloopnode, expression: tnode;
|
|
||||||
is_string: boolean;
|
|
||||||
tmpdef, convertdef: tdef;
|
|
||||||
elementcount: aword;
|
|
||||||
begin
|
|
||||||
expression := expr;
|
|
||||||
|
|
||||||
{ result is a block of statements }
|
|
||||||
result:=internalstatements(loopstatement);
|
|
||||||
|
|
||||||
is_string:=ado_IsConstString in tarraydef(expr.resultdef).arrayoptions;
|
|
||||||
|
|
||||||
// if array element type <> loovar type then create a conversion if possible
|
|
||||||
if compare_defs(tarraydef(expression.resultdef).elementdef,hloopvar.resultdef,nothingn)=te_incompatible then
|
|
||||||
begin
|
|
||||||
tmpdef:=expression.resultdef;
|
|
||||||
elementcount:=1;
|
|
||||||
while assigned(tmpdef) and (tmpdef.typ=arraydef) and
|
|
||||||
(tarraydef(tmpdef).arrayoptions = []) and
|
|
||||||
(compare_defs(tarraydef(tmpdef).elementdef,hloopvar.resultdef,nothingn)=te_incompatible) do
|
|
||||||
begin
|
|
||||||
elementcount:=elementcount*tarraydef(tmpdef).elecount;
|
|
||||||
tmpdef:=tarraydef(tmpdef).elementdef;
|
|
||||||
end;
|
|
||||||
if assigned(tmpdef) and (tmpdef.typ=arraydef) and (tarraydef(tmpdef).arrayoptions = []) then
|
|
||||||
begin
|
|
||||||
elementcount:=elementcount*tarraydef(tmpdef).elecount;
|
|
||||||
convertdef:=tarraydef.create(0,elementcount-1,s32inttype);
|
|
||||||
tarraydef(convertdef).elementdef:=tarraydef(tmpdef).elementdef;
|
|
||||||
expression:=expr.getcopy;
|
|
||||||
expression:=ctypeconvnode.create_internal(expression,convertdef);
|
|
||||||
typecheckpass(expression);
|
|
||||||
addstatement(loopstatement,expression);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if (node_complexity(expression) > 1) and not is_open_array(expression.resultdef) then
|
|
||||||
begin
|
|
||||||
{ create a temp variable for expression }
|
|
||||||
arrayvar := ctempcreatenode.create(
|
|
||||||
expression.resultdef,
|
|
||||||
expression.resultdef.size,
|
|
||||||
tt_persistent,true);
|
|
||||||
|
|
||||||
if is_string then
|
|
||||||
begin
|
|
||||||
lowbound:=genintconstnode(1);
|
|
||||||
highbound:=cinlinenode.create(in_length_x,false,ctemprefnode.create(arrayvar))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
lowbound:=cinlinenode.create(in_low_x,false,ctemprefnode.create(arrayvar));
|
|
||||||
highbound:=cinlinenode.create(in_high_x,false,ctemprefnode.create(arrayvar));
|
|
||||||
end;
|
|
||||||
|
|
||||||
addstatement(loopstatement,arrayvar);
|
|
||||||
addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(arrayvar),expression.getcopy));
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
arrayvar:=nil;
|
|
||||||
if is_string then
|
|
||||||
begin
|
|
||||||
lowbound:=genintconstnode(1);
|
|
||||||
highbound:=cinlinenode.create(in_length_x,false,expression.getcopy);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
lowbound:=cinlinenode.create(in_low_x,false,expression.getcopy);
|
|
||||||
highbound:=cinlinenode.create(in_high_x,false,expression.getcopy);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ create a loop counter }
|
|
||||||
loopvar := ctempcreatenode.create(
|
|
||||||
tarraydef(expression.resultdef).rangedef,
|
|
||||||
tarraydef(expression.resultdef).rangedef.size,
|
|
||||||
tt_persistent,true);
|
|
||||||
|
|
||||||
addstatement(loopstatement,loopvar);
|
|
||||||
|
|
||||||
arrayindex:=ctemprefnode.create(loopvar);
|
|
||||||
|
|
||||||
loopbody:=internalstatements(loopbodystatement);
|
|
||||||
// for-in loop variable := array_expression[index]
|
|
||||||
if assigned(arrayvar) then
|
|
||||||
addstatement(loopbodystatement,
|
|
||||||
cassignmentnode.create(hloopvar,cvecnode.create(ctemprefnode.create(arrayvar),arrayindex)))
|
|
||||||
else
|
|
||||||
addstatement(loopbodystatement,
|
|
||||||
cassignmentnode.create(hloopvar,cvecnode.create(expression.getcopy,arrayindex)));
|
|
||||||
|
|
||||||
{ add the actual statement to the loop }
|
|
||||||
addstatement(loopbodystatement,hloopbody);
|
|
||||||
|
|
||||||
forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
|
||||||
lowbound,
|
|
||||||
highbound,
|
|
||||||
loopbody,
|
|
||||||
false);
|
|
||||||
|
|
||||||
addstatement(loopstatement,forloopnode);
|
|
||||||
{ free the loop counter }
|
|
||||||
addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
|
||||||
{ free the temp variable for expression if needed }
|
|
||||||
if arrayvar<>nil then
|
|
||||||
addstatement(loopstatement,ctempdeletenode.create(arrayvar));
|
|
||||||
end;
|
|
||||||
|
|
||||||
function create_set_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
||||||
var
|
|
||||||
loopstatement, loopbodystatement: tstatementnode;
|
|
||||||
loopvar, setvar: ttempcreatenode;
|
|
||||||
loopbody, forloopnode: tnode;
|
|
||||||
begin
|
|
||||||
// first check is set is empty and if it so then skip other processing
|
|
||||||
if not Assigned(tsetdef(expr.resultdef).elementdef) then
|
|
||||||
begin
|
|
||||||
result:=cnothingnode.create;
|
|
||||||
// free unused nodes
|
|
||||||
hloopvar.free;
|
|
||||||
hloopbody.free;
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
{ result is a block of statements }
|
|
||||||
result:=internalstatements(loopstatement);
|
|
||||||
|
|
||||||
{ create a temp variable for expression }
|
|
||||||
setvar := ctempcreatenode.create(
|
|
||||||
expr.resultdef,
|
|
||||||
expr.resultdef.size,
|
|
||||||
tt_persistent,true);
|
|
||||||
|
|
||||||
addstatement(loopstatement,setvar);
|
|
||||||
addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(setvar),expr.getcopy));
|
|
||||||
|
|
||||||
{ create a loop counter }
|
|
||||||
loopvar := ctempcreatenode.create(
|
|
||||||
tsetdef(expr.resultdef).elementdef,
|
|
||||||
tsetdef(expr.resultdef).elementdef.size,
|
|
||||||
tt_persistent,true);
|
|
||||||
|
|
||||||
addstatement(loopstatement,loopvar);
|
|
||||||
|
|
||||||
// if loopvar in set then
|
|
||||||
// begin
|
|
||||||
// hloopvar := loopvar
|
|
||||||
// for-in loop body
|
|
||||||
// end
|
|
||||||
|
|
||||||
loopbody:=cifnode.create(
|
|
||||||
cinnode.create(ctemprefnode.create(loopvar),ctemprefnode.create(setvar)),
|
|
||||||
internalstatements(loopbodystatement),
|
|
||||||
nil
|
|
||||||
);
|
|
||||||
|
|
||||||
addstatement(loopbodystatement,cassignmentnode.create(hloopvar,ctemprefnode.create(loopvar)));
|
|
||||||
{ add the actual statement to the loop }
|
|
||||||
addstatement(loopbodystatement,hloopbody);
|
|
||||||
|
|
||||||
forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
|
||||||
cinlinenode.create(in_low_x,false,ctemprefnode.create(setvar)),
|
|
||||||
cinlinenode.create(in_high_x,false,ctemprefnode.create(setvar)),
|
|
||||||
loopbody,
|
|
||||||
false);
|
|
||||||
|
|
||||||
addstatement(loopstatement,forloopnode);
|
|
||||||
{ free the loop counter }
|
|
||||||
addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
|
||||||
{ free the temp variable for expression }
|
|
||||||
addstatement(loopstatement,ctempdeletenode.create(setvar));
|
|
||||||
end;
|
|
||||||
|
|
||||||
function create_enumerator_for_in_loop(hloopvar, hloopbody, expr: tnode;
|
|
||||||
enumerator_get, enumerator_move: tprocdef; enumerator_current: tpropertysym): tnode;
|
|
||||||
var
|
|
||||||
loopstatement, loopbodystatement: tstatementnode;
|
|
||||||
enumvar: ttempcreatenode;
|
|
||||||
loopbody, whileloopnode,
|
|
||||||
enum_get, enum_move, enum_current, enum_get_params: tnode;
|
|
||||||
propaccesslist: tpropaccesslist;
|
|
||||||
enumerator_is_class: boolean;
|
|
||||||
enumerator_destructor: tprocdef;
|
|
||||||
begin
|
|
||||||
{ result is a block of statements }
|
|
||||||
result:=internalstatements(loopstatement);
|
|
||||||
|
|
||||||
enumerator_is_class := is_class(enumerator_get.returndef);
|
|
||||||
|
|
||||||
{ create a temp variable for enumerator }
|
|
||||||
enumvar := ctempcreatenode.create(
|
|
||||||
enumerator_get.returndef,
|
|
||||||
enumerator_get.returndef.size,
|
|
||||||
tt_persistent,true);
|
|
||||||
|
|
||||||
addstatement(loopstatement,enumvar);
|
|
||||||
|
|
||||||
if enumerator_get.proctypeoption=potype_operator then
|
|
||||||
begin
|
|
||||||
enum_get_params:=ccallparanode.create(expr.getcopy,nil);
|
|
||||||
enum_get:=ccallnode.create(enum_get_params, tprocsym(enumerator_get.procsym), nil, nil, []);
|
|
||||||
tcallnode(enum_get).procdefinition:=enumerator_get;
|
|
||||||
addsymref(enumerator_get.procsym);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
enum_get:=ccallnode.create(nil, tprocsym(enumerator_get.procsym), enumerator_get.owner, expr.getcopy, []);
|
|
||||||
|
|
||||||
addstatement(loopstatement,
|
|
||||||
cassignmentnode.create(
|
|
||||||
ctemprefnode.create(enumvar),
|
|
||||||
enum_get
|
|
||||||
));
|
|
||||||
|
|
||||||
loopbody:=internalstatements(loopbodystatement);
|
|
||||||
{ for-in loop variable := enumerator.current }
|
|
||||||
if getpropaccesslist(enumerator_current,palt_read,propaccesslist) then
|
|
||||||
begin
|
|
||||||
case propaccesslist.firstsym^.sym.typ of
|
|
||||||
fieldvarsym :
|
|
||||||
begin
|
|
||||||
{ generate access code }
|
|
||||||
enum_current:=ctemprefnode.create(enumvar);
|
|
||||||
propaccesslist_to_node(enum_current,enumerator_current.owner,propaccesslist);
|
|
||||||
include(enum_current.flags,nf_isproperty);
|
|
||||||
end;
|
|
||||||
procsym :
|
|
||||||
begin
|
|
||||||
{ generate the method call }
|
|
||||||
enum_current:=ccallnode.create(nil,tprocsym(propaccesslist.firstsym^.sym),enumerator_current.owner,ctemprefnode.create(enumvar),[]);
|
|
||||||
include(enum_current.flags,nf_isproperty);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
enum_current:=cerrornode.create;
|
|
||||||
Message(type_e_mismatch);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
enum_current:=cerrornode.create;
|
|
||||||
|
|
||||||
addstatement(loopbodystatement,
|
|
||||||
cassignmentnode.create(hloopvar, enum_current));
|
|
||||||
|
|
||||||
{ add the actual statement to the loop }
|
|
||||||
addstatement(loopbodystatement,hloopbody);
|
|
||||||
|
|
||||||
enum_move:=ccallnode.create(nil, tprocsym(enumerator_move.procsym), enumerator_move.owner, ctemprefnode.create(enumvar), []);
|
|
||||||
whileloopnode:=cwhilerepeatnode.create(enum_move,loopbody,true,false);
|
|
||||||
|
|
||||||
if enumerator_is_class then
|
|
||||||
begin
|
|
||||||
{ insert a try-finally and call the destructor for the enumerator in the finally section }
|
|
||||||
enumerator_destructor:=tobjectdef(enumerator_get.returndef).find_destructor;
|
|
||||||
if assigned(enumerator_destructor) then
|
|
||||||
begin
|
|
||||||
whileloopnode:=ctryfinallynode.create(
|
|
||||||
whileloopnode, // try node
|
|
||||||
ccallnode.create(nil,tprocsym(enumerator_destructor.procsym), // finally node
|
|
||||||
enumerator_destructor.procsym.owner,ctemprefnode.create(enumvar),[]));
|
|
||||||
end;
|
|
||||||
{ if getenumerator <> nil then do the loop }
|
|
||||||
whileloopnode:=cifnode.create(
|
|
||||||
caddnode.create(unequaln, ctemprefnode.create(enumvar), cnilnode.create),
|
|
||||||
whileloopnode,
|
|
||||||
nil
|
|
||||||
);
|
|
||||||
end;
|
|
||||||
|
|
||||||
addstatement(loopstatement, whileloopnode);
|
|
||||||
|
|
||||||
if is_object(enumerator_get.returndef) then
|
|
||||||
begin
|
|
||||||
// call the object destructor too
|
|
||||||
enumerator_destructor:=tobjectdef(enumerator_get.returndef).find_destructor;
|
|
||||||
if assigned(enumerator_destructor) then
|
|
||||||
begin
|
|
||||||
addstatement(loopstatement,
|
|
||||||
ccallnode.create(nil,tprocsym(enumerator_destructor.procsym),
|
|
||||||
enumerator_destructor.procsym.owner,ctemprefnode.create(enumvar),[]));
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ free the temp variable for enumerator }
|
|
||||||
addstatement(loopstatement,ctempdeletenode.create(enumvar));
|
|
||||||
end;
|
|
||||||
|
|
||||||
function create_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
||||||
var
|
|
||||||
pd, movenext: tprocdef;
|
|
||||||
current: tpropertysym;
|
|
||||||
storefilepos: tfileposinfo;
|
|
||||||
begin
|
|
||||||
storefilepos:=current_filepos;
|
|
||||||
current_filepos:=hloopvar.fileinfo;
|
|
||||||
if expr.nodetype=typen then
|
|
||||||
begin
|
|
||||||
if (expr.resultdef.typ=enumdef) and tenumdef(expr.resultdef).has_jumps then
|
|
||||||
begin
|
|
||||||
result:=cerrornode.create;
|
|
||||||
hloopvar.free;
|
|
||||||
hloopbody.free;
|
|
||||||
MessagePos1(expr.fileinfo,parser_e_for_in_loop_cannot_be_used_for_the_type,expr.resultdef.typename);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
result:=create_type_for_in_loop(hloopvar, hloopbody, expr);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
{ loop is made for an expression }
|
|
||||||
// search for operator first
|
|
||||||
pd:=search_enumerator_operator(expr.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 pd<>nil then
|
|
||||||
begin
|
|
||||||
// seach movenext and current symbols
|
|
||||||
movenext:=tobjectdef(pd.returndef).search_enumerator_move;
|
|
||||||
if movenext = nil then
|
|
||||||
begin
|
begin
|
||||||
result:=cerrornode.create;
|
result:=cfornode.create(hloopvar,
|
||||||
hloopvar.free;
|
cinlinenode.create(in_low_x,false,expr.getcopy),
|
||||||
hloopbody.free;
|
cinlinenode.create(in_high_x,false,expr.getcopy),
|
||||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.GetTypeName);
|
hloopbody,
|
||||||
end
|
false);
|
||||||
else
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function create_string_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||||
|
var
|
||||||
|
loopstatement, loopbodystatement: tstatementnode;
|
||||||
|
loopvar, stringvar: ttempcreatenode;
|
||||||
|
stringindex, loopbody, forloopnode: tnode;
|
||||||
begin
|
begin
|
||||||
current:=tpropertysym(tobjectdef(pd.returndef).search_enumerator_current);
|
{ result is a block of statements }
|
||||||
if current = nil then
|
result:=internalstatements(loopstatement);
|
||||||
begin
|
|
||||||
result:=cerrornode.create;
|
{ create a temp variable for expression }
|
||||||
hloopvar.free;
|
stringvar := ctempcreatenode.create(
|
||||||
hloopbody.free;
|
expr.resultdef,
|
||||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.GetTypeName);
|
expr.resultdef.size,
|
||||||
end
|
tt_persistent,true);
|
||||||
|
|
||||||
|
addstatement(loopstatement,stringvar);
|
||||||
|
addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(stringvar),expr.getcopy));
|
||||||
|
|
||||||
|
{ create a loop counter: signed integer with size of string length }
|
||||||
|
loopvar := ctempcreatenode.create(
|
||||||
|
sinttype,
|
||||||
|
sinttype.size,
|
||||||
|
tt_persistent,true);
|
||||||
|
|
||||||
|
addstatement(loopstatement,loopvar);
|
||||||
|
|
||||||
|
stringindex:=ctemprefnode.create(loopvar);
|
||||||
|
|
||||||
|
loopbody:=internalstatements(loopbodystatement);
|
||||||
|
// for-in loop variable := string_expression[index]
|
||||||
|
addstatement(loopbodystatement,
|
||||||
|
cassignmentnode.create(hloopvar, cvecnode.create(ctemprefnode.create(stringvar),stringindex)));
|
||||||
|
|
||||||
|
{ add the actual statement to the loop }
|
||||||
|
addstatement(loopbodystatement,hloopbody);
|
||||||
|
|
||||||
|
forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
||||||
|
genintconstnode(1),
|
||||||
|
cinlinenode.create(in_length_x,false,ctemprefnode.create(stringvar)),
|
||||||
|
loopbody,
|
||||||
|
false);
|
||||||
|
|
||||||
|
addstatement(loopstatement,forloopnode);
|
||||||
|
{ free the loop counter }
|
||||||
|
addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
||||||
|
{ free the temp variable for expression }
|
||||||
|
addstatement(loopstatement,ctempdeletenode.create(stringvar));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function create_array_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||||
|
var
|
||||||
|
loopstatement, loopbodystatement: tstatementnode;
|
||||||
|
loopvar, arrayvar: ttempcreatenode;
|
||||||
|
arrayindex, lowbound, highbound, loopbody, forloopnode, expression: tnode;
|
||||||
|
is_string: boolean;
|
||||||
|
tmpdef, convertdef: tdef;
|
||||||
|
elementcount: aword;
|
||||||
|
begin
|
||||||
|
expression := expr;
|
||||||
|
|
||||||
|
{ result is a block of statements }
|
||||||
|
result:=internalstatements(loopstatement);
|
||||||
|
|
||||||
|
is_string:=ado_IsConstString in tarraydef(expr.resultdef).arrayoptions;
|
||||||
|
|
||||||
|
// if array element type <> loovar type then create a conversion if possible
|
||||||
|
if compare_defs(tarraydef(expression.resultdef).elementdef,hloopvar.resultdef,nothingn)=te_incompatible then
|
||||||
|
begin
|
||||||
|
tmpdef:=expression.resultdef;
|
||||||
|
elementcount:=1;
|
||||||
|
while assigned(tmpdef) and (tmpdef.typ=arraydef) and
|
||||||
|
(tarraydef(tmpdef).arrayoptions = []) and
|
||||||
|
(compare_defs(tarraydef(tmpdef).elementdef,hloopvar.resultdef,nothingn)=te_incompatible) do
|
||||||
|
begin
|
||||||
|
elementcount:=elementcount*tarraydef(tmpdef).elecount;
|
||||||
|
tmpdef:=tarraydef(tmpdef).elementdef;
|
||||||
|
end;
|
||||||
|
if assigned(tmpdef) and (tmpdef.typ=arraydef) and (tarraydef(tmpdef).arrayoptions = []) then
|
||||||
|
begin
|
||||||
|
elementcount:=elementcount*tarraydef(tmpdef).elecount;
|
||||||
|
convertdef:=tarraydef.create(0,elementcount-1,s32inttype);
|
||||||
|
tarraydef(convertdef).elementdef:=tarraydef(tmpdef).elementdef;
|
||||||
|
expression:=expr.getcopy;
|
||||||
|
expression:=ctypeconvnode.create_internal(expression,convertdef);
|
||||||
|
typecheckpass(expression);
|
||||||
|
addstatement(loopstatement,expression);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (node_complexity(expression) > 1) and not is_open_array(expression.resultdef) then
|
||||||
|
begin
|
||||||
|
{ create a temp variable for expression }
|
||||||
|
arrayvar := ctempcreatenode.create(
|
||||||
|
expression.resultdef,
|
||||||
|
expression.resultdef.size,
|
||||||
|
tt_persistent,true);
|
||||||
|
|
||||||
|
if is_string then
|
||||||
|
begin
|
||||||
|
lowbound:=genintconstnode(1);
|
||||||
|
highbound:=cinlinenode.create(in_length_x,false,ctemprefnode.create(arrayvar))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
lowbound:=cinlinenode.create(in_low_x,false,ctemprefnode.create(arrayvar));
|
||||||
|
highbound:=cinlinenode.create(in_high_x,false,ctemprefnode.create(arrayvar));
|
||||||
|
end;
|
||||||
|
|
||||||
|
addstatement(loopstatement,arrayvar);
|
||||||
|
addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(arrayvar),expression.getcopy));
|
||||||
|
end
|
||||||
else
|
else
|
||||||
result:=create_enumerator_for_in_loop(hloopvar, hloopbody, expr, pd, movenext, current);
|
begin
|
||||||
|
arrayvar:=nil;
|
||||||
|
if is_string then
|
||||||
|
begin
|
||||||
|
lowbound:=genintconstnode(1);
|
||||||
|
highbound:=cinlinenode.create(in_length_x,false,expression.getcopy);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
lowbound:=cinlinenode.create(in_low_x,false,expression.getcopy);
|
||||||
|
highbound:=cinlinenode.create(in_high_x,false,expression.getcopy);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ create a loop counter }
|
||||||
|
loopvar := ctempcreatenode.create(
|
||||||
|
tarraydef(expression.resultdef).rangedef,
|
||||||
|
tarraydef(expression.resultdef).rangedef.size,
|
||||||
|
tt_persistent,true);
|
||||||
|
|
||||||
|
addstatement(loopstatement,loopvar);
|
||||||
|
|
||||||
|
arrayindex:=ctemprefnode.create(loopvar);
|
||||||
|
|
||||||
|
loopbody:=internalstatements(loopbodystatement);
|
||||||
|
// for-in loop variable := array_expression[index]
|
||||||
|
if assigned(arrayvar) then
|
||||||
|
addstatement(loopbodystatement,
|
||||||
|
cassignmentnode.create(hloopvar,cvecnode.create(ctemprefnode.create(arrayvar),arrayindex)))
|
||||||
|
else
|
||||||
|
addstatement(loopbodystatement,
|
||||||
|
cassignmentnode.create(hloopvar,cvecnode.create(expression.getcopy,arrayindex)));
|
||||||
|
|
||||||
|
{ add the actual statement to the loop }
|
||||||
|
addstatement(loopbodystatement,hloopbody);
|
||||||
|
|
||||||
|
forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
||||||
|
lowbound,
|
||||||
|
highbound,
|
||||||
|
loopbody,
|
||||||
|
false);
|
||||||
|
|
||||||
|
addstatement(loopstatement,forloopnode);
|
||||||
|
{ free the loop counter }
|
||||||
|
addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
||||||
|
{ free the temp variable for expression if needed }
|
||||||
|
if arrayvar<>nil then
|
||||||
|
addstatement(loopstatement,ctempdeletenode.create(arrayvar));
|
||||||
end;
|
end;
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
function create_set_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||||
case expr.resultdef.typ of
|
var
|
||||||
stringdef: result:=create_string_for_in_loop(hloopvar, hloopbody, expr);
|
loopstatement, loopbodystatement: tstatementnode;
|
||||||
arraydef: result:=create_array_for_in_loop(hloopvar, hloopbody, expr);
|
loopvar, setvar: ttempcreatenode;
|
||||||
setdef: result:=create_set_for_in_loop(hloopvar, hloopbody, expr);
|
loopbody, forloopnode: tnode;
|
||||||
else
|
begin
|
||||||
begin
|
// first check is set is empty and if it so then skip other processing
|
||||||
result:=cerrornode.create;
|
if not Assigned(tsetdef(expr.resultdef).elementdef) then
|
||||||
hloopvar.free;
|
begin
|
||||||
hloopbody.free;
|
result:=cnothingnode.create;
|
||||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.GetTypeName);
|
// free unused nodes
|
||||||
end;
|
hloopvar.free;
|
||||||
|
hloopbody.free;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
{ result is a block of statements }
|
||||||
|
result:=internalstatements(loopstatement);
|
||||||
|
|
||||||
|
{ create a temp variable for expression }
|
||||||
|
setvar := ctempcreatenode.create(
|
||||||
|
expr.resultdef,
|
||||||
|
expr.resultdef.size,
|
||||||
|
tt_persistent,true);
|
||||||
|
|
||||||
|
addstatement(loopstatement,setvar);
|
||||||
|
addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(setvar),expr.getcopy));
|
||||||
|
|
||||||
|
{ create a loop counter }
|
||||||
|
loopvar := ctempcreatenode.create(
|
||||||
|
tsetdef(expr.resultdef).elementdef,
|
||||||
|
tsetdef(expr.resultdef).elementdef.size,
|
||||||
|
tt_persistent,true);
|
||||||
|
|
||||||
|
addstatement(loopstatement,loopvar);
|
||||||
|
|
||||||
|
// if loopvar in set then
|
||||||
|
// begin
|
||||||
|
// hloopvar := loopvar
|
||||||
|
// for-in loop body
|
||||||
|
// end
|
||||||
|
|
||||||
|
loopbody:=cifnode.create(
|
||||||
|
cinnode.create(ctemprefnode.create(loopvar),ctemprefnode.create(setvar)),
|
||||||
|
internalstatements(loopbodystatement),
|
||||||
|
nil);
|
||||||
|
|
||||||
|
addstatement(loopbodystatement,cassignmentnode.create(hloopvar,ctemprefnode.create(loopvar)));
|
||||||
|
{ add the actual statement to the loop }
|
||||||
|
addstatement(loopbodystatement,hloopbody);
|
||||||
|
|
||||||
|
forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
||||||
|
cinlinenode.create(in_low_x,false,ctemprefnode.create(setvar)),
|
||||||
|
cinlinenode.create(in_high_x,false,ctemprefnode.create(setvar)),
|
||||||
|
loopbody,
|
||||||
|
false);
|
||||||
|
|
||||||
|
addstatement(loopstatement,forloopnode);
|
||||||
|
{ free the loop counter }
|
||||||
|
addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
||||||
|
{ free the temp variable for expression }
|
||||||
|
addstatement(loopstatement,ctempdeletenode.create(setvar));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function create_enumerator_for_in_loop(hloopvar, hloopbody, expr: tnode;
|
||||||
|
enumerator_get, enumerator_move: tprocdef; enumerator_current: tpropertysym): tnode;
|
||||||
|
var
|
||||||
|
loopstatement, loopbodystatement: tstatementnode;
|
||||||
|
enumvar: ttempcreatenode;
|
||||||
|
loopbody, whileloopnode,
|
||||||
|
enum_get, enum_move, enum_current, enum_get_params: tnode;
|
||||||
|
propaccesslist: tpropaccesslist;
|
||||||
|
enumerator_is_class: boolean;
|
||||||
|
enumerator_destructor: tprocdef;
|
||||||
|
begin
|
||||||
|
{ result is a block of statements }
|
||||||
|
result:=internalstatements(loopstatement);
|
||||||
|
|
||||||
|
enumerator_is_class := is_class(enumerator_get.returndef);
|
||||||
|
|
||||||
|
{ create a temp variable for enumerator }
|
||||||
|
enumvar := ctempcreatenode.create(
|
||||||
|
enumerator_get.returndef,
|
||||||
|
enumerator_get.returndef.size,
|
||||||
|
tt_persistent,true);
|
||||||
|
|
||||||
|
addstatement(loopstatement,enumvar);
|
||||||
|
|
||||||
|
if enumerator_get.proctypeoption=potype_operator then
|
||||||
|
begin
|
||||||
|
enum_get_params:=ccallparanode.create(expr.getcopy,nil);
|
||||||
|
enum_get:=ccallnode.create(enum_get_params, tprocsym(enumerator_get.procsym), nil, nil, []);
|
||||||
|
tcallnode(enum_get).procdefinition:=enumerator_get;
|
||||||
|
addsymref(enumerator_get.procsym);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
enum_get:=ccallnode.create(nil, tprocsym(enumerator_get.procsym), enumerator_get.owner, expr.getcopy, []);
|
||||||
|
|
||||||
|
addstatement(loopstatement,
|
||||||
|
cassignmentnode.create(
|
||||||
|
ctemprefnode.create(enumvar),
|
||||||
|
enum_get
|
||||||
|
));
|
||||||
|
|
||||||
|
loopbody:=internalstatements(loopbodystatement);
|
||||||
|
{ for-in loop variable := enumerator.current }
|
||||||
|
if getpropaccesslist(enumerator_current,palt_read,propaccesslist) then
|
||||||
|
begin
|
||||||
|
case propaccesslist.firstsym^.sym.typ of
|
||||||
|
fieldvarsym :
|
||||||
|
begin
|
||||||
|
{ generate access code }
|
||||||
|
enum_current:=ctemprefnode.create(enumvar);
|
||||||
|
propaccesslist_to_node(enum_current,enumerator_current.owner,propaccesslist);
|
||||||
|
include(enum_current.flags,nf_isproperty);
|
||||||
|
end;
|
||||||
|
procsym :
|
||||||
|
begin
|
||||||
|
{ generate the method call }
|
||||||
|
enum_current:=ccallnode.create(nil,tprocsym(propaccesslist.firstsym^.sym),enumerator_current.owner,ctemprefnode.create(enumvar),[]);
|
||||||
|
include(enum_current.flags,nf_isproperty);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
enum_current:=cerrornode.create;
|
||||||
|
Message(type_e_mismatch);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
enum_current:=cerrornode.create;
|
||||||
|
|
||||||
|
addstatement(loopbodystatement,
|
||||||
|
cassignmentnode.create(hloopvar, enum_current));
|
||||||
|
|
||||||
|
{ add the actual statement to the loop }
|
||||||
|
addstatement(loopbodystatement,hloopbody);
|
||||||
|
|
||||||
|
enum_move:=ccallnode.create(nil, tprocsym(enumerator_move.procsym), enumerator_move.owner, ctemprefnode.create(enumvar), []);
|
||||||
|
whileloopnode:=cwhilerepeatnode.create(enum_move,loopbody,true,false);
|
||||||
|
|
||||||
|
if enumerator_is_class then
|
||||||
|
begin
|
||||||
|
{ insert a try-finally and call the destructor for the enumerator in the finally section }
|
||||||
|
enumerator_destructor:=tobjectdef(enumerator_get.returndef).find_destructor;
|
||||||
|
if assigned(enumerator_destructor) then
|
||||||
|
begin
|
||||||
|
whileloopnode:=ctryfinallynode.create(
|
||||||
|
whileloopnode, // try node
|
||||||
|
ccallnode.create(nil,tprocsym(enumerator_destructor.procsym), // finally node
|
||||||
|
enumerator_destructor.procsym.owner,ctemprefnode.create(enumvar),[]));
|
||||||
|
end;
|
||||||
|
{ if getenumerator <> nil then do the loop }
|
||||||
|
whileloopnode:=cifnode.create(
|
||||||
|
caddnode.create(unequaln, ctemprefnode.create(enumvar), cnilnode.create),
|
||||||
|
whileloopnode,
|
||||||
|
nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
addstatement(loopstatement, whileloopnode);
|
||||||
|
|
||||||
|
if is_object(enumerator_get.returndef) then
|
||||||
|
begin
|
||||||
|
// call the object destructor too
|
||||||
|
enumerator_destructor:=tobjectdef(enumerator_get.returndef).find_destructor;
|
||||||
|
if assigned(enumerator_destructor) then
|
||||||
|
begin
|
||||||
|
addstatement(loopstatement,
|
||||||
|
ccallnode.create(nil,tprocsym(enumerator_destructor.procsym),
|
||||||
|
enumerator_destructor.procsym.owner,ctemprefnode.create(enumvar),[]));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ free the temp variable for enumerator }
|
||||||
|
addstatement(loopstatement,ctempdeletenode.create(enumvar));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function create_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||||
|
var
|
||||||
|
pd, movenext: tprocdef;
|
||||||
|
current: tpropertysym;
|
||||||
|
storefilepos: tfileposinfo;
|
||||||
|
begin
|
||||||
|
storefilepos:=current_filepos;
|
||||||
|
current_filepos:=hloopvar.fileinfo;
|
||||||
|
if expr.nodetype=typen then
|
||||||
|
begin
|
||||||
|
if (expr.resultdef.typ=enumdef) and tenumdef(expr.resultdef).has_jumps then
|
||||||
|
begin
|
||||||
|
result:=cerrornode.create;
|
||||||
|
hloopvar.free;
|
||||||
|
hloopbody.free;
|
||||||
|
MessagePos1(expr.fileinfo,parser_e_for_in_loop_cannot_be_used_for_the_type,expr.resultdef.typename);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
result:=create_type_for_in_loop(hloopvar, hloopbody, expr);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{ loop is made for an expression }
|
||||||
|
// search for operator first
|
||||||
|
pd:=search_enumerator_operator(expr.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 pd<>nil then
|
||||||
|
begin
|
||||||
|
// seach movenext and current symbols
|
||||||
|
movenext:=tobjectdef(pd.returndef).search_enumerator_move;
|
||||||
|
if movenext = nil then
|
||||||
|
begin
|
||||||
|
result:=cerrornode.create;
|
||||||
|
hloopvar.free;
|
||||||
|
hloopbody.free;
|
||||||
|
MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.GetTypeName);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
current:=tpropertysym(tobjectdef(pd.returndef).search_enumerator_current);
|
||||||
|
if current = nil then
|
||||||
|
begin
|
||||||
|
result:=cerrornode.create;
|
||||||
|
hloopvar.free;
|
||||||
|
hloopbody.free;
|
||||||
|
MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.GetTypeName);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
result:=create_enumerator_for_in_loop(hloopvar, hloopbody, expr, pd, movenext, current);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
case expr.resultdef.typ of
|
||||||
|
stringdef: result:=create_string_for_in_loop(hloopvar, hloopbody, expr);
|
||||||
|
arraydef: result:=create_array_for_in_loop(hloopvar, hloopbody, expr);
|
||||||
|
setdef: result:=create_set_for_in_loop(hloopvar, hloopbody, expr);
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
result:=cerrornode.create;
|
||||||
|
hloopvar.free;
|
||||||
|
hloopbody.free;
|
||||||
|
MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.GetTypeName);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
current_filepos:=storefilepos;
|
||||||
end;
|
end;
|
||||||
end;
|
|
||||||
end;
|
|
||||||
current_filepos:=storefilepos;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{****************************************************************************
|
{****************************************************************************
|
||||||
TLOOPNODE
|
TLOOPNODE
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user