mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 16:11:33 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1839 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1839 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     Copyright (c) 1998-2002 by Florian Klaempfl
 | |
| 
 | |
|     Type checking and register allocation for nodes that influence
 | |
|     the flow
 | |
| 
 | |
|     This program is free software; you can redistribute it and/or modify
 | |
|     it under the terms of the GNU General Public License as published by
 | |
|     the Free Software Foundation; either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU General Public License
 | |
|     along with this program; if not, write to the Free Software
 | |
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
| 
 | |
|  ****************************************************************************
 | |
| }
 | |
| unit nflw;
 | |
| 
 | |
| {$i fpcdefs.inc}
 | |
| 
 | |
| interface
 | |
| 
 | |
|     uses
 | |
|       cclasses,
 | |
|       node,cpubase,
 | |
|       symnot,
 | |
|       symtype,symbase,symdef,symsym,
 | |
|       optloop;
 | |
| 
 | |
|     type
 | |
|        { flags used by loop nodes }
 | |
|        tloopflag = (
 | |
|          { set if it is a for ... downto ... do loop }
 | |
|          lnf_backward,
 | |
|          { Do we need to parse childs to set var state? }
 | |
|          lnf_varstate,
 | |
|          { Do a test at the begin of the loop?}
 | |
|          lnf_testatbegin,
 | |
|          { Negate the loop test? }
 | |
|          lnf_checknegate,
 | |
|          { Should the value of the loop variable on exit be correct. }
 | |
|          lnf_dont_mind_loopvar_on_exit);
 | |
|        tloopflags = set of tloopflag;
 | |
| 
 | |
|     const
 | |
|          { loop flags which must match to consider loop nodes equal regarding the flags }
 | |
|          loopflagsequal = [lnf_backward];
 | |
| 
 | |
|     type
 | |
|        tlabelnode = class;
 | |
| 
 | |
|        tloopnode = class(tbinarynode)
 | |
|           t1,t2 : tnode;
 | |
|           loopflags : tloopflags;
 | |
|           constructor create(tt : tnodetype;l,r,_t1,_t2 : tnode);virtual;
 | |
|           destructor destroy;override;
 | |
|           function dogetcopy : tnode;override;
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           procedure buildderefimpl;override;
 | |
|           procedure derefimpl;override;
 | |
|           procedure insertintolist(l : tnodelist);override;
 | |
|           procedure printnodetree(var t:text);override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|        end;
 | |
| 
 | |
|        twhilerepeatnode = class(tloopnode)
 | |
|           constructor create(l,r:Tnode;tab,cn:boolean);virtual;reintroduce;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
| {$ifdef state_tracking}
 | |
|           function track_state_pass(exec_known:boolean):boolean;override;
 | |
| {$endif}
 | |
|        end;
 | |
|        twhilerepeatnodeclass = class of twhilerepeatnode;
 | |
| 
 | |
|        tifnode = class(tloopnode)
 | |
|           constructor create(l,r,_t1 : tnode);virtual;reintroduce;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function simplify : tnode;override;
 | |
|          private
 | |
|           function internalsimplify(warn: boolean) : tnode;
 | |
|        end;
 | |
|        tifnodeclass = class of tifnode;
 | |
| 
 | |
|        tfornode = class(tloopnode)
 | |
|           { if count isn divisable by unrolls then
 | |
|             the for loop must jump to this label to get the correct
 | |
|             number of executions }
 | |
|           entrylabel : tnode;
 | |
|           loopvar_notid:cardinal;
 | |
|           constructor create(l,r,_t1,_t2 : tnode;back : boolean);virtual;reintroduce;
 | |
|           procedure loop_var_access(not_type:Tnotification_flag;symbol:Tsym);
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function simplify : tnode;override;
 | |
|        end;
 | |
|        tfornodeclass = class of tfornode;
 | |
| 
 | |
|        texitnode = class(tunarynode)
 | |
|           constructor create(l:tnode);virtual;
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|        end;
 | |
|        texitnodeclass = class of texitnode;
 | |
| 
 | |
|        tbreaknode = class(tnode)
 | |
|           constructor create;virtual;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|        end;
 | |
|        tbreaknodeclass = class of tbreaknode;
 | |
| 
 | |
|        tcontinuenode = class(tnode)
 | |
|           constructor create;virtual;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|        end;
 | |
|        tcontinuenodeclass = class of tcontinuenode;
 | |
| 
 | |
|        tgotonode = class(tnode)
 | |
|        private
 | |
|           labelnodeidx : longint;
 | |
|        public
 | |
|           labelsym : tlabelsym;
 | |
|           labelnode : tlabelnode;
 | |
|           exceptionblock : integer;
 | |
|           constructor create(p : tlabelsym);virtual;
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           procedure buildderefimpl;override;
 | |
|           procedure derefimpl;override;
 | |
|           procedure resolveppuidx;override;
 | |
|           function dogetcopy : tnode;override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|        end;
 | |
|        tgotonodeclass = class of tgotonode;
 | |
| 
 | |
|        tlabelnode = class(tunarynode)
 | |
|           exceptionblock : integer;
 | |
|           { when copying trees, this points to the newly created copy of a label }
 | |
|           copiedto : tlabelnode;
 | |
|           labsym : tlabelsym;
 | |
|           constructor create(l:tnode;alabsym:tlabelsym);virtual;
 | |
|           destructor destroy;override;
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           procedure buildderefimpl;override;
 | |
|           procedure derefimpl;override;
 | |
|           function dogetcopy : tnode;override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|        end;
 | |
|        tlabelnodeclass = class of tlabelnode;
 | |
| 
 | |
|        traisenode = class(ttertiarynode)
 | |
|           constructor create(l,taddr,tframe:tnode);virtual;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|        end;
 | |
|        traisenodeclass = class of traisenode;
 | |
| 
 | |
|        ttryexceptnode = class(tloopnode)
 | |
|           constructor create(l,r,_t1 : tnode);virtual;reintroduce;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|        end;
 | |
|        ttryexceptnodeclass = class of ttryexceptnode;
 | |
| 
 | |
|        ttryfinallynode = class(tloopnode)
 | |
|           implicitframe : boolean;
 | |
|           constructor create(l,r:tnode);virtual;reintroduce;
 | |
|           constructor create_implicit(l,r,_t1:tnode);virtual;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function simplify: tnode;override;
 | |
|        end;
 | |
|        ttryfinallynodeclass = class of ttryfinallynode;
 | |
| 
 | |
|        tonnode = class(tbinarynode)
 | |
|           excepTSymtable : TSymtable;
 | |
|           excepttype : tobjectdef;
 | |
|           constructor create(l,r:tnode);virtual;
 | |
|           destructor destroy;override;
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function dogetcopy : tnode;override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|        end;
 | |
|        tonnodeclass = class of tonnode;
 | |
| 
 | |
|     var
 | |
|        cwhilerepeatnode : twhilerepeatnodeclass;
 | |
|        cifnode : tifnodeclass;
 | |
|        cfornode : tfornodeclass;
 | |
|        cexitnode : texitnodeclass;
 | |
|        cbreaknode : tbreaknodeclass;
 | |
|        ccontinuenode : tcontinuenodeclass;
 | |
|        cgotonode : tgotonodeclass;
 | |
|        clabelnode : tlabelnodeclass;
 | |
|        craisenode : traisenodeclass;
 | |
|        ctryexceptnode : ttryexceptnodeclass;
 | |
|        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,symtable,paramgr,defcmp,defutil,htypechk,pass_1,
 | |
|       ncal,nadd,ncon,nmem,nld,ncnv,nbas,cgobj,nutils,ninl,nset,
 | |
|     {$ifdef state_tracking}
 | |
|       nstate,
 | |
|     {$endif}
 | |
|       cgbase,procinfo
 | |
|       ;
 | |
| 
 | |
| 
 | |
| // 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, 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).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;
 | |
|   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;
 | |
| 
 | |
| {****************************************************************************
 | |
|                                  TLOOPNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tloopnode.create(tt : tnodetype;l,r,_t1,_t2 : tnode);
 | |
| 
 | |
|       begin
 | |
|          inherited create(tt,l,r);
 | |
|          t1:=_t1;
 | |
|          t2:=_t2;
 | |
|          fileinfo:=l.fileinfo;
 | |
|       end;
 | |
| 
 | |
|     destructor tloopnode.destroy;
 | |
| 
 | |
|       begin
 | |
|          t1.free;
 | |
|          t2.free;
 | |
|          inherited destroy;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor tloopnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|         t1:=ppuloadnode(ppufile);
 | |
|         t2:=ppuloadnode(ppufile);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tloopnode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|         ppuwritenode(ppufile,t1);
 | |
|         ppuwritenode(ppufile,t2);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tloopnode.buildderefimpl;
 | |
|       begin
 | |
|         inherited buildderefimpl;
 | |
|         if assigned(t1) then
 | |
|           t1.buildderefimpl;
 | |
|         if assigned(t2) then
 | |
|           t2.buildderefimpl;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tloopnode.derefimpl;
 | |
|       begin
 | |
|         inherited derefimpl;
 | |
|         if assigned(t1) then
 | |
|           t1.derefimpl;
 | |
|         if assigned(t2) then
 | |
|           t2.derefimpl;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tloopnode.dogetcopy : tnode;
 | |
| 
 | |
|       var
 | |
|          p : tloopnode;
 | |
| 
 | |
|       begin
 | |
|          p:=tloopnode(inherited dogetcopy);
 | |
|          if assigned(t1) then
 | |
|            p.t1:=t1.dogetcopy
 | |
|          else
 | |
|            p.t1:=nil;
 | |
|          if assigned(t2) then
 | |
|            p.t2:=t2.dogetcopy
 | |
|          else
 | |
|            p.t2:=nil;
 | |
|          p.loopflags:=loopflags;
 | |
|          dogetcopy:=p;
 | |
|       end;
 | |
| 
 | |
|     procedure tloopnode.insertintolist(l : tnodelist);
 | |
| 
 | |
|       begin
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tloopnode.printnodetree(var t:text);
 | |
|       begin
 | |
|         write(t,printnodeindention,'(');
 | |
|         printnodeindent;
 | |
|         printnodeinfo(t);
 | |
|         writeln(t);
 | |
|         printnode(t,left);
 | |
|         printnode(t,right);
 | |
|         printnode(t,t1);
 | |
|         printnode(t,t2);
 | |
|         printnodeunindent;
 | |
|         writeln(t,printnodeindention,')');
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tloopnode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         docompare :=
 | |
|           inherited docompare(p) and
 | |
|           (loopflags*loopflagsequal=tloopnode(p).loopflags*loopflagsequal) and
 | |
|           t1.isequal(tloopnode(p).t1) and
 | |
|           t2.isequal(tloopnode(p).t2);
 | |
|       end;
 | |
| 
 | |
| {****************************************************************************
 | |
|                                TWHILEREPEATNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor Twhilerepeatnode.create(l,r:Tnode;tab,cn:boolean);
 | |
|       begin
 | |
|           inherited create(whilerepeatn,l,r,nil,nil);
 | |
|           if tab then
 | |
|               include(loopflags, lnf_testatbegin);
 | |
|           if cn then
 | |
|               include(loopflags,lnf_checknegate);
 | |
|       end;
 | |
| 
 | |
|     function twhilerepeatnode.pass_typecheck:tnode;
 | |
|       var
 | |
|          t:Tunarynode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          resultdef:=voidtype;
 | |
| 
 | |
|          typecheckpass(left);
 | |
| 
 | |
|          { tp procvar support }
 | |
|          maybe_call_procvar(left,true);
 | |
| 
 | |
|          {A not node can be removed.}
 | |
|          if left.nodetype=notn then
 | |
|            begin
 | |
|              t:=Tunarynode(left);
 | |
|              left:=Tunarynode(left).left;
 | |
|              t.left:=nil;
 | |
|              t.destroy;
 | |
|              {Symdif operator, in case you are wondering:}
 | |
|              loopflags:=loopflags >< [lnf_checknegate];
 | |
|            end;
 | |
|          { loop instruction }
 | |
|          if assigned(right) then
 | |
|            typecheckpass(right);
 | |
|          set_varstate(left,vs_read,[vsf_must_be_valid]);
 | |
|          if codegenerror then
 | |
|            exit;
 | |
| 
 | |
|          if not is_boolean(left.resultdef) then
 | |
|            begin
 | |
|              if left.resultdef.typ=variantdef then
 | |
|                inserttypeconv(left,booltype)
 | |
|              else
 | |
|                CGMessage1(type_e_boolean_expr_expected,left.resultdef.typename);
 | |
|            end;
 | |
| 
 | |
|          { Give warnings for code that will never be executed for
 | |
|            while false do }
 | |
|          if (lnf_testatbegin in loopflags) and
 | |
|             (left.nodetype=ordconstn) and
 | |
|             (tordconstnode(left).value.uvalue=0) and
 | |
|             assigned(right) then
 | |
|            CGMessagePos(right.fileinfo,cg_w_unreachable_code);
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {$ifdef prefetchnext}
 | |
|     type
 | |
|       passignmentquery = ^tassignmentquery;
 | |
|       tassignmentquery = record
 | |
|         towhat: tnode;
 | |
|         source: tassignmentnode;
 | |
|         statementcount: cardinal;
 | |
|       end;
 | |
| 
 | |
|     function checkassignment(var n: tnode; arg: pointer): foreachnoderesult;
 | |
|       var
 | |
|         query: passignmentquery absolute arg;
 | |
|         temp, prederef: tnode;
 | |
|       begin
 | |
|         result := fen_norecurse_false;
 | |
|         if (n.nodetype in [assignn,inlinen,forn,calln,whilerepeatn,casen,ifn]) then
 | |
|           inc(query^.statementcount);
 | |
|         { make sure there's something else in the loop besides going to the }
 | |
|         { next item                                                         }
 | |
|         if (query^.statementcount > 1) and
 | |
|            (n.nodetype = assignn) then
 | |
|           begin
 | |
|             { skip type conversions of assignment target }
 | |
|             temp := tassignmentnode(n).left;
 | |
|             while (temp.nodetype = typeconvn) do
 | |
|               temp := ttypeconvnode(temp).left;
 | |
| 
 | |
|             { assignment to x of the while assigned(x) check? }
 | |
|             if not(temp.isequal(query^.towhat)) then
 | |
|               exit;
 | |
| 
 | |
|             { right hand side of assignment dereferenced field of }
 | |
|             { x? (no derefn in case of class)                     }
 | |
|             temp := tassignmentnode(n).right;
 | |
|             while (temp.nodetype = typeconvn) do
 | |
|               temp := ttypeconvnode(temp).left;
 | |
|             if (temp.nodetype <> subscriptn) then
 | |
|               exit;
 | |
| 
 | |
|             prederef := tsubscriptnode(temp).left;
 | |
|             temp := prederef;
 | |
|             while (temp.nodetype = typeconvn) do
 | |
|               temp := ttypeconvnode(temp).left;
 | |
| 
 | |
|             { see tests/test/prefetch1.pp }
 | |
|             if (temp.nodetype = derefn) then
 | |
|               temp := tderefnode(temp).left
 | |
|             else
 | |
|               temp := prederef;
 | |
| 
 | |
|             if temp.isequal(query^.towhat) then
 | |
|               begin
 | |
|                 query^.source := tassignmentnode(n);
 | |
|                 result := fen_norecurse_true;
 | |
|                end
 | |
|           end
 | |
|         { don't check nodes which can't contain an assignment or whose }
 | |
|         { final assignment can vary a lot                              }
 | |
|         else if not(n.nodetype in [calln,inlinen,casen,whilerepeatn,forn]) then
 | |
|           result := fen_false;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function findassignment(where: tnode; towhat: tnode): tassignmentnode;
 | |
|       var
 | |
|         query: tassignmentquery;
 | |
|       begin
 | |
|         query.towhat := towhat;
 | |
|         query.source := nil;
 | |
|         query.statementcount := 0;
 | |
|         if foreachnodestatic(where,@checkassignment,@query) then
 | |
|           result := query.source
 | |
|         else
 | |
|            result := nil;
 | |
|       end;
 | |
| {$endif prefetchnext}
 | |
| 
 | |
| 
 | |
|     function twhilerepeatnode.pass_1 : tnode;
 | |
| {$ifdef prefetchnext}
 | |
|       var
 | |
|          runnernode, prefetchcode: tnode;
 | |
|          assignmentnode: tassignmentnode;
 | |
|          prefetchstatements: tstatementnode;
 | |
| {$endif prefetchnext}
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
| 
 | |
|          firstpass(left);
 | |
|          if codegenerror then
 | |
|            exit;
 | |
| 
 | |
|          { loop instruction }
 | |
|          if assigned(right) then
 | |
|            begin
 | |
|               firstpass(right);
 | |
|               if codegenerror then
 | |
|                 exit;
 | |
|            end;
 | |
| 
 | |
| {$ifdef prefetchnext}
 | |
|          { do at the end so all complex typeconversions are already }
 | |
|          { converted to calln's                                     }
 | |
|          if (cs_opt_level1 in current_settings.optimizerswitches) and
 | |
|             (lnf_testatbegin in loopflags) then
 | |
|            begin
 | |
|              { get first component of the while check }
 | |
|              runnernode := left;
 | |
|              while (runnernode.nodetype in [andn,orn,notn,xorn,typeconvn]) do
 | |
|                runnernode := tunarynode(runnernode).left;
 | |
|              { is it an assigned(x) check? }
 | |
|              if ((runnernode.nodetype = inlinen) and
 | |
|                  (tinlinenode(runnernode).inlinenumber = in_assigned_x)) or
 | |
|                 ((runnernode.nodetype = unequaln) and
 | |
|                  (taddnode(runnernode).right.nodetype = niln)) then
 | |
|                begin
 | |
|                  runnernode := tunarynode(runnernode).left;
 | |
|                  { in case of in_assigned_x, there's a callparan in between }
 | |
|                  if (runnernode.nodetype = callparan) then
 | |
|                    runnernode := tcallparanode(runnernode).left;
 | |
|                  while (runnernode.nodetype = typeconvn) do
 | |
|                    runnernode := ttypeconvnode(runnernode).left;
 | |
|                  { is there an "x := x(^).somefield"? }
 | |
|                  assignmentnode := findassignment(right,runnernode);
 | |
|                  if assigned(assignmentnode) then
 | |
|                    begin
 | |
|                      prefetchcode := internalstatements(prefetchstatements);
 | |
|                      addstatement(prefetchstatements,geninlinenode(in_prefetch_var,false,
 | |
|                        cderefnode.create(ctypeconvnode.create(assignmentnode.right.getcopy,voidpointertype))));
 | |
|                      addstatement(prefetchstatements,right);
 | |
|                      right := prefetchcode;
 | |
|                      typecheckpass(right);
 | |
|                    end;
 | |
|                end;
 | |
|            end;
 | |
| {$endif prefetchnext}
 | |
|       end;
 | |
| 
 | |
| {$ifdef state_tracking}
 | |
|     function Twhilerepeatnode.track_state_pass(exec_known:boolean):boolean;
 | |
| 
 | |
|     var condition:Tnode;
 | |
|         code:Tnode;
 | |
|         done:boolean;
 | |
|         value:boolean;
 | |
|         change:boolean;
 | |
|         firsttest:boolean;
 | |
|         factval:Tnode;
 | |
| 
 | |
|     begin
 | |
|         track_state_pass:=false;
 | |
|         done:=false;
 | |
|         firsttest:=true;
 | |
|         {For repeat until statements, first do a pass through the code.}
 | |
|         if not(lnf_testatbegin in flags) then
 | |
|             begin
 | |
|                 code:=right.getcopy;
 | |
|                 if code.track_state_pass(exec_known) then
 | |
|                     track_state_pass:=true;
 | |
|                 code.destroy;
 | |
|             end;
 | |
|         repeat
 | |
|             condition:=left.getcopy;
 | |
|             code:=right.getcopy;
 | |
|             change:=condition.track_state_pass(exec_known);
 | |
|             factval:=aktstate.find_fact(left);
 | |
|             if factval<>nil then
 | |
|                 begin
 | |
|                     condition.destroy;
 | |
|                     condition:=factval.getcopy;
 | |
|                     change:=true;
 | |
|                 end;
 | |
|             if change then
 | |
|                 begin
 | |
|                     track_state_pass:=true;
 | |
|                     {Force new resultdef pass.}
 | |
|                     condition.resultdef:=nil;
 | |
|                     do_typecheckpass(condition);
 | |
|                 end;
 | |
|             if is_constboolnode(condition) then
 | |
|                 begin
 | |
|                     {Try to turn a while loop into a repeat loop.}
 | |
|                     if firsttest then
 | |
|                         exclude(flags,testatbegin);
 | |
|                     value:=(Tordconstnode(condition).value<>0) xor checknegate;
 | |
|                     if value then
 | |
|                         begin
 | |
|                             if code.track_state_pass(exec_known) then
 | |
|                                 track_state_pass:=true;
 | |
|                         end
 | |
|                     else
 | |
|                         done:=true;
 | |
|                 end
 | |
|             else
 | |
|                 begin
 | |
|                     {Remove any modified variables from the state.}
 | |
|                     code.track_state_pass(false);
 | |
|                     done:=true;
 | |
|                 end;
 | |
|             code.destroy;
 | |
|             condition.destroy;
 | |
|             firsttest:=false;
 | |
|         until done;
 | |
|         {The loop condition is also known, for example:
 | |
|          while i<10 do
 | |
|             begin
 | |
|                 ...
 | |
|             end;
 | |
| 
 | |
|          When the loop is done, we do know that i<10 = false.
 | |
|         }
 | |
|         condition:=left.getcopy;
 | |
|         if condition.track_state_pass(exec_known) then
 | |
|             begin
 | |
|                 track_state_pass:=true;
 | |
|                 {Force new resultdef pass.}
 | |
|                 condition.resultdef:=nil;
 | |
|                 do_typecheckpass(condition);
 | |
|             end;
 | |
|         if not is_constboolnode(condition) then
 | |
|             aktstate.store_fact(condition,
 | |
|              cordconstnode.create(byte(checknegate),booltype,true))
 | |
|         else
 | |
|             condition.destroy;
 | |
|     end;
 | |
| {$endif}
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                TIFNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tifnode.create(l,r,_t1 : tnode);
 | |
|       begin
 | |
|          inherited create(ifn,l,r,_t1,nil);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tifnode.internalsimplify(warn: boolean) : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         { optimize constant expressions }
 | |
|         if (left.nodetype=ordconstn) then
 | |
|           begin
 | |
|              if tordconstnode(left).value.uvalue=1 then
 | |
|                begin
 | |
|                   if assigned(right) then
 | |
|                     result:=right
 | |
|                   else
 | |
|                     result:=cnothingnode.create;
 | |
|                   right:=nil;
 | |
|                   if warn and assigned(t1) then
 | |
|                     CGMessagePos(t1.fileinfo,cg_w_unreachable_code);
 | |
|                end
 | |
|              else
 | |
|                begin
 | |
|                   if assigned(t1) then
 | |
|                     result:=t1
 | |
|                   else
 | |
|                     result:=cnothingnode.create;
 | |
|                   t1:=nil;
 | |
|                   if warn and assigned(right) then
 | |
|                     CGMessagePos(right.fileinfo,cg_w_unreachable_code);
 | |
|                end;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tifnode.simplify : tnode;
 | |
|       begin
 | |
|         result:=internalsimplify(false);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tifnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          resultdef:=voidtype;
 | |
| 
 | |
|          typecheckpass(left);
 | |
| 
 | |
|          { tp procvar support }
 | |
|          maybe_call_procvar(left,true);
 | |
| 
 | |
|          { if path }
 | |
|          if assigned(right) then
 | |
|            typecheckpass(right);
 | |
|          { else path }
 | |
|          if assigned(t1) then
 | |
|            typecheckpass(t1);
 | |
|          set_varstate(left,vs_read,[vsf_must_be_valid]);
 | |
|          if codegenerror then
 | |
|            exit;
 | |
| 
 | |
|          if not is_boolean(left.resultdef) then
 | |
|            begin
 | |
|              if left.resultdef.typ=variantdef then
 | |
|                inserttypeconv(left,booltype)
 | |
|              else
 | |
|                Message1(type_e_boolean_expr_expected,left.resultdef.typename);
 | |
|            end;
 | |
|          result:=internalsimplify(true);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tifnode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
|          firstpass(left);
 | |
| 
 | |
|          { if path }
 | |
|          if assigned(right) then
 | |
|            firstpass(right);
 | |
| 
 | |
|          { else path }
 | |
|          if assigned(t1) then
 | |
|            firstpass(t1);
 | |
| 
 | |
|          { leave if we've got an error in one of the paths }
 | |
| 
 | |
|          if codegenerror then
 | |
|            exit;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                               TFORNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tfornode.create(l,r,_t1,_t2 : tnode;back : boolean);
 | |
| 
 | |
|       begin
 | |
|          inherited create(forn,l,r,_t1,_t2);
 | |
|          if back then
 | |
|            include(loopflags,lnf_backward);
 | |
|          include(loopflags,lnf_testatbegin);
 | |
|       end;
 | |
| 
 | |
|     procedure Tfornode.loop_var_access(not_type:Tnotification_flag;
 | |
|                                        symbol:Tsym);
 | |
| 
 | |
|     begin
 | |
|       {If there is a read access, the value of the loop counter is important;
 | |
|        at the end of the loop the loop variable should contain the value it
 | |
|        had in the last iteration.}
 | |
|       if not_type=vn_onwrite then
 | |
|         begin
 | |
|           writeln('Loopvar does not matter on exit');
 | |
|         end
 | |
|       else
 | |
|         begin
 | |
|           exclude(loopflags,lnf_dont_mind_loopvar_on_exit);
 | |
|           writeln('Loopvar does matter on exit');
 | |
|         end;
 | |
|       Tabstractvarsym(symbol).unregister_notification(loopvar_notid);
 | |
|     end;
 | |
| 
 | |
| 
 | |
|     function tfornode.simplify : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         if (t1.nodetype=ordconstn) and
 | |
|            (right.nodetype=ordconstn) and
 | |
|            (
 | |
|             (
 | |
|              (lnf_backward in loopflags) and
 | |
|              (tordconstnode(right).value<tordconstnode(t1).value)
 | |
|             ) or
 | |
|             (
 | |
|               not(lnf_backward in loopflags) and
 | |
|               (tordconstnode(right).value>tordconstnode(t1).value)
 | |
|             )
 | |
|            ) then
 | |
|         result:=cnothingnode.create;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tfornode.pass_typecheck:tnode;
 | |
|       var
 | |
|         res : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          resultdef:=voidtype;
 | |
| 
 | |
|          { process the loopvar, from and to, varstates are already set }
 | |
|          typecheckpass(left);
 | |
|          typecheckpass(right);
 | |
|          typecheckpass(t1);
 | |
| 
 | |
|          set_varstate(left,vs_written,[]);
 | |
| 
 | |
|          { loop unrolling }
 | |
|          if cs_opt_loopunroll in current_settings.optimizerswitches then
 | |
|            begin
 | |
|              res:=unroll_loop(self);
 | |
|              if assigned(res) then
 | |
|                begin
 | |
|                  typecheckpass(res);
 | |
|                  result:=res;
 | |
|                  exit;
 | |
|                end;
 | |
|            end;
 | |
| 
 | |
|          { Can we spare the first comparision? }
 | |
|          if (t1.nodetype=ordconstn) and
 | |
|             (right.nodetype=ordconstn) and
 | |
|             (
 | |
|              (
 | |
|               (lnf_backward in loopflags) and
 | |
|               (Tordconstnode(right).value>=Tordconstnode(t1).value)
 | |
|              ) or
 | |
|              (
 | |
|                not(lnf_backward in loopflags) and
 | |
|                (Tordconstnode(right).value<=Tordconstnode(t1).value)
 | |
|              )
 | |
|             ) then
 | |
|            exclude(loopflags,lnf_testatbegin);
 | |
| 
 | |
|          { Make sure that the loop var and the
 | |
|            from and to values are compatible types }
 | |
|          check_ranges(right.fileinfo,right,left.resultdef);
 | |
|          inserttypeconv(right,left.resultdef);
 | |
| 
 | |
|          check_ranges(t1.fileinfo,t1,left.resultdef);
 | |
|          inserttypeconv(t1,left.resultdef);
 | |
| 
 | |
|          if assigned(t2) then
 | |
|            typecheckpass(t2);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tfornode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
| 
 | |
|          firstpass(left);
 | |
|          firstpass(right);
 | |
|          firstpass(t1);
 | |
| 
 | |
|          if assigned(t2) then
 | |
|           begin
 | |
|             firstpass(t2);
 | |
|             if codegenerror then
 | |
|              exit;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TEXITNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor texitnode.create(l:tnode);
 | |
|       begin
 | |
|         inherited create(exitn,l);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor texitnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure texitnode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function texitnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         if assigned(left) then
 | |
|           begin
 | |
|             { add assignment to funcretsym }
 | |
|             inserttypeconv(left,current_procinfo.procdef.returndef);
 | |
|             left:=cassignmentnode.create(
 | |
|                 cloadnode.create(current_procinfo.procdef.funcretsym,current_procinfo.procdef.funcretsym.owner),
 | |
|                 left);
 | |
|             typecheckpass(left);
 | |
|             set_varstate(left,vs_read,[vsf_must_be_valid]);
 | |
|           end;
 | |
|         resultdef:=voidtype;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function texitnode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
|          if assigned(left) then
 | |
|            begin
 | |
|               firstpass(left);
 | |
|               if codegenerror then
 | |
|                exit;
 | |
|            end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TBREAKNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tbreaknode.create;
 | |
| 
 | |
|       begin
 | |
|         inherited create(breakn);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tbreaknode.pass_typecheck:tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         resultdef:=voidtype;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tbreaknode.pass_1 : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         expectloc:=LOC_VOID;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TCONTINUENODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tcontinuenode.create;
 | |
|       begin
 | |
|         inherited create(continuen);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tcontinuenode.pass_typecheck:tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         resultdef:=voidtype;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tcontinuenode.pass_1 : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         expectloc:=LOC_VOID;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TGOTONODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tgotonode.create(p : tlabelsym);
 | |
|       begin
 | |
|         inherited create(goton);
 | |
|         exceptionblock:=current_exceptblock;
 | |
|         labelnode:=nil;
 | |
|         labelsym:=p;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor tgotonode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|         labelnodeidx:=ppufile.getlongint;
 | |
|         exceptionblock:=ppufile.getbyte;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tgotonode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|         labelnodeidx:=labelnode.ppuidx;
 | |
|         ppufile.putlongint(labelnodeidx);
 | |
|         ppufile.putbyte(exceptionblock);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tgotonode.buildderefimpl;
 | |
|       begin
 | |
|         inherited buildderefimpl;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tgotonode.derefimpl;
 | |
|       begin
 | |
|         inherited derefimpl;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tgotonode.resolveppuidx;
 | |
|       begin
 | |
|         labelnode:=tlabelnode(nodeppuidxget(labelnodeidx));
 | |
|         if labelnode.nodetype<>labeln then
 | |
|           internalerror(200809021);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tgotonode.pass_typecheck:tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         resultdef:=voidtype;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tgotonode.pass_1 : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         expectloc:=LOC_VOID;
 | |
|         include(current_procinfo.flags,pi_has_goto);
 | |
| 
 | |
|         { The labelnode can already be set when
 | |
|           this node was copied }
 | |
|         if not assigned(labelnode) then
 | |
|           begin
 | |
|             if assigned(labelsym.code) then
 | |
|               labelnode:=tlabelnode(labelsym.code)
 | |
|             else
 | |
|               CGMessage1(cg_e_goto_label_not_found,labelsym.realname);
 | |
|           end;
 | |
| 
 | |
|         { check if we don't mess with exception blocks }
 | |
|         if assigned(labelnode) and
 | |
|            (exceptionblock<>labelnode.exceptionblock) then
 | |
|           CGMessage(cg_e_goto_inout_of_exception_block);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|    function tgotonode.dogetcopy : tnode;
 | |
|      var
 | |
|        p : tgotonode;
 | |
|      begin
 | |
|         p:=tgotonode(inherited dogetcopy);
 | |
|         p.exceptionblock:=exceptionblock;
 | |
| 
 | |
|         { generate labelnode if not done yet }
 | |
|         if not(assigned(labelnode)) then
 | |
|           begin
 | |
|             if assigned(labelsym) and assigned(labelsym.code) then
 | |
|               labelnode:=tlabelnode(labelsym.code)
 | |
|           end;
 | |
| 
 | |
|         p.labelsym:=labelsym;
 | |
|         if assigned(labelnode) then
 | |
|           p.labelnode:=tlabelnode(labelnode.dogetcopy)
 | |
|         else
 | |
|           begin
 | |
|             { don't trigger IE when there was already an error, i.e. the
 | |
|               label is not defined. See tw11763 (PFV) }
 | |
|             if errorcount=0 then
 | |
|               internalerror(200610291);
 | |
|           end;
 | |
|         result:=p;
 | |
|      end;
 | |
| 
 | |
| 
 | |
|     function tgotonode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         docompare := false;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TLABELNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tlabelnode.create(l:tnode;alabsym:tlabelsym);
 | |
|       begin
 | |
|         inherited create(labeln,l);
 | |
|         exceptionblock:=current_exceptblock;
 | |
|         labsym:=alabsym;
 | |
|         { Register labelnode in labelsym }
 | |
|         labsym.code:=self;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor tlabelnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|         exceptionblock:=ppufile.getbyte;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     destructor tlabelnode.destroy;
 | |
|       begin
 | |
|         { Remove reference in labelsym, this is to prevent
 | |
|           goto's to this label }
 | |
|         if assigned(labsym) and (labsym.code=pointer(self)) then
 | |
|           labsym.code:=nil;
 | |
|         inherited destroy;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tlabelnode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|         ppufile.putbyte(exceptionblock);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tlabelnode.buildderefimpl;
 | |
|       begin
 | |
|         inherited buildderefimpl;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tlabelnode.derefimpl;
 | |
|       begin
 | |
|         inherited derefimpl;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tlabelnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         { left could still be unassigned }
 | |
|         if assigned(left) then
 | |
|          typecheckpass(left);
 | |
|         resultdef:=voidtype;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tlabelnode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
|          if assigned(left) then
 | |
|            firstpass(left);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|    function tlabelnode.dogetcopy : tnode;
 | |
|      begin
 | |
|         if not(assigned(copiedto)) then
 | |
|           copiedto:=tlabelnode(inherited dogetcopy);
 | |
|         copiedto.exceptionblock:=exceptionblock;
 | |
| 
 | |
|         result:=copiedto;
 | |
|      end;
 | |
| 
 | |
| 
 | |
|     function tlabelnode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         docompare := false;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                             TRAISENODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor traisenode.create(l,taddr,tframe:tnode);
 | |
|       begin
 | |
|          inherited create(raisen,l,taddr,tframe);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function traisenode.pass_typecheck:tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          resultdef:=voidtype;
 | |
|          if assigned(left) then
 | |
|            begin
 | |
|              { first para must be a _class_ }
 | |
|              typecheckpass(left);
 | |
|              set_varstate(left,vs_read,[vsf_must_be_valid]);
 | |
|              if codegenerror then
 | |
|               exit;
 | |
|              if not(is_class(left.resultdef)) then
 | |
|                CGMessage1(type_e_class_type_expected,left.resultdef.typename);
 | |
|              { insert needed typeconvs for addr,frame }
 | |
|              if assigned(right) then
 | |
|                begin
 | |
|                  { addr }
 | |
|                  typecheckpass(right);
 | |
|                  inserttypeconv(right,voidpointertype);
 | |
|                  { frame }
 | |
|                  if assigned(third) then
 | |
|                   begin
 | |
|                     typecheckpass(third);
 | |
|                     inserttypeconv(third,voidpointertype);
 | |
|                   end;
 | |
|                end;
 | |
|            end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function traisenode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          include(current_procinfo.flags,pi_do_call);
 | |
|          expectloc:=LOC_VOID;
 | |
|          if assigned(left) then
 | |
|            begin
 | |
|               { first para must be a _class_ }
 | |
|               firstpass(left);
 | |
|               { insert needed typeconvs for addr,frame }
 | |
|               if assigned(right) then
 | |
|                begin
 | |
|                  { addr }
 | |
|                  firstpass(right);
 | |
|                  { frame }
 | |
|                  if assigned(third) then
 | |
|                   firstpass(third);
 | |
|                end;
 | |
|            end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TTRYEXCEPTNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor ttryexceptnode.create(l,r,_t1 : tnode);
 | |
|       begin
 | |
|          inherited create(tryexceptn,l,r,_t1,nil);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttryexceptnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          typecheckpass(left);
 | |
|          { on statements }
 | |
|          if assigned(right) then
 | |
|            typecheckpass(right);
 | |
|          { else block }
 | |
|          if assigned(t1) then
 | |
|            typecheckpass(t1);
 | |
|          resultdef:=voidtype;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttryexceptnode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          include(current_procinfo.flags,pi_do_call);
 | |
|          expectloc:=LOC_VOID;
 | |
|          firstpass(left);
 | |
|          { on statements }
 | |
|          if assigned(right) then
 | |
|            firstpass(right);
 | |
|          { else block }
 | |
|          if assigned(t1) then
 | |
|            firstpass(t1);
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                            TTRYFINALLYNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor ttryfinallynode.create(l,r:tnode);
 | |
|       begin
 | |
|         inherited create(tryfinallyn,l,r,nil,nil);
 | |
|         implicitframe:=false;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttryfinallynode.create_implicit(l,r,_t1:tnode);
 | |
|       begin
 | |
|         inherited create(tryfinallyn,l,r,_t1,nil);
 | |
|         implicitframe:=true;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttryfinallynode.pass_typecheck:tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          include(current_procinfo.flags,pi_do_call);
 | |
|          resultdef:=voidtype;
 | |
| 
 | |
|          typecheckpass(left);
 | |
|          // "try block" is "used"? (JM)
 | |
|          set_varstate(left,vs_readwritten,[vsf_must_be_valid]);
 | |
| 
 | |
|          typecheckpass(right);
 | |
|          // "except block" is "used"? (JM)
 | |
|          set_varstate(right,vs_readwritten,[vsf_must_be_valid]);
 | |
| 
 | |
|          { special finally block only executed when there was an exception }
 | |
|          if assigned(t1) then
 | |
|            begin
 | |
|              typecheckpass(t1);
 | |
|              // "finally block" is "used"? (JM)
 | |
|              set_varstate(t1,vs_readwritten,[vsf_must_be_valid]);
 | |
|            end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttryfinallynode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
|          firstpass(left);
 | |
| 
 | |
|          firstpass(right);
 | |
| 
 | |
|          if assigned(t1) then
 | |
|            firstpass(t1);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|    function ttryfinallynode.simplify: tnode;
 | |
|      begin
 | |
|        result:=nil;
 | |
|        { if the try contains no code, we can kill
 | |
|          the try and except and return only the
 | |
|          finally part }
 | |
|        if has_no_code(left) then
 | |
|          begin
 | |
|            result:=right;
 | |
|            right:=nil;
 | |
|          end;
 | |
|      end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                 TONNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tonnode.create(l,r:tnode);
 | |
|       begin
 | |
|          inherited create(onn,l,r);
 | |
|          excepTSymtable:=nil;
 | |
|          excepttype:=nil;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     destructor tonnode.destroy;
 | |
|       begin
 | |
|         { copied nodes don't need to release the symtable }
 | |
|         if assigned(excepTSymtable) then
 | |
|          excepTSymtable.free;
 | |
|         inherited destroy;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor tonnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|         excepTSymtable:=nil;
 | |
|         excepttype:=nil;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tonnode.dogetcopy : tnode;
 | |
|       var
 | |
|          n : tonnode;
 | |
|       begin
 | |
|          n:=tonnode(inherited dogetcopy);
 | |
|          if assigned(exceptsymtable) then
 | |
|            n.exceptsymtable:=exceptsymtable.getcopy
 | |
|          else
 | |
|            n.exceptsymtable:=nil;
 | |
|          n.excepttype:=excepttype;
 | |
|          result:=n;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tonnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          resultdef:=voidtype;
 | |
|          if not(is_class(excepttype)) then
 | |
|            CGMessage1(type_e_class_type_expected,excepttype.typename);
 | |
|          if assigned(left) then
 | |
|            typecheckpass(left);
 | |
|          if assigned(right) then
 | |
|            typecheckpass(right);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tonnode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          include(current_procinfo.flags,pi_do_call);
 | |
|          expectloc:=LOC_VOID;
 | |
|          if assigned(left) then
 | |
|            firstpass(left);
 | |
| 
 | |
|          if assigned(right) then
 | |
|            firstpass(right);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tonnode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         docompare := false;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| begin
 | |
|    cwhilerepeatnode:=twhilerepeatnode;
 | |
|    cifnode:=tifnode;
 | |
|    cfornode:=tfornode;
 | |
|    cexitnode:=texitnode;
 | |
|    cgotonode:=tgotonode;
 | |
|    clabelnode:=tlabelnode;
 | |
|    craisenode:=traisenode;
 | |
|    ctryexceptnode:=ttryexceptnode;
 | |
|    ctryfinallynode:=ttryfinallynode;
 | |
|    connode:=tonnode;
 | |
| end.
 | 
