Przeglądaj źródła

* fixed indentation of for-in code

git-svn-id: trunk@15449 -
Jonas Maebe 15 lat temu
rodzic
commit
df525d98a3
1 zmienionych plików z 394 dodań i 391 usunięć
  1. 394 391
      compiler/nflw.pas

+ 394 - 391
compiler/nflw.pas

@@ -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