|
@@ -241,426 +241,429 @@ 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_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);
|
|
|
+ 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);
|
|
|
|
|
|
- addstatement(loopstatement,stringvar);
|
|
|
- addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(stringvar),expr.getcopy));
|
|
|
+ { create a temp variable for expression }
|
|
|
+ stringvar := ctempcreatenode.create(
|
|
|
+ expr.resultdef,
|
|
|
+ expr.resultdef.size,
|
|
|
+ tt_persistent,true);
|
|
|
|
|
|
- { create a loop counter: signed integer with size of string length }
|
|
|
- loopvar := ctempcreatenode.create(
|
|
|
- sinttype,
|
|
|
- sinttype.size,
|
|
|
- tt_persistent,true);
|
|
|
+ addstatement(loopstatement,stringvar);
|
|
|
+ addstatement(loopstatement,cassignmentnode.create(ctemprefnode.create(stringvar),expr.getcopy));
|
|
|
|
|
|
- addstatement(loopstatement,loopvar);
|
|
|
+ { create a loop counter: signed integer with size of string length }
|
|
|
+ loopvar := ctempcreatenode.create(
|
|
|
+ sinttype,
|
|
|
+ sinttype.size,
|
|
|
+ tt_persistent,true);
|
|
|
|
|
|
- stringindex:=ctemprefnode.create(loopvar);
|
|
|
+ addstatement(loopstatement,loopvar);
|
|
|
|
|
|
- loopbody:=internalstatements(loopbodystatement);
|
|
|
- // for-in loop variable := string_expression[index]
|
|
|
- addstatement(loopbodystatement,
|
|
|
- cassignmentnode.create(hloopvar, cvecnode.create(ctemprefnode.create(stringvar),stringindex)));
|
|
|
+ stringindex:=ctemprefnode.create(loopvar);
|
|
|
|
|
|
- { add the actual statement to the loop }
|
|
|
- addstatement(loopbodystatement,hloopbody);
|
|
|
+ loopbody:=internalstatements(loopbodystatement);
|
|
|
+ // for-in loop variable := string_expression[index]
|
|
|
+ addstatement(loopbodystatement,
|
|
|
+ cassignmentnode.create(hloopvar, cvecnode.create(ctemprefnode.create(stringvar),stringindex)));
|
|
|
|
|
|
- forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
|
|
- genintconstnode(1),
|
|
|
- cinlinenode.create(in_length_x,false,ctemprefnode.create(stringvar)),
|
|
|
- loopbody,
|
|
|
- false);
|
|
|
+ { add the actual statement to the loop }
|
|
|
+ addstatement(loopbodystatement,hloopbody);
|
|
|
|
|
|
- addstatement(loopstatement,forloopnode);
|
|
|
- { free the loop counter }
|
|
|
- addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
|
|
- { free the temp variable for expression }
|
|
|
- addstatement(loopstatement,ctempdeletenode.create(stringvar));
|
|
|
-end;
|
|
|
+ forloopnode:=cfornode.create(ctemprefnode.create(loopvar),
|
|
|
+ genintconstnode(1),
|
|
|
+ cinlinenode.create(in_length_x,false,ctemprefnode.create(stringvar)),
|
|
|
+ loopbody,
|
|
|
+ false);
|
|
|
|
|
|
-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;
|
|
|
+ addstatement(loopstatement,forloopnode);
|
|
|
+ { free the loop counter }
|
|
|
+ addstatement(loopstatement,ctempdeletenode.create(loopvar));
|
|
|
+ { free the temp variable for expression }
|
|
|
+ addstatement(loopstatement,ctempdeletenode.create(stringvar));
|
|
|
+ end;
|
|
|
|
|
|
- { result is a block of statements }
|
|
|
- result:=internalstatements(loopstatement);
|
|
|
|
|
|
- is_string:=ado_IsConstString in tarraydef(expr.resultdef).arrayoptions;
|
|
|
+ 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;
|
|
|
|
|
|
- // 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;
|
|
|
+ { result is a block of statements }
|
|
|
+ result:=internalstatements(loopstatement);
|
|
|
|
|
|
- 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);
|
|
|
+ is_string:=ado_IsConstString in tarraydef(expr.resultdef).arrayoptions;
|
|
|
|
|
|
- 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;
|
|
|
+ // 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;
|
|
|
|
|
|
- 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;
|
|
|
+ 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);
|
|
|
|
|
|
-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;
|
|
|
+ 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;
|
|
|
|
|
|
-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(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;
|
|
|
|
|
|
- addstatement(loopbodystatement,
|
|
|
- cassignmentnode.create(hloopvar, enum_current));
|
|
|
+ { create a loop counter }
|
|
|
+ loopvar := ctempcreatenode.create(
|
|
|
+ tarraydef(expression.resultdef).rangedef,
|
|
|
+ tarraydef(expression.resultdef).rangedef.size,
|
|
|
+ tt_persistent,true);
|
|
|
|
|
|
- { add the actual statement to the loop }
|
|
|
- addstatement(loopbodystatement,hloopbody);
|
|
|
+ addstatement(loopstatement,loopvar);
|
|
|
|
|
|
- enum_move:=ccallnode.create(nil, tprocsym(enumerator_move.procsym), enumerator_move.owner, ctemprefnode.create(enumvar), []);
|
|
|
- whileloopnode:=cwhilerepeatnode.create(enum_move,loopbody,true,false);
|
|
|
+ arrayindex:=ctemprefnode.create(loopvar);
|
|
|
|
|
|
- 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;
|
|
|
+ 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)));
|
|
|
|
|
|
- { free the temp variable for enumerator }
|
|
|
- addstatement(loopstatement,ctempdeletenode.create(enumvar));
|
|
|
-end;
|
|
|
+ { add the actual statement to the loop }
|
|
|
+ addstatement(loopbodystatement,hloopbody);
|
|
|
|
|
|
-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
|
|
|
+ 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
|
|
|
- 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
|
|
|
+ // 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
|
|
|
- result:=create_enumerator_for_in_loop(hloopvar, hloopbody, expr, pd, movenext, current);
|
|
|
+ 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;
|
|
|
- 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;
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
- current_filepos:=storefilepos;
|
|
|
-end;
|
|
|
|
|
|
{****************************************************************************
|
|
|
TLOOPNODE
|