|
@@ -216,17 +216,22 @@ interface
|
|
|
ctryfinallynode : ttryfinallynodeclass;
|
|
|
connode : tonnodeclass;
|
|
|
|
|
|
+// for-in loop helpers
|
|
|
+function create_type_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
|
+function create_string_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
|
+function create_array_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
|
+function create_set_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
|
+function create_enumerator_for_in_loop(hloopvar, hloopbody, expr: tnode;
|
|
|
+ enumerator_get, enumerator_move: tprocdef; enumerator_current: tpropertysym): tnode;
|
|
|
+function create_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
|
|
|
|
|
implementation
|
|
|
|
|
|
uses
|
|
|
globtype,systems,constexp,
|
|
|
cutils,verbose,globals,
|
|
|
- symconst,paramgr,defcmp,defutil,htypechk,pass_1,
|
|
|
- ncal,nadd,ncon,nmem,nld,ncnv,nbas,cgobj,nutils,
|
|
|
- {$ifdef prefetchnext}
|
|
|
- ninl,
|
|
|
- {$endif prefetchnext}
|
|
|
+ symconst,symtable,paramgr,defcmp,defutil,htypechk,pass_1,
|
|
|
+ ncal,nadd,ncon,nmem,nld,ncnv,nbas,cgobj,nutils,ninl,nset,
|
|
|
{$ifdef state_tracking}
|
|
|
nstate,
|
|
|
{$endif}
|
|
@@ -234,6 +239,353 @@ implementation
|
|
|
;
|
|
|
|
|
|
|
|
|
+// for-in loop helpers
|
|
|
+
|
|
|
+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: tnode;
|
|
|
+begin
|
|
|
+ { result is a block of statements }
|
|
|
+ result:=internalstatements(loopstatement);
|
|
|
+
|
|
|
+ if (node_complexity(expr) > 1) and not is_open_array(expr.resultdef) then
|
|
|
+ begin
|
|
|
+ { create a temp variable for expression }
|
|
|
+ arrayvar := ctempcreatenode.create(
|
|
|
+ expr.resultdef,
|
|
|
+ expr.resultdef.size,
|
|
|
+ tt_persistent,true);
|
|
|
+
|
|
|
+ lowbound:=cinlinenode.create(in_low_x,false,ctemprefnode.create(arrayvar));
|
|
|
+ highbound:=cinlinenode.create(in_high_x,false,ctemprefnode.create(arrayvar));
|
|
|
+
|
|
|
+ addstatement(loopstatement,arrayvar);
|
|
|
+ addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(arrayvar),expr.getcopy));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ arrayvar:=nil;
|
|
|
+ lowbound:=cinlinenode.create(in_low_x,false,expr.getcopy);
|
|
|
+ highbound:=cinlinenode.create(in_high_x,false,expr.getcopy);
|
|
|
+ end;
|
|
|
+
|
|
|
+ { create a loop counter }
|
|
|
+ loopvar := ctempcreatenode.create(
|
|
|
+ tarraydef(expr.resultdef).rangedef,
|
|
|
+ tarraydef(expr.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(expr.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
|
|
|
+ { 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).Finddestructor;
|
|
|
+ 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).Finddestructor;
|
|
|
+ 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;
|
|
|
+begin
|
|
|
+ if expr.nodetype=typen then
|
|
|
+ result:=create_type_for_in_loop(hloopvar, hloopbody, expr)
|
|
|
+ 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;
|
|
|
+ Message1(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;
|
|
|
+ Message1(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;
|
|
|
+ Message1(sym_e_no_enumerator,expr.resultdef.GetTypeName);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
{****************************************************************************
|
|
|
TLOOPNODE
|
|
|
*****************************************************************************}
|