/*

CLASS {Fun|ction}, RECURSIVE, UNTESTED, BITWISE :

IMPORT: {Variable}, {Parser}, {Text_parser}, {Statement}, {Case}, {For},
		{Assignment}, {Expression}, {Type}, {Compiler}, {Generator}, {Limit},
		{Local}, {String_functions}, {System_functions}, {Console}, {Table},
        {Log_html}, {File_path}, {Localize_str}, {Calc_hash} ;

*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AL4Compiler.Statements;
using AL4Compiler._CSharp;

namespace AL4Compiler
{
    public class Function
    {
        /*
        
        {Parser} Parse|_source, INIT
        METHOD err|or_message( STR M|_essage) : Parse.Err(M) .
        METHOD warn|inig_megs( STR M|_essage) : Parse.Warn(M) .
        METHOD style_warn|inig_megs( STR M|_essage) : Parse.Style_warn(M) .

		STR		A_Name_1|_just_to_see_it_on_top_of_the_props_list_while_debugging,
				INIT
        STR     Names|_of_function[]
        STR		Names_low|ered[]
        
        METHOD Provide_names_lowered :
	        CASE Names_low[].Count > 0 ? ==> ;
	        FOR n IN Names[] : Names_low[] << n.Lower ; .     
        
		STR whole_name|_cached
		
		METHOD Whole_name ==> STR :
		    CASE whole_name != "" ? RESULT = whole_name ==> ;
		    whole_name = Whole_name_of(Names[])
		    RESULT = whole_name .

        INT		hash_name|s[]
        INT		hash_low|ered_names[]
        
        METHOD Hash_name(
        INT Index|_name INDEXING INT) ==> INT
    		:
            CASE hash_name[].Count == 0 ? 
                 FOR n IN Names[] :
                     hash_name[] << Calc_hash32(n) ;
            ;
            RESULT = hash_name[Index] .
        
        METHOD Hash_low|ered_name(
        INT Index|_name INDEXING INT) ==> INT
    		:
            CASE hash_low[].Count == 0 ? 
                 FOR n IN Names[] :
                     hash_low[] << Calc_hash32(n.Lower) ;
            ;
            RESULT = hash_low[Index] .
            
        METHOD Is_public ==> BOOL : 
               RESULT = Names[0].[0].Upper == Names[0].[0] 
               RESULT ||= Modifiers['PUBLIC'] .
               
        {Var}   Param|eters[]
        
        METHOD First_param_type ==> {Type} :
			CASE Modifiers['STATIC'] ? RESULT = Param[0].Type_
			ELSE RESULT = Class ; .
        
        {Var}   Result|_returning
        BOOL    Is_test|_but_not_a_method
        BOOL    Is_trivial|_may_be_not_need_testing
        --------------------------- 'redirection while TRANSLATION'
        {Fun}   Redirect_|to_original_function_method_
        --------------------------- 'starting - ending position'
        INT     Header_line INDEXING STR
        INT     Line_start
        INT     Pos_start
        INT     Line_end
        INT     Line_native|_code
        --------------------------- 'compiled'
        STR     Final_name
        METHOD Set_final_name(STR New|_final_name) : Final_name = New .
        {Statement} Block|_of_code[]
        {Var}   Local_var|iables[]
        STR     Native_code   
        --------------------------- 'system functions'
        BOOL    Is_system|_special_function
        {system_fun} System_fun|ction_identifier
        
        ENUM {system_fun|ctions} :
			'SYSFUN_UNDEFINED',
			'SYSFUN_Index', 'SYSFUN_Len', 'SYSFUN_Count', 'SYSFUN_Name', 
			'SYSFUN_Find_str', 'SYSFUN_Insert', 'SYSFUN_Delete',
			'SYSFUN_Allocate',
			'SYSFUN_Remove', 'SYSFUN_Clear', 'SYSFUN_Find_item', 'SYSFUN_Swap',
			'SYSFUN_Str', 'SYSFUN_RealStr',
			'SYSFUN_BoolStr', 'SYSFUN_StrInt', 'SYSFUN_RealInt', 
			'SYSFUN_EnumInt', 'SYSFUN_Byte', 'SYSFUN_StrHex16', 'SYSFUN_First', 
			'SYSFUN_Next', 'SYSFUN_Previous', 'SYSFUN_Last', 'SYSFUN_Shl', 
			'SYSFUN_Shr', 'SYSFUN_Rol', 'SYSFUN_Ror', 
			'SYSFUN_Compare_substrings', 'SYSFUN_Compare_substr1', 
			'SYSFUN_Clone|_STRUCTURE', 'SYSFUN_Dismiss|_STRUCTURE' .
        
        --------------------------- 'test recursive'
        {Fun}   Call_functions_|list_[]
        {Fun}	Use_functions_|list_[]
        STR		Call_from|_functions[]
        BOOL    Recursive|_actually
        --------------------------- 'has...'
        BOOL    Has_stop
        INT     Usage_count
        INT		Count_ref|erenced
        BOOL	Removed|_do_not_generate
        --------------------------- 'override method'
        {Fun}   Ancestor_|method_
        --------------------------- 'operator'
        BOOL	Is_operator
        --------------------------- 'for {Expression} compilation'
        INT		Level_operand
        
        FUN comp|iler_of_parser({Parser} P|arser_in) ==> {Compiler} :
			RESULT = P.Compiler_.{Compiler} .
			
        METHOD Compiler ==> {Compiler} : RESULT = Class.Compiler .
        
        METHOD Has_non_abstract_ancestor ==> BOOL :
			{Fun} a|ncestor_checking = Ancestor_
			FOR i|dummy IN [0 TO comp(Parse).All_classes[].Count] :
			    CASE a == NONE ? ==> ;
			    CASE !a.Class.Modifiers['ABSTRACT'] ? RESULT = TRUE ==> ;
			    a = a.Ancestor_ ; .
			    
        {Type} Class_|where_function_is_defined_
			    
        METHOD Class|_from ==> {Type} :
			CASE Class_ != NONE ? RESULT = Class_
			ELSE RESULT = Parse.Class_ ; .
        BOOL	Overridden
        ------------- 'garbage collection of expressions, variables, statements'
        {Expr}  All_expr|essions_created_while_compiling_function[]
        {Var}   All_var |iables_created_while_compiling_function[]
        {Statement} Keep_statements[]
        --------------------------- 'check if can be STATIC'
        BOOL    This_used|_explicitly_or_implicitly
        --------------------------- 'danger things'
        BOOL    Has_add|_append_insert_operations
        BOOL	Has_return|_statements_So_can_not_be_inlined
        BOOL	Has_break_cont|inue_statements_Do_not_inline
        --------------------------- 'debug'
        INT     Total_fn|_index
        INT		Global_n|umber_of_function
        ------------------------------ 'collecting suspect passing arrays'
        INT 	Passing_arrays|_lines_with_suspicious_stmts[]
        {Var} 	Weak_arrays_passing|_in_suspicious_stmts[]
        {Fun} 	Passing_to_function_|suspicious_[]
        INT 	Passing_as_param|eter_index[]
        ------------------------------ 'overloading'
        {Fun}	Overloaded_|versions_[]
        {Fun}	Overload_base_|function_

        METHOD Overloaded_differ_by_first_param
        |eter_types ==> BOOL
        	:
			CASE Overloaded_[].Count == 0 ? ==> ;
			FOR fn IN Overloaded_[] :
			    CASE ?
			    [fn.Index == 0] ?
			         {Type} fpt|_first_parameter_type = fn.First_param_type
			    [fn.First_param_type == fpt] ? CONTINUE fn
			    ELSE RESULT = TRUE ==> ;
			; .
        //----------------- 'if the object is a parameter referring to a function'
        //BOOL    Is_function_param
        //{Fun}   Actual_function_|value_for_parameter_function_
        -------------------------------- 'STOREd parameter'
        {Var}   Stored_param
        INT     Stored_initial_value
        BOOL    Calls_stored_fun|ctions
        -------------------------------- 'setter / getter'
        {Fun}   Getter_method_
        {Var}   Getter_field_
        {Fun}   Setter_|method_for_this_getter_method_
		-------------------------------- 'feature to minimize incorrect use'
		STR		Wait_names_f|unctions[]
		{Fun}	Waiting_|to_end_of_function_[]
		INT		Lines_waiting[]
        -------------------------------- 'for interpretator'
        INT		Internal_index
        INT		Native_index|_for_native_functions_only
        INT		Virtual_index|_for_methods_only
        -------------------------------- 'last expression created'
        {Expr}  Last_expr|ession_recognized
        BOOL	Wait_var|iables_as_last_expr
        BOOL	Wait_field|s_s_last_expr
        BOOL	Wait_fun|ctions_as_last_expr
        --------------------------- 'optimize once'
        BOOL    Optimizations_G|_done_unused_variables_removed
        INT		Inlined_calls
        BOOL	Is_deleting_obj|ects
        
        METHOD Set_last_expr|ession_VAR_FUN({Expr} E|xpression) :
			CASE Last_expr != NONE ?
			     CASE Last_expr.At_line > E.At_line ? ==> ;
			     CASE Last_expr.At_line == E.At_line && (
			     	  Last_expr.At_pos > E.At_pos)
			     	  ? 
			          ==> ;
			;
            CASE E.Operation == 'VAR' && Wait_var
            	 || E.Operation == 'FIELD' && Wait_field
            	 || E.Operation == 'FUN' && Wait_fun
            	 ?
                 Last_expr = E ; .
        
        {Fun}   Last_fun_|ction_call_recognized_


        CONSTRUCT :
			Total_fn = comp(Parse).Total_fun
        	comp(Parse).Total_fun += 1
        	//DEBUG:
        	//      //CASE Total_fn == 10012 ?
        	//      //     << "fn " Total_fn.Str " created" #NL
        	//      //     	"" Trace_stack(100) #NL ;
        	//;
        .
        
        //DESTRUCT :
        //:
        // CASE A_Name_0.Starting("sc") && A_Name_0.Ending("<--") ?
        // ;
        //

        */
        public Compiler comp(Parser p)
        {
        	return p.Compiler_;
        }
        
        public Parser Parse = null;
        private void err(string M) { comp(Parse).Error(M); }
        private void warn(string M) { comp(Parse).Warning(M); }

        public List<String> Names = new List<string>();
        public List<Variable> Param = new List<Variable>();
        public Variable Result = null;
        public bool Is_test;
        //------------------------ 'starting position'
        public int Line_start;
        public int Pos_start;
        //------------------------ 'compiled'
        public string Final_name = "";
        public List<Statement> Block = new List<Statement>();
        public List<Variable> Local_var = new List<Variable>();
        public bool Is_system;
        public string Native_code = "";
        public List<Function> Call_ = new List<Function>();
        public List<Type> Test_import_ = new List<Type>();
        //-------------------------- 'danger things'
        public bool Has_add;
        //-------------------------- 'debug'
        public int Total_fn;

        public Function(Parser P)
        {
            Total_fn = P.Compiler_.Total_fun_index++;
            //if (Total_fn == 156)
            //{ }
        }

        public Type Class()
        {
            return Parse.Class_;
        }

        /*
        
        METHOD Search_var|iable(
            STR Name|_of_variable,
            BOOL Case|_sensitive ) ==> {Var}
            :
            ------------------------------------- ''
            RESULT = Find_local_var(Name, Case)
            CASE RESULT != NONE ? ==> ;
            CASE Modifiers['STATIC'] && Name != "DATA" ? ==> ;
            {Type} c|lass_where_search_field = comp(Parse).Current_class
            CASE !Case ? STR name_low|ered = Name.Lower ;
            FOR i|dummy IN [0 TO 1000] :
                CASE c == NONE ? BREAK i ;
                FOR v IN c.Field[] :
                    CASE v.Names[0].[0] != Name.[0] ? 
                         CASE Case ? CONTINUE v ;
                         CASE v.Names[0].[0].Lower != name_low.[0] ? 
                              CONTINUE v ;
                    ;
                	CASE !Case ? v.Provide_names_lowered ;
                	CASE !Case && name_low IN v.Names_low[]
                		 || Case && Name IN v.Names[]
                		 ? 
                         RESULT = v
                         CASE Name == "DATA" && c.Ending_lines[].Count == 0 ? 
                              Parse.Err("There are no lines after the END "
                              "statement"._No_DATA) ;
                         Check_var_abandoned_deprecated(v) ==> ;
                ;
                c = c.Base_ ; .
        */
        public Variable Search_var(string Name)
        {
            foreach (Variable v in Local_var)
            {
                if (v.Names.Contains(Name))
                    return v;
            }
            if (Modifiers[(int)Fun_mod.STATIC]) return null;
            Type c = comp(Parse).Current_class;
            while (c != null)
            {
	            foreach (Variable v in c.Field)
	            {
	                if (v.Names.Contains(Name))
	                    return v;
	            }
	            c = c.Base_;
            } 
            return null;
        }

        /*
                
        METHOD Check_var_abandoned_deprecated(
        {Var} V|ariable)
            :
            CASE V.Modifiers['ABANDONED_FIELD'] ?
                 Parse.Err("Field"._Efield " " V.Names[0] 
                 " " ( "is abandoned, use"._Eis1 ) ": " V.Deprecate)
            ;
            CASE V.Modifiers['DEPRECATED_FIELD'] ?
                 Parse.Warn("Field"._Wfield2 " " V.Names[0] 
                 " " ("is deprecated, use"._Wis2 ) ": " V.Deprecate)
            ; .
            
		METHOD Warn_about_deprecated :
			CASE !Modifiers['DEPRECATED_FUN'] ? ==> ;
			
			CASE comp(Parse).Current_fun != THIS
				 && comp(Parse).Current_fun.Modifiers['DEPRECATED_FUN']
				 ? ==>
			;
			CASE Warned_about_deprecated ? ==> ;
			Warned_about_deprecated = TRUE
			CASE comp(Parse).Do_not_show_platform_dependent
				 && "platform" IN Deprecate.Lower
				 ?
			     ==> ;
			CASE " " IN Deprecate ?
			     STR w|arning_message = "Function is deprecated"._WFunDeprecated1 
			ELSE w = "Function is deprecated, use"._WFunDeprecated ;
		    w = w ": " Deprecate 
		    w = w " -- " Whole_name
			Parse.Warn(w) .
            	
		{Type} Operator_classes_|list_defined_in_OPERATORS_modifier_[]
		
		METHOD Overloaded_on_which_fun ==> {Fun} :
			INT i|ndex_in_methods = Class.Method[].Find(THIS)
			FOR j INDEXING {Fun} IN [i-1 DOWNTO 0] :
			    CASE Class.Method[j].Overloaded_[].Count > 0 ?
			         RESULT = Class.Method[j] ==> ;
			; .
            	
		METHOD Search_operator(
		{Expr}.{bin} Op|eration,
        {Expr} A|_operand,
        {Expr} B|_operand) ==> {Fun}
        	:
        	{Fun} base_fun|ction = THIS
			CASE Overload_base_!=NONE ?
			     base_fun = Overloaded_on_which_fun ;
			FOR c IN base_fun.Operator_classes_[] :
			    RESULT = c.Search_operator(Op, A, B)
			    CASE RESULT != NONE ? ==> ;
        	; .
        
        INT Count_not|_operations
        

        
        METHOD Find_local_var|iable(
            STR Name|_of_variable,
            BOOL Case|_sensitive) ==> {Var}
            :
            CASE !Case ? STR name_low|ered = Name.Lower ;
            FOR v IN Local_var[] :
                CASE Case && Name IN v.Names[] ? 
                     v.Count_ref += 1
                     RESULT = v ==> ;
                CASE Case ? CONTINUE v ;
                v.Provide_names_lowered
                CASE name_low IN v.Names_low[] ?
                	 v.Count_ref += 1
                	 CASE v.In_local_ != Current_local ? 
                	      Parse.Err("Using local variable defined in the LOCAL "
                	      "block out of the block"._ELocalOutOfBlock) ;
                	 RESULT = v ==> ;
            ; .
        
        ENUM {fun_mod|ifier}:
             'RECURSIVE_FUN|CTION',
             'NEW|_INSTANCE_RETURNING',
             'NATIVE_FUN|CTION',
             'STATIC|_FUNCTION', 
             'REPLACE|_OVERRIDE_METHOD',
             'OPTIONAL|_BASE_FUNCTION',
             'DEPRECATED_FUN|CTION',
             'ABANDONED_FUN|CTION',
             'CALLBACK|_FUNCTION',
             'HANDLER|_CAN_CALL_CALLBACK_DIRECTLY',
             'UNCOOKED|_NOT_IMPLEMENTED',
             'PUBLIC|_FORCE',
             'PUSH_METHOD',
             'POP|_PUSHED_METHOD', 
             'STORE|_ADDITIONAL_INT_PARAMETER',
             'FORGET|_STORED_PARAMETERS',
			 'WAIT|_FOR_CALL_ONE_OF_METHODS',
			 'SETTER|_FOR_PREVIOUS_FUNCTION',
			 'OPERATORS|_USED_FROM_CLASSES',
			 'TRAP_FUN|CTION',
			 'INLINE|_ALWAYS',
			 'DEBUG_FUN|CTION',
             'UNSUPPORTED|_FEATURE' .

        BOOL Modifiers|_of_function[{fun_mod}]
        STR  Deprecate|d_abandoned_function_text
        INT  Restricts|_parameters_start_position
        BOOL Warned_about_deprecated|_function_used
		{Fun} Pop_method_|to_call_at_end_of_push_block_
		INT  Priority|_for_binary_operation_functions
        
        METHOD Push_method ==> {Fun} :
        	FOR m IN Class.Method[] :
        	    CASE m.Pop_method_ == THIS ? RESULT = m ==> ;
        	; .
        
		----------- 'other properties'
        STR	 Depends|_on_classes_functions_methods_listed_in_NATIVE[]
        {Var} Trap_field|_for_TRAP_FUNctions_only
        BOOL Error_if_not_inlined


        METHOD Handle_modifier, RECURSIVE :
            ---------------------------------- ''
            PUSH comp(Parse).Current_class = Parse.Class_ :
                 CASE Parse.End_of_line ? Parse.Fin ;
                INT from|_pos = Parse.Pos
                STR m|odifier_id = Parse.Ident
                CASE m ?
                ["RECURSIVE"]: {fun_mod} fm|odifier = 'RECURSIVE_FUN'
                ["NEW"]:                 fm = 'NEW'
                ["NATIVE"]:              fm = 'NATIVE_FUN'
                	CASE Parse.Symbol("(") ?
                	     handle_list_of_dependances
                	     Parse.Wait(")") ;
                ["STATIC"]:              fm = 'STATIC'
                ["OPTIONAL"]:			 fm = 'OPTIONAL'
                ["REPLACE"]:             fm = 'REPLACE'
                ["DEPRECATED"]:          fm = 'DEPRECATED_FUN'
                ["ABANDONED"]:           fm = 'ABANDONED_FUN'
                ["CALLBACK"]:            fm = 'CALLBACK'
                ["HANDLER"]:             fm = 'HANDLER'
                ["UNCOOKED"]:            fm = 'UNCOOKED'
                ["PUBLIC"]:              fm = 'PUBLIC'
                                         CASE Is_public ?
                                              Parse.Warn("Ambiguous PUBLIC: "
                                              "already is public"._Wamb )
                                         ;
                ["IF", "RESTRICT"]: Parse.Pos = from
                    check_restrictions_syntax ==>
                ["PUSH"]:				 fm = 'PUSH_METHOD'
                ["POP"]:				 fm = 'POP'
                ["STORE"]:               fm = 'STORE'
                ["FORGET"]:              fm = 'FORGET'
                ["SETTER"]:              fm = 'SETTER'
                                         CASE Modifiers[fm] ?
                                              Parse.Err( "Method can not be a "
                                              "setter more then for one "
                                              "field"._Emethod )
                                         ;
                ["OPERATORS"]:			 fm = {fun_mod}.'OPERATORS'
                ["WAIT"]:				 fm = {fun_mod}.'WAIT'
                ["TRAP"]:				 fm = 'TRAP_FUN'
                ["INLINE"]:				 fm = 'INLINE'
                ["DEBUG"]:				 fm = 'DEBUG_FUN'
            	["PRIORITY"]:			 
            	    CASE Parse.Symbol("LIKE") ? 
            	         Parse.Wait("(")
            	         STR op|eration_like = Parse.Skip_to(")") 
            	         Parse.Wait(")")
            	         Priority = Priority_by_op(op)
            		ELSE Parse.Wait("(")
            			 Priority = Parse.Number
            			 Parse.Wait(")")         
            	    ;
					CASE Param[].Count != 2 || Result == NONE ? 
        	             Parse.Err("The PRIORITY modifier is "
        	             "applicable only to 2-parameters functions "
        	             "returning a result"._EPrior2ParamResultFuncs) 
        	        ;                
        	        CASE Priority==0 ? 
        	             Parse.Warn("PRIORITY(0) replaced to default "
        	             "PRIORITY(100)"._WPriority0) 
        	        ;
        	        ==>
            	["UNSUPPORTED"]:         fm = 'UNSUPPORTED'
                ELSE Parse.Err("Unknown modifier"._Eunk ": " m) ==> 
            	;
                CASE Modifiers[fm] ? Parse.Warn("Duplicating modifier"._Wdup 
                                     " " fm.Name)
                ;
                Modifiers[fm] = TRUE
                CASE fm ?
                ['RECURSIVE_FUN']:  Class.Detect({Type}.{class_mod}.'RECURSIVE')
                ['NATIVE_FUN']:     NONE
                ['NEW', 'UNCOOKED', 'PUBLIC']: NONE
                ['CALLBACK', 'HANDLER']: NONE
                ['STATIC']: 
                            CASE Ancestor_ != NONE ?
                                 Parse.Err("It is not possible to OVERRIDE "
                                 "a static function"._Eitis )
                            ;
                ['OPTIONAL']: NONE
                ['REPLACE']:
                            CASE Ancestor_ == NONE ?
                                 Parse.Err("Defining REPLACE for a function "
                                 "without prototype in ancestor "
                                 "classes"._Edef)
                            ;
                ['DEPRECATED_FUN', 'ABANDONED_FUN', 'UNSUPPORTED']:
                               Parse.Wait("(")
                               Parse.Wait("'")
                               from = Parse.Pos
                               NONE = Parse.Skip_to("'")
                               
                               Deprecate = Parse.Source[Parse.Line].[
                                    from TO Parse.Pos-1]
                                    
                               Parse.Wait("'")
                               Parse.Wait(")")
                               ---------- 'check only one such modifier present'
                               INT mut|ually_exclusive = 0
                               CASE Modifiers['DEPRECATED_FUN'] ? mut += 1 ;
                               CASE Modifiers['ABANDONED_FUN'] ? mut += 1 ;
                               CASE Modifiers['UNSUPPORTED'] ? mut += 1 ;
                               CASE mut > 1 ?
                                    Parse.Err("Function can be either abandoned"
                                    " or deprecated or unsupported, "
                                    "exclusively"._Efun )
                               ;
                ['PUSH_METHOD']: NONE
                ['POP']: Parse.Wait("(")
                         STR push_name = Parse.Ident
                         {Type} cc|lass_current = comp(Parse).Current_class 
                         {Fun} push_method = Class.Find_fun(push_name, TRUE)
                         CASE cc.Last_fun != (
                              push_method)
                              ?
                              Parse.Err("POP-method should be declared just "
                              "following a correspondent PUSH-method"._Epop)
                         ;
                         CASE !push_method.Modifiers['PUSH_METHOD'] ?
                              Parse.Err("Method"._Emethod6 
                              " " push_method.Whole_name 
                              " " ("is not marked with a modifier "
                              "PUSH"._Eisnotmarked ))
                         ;
                         push_method.Pop_method_ = THIS
                         Parse.Wait(")")
                         CASE Param[].Count > 0 ?
                              Parse.Err("POP-method must not have "
                              "parameters"._Epop2 )
                         ;
                ['STORE']: 
                        CASE Stored_param != NONE ?
                             err("Only one STORE parameter is allowed"._Eonly )
                        ;
                        Parse.Wait("(")
                        -------------------------- 'stored parameter name(s)'
                        Stored_param = {Var}(Line = Parse.Line, 
                             Type_ = comp(Parse).TYPE_INT, In_fun_= THIS,
                             Is_param = TRUE, Is_stored_param = TRUE,
                             Initial_ = comp(Parse).EM1)
                             
                        Parse.Scan_names(Stored_param.Names[], "")
                        FOR n IN Stored_param.Names[] :
                            CASE n !IN all_id[] ? CONTINUE n ;
                            err("Duplicating parameter name"._Edup ": " n)
                            all_id[] << n ;
                        Parse.Check_names(Stored_param.Names[])
                        Parse.Check_reserved(Stored_param.Names[])
                        
                        ------------------- 'indexing of Stored_param'
                        CASE Parse.Symbol("INDEXING") ?
                             CASE Parse.Symbol("(") ?
                              Stored_param.Type_indexing = Parse.Skip_to(")")
                              Parse.Wait(")")
                        	 ELSE Stored_param.Type_indexing = Parse.Scan_type
                        	 ;
                        ;
                        -------------------------------- 'initial value ?'
                        CASE Parse.Symbol("=") ? 
                             Stored_initial_value = Parse.Integer
                              
                             {Expr} e_stored = {Expr}(Operation='CONST', 
                             	Var_arg= {Var}(Is_const=TRUE, Line=0,
                             	Type_= comp(Parse).TYPE_INT,
                             	Int_c = Stored_initial_value)), OWNED BY THIS
                             	
                             Stored_param.Initial_ = e_stored ;
                        Parse.Wait(")")
                ['FORGET']: 
                        CASE Result != NONE ?
                             err("Function returning results should not "
                             "have the FORGET modifier"._Efun1 )
                        ;
                ['SETTER']: Parse.Wait("FOR")
                			CASE Parse.Symbol(".") ?
                			     Parse.Wait("[")
                			     Parse.Wait("]")
                			     setup_setter(".")
                			ELSE setup_setter(Parse.Ident) ;
                ['OPERATORS']: Operators_modifier 
                ['TRAP_FUN']:
                		CASE ?
                		[Result != NONE] ?
                		     err("TRAP function should not return any "
                		     "result"._ETrapReturn)
                		[Param[].Count > 2] ?
                		     err("TRAP function can not accept more then 2 "
                		     "parameters"._ETrap2Params)
                		[Param[].Count == 2] ?
                		     BOOL ok_p|arameters = Param[0].Type_n == "INT"
                		     
                		     ok_p ||= Param[0].Type_n == "{bool}" && (
                		 		Param[1].Type_n == "INT")
                		 		
                		     ok_p &&= Result == NONE
                		 		
                		     CASE !ok_p ?
                		     err("TRAP function accepting two parameters "
                		      "should have either the first parameter of type "
                		      "INT (used as an index in an array) or "
                		      "the first BOOL and the second INT"._ETrapIndex
                		      " " ("but"._but) ":(" Param[0].Type_.Kind.Name
                		      ", " Param[1].Type_.Kind.Name ")")
                              //" " if(Result != NONE, "and should not retur "
                              //"a result"._ETrapWriteWithResult)
                		     ;
                		;
                ['WAIT']:	Parse.Wait("(")
                            FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                                Wait_names_f[] << Parse.Ident
                                CASE !Parse.Symbol(",") ? BREAK i ;
                            ;
                            Parse.Wait(")")
                ['DEBUG_FUN']: NONE
                ['INLINE']:
                			CASE Parse.Symbol("(") ?
                			     Parse.Wait("TRUE")
                			     Parse.Wait(")")
                			     Error_if_not_inlined = TRUE ;
                ;
                ------------------------------ 'incompatible pairs of modifiers'
                CASE Modifiers['NATIVE_FUN'] && Modifiers['RECURSIVE_FUN'] ?
                     err("Native function recursion can not be "
                     "controlled"._Enat)
                ;
                CASE Modifiers['POP'] && Modifiers['STATIC'] ?
                     Parse.Err("Static function can not have modifier "
                     "POP"._Estat)
                ;
                CASE Modifiers['STORE'] && Modifiers['STATIC'] ?
                     Parse.Err("Static function can not have STOREd "
                     "parameters"._Estat2)
                ;
                CASE Modifiers['FORGET'] && Modifiers['STATIC'] ?
                     Parse.Err("Static function can not be used to FORGET "
                     "STOREd parameters of an object"._Estat3)
                ;
                CASE Modifiers['FORGET'] && Modifiers['REPLACE'] ?
                     Parse.Err("Method which REPLACEs its ancestor can not be "
                     "used to FORGET STOREd parameters"._Emethod3)
                ;
                CASE Modifiers['STATIC'] && Modifiers['SETTER'] ?
                     Parse.Err("Static function can be declared as a "
                     "setter"._Estat4) ;
                CASE Modifiers['STATIC'] && (Modifiers['REPLACE'] 
                     || Modifiers['OPTIONAL']) 
                     ? 
                     Parse.Err("Modifiers REPLACE/OPTIONAL are not appropriate "
                     "for a static function"._Estat5) ;
                -------------------------- 'INLINE and ...'
                CASE Modifiers['INLINE'] && Modifiers['RECURSIVE_FUN'] ?
                     Parse.Err("Recursive function can not be INLINE"._Erecur) 
                ;
                CASE Modifiers['INLINE'] && Modifiers['NATIVE_FUN'] ?
                     Parse.Err("Native function can be declared INLINE"._Enativ)
                ;
                CASE Modifiers['INLINE'] && Modifiers['NEW'] ?
                     Parse.Err("NEW function (returning new objects created) "
                     "can not be declared INLINE"._Enew4) ;
            ; .
            
        FUN Priority_by_op|eration(STR Op|eration_as_string) ==> INT :
            CASE Op.Trim.Upper ? 
            ["<", "<=", ">", ">=", "==", "!=", "<>"]: RESULT = 100
            ["LIKE", "!LIKE"]: RESULT = 100
            ["IN", "!IN"]: RESULT = 100
            [""]: RESULT = 200
            ["||", "OR"]: RESULT = 300
            ["&&", "AND"]: RESULT = 400
            ["|"]: RESULT = 500
            ["&", "^"]: RESULT = 600
            ["+", "-"]: RESULT = 700
            ["*", "/", "%"]: RESULT = 800 ; .
            
        METHOD Operators_modifier :
        	Parse.Wait("(")
    		FOR dummy IN [Parse.Pos TO Parse.Last] :
    			STR sc|anned_class = Parse.Scan_type
    			
    			{Type} cl|ass_listed 
    				= comp(Parse).Current_class.Find_type(sc)
    			
    			CASE cl.Kind != 'CLASS' ?
    			     Parse.Err("Only classes should be listed in "
    			     "the OPERATORS(...)"._EOnlyClasses)
    			;
    			Operator_classes_[] << cl
    			CASE !Parse.Symbol(",") ? BREAK dummy ;
    		;
    		Parse.Wait(")") .

        
		METHOD handle_list_of_dependances:
			FOR i|dummy IN [0 TO Parse.Last]:
			    CASE Parse.End_of_line ? ==> ;
				STR s|ingle_dependance = Parse.Scan_type
				{Type} t|ype_scanned = Class.Find_type(s)
				CASE t.Kind != 'CLASS' ?
				     Parse.Err("Waiting for class name"._EWaitClass ": " s) ;
				CASE Parse.Symbol(".") ?
				     STR id|entifier_method_name = Parse.Ident
				     s = s "." id ;
				Depends[] << s
				CASE !Parse.Symbol(",") ? ==> ;
			; .
			
        METHOD setup_setter( STR F|or_variable_or_function ) :
            CASE Class.Last_var != NONE ?
                 CASE Param[].Count != 1 ?
                      Parse.Err("Setter for a field should have single "
                      "parameter"._Esett)
                 ;
                 Getter_field_ = Class.Last_var
                 CASE F !IN Getter_field_.Names[] ?
                      Parse.Err("Last declared field"._Elast " "
                      "" Getter_field_.Whole_name 
                      " " ("is not matching to"._Eisnot2 ) " " F)
                 ;
                 CASE Getter_field_.Type_n != Param[0].Type_n ?
                      Parse.Err("Setter of type"._Esett2 " " Param[0].Type_n
                      " " ("is not applicable to a field of type"._Eisnot3 ) 
                      " " Getter_field_.Type_n )
                 ;
                 CASE Param[0].Is_array ?
                      Parse.Err("Setter for a field can not handle an array "
                      "as a parameter"._Esett3 )
                 ;
                 Getter_field_.Setter_method_ = THIS ==> ;
            CASE Class.Last_fun != NONE ?
                 Getter_method_ = Class.Last_fun
                 ----------------------------------- 'setter should be next'
                 CASE F !IN Getter_method_.Names[] ?
                      Parse.Err("Last declared method"._Elast2 " "
                      "" Getter_method_.Whole_name 
                      " " ("is not matching to"._Eisnot4 ) " " F) ;
                 ----------------------------------- 'parameters, types'
                 CASE Param[].Count != Getter_method_.Param[].Count+1 ?
                      Parse.Err("Setter should have number of parameters "
                      "equal to number of parameters of a getter plus "
                      "one"._Esett4)
                 ;
                 CASE Getter_method_.Result == NONE ?
                      Parse.Err("Getter method"._Egett " " F 
                      " " ("has not a result"._Ehasnot ) )
                 ;
                 CASE Getter_method_.Result.Type_n != Param[*].Type_n ?
                      Parse.Err("Getter method result type"._Egett2 " "
                      "" Getter_method_.Result.Type_n " " ("is not matching "
                      "setter last parameter type"._Eisnot5 )
                      " " Param[*].Type_n)
                 ;
                 CASE Param[*].Is_array ?
                      Parse.Err("Setter should not handle an array as the last "
                      "parameter"._Esett5 )
                 ;
                 FOR i IN [0 TO Param[].Count-2] :
                     CASE Param[i].Type_n != Getter_method_.Param[i].Type_n ?
                          Parse.Err("All the parameters of a getter and a "
                          "setter should have the same data types (except the "
                          "last setter parameter)"._Eall ) ;
                 ;
                 Getter_method_.Setter_ = THIS ==> ;
                 
            Parse.Err("Setter must be declared just after the "
            "field / function to which it is used as a setter"._Esett6 ) .
		
		METHOD check_restrictions_syntax :
            ------------------ 'RESTRICT x IN [...], IF y IN ..., THEN z IN ...'
            Restricts = Parse.Pos
            BOOL then_w|aiting_for = FALSE
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                CASE then_w ? Parse.Wait("THEN")
                            then_w = FALSE
                ELSE STR k|ey_word = Parse.Ident
                     CASE k ?
                     ["RESTRICT", "THEN"]: then_w = FALSE
                     ["IF"]: then_w = TRUE
                     
                     ELSE Parse.Err("RESTRICT modifiers should be the last in "
                     "a list of function modifiers"._Erestrict )
                     ;
                ;
                check_restriction_1
                CASE !Parse.Symbol(",") ? BREAK x ;
                CASE then_w ?
                     BOOL need_br|eak = check_restrictions_AND
                     	  need_br &&= !Parse.Symbol(",")  
                     CASE need_br ? BREAK x ;
                ;
            ; .
            
        METHOD check_restrictions_AND ==> BOOL :
            FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                CASE !Parse.Symbol("AND") ? BREAK i ;
                RESULT = TRUE
                check_restriction_1
            ; .
            
        METHOD check_restriction_1 :
            ----------------------------------- 'which parameter'
            STR n|ame_param = Parse.Ident
            {Var} p|arameter = NONE
            FOR param IN Param[] :
                CASE n IN param.Names[] ?
                     p = param
                     BREAK param ;
            ;
            CASE p == NONE ? Parse.Err("Parameter"._Eparam " " n 
                             " " ("was not defined"._Ewas) )
            ;
            CASE p.Is_array ? Parse.Err("Array parameter"._Earr 
                              " " n " " ("can not be "
                              "restricted or used for restrictions"._Ecan ))
            ;
            CASE p.Type_.Kind ?
            ['BOOL', 'INT', 'REAL', 'ENUM', 'STR']: NONE
            ['CLASS', 'STRUCTURE']: 
                 Parse.Err("Parameter"._Eparam2 
                 " " p.Whole_name " " ("can not be "
                 "restricted or used to restrict other parameters"._Ecan2 ))
            ;
            CASE ?
            [Parse.Symbol("IS")] ?
                 CASE !Parse.Symbol("CONSTANT") ?
                      Parse.Wait("CONST") ;
            [Parse.Symbol("<=")] ? NONE = real_value
        	[Parse.Symbol(">=")] ? NONE = real_value
        	[Parse.Symbol("==")] ? NONE = real_value
        	[Parse.Symbol("!=")] ? NONE = real_value
        	[Parse.Symbol("<")] ? NONE = real_value
        	[Parse.Symbol(">")] ? NONE = real_value
            ELSE
                Parse.Wait("IN")
                CASE Parse.Symbol("FLAGS") ?
                     BOOL flags|_attribute = TRUE
                ELSE flags = FALSE ;
                CASE flags && p.Type_n !IN ["INT", "INTEGER", "BYTE"] ?
                     Parse.Err("FLAGS is applicable only to INT or BYTE "
                     "parameter, but"._Eflags " " p.Whole_name 
                     " " ("type kind is"._Etype ) " " p.Type_.Kind.Name) ;
                ---------------------------- 'IN what ?'
                check_contained_in_syntax(p, flags)
            ; .
            
            
        METHOD check_contained_in_syntax(
            {Var} P|arameter,
            BOOL Flags|_attribute)
            :
            check_contained_in1(P, Flags)
            Parse.Skip_sp
            CASE Parse.Next_char != "," ? ==> ;
            FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                INT was|_position = Parse.Pos
                BOOL or_foll|owed = Parse.Symbol(",")
                	 or_foll &&= Parse.Symbol("OR")  
                CASE or_foll ?
                     Parse.Wait("IN")
                     check_contained_in1(P, Flags)
                ELSE Parse.Pos = was ;
            ; .
            
        
        METHOD check_contained_in1(
        	{Var} P|arameter, BOOL Flags|_attribute)
        	:
            --------------------------------- '{named set of constants}'
            CASE P.Type_n IN ["INT", "INTEGER", "BYTE", "STR", "STRING"] && (
                 Parse.Symbol("{") )
                 ?
                 NONE = Parse.Ident
                 Parse.Wait("}")
                 CASE Parse.Symbol(".") ?
                      Parse.Wait("{")
                      NONE = Parse.Ident
                      Parse.Wait("}") ;
                 ==> ;
            ----------------------------------- 'values or range'
            Parse.Wait("[")
            CASE P.Type_.Kind == 'REAL' || P.Type_n == "REAL" ?
                 NONE = real_value
                 Parse.Wait("TO")
                 NONE = real_value
            ELSE list_of_values(P.Type_n, Flags) ;
            Parse.Wait("]") .
            
            
        INT line_restr|iction_error
        
        METHOD Check_actual_parameters_restrictions(
            {Expr} E|xpressions_actual_parameters[])
            :
            -------------------- 'called in {Expr} when compiling function call'
            line_restr = Parse.Line
            PUSH Parse.Line = Line_start :
            PUSH Parse.Pos = Restricts :
            PUSH Parse.Compiler.Current_class = Parse.Class_ :
                 FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                     CASE Parse.Ident ?
                     ["RESTRICT"]: restrict_param(E[], TRUE)
                     ["IF"]: conditional_restrict_param(E[])
                     
                     ELSE Parse.Err("Internal error - while scanning "
                          "restrictions for parameters: " Parse.Next20)
                     ;
                     CASE !Parse.Symbol(",") ? BREAK x ;
                 ;
            ;
            ;
            ; .
        
        METHOD conditional_restrict_param({Expr} E|xpressions[]) :
            BOOL cond|ition_satisfied = check_single_restriction(E[])
            FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                Parse.Wait(",")
                CASE !Parse.Symbol("AND") ? BREAK i ;
                CASE !check_single_restriction(E[]) ? cond = FALSE ;
            ;
            Parse.Wait("THEN")
            restrict_param(E[], cond) .
            
            
        FUN is_parameter_constant({Expr} E|xpr_actual_parameter) ==> BOOL,
            RECURSIVE
            :
            ------------------------------ 'constant or bitwise or of constants'
            CASE E.Operation == 'CONST' ? RESULT = TRUE ==> ;
            CASE E.Operation == 'BINARY' ?
                 RESULT = is_parameter_constant(E.Arg1_) 
                 RESULT &&= is_parameter_constant(E.Arg2_) ; .
            
            
        BOOL actually_restrict
            
        METHOD restrict_param({Expr} E|xpressions[], BOOL A|ctually_restrict) :
            PUSH actually_restrict = A :
                 INT at|_position = Parse.Pos
                 BOOL cond|ition = check_single_restriction(E[])
                 CASE A && !cond ?
                      PUSH Parse.Pos = at :
                           STR context|_error = Parse.Next20
                           PUSH Parse.Line = line_restr :
                                Parse.Err("Restriction is not satisfied for a "
                                "parameter"._Erestrict2 ": " context) ;
                      ;
                 ;
            ; .
            
            
        METHOD check_single_restriction({Expr} E|xpressions[]) ==> BOOL :
            ---------------------------- 'E[] - array of actual parameters'
            STR n|ame_param = Parse.Ident 
            FOR par IN Param[] :
                CASE n IN par.Names[] ?
                     INT index|_parameter INDEXING {Expr} = par.Index 
                     {Var} p|arameter_variable = par
                     BREAK par ;
            ;
            CASE p == NONE ?
                 Parse.Err(n 
                 " " ("is not a parameter to restrict it"._Erestrict3 ))
        	;
            CASE Parse.Symbol("IS") ?
                 CASE !Parse.Symbol("CONSTANT") ?
                      Parse.Wait("CONST") ;
                 CASE E[index].Operation == 'CONSTANT' ?
                      RESULT = TRUE ==> ;  
                 CASE actually_restrict ?
                      PUSH Parse.Line = line_restr :
                           Parse.Err("Parameter"._Eparam3 " " n 
                           " " ("is restricted but not a constant was passed "
                           "in place"._Eis3 ) 
                           " (" E[index].Operation.Name ")") ==> ;
                 ;
                 ==>
            ;
            BOOL or_result = FALSE
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                CASE ?
                [Parse.Symbol("<=")] ? STR rel|ation_sign = "<="
                [Parse.Symbol(">=")] ? rel = ">="
                [Parse.Symbol("<")] ? rel = "<"
                [Parse.Symbol(">")] ? rel = ">"
                [Parse.Symbol("!=")] ? rel = "!="
                [Parse.Symbol("==")] ? rel = "==" ;
                CASE rel != "" ?
                     CASE actually_restrict && (
                          E[index].Operation != 'CONSTANT')
                          ?
                          error_param_not_const(n, E[index].Operation.Name, 
                            line_restr)
                     ;
                     RESULT = or_result || check_relation(p, E[index], rel)
                ELSE
                    ------------------------------------ 'IN [...]'
                    Parse.Wait("IN")
                    CASE Parse.Symbol("FLAGS") ?
                         BOOL any|_flag_is_accepted = TRUE ;
                    CASE !any && actually_restrict && (
                         E[index].Operation != 'CONSTANT')
                         ?
                         error_param_not_const(n, E[index].Operation.Name,
                            line_restr)
                    ;
                    RESULT = or_result || check_single_IN_list(p, E[index], any)
                ;
                ---------------------------------- ', OR IN ... , OR IN ... ...'
                Parse.Skip_sp
                CASE Parse.Next_char != "," ? ==> ;
                INT was|_position = Parse.Pos
                CASE Parse.Symbol(",") ?
                     CASE Parse.Symbol("OR") ?
	                      or_result = RESULT
	                      CONTINUE x ;
                ;
                DONE
	                 Parse.Pos = was ==>
            ; .
            
        METHOD error_param_not_const(
            STR N|ame_of_parameter,
            STR OName|_operation,
            INT Line_restr|iction)
            :
            PUSH Parse.Line = Line_restr :
                 Parse.Err("Parameter"._Eparam4 " " N 
                 " " ("is restricted but not a constant was passed in "
                 "place"._Eis4 ) " (" OName ")" ) ; .

            
        METHOD check_relation(
            {Var} P|arameter_var,
            {Expr} E|expression,
            STR Rel|ation) ==> BOOL
            :
            CASE P.Type_.Kind == 'REAL' ?
                 REAL val|ue_to_compare = E.Var_arg.Real_c
                 REAL n1|_bound = real_value
                 CASE Rel ?
                 ["<"] : RESULT = val < n1
                 ["<="]: RESULT = val <= n1
                 [">"] : RESULT = val > n1
                 [">="]: RESULT = val >= n1
                 ["==", "!="]: //RESULT = val == n1
                    Parse.Err("It is not allowed to compare real values using "
                    "== and != operations"._Eitisnotallowed)
                 //["!="]: RESULT = val != n1
                 ;
                 ==> ;
            CASE P.Type_.Kind == 'INT' ?
                 INT ival|ue_to_compare_integer = E.Var_arg.Int_c
                 INT n2|_bound = Parse.Integer
                 CASE Rel ?
                 ["<"] : RESULT = ival < n2
                 ["<="]: RESULT = ival <= n2
                 [">"] : RESULT = ival > n2
                 [">="]: RESULT = ival >= n2
                 ["=="]: RESULT = ival == n2
                 ["!="]: RESULT = ival != n2 ;
                 ==> ;
                 
            Parse.Err("Parameter of type kind"._Eparam7 
                " " P.Type_.Kind.Name " " ("is not applicable for "
                          "operation"._Eisnot18 ": '" Rel "'" )) .
            
        METHOD check_single_IN_list(
            {Var} P|arameter_var,
            {Expr} E|expression,
            BOOL Any|_flag_accepted) ==> BOOL
            :
            -------------------------------- 'IN {named set of constants} ?'
            CASE P.Type_.Kind IN ['INT', 'STR'] && Parse.Symbol("{") ?
                 STR set_names[]
                 collect_set_names(set_names[])
                 Parse.Wait("}")
                 {Type} wclass|_where_search = Class
                 CASE set_names[].Count == 1 && Parse.Symbol(".") ?
                      wclass = Class.Find_type(set_names[0])
                      set_names[].Clear
                      Parse.Wait("{")
                      collect_set_names(set_names[])
                      Parse.Wait("}") ;
                 {Type} sets_of_const|ants[]
                 FOR set IN set_names[] :
                     sets_of_const[] << wclass.Find_set_of_constants(set) ;
                 RESULT = check_const_in_sets(E, sets_of_const[], Any) 
                 ==> ;
            ---------------------------------- 'IN [range or list of values] ?'
            Parse.Wait("[")
            CASE P.Type_.Kind == 'REAL' ?
                 ----------------------------- 'IN [x TO y] (range)'
                 REAL n1|_bound = real_value
                 Parse.Wait("TO")
                 REAL n2|_bound = real_value
                 CASE E.Var_arg.Type_.Kind == 'REAL' ?
                      REAL val|ue_to_compare = E.Var_arg.Real_c
                 ELSE val = E.Var_arg.Int_c ;
                 RESULT = val >= n1 && val <= n2
                 Parse.Wait("]") ==> ;
            -------------------------------- 'IN [x1, x2, ...] (list of values)'
            INT n_item|_counter = 0
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                n_item += 1
                CASE P.Type_.Kind ?
                ['BOOL']: 
                        CASE Parse.Symbol("TRUE") ?
                             BOOL bool_val = TRUE 
                        ELSE Parse.Wait("FALSE") ;
                        CASE (E.Var_arg.Int_c != 0) == bool_val ?
                             RESULT = TRUE ;
                ['INT']:
                        Parse.Skip_sp
                        CASE Parse.Next_char IN "-+0123456789" ?
                             INT num|ber_scanned = Parse.Integer
                        ELSE {Var} c|onstant = find_int_const
                             num = c.Int_c ;
                        CASE Parse.Symbol("TO") ?
                             RESULT ||= check_int_range(
                                          num, E.Var_arg.Int_c)
                             BREAK x ;
                        CASE !Any && num == E.Var_arg.Int_c ? 
                             RESULT = TRUE ;
                        CASE Any && number_present_in_flags(num, E) ?
                             RESULT = TRUE ;
                ['ENUM']: 
                        Parse.Wait("'")
                        STR item|_name = "'" Parse.Ident "'"
                        Parse.Wait("'")
                        {Var} en|um_item = P.Type_.Find_enum_item(item)
                        CASE E.Var_arg.Int_c == en.Int_c ?
                              RESULT = TRUE ;
                ['STR']:
                        STR s|tring_val = Scan_string_const(10)
                        CASE s == E.Var_arg.Str_c ? RESULT = TRUE ;
                        
                ['REAL', 'CLASS', 'STRUCTURE']: 
                        Parse.Err("Parameter of type kind"._Eparam5 
                        " " P.Type_.Kind.Name " " ("is not applicable for IN "
                        "operation"._Eisnot6 ))
                ;
                CASE ! Parse.Symbol(",") ? BREAK x ;
            ;
            Parse.Wait("]") .
            
        METHOD real_value ==> REAL :
			CASE Parse.Next_symbol("0x") ?
				 RESULT = Parse.Integer ==> ;
            RESULT = Parse.Real_number .
            
            
        FUN check_const_in_sets({Expr} E|xpression_to_check,
            {Type} Sets_of_const|ants[], BOOL Any|_flag_is_ok) ==> BOOL
            :
            FOR s IN Sets_of_const[] :
                FOR c_item IN s.Items[] :
                    INT num|_value = c_item.Int_c
                    CASE !Any && num == E.Var_arg.Int_c ?
                         RESULT = TRUE ==> ;
                    CASE Any && number_present_in_flags(num, E) ?
                         RESULT = TRUE ==> ;
                ;
            ; .
        


        METHOD collect_set_names( STR Set_names[] ) :
            FOR pos|dummy IN [Parse.Pos TO Parse.Last] :
                Set_names[] << "{" Parse.Ident "}"
                CASE ! Parse.Symbol(",") ? BREAK pos ;
            ; .
            
            
        METHOD check_int_range( INT N1|_first_number_of_range, 
            INT C|onst_param_value_to_check) ==> BOOL
            :
            ---------------------------------------- 'IN [N1 TO ... '
            CASE Parse.Next_char IN "-+0123456789" ?
                 INT n2|_second_number_of_range = Parse.Integer
            ELSE {Var} c|onstant = find_int_const
                 n2 = c.Int_c ;
            RESULT = C >= N1 && C <= n2 .
             
            
            
            
        FUN number_present_in_flags( INT N|umber_search, 
            {Expr} E|xpression ) ==> BOOL, RECURSIVE
            :
            --------------------- 'E is in form X | Y | ... && N in [X, Y, ...]'
            CASE E.Operation == 'CONST' ?
                 RESULT = N == E.Var_arg.Int_c ==> ;
            CASE E.Operation == 'BINARY' ?
                 RESULT = E.Sign == 'OR_B'
                 CASE RESULT ? 
                      RESULT = number_present_in_flags(N, E.Arg1_) 
                      RESULT ||= number_present_in_flags(N, E.Arg2_) ; 
            ; .

                    
            
        METHOD find_int_const ==> {Var} :
            CASE Parse.Symbol("{") ?
                 STR iclass|_name = "{" Parse.Ident "}"
                 Parse.Wait("}")
                 {Type} t|ype_where_search = Class.Find_type(iclass)
                 Parse.Wait(".")
                 STR id|entifier = Parse.Ident
                 RESULT = t.Search_const(id, FALSE)
            ELSE id = Parse.Ident 
                 RESULT = Class.Search_const(id, TRUE) ;
            CASE RESULT == NONE ?
                 PUSH Parse.Line = line_restr :
                      CASE iclass != "" ?
                           Parse.Err("Constant"._Econst " " iclass "." id 
                           " " ("is not defined"._Eisnot7 ))
                      ELSE Parse.Err("Constant"._Econst2 " " id 
                           " " ("is not defined"._Eisnotdef )) ;
                 ;
            ; .
                
                
        METHOD list_of_values(
        STR T|ype_name, BOOL Flags|_attribute_dummy )
            :
            INT n_item|_counter = 0
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                n_item += 1
                CASE T ?
                ["BOOL", "BOOLEAN"]: 
                        CASE !Parse.Symbol("TRUE") ?
                             Parse.Wait("FALSE") ;
                ["BYTE"]: waiting_byte
                          CASE n_item == 1 && Parse.Symbol("TO") ?
                               waiting_byte ==> ;
                ["INT", "INTEGER"]:
                          waiting_int
                          CASE n_item == 1 && Parse.Symbol("TO") ?
                               waiting_int ==> ;
                ["STR", "STRING"]:  NONE = Scan_string_const(11)
                ELSE Parse.Wait("'")
                     NONE = Parse.Ident
                     Parse.Wait("'") ;
                CASE ! Parse.Symbol(",") ? ==> ;
            ; .
            
            
            
            
        METHOD waiting_byte|_value :
            INT n|umber_got = Parse.Number
            CASE n < 0 || n > 255 ?
                 Parse.Err("Value"._Evalue " " n.Str 
                 " " ("is out of bounds"._Eis5 )) ; .
        
        METHOD waiting_int|eger_constant :
            Parse.Skip_sp
            
            CASE Parse.Next_char IN "-+0123456789" ?
                 INT n|_value_dummy = Parse.Integer ==> ;
            CASE Parse.Symbol("{") ?
                 STR t|ype_name = "{" Parse.Ident "}"
                 Parse.Wait("}")
                 NONE = Class.Find_type(t)
                 Parse.Wait(".") ;
            NONE = Parse.Ident .
        
        */
        public enum Fun_mod { RECURSIVE, NEW, NATIVE, STATIC, CONST, CALLBACK };
        public bool[] Modifiers = new bool[(int)Fun_mod.CALLBACK + 1];

        public void Handle_modifier()
        {
            string m = Parse.Ident().ToUpper();
            bool sw_ok = false;
            if (m != "")
                switch (m[0])
                {
                    case 'R':
                        if (m == "RECURSIVE")
                        {
                            sw_ok = true;
                            Modifiers[(int)Fun_mod.RECURSIVE] = true;
                        }
                        break;
                    case 'N':
                        if (m == "NEW")
                        {
                            sw_ok = true;
                            Modifiers[(int)Fun_mod.NEW] = true;
                        }
                        else if (m == "NATIVE")
                        {
                            sw_ok = true;
                            Modifiers[(int)Fun_mod.NATIVE] = true;
                        }
                        break;
                    case 'C':
                        if (m == "CONST" || m == "CONSTANT")
                        {
                            sw_ok = true;
                            Modifiers[(int)Fun_mod.CONST] = true;
                        }
                        break;
                    case 'S':
                        if (m == "STATIC")
                        {
                            sw_ok = true;
                            Modifiers[(int)Fun_mod.STATIC] = true;
                        }
                        break;
                }
            if (!sw_ok)
                comp(Parse).Error("Unknown modifier: " + m);
        }

        /*
        {Statement} Nesting|_statement_level[]
        BOOL has_new|_objects_assigned_to_result
        BOOL Calls_base|_method
        
        {Assign} Assignments_to_RESULT[]
        //BOOL already_compiled

        METHOD Compile|_function_code :
            //DEBUG:
            //    CASE "create_control" IN Names[] ?
            //         << "compiling function " Names[*] " in class "
            //            "" Class.Names[].Whole_name #NL
            //         >> STR dummy_input ;
            //;
            CASE Overloaded_[].Count > 0 ? ==> ;
            Block[].Clear
            all_id[].Clear
            Last_expr = NONE
            Last_fun_ = NONE
            FOR i IN [Local_var[].Count-1 DOWNTO 0] :
                CASE Local_var[i].Is_param ? CONTINUE i ;
                CASE Local_var[i].Line == -1 ?
                     //DEBUG:
                     //      CASE Local_var[i].Names[0] == "X__extr_tmp_286" ?
                     //           >> ;
                     //;
                     Local_var[].Delete(i) ;
            ;
			------------------------------- 'set current class'
        {Compiler} c|ompiler = comp(Parse) 
        PUSH c.Current_class = Class :
        PUSH Parse.Line = Line_start :
            {Type} cc|urrent_class = comp(Parse).Current_class
            CASE c.Verbose2 ?
                 << "compiling fun"._Mcomp 
                    ": " cc.Names[0] "." Whole_name
                    ", Line_start = " Line_start.Str 
                    ", Line_end = " Line_end.Str
                    ", Total_fn = " Total_fn.Str #NL ;
			------------------------------- 'WAIT functions'
			FOR wn IN Wait_names_f[] :
				NONE = Class.Find_fun(wn, TRUE) ;
			-------------------------- 'check list of dependances NATIVE(...)'
			FOR dep IN Depends[] :
			    CASE "." !IN dep ? CONTINUE dep ;
			    STR tname|_of_class = dep.[0 TO dep.Find(".")-1]
			    {Type} cdep|end_on_class = Class.Find_type(tname)
			    STR fname|_of_function = dep.[dep.Find(".")+1 TO *]
			    {Fun} f|unction_depend_on = cdep.Find_fun(fname, TRUE)
			    CASE f.Class != cdep ?
			         Parse.Err("Function is located not in the class "
			         "specified"._EFunNotInClass ": " f.Class.Names[0] 
			         "." f.Whole_name) ;
			;
			------------------ 'add from DEBUG IMPORT'
			INT was_imp_count|_imported_classes INDEXING {Type} 
			was_imp_count = cc.Import_[].Count
			CASE Modifiers['DEBUG_FUN'] ?
	             FOR di IN cc.Debug_import_[] : cc.Import_[] << di ;
			;
            ------------------------------ 'compile function'
			compile_function
            ------------------------------ 'restore import'
            FOR ii IN [cc.Import_[].Count-1 DOWNTO was_imp_count] :
                cc.Import_[].Delete(ii) ;
                			
			------------------------------- 'rest Waiting_[] ?'
			FOR w IN Waiting_[] :
				CASE !(w == NONE && Waiting_[w.Index+1] != NONE) ?
					 CONTINUE w ;
				INT line|_from = Lines_waiting[w.Index]
				STR gr|oup_of_waiting_methods = ""
				FOR i_w IN [w.Index+1 TO Waiting_[].Count-1] :
					CASE Waiting_[i_w] == NONE ? BREAK i_w ;
					gr = gr Waiting_[i_w].Whole_name ", " ;
				gr = gr.[0 TO *-2]
				CASE "," IN gr ?
					 Parse.Err(
                     "It was waiting for call of a function from list"._Eitwas
					 ": " gr " " ("in the"._Ein ) " " Whole_name 
					 " (" ("from line"._Efrom ) " " line.Str ")")
				ELSE Parse.Err(
                     "It was waiting for call of the function"._Eitwas2
                     " " gr " " ("in the"._Ein2 ) " " Whole_name
					 " (" ("from line"._Efrom2 ) " " line.Str ")") ;
			;
			Waiting_[].Clear
			Lines_waiting[].Clear
            -------------------- 'if BASE call is last, check there are no ==>'
            CASE Ancestor_ != NONE && calls_base_method(Block[]) && ! (
                 Block[0].Work == 'ASSIGN' && (
                 Block[0].{Assign}.Dest.Operation == 'FUN') && (
                 Block[0].{Assign}.Dest.Fun_ == Ancestor_) )
                 ?
                 CASE return_statements_present(Block[]) ?
                      Parse.Err("Method calling its ancestor method not in the "
                      "first statement, can not use return statements ==> "
                      "in its body"._Emethod7 ) ;
            ;
            --------------------- 'check ambiguous ==> operations'
            CASE !Modifiers['NATIVE_FUN'] ?
            	 check_ambiguous_ret(FALSE, Block[], TRUE) ;
			-------------------------------- 'verbose end message'
			CASE c.Verbose2 ?
                 << "end compiling"._Mend 
                    ": " cc.Names[0] "." Whole_name #NL; 
        ;
        ; .
        
       	METHOD check_ambiguous_ret(
       	BOOL Is_case|_statement_parent,
       	{Statement} B|lock_checking[],
       	BOOL Is_ending|_block_is), RECURSIVE
       		:
			CASE !Is_ending || B[].Count == 0 ? ==> ;
			CASE Is_case ?
			     FOR br IN B[] :
			         //CASE br.Work IN ['FOR', 'FOREVER', 'DEBUG'] && (
			         CASE br.Work IN ['FOR', 'DEBUG'] && (
			         	  br.Block_[].Count > 0)
			         	  ?
			              CONTINUE br ;
			     	 check_ambiguous_ret(FALSE, br.Block_[], TRUE) ;
			     ==>
			;
			FOR br IN B[] :
				CASE br.Work == 'RETURN' && Is_ending ?
				     PUSH Parse.Line = br.Line :
				     	  Parse.Err("Ambiguous ==> statement") ;
				;
			;
			//CASE B[*].Work IN ['FOR', 'FOREVER', 'DEBUG'] ? ==> ;
			CASE B[*].Work IN ['FOR', 'DEBUG'] ? ==> ;
			check_ambiguous_ret(B[*].Work == 'CASE', B[*].Block_[], TRUE) .
			         
			     
                    
        METHOD calls_base_method(
        {Statement} St|atement[]) ==> BOOL, RECURSIVE
        	:
            FOR s IN St[] :
                CASE s.Work == 'ASSIGN' && (
                     s.{Assign}.Dest.Operation == 'FUN') && (
                     s.{Assign}.Dest.Fun_ == Ancestor_)
                     ?
                     RESULT = TRUE ==> ;
                CASE s.Block_[].Count > 0 ?
                     RESULT = calls_base_method(s.Block_[])
                     CASE RESULT ? ==> ;
                ;
            ; .
                    
        FUNCTION return_statements_present(
        {Statement} St|atements[]) ==> BOOL,
            RECURSIVE
            :
            FOR s IN St[] :
                CASE s.Work == 'RETURN' ? RESULT = TRUE ==> ;
                CASE s.Block_[].Count > 0 ?
                     RESULT = return_statements_present(s.Block_[])
                     CASE RESULT ? ==> ;
                ;
            ; .
            
        STR all_final|_names_for_vars[]
        INT Current_level
        
        METHOD compile_native_function:
             Parse.Line = Line_start
             Parse.Pos = Pos_start
             Line_native = Parse.Line
             CASE Native_code == "" ? Native_code = Scan_string_const(12) ;
             //DEBUG:
             //ASE Names[0] == "Console_color" ?
             //    << "---------------- 1 -------------"#NL
             //    << Native_code.Replace_all(#NL, "\n"#LF#CR) >> ;
             //;
             Interprete_native_code(comp(Parse))
             --------------------------------------- '.'
             CASE Parse.End_of_line ? Parse.Fin ;
             Parse.Wait(".")  
             Line_end = Parse.Line .

             
        METHOD Interprete_native_code(
        {Compiler} Ccomp|iler)
        	:
             ---------------------------------- '/ / /copy Native_code'
             STR nlines|_of_native_code[]
             Split(nlines[], Native_code, #NL)
             FOR s IN nlines[] :
                 CASE Starting(s.Lower, "///copy") && !(
                 	  Starting(s.Lower, "///copy-"))
                 	  ?
                      s = s.["///copy ".Len TO *].Trim
                 ELSE CONTINUE s ;
                 ---------------------------- 'another file(s) to copy'
                 INT copy_n|umber_of_files_to_copy_before
                 	 = Ccomp.Copy_files[].Count
                 	 
                 INT copy_ntest|dummy = Ccomp.Copy_files_test[].Count
                 {Type} none_to_copy = NONE
                 	 
                 FOR j|dummy IN [
                  Ccomp.Copy_for_class[].Count TO copy_n-1]:
                 	 Ccomp.Copy_for_class[] << none_to_copy ;
                 	 
                 file_to_copy(s, Ccompiler, FALSE)
                 	
                 file_to_copy(s, Ccompiler, TRUE)
                 	
                 FOR i_cf|dummy IN [
                 	 Ccomp.Copy_for_class[].Count TO (
                 	 Ccomp.Copy_files[].Count-1)]:
                     Ccomp.Copy_for_class[] << Class ;
                 //DEBUG: << "/////////////////////////////////////"#NL
                 //	FOR s2 IN comp.Copy_files[] :
                 //	    << "************************************"
                 //	    << "to copy:" s2 #NL ;
                 //	FOR s2 IN comp.Copy_files_test[] :
                 //	    << "************************************"
                 //	    << "at test:" s2 #NL ;
                 //	>> ;
             ; .
             
        //{Type} Destination_type_

			
		METHOD compile_function :
			//DEBUG:
			//      CASE Names[0].Ending("CONSTRUCT")
			//           && Class.Construct != THIS 
			//           ?
			//           << "CONSTRUCT " Names[0] " is not a construct of class "
			//           	  "" Class.Whole_name >> ;
			//;
			//DEBUG: 
			//	 CASE "all_tests" IN Names[] ?
			//	      BOOL is_all_tests = TRUE
			//	      << "###############" >> STR dummy_input ;
			//;
			//DEBUG:
			//      CASE Trace_counter(1) == 19 ?
			//           << "compile_function 19: " Names[].Whole_name 
			//           " method of class " Class.Names[].Whole_name
			//           " Total_fn=" Total_fn.Str
			//           " Line_start=" Line_start.Str
			//           " Line_end=" Line_end.Str #NL ;
			//; 
			Fix_last_dest = FALSE
            -------------------------- ''
            CASE comp(Parse).Verbose3 ?
                 << "compiling function " Whole_name 
                    ", Line_start = " Line_start.Str  #NL
            ;
            {Type} cc|urrent_class = comp(Parse).Current_class
            Parse.Line = Line_start
            CASE Final_name ?
                 ["-"]: compile_native_function ==>
                 [""]: Final_name = cc.Next_final_name(Names[], TRUE) ;
            PUSH comp(Parse).Current_fun = THIS :
                Local_var[].Clear
                CASE Result != NONE ?
                     Local_var[] << Result
                     Result.Count_ref = 1
                     Result.Used_for_r = TRUE
                     CASE ?
                     [Result.Type_.Kind == 'STRUCTURE'
                      && Modifiers['NATIVE_FUN']] ?
                          Parse.Err("It is not allowed to return a structure "
                          "as a result of a native function"._EStructFromNative)
                      
                     [Ancestor_ != NONE 
                      && !Variables_compat(Result, Ancestor_.Result)] ?
                          Parse.Err("Result type is not compatible with result "
                          "type of the ancestor method"._Eresult )
                          
                     [Result.Type_.Kind != 'CLASS' && Modifiers['NEW']] ?
                          Parse.Err("Modifier NEW is applicable only for "
                          "functions returning an object of a class"
                          ""._ENewNotClass)
                          
                     ;
                ;
                ---------------------- 'parameters >> local_vars'
                CASE !Modifiers['STATIC'] ?
                    Local_var[] << {Var}(In_fun_ = THIS, Names[] << "THIS",
                        Type_ = cc, Line = Line_start, 
                        Modifiers[{var_mod}.'READ']= TRUE)
                    Local_var[*].Set_final_name("this") ;
                FOR p IN Param[] :
                    FOR n IN p.Names[] : all_id[] << n ;
                    Local_var[] << p
                    CASE p.Type_.Kind == 'STRUCTURE' && Modifiers['NATIVE_FUN']?
                         Parse.Err("It is not allowed to pass a structure to a "
                         "native function"._EStrucToNative)
                    ;
                    CASE !p.Is_array ?
                         p.Modifiers[{Variable}.{var_mod}.'READ'] = TRUE ;
                    CASE Ancestor_ != NONE && !Variables_compat(p,
                             Ancestor_.Param[p.Index])
                         ?
                         STR t1|type_name = p.Type_.Whole_name
                         CASE p.Type_.Kind == 'ENUM' ?
                              t1 = p.Type_.Base_.Whole_name "." t1 ;
                         STR t2|type_name 
                         t2 = Ancestor_.Param[p.Index].Type_.Whole_name
                         CASE Ancestor_.Param[p.Index].Type_.Kind != 'ENUM' ?
                              t2 = Ancestor_.Param[
                              	p.Index].Type_.Base_.Whole_name "." t2
                         ;
                         Parse.Err("Parameter"._Eparam6 " " p.Names[0]
                         " " ("of type"._Eof ) " " t1 
                         " (" p.Type_.Kind.Name 
                         ") " ("is not compatible with correspondent "
                         "parameter"._Eisnot8 )
                         " " Ancestor_.Param[p.Index].Names[0] 
                         " " ("of type"._Eof2) " " t2
                         " (" Ancestor_.Param[p.Index].Type_.Kind.Name ")") ;
                ;
                CASE Stored_param != NONE ?
                     Local_var[] << Stored_param ;
                ----------------------- 'do compile'
                CASE comp(Parse).Verbose3 ?
                     << "start compiling " Whole_name 
                        ", Line_start=" Line_start.Str #NL
                ;
                Parse.Line = Line_start
                Parse.Pos = Pos_start
                CASE ?
                [Result != NONE //&& Class_.Syntax_fun==":" 
                 && Parse.Symbol("=")] ?
                     BOOL short_body = TRUE
                     //PUSH Destination_type_ = Result.Type_ :
						  {Assign} a|ssign_result = {Assign}(
						  		   Line = Parse.Line, Pos= Pos_start,
				    			   Function_ = THIS, Work = 'ASSIGN', Level = 0,
				    			   Dest = {Expr}(Operation = 'VAR',
				    			  	 Var_arg = Search_var("RESULT",
				    			  		 !Parse.Case_insensitive))),
				    			   OWNED BY THIS
				    			   
                     //;
			    			  
					 a.Dest.Var_arg.Used_for_w = TRUE
					 a.Source = Recognize_typed(Parse, Result.Type_.Kind)
					 CASE ?
					 [a.Source.Operation == 'NEW_OBJ'
					  && Result.Type_.Kind == 'CLASS'
					  && a.Source.Type_expr != Result.Type_] ? 
					      Parse.Err("It is not allowed to use short "
					      "version of a function if the expression assigned "
					      "is an object creation with a type different "
					      "then the function resulting type (even derived)."
					      ""._ENotAllowShortFun)
					 [a.Source.Type_expr.Kind == 'STRUCTURE'
					  && a.Source.Operation IN ['VAR', 'FIELD', 'INDEX']] ?
					     Parse.Err("It is required to use CLONE function "
					     "while returning a structure"._ERequireCLONE)
					 ;
					 CASE a.Source.Operation == 'NEW_OBJ' 
					 	  && Result.Type_.Kind == 'CLASS'     
					      && !Modifiers['NEW']
					      ? 
					      Parse.Err("New object is returned but the function "
					      "has no modifier NEW specified"._EReturnedNewNoModif)
					 ;
					 extract_new_operations(a.Source, Block[], 0)
					 Block[] << a
					 CASE Parse.End_of_line ? Parse.Fin ;
					 Parse.Wait(".")
                [Line_start > 0] ?
                     CASE Parse.End_of_line ? Parse.Fin ;
                     Parse.Skip_sp
                     CASE Modifiers['NATIVE_FUN'] && Parse.Next_char IN #QU"@" ?
                          PUSH Parse.Ending_incl :
                               Line_native = Parse.Line
                               Native_code = Scan_string_const(14)
					             //DEBUG:
					             //ASE Names[0] == "Console_color" ?
					             //    << "---------------- 2 ----------"#NL
					             //    << Native_code.Replace_all(
					             //    #NL, "\n"#LF#CR) >> ;
					             //;
                          ;
                     ELSE
                     	  -------------------------- 'compiling body'
                     	  compile_block(Block[])
						  Line_native = Parse.Line
						  
                          BOOL native|_code_at_end_of_function = Modifiers[
                          'NATIVE_FUN']
                     ;
                     CASE native ? Parse.Wait("NATIVE") ;
                     CASE native && Parse.Symbol(":") ? NONE ;
                     CASE native ?
                          INT where|_parameter = 15
                          //DEBUG:
                          //	  CASE Names[0] == "Console_color" ?
                          //          where = 3 ;
                          //;
                          Native_code = Scan_string_const(where)
			              //DEBUG:
			              //SE Names[0] == "Console_color" ?
			              //   << "---------------- 3 -------------"#NL
			              //   << Native_code.Replace_all(
			              //   #NL, "\n"#LF#CR) >> ;
			              //;
                      
                     ;

                     CASE Parse.End_of_line ? Parse.Fin ;
                     Parse.Wait(".")
                     Parse.Fin ;
                Line_end = Parse.Line
                ---------------------- 'variables unique final names'
                unique_final_names
                ---------------------- 'trivial?'
                FOR st IN Block[] :
                    CASE st.Work ?
                    ['ASSIGN', 'APPEND', 'OUTPUT', 'INPUT', 'RETURN', 'PUSH',
                     'STOP', 'COMMENT', 'ASSERT', 'DEBUG', 'CALL_NATIVE']:
                    	NONE
                    	
                    ['BREAK', 'NEXT', 'CONTINUE', 
                     'CASE', 'ELSE', 'FOR', 'LIMIT', 'LOCAL']:
                        BOOL not_trivial = TRUE ;
                ;
                CASE ! not_trivial ? Is_trivial = TRUE ;
                ---------------------- 'ambiguous?'
                CASE Modifiers['NATIVE_FUN'] ? 
                     comp(Parse).Current_class.Detect({class_mod}.'NATIVE') ==>
                ;
                FOR v IN Local_var[]:
                    CASE ?
                    [v.Count_ref == 0 && v.Names[0] != "THIS" && (
                     Parse.Dummy_word !IN v.Names[*].Upper ) && (
                     !v.From_LIKE) && Overload_base_==NONE] ?
                        CASE v.Names[0] != "RESULT" && Block[].Count > 0 && (
                        	 !v.Declared_in_debug) && v.Names[0].[0] != "_"
                        	 && Parse.Syntax_name == ""
                        	 && !(v.Is_param && Merge(Names_low[
                        	 ], " ").Find("proto") >= 0)
                        	 ?
                             ---------- 'variable not used'
                             PUSH Parse.Line = v.Line :
                                  Parse.Warn("Variable"._Wvar 
                                  " " v.Whole_name 
                                  " " ("was not used in function"._Wwasnot ) 
                                  " " Names[*] 
                                  " " ("but it has not word 'dummy' in its "
                                  "name"._Wbut ) )
                                  
                                  v.Count_ref += 1
                             ;
                             CONTINUE v ;
                        CASE Block[].Count > 0 && (
                             Parse.Dummy_word !IN Names[*].Upper) && (
                             Ancestor_ == NONE) && v.Names[0].[0] != "_"
                             && Parse.Syntax_name == ""
                             && !(v.Is_param && Merge(Names_low[
                             ], " ").Find("proto") >= 0)
                             ?
                             Parse.Warn(v.Names[0] " " ("variable was "
                             "not assigned in function"._Wresult)
                             " " Whole_name 
                             " " ("but the function is not "
                             "marked with key 'dummy'"._Wbut2 ))
                        ;
                    [!v.Is_loop && v.Count_ref > 0 && (
                     Parse.Dummy_word IN v.Names[*].Upper)
                     && Parse.Syntax_name == ""] ?
                        PUSH Parse.Line = v.Line :
                             Parse.Warn("Variable"._Wvar3
                             " " v.Whole_name 
                             " " ("was used in function"._Wwasnot3 ) 
                             " " Names[*]
                             " " ("but it has word 'dummy' in its "
                             "name"._Wbut3 ) ) ;
                    ;
                ;
                CASE ! Modifiers['STATIC'] && ! This_used && (
                     THIS != Class.Construct && THIS != Class.Destruct) && (
                     Names[*] !IN [
                     "_Construct", "_Destruct"] && Block[].Count > 0) && (
                     Parse.Dummy_word !IN Names[*].Upper) && (
                     Ancestor_ == NONE) && !Modifiers['TRAP_FUN']
                     && "PROTOTYPE" !IN Names[*].Upper
                     && Parse.Syntax_name == ""
                     ?
                     PUSH Parse.Line = Line_start :
                          Parse.Warn("THIS is not used though function is not "
                          "declared as static FUNCTION"._Wthis ": " Names[*]
                          " " ("(Or mark is a prototype to override it in an "
                          "inheritance class including word 'PROTOTYPE' into "
                          "its last name)"._Wprototype)) ;
                ;
                Parse.Line = Line_start
                CASE Ancestor_ != NONE && Result == NONE && ! Calls_base && (
                     ! Modifiers['REPLACE']) && THIS != Class.Construct && (
                     THIS != Class.Destruct) && !(
                     Ancestor_.Ancestor_ == NONE && (
                     Ancestor_.Block[].Count == 0))
                     && !Ancestor_.Modifiers['OPTIONAL']
                     ?
                     Parse.Err("Function"._Efun2 " " THIS.Names[0] 
                     " " ("overrides base method"._Eover ) 
                     " " Ancestor_.Class.Names[0] 
                     "." Ancestor_.Names[0] " " ("but does not call it (BASE) "
                     "and has not replacing it (REPLACE)"._Ebut )) ;
                ------------------------- 'warning about first section comment'
                CASE count_statements(Block[]) > 1 ?
                     STR h|eader_line = Parse.Source[Header_line].TrimR
                     BOOL long_header = #LF IN h
                     FOR i IN [Header_line+1 TO Parse.Source[].Count-1] :
                         STR hs|tring_of_header = Parse.Source[i].Trim
                         CASE hs == "" ? CONTINUE i ;
                         DONE     
	                          CASE Starting(hs, "==>") ?
	                               h = h #NL hs
	                               long_header = TRUE ;
	                          BREAK i ;
                     FOR i IN [h.Len-2 DOWNTO 0] :
                         CASE h.[i] IN [ #CR, #LF ] ?
                              BOOL ss|eparate_string_colon = TRUE
                              BREAK i ;
                         CASE h.[i] !IN " " #TAB ? BREAK i ;
                     ;
                     //ss &&= h.[*] == ":"
                     CASE !Ending(h.Trim, ":") ? ss = TRUE ;
                     CASE long_header && !short_body && !ss 
                     	  && !Modifiers['NATIVE_FUN']
                     	  ?
                          PUSH Parse.Line = Line_start :
                               Parse.Warn("Symbol ':' should be placed "
                               "in a separate line if function header "
                               "contains several lines"._Wsym ) ;
                     ;
                ;
                PUSH Parse.Line = Line_start :
	                 CASE Modifiers['NEW'] ?
	                      check_all_assignments_to_RESULT_are_last ;
	                 CASE Warnings_indexing1[].Count > 0 ?
	                      SILENT:
							  Parse.Index_warn("It is desired to index"
							  " arrays with "
							  "variables only which are marked with "
							  "'INDEXING {type}' following its declaration"
							  ""._WIndexingDesired
		                      ", " ("lines of code are"._WLinesAre1) 
		                      ":" Merge(Warnings_indexing1[], ","))
	                      ; 
	                 ;
	                 CASE Warnings_indexing2[].Count > 0 ?
	                 	  SILENT:     
		                	  Parse.Index_warn("It is desired to pass INDEXING "
		                	  "variable in place of INDEXING parameter"
		                      ""._WMustIndexingParam
		                      ", " ("lines of code are"._WLinesAre2) 
		                      ":" Merge(Warnings_indexing2[], ","))
	                 	  ;
	                 ;
                ;
            ; .
            
        STR Warnings_indexing1[]
        STR Warnings_indexing2[]
			
            
            
		METHOD unique_final_names|_of_local_vars :
            FOR v IN Local_var[] :
                CASE v.Final_name != "" ?
                     CASE v.Final_name !IN all_final[] ?
                          all_final[] << v.Final_name ;
                     CONTINUE v ;
                CASE v.Replaced ? CONTINUE v ;
                v.Set_final_name(var_final_name(v.Names[]))
                CASE v.Final_name == "" ?
                	 Parse.Err("Can not make final name for "
                	 "variable"._Ecan3 " " v.Names[*]) ;
                //DEBUG:
                //      CASE is_all_tests ?
                //           << v.Final_name #NL ;
                //;
            ;
            FOR v IN Local_var[] :
                CASE v.Replaced ?
                     v.Set_final_name(v.Replace_to_.Final_name) ;
            ; .
	
            
		FUN count_statements(
		{Statement} Block|_of_statemens[]) ==> INT, RECURSIVE
			:
			RESULT = Block[].Count
			FOR s IN Block[] :
			    RESULT += count_statements(s.Block_[]) ; .
            
		METHOD var_final_name(STR Names|_of_variable[]) ==> STR :
			FOR i IN [0 TO Local_var[].Count] :
                STR fin|al_name = "X_" Parse.Only_letters_dig(
                	Names[0], SUPPORTS_NATIONAL_NAMES)
                	
                CASE i > 0 ? fin = fin "_" i.Str ;
                CASE fin !IN all_final[] ?
                    all_final[] << fin
                    RESULT = fin ==> ;
            ; .
            
		FUN file_to_copy(
			STR S|ource_file_name,
			{Compiler} The_Compiler,
			BOOL test|_for)
			:
			CASE Ending(S, ".*") ?
			     CASE !test ?
	                  STR s|ource_found = The_Compiler.Find_source_to_copy(
	                 	 S, The_Compiler.Source_paths[])
			     ELSE s = The_Compiler.Find_source_to_copy(
	                 	 S, The_Compiler.Source_test_paths[]) ; 
                 	
                 CASE "\" !IN s && "/" !IN s && Ending(s, ".cpp") ?
                      s = S ;
                 //DEBUG: << "need ///copy " S " --> " s #NL >> ;
			ELSE s = S ;
			CASE !test ?
	             CASE s !IN The_Compiler.Copy_files[] ?
	                  The_Compiler.Copy_files[] << s ;
			ELSE
	             CASE s !IN The_Compiler.Copy_files_test[] ?
	                  The_Compiler.Copy_files_test[] << s ;
			;
            CASE !Ending(s, ".cpp") ? ==> ;
            s = Change_ext(s, ".h")
            CASE !test ?
	             CASE s !IN The_Compiler.Copy_files[] && s.Exists ?
	                  //DEBUG: << "also: " s #NL >> ;
	                  The_Compiler.Copy_files[] << s ;
            ELSE 
	             CASE s !IN The_Compiler.Copy_files_test[] && s.Exists ?
	                  //DEBUG: << "also: " s #NL >> ;
	                  The_Compiler.Copy_files_test[] << s ;
            ; .

            
        METHOD check_all_assignments_to_RESULT_are_last :
            --------- 'check all assignments to RESULT in NEW function'
            FOR a IN Assignments_to_RESULT[] :
                {Expr} s|ource_of_assignment = a.Source
                BOOL n|ew_object = s.Operation == 'NEW_OBJ'
                n ||= s.Operation == 'FUN' && s.Fun_.Modifiers['NEW']
                CASE n && s.Owned_ == NONE && s.Array_ == NONE && (
                     is_last_assign_to_RESULT(Block[], a) == (
                     'FIRTHER_ASSIGNMENTS'))
                     ?
                     PUSH Parse.Line = a.Line :
                          Parse.Err("Assignment to RESULT in NEW function "
                          "is not the last: adding to an array (>>) or "
                          "setting an owner (OWNED BY) is required"._Eassign )
                     ;
                ;
            ; .
            
        FUN has_section_comments(
        {Statement} B|lock_statements[]) ==> BOOL, RECURSIVE
            :
            -------------------------------------------- 'if comments are used?'
            FOR st IN B[] :
                CASE st.Work == 'COMMENT' ? RESULT = TRUE ==> ;
                RESULT = has_section_comments(st.Block_[])
                CASE RESULT ? ==> ;
            ; .
            
        ENUM {is_last|_assignment} : 
                                     'FIRTHER_ASSIGNMENTS|_TO_RESULT_EXIST',
                                     'LAST_ASSIGNMENT|_TO_RESULT',
                                     'EXIT_FOUND|_FOLLOWING_THE_ASSIGNMENT' .
            
        METHOD is_last_assign_to_RESULT({Statement} B|lock_of_statements[],
            {Statement} A|ssignment_to_result) ==> {is_last}, RECURSIVE
            :
            --------------------------------------------- 'A in B[] ?'
            INT i|ndex_of_assignment_in_block = B[].Find(A)
            CASE i >= 0 ?
                 FOR j IN [i+1 TO B[].Count-1] :
                     CASE B[j].Work IN ['RETURN', 'STOP'] ?
                          RESULT = 'EXIT_FOUND' ==> ;
                          
                     CASE B[j].{Assign} != NONE && (
                          B[j].{Assign} IN Assignments_to_RESULT[])
                          ?
                          ==> ;
                          
                     CASE B[j].Block_[].Count > 0 && (
                          block_contains_assignments_to_RESULT(B[j].Block_[]))
                          ?
                          ==> ;
                 ;
            ;
            ---------------------------------------------- 'A in B[].Block_[] ?'
            FOR st IN B[] :
                CASE st.Block_[].Count == 0 || ! block_contains_statement(
                     st.Block_[], A)
                     ?
                     CONTINUE st ;
                CASE is_last_assign_to_RESULT(st.Block_[], A) ?
                ['FIRTHER_ASSIGNMENTS']: ==> 
                ['EXIT_FOUND']         : RESULT = 'EXIT_FOUND' ==>
                ['LAST_ASSIGNMENT']    : NONE ;
                FOR j IN [st.Index+1 TO B[].Count-1] :
                     CASE B[j].Work IN ['RETURN', 'STOP'] ?
                          RESULT = 'EXIT_FOUND' ==> ;
                     CASE B[j].{Assign} != NONE && (
                          B[j].{Assign} IN Assignments_to_RESULT[])
                          ?
                          ==> ;
                     CASE B[j].Block_[].Count == 0 ? CONTINUE j ;
                     CASE block_contains_assignments_to_RESULT(B[j].Block_[]) ?
                          ==> ;
                ;
            ;
            RESULT = 'LAST_ASSIGNMENT' .
            
        FUN block_contains_statement({Statement} B|lock_of_stmt[], 
            {Statement} St|atement_to_search) ==> BOOL, RECURSIVE
            :
            ------------------------------------------ 'St IN B[] ?'
            CASE St IN B[] ? RESULT = TRUE ==> ;
            ------------------------------------------ 'St IN B[i].Block_[] ?'
            FOR st IN B[] :
                CASE st.Block_[].Count > 0 && block_contains_statement(
                     st.Block_[], St)
                     ?
                     RESULT = TRUE ==> ;
            ; .
            
        METHOD block_contains_assignments_to_RESULT(
            {Statement} B|lock_of_statements[]) ==> BOOL, RECURSIVE
            :
            -------------- 'Any statement in block is an assignment to RESULT ?'
            FOR s IN B[] :
                CASE s.{Assign} != NONE && s IN Assignments_to_RESULT[] ?
                     RESULT = TRUE ==> ;
                CASE s.Block_[].Count > 0 && (
                     block_contains_assignments_to_RESULT(s.Block_[]))
                     ?
                     RESULT = TRUE ==> ;
            ; .
                     
        */
        private List<Statement> nesting = new List<Statement>();
        //private bool has_new = false;

        static int CNT_Compile;

        public void Compile()
        {
            if (++CNT_Compile == 713)
            { }
            //if (Total_fn == 156)
            //{ }

            if (Final_name == "-") return;
            if (Final_name == "") 
            	Final_name = comp(Parse).Current_class.Next_final_name(Names, true);
            Function temp = comp(Parse).Current_fun;
            comp(Parse).Current_fun = this;
            try
            {
                //------------------ 'params >> local_vars'
                foreach (Variable p in Param)
                {
                    foreach (string n in p.Names)
                    {
                        all_id.Add(n);
                    }
                    Local_var.Add(p);
                }
                if (Result != null)
                    Local_var.Add(Result);
                if (!Modifiers[(int)Fun_mod.STATIC])
                {
                    Variable th = new Variable(comp(Parse));
                    th.In_fun_ = this;
                    th.Names.Add("THIS");
                    th.Type_ = comp(Parse).Current_class;
                    th.Final_name = "this";
                    th.Line = Line_start;
                    Local_var.Add(th);
                }
                //------------------- 'do compile'
                if (Line_start > 0)
                {
                    Parse.Line = Line_start;
                    Parse.Pos = Pos_start;
                    if (Parse.End_of_line()) Parse.Fin();
                    if (Modifiers[(int)Fun_mod.NATIVE])
                    {
                        bool ei = Parse.Ending_incl;
                        Native_code = Parse.String_const(false);
                        Parse.Ending_incl = ei;
                    }
                    else compile_block(Block);
                    Parse.Wait(".");
                }
                //------------------- 'variables unique final names'
                List<string> all_final = new List<string>();
                foreach (Variable v in Local_var)
                {
                    if (v.Total_index == 797)
                    { }

                    for (int i = 0; i <= Local_var.Count && v.Final_name == ""; i++)
                    {
                        string fin = "X_" + v.Names[0];
                        if (i > 0) fin += "_" + i.ToString();
                        if (!all_final.Contains(fin))
                        {
                            all_final.Add(fin);
                            v.Final_name = fin;
                        }
                    }
                    if (v.Final_name == "")
                        Parse.Err("Can not make final name for variable " + v.Names[v.Names.Count - 1]);
                }
                //------------------- 'ambiguous?'
                if (Modifiers[(int)Fun_mod.NATIVE])
                {
                    comp(Parse).Current_class.Detect(Type.Class_mod.NATIVE);
                    return;
                }
                foreach (Variable v in Local_var)
                    if (!v.Used && v.Names[0] != "THIS" 
                    	&& v.Names[0] != "RESULT" 
                    	&& !v.Names[v.Names.Count - 1].ToLower().Contains("dummy"))
                        Parse.Warn("Variable " + v.Names[v.Names.Count - 1] + " was not used in " +
                            "function " + Names[Names.Count - 1] + " but it has not word 'dummy' in " +
                            "its name");
            }
            finally { comp(Parse).Current_fun = temp; }
        }

        /*
        STR all_id|entifiers[]
        //INT level|_of_block
		INT block_until_comment
		INT nesting_level
		
		METHOD calc_nesting_level ==> INT :
			RESULT = 0
			FOR n IN [Nesting[].Count-1 DOWNTO 0] :
			    RESULT += 1
			    CASE Nesting[n].{For}.Done >= 0 ? RESULT -= 1 ;
			    CASE n > 0
			         && Nesting[n-1].Starting_bracket 
			         != Nesting[n].Starting_bracket
			         ? ==> ;
			; .
            //RESULT = nesting_level
            //CASE RESULT <= 3 ? ==> ;
            //FOR n IN [Nesting[].Count-1 DOWNTO 0] :
            //    CASE Nesting[n].{For}.Done >= 0 ? RESULT -= 1 ;
            //; .

        METHOD compile_block(
        {Statement} Block|_statements[]), RECURSIVE
        	:
		PUSH Current_level = Current_level + 1 : 
			//DEBUG:
			//      CASE Trace_counter(1) == 89 ?
			//           BOOL b_debug|_block = TRUE
			//           << Parse.Line.Str " " Parse.Pos.Str #NL
			//           << "-".Repeat(80) Parse.Rest_of_line ;
			//;
            ---------------------------------- 'Block of statements'
            PUSH count_compiled_simple = 0 :
            PUSH count_compiled_block = 0 :
				 //DEBUG: << "start block level " level.Str #NL ;
                 INT n_simple|_statements = 0
                 INT n_block|_statements = 0
                 INT n_lines|_maximum = Parse.Source[].Count - Parse.Line
                 
                 Parse.Skip_sp
                 CASE Parse.End_of_line ?
                      Parse.Fin ;
                 
                 FOR x|dummy IN [0 TO n_lines * 2] :
                     //DEBUG:
                     //      CASE b_debug ?
                     //     << "line " (
                     //        Parse.Line + comp(Parse).Add_to_line).Str
                     //        ": " //Parse.Source[Parse.Line] #NL ;
                     //        "" Parse.Rest_of_line #NL ;
                     //;
                     STR s|tring_line = Parse.Source[Parse.Line]
                     CASE Ending(s.TrimR, "==>") ?
                          s = Remove_trailing(s.TrimR, "==>") ;
                     //CASE Class_.Syntax_fun==":"
                     //     &&
                     STR t|rimmed_s = s.Trim
                     CASE #LF IN s.Trim && x > 0
                          && !Starting(Remove_all(
                     	  		Remove_all(s.Trim, " "), #TAB), "NATIVE")
                     	  && !Ending(t, "?") && !Ending(t, ";")
                     	  && !Ending(t, "{") 
                     	  && !(Ending(t, "--") && Find_last(t, "<--")>=0)
                     	  && !(Ending(t.Upper, "BEGIN") && t.[*-5].Trim=="")
                     	  ?
                     	  INT cLF|_count = count_ch(s, #LF)
                     	   
                     	  STR nx|_next_line = Parse.Source[
                     	  	  Parse.Line + cLF + 1].Trim 
                     	  	  
                     	  CASE cLF > 0 ? 
                     	       INT last_LF|_pos = Find_last(s.TrimR,#LF)
                     	       STR last_s|_line = s.[last_LF TO *].Trim  
                     	       CASE last_s.[*] IN [":", "?"] ? 
                     	            nx = ":" ;
                     	  ;
                     	  	  
                          CASE nx.[0] !IN ":;."#0 && !Starting(nx, "--")
                               && nx != "ELSE" //&& last_s.[*] !IN ":?"
                               && !Starting(last_s, "--")
                          	   ?
                               style_warn("Line of code which is not fit" 
                               " one line of text should be separated "
                               "from following lines with empty lines"
                               ""._WMultilineWantSepFromNext
                               ""//" last_p:[" last_s "]"
                               " next:[" nx "]"
                               " cLF=" cLF.Str #NL
                               " last_s:[" last_s "]" ) ;
                     ;
                     
                     Parse.Skip_sp
                     CASE Parse.End_of_line ?
                          Parse.Fin
                          CONTINUE x ;
                     ------------------------------------------- 'end of stmt ?'
                     CASE Parse.Next_char ?
                          ["."]:
                     		CASE !Parse.Next_symbol("..") ? BREAK x ;
                          [";", "["]:
                              ident_pos = Parse.Pos
                              BREAK x
                          ["{"]:
                     		CASE Parse.Next_symbol("{{") ? BREAK x ;
                          ["}"]:
                          	//CASE Class_.Syntax_fun != ":" ? BREAK x ;
                          	BREAK x
                          ["-"]:
                              CASE Parse.Source[Parse.Line].Find(">") > 0 ? 
                          	CASE Parse.Next_symbol("-->") ? BREAK x ;
                          	  ;
                          ["E"]: 
                                CASE Parse.Next_symbol("ELSE")
                                     || TRUE // Class_.Syntax_fun != ":" 
                                     && Parse.Next_symbol("END")
                                     ? BREAK x ;
                          ["e"]:
                                //CASE Class_.Syntax_fun != ":"
                                //     && Parse.Next_symbol("END")
                                //     ? BREAK x ;
                                CASE Parse.Next_symbol("else")
                                     || TRUE // Class_.Syntax_fun != ":" 
                                     && Parse.Next_symbol("end")
                                     ? BREAK x ;
                     ;
					 ------------------------------- 'compile single statement'
                     BOOL b_end|_of_block 
                     count_compiled_simple = n_simple
                     count_compiled_block = n_block
                     b_end = compile_single_statement(
                     	Block[], n_simple, n_block)
                     	
                     count_compiled_statements += 1
                     ------------------------------- 'collect counters'
                     n_simple = count_compiled_simple
                     n_block = count_compiled_block
                     count_compiled_simple = 0
                     count_compiled_block = 0
                     CASE b_end ? BREAK x ;
                 ;
                 CASE calc_nesting_level > 3 && !Compiling_debug ?
                      CASE !(calc_nesting_level == 4 
                      	   && n_block == 0 && n_simple <= 1)
                      	   ?
	                       FOR n IN Nesting[] :
	                       	   CASE n.Work !IN ['FOR', 'CASE'] ? 
	                       	        CONTINUE n ;
	                           STR line|s_where = line (n.Line+1).Str ", "
	                       ;
	                       CASE !Parse.Not_restrict_nesting ?
	                       		STR add|_details = " (in lines: " 
	                       			"" line.[0 TO *-2] ")"
	                       			
	                       		//DEBUG: add << " nesting_level=" nesting_level.Str
	                       			   //" n_block=" n_block.Str
	                       			   //" n_simple=" n_simple.Str #NL ;
	                       			     
		                        Parse.Class_.Detect_bad("More then 3 "
		                        "nesting levels of work statements" add)
	                       ;
                      ;
                 ;
                 CASE Parse.Next_symbol("NATIVE") ?
                      CASE ?
                      [!Modifiers['NATIVE_FUN']] ?
                           Parse.Err("Invalid directive NATIVE: function is not" 
                           " native"._Einvalid4 ": " Whole_name)
                      [Current_level > 1] ?
                           Parse.Err("Invalid directive NATIVE position: can be"
                           " only the last in a native function"._Einvalid ) ;
                 ;
                 CASE !Compiling_debug ?
                      check_amount_simple(n_simple)
                      check_amount_block(n_block) ;
                 check_assertions(Block[]) ;
				 //DEBUG: << "end block level " level.Str #NL ;
            ;
		; .
		
		FUN count_ch|aracter(
		STR S|tring_where_count, STR C|haracter_to_count) ==> INT
			:
			FOR i IN [0 TO S.Len-1] :
			    CASE S.[i] == C ? RESULT += 1 ;
			; .
            
   		METHOD compile_comment ==> {Assign}, NEW :
            FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                CASE !Parse.Symbol("-") ? BREAK i ;
            ;
            INT line|_comment_found_in = Parse.Line 
            INT pos_before = Parse.Pos
            CASE Parse.Symbol("'") ?
                 STR c|omment_label = "'" Parse.Skip_to("'") "'"
                 Parse.Wait("'") ;
                 
		    RESULT = {Assign}(Line = Parse.Line, Pos= pos_before,
		    	Level= Current_level, Function_= THIS, Work= 'COMMENT',
			    Source = {Expr}(
				    Operation = {Expr}.{operation}.'CONST',
				    Var_arg = {Var}(Line= 0, Str_c= c, Is_const= TRUE,
				    Type_= Parse.Compiler.TYPE_STR))),
			    OWNED BY THIS
            ------------------------------- 'reused ?'
            CASE Parse.Symbol(",") ?
                 Parse.Wait("REUSED")
                 {Type} cc|urrent_class= Parse.Compiler.Current_class
                 CASE !RESULT.Reused ?
                      CASE !Parse.Compiler.Is_silent 
                           && line !IN cc.Reused_comments[]
                           && Overload_base_==NONE && Overloaded_[].Count==0
                           ?
                           cc.Reused_comments[] << line ;
                 	  RESULT.Reused = TRUE ;
            ; .
                 
        INT count_compiled_simple|_statements
        INT count_compiled_block|_statements
        {Expr} Last_arg|ument_for_field_expression
        INT ident_pos|ition_identifier
				 
		METHOD compile_single_statement(
            {Statement} Block|_statements[],
            INT N_simple|_counted_in_block_already,
            INT N_block|_counted_in_block_already) ==> BOOL
            :
            Last_arg = NONE
            ----------------------- 'return RESULT.End to indicate end of block'
			 CASE Block[*].Is_jump ?
			      CASE !Parse.Next_symbol("--") ?
				  	   Parse.Warn("Unreacheable statement"._Wunreach ) ;
			 ;
			 comp(Parse).Incremented[].Clear
			 CASE Parse.Next_char ?
			 [#0]  : Parse.Fin ==>
			 ["-"] : 
                     CASE !Compiling_debug ?
						  check_amount_simple(N_simple)
						  check_amount_block(N_block) ;
					 check_assertions(Block[])
					 CASE block_until_comment == Current_level ?
						   RESULT = TRUE ==> ;
					 {Assign} a|ssignment_temp = compile_comment
					 Block[] << a
                     count_compiled_simple = 0
                     count_compiled_block = 0
                     ------------------ 'finish after block comment'
                     Parse.Fin
                     ==>
			 ["{"] : 
			  		 CASE compile_declaration(Block[]) ?
					  	  count_compiled_simple += 1 ;
			  		 ==>
			 ["="] : 
			 		 INT pos_before = Parse.Pos
                     CASE Parse.Symbol("==>") ?
                          CASE Modifiers['NATIVE_FUN']
                           	   && !ALLOW_EXIT_IN_NATIVE
                           	   ?
                               Parse.Err("It is not allowed to use ==> in "
                               "NATIVE functions for the target language"
                               ""._ENotAllowedReturnInNATIVE " "
                               "" TARGET_LANG(comp(Parse)))
                          ;
						  compile_return(Block[], pos_before)
                     ;
					 ==>
			 ["<"] : compile_output(Block[], FALSE)
					 count_compiled_simple += 1 ==>
			 [">"] : compile_input(Block[])
					 count_compiled_simple += 1 ==>
			 ["."]:
			  	   CASE Parse.Next_symbol("..") ?
			  		    compile_simple(Block[]) ==> ;
			  		    
			 ["("]:
            		PUSH Left_side = TRUE :
	               		 {Expr} left|_side_of_assign = Recognize(Parse),
				 			 >> All_expr[] ;
			 		Compile_assign(left, Block[])
			 		check_assignment_indexing(Block[*])
			 		count_compiled_simple += 1 ==>
             ;
			 ident_pos = Parse.Pos
			 STR key|word_id = Parse.Ident 
			 CASE key ?
				  ["BOOL", "BOOLEAN", "INT", "INTEGER", "REAL",
				   "STR", "STRING", "BYTE"]:
						   Parse.Pos = ident_pos
						   CASE compile_declaration(Block[]) ?
						   		count_compiled_simple += 1 ;
                  //["FOREVER"]: block_statement(pos)
                  //             compile_forever(Block[])
                  //             count_compiled_block += 1
				  ["FOR"]: block_statement(ident_pos)
                           compile_for(Block[])
						   count_compiled_block += 1
				  ["DONE"]: compile_done
				  ["CASE"]: block_statement(ident_pos)
                            compile_case(Block[])
							count_compiled_block += 1
				  ["LIMIT"]: block_statement(ident_pos)
				  			 compile_limit(Block[])
							 count_compiled_block += 1
				  ["LOCAL"]: block_statement(ident_pos)
				  			 compile_local(Block[])
							 count_compiled_block += 1
				  ["PUSH"]: block_statement(ident_pos)
                            compile_push(Block[])
							count_compiled_block += 1
				  ["BREAK"]: compile_break(Block[])
							 count_compiled_simple += 1
				  ["CONTINUE"]: compile_continue(Block[])
								count_compiled_simple += 1
				  ["NEXT"]: compile_next(Block[])
								count_compiled_simple += 1
				  ["STOP"]: compile_stop(Block[])
							count_compiled_simple += 1
				  ["ASSERT"]: compile_assert(Block[])
				  ["SILENT"]: compile_silent(Block[])
				  ["DEBUG"]: block_statement(ident_pos)
                             compile_debug(Block[], TRUE)
				  ["NATIVE"]: Parse.Pos = ident_pos
							  RESULT = TRUE ==>
				  ["LIKE"]: compile_like(Block[])
							count_compiled_simple += 1
                  ["REVERT"]: compile_revert(Block[])
                              count_compiled_simple += 1
                  ["UNCOOKED"]:
                  				CASE !Modifiers['UNCOOKED'] ?
                  				     CASE Compiling_like ?
                  				          Parse.Err("It is not allowed to use "
                  				          "UNCOOKED statement in a block called "
                  				          "in LIKE/REVERT statements"
                  				          ""._EUncookedInLike)
                  				     ELSE
	                  				      Parse.Err("Function also must be " 
	                  				      "marked as UNCOOKED"._EMustUncooked)
                  				     ;
                  				;
                  				count_compiled_simple += 1
			 ELSE count_compiled_simple += 1
				  Parse.Pos = ident_pos
				  compile_simple(Block[])
				  ------ 'do not count assignments to the same variable'
				  {Assign} pr|evious = Block[*-1].{Assign}
				  {Assign} en|ding_assign = Block[*].{Assign}
				  CASE pr.Dest.Var_arg != NONE && (
					   pr.Dest.Var_arg == en.Dest.Var_arg)
                       ?
					   count_compiled_simple -= 1 ;
			 ;
			 //DEBUG:
			 //      CASE Block[*].Total_stmt == 10234 ?
			 //           Block[*].Test_output ;
			 //;
			 CASE Parse.End_of_line ? Parse.Fin ; .
	
		

        METHOD block_statement( INT Pos|ition_in_current_line ) :
            STR start|_of_line = Parse.Source[Parse.Line].[0 TO Pos-1].Trim
            CASE start != "" ?
                 Parse.Err("Block statement must start from a new "
                 "line"._Eblock5) ; .
                 
        */
        private List<string> all_id = new List<string>();
        private int level;

        static int CNT_compile_block;

        private void compile_block(List<Statement> Block)
        {
            if (++CNT_compile_block == 5)
            { }

            level++;
            try
            {
                if (nesting.Count > 4)
                {
                    string lines = "";
                    foreach (Statement s in nesting)
                        lines += (s.Line+1).ToString() + ", ";
                    Parse.Class_.Detect_bad("More then 3 nesting levels " +
                    "of work statements (in lines: " + 
                    lines.Substring(0, lines.Length-2) + ")");
                }
                int n_simple = 0;
                int n_block = 0;
                bool break_x = false;
                for (int xdummy = Parse.Line;
                	xdummy <= Parse.Source.Count && !break_x; xdummy++)
                {
                    if (xdummy == 507 && CNT_compile_block == 66)
                    { }
                    comp(Parse).Incremented.Clear();
                    Parse.Skip_sp();
                    if (Parse.End_of_line())
                    {
                        Parse.Fin();
                        continue;
                    }
                    switch ((Parse.Next_char() + (char)0)[0])
                    {
                        case '.':
							if (!Parse.Next_symbol(".."))
							{ 
								break_x = true; continue;
							}
                            break;
                        case ';':
                        case '[':
                            break_x = true; continue;
                        case 'E':
                            if (Parse.Next_symbol("ELSE"))
                            {
                                break_x = true; continue;
                            }
                            break;
                    }
                    //if (Block.Count > 0 && Block[Block.Count - 1].Is_jump())
                    //    Parse.Warn("Unreacheable statement");
                    switch ((Parse.Next_char() + (char)0)[0])
                    {
                        case (char)0: Parse.Fin();
                            continue;
                        case '-':
                            if (!Compiling_debug)
                            {
                                check_amount_simple(n_simple);
                                check_amount_block(n_block);
                            }
                            check_assertions(Block);
                            while (Parse.Symbol("-")) { }
                            string c = "";
                            if (Parse.Symbol("'"))
                            {
                                c = "'" + Parse.Skip_to("'") + "'";
                                Parse.Wait("'");
                            }
                            Assignment a = new Assignment();
                            {
                                a.Work = Statement.Workflow.COMMENT_BLOCK;
                                a.Line = Parse.Line;
                                a.Source = new Expression();
                                {
                                    a.Source.Operation = Expression.Operation_kind.CONST;
                                    a.Source.Var_arg = new Variable(comp(Parse));
                                    {
                                        a.Source.Var_arg.Line = 0;
                                        a.Source.Var_arg.Str_c = c;
                                    }
                                }
                            }
                            Block.Add(a);
                            if (Parse.Symbol(",") && Parse.Symbol("REUSED")) { }
                            n_simple = 0;
                            n_block = 0;
                            continue;
                        case '{':
                            compile_declaration(Block);
                            n_simple++;
                            continue;
                        case '=':
                            if (Parse.Symbol("==>"))
                            {
                                compile_return(Block);
                                n_simple++;
                                continue;
                            }
                            else { break_x = true; }
                            break;
                        case '<':
                            compile_output(Block);
                            n_simple++;
                            continue;
                        case '>':
                            compile_input(Block);
                            n_simple++;
                            continue;
                        case '.':
				  			if (Parse.Next_symbol(".."))
				  			{
				  		     	compile_simple(Block);
				  		     	return;
				  			}
				  			break;
                    }
                    Parse.Symbol("DONE");
                    if (Parse.End_of_line()) {
                    	Parse.Fin();
                    	continue;
                    }
                    int pos = Parse.Pos;
                    string key = Parse.Ident();
                    bool sw_ok = false;
                    bool do_declare = false;
                    switch ((key + " ")[0])
                    {
                        case 'F':
                            if (key == "FOREVER")
                            {
                                sw_ok = true;
                                compile_forever(Block);
                                n_block++;
                            }
                            else if (key == "FOR")
                            {
                                sw_ok = true;
                                compile_for(Block);
                                n_block++;
                            }
                            break;
                        case 'S':
                            if (key == "STR" || key == "STRING")
                                do_declare = true;
                            else if (key == "STOP")
                            {
                                sw_ok = true;
                                compile_stop(Block);
                                n_simple++;
                            }
                            else if (key == "SILENT")
                 			{
                 				sw_ok = true; 
                 				bool old_Is_silent = Compiler.Is_silent;
                 				Compiler.Is_silent = true;
                 				Parse.Wait(":");
                 				if (Parse.End_of_line()) Parse.Fin();
                 				compile_block(Block);
                 				if (Parse.End_of_line()) Parse.Fin();
                 				Parse.Wait(";");
                 				Compiler.Is_silent = old_Is_silent;
                 			}
                            break;
                        case 'P':
                            if (key == "PUSH")
                            {
                                sw_ok = true;
                                compile_push(Block);
                                n_block++;
                            }
                            break;
                        case 'B':
                            if (key == "BREAK")
                            {
                                sw_ok = true;
                                compile_break(Block);
                                n_simple++;
                            }
                            else if (key == "BOOL")
                                do_declare = true;
                            break;
                        case 'C':
                            if (key == "CASE")
                            {
                                sw_ok = true;
                                compile_case(Block);
                                n_block++;
                            }
                            else if (key == "CONTINUE")
                            {
                                sw_ok = true;
                                compile_continue(Block);
                                n_simple++;
                            }
                            break;
                        case 'I':
                            if (key == "INT" || key == "INTEGER")
                                do_declare = true;
                            break;
                        case 'R':
                            if (key == "REAL")
                                do_declare = true;
                            break;
                        case 'A':
                            if (key == "ASSERT")
                            {
                                sw_ok = true;
                                compile_assert(Block);
                                n_simple++;
                            }
                            break;
                        case 'D':
                            if (key == "DEBUG")
                            {
                                sw_ok = true;
                                compile_debug(Block, true);
                            }
                            break;
                    }
                    if (do_declare)
                    {
                        Parse.Pos = pos;
                        compile_declaration(Block);
                        n_simple++;
                    }
                    else if (!sw_ok)
                    {
                        n_simple++;
                        Parse.Pos = pos;
                        compile_simple(Block);
                    }
                    if (Parse.End_of_line()) Parse.Fin();
                }
                if (!Compiling_debug)
                {
                    check_amount_simple(n_simple);
                    check_amount_block(n_block);
                }
                check_assertions(Block);
            }
            finally
            {
                level--;
            }
        }

        /*
        
        METHOD check_assertions({Statement} Block|_of_stmts[]) :
            CASE Current_level != 1 ? ==> ;
            CASE comp(Parse).Generating_test && Block[
                    ].Count > 0 && assertions == 0 && (
					Block[*].Work != 'COMMENT')
                    ?
                    Parse.Warn("In TEST block, section should "
                    "contain ASSERT"._Wintest )
            ; 
            assertions = 0 .
			
        */
        private void check_assertions(List<Statement> Block)
        {
            if (level != 1) return;
            if (comp(Parse).Generating_test() && Block.Count > 0 &&
                assertions == 0)
                Parse.Warn("In TEST block, section should contain ASSERT");
            assertions = 0;
        }

        /*
        
        METHOD compile_return(
        {Statement} Block|_of_stmts[], INT Pos_start)
            :
			Has_return = TRUE
			
            Block[] << {Case}(Work= 'RETURN', Line= Parse.Line, Pos= Pos_start,
                    Function_= THIS, Level= Current_level)
                    
            FOR i IN [Nesting[].Count-1 DOWNTO 0]:
                {Statement} st|atement_in_nesting = Nesting[i]
                CASE st.Work == 'PUSH' ?
                     st.{Assign}.Intersect = TRUE ;
            ;
            Parse.Skip_sp
            CASE Parse.Next_char ? [";", ".", "}"]: ==> ;
            CASE Parse.Next_symbol("-->") || Parse.Next_symbol("end")
                 || Parse.Next_symbol("END")
                 ? ==> ;
            Parse.Fin .
        */
        private void compile_return(List<Statement> Block)
        {
            Case r = new Case();
            r.Work = Statement.Workflow.RETURN;
            r.Line = Parse.Line;
            Block.Add(r);
            Parse.Skip_sp();
            if (";.".Contains(Parse.Next_char())) return;
            Parse.Fin();
        }

        /*
        
        METHOD check_amount_simple|_statements(INT N|_statements) :
            CASE N > 7 ? 
                Parse.Class_.Detect_bad("More then 7 simple statements "
                "in block") ; .
        */
        private void check_amount_simple(int N)
        {
            if (N > 7)
                Parse.Class_.Detect_bad("More then 7 simple statements in block");
        }

        /*
        
        METHOD check_amount_block|_statements(INT N|_statements) :
            CASE N > 7 ? 
                Parse.Class_.Detect_bad("More then 7 block statements "
                "in a block") ; .
        */
        private void check_amount_block(int N)
        {
            if (N > 7)
                Parse.Class_.Detect_bad("More then 7 block statements in a block");
        }

        /*
        
        METHOD Expr|ession_recognizing ==> {Expr}, NEW :
            RESULT = Recognize(Parse) .
        */
        public Expression Expr()
        {
            return Expression.Recognize(Parse);
        }

        /*
        
        METHOD compile_for_infinite(
        {Statement} Block|_of_statements[])
            :
            ---------------------------------- 'check if test'
            CASE comp(Parse).Current_fun.Is_test ?
                 Parse.Err(
                 "It is not allowed to use infinite loops in tests"._Eitis2 ) ;
            ---------------------------------- 'very rare needed (may be never)'
            Parse.Class_.Detect('INFINITE')
            //Parse.Wait(":")
            
            f|orever_loop = {For}(Work= 'FOR', Line= Parse.Line, Pos= 0, 
                Function_= THIS, Level= Current_level, Infinite= TRUE), 
                >> Block[]
                
            STR finishing|_symbol = symbol_starting_block(f)
                
            Nesting[] << f
        	nesting_level += 1
            ---------------------------------- 'compile to temp array 1st'
            {Statement} temp|_block[]
            compile_block(temp[])
            FOR t IN temp[] :
                f.Block_[] << t
                comp(Parse).Current_fun.Keep_statements[] << t ;
            Nesting[].Remove(f)
        	nesting_level -= 1
        	CASE finishing==";" ? 
        	     Parse.Want_semicolon("ending infinite FOR at " (f.Line+1).Str) 
        	ELSE Parse.Wait(finishing) ; .
        */
        private void compile_forever(List<Statement> Block)
        {
            Parse.Class_.Detect(Type.Class_mod.INFINITE);
            Parse.Wait(":");
            For f = new For();
            f.Work = Statement.Workflow.FOREVER;
            f.Line = Parse.Line;
            Block.Add(f);
            nesting.Add(f);
            compile_block(f.Block_);
            nesting.Remove(f);
            Parse.Wait(";");
        }

        /*
        
        METHOD loop_by_range(
        {Var} V|ar_of_loop) ==> BOOL
        	:
        	FOR i IN [Nesting[].Count-1 DOWNTO 0] :
        	    {For} sfor|_statement_i = Nesting[i].{For}
        	    CASE sfor.Var == V ?
        	         RESULT = sfor.Array == NONE
        	         CASE RESULT ? ==> ;
        	    ;
        	; .
        	

        METHOD compile_for({Statement} Block|_of_statements[]) :
            INT line|_starting = Parse.Line
            CASE Parse.Symbol(",") ? 
                 Parse.Wait("INFINITE")
                 compile_for_infinite(Block[]) ==> ;
            ------------------------------------ 'Name of FOR loop variable'
            STR name|_loop_var = Parse.Ident
            STR name2|_loop_var = name
            {Type} cc|lass_current = comp(Parse).Current_class
            
            CASE Parse.Symbol("|") ?
                name2 = name Parse.Ident ;
            ------------------------------------ 'Create variable'
            {Var} v|ar_loop = Search_var(name, TRUE)
            CASE v == NONE ?
                v = {Var}(In_fun_ = THIS, Is_loop = TRUE, Line = Parse.Line),
                    >> Local_var[]
                v.Names[] << name
                all_id[] << name
                CASE name2 != name ? 
                     CASE name2 IN all_id[] ?
                          Parse.Err("Duplicating name"._Edup2 ": " name2) ;
                     all_id[] << name2
                     v.Names[] << name2 ;
                Parse.Check_reserved(v.Names[])
            ;
            ------------------------------- 'excplicit INDEXING'
            CASE Parse.Symbol("INDEXING") ?
                 BOOL explicit_indexing = TRUE
                 CASE Parse.Symbol("(") ?
                      v.Type_indexing = Parse.Skip_to(")")
                      Parse.Wait(")")
                 ELSE v.Type_indexing = Parse.Scan_type ;
                 STR t_i|ndexing_types[]
                 Split(t_i[], v.Type_indexing, ",")
                 FOR it IN [0 TO t_i[].Count-1] :
                 	 STR t|ype_at_i = t_i[it].Trim
                     v.Indexing_[] << comp(Parse).Current_class.Find_type(t) 
                     v.Automatic_indexing = FALSE
                 ;
            ;
            ----------------------------------- 'other checks'
            CASE !v.Is_loop ?
                err("Variable"._Evar " " name 
                " " ("can not be reused as a loop variable"._Ecannot ))
            ;
            CASE name !IN v.Names[] || name2 !IN v.Names[] ?
                err("Wrong re-defining variable"._Ewrong " " name2) ;
            FOR n IN Nesting[] :
                CASE v == n.{For}.Var ?
                    err("Re-using loop variable"._Ereusing " " v.Names[*] 
                    " " ("in the nested loop"._Einthe )) ;
            ;
            BOOL is_enum|erate = Parse.Symbol("ENUMERATE")
            is_enum ||= Parse.Symbol("ENUM") 
            CASE is_enum ?
                 CASE explicit_indexing ? 
                      Parse.Err("Explicit indexing of the FOR ... ENUM ... "
                      "loop variable"._EExcplicitIndexingForEnum)
                 ;
                 for_enum(Block[], v) ==> ;
            CASE Parse.End_of_line ? Parse.Fin ;     
            Parse.Wait("IN")
            ----------------------------------- 'create f representing {For}'
            f|or_loop_temp = {For}(Var = v, Line = Parse.Line, Pos= 0,
                Function_ = THIS, Level = Current_level)
                
            v.For_ = f
            Parse.Skip_sp
            CASE ?
            [Parse.Next_char == "{"] ?
                 STR en|ame_of_enumeration = Parse.Scan_type
                 {Type} e|numeration_type = cc.Find_type(en)
                 CASE e.Kind == 'CLASS' ?
                      Parse.Wait(".")
                      en = Parse.Scan_type
                      e = e.Find_type(en) ;
                 CASE e.Kind != 'ENUMERATION' ?
                      Parse.Err("Waiting for enumeration type"._WaitEnum) ;
                 v.Type_ = e
                 
                 f.Range1 = {Expr}(Operation = 'CONST',
                 	Var_arg = comp(Parse).N0_c), >> All_expr[]
                 	
                 f.Range2 = {Expr}(Operation = 'CONST',
                 	Var_arg = {Var}(Int_c = e.Items[].Count-1, Is_const= TRUE,
                 	Type_ = comp(Parse).TYPE_INT, Line = -1))
                 	
            [Parse.Next_char == "["] ?
                 Parse.Skip_char
                 v.Type_ = comp(Parse).TYPE_INT
                 f.Range1 = Recognize_typed(Parse, 'INT'), >> All_expr[]
                 extract_new_operations(f.Range1, Block[], 0)
                 CASE Parse.Ident ?
                 ["TO"]: NONE
                 
                 ["DOWNTO"]: f.Downto = TRUE
                      
                 ELSE err("Waiting for TO or DOWNTO, but"._Ewait
                      ": " Parse.Next20) ;
                      
                 f.Range2 = {Expr}.Recognize_typed(Parse, 'INT'),
                          >> All_expr[]
                          
                 extract_new_operations(f.Range2, Block[], 0)
                          
                 CASE f.Range2.Operation == 'CONST' ?
                      CASE f.Downto && f.Range2.Var_arg.Int_c == MIN_INT || (
                      	   !f.Downto && f.Range2.Var_arg.Int_c == MAX_INT)
                      	   ?
                           err("Using ...TO MAX_INT] and ...DOWNTO MIN_INT]"
                           " in a FOR loop is not allowed"._EUsing
                           ": " f.Range2.Var_arg.Int_c.Str) ;
                 ;
                 CASE v.Type_ != NONE && v.Type_.Kind != 'INT' ?
                      err("Loop variable type is "
                      "not compatible with the integer range"._Eloop )
                 ;
                 CASE v.Type_ == NONE ? v.Type_ = comp(Parse).TYPE_INT ;
                 CASE v.Type_.Kind != 'INT' ? BOOL bad|_var_type = TRUE ;
                 CASE !explicit_indexing ?     
	                  CASE !automatic_indexing_on_Count(v, f.Range2) ?
	                       NONE = automatic_indexing_on_Count(v, f.Range1) ;
                 ;
                 Parse.Wait("]")
            ELSE
            	 //DEBUG: << (Parse.Line + 1).S 
            	 //			"xxxxxxxxxxxxxxxxxxxxxxxxxxxxx[" Parse.Rest_of_line 
            	 //			"]"#NL ;
            	 PUSH Parse.Source[Parse.Line] : 
            	 	  BOOL range_present = make_empty_last_square_brackets
            	 	  f.Array = {Expr}.Recognize(Parse), >> All_expr[]
            	 	  ---------------- 'provide INDEXING'
            	 	  CASE !explicit_indexing 
            	 	       && f.Array.Var_arg.Indexing_[].Count > 0
            	 	       ?
            	 	       v.Indexing_[].Clear
            	 	       FOR ix IN f.Array.Var_arg.Indexing_[] : 
            	 	  	   	   v.Indexing_[] << ix ;
            	 	       v.Automatic_indexing = TRUE
            	 	  ;
            	 	  extract_new_operations(f.Array, Block[], 0) 
            	 ;
            	 //DEBUG: << (Parse.Line + 1).S 
            	 //			"yyyyyyyyyyyyyyyyyyyyyyyyyyyyy[" Parse.Rest_of_line 
            	 //			"]"#NL ;
                 CASE ?
                 [!f.Array.Is_array] ?
                      err("An array must be specified to iterate in it"._Earr2 )
                 //[f.Array.Type_expr.Kind == 'STRUCTURE'] ?
                 //     err("It is not allowed to loop on an array of structures"
                 //     ""._EForOnStrucArr)
                 ;
                 CASE v.Type_ == NONE ? v.Type_ = f.Array.Type_expr ;
                 CASE ?
                 [v.Type_.Kind == 'INT' 
                  && f.Array.Type_expr.Kind == 'STRUCTURE'] ? NONE     
                 [v.Type_ != f.Array.Type_expr] ? bad = TRUE ;
                 CASE range_present ?
                      Parse.Pos -= 1
                      PUSH comp(Parse).Current_array = f.Array :
	                       f.Range1 = Recognize_typed(Parse, 'INT'),
	                       	>> All_expr[]
	                       	
	                       extract_new_operations(f.Range1, Block[], 0)
	                       CASE Parse.Ident ?
	                            ["TO"]: NONE
	                            ["DOWNTO"]: f.Downto = TRUE
	                            
	                       ELSE err("Waiting for TO or DOWNTO, but: "._EwaitTO
	                      	    ": " Parse.Next20)
	                       ;
	                       f.Range2 = Recognize_typed(Parse, 'INT'),
	                       			  >> All_expr[]
	                       			  
	                       extract_new_operations(f.Range2, Block[], 0)
                      ;
                      Parse.Wait("]")
            	  //DEBUG: << (Parse.Line + 1).S 
            	  //		"zzzzzzzzzzzzzzzzzzzzzzzzzzzzz[" Parse.Rest_of_line 
            	  //		 "]"#NL ;
                 ;
            ;
            CASE f.Range1 != NONE && f.Array == NONE ?
                 ----------------------------------- 'check INT'
                 BOOL is_int|egers = f.Range1.Type_expr.Kind == 'INT'
                 is_int &&= f.Range2.Type_expr.Kind == 'INT'
                 CASE !is_int ?
                      err("Range for iterations "
                      "must be specified by two integer values"._Erange ) ;
            ;
            CASE bad ?
                 STR er|ror_text = "Type of loop variable"._Etype2 
                 	" (" v.Type_.Whole_name ") " 
                 	"is not the same as the type of the array"._Eisnot9 
                 	
                 er = er " (" f.Array.Type_expr.Whole_name ")"
                 Parse.Err(er) ;
            -------- 'for CLASS/STRUCTURE variables check for import its class'
            CASE v.Type_.Kind IN ['CLASS', 'STRUCTURE'] ?
                 check_type_imported(v.Type_, "FOR") ;
            ----------------------------------- 'UNROLL modifier'
            CASE Parse.Symbol(",") ?
                 Parse.Wait("UNROLL")
                 f.Unroll = TRUE
                 CASE ?
                 [Parse.Symbol("(")] ?
                      f.Unroll_factor = Parse.Number
                      Parse.Wait(")")
                      CASE f.Unroll_factor <= 1 ?
                           Parse.Err("Unroll factor should be greater then 1"
                           ""._EUnrollFactor0)
                      ;
                 [f.Array != NONE] ?
                      Parse.Err("Unroll factor should be specified for an array"
                      ""._EUnrollFactor)
                 [f.Range1.Operation != 'CONST' || f.Range2.Operation != 'CONST'
                 ] ?  Parse.Err("Unroll factor should be specified in case when"
                 	  " range is specified by not constant values"._EUnroll)
                 ;
                 CASE comp(Parse).Not_unroll ?
                      f.Unroll = FALSE ;
            ;
            Block[] << f
            STR finishing|_symbol = symbol_starting_block(f)
            //Parse.Wait(":")
            ----------------------- 'IN STRUCT[] --> IN [0 TO STRUCT[].Count-1]'
            CASE f.Array.Type_expr.Kind == 'STRUCTURE' ? 
                 f.In_struct_array = f.Array
                 v.Type_ = Parse.Compiler.TYPE_INT
                 CASE f.Range1 == NONE ?
                      f.Range1 = Parse.Compiler.E0
                      
                      {Expr} cnt|_items = {Expr}(Operation= 'SYSTEM_FUN',
                      	Fun_= Parse.Compiler.SYSFUN_Count,
                      	Items_[] << f.Array), OWNED BY f
                      	
                      f.Range2 = {Expr}(Operation= 'BINARY', Sign= 'MINUS',
                      	Arg1_= cnt, Arg2_= Parse.Compiler.E1), OWNED BY f
                 ;
                 f.Array = NONE
            ;
            ----------------------------------- 'body'
            Nesting[] << f
			nesting_level += 1
            {Statement} temp|_block[]
            compile_block(temp[])
            FOR tmp IN temp[] :
                f.Block_[] << tmp
                comp(Parse).Current_fun.Keep_statements[] << tmp ;
            --------------- '$DEBUG? ==> += empty statement'
            CASE "$DEBUG" IN comp(Parse).Defined_name[] ?
                 {Statement} last|_for_line = {Assign}(Line= Parse.Line,
                 	Pos= ident_pos, Function_ = THIS, Level = Current_level,
                 	Work= 'COMMENT'), 
                 OWNED BY THIS
                 
                 f.Block_[] << last
            ;
            Nesting[].Remove(f)
			nesting_level -= 1
			CASE finishing==";" ? 
			     Parse.Want_semicolon("ending FOR started at line " (line+1).Str)
			ELSE Parse.Wait(finishing) ;
            CASE !v.Used_for_r && !v.Used_for_w && (
            	 Parse.Dummy_word !IN v.Names[*].Upper)
            	 && Parse.Syntax_name == ""
            	 ?
                 PUSH Parse.Line = line :
                      warn("Variable"._Wvar2 " " v.Names[*] 
                      " " ("is not used in the loop "
                      "but it has not declared 'dummy'"._Wisnot )) ;
            ; 
            CASE f.Unroll && f.Has_next ? 
                 Parse.Err("It is not allowed to unroll FOR loops having "
                 "NEXT statements"._EUnrollAndNext) ;
            --------------- 'check if DONE used correctly'
            check_done(f) .
            
        METHOD symbol_starting_block({Statement} St|atement) ==> STR :
        	RESULT = ";"
            CASE ?
        	[Parse.Symbol(":") || Parse.Symbol("?")] ?
        	    St.Starting_bracket = ":"
        	    RESULT = ";"
        	[Parse.Symbol("{")] ?
        	    St.Starting_bracket = "{"
        	    RESULT = "}"
        	[Parse.Symbol("<--")] ?
        	    St.Starting_bracket = "<--"
        	    RESULT = "-->"
        	[Parse.Symbol("BEGIN")] ? 
        	    St.Starting_bracket = "BEGIN"
        	    RESULT = "END"
        	[Parse.Symbol("begin")] ?
        	    St.Starting_bracket = "begin"
        	    RESULT = "end"
        	ELSE Parse.Err("Waiting for '{', 'BEGIN' or 'begin'"._EWaitBEGIN) 
        	; .
            
        METHOD automatic_indexing_on_Count
        |_or_variables_defining_range(
        {Var} v|ariable_of_loop,
        {Expr} Range|_2_or_1_may_be_accesing_Count) ==> BOOL
        	:
	        CASE ?
	        [Range.Operation == 'SYSTEM_FUN' 
	         && Range.Fun_ == comp(Parse).SYSFUN_Count] ?
	         	CASE Range.Items_[0].Var_arg.Indexing_[].Count > 0 ?
	         	     {Var} vi|ndexing_var = Range.Items_[0].Var_arg
	         	ELSE {Type} it|ype_intexing = Range.Items_[0].Type_expr ;
	        [Range.Operation == 'SYSTEM_FUN' 
	         && Range.Fun_ == comp(Parse).SYSFUN_Len] ?
	            it = comp(Parse).TYPE_STR
	        [Range.Operation == 'BINARY'
	         && Range.Arg1_.Operation == 'SYSTEM_FUN'
	         && Range.Arg1_.Fun_ == comp(Parse).SYSFUN_Count] ?
	            it = Range.Arg1_.Items_[0].Type_expr
	        [Range.Operation IN ['VAR', 'FIELD'] 
	         && Range.Var_arg.Indexing_[].Count > 0] ?
	            vi = Range.Var_arg
	        [Range.Operation == 'BINARY'] ?
	            CASE ?
	            [Range.Arg1_.Operation IN ['VAR', 'FIELD']
	             && Range.Arg1_.Var_arg.Indexing_[].Count > 0] ?
	                 vi = Range.Arg1_.Var_arg
	            [Range.Arg1_.Operation == 'SYSTEM_FUN'
	             && Range.Arg1_.Fun_ == comp(Parse).SYSFUN_Len] ?
	                 it = comp(Parse).TYPE_STR
	            [Range.Arg2_.Operation IN ['VAR', 'FIELD']
	             && Range.Arg2_.Var_arg.Indexing_[].Count > 0] ?
	                 vi = Range.Arg2_.Var_arg
	            [Range.Arg2_.Operation == 'SYSTEM_FUN'
	             && Range.Arg2_.Fun_ == comp(Parse).SYSFUN_Len] ?
	                 it = comp(Parse).TYPE_STR
	            ELSE ==> ;
	        ELSE ==> ;
	        
	        CASE vi != NONE ?
	             v.Indexing_[].Clear
	             FOR ix IN vi.Indexing_[] :
	                 v.Indexing_[] << ix ;
	             v.Automatic_indexing = TRUE
	             RESULT = TRUE ==> ;
	             
	        CASE it == NONE ? ==> ;

	        v.Indexing_[].Clear
	        v.Indexing_[] << it
	        v.Automatic_indexing = TRUE
	        RESULT = TRUE .
            
        METHOD for_enum({Statement} Block|_statements[],
        	{Var} v|ariable)
            :
	        INT line|_starting = Parse.Line
	        INT limit|_iterations = 1_000_000
	        CASE Parse.Symbol("(") ?
	             Parse.Wait("MAX")
	             limit = Parse.Number 
	             Parse.Wait(")") ;
	             
	        {Expr} ef|unction_enum = Recognize_typed(Parse, 'BOOL'), 
	        	>> comp(Parse).Current_fun.All_expr[]
	        	
	        CASE ef.Operation != 'FUN' || ef.Fun_.Modifiers['STATIC'] ?
	             Parse.Err("FOR ENUM not on base a method"._EForEnumNotMethod);
	        CASE ef.Fun_.Param[].Count > 0 ?
	             Parse.Err("Method called in FOR ENUM should not have "
	             "parameters"._EForEnumParams) ;
	        -------------- 'create statement FOR'
	        f|or_loop_temp = {For}(Var = v, Line = Parse.Line, Pos= 0,
                Function_ = THIS, Level = Current_level, Breaked= TRUE)
                
            v.For_ = f
            Parse.Skip_sp
            Block[] << f
            STR finishing|_symbol = symbol_starting_block(f)
            //Parse.Wait(":")
            ----------------------------------- 'range from 0 to limit'
            CASE v.Type_ != NONE && v.Type_.Kind != 'INT' ?
                 Parse.Err("Type of FOR ENUM variable must be INTEGER"
                 ""._EForEnumVarTypeNotINT)
            ;
            v.Type_ = comp(Parse).TYPE_INT
            f.Range1 = comp(Parse).E0
            
            f.Range2 = {Expr}(Operation= 'CONST',
            	Var_arg= {Var}(
            		Line=0, Type_= comp(Parse).TYPE_INT, Int_c= limit)),
            	>> All_expr[]
            ----------------------------------- 'body'
            Nesting[] << f
			nesting_level += 1
            --------------------- 'add iteration condition check'
            {Case} c|ase_check_iteration = {Case}(Level=Current_level,
            	Line=line, Pos= 0, Function_= THIS, Condition= ef),
            	>> comp(Parse).Current_fun.Keep_statements[]
            	
            f.Block_[] << c
            	
            {Case} t|rue_case = {Case}(Level= Current_level,
            	Line= line, Pos= 0, Function_= THIS, 
            	Values[] << comp(Parse).TRUE_c),
            	>> comp(Parse).Current_fun.Keep_statements[]
            	
            c.Block_[] << t
            	
            {For} br|eak_if_final_iteration = {For}(Level=Current_level,
            	Line=line, Pos= Parse.Pos, Function_= THIS,
            	Work= 'BREAK', Loop_= f),
            	>> comp(Parse).Current_fun.Keep_statements[]
            	 
            t.Block_[] << br
            --------------------- 'other nesting block statements'
            {Statement} temp|_block[]
            compile_block(temp[])
            FOR tmp IN temp[] :
                f.Block_[] << tmp
                comp(Parse).Current_fun.Keep_statements[] << tmp ;
            Nesting[].Remove(f)
			nesting_level -= 1
			CASE finishing==";" ? 
			     Parse.Want_semicolon("ending FOR started at line " (line+1).Str)
			ELSE Parse.Wait(finishing) ;
            check_done(f) .
            
        METHOD compile_done :
	        {For} f|or_current = Nesting[*].{For}
	        CASE f == NONE ?
	             Parse.Err("Statement DONE not nesting a FOR block"
	             ""._EDoneNotInFor)
	        ;
	        CASE f.Done >= 0 ?
	             Parse.Err("More then one DONE statement in the FOR block"
	             ""._EDoneDup)
	        ;
	        f.Done = f.Block_[].Count .
	        
        METHOD check_done({For} f|or_statement) :
	        FOR i IN [f.Block_[].Count-1 DOWNTO 0] :
	            CASE f.Block_[i].Work == 'COMMENT' ? CONTINUE i ;
	            DONE     
		             {Statement} last|_not_comment = f.Block_[i]
		             BREAK i ;     
	        CASE f.Done < 0 ?
	             CASE last.Work IN ['BREAK', 'RETURN'] ?
	             	PUSH Parse.Line = last.Line-1 :     
			             Parse.Warn("Still the last statement of the FOR "
			             "is BREAK or ==>, it is necessary to use the "
			             "statement DONE just after the last CONTINUE "
			             "statement"._WLastOfForIsBreakButDoneNotUsed)  ;
	             ;
	             ==>
	        ;
	        CASE last.Work !IN ['BREAK', 'RETURN'] ?
	        	 PUSH Parse.Line = f.Block_[f.Done].Line :    
	        	      CASE Parse.Line <= 0 ? Parse.Line = f.Line ;
		              Parse.Err("Statement DONE can be used only in FOR "
		              "blocks ending with the BREAK/==> statement"
		              ""._EDoneNotBreak)
		              ==> ;
	        ;
	        FOR i IN [f.Block_[].Count-1 DOWNTO 0] :
	        	{Statement} temp|_array[]
	        	temp[].Clear
	        	temp[] <<  f.Block_[i]
	            CASE has_continue(temp[], f) ?
	                 //INT case|_position = i
	                 BREAK i ;
	        ;
	        INT next|_following_done_not_comment = f.Done
	        FOR i IN [f.Done TO f.Block_[].Count-1] :
	            CASE f.Block_[i].Work == 'COMMENT' ? CONTINUE i ;
	            DONE     
		             next = i
		             BREAK i ;     
	        FOR i IN [next DOWNTO 0] :
	            CASE i == f.Done ? ==> ;
	            CASE f.Block_[i].Work == 'COMMENT' ? CONTINUE i ;
	            temp[].Clear
	            temp[] << f.Block_[i]     
	            CASE !has_continue(temp[], f) ? CONTINUE i ;    
	            DONE
	            PUSH Parse.Line = f.Block_[f.Done].Line :
		             Parse.Err("Statement DONE should be places just after "
		             "the last CONTINUE statement"._EDoneAfterContinue) 
	            ; 
	            ==>
	        ; .  
	        
        FUN has_continue(
        {Statement} b|lock_of_statements[], 
        {For} f|or_of_which_continue_is) ==> BOOL, RECURSIVE
        	:
        	FOR st IN b[] :
        	    CASE st.Work == 'CONTINUE' && st.{For}.Loop_ == f ?
        	         RESULT = TRUE ;
        	    RESULT = has_continue(st.Block_[], f)
        	    CASE RESULT ? ==> ;
        	; .
	        	     

        METHOD make_empty_last_square_brackets
        ==> BOOL
        	:
			STR s|tring_at_Line = Parse.Source[Parse.Line]
			BOOL in_str|ing_const
			FOR i IN [0 TO s.Len-1] :
				CASE s.[i] == #QU ? in_str = !in_str ; 
				CASE in_str ? s = s.[0 TO i-1] #QU s.[i+1 TO *] ;
			;
			INT prev|ious_symbol_position = -1 
			FOR i IN [Parse.Pos TO s.Len-1] :
			    CASE s.[i] != ":" ?
			         CASE s.[i] !IN #SP#TAB#NL ? prev = i ;
			         CONTINUE i ;
			    DONE
				     CASE s.[prev] != "]" ? ==> ;
				     BREAK i ;
			INT lev|el_brackets = 1
			FOR i IN [prev-1 DOWNTO Parse.Pos+1] :
				CASE s.[i] ?
				["]"]: lev += 1
				["["]: lev -= 1
					   CASE lev <= 0 ?
					        INT at|_position_bracket = i
					        BREAK i ;
				;
			;
			CASE at < Parse.Pos ? ==> ;
			RESULT = s.[at+1 TO prev-1].Trim != ""
			Parse.Source[Parse.Line] = Parse.Source[Parse.Line].[0 TO at] "]:" . 
			    
            
        METHOD check_type_imported(
            {Type} T|ype_to_check,
            STR St|atement_type_DUMMY)
            :
            {Type} cc|urrent_class = comp(Parse).Current_class
            {Type} c|lass_to_check = T
            CASE T.Kind == 'STRUCTURE' ? c = T.In_class_ ;
            CASE ?
            [c == cc] ? ==>
            [c.Names[1] == "{Object}"] ? ==>
            [Compiling_debug && (
             c !IN cc.Debug_import_[]) && (
             c !IN cc.Import_[])] ?
                 BOOL bad_type = TRUE
            [!Compiling_debug && c !IN cc.Import_[]] ?
                 bad_type = TRUE ;
            
            CASE bad_type ?
                 CASE T.Kind == 'CLASS' ?
                      err("Variable has type of class which is not "
                      "imported"._Eloop2 ": " T.Whole_name)
                      
                 ELSE err("Variable has type of record located in class "
                      "which is not imported"._Eloop3 
                      ": " c.Whole_name)
                 ;
            ELSE ------------------------------------ 'mark such import "used"'
                 CASE c !IN cc.Used_imports_[] ? cc.Used_imports_[] << c ;
            ; .

        */
        private void compile_for(List<Statement> Block)
        {
            int line = Parse.Line;
            string name = Parse.Ident();
            string name2 = name;
            if (Parse.Symbol("|"))
                name2 = name + Parse.Ident();
            //-------------------------------- 'variable'
            Variable v = comp(Parse).Current_fun.Search_var(name);
            if (v == null)
            {
                v = new Variable(comp(Parse));
                v.In_fun_ = this;
                v.Is_loop_var = true;
                v.Line = Parse.Line;
                Local_var.Add(v);
                v.Names.Add(name);
                if (name2 != name) v.Names.Add(name2);
                Parse.Check_reserved(v.Names);
                Parse.Check_local_names(v.Names);
            }
            //-------------- indexing
            if (Parse.Symbol("INDEXING")) {
            	if (Parse.Symbol("(")) {
            	   Parse.Skip_to(")");
            	   Parse.Wait(")");
            	}
            	else Parse.Skip_to(" ");
            }
            if (!v.Is_loop_var)
                err("Variable " + name + " can not be reused as a loop variable");
            if (!v.Names.Contains(name) || !v.Names.Contains(name2))
                err("Wrong re-defining variable " + name2 );
            foreach (Statement n in nesting)
            {
                if (n.Work == Statement.Workflow.FOR && ((AL4Compiler._CSharp.For)n).Var == v)
                    err("Re-using loop variable " + v.Names[v.Names.Count - 1] +
                        " in the nesting loop");
            }
            Parse.Wait("IN");
            //---------------------------------------- 'array'
            For f = new For();
            f.Work = Statement.Workflow.FOR;
            f.Line = Parse.Line;
            f.Var = v;
            Block.Add(f);
            Parse.Skip_sp();
            switch ((Parse.Next_char() + " ")[0])
            {
                case '[':
                    v.Type_ = comp(Parse).TYPE_INT;
                    Parse.Skip_char();
                    f.Range1 = Expression.Recognize_typed(Parse, Type.Kind_type.INT);
                    string id = Parse.Ident();
                    if (id == "TO") { }
                    else if (id == "DOWNTO") f.Downto = true;
                    else err("Waiting for TO or DOWNTO but: " + Parse.Next20());
                    f.Range2 = Expression.Recognize_typed(Parse, Type.Kind_type.INT);
                    //---------------------------------- 'check int'
                    Type t1 = f.Range1 != null ? f.Range1.Type_expr() : null;
                    Type t2 = f.Range2 != null ? f.Range2.Type_expr() : null;
                    bool integers = f.Range1 != null && f.Range2 != null && 
                        t1 != null && t2 != null &&
                        t1.Kind == Type.Kind_type.INT && t2.Kind == Type.Kind_type.INT;
                    if (!integers) err("Range for iterations " +
                            "must be specified by two integer values");
                    if (v.Type_ != null && v.Type_.Kind != Type.Kind_type.INT)
                        err("Loop variable type is " +
                            "not compatible with the integer range");
                    v.Type_ = comp(Parse).TYPE_INT;
                    Parse.Wait("]");
                    break;
                default:
                    f.Array = Expression.Recognize(Parse);
                    if (f.Array != null && !f.Array.Is_array())
                        err("An array must be specified to iterate in it");
                    if (f.Array != null)
                        v.Type_ = f.Array.Type_expr();
                    break;
            }
            Parse.Wait(":");
            //-------------------------------- 'body'
            nesting.Add(f);
            compile_block(f.Block_);
            nesting.Remove(f);
            Parse.Wait(";");
            if (!v.Used && !v.Names[v.Names.Count - 1].Contains("dummy"))
            {
                int temp = Parse.Line;
                Parse.Line = line;
                try
                {
                    warn("Variable " + v.Names[v.Names.Count - 1] +
                        " is not used in the loop but it is not declared 'dummy'");
                }
                finally { Parse.Line = temp; }
            }
        }

        /*
        
        METHOD compile_break({Statement} Block|_of_statements[]) :
			Has_break_cont = TRUE
            Block[] << handle_break_cont('BREAK', Nesting[].Count) .
        */
        private void compile_break(List<Statement> Block)
        {
            Block.Add(handle_break_cont(Statement.Workflow.BREAK));
        }

        /*
        
        METHOD compile_continue(
        	{Statement} Block|_of_statements[])
        	:
			Has_break_cont = TRUE
            Block[] << handle_break_cont('CONTINUE', Nesting[].Count) .
        */
        private void compile_continue(List<Statement> Block)
        {
            Block.Add(handle_break_cont(Statement.Workflow.CONTINUE));
        }
        
        /*
        
        METHOD compile_next(
        	{Statement} Block|_of_statements[])
        	:
			Has_break_cont = TRUE
            Block[] << handle_break_cont('NEXT', Nesting[].Count) 
            {For} next|_statement = Block[*].{For}
            CASE next.Loop_.Array != NONE ? 
                 Parse.Wait(".") 
                 Parse.Wait("INDEX") ;
            CASE next.Loop_.Downto ? 
                 Parse.Wait("-=")
            ELSE Parse.Wait("+=") ;
            next.By = Recognize_typed(Parse, 'INT')
            next.Loop_.Has_next = TRUE .

        
        METHOD handle_break_cont|inue(
        	{Statement}.{work} W|orkflow,
        	INT From|_index_in_nesting_search_down) ==> {For}, NEW, RECURSIVE
        	:
            RESULT = {For}(Work = W, Line = Parse.Line, Pos= ident_pos,
            	Function_ = THIS, Level = Current_level),
            	OWNED BY THIS
            	
            STR lab|el_loop = Parse.Ident
            {Var} v|ariable = Search_var(lab, TRUE)
            CASE v !IN Local_var[] ?
                err(lab " " ("is not a local variable"._Eisnot10 )) ;
            FOR i INDEXING {Statement} IN [From-1 DOWNTO 0]:
                {Statement} st|atement_in_nesting = Nesting[i]
                CASE st.Work == 'PUSH' ?
                     st.{Assign}.Intersect = TRUE ;
                CASE st.{For} == NONE ? CONTINUE i ;
                DONE     
	                 CASE st.{For}.Var != v ?
	                	  CASE W == 'BREAK' ?
	                     	   err("The BREAK statement label must be"._ETheBrk
	                     	   " " st.{For}.Var.Names[0])
	                	  ELSE err("The NEXT/CONTINUE statement label must "
	                	  "be"._ETheCont " " st.{For}.Var.Names[0]) ;
	                 ;
	                 CASE W IN ['NEXT', 'CONTINUE'] ?
	                      RESULT.Loop_ = st.{For}
	                      st.{For}.Continued = TRUE ==> ;
	                 CASE Parse.Symbol(",") ?
	                      CASE ?
	                      [Parse.Symbol("CONTINUE")] ?
	                           RESULT = handle_break_cont('CONTINUE', i) ==> 
	                      [Parse.Symbol("NEXT")] ?
	                           RESULT = handle_break_cont('NEXT', i) ==> 
	                      ;
	                      Parse.Wait("BREAK")
	                      RESULT = handle_break_cont('BREAK', i) ==> ;
	                 RESULT.Loop_ = st.{For}
	                 st.{For}.Breaked = TRUE ==> ;
            err(lab " " ("is not a label of a loop"._Eisnot11 )) .
            
        */
        private Statement handle_break_cont(Statement.Workflow W)
        {
            For Result = new For();
            Result.Work = W;
            Result.Line = Parse.Line;
            string lab = Parse.Ident();
            Variable v = Search_var(lab);
            if (!Local_var.Contains(v))
                err(lab + " is not a local variable");
            while (Parse.Symbol(","))
            {
            	string k = Parse.Ident();
            	if (k == "BREAK") W = Statement.Workflow.BREAK;
            	else if (k == "CONTINUE") W = Statement.Workflow.CONTINUE;
            	else err("Waiting for BREAK or CONTINUE: " + Parse.Rest_of_line());
            	
            	Result.Work = W;
            	lab = Parse.Ident();
            	v = Search_var(lab);
	            if (!Local_var.Contains(v))
	                err(lab + " is not a local variable");
            }
            foreach (Statement n in nesting)
            {
                if (n is For && ((For)n).Var == v)
                {
                    Result.Loop_ = n;
                    if (W == Statement.Workflow.BREAK)
                        ((For)n).Breaked = true;
                    else ((For)n).Continued = true;
                    break;
                }
            }
            if (Result.Loop_ == null)
                err(lab + " is not a label of a loop");
            return Result;
        }

        /*
        
        METHOD compile_case({Statement} Block|_of_statements[]) :
            ---------------------- 'create CASE'
            s|witch_statement_temp = {Case}(Line = Parse.Line, Pos= ident_pos,
            	Top_case = TRUE, Function_ = THIS, Level = Current_level)
                
            STR finishing|_symbol = ";"
            //CASE Class_.Syntax_fun!=":" ?
            CASE Parse.Symbol("THEN") || Parse.Symbol("then") ? NONE ;
            Parse.Skip_sp     
            CASE Parse.Next_symbol("?")
            	 || Parse.Next_symbol(":")     
                 || Parse.Next_symbol("{") 
                 && Parse.Source[Parse.Line].[Parse.Pos+1].Trim == ""
                 || Parse.Next_symbol("BEGIN") 
                 || Parse.Next_symbol("begin")
                 || Parse.Next_symbol("<--")
                 ? 
                 BOOL sequent|ial_case = TRUE
                 finishing = symbol_starting_block(s)
            ELSE sequent = FALSE // Parse.Symbol(":") 
            	 //Parse.Wait("?") 
            ;
            CASE !sequent ?
                 s.Condition = Expr
                 CASE s.Condition.Type_expr == NONE 
                      || s.Condition.Type_expr.Kind !IN [
                 	  'BOOL', 'INT', 'ENUM', 'STR']
                 	  ?
                      Parse.Err("CASE condition must be of BOOL, INT, ENUM,"
                      "BYTE or STR data type"._ECaseCondMustBeTyped)
                 ;
                 extract_new_operations(s.Condition, Block[], 0)
                 CASE ?
                 [s.Condition.Type_expr.Kind == 'REAL'] ?
                      Parse.Err("CASE expression can not have REAL "
                      "type"._Ecase)
                      
                 [s.Condition.Type_expr.Kind == 'CLASS'] ?
                      Parse.Err("CASE expression can not have object "
                      "type"._Ecase2)
                 ;
                 Parse.Spaces_back
                 PUSH Parse.Pos :
                      STR rest_to_q|uestion_mark = Parse.Skip_to("?")
                      
                      STR line_b|efore_question = Parse.Source[Parse.Line].[
                          0 TO Parse.Pos]
                          
                      CASE #NL IN line_b && #NL !IN rest_to_q
                           ?
                           Parse.Warn("In CASE statements having conditions "
                           "containing several lines a question mark should be "
                           "placed in a separate line"._Wincase ) ;
                 ;
                 //Parse.Wait("?")
                 finishing = symbol_starting_block(s)
                 ---------------- '1 line CASE cond ? ... ELSE ... ;'
                 CASE s.Condition.Type_expr.Kind == 'BOOL' 
                      && Ending(Parse.Source[Parse.Line].Trim, ";") 
                      ?
                      STR rest|_of_line = Parse.Rest_of_line 
			          INT else|_in_same_line = rest.Hide_str.Find(" ELSE ") 
                 ;
		         CASE else > 0 ?
		         	  Block[] << s     
		         	  compile_1line_case_else(s, rest, else) ==> ;
            ;
            CASE Parse.End_of_line ? Parse.Fin ;
            STR sline|_current = Parse.Source[Parse.Line].[Parse.Pos TO *].Trim
            CASE sline.[0] == "{" && Starting(sline.[1 TO *].TrimL, "{") ? 
            	 compile_case_overload(Block[]) 
            	 Parse.Wait(finishing) ==> ;
            Block[] << s
            Nesting[] << s
			nesting_level += 1
			------------------ 'branches'
            CASE Parse.End_of_line ? Parse.Fin ;
            Parse.Skip_sp
            CASE s.Condition != NONE && s.Condition.Type_expr.Kind == 'BOOL' ?
                 PUSH count_compiled_statements = 0 :
                      bool_cond_true(s)
                      BOOL no_statements = count_compiled_statements==0 ;
                 CASE Parse.Symbol("ELSE") ?
                      PUSH count_compiled_statements = 0 :
                           bool_cond_else(s)
                           no_statements = count_compiled_statements==0 ;
                 ;
                 CASE no_statements ? 
                      Parse.Err("There are no statements in the CASE branch"
                      ""._ENoStatements) 
                 ;
            ELSE compile_cases(s, Block[]) ;
            
            CASE finishing==";" ? 
	             Parse.Want_semicolon("ending CASE started at line"._Eending 
	             " " (s.Line+1).Str)
            ELSE Parse.Wait(finishing) ;
                
            Nesting[].Remove(s)
			nesting_level -= 1 .
			
INT count_compiled_statements
			
METHOD bool_cond_true({Case} s|tatement) :
	t|rue_case = {Case}(Line = Parse.Line, Pos= Parse.Pos, Function_ = THIS,
	Level = Current_level), OWNED BY s
	s.Block_[] << t
	t.Values[] << comp(Parse).TRUE_c
	{Statement} temp|_block[]
	temp[].Clear
	compile_block(temp[])
	FOR st IN temp[] :
	    t.Block_[] << st
	    comp(Parse).Current_fun.Keep_statements[] << st ; .
	    
METHOD bool_cond_else({Case} s|tatement) :
	f|alse_case = {Case}(Work = 'ELSE', Function_ = THIS,
	   Line = Parse.Line, Pos= Parse.Pos, Level = Current_level), OWNED BY s
	s.Block_[] << f
	{Statement} temp|_block[]
	temp[].Clear
	compile_block(temp[])
	FOR st IN temp[] :
	    f.Block_[] << st
	    comp(Parse).Current_fun.Keep_statements[] << st ; .
			
METHOD compile_1line_case_else(
{Case} s|tatement, STR rest|_of_line_to_compile, 
INT else|_position)
    :
    STR before|_Pos = Parse.Source[Parse.Line].[0 TO Parse.Pos-1]
    PUSH Parse.Source[Parse.Line] = before rest.[0 TO else-1] ";" :
    PUSH Parse.Line :
         //LIKE compile_case ............. 'bool condition - true branch'
         bool_cond_true(s)
    ;
    ;
    Parse.Pos = before.Len + else
    Parse.Wait("ELSE")
    //LIKE compile_case  ................. 'bool condition - ELSE branch'
    bool_cond_else(s)
    Parse.Wait(";") .
    
METHOD compile_limit({Statement} Block|_of_statements[]) :
    ---------------------- 'create LIMIT'
    s|tatement_temp = {Limit}(Line = Parse.Line, Pos= ident_pos,
        Function_ = THIS, Level = Current_level)
        
    CASE Parse.Ident ?
    ["TIME"]: s.By_what = 'TIME'
    ["FUN", "FUNCTIONS"]: s.By_what = 'FUNC'
    	Parse.Compiler.Has_LIMIT_FUNC = TRUE
    ["LOOPS"]: s.By_what = 'LOOPS'
    	Parse.Compiler.Has_LIMIT_LOOPS = TRUE
    ELSE Parse.Err("Waiting for LIMIT TIME/FUN|CTIONS/LOOPS but"
    	 ""._EWaiting_limit ": " Parse.Next20) ;
    Parse.Wait("(")
    s.Condition = Expr 
    CASE s.Condition.Type_expr.Kind !IN ['INT', 'REAL'] ? 
         Parse.Err("Waiting for a numeric expression byt found"
         ""._EWait_numeric_limit ": " s.Condition.Type_expr.Kind.Name) ;
    Parse.Wait(")")
    CASE s.By_what == 'TIME' ? 
         CASE Parse.Ident ? 
         ["MSEC", "MILLISECONDS", "MS"]: s.Units = 'MILLISEC'
         ["SEC", "SECONDS", "S"]: s.Units = 'SECONDS'
         ["MIN", "MINUTES", "M"]: s.Units = 'MINUTES'
         ["HOURS", "H"]: s.Units = 'HOUR'
         ["DAYS", "D"]: s.Units = 'DAYS' 
         ELSE Parse.Err("Waiting for time units (MSEC/SEC/MIN/HOURS/DAYS) but"
         	  ""._EWaiting_time_units ": " Parse.Next20) ;
    ;
    STR finishing|_symbol = symbol_starting_block(s)
    //Parse.Wait(":")
    ---------------- 'nested block'
    {Statement} temp|_block[]
	compile_block(temp[])
	CASE finishing==";" ? 
	     Parse.Want_semicolon("ending LIMIT block at " (s.Line+1).Str)
	ELSE Parse.Wait(finishing) ;
	FOR st IN temp[] :
        s.Block_[] << st
        comp(Parse).Current_fun.Keep_statements[] << st ;
    Block[] << s .
    
{Local} Current_local|_block_compiling
    
METHOD compile_local({Statement} Block|_of_statements[]) :
	CASE Current_local != NONE ? 
	     Parse.Err("Nested LOCAL blocks are not allowed"._ENestedLOCAL) ;
    ---------------------- 'create LIMIT'
    s|tatement_temp = {Local}(Line = Parse.Line, Pos= ident_pos,
        Function_ = THIS, Level = Current_level)
        
    STR finishing|_symbol = symbol_starting_block(s)
    PUSH Current_local = s :
	     ---------------- 'nested block'
	     {Statement} temp|_block[]
		 compile_block(temp[])
		 CASE finishing==";" ? 
		      Parse.Want_semicolon("ending LIMIT block at " (s.Line+1).Str)
		 ELSE Parse.Wait(finishing) ;
		 FOR st IN temp[] :
	         s.Block_[] << st
	         comp(Parse).Current_fun.Keep_statements[] << st ;
    ;
    Block[] << s .
    
    
FUN Hide_str|ing_constants_replace_tabs(
STR S|tring_source) ==> STR
    :
    RESULT = S
    BOOL in_s|tring_literal = FALSE
    FOR i IN [0 TO RESULT.Len-1] :
        CASE RESULT.[i] ? 
        [#QU]: in_s = !in_s
        [#TAB]: RESULT.[i] = #SP ;
        CASE in_s ? RESULT.[i] = #QU ;
    ; .
            
        {Statement} All_statements|_which_were_created_in_weak_lists[]
                     
        METHOD compile_case_overload(
        {Statement} Block|_of_statements[])
        	:
			CASE Overload_base_==NONE ?
			     Parse.Err("Function is not overloaded, so it can not have "
			     "CASE statements in such form"._ENotOverloaded)
			;
			------------------ 'fix { { --> {{'
			
			FOR y IN [Parse.Line TO Parse.Source[].Count-1] :
			    STR s|tring_at_y = Parse.Source[y]
			    CASE y == Parse.Line ? s = s.[Parse.Pos TO *].Trim
			    ELSE s = s.Trim ;
			    CASE s.[0] == "{" ? 
			         CASE Starting(s.[1 TO *].TrimL, "{") ?
			              CASE Parse.Line == y ? 
			              	   Parse.Source[y] = Parse.Source[y].[0 TO Parse.Pos-1] 
			              	   		"{" s.[1 TO *].TrimL
			              	   		
			              ELSE Parse.Source[y] = "{" s.[1 TO *].TrimL ; 
			         ;
			    ;
			    CASE s.[*] == "." ? BREAK y ;
			;
			Parse.Reset_cache_last_pos
			-------------------------- 'find self in overloaded functions list'
			INT i|ndex_this_function = Class.Method[].Find(THIS)
			FOR j INDEXING {Fun} IN [i-1 DOWNTO 0] :
			    CASE Class.Method[j].Overloaded_[].Count > 0 ?
			         {Fun} of|unction_overloaded = Class.Method[j] 
			         i = of.Overloaded_[].Find(THIS)
			         BREAK j ;
			;
			CASE i < 0 ? 
			     Parse.Err("Internal error: overloading index was not found") ;
			---------------------- 'mark all the parameters overloaded as used'
			FOR p IN of.Param[] :
			    p.Used_for_r = TRUE ;
			-------------------------- 'find only the case with index i+1'
			INT nsign|ature_numbers_found[]
			FOR y IN [Parse.Line TO Parse.Source[].Count] :
                //CASE Class_.Syntax_fun.[0] IN "Bb" ? 
                //     STR wait_then = "then"     
                //     CASE !Parse.Symbol("if") ?
                //          wait_then = "THEN"
                //          Parse.Wait("IF") ;
                //;
			    Parse.Wait("{{")
			    BOOL desired|_branch = FALSE 
			    FOR x|dummy IN [Parse.Pos TO Parse.Last] :
			    	INT n|umber_of_signature = Parse.Number
			    	CASE ?
			    	[n < 1 || n > of.Overloaded_[].Count] ?
			    	     Parse.Err("Type signature index should be between 1 "
			    	     "and"._ESignatureIndex " " of.Overloaded_[].Count.Str)
			    	[n IN nsign[]] ?
			    	     Parse.Err("Duplicating signature index"._EDupSignat
			    	     ": " n.Str) 
			    	;
			    	nsign[] << n
			    	CASE n == i+1 ? desired = TRUE ;
			    	---------------- 'check signature'
			    	Parse.Wait("/")
			    	STR sig|nature_types = scan_signature
			    	CASE desired && sig != get_signature(of) ?
			    	     Parse.Err("Signature does not correspond to the index"
			    	     ""._ESignatNotCorrespond ": " n.Str "/" sig
			    	     " but waiting for " n.Str "/" get_signature(of))
			    	;
			    	CASE !Parse.Symbol(",") ? BREAK x ;
			    ;
			    Parse.Wait("}")
			    Parse.Wait("}")
			    //STR finishing|_symbol = symbol_starting_block
			    Parse.Wait(":")
			    CASE desired ?
			         compile_block(Block[])
			    ELSE
			    	 skip_branch()
			    	 //PUSH Dummy_compile = TRUE :
				    	  //{Statement} temp|_to_skip_temp[]
				    	  //compile_block(temp[]) ;
			    ;
			    CASE !Parse.Next_symbol("{{") ? BREAK y ;
			; .
			
        METHOD skip_branch :
            FOR y IN [Parse.Line TO Parse.Source[].Count-1] :
                STR s|tring_at_y = Parse.Source[y].Trim
                CASE y > Parse.Line && Starting(s, "{{") ? 
                     Parse.Line = y
                     Parse.Pos = 0 ==> ;
                CASE s.[0] IN "CFDPS" && s.Keyword_starting IN [
                	 "CASE", "FOR", "DEBUG", "PUSH", "SILENT"] 
                	 ? 
                     INT lev|el_nesting += 1 ;
                CASE s.[*] IN ";." ? 
                     lev -= 1 ;
                CASE lev < 0 || s.[*]=="." ? 
                     Parse.Line = y
                     Parse.Pos = Find_last(Parse.Source[y], ";") ==> ;
            ; .
            
        FUN Keyword_starting(
        STR S|tring_starts_from_ident) ==> STR
            :
            FOR i IN [0 TO S.Len] :
                CASE S.[i] !IN "ABCDEFGHIJKLMINOPQRSTUVWXYZ" ? 
                     RESULT = S.[0 TO i-1] ==> ;
            ; .
			
        METHOD scan_signature ==> STR :
			FOR idummy IN [Parse.Pos TO Parse.Last] :
			    RESULT = RESULT Parse.Scan_type
			    CASE !Parse.Symbol("/") ? ==> ;
			    RESULT = RESULT "/" ; .
			    
        METHOD get_signature({Fun} OF|unction_overloaded) ==> STR :
			FOR p IN Param[] :
			    CASE the_same_type_parameter(OF, p.Index) ? CONTINUE p ;
			    CASE p.Type_.Kind ?
			    ['BOOL']: RESULT = RESULT "/{bool}"
			    ['INT']: RESULT = RESULT "/INT"
			    ['REAL']: RESULT = RESULT "/REAL"
			    ['STR']: RESULT = RESULT "/STR"
			    ['ENUM', 'STRUCTURE', 'CLASS']: 
			        RESULT = RESULT "/" p.Type_.Names[0]
			    ;
			;
			RESULT = RESULT.[1 TO *] .
			
        FUN the_same_type_parameter(
        {Fun} OF|unction_overloaded, INT P|arameter INDEXING {Var}) ==> BOOL
        	:
        	{Type} t0|_of_the_1st_overloaded = OF.Overloaded_[0].Param[P].Type_
        	FOR f IN OF.Overloaded_[] :
        		CASE f.Index == 0 ? CONTINUE f ;
        		CASE f.Param[P].Type_.Kind != t0.Kind ? ==> ;
        		CASE t0.Kind IN ['ENUM', 'STRUCTURE', 'CLASS']
        			 && f.Param[P].Type_ != t0
        			 ?
        		     ==> ;
        	;
        	RESULT = TRUE .
			    
                               
        */
        private void compile_case(List<Statement> Block)
        {
            Case s = new Case();
            
            s.Line = Parse.Line;
            Block.Add(s);

            if (!Parse.Symbol("?"))
            {
                s.Condition = Expr();
                Parse.Wait("?");
            }

            nesting.Add(s);
            if (Parse.End_of_line()) Parse.Fin();
            if (s.Condition != null && s.Condition.Type_expr() != null && s.Condition.Type_expr().Kind == Type.Kind_type.BOOL)
            {
                Case t = new Case();
                t.Line = Parse.Line;
                s.Block_.Add(t);
                t.Values.Add(comp(Parse).TRUE_c);
                compile_block(t.Block_);
                if (Parse.Symbol("ELSE"))
                {
                    Statement f = new Statement();
                    f.Work = Statement.Workflow.ELSE;
                    f.Line = Parse.Line;
                    s.Block_.Add(f);
                    compile_block(f.Block_);
                }
            }
            else compile_cases(s);
            Parse.Wait(";");
            nesting.Remove(s);
        }

        /*
        INT position_case|_start
        
        METHOD compile_cases(
        {Case} S|witch_statement,
        {Statement} Block|_parent[])
        	:
            ------------------------------- 'Cases of CASE'
            {Var} all_ranges[]
            {Type} t|ype_of_condition = S.Condition.Type_expr
            INT n|um_not_else_blocks
            INT line|_switch_started = Parse.Line
            {Assign} comments|_before_any_case[]
            FOR x|dummy IN [Parse.Line TO Parse.Source[].Count] :
                Parse.Skip_sp
                BOOL next_else = FALSE
                CASE Parse.Next_char ?
             	["."]:
        			CASE !Parse.Next_symbol("..") ? BREAK x ;
                [";", #0 ]: BREAK x
                ["-"]:
        			CASE ?
        			[Parse.Next_symbol("-->")] ? BREAK x
        			[Parse.Next_symbol("--")] ?
        			     {Assign} a|_comment = compile_comment,
        			     	>> Keep_statements[]
        			     	
        				 comments[] << a
        			;
                ["}"]: BREAK x
                ["e"]:
                    	CASE ?
                    	[Parse.Next_symbol("else")] ? next_else = TRUE
                    	[Parse.Next_symbol("end") ] ? BREAK x ;
                ["E"]:
                    	CASE ? 
                    	[Parse.Next_symbol("ELSE")] ? next_else = TRUE     
                    	[Parse.Next_symbol("END") ] ? BREAK x ;
                ["["]: INT count_cases|_other_then_ELSE += 1  
                
                    c|ase_of_switch = {Case}(Line = Parse.Line, 
                    	Pos= Parse.Pos,
                        Function_ = THIS,Level = Current_level),
                        OWNED BY S
                        
                    FOR cc IN comments[] :
                        c.Block_[] << cc ;
                    comments[].Clear
                    S.Block_[] << c
                    Parse.Wait("[")
                    CASE Parse.Next_symbol("]") ?
                    	 Parse.Err("Branch condition is empty"
                    	 ""._EEmptyCondition)
                    ;     
                    PUSH position_case = Parse.Pos :
                         CASE S.Condition == NONE ?
                         	  ------------------- 'sequential?'
                              c.Condition = Recognize_typed(Parse, 
                                'BOOL')
                              ------------- 'last is the CASE'
                              {Statement} last|_in_block = Block[*]
                              Block[].Delete(Block[].Count-1)
                              
                              extract_new_operations(c.Condition,
                              	Block[], 0)
                              ------ '... it stay be the last'
                              Block[] << last	
                              disallow_new_operations(c.Condition)
                              ----------------- ']'
                              Parse.Skip_sp
                              STR before_q|uestionmark = Parse.Rest_of_line
                              before_q = before_q.[0 TO before_q.Find("?")-1]
                               
                              Parse.Wait("]")
                              ----------------- '? ...'
                              Parse.Skip_sp
                              STR after_q|uestion_mark = Parse.Rest_of_line
                              after_q = after_q.[1 TO *]
                              should_be_1st_or_last_in_line(before_q, after_q)
                              
                              Parse.Wait("?")
                         ELSE n += collect_values(t, c, all_ranges[]) 
                              Parse.Wait("]")
                              //CASE wait_then != "" ? Parse.Wait(wait_then) 
                              //ELSE Parse.Wait(":") ;
                              Parse.Wait(":")
                         ;
                    ;
                ELSE next_else = TRUE ;
                CASE next_else ? 
                     c = {Case}(
                			Work = 'ELSE', Line = Parse.Line, Pos= Parse.Pos,
                			Function_ = THIS, Level = Current_level),
                			OWNED BY S
                                
                     S.Block_[] << c
                     Parse.Wait("ELSE")
                     CASE S.Condition == NONE && S.Block_[].Count == 1 ?
                          err(
                          "ELSE only branch has no sense for CASE ? without "
                          "conditional branches specified"._Eelse )
                     ;
                     CASE S.Condition.Type_expr.Kind == 'ENUM' ?
                          err("Using ELSE in CASE statement with "
                          "enumeration in condition is not allowed"._Eusing )
                     ;
                ;
                CASE Parse.End_of_line ? Parse.Fin ;
                BOOL none_is_next = Parse.Next_symbol("NONE")
                {Statement} temp|_block[]
                temp[].Clear
                PUSH count_compiled_statements = 0 :
                	 compile_block(temp[])
                	 CASE !none_is_next && count_compiled_statements==0 ? 
                	      Parse.Err("The branch of the CASE statement "
                	      "has no statements"._ENoStmtInBranch) 
                	 ;
                ;
                FOR st IN temp[] :
                    c.Block_[] << st
                    comp(Parse).Current_fun.Keep_statements[] << st ;
                CASE c.Work == 'ELSE' ? BREAK x ;
            ;
            CASE S.Condition.Type_expr.Kind!='BOOL' && count_cases==0 ? 
            	 err("CASE with not a condition other then BOOL should "
            	 "have at least one branch other then ELSE"
            	 ""._ECASE_no_branches)
            ;
            CASE S.Condition.Type_expr.Kind == 'ENUM' ?
                FOR ei IN S.Condition.Type_expr.Items[] :
                    CASE ei !IN all_ranges[] ?
                        err("Not all enumeration items are listed in "
                        "cases"._Enot ": " ei.Whole_name)
                        BREAK ei ;
                ;
            ;
            //CASE n <= 1 && t.Kind != 'BOOL' ?
            CASE n == 0 && t.Kind != 'BOOL' ?
                PUSH Parse.Line = line :
                    warn("Amount of cases is too low "
                    "for such condition type"._Wamount ) ;
            ; .
            
METHOD should_be_1st_or_last_in_line(
STR before_q|uestionmark, STR after_q|uestionmark) 
    :
	CASE before_q.Find(#CR) < 0 && before_q.Find(#LF) < 0 ? ==> ;
    CASE after_q.Trim == "" ? ==> ;
    INT p|osition_CR_LF = Find_last(before_q, #CR)
    CASE p < 0 ? p = Find_last(before_q, #LF) ;
    CASE p >= 0 ? STR ac|tual_before = before_q.[p+1 TO *]
    ELSE ac = before_q ;     
    CASE ac.Trim == "" ? ==> ;
    Parse.Err("In CASE branches with long conditions occupying several lines, "
    "the questionmark sign '?' should be either the last or the "
    "first in the line"._Q1stOrLastOnly
    #NL "before: [" before_q "]" #NL "after: [" after_q "]") .
            
METHOD collect_values({Type} T|ype_of_expression,
    {Case} C|ase_branch, {Var} All_ranges[]) ==> INT
    :                                 
    ---------------------------- 'range or values list'
    {Var} val|ue_first = scan_constant(T), >> All_var[]
    CASE T.Kind == 'INT' && Parse.Symbol("TO") ?
         RESULT += 2
         
         C.Range1 = {Expr}(
         		Operation = 'VAR',
                Var_arg = val), OWNED BY C
                
         C.Range2 = {Expr}(
         		Operation = 'VAR',
                Var_arg = scan_constant(T)), OWNED BY C
                
         BOOL dup|licate = check_duplicated_case(
                val, C.Range2.Var_arg, All_ranges[])
                
    ELSE C.Values[] << val
         dup = check_duplicated_case(val, val, All_ranges[])
         scan_list_const(C, T, All_ranges[])
         RESULT += C.Values[].Count ;
    ---------------------------- 'duplications found ?'
    CASE dup ?
         PUSH Parse.Pos = position_case :
              err("Duplicated value"._Edup3 ": " Parse.Next20) ;
    ; .
            
        */
        static int CNT_compile_cases;

        private void compile_cases(Case S)
        {
            if (++CNT_compile_cases == 17)
            { }

            List<Variable> all_ranges = new List<Variable>();
            Type t = S.Condition == null ? null : S.Condition.Type_expr();
            int n = 0;
            int line = Parse.Line;
            bool break_x = false;
            for (int x = Parse.Line; !break_x && x <= Parse.Source.Count; x++)
            {
                Parse.Skip_sp();
                Case c = null;
                switch ((Parse.Next_char() + (char)0)[0])
                {
                    case ';':
                    case '.':
                    case (Char)0: break_x = true; continue;
                    case '[': c = new Case();
                        c.Line = Parse.Line;
                        S.Block_.Add(c);
                        Parse.Wait("[");
                        //bool dup = false;
                        int pos = Parse.Pos;
                        //------------------- 'sequential ?'
                        if (S.Condition == null)
                        {
                            c.Condition = Expr();
                            Parse.Wait("]");
                            Parse.Wait("?");
                        }
                        else 
                        {
                            n += collect_values(t, c, pos, all_ranges);
                            Parse.Wait("]");
                            Parse.Wait(":");
                        }
                        break;
                    default: c = new Case();
                        c.Work = Statement.Workflow.ELSE;
                        c.Line = Parse.Line;
                        S.Block_.Add(c);
                        Parse.Wait("ELSE");
                        if (S.Condition != null && S.Condition.Type_expr().Kind == Type.Kind_type.ENUM)
                            err("Using ELSE in CASE statement with enumeration " +
                                "in condition is not allowed");
                        break;
                }
                if (c != null) compile_block(c.Block_); 
                if (c != null && c.Work == Statement.Workflow.ELSE) break;
            }
            if (S.Condition != null && S.Condition.Type_expr().Kind == Type.Kind_type.ENUM)
            {
                foreach (Variable ei in S.Condition.Type_expr().Items)
                {
                    if (!all_ranges.Contains(ei))
                    {
                        err("Not all enumeration items are listed in cases: " +
                            ei.Names[ei.Names.Count - 1]);
                        break;
                    }
                }
            }
            if (n <= 1 && t != null && t.Kind != Type.Kind_type.BOOL)
            {
                int save = Parse.Line;
                Parse.Line = line;
                try
                {
                    warn("Amount of cases is too low for such condition type");
                }
                finally { Parse.Line = save; }
            }
        }



        int collect_values(Type T, Case C, int Pos, List<Variable> all_ranges)
        {
            Variable val = scan_constant(T);
            bool dup = false;
            int n = 0;
            if (T != null && T.Kind == Type.Kind_type.INT && Parse.Symbol("TO"))
            {
                C.Range1 = new Expression();
                C.Range1.Operation = Expression.Operation_kind.VAR;
                C.Range1.Var_arg = val;
                C.Range2 = new Expression();
                C.Range2.Operation = Expression.Operation_kind.VAR;
                C.Range2.Var_arg = scan_constant(T);
                dup = check_duplicated_case(val, C.Range2.Var_arg, all_ranges);
                n += 2;
            }
            else
            {
                C.Values.Add(val);
                dup = check_duplicated_case(val, val, all_ranges);
                scan_list_const(C, T, all_ranges);
                n += C.Values.Count;
            }
            if (dup)
            {
                int sav = Parse.Pos;
                Parse.Pos = Pos;
                err("Duplicated value: " + Parse.Next20());
                Parse.Pos = sav;
            }
            return n;
        }

        /*
        
        METHOD scan_list_const({Case} C|ase_of_switch,
            {Type} T|ype_of_condition, {Var} A|ll_ranges[])
            :
            ------------------------------------------ 'value, value, ...'
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                CASE !Parse.Symbol(",") ? ==> ;
                INT at|_position = Parse.Pos
                {Var} v|alue_next = scan_constant(T), >> C.Values[]
                CASE check_duplicated_case(v, v, A[]) ?
                    PUSH Parse.Pos = at :
                        err("Duplicated value"._Edup4 ": " Parse.Next20) ;
                ;
            ; .
        */
        private void scan_list_const(Case C, Type T, List<Variable> A)
        {
            for (int x = Parse.Pos; x <= Parse.Last(); x++)
            {
                if (!Parse.Symbol(",")) return;
                int at = Parse.Pos;
                Variable v = scan_constant(T);
                C.Values.Add(v);
                if (check_duplicated_case(v, v, A))
                {
                    int save = Parse.Pos;
                    try {
                        Parse.Pos = at;
                        err("Duplicated value: " + Parse.Next20());
                    } finally { Parse.Pos = save; }
                }
            }
        }

        /*
        
        METHOD scan_constant({Type} T|ype_of_const) ==> {Var}, NEW :
            RESULT = {Var}(Is_const = TRUE, Type_ = T, Line = Parse.Line),
                     OWNED BY comp(Parse).Current_fun
            Parse.Skip_sp
            CASE Parse.Is_letter(Parse.Next_char) ?
                 STR id|entifier = Parse.Ident
                 {Type} cc|lass_current = comp(Parse).Current_class
                 {Var} c|onstant = cc.Search_const(id, TRUE)
                 CASE c == NONE ? 
                      Parse.Err("Constant"._Econst3 " " id
                                  " " ("was not found"._Ewasnot ))
                 ;
                 RESULT.Int_c = c.Int_c
                 RESULT.Real_c = c.Real_c
                 //RESULT.Bool_c = c.Bool_c
                 RESULT.Str_c = c.Str_c ==> ;
            CASE T.Kind ?
                 ['INT']:   RESULT.Int_c = Parse.Integer
                 ['REAL']:  RESULT.Real_c = Parse.Real_number
                 ['STR']:   RESULT.Str_c = Scan_string_const(16)
                 ['ENUM']:
					CASE Parse.Next_symbol("{") ?
						 STR n|ame_of_type = Parse.Scan_type
						 
						 {Type} t|ype_where_from 
						 	= comp(Parse).Current_class.Find_type(n)
						 	
						 CASE t.Kind == 'CLASS' ?
						      Parse.Wait(".")
						      n = Parse.Scan_type
						      t = comp(Parse).Current_class.Find_type(n)
						 ;
						 CASE t.Kind != 'ENUM' ?
						      Parse.Err("Type is not a enumeration"._ENotEnum 
						      ": " n)
						 ;
						 CASE t != T ?
						      Parse.Err("Type is not mathcing to type of the "
						      "CASE expression type"._ENotSameEnum ": " n)
						 ;
						 Parse.Wait(".")
					;
					Parse.Wait("'")
                    STR name|_of_const = "'" Parse.Ident_ex("-0123456789") "'"
                    Parse.Wait("'")
                    RESULT = T.Find_enum_item(name)
                    
                 ['BOOL']:  
                            CASE Parse.Ident ?
                                 ["TRUE"]: RESULT.Int_c = 1
                                 ["FALSE"]: RESULT.Int_c = 0
                                 
                            ELSE Parse.Err("Invalid BOOL constant"._Einvalid2 
                                 ": " Parse.Next20)
                            ;
                 ['CLASS', 'STRUCTURE']:
                          Parse.Err("Internal error - strange constant "
                          "needed of kind"._Einternal " " T.Kind.Name)
            ; .
        */
        private Variable scan_constant(Type T)
        {
            Variable Result = new Variable(comp(Parse));
            Result.Is_constant = true;
            Result.Type_ = T;
            Result.Line = Parse.Line;
            if (T != null)
            {
                switch (T.Kind)
                {
                    case Type.Kind_type.INT: Result.Int_c = Parse.Integer(); break;
                    case Type.Kind_type.REAL: Result.Real_c = Parse.Real_number(); break;
                    case Type.Kind_type.STR: Result.Str_c = Parse.String_const(false); break;
                    case Type.Kind_type.ENUM: Parse.Wait("'");
                        string name = "'" + Parse.Ident() + "'";
                        Parse.Wait("'");
                        Result = T.Find_enum_item(name);
                        break;
                    case Type.Kind_type.BOOL:
                        if (Parse.Symbol("TRUE")) Result.Bool_c = true;
                        else if (Parse.Symbol("FALSE")) Result.Bool_c = false;
                        else Parse.Err("Invalid BOOL constant: " + Parse.Next20());
                        break;
                    default: Parse.Err("Internal error - strange constant needed");
                        break;
                }
            }
            return Result;
        }

        /*
        
        METHOD check_duplicated_case(
        	{Var} V1|_value, {Var} V2|_value,
            {Var} A|ll_ranges[]) ==> BOOL
            :
            ------------------------------------ 'CASE values must be unique'
            FOR a IN A[] :
                CASE a.Index % 2 == 0 ?
                    BOOL dup|licated
                    CASE V1.Type_.Kind ?
                        ['INT']: dup = V1.Int_c >= a.Int_c
                                         dup &&= V2.Int_c <= A[a.Index+1].Int_c
                        ['STR']: dup = V1.Str_c == a.Str_c
                        
                        ['BOOL', 'ENUM']:    dup = V1 == a
                         
                        ['REAL', 'CLASS', 'STRUCTURE']:
                          Parse.Err("Internal error - strange CASE "
                          "condition"._Einternal2 )
                    ;
                    CASE dup ? RESULT = TRUE ==> ;
                ;
            ;
            A[] << V1 << V2 .        
        */
        private bool check_duplicated_case(Variable V1, Variable V2, List<Variable> A)
        {
            for (int i = 0; i < A.Count; i++)
            {
                Variable a = A[i];
                if (i % 2 == 0)
                {
                    bool dup = false;
                    if (V1 != null)
                    switch (V1.Type_.Kind)
                    {
                        case Type.Kind_type.INT:
                            dup = V1.Int_c >= a.Int_c && V2.Int_c <= A[i + 1].Int_c;
                            break;
                        case Type.Kind_type.STR:
                            dup = V1.Str_c == a.Str_c;
                            break;
                        case Type.Kind_type.BOOL: 
                        case Type.Kind_type.ENUM:
                            dup = V1 == a; break;
                        default: Parse.Err("Internal error - strange CASE condition"); 
                            break;
                    }
                    if (dup) return true;
                }
            }
            A.Add(V1);
            A.Add(V2);
            return false;
        }

        /*
        
        METHOD compile_silent|_not_warnings(
        {Statement} Block|_of_statemens_add_to[])
        	:
        	INT line|_now = Parse.Line
        	STR finishing|_symbol = symbol_starting_block(NONE)
        	//Parse.Wait(":")
        	CASE Parse.End_of_line ? Parse.Fin ;
	        PUSH comp(Parse).Is_silent = TRUE :
	        	  compile_block(Block[]) ;
	        CASE finishing  == ";" ? 
	             Parse.Want_semicolon("ending SILENT started at line " 
	             "" (line+1).Str)
	        ELSE Parse.Wait(finishing) ; .
        
        
        BOOL Compiling_debug|_code
        
        METHOD compile_debug(
            {Statement} Block|_of_statemens[],
            BOOL Active|_debug)
            :
            ------------------------------ 'add from DEBUG IMPORT'
            {Type} cc|lass_compiling = comp(Parse).Current_class
            INT count|_imported_classes = cc.Import_[].Count
            FOR di IN cc.Debug_import_[] :
                CASE di!IN cc.Import_[] ?
                	 cc.Import_[] << di ;
            ;
            ------------------------------ 'compile DEBUG block'
            PUSH Compiling_debug = TRUE :
                 Parse.Warn("Debug code is not removed"._Wdebug )
                 CASE !Parse.Symbol(":") ?
                      Parse.Warn("Waiting for ':' following DEBUG"
                      ""._Waiting_colon)
                 ;
                 
                 d|ebug_statement = {Assign}(
                 		Work = 'DEBUG', Line = Parse.Line, Pos= ident_pos,
                        Function_ = THIS, Level = Current_level,
                        Ignore = !Active),
                 	 >> Block[]
                        
                 CASE Parse.Next_char == #QU ?
                      Parse.Warn("Supposing << just following DEBUG" ":"
                      ""._WSupposingKK)
                      
                      {Statement} temp|_block[]
                      temp[].Clear
                      compile_output(temp[], TRUE)
                      FOR st IN temp[] :
                          d.Block_[] << st
                          comp(Parse).Current_fun.Keep_statements[] << st ;
                      temp[].Clear
                 ;
                        
                 CASE Parse.End_of_line ? Parse.Fin ;
                 compile_block(temp[])
                 FOR st IN temp[] :
                     d.Block_[] << st
                     comp(Parse).Current_fun.Keep_statements[] << st ;
                     
                 Parse.Want_semicolon("ending DEBUG statement started at line "
                 "" (d.Line+1).Str )
            ;
            ------------------------------ 'restore import'
            FOR i IN [cc.Import_[].Count-1 DOWNTO count] :
                cc.Import_[].Delete(i) ; .
        */
        static bool Compiling_debug;

        void compile_debug(List<Statement> Block, bool Active)
        {
            bool was_compiling_debug = Compiling_debug;
            Compiling_debug = true;
            try
            {
                Parse.Warn("Debug code is not removed");
                Parse.Wait(":");
                Assignment d = new Assignment();
                d.Work = Statement.Workflow.DEBUG;
                d.Line = Parse.Line;
                d.Ignore = !Active;
                Block.Add(d);
                compile_block(d.Block_);
                Parse.Wait(";");
            }
            finally
            {
                Compiling_debug = was_compiling_debug;
            }
        }

        /*
        BOOL Compiling_push|_statement
        
        METHOD compile_push({Statement} Block|_of_statements[]) :
			------------------------------------------------ 'PUSH var = expr :'
            PUSH Left_side = TRUE :
            PUSH Compiling_push = TRUE :
                 {Expr} dest|ination_temp = Expr
                 
                 p|ush_stmt_temp = {Assign}(
                 	Work = 'PUSH',
                 	Dest = dest,
                    Line = Parse.Line, Pos= ident_pos,
                    Function_ = THIS,
                    Level = Current_level)
                    
                 CASE dest.Operation == 'FIELD' 
                 	  && ! comp(Parse).Current_class.Is_descend(
                 	  	   dest.Var_arg.In_type_, comp(Parse))
                 	  && dest.Var_arg.Modifiers[{var_mod}.'READ']
                 	  ?
                      CASE dest.Var_arg.Setter_method_ == NONE ?
		                   Parse.Err("Assigning value to a read only field"
		                   " which has no setter"._Eassign9
		                   ": " dest.Var_arg.Whole_name)
		                   
                      ELSE BOOL setter_call = TRUE ;  
                 ;
                 
            ;
            ;
			CASE dest.Operation == 'FUN' && (
				 dest.Fun_.Modifiers['PUSH_METHOD'])
				 ? 
				 CASE dest.Fun_.Pop_method_ != NONE ?
					  dest.Fun_.Pop_method_.Usage_count += 1
					  CASE dest.Fun_.Pop_method_ !IN dest.Fun_.Use_functions_[]?
					     dest.Fun_.Use_functions_[] << dest.Fun_.Pop_method_ ;
					  CASE dest.Fun_.Pop_method_ !IN Use_functions_[]?
					     Use_functions_[] << dest.Fun_.Pop_method_ ;
				 ; 
			ELSE
				CASE dest.Operation !IN ['VAR', 'FIELD', 'INDEX'] ?
					 Parse.Err(
                     "PUSHed value is not a variable or a method call"._Epush )
                ;
                PUSH Assign_target = dest :
	                 CASE dest.Type_expr.Kind IN ['CLASS', 'STRUCTURE'] ?
	                      check_type_imported(dest.Type_expr, "PUSH") ;
					 CASE Parse.Symbol("=") ? 
						  p.Source = Expr, >> All_expr[]
						  extract_new_operations(p.Source, Block[], 0)
						  Check_structure_clone_dismiss(p.Source, Parse)
						  Assign_check_compat(dest, p.Source) ;
					 BOOL fix|ed_while_executing = dest.Operation == 'INDEX'
					 CASE fix ?
						 BOOL was|_fixed = dest.Arg1_.Var_arg.Is_fixed
						 dest.Arg1_.Var_arg.Is_fixed = fix
						 dest.Arg1_.Var_arg.Is_temp_fixed = TRUE
					 ;
					 CASE setter_call ?
					      p.Dest = {Expr}(Operation = 'FUN',
	                      		 Fun_ = dest.Var_arg.Setter_method_,
	                      		 This_ = dest.Arg1_,
	                      		 Items_[] << p.Source)
					      {Type} cc|lass_current = comp(Parse).Current_class
					      CASE p.Dest.Fun_.Class !IN cc.Used_imports_[] ?
					           cc.Used_imports_[] << p.Dest.Fun_.Class ;
					      p.Source = NONE ;
                ;
			;
			Block[] << p
            Nesting[] << p
            STR finishing|_symbol = symbol_starting_block(p)
            //Parse.Wait(":")
            {Statement} temp|_block[]
            -------------------------- 'nested block'
            compile_block(temp[])
            
            FOR st IN temp[] :
                p.Block_[] << st
                comp(Parse).Current_fun.Keep_statements[] << st ;
                
            CASE finishing==";" ? 
            	 Parse.Want_semicolon(
            	 "ending PUSH statement started at line"._Eend 
            	 " " (p.Line+1).Str)
            ELSE Parse.Wait(finishing) ;
            
            CASE fix ? 
                 p.Dest.Arg1_.Var_arg.Is_fixed = was 
                 p.Dest.Arg1_.Var_arg.Is_temp_fixed = FALSE 
            ;
            Nesting[].Remove(p) .
        */
        private void compile_push(List<Statement> Block)
        {
            int at_pos = Parse.Pos;
            Assignment p = new Assignment();
            p.Work = Statement.Workflow.PUSH;
            p.Dest = Expr();
            p.Line = Parse.Line;
            Block.Add(p);
            if (p.Dest.Operation != Expression.Operation_kind.VAR &&
                p.Dest.Operation != Expression.Operation_kind.FIELD &&
                p.Dest.Operation != Expression.Operation_kind.INDEX)
                Parse.Err("PUSHed value is not a variable");
            if (Parse.Symbol("="))
            {
                p.Source = Expr();
                Assign_check_compat(p.Dest, p.Source, at_pos);
            }
            bool fix = p.Dest != null && p.Dest.Operation == Expression.Operation_kind.INDEX;
            fix = fix && p.Dest.Arg1_.Operation == Expression.Operation_kind.VAR;
            bool was = false;
            if (fix) {
                was = p.Dest.Arg1_.Var_arg.Is_fixed;
                p.Dest.Arg1_.Var_arg.Is_fixed = fix;
            }
            Parse.Wait(":");
            compile_block(p.Block_);
            Parse.Wait(";");
            if (fix)
            {
                p.Dest.Arg1_.Var_arg.Is_fixed = was;
            }
        }
        
        
        /*
		BOOL nesting_LIKE
        BOOL Compiling_like
        //STR except|_list[]
        //INT but_start|_of_block_replacing_the_last_of_except
        STR replace_from|_in_like_statement[]
        STR replace_to|_in_like_statement[]
        INT count_replace|_pattern[]
        
		
		METHOD compile_like({Statement} Block|_of_statemens[]) :
			--------------------------------------------- 'nesting not allowed'
			CASE block_until_comment > 0 ? nesting_LIKE = TRUE ;
			CASE Compiling_like ?
			     Parse.Err("Nesting LIKE statements are not "
			     "allowed"._ENestingLIKE) ==>
			;
            PUSH Compiling_like = TRUE :
                 Parse.Want_original
                ------------------------------------------------------- 'method'
                {Type} cc|lass_current = comp(Parse).Current_class
                CASE Parse.Next_symbol("...") ?
                     {Fun} method|_like_in = comp(Parse).Current_fun
                ELSE method = cc.Find_fun(Parse.Ident, FALSE)
                	 CASE method != NONE ?
                	      method.Warn_about_deprecated
                	      method.Usage_count += 1 
                	      method.Count_ref += 1 ;
                ;
                CASE method.Class != cc ?
                     Parse.Err("It is not allowed to use in LIKE methods from "
                     "other classes"._Eitis3 )
                ;
                //CASE cc.Method[].Find(THIS) < cc.Method[].Find(method) ?
                CASE Line_start < method.Line_start ?
                     Parse.Err(" from a method it should be defined "
                     "earlier"._Etouse )
                ;
                ------------------------------------------------------- 'label'
                Parse.Wait("...")
                FOR j|dummy IN [Parse.Pos TO Parse.Last] :
                    CASE !Parse.Symbol(".") ? BREAK j ;
                ;
                Parse.Wait("'")
                STR label|_name = "'" Parse.Skip_to("'") "'"
                Parse.Wait("'")
                replace_from[].Clear
                replace_to[].Clear
                count_replace[].Clear
                //CASE Parse.Symbol(",") ?
                //     Parse.Wait("EXCEPT")
                //     FOR j|dummy IN [Parse.Pos TO Parse.Last] :
                //         Parse.Wait("'")
                //         except[] << "'" Parse.Skip_to("'") "'"
                //         Parse.Wait("'")
                //         CASE !Parse.Symbol(",") ? BREAK j ;
                //     ;
                //;
                CASE Parse.Symbol(",") ?
                     CASE Parse.End_of_line ? Parse.Fin ;
                     Parse.Wait("BUT")
                     scan_replacements ;
                     
                CASE Parse.End_of_line ?
                     INT was_line = Parse.Line
                     INT was_pos|ition = Parse.Pos
	                 Parse.Fin
                     //CASE Parse.Symbol("BUT") ?
                     //     CASE Parse.Symbol("IN") ? NONE ;
                     //     Parse.Wait("'")
                     //     STR but|_name = "'" Parse.Skip_to("'") "'"
                     //     Parse.Wait("'")
                     //     Parse.Wait(":")
                     //     Parse.Fin
                     //     except[] << but
                     //     but_start = Parse.Line
                     //ELSE
	                 Parse.Line = was_line 
	                 Parse.Pos = was_pos 
	                 //;
                ;
                //CASE Dummy_compile ? ==> ;
                --------------------------------------------------- 'find label'
                INT from_line = Parse.Line
                PUSH comp(Parse).Compiling_LIKE = TRUE :
                PUSH comp(Parse).Error_prefix =
                     "(Called from line " (Parse.Line+1).Str ")" :
                PUSH comp(Parse).Error_Called_from_line = Parse.Line :
                PUSH Parse.Line = method.Line_start + 1:
                PUSH Parse.Pos = 0 :
                PUSH block_until_comment = Current_level+1 :
                PUSH nesting_level = 0 :
                     FOR i IN [Parse.Line TO Parse.Source[].Count-1] :
                         Parse.Line = i
                         Parse.Want_original
                         Parse.Pos = 0
                         Parse.Skip_sp
                         CASE !Parse.Symbol("--") ?
                              CASE is_class_level(Parse) ?
                                   PUSH Parse.Line = from_line :
                                     Parse.Err("Comment"._Ecomment
                                     " " label " " ("was not found in "
                                     "method"._Emethod5 )
                                     " " method.Whole_name)
                                   ;
                              ==> ;
                              CONTINUE i ;
                         FOR j|dummy IN [Parse.Pos TO Parse.Last] :
                             CASE !Parse.Symbol("-") ? BREAK j ;
                         ;
                         INT line|_found = Parse.Line
                         CASE !Parse.Symbol("'") ? CONTINUE i ;
                         CASE label == "'" Parse.Skip_to("'") "'" ?
                              Parse.Wait("'")
                              CASE !Parse.Symbol(",") ||
                                   !Parse.Symbol("REUSED")
                                   ?
                                   Parse.Err("Comment"._Ecomment2
                                   " ---- " label " " ("is reused in LIKE "
                                   "statement(s) but it is not marked as "
                                   "REUSED"._Eis6 ))
                              ;
                              //DEBUG:
                              //      Console_color('RED') 
                              //      << "found reused comment in line "
                              //"" Parse.Line " -- will be removed from "
                              //"Reused_comments, class=" cc.Names[0] #NL
                              //		Console_color('SILVER') 
                              //		CASE Parse.Line == 1397 ? 
                              //		     << "!!!!!!!!!!!!! ### "
                              //		;
                              //		FOR rc IN cc.Reused_comments[] :
                              //		    CASE rc==line ? INT count_rc += 1 ;
                              //		;
                              //		<< " " count_rc.S #NL
                              //;
                              cc.Reused_comments[].Remove(line)
                              CASE Dummy_compile ? ==> ;
                              Parse.Line = i+1
                              Parse.Want_original
                              Parse.Pos = 0
                              BREAK i ;
                     ;
                     INT block_start INDEXING STR = Parse.Line
                 	 CASE replace_from[].Count > 0 ?
                 	      do_replacements(from_line) 
                 	 ;
                 	 ---------------------- 'remove $-s'
                 	 Parse.Line -= 1
                 	 Parse.Pos = Parse.Last+1
                 	 Parse.Fin
                 	 ---------------------- 'compile sequence as block'
                     compile_block(Block[])
                     CASE replace_from[].Count > 0 ?
                          restore_replacements(block_start) ;
                     CASE !Parse.Symbol("--") ?
                            Parse.Err("Block used in LIKE must be ended with a "
                            "comment --...-- 'label' but"._Eblock3
                            ": " Parse.Next20) ;
                ;
                ;
                ;
                ;
                ;
                ;
                ;
                CASE nesting_LIKE ?
                      Parse.Err("Calling with LIKE a block having LIKE is not "
                      "allowed"._Ecall )
                ;
                //CASE but_start > 0 ?
                //     Parse.Line = but_start
                //     skip_to_end_of_block ;
                nesting_LIKE = FALSE
                //except[].Clear
                //but_start = 0
            ; .
            
		METHOD scan_replacements :
			FOR idummy IN [1 TO 1000] :
			    Parse.Wait("(")
			    CASE Parse.Symbol("'") ?
			         STR from|_what = Parse.Skip_to("'")
			         Parse.Wait("'")
			    ELSE from = Parse.Skip_to("==>").Trim ;
			    CASE from.Trim == "" ?
			         Parse.Err("It is not allowed to omit a replacement pattern"
			         ""._EOmitPattern)
			    ;
			    CASE Parse.End_of_line ? Parse.Fin ;
			    Parse.Wait("==>")
			    CASE Parse.Symbol("'") ?
			         STR to|_replacement = Parse.Skip_to("'")
			         Parse.Wait("'")
			    ELSE to = Parse.Skip_to(")").Trim ;
			    Parse.Wait(")")
			    INT c|ount_replacements_wait = 1
			    CASE Parse.Symbol("*") ?
			    	 CASE Parse.Symbol("?") ? 
			    	      c = 0
			    	 ELSE c = Parse.Number ;
			    ;
			    ------------------ 'collect 1 item'
			    replace_from[] << from
			    replace_to[] << to
			    count_replace[] << c
			    CASE !Parse.Symbol(",") ? ==> ;
			    CASE Parse.End_of_line ? Parse.Fin ; 
			; .
			
		STR save_repl|acements[]
		
		FUN start_from_id(
		STR s_line|_checking_to_starting_from, STR arr|ay_of_idents[]) ==> BOOL
		    :
			FOR s IN arr[] :
			    CASE Starting(s_line,s) ? 
			         RESULT = s_line.[s.Len].Trim == "" ==> ;
			; .
			
		INT count_repl|aced_times
			
		METHOD do_replacements(INT from_line) :
			save_repl[].Clear
			INT level|_nesting = 0
			STR operators[] << "CASE" << "FOR" << "DEBUG" << "PUSH" << 
				"SILENT" << "LIMIT" << "LOCAL"
				     
			operators[] << "case" << "for" << "debug" << "push" << "silent" << 
				"limit" << "local"
				     
			INT start_line = Parse.Line
		    FOR i IN [start_line TO Parse.Source[].Count-1] :
		        INT to_line|_end = i
		        PUSH Parse.Line = i : Parse.Want_original ;
		        STR s|tring_at_i = Parse.Source[i]
		        save_repl[] << s
		        //CASE from.Index == 0 ? save_repl[] << s ;
		        s = Replace_all(s, #TAB, " ").Trim
		        STR id|entifier_starting = get_first_id(s)
				CASE id.[0] IN "CDFLPScdflps"
				     && start_from_id(id, operators[])
				     ?
                     //DEBUG: << "+level at " i.Str " (" level.Str 
                     //       "): " s #NL ;
				     level += 1 ;
				CASE Ending(s, ";") || Ending(s, "}") && s.[*-1].Trim=="" 
				     || Ending(s, "-->")
				     || (Ending (s, "END") || Ending(s, "end")) 
				     && (s.[*-4]).Trim=="" 
				     ?
                     //DEBUG: << "-level at " i.Str " (" level.Str 
                     //       "): " s #NL ;
				     level -= 1 ;
				CASE level == 0 && Starting(s, "--")
				     && !Starting(Replace_all(s,"-", ""), ">")
				     ?
                     //DEBUG: << "end at " i.Str #NL ;
				     BREAK i ;
                //CASE from IN s ?
                //     s = do_replaces_in_line(
                //         Parse.Source[i], from, replace_to[from.Index])
                //     Parse.Source[i] = s ;
		        CASE s.[*]=="." ? BREAK i ;
		    ;
			FOR from IN replace_from[] :
				count_repl = 0
			    DEBUG:
			          CASE start_line==807 ? 
			               ----------- '808' 
			          ;
			    ;
			    FOR i IN [start_line TO to_line-1] :
			    	//CASE from.Index == 0 ? save_repl[] << s ;
			    	s = Parse.Source[i]
			    	s = Replace_all(s, #TAB, " ").Trim
					CASE from IN s ?
						 s = do_replaces_in_line(
							 s, from, replace_to[from.Index])
							 
			             Parse.Source[i] = s ;
			    ;
			    CASE ?
			    [count_repl != count_replace[from.Index]
			     && count_replace[from.Index] > 0] ?
			         PUSH Parse.Line = from_line :
				          Parse.Err("Amount of replacements (" from 
				          " ==> " replace_to[from.Index] ") was specified * "
				          "" count_replace[from.Index].Str 
				          " but actually there were " count_repl.Str 
				          " patterns found in lines (" (start_line+1).Str 
				          "-" (to_line+1).Str ")") 
                        //DEBUG: >> ;
			         ;
			    [count_repl == 0] ?
			         PUSH Parse.Line = from_line :
				          Parse.Err("There were no replacements (" from 
				          " ==> " replace_to[from.Index] ") found "
				          " in lines (" (start_line+1).Str 
				          "-" (to_line+1).Str ")") 
			         ;
			    ;
			; .
			
		METHOD do_replaces_in_line(
		STR line|_replace_in, STR from|_pattern, STR to_t|ext_2) ==> STR
		    :
		    INT last_ch|ar_to_check = line.Len-1
		    RESULT = line
		    FOR x|dummy IN [0 TO line.Length] :
		        INT pos|ition_pattern = Find_last(RESULT.[0 TO last_ch],from) 
		    	CASE pos < 0 ? ==> ;
		    	count_repl += 1     
		    	RESULT = RESULT.[0 TO pos-1] to_t RESULT.[pos + from.Len TO *]
		    	last_ch = pos-1     
		    ; .
			
		METHOD get_first_id|entifier(
		STR S|tring_starting_with_identifier) ==> STR
			:
			FOR i IN [0 TO S.Len-1] :
			    CASE !Parse.Is_letter(S.[i]) && S.[i] !IN "_0123456789" ? ==> ;
			    RESULT = RESULT S.[i] ; .
			
		METHOD restore_replacements(INT from_line INDEXING STR) :
			FOR s IN save_repl[] :
			    Parse.Source[from_line + s.Index] = s ; .

		TODO: "Compiling revert, check if value assigned is assignable" .
            
        METHOD compile_revert({Statement} Block|_of_statemens[]) :
            PUSH comp(Parse).Compiling_LIKE = TRUE :
                ------------------------------------------------------- 'method'
                {Type} cc|lass_current = comp(Parse).Current_class
                CASE Parse.Next_symbol("...") ?
                     {Fun} method|_like_in = comp(Parse).Current_fun
                ELSE method = cc.Find_fun(Parse.Ident, TRUE) ;
                CASE method.Class != cc ?
                     Parse.Err("It is not allowed to use in REVERT code from "
                     "other classes"._Eitisnot2 )
                ;
                CASE cc.Method[].Find(THIS) < cc.Method[].Find(method) ?
                     Parse.Err("To use REVERT from a method it should be "
                     "defined earlier"._Etouse2 )
                ;
                ------------------------------------------------------- 'label'
                Parse.Wait(".")
                Parse.Wait(".")
                Parse.Wait(".")
                FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                    CASE !Parse.Symbol(".") ? BREAK i ;
                ;
                Parse.Wait("'")
                STR label|_name = "'" Parse.Skip_to("'") "'"
                Parse.Wait("'")
                --------------------------------------------------- 'find label'
                PUSH Parse.Line :
                     CASE !find_revert_block(method.Block[], label, Block[])
                          ?
                          Parse.Err("The block labeled"._Ethe " " label 
                          " " ("was not found to revert"._Ewasnot2 ) ) ;
                ;
                //CASE method == comp(Parse).Current_fun ? NONE ;
            ; .
            
        METHOD find_revert_block(
            {Statement} Source|_block_to_search_label[],
            STR Label|_starting_block_to_revert,
            {Statement} Dest|ination_block_to_place_reverted_code[
            ]) ==> BOOL, RECURSIVE
            :
            FOR st IN Source[] :
                CASE st.Work == 'COMMENT' && (
                     st.{Assign}.Source.Var_arg.Str_c == Label)
                     ?
                     {Type} cc|lass_current = comp(Parse).Current_class
                     cc.Reused_comments[].Remove(st.Line)
                     CASE !st.{Assign}.Reused ?
                          PUSH Parse.Line = st.Line :
                               Parse.Err("Block of code"._Eblock4
                               " " Label " " ("is reused "
                               "but it is not marked as REUSED"._Eis7 ) ) ;
                     ;
                     PUSH comp(Parse).Error_prefix =
                          "(Called from line " (Parse.Line+1).Str ")" :
                          revert_block(Source[], st.Index+1, Dest[]) ;
                     RESULT = TRUE ==> ;
                CASE st.Block_[].Count > 0 ?
                     RESULT = find_revert_block(st.Block_[], Label, Dest[])
                     CASE RESULT ? ==> ;
                ;
            ; .
            
        METHOD revert_block(
            {Statement} Source|_block_containing_block_to_revert[],
            INT From|_index_of_first_statement_to_revert,
            {Statement} Dest|ination_block_to_place_reverted_code[])
            :
            ----------------------------------- ''
            INT n|umber_reverted = 0
            FOR i IN [From TO Source[].Count-1] :
                Parse.Line = Source[i].Line
                CASE Source[i].Work == 'COMMENT' ?
                     CASE n == 0 ?
                          Parse.Warn("There are no statements to "
                          "revert"._Wthere )
                     ;
                     ==> ;
                n += 1
                CASE Source[i].Work != 'ASSIGN' ?
                     Parse.Err("Only assignments can be reverted"._Eonly2 )
                ;
                r|everted_statement = {Assign}(
                	Line = Source[i].Line, Pos= ident_pos,
                    Work = 'ASSIGN',
                    Function_ = comp(Parse).Current_fun,
                    Level = Current_level), >> Dest[]
                -------------------------------- 'revert source and destination'
                revert_operands(r, Source[i].{Assign}.Source,
                        Source[i].{Assign}.Dest)
                --------------------------------- 'remap local variables'
                r.Source = remap_local_var(r.Source)
                r.Dest = remap_local_var(r.Dest)
            ;
            Parse.Err("Block of code to revert should be ended with a block "
            "comment"._Eblock2 ) .
            
        METHOD revert_operands(
            {Assign} R|everted_assignment,
            {Expr} S|ource_field_or_var_to_revert, 
            {Expr} D|estion_in_source_statement)
            :
            ----------- ''
            CASE S.Operation ?
            ['VAR', 'INDEX']: ------ 'source was a local variable or array item'
                    R.Dest = S
                    R.Source = D
                    check_destination_was_simple(D)
            ['FIELD']: -------------------------------- 'field of object or ?'
                    CASE is_field_of_variable(S.Arg1_) ?
                         R.Dest = S
                         R.Source = D
                         check_destination_was_simple(D) ==> ;
                    CASE S.Var_arg.In_type_ == NONE ?
                         Parse.Err("Field"._Efield2 
                         " " S.Var_arg.Whole_name 
                         " " ("is not a field of a local record variable and "
                         "can not be reverted"._Eisnot12 ) )
                    ;
                    CASE S.Var_arg.Setter_method_ != NONE ?
                         R.Dest = NONE
                         
                         R.Source = {Expr}(
                         	Operation = 'FUN',
                            Fun_ = reuse_method(S.Var_arg.Setter_method_))
                            
                         R.Source.Items_[] << D
                         check_destination_was_simple(D) ==> ;
                    R.Source = D
            ['FUN', 'BASE_FUN']: ------- 'function which is setter or getter'
                    CASE S.Fun_.Getter_field_ != NONE && D == NONE ?
                         R.Dest = S.Items_[0]
                         
                         R.Source = {Expr}(
                         	Operation = 'FIELD',
                            Var_arg = S.Fun_.Getter_field_,
                            Arg1_ = S.This_)
                    ;
            
                    CASE S.Fun_.Getter_method_ != NONE && D == NONE ?
                         R.Dest = S.Items_[*]
                         
                         R.Source = {Expr}(
                         	Operation = 'FUN',
                            Fun_ = reuse_method(S.Fun_.Getter_method_),
                            This_ = S.This_)
                            
                         copy_param(R.Source.Items_[], S.Items_[],
                            S.Items_[].Count-1)
                    ;
                            
                    CASE D != NONE && S.Fun_.Setter_ != NONE ?
                         --------------------------------- 'S was a getter'
                         R.Dest = NONE
                         
                         R.Source = {Expr}(Operation = 'FUN',
                            Fun_ = reuse_method(S.Fun_.Setter_),
                            This_ = S.This_)
                            
                         copy_param(R.Source.Items_[], S.Items_[],
                            S.Items_[].Count)
                            
                         R.Source.Items_[] << D
                         check_destination_was_simple(D) ==> ;
                            
                    CASE R.Dest == NONE && R.Source == NONE ?
                         Parse.Err("Function"._Efun3 
                         " " S.Fun_.Whole_name 
                         " " ("is not a setter or getter and can not be "
                         "reverted"._Eisnot13 )) ==> ;
                         
                    CASE R.Dest.Operation ?
                    ['VAR', 'INDEX']: NONE
                    ['FIELD']: 
                            CASE R.Dest.Var_arg.Setter_method_ != NONE ?
                                 ------------- 'new left side --> setter'
                                 {Expr} d|estination_temp = R.Dest
                                 {Expr} s|ource_temp = R.Source
                                 All_expr[] << s << d
                                 R.Dest = NONE
                                 
                                 R.Source = {Expr}(
                                 	Operation = 'FUN',
                                 	Fun_ = reuse_method(
                                         d.Var_arg.Setter_method_),
                                 	This_ = d.Arg1_,
                                 	Items_[] << s)
                            ;
                                     
                    ['FUN', 'BASE_FUN']: 
                            CASE R.Dest.Fun_.Setter_ != NONE ?
                                 ---------------- 'new left side is function'
                                 d = R.Dest
                                 s = R.Source
                                 All_expr[] << s << d
                                 R.Dest = NONE
                                 
                                 R.Source = {Expr}(Operation = 'FUN',
                                   Fun_ = reuse_method(d.Fun_.Setter_),
                                   This_ = d.This_)
                                 ---------------- 'parameters (+source)'
                                 copy_param(R.Source.Items_[], d.Items_[],
                                   d.Items_[].Count)
                                   
                                 R.Source.Items_[] << s
                                 ==> ;
                                 
                            Parse.Err("Function"._Efun4 
                            " " R.Dest.Fun_.Whole_name 
                            " " ("has not a setter so it can not be "
                            "reverted"._Ehasnot2 ))
                            
                    ['BINARY', 'NEW_OBJ', 'ARRAY', 'AS', 'CONST', 'INT2REAL',
                     'NOT_B', 'NOT', 'NEG', 'UNKNOWN',
                     'SYSTEM_FUN']: NONE ;
                     
            ['BINARY', 'NEW_OBJ', 'ARRAY', 'AS', 'CONST', 'INT2REAL',
             'UNKNOWN', 'NOT_B', 'NOT', 'NEG', 'SYSTEM_FUN']:
                
				Parse.Err("Source can not be reverted in the assignment"
				""._Esource )
            ; .
            
        METHOD reuse_method({Fun} F|unction_reverted) ==> {Fun} :
            CASE F !IN Call_functions_[] ? 
                 Call_functions_[] << F
                 
                 STR c_from|_call = Class.Whole_name 
                 c_from = c_from "." Whole_name " (reuse|reverted)"
                 Call_from[] << c_from 
            ;
            RESULT = F .

        FUN copy_param|eters(   {Expr} Dest|ination_parameters[],
                                {Expr} Source|_parameters[],
                                INT Count|_to_copy)
                                :
            FOR i INDEXING {Expr} IN [0 TO Count-1] :
                Dest[] << Source[i] ; .
                         
        METHOD check_destination_was_simple({Expr} D|estination) :
            CASE D.Operation ?
            ['VAR', 'INDEX']: NONE
            ['FIELD']: 
                       CASE is_field_of_variable(D.Arg1_) ? ==> ;
                       CASE D.Var_arg.In_type_ == NONE ?
                            Parse.Err("Field"._Efield3 " " D.Var_arg.Whole_name
                            " " ("is not a filed of a local record"
                            " variable and can not be reverted"._Eisnot14 ) )
                       ;
            ['FUN', 'BASE_FUN', 'SYSTEM_FUN', 'BINARY', 'NEW_OBJ', 'ARRAY', 
             'AS', 'CONST', 'INT2REAL', 'UNKNOWN', 'NOT_B', 'NOT', 'NEG']:
                
				NONE ; .
             
        FUN is_field_of_variable({Expr} A|rgument_of) ==> BOOL :
            {Expr} a|rgument_to_check_on_each_iteration = A
            FOR i|dummy IN [1 TO 1000_000] :
                DONE
                CASE ?
                [a.Operation IN ['VAR']] ? RESULT = TRUE ==>
                [a.Operation == 'FIELD'] ? a = a.Arg1_
                                           CONTINUE i
                [a.Operation == 'INDEX'] ? a = a.Arg1_
                                           CONTINUE i ;
                ==>
            ; .
            
        METHOD remap_local_var|iables(
        	{Expr} E|xpression) ==> {Expr}, NEW, RECURSIVE
            :    
            CASE !local_vars_used_in(E) ? RESULT = E ==> ;
            
            RESULT = {Expression}(
            	Operation = E.Operation,
            	Sign = E.Sign,
                Fun_ = E.Fun_,
                Var_arg = E.Var_arg ), >> All_expr[]
                
            RESULT.Arg1_ = remap_local_var(E.Arg1_), >> All_expr[]
            RESULT.Arg2_ = remap_local_var(E.Arg2_), >> All_expr[]
            RESULT.Arg3_ = remap_local_var(E.Arg3_), >> All_expr[]
            RESULT.This_ = remap_local_var(E.This_), >> All_expr[]
            FOR it IN E.Items_[] :
                {Expr} remapped = remap_local_var(it), >> All_expr[]
                RESULT.Items_[] << remapped ;
            ------------------------------------ 'remap local variable'
            CASE E.Operation != 'VAR' ? ==> ;
            CASE E.Var_arg.In_type_ != NONE ? ==> ;
            
            {Var} lvar|iable_remapped_to = Find_local_var(E.Var_arg.Names[0],
                TRUE)
                
            CASE lvar == NONE ?
                 Parse.Err("Could not remap local variable"._Ecouldnotremap 
                 " " E.Var_arg.Names[0]
                 " " ("from another method"._Efromanother ) ) ==>
            ;
            CASE E.Var_arg.Names[1] != lvar.Names[1] ?
                 STR er|ror_text = "" 
                 	"Remapped variables names should match"._Eremapped
                 	": " E.Var_arg.Whole_name
                 	 
                 er = er " -> " lvar.Whole_name
                 Parse.Err(er)
            ;
            CASE E.Var_arg.Type_ != lvar.Type_ && (
            	 E.Var_arg.Type_.Names[0] != "{}")
            	 ?
            	 er = "Remapping variable"._Eremapping 
                 	" " E.Var_arg.Whole_name
                 	" " ("data type is not matching to data type of the "
                 	   "correspondent local variable"._Edatatype )
                 	   
            	 er = er ": " E.Var_arg.Type_.Whole_name
            	 er = er " != " lvar.Type_.Whole_name
                 Parse.Err(er)
            ;
            RESULT = {Expr}(Operation = 'VAR', Var_arg = lvar) 
            lvar.Used_for_w = TRUE .
        
        FUN local_vars_used_in({Expr} X|pression_check) ==> BOOL,
            RECURSIVE
            :
            CASE X.Operation ?
            ['UNKNOWN']: NONE
            ['BINARY', 'FUN', 'BASE_FUN', 'INDEX', 'FIELD', 'SYSTEM_FUN']:
                RESULT = local_vars_used_in(X.Arg1_)
                RESULT ||= local_vars_used_in(X.Arg2_)
                RESULT ||= local_vars_used_in(X.Arg3_)
                RESULT ||= local_vars_used_in(X.This_)
                FOR it IN X.Items_[] :
                    RESULT ||= local_vars_used_in(it) ;
            ['VAR']: RESULT = X.Var_arg.In_type_ == NONE
            ['INT2REAL', 'NOT_B', 'NOT', 'NEG']:
            	RESULT = local_vars_used_in(X.Arg1_)
            ['NEW_OBJ', 'ARRAY', 'AS', 'CONST']: NONE ; .
        
            
        FUN is_class_level({Parser} Parse|_source) ==> BOOL :
            PUSH Parse.Pos :
                 Parse.Skip_sp
                 CASE !Parse.Next_is_letter ? ==> ;
                 STR k|eyword_first = Parse.Ident
                 CASE k IN ["FUN", "FUNCTION", "OVERRIDE", "METHOD",
                 	  "CONST", "CONSTANT", "ENUM", "ENUMERASTION", "RECORD", 
                 	  "OBJECT", "TABLE", "END"]
                      ?
                      RESULT = TRUE ;
            ; .
			
        BOOL Left_side|_is_compiling
        BOOL Dummy_compile

        METHOD compile_declaration(
        	{Statement} Block|_of_statements[]) ==> BOOL
        	:
			PUSH Fix_last_dest:
	             -------------------------------------- 'Scan type name'
	             STR name_t|ype = Parse.Scan_type
				 {Type} t|ype_of_var = Parse.Class_.Find_type(name_t)
				 comp(Parse).Current_class.Can_be_imported(t, name_t)
	             Parse.Skip_sp
	             {Expr} left|_side = NONE
	             ---------------- 'Call static function or declare variable ?'
	             CASE name_t.[0] == "{" && Parse.Next_char == "." ?
	                  Parse.Skip_char
	                  {Fun} static_f|unction = t.Find_fun(Parse.Ident, TRUE)
	                  CASE ! static_f.Modifiers['STATIC'] ?
	                       err("Function"._Efun5 " " static_f.Names[*] 
	                       " " ("is not static"._Eisnot15 ) )
	                  ;
	                  PUSH Left_side = TRUE :
	                       left = Operation_call_fun(static_f, NONE, Parse), 
	                            >> All_expr[]
	                  ;
	             ELSE left = new_var(t), >> All_expr[]
	                  BOOL decl|aration_of_new_var = TRUE
	                  Fix_last_dest = FALSE
	                  Set_last_dest(left, TRUE)
	             ;
	             CASE comp(Parse).Is_silent ? 
	                  left.Var_arg.Count_ref += 1;
	             Parse.Skip_sp
	             CASE left.Operation == 'VAR' ?
	                  CASE left.Type_expr.Kind == 'INT' ?
		                   BOOL is_index = Parse.Symbol("INDEXING") 
		                   CASE ?
		                   [is_index && Parse.Symbol("(")] ?
		                       left.Var_arg.Type_indexing = Parse.Skip_to(")")
		                       Parse.Wait(")")
		                   [is_index] ?
		                       left.Var_arg.Type_indexing = Parse.Scan_type
		                   ;
		                   CASE left.Var_arg.Type_indexing != "" ?
		                        STR x_t|ypes_indexing[]
		                        Split(x_t[], left.Var_arg.Type_indexing, ",")
		                        FOR xt IN x_t[] :
			                  	    {Type} ti|ndexing_type 
			                  	    ti = Parse.Class_.Find_type(xt.Trim)     
		                        	left.Var_arg.Indexing_[] << ti ;
		                   ;
	                  ; 
	                  CASE Parse.Next_char IN [";", ".", #0] && decl ?
	                       CASE ?
	                       [left.Is_fixed] ? NONE
	                       [left.Is_array] ?
	                            clear|_array = {Assign}(Function_ = THIS,
	                            	Line = 0, //Line=Parse.Line, 
	                            	Pos= 0, 
	                            	Level = Current_level,
	                            	Source = {Expr}(
	                            		Operation = 'SYSTEM_FUN',
	                            		Fun_ = comp(Parse).SYSFUN_Delete,
	                            		Items_[] << left, 
	                            		Items_[] << comp(Parse).E0,
	                            		Items_[] << comp(Parse).Max_int)),
	                            >> Block[]
	                            
	                            left.Var_arg.Has_changing_size = TRUE
	                       [left.Type_expr.Kind IN ['INT', 'ENUM',
	                       	'BOOL', 'STR']] ?
	                       		NONE
	                       [left.Type_expr.Kind == 'STRUCTURE'] ?
	                            make_assign_new(left, Block[])
	                       ELSE make_assign_none(left, Block[]) ;
	                       CASE Parse.Next_char == "." && decl ?
	                            left = left.Chain_operations(Parse, TRUE),
	                            	   >> All_expr[]
	                            	   
	                            call|_function = {Assign}(Function_= THIS,
	                            	Line= Parse.Line, Pos= 0, 
	                            	Level= Current_level,
	                            	Source= left), 
	                            	>> Block[]
	                       ;
	                  ELSE left.Var_arg.Assigned = TRUE
	                  	   RESULT = TRUE
	                       CASE Compiling_like ?
	                            left.Var_arg.Used_for_w = TRUE ;
	                       Compile_assign(left, Block[])
	                       check_assignment_indexing(Block[*])
	                  ;
	             ELSE call = {Assign}(Source = left,
	             		Line = Parse.Line, Pos= Parse.Pos,  Function_ = THIS,
	             		Level = Current_level), >> Block[]
	             ; 
	             Block[*].{Assign}.Is_decl = TRUE
            ; .
            
		METHOD make_assign_none(
		{Expr} D|estination, {Statement} Block|_to_add_to[])
			:
            a|ssign_none = {Assign}(Dest = D,
           		 Function_ = THIS, Line = Parse.Line, Pos= ident_pos,
           		 Level = Current_level,
           		 Source = {Expr}(
                       Operation = {operation}.'CONST',
                       Var_arg = comp(Parse).NONE_c)),
           		 >> Block[]
            CASE D.Type_expr.Kind ?
            ['BOOL']: 
				a.Source.Var_arg = {Var}(Int_c = 0, Is_const= TRUE,
					Type_ = comp(Parse).TYPE_BOOL, Line = -3)
					
            ['INT', 'ENUM']:
				a.Source.Var_arg = {Var}(Int_c = 0, Is_const= TRUE,
					Type_ = comp(Parse).TYPE_INT, Line = -3)
					
            ['REAL']:
				a.Source.Var_arg = {Var}(Real_c = 0.0, Is_const= TRUE,
					Type_ = comp(Parse).TYPE_REAL, Line = -3)
            
            ['STR']:
				a.Source.Var_arg = {Var}(Str_c = "", Is_const= TRUE,
					Type_ = comp(Parse).TYPE_STR, Line = -3)
					
            ['CLASS', 'STRUCTURE']: NONE ; .

		METHOD make_assign_new(
		{Expr} D|estination, {Statement} Block|_to_add_to[])
			:
            a|ssign_none = {Assign}(Dest = D,
           		 Function_ = THIS, Line = Parse.Line, Pos= ident_pos,
           		 Level = Current_level,
           		 Source = {Expr}(
                       Operation = {operation}.'NEW_OBJ',
                       Type_obj_ = D.Type_expr)),
           		 >> Block[] .

        */
        public void compile_declaration(List<Statement> Block)
        {
            string t = Parse.Scan_type();
            Type T = Parse.Class_.Find_type(t);
            Parse.Skip_sp();
            int at_pos = Parse.Pos;
            Expression left = null;
            bool decl = false;
            if (Parse.Next_char() == ".")
            {
                Parse.Skip_char();
                Function Static_f = T.Find_fun(Parse.Ident());
                if (!Static_f.Modifiers[(int)Fun_mod.STATIC])
                    err("Function " + Static_f.Names[Static_f.Names.Count - 1] + " is not static");
                left = Expression.Operation_call_fun(Static_f, null, Parse);
            }
            else
            {
                left = new_var(T);
                decl = true;
            }
            Parse.Skip_sp();
            if (left == null) { err("...Left side is not defined"); }
            else
            {
                if (left.Operation == Expression.Operation_kind.VAR)
                {
                    if ((";. " + (Char)0).Contains(Parse.Next_char()) && decl)
                    {
                        Assignment a = new Assignment();
                        a.Line = Parse.Line;
                        a.Dest = left;
                        a.Source = new Expression();
                        a.Source.Operation = Expression.Operation_kind.CONST;
                        a.Source.Var_arg = comp(Parse).NONE_c;
                        Block.Add(a);
                    }
                    else
                        Compile_assign(left, Block);
                }
                else
                {
                    Assignment a = new Assignment();
                    a.Source = left;
                    a.Line = Parse.Line;
                    Block.Add(a);
                }
            }
        }

        /*
        
        METHOD new_var|iable_declared(
        	{Type} T|ype_of_var) ==> {Expr}, NEW
        	:
            STR lvn|_local_var_names[]
            Parse.Scan_names(lvn[], "")
            ----------------------------- 'check already defined'
            FOR n IN lvn[] :
                {Fun} fa|lready_defined_function 
                 	   = comp(Parse).Current_class.Search_fun(n,
                 	   CASE_SEN, FALSE)
                 	   
                CASE !Dummy_compile ?
                	 {Var} a|lready_defined = Search_var(n, TRUE) 
	                 CASE ?
	                 [a != NONE] ?
	                      err("Duplicating name"._Edup5 ": " n 
	                      " (" ("already defined in line"._Ealready ) 
	                      " " (a.Line+1).Str " " ("of class"._EOfClass)
	                      " " a.In_type_.Whole_name ")")
	                      
	                 [n IN all_id[]] ?
	                      err("Duplicating name"._Edup6 ": " n) ;
                ;
                CASE ?
                [a != NONE && a !IN Local_var[]] ?
                     CASE !Modifiers['STATIC'] ?
	                      warn("Local variable has the same name as class"
	                      " field: "._WLocalNameEqualToFieldName n)
	                      
	                      BOOL same_as_field = TRUE
                     ;
                [fa != NONE] ?
                     warn("Local variable name"._Edup50 ": " n 
                     " (" ("overrides function name defined in line"
                     ""._Ealready01 )
                     " " ("in class"._in_class) fa.Class.Whole_name 
                     " " (fa.Line_start+1).Str ")")
                ;
                CASE ! Modifiers['STATIC'] ? check_reusing_field_name(n) ;
                CASE !Dummy_compile ? all_id[] << n ; 
            ;
            --------------------------------- 'create local variable'
            {Var} v|ariable_declared = {Var}(
                Line = Parse.Line + comp(Parse).Add_to_line,
                Type_ = T, Same_name_as_field = same_as_field,
                In_fun_ = THIS, In_local_ = Current_local), OWNED BY THIS
                
            FOR n IN lvn[] : v.Names[] << n ;
            CASE !Dummy_compile ? Local_var[] << v ;
            CASE Compiling_debug ? v.Declared_in_debug = TRUE ;
			--------------------------------- 'check common naming rules'
            Parse.Check_names(v.Names[])
            Parse.Check_reserved(v.Names[])
            Parse.Check_local_names(v.Names[])
            CASE Parse.Symbol("[") ?
                v.Is_array = TRUE
                CASE Parse.Next_char == "{" ?
                    v.Is_fixed = TRUE
                    v.Size_n = Parse.Scan_type
                    v.Size_type_ = Parse.Class_.Find_type(v.Size_n)
                    
                    comp(Parse).Current_class.Can_be_imported(
                    	v.Size_type_, v.Size_n) 
                ;
                Parse.Wait("]") ;
            RESULT = {Expr}(Operation = 'VAR', Var_arg = v), OWNED BY THIS .
            
        METHOD check_reusing_field_name(
        STR N|ame_of_variable )
            :
            {Type} cclass|_type = Class
            FOR i|dummy IN [1 TO 100] :
                FOR fld IN cclass.Field[] :
                    CASE N IN fld.Names[] ?
                         warn("Name"._Ename " " N 
                         " " ("is used for the class field and it is "
                         "not good idea to reuse it for a local "
                         "variable"._Wis8 ) ) ==> ;
                ;
                cclass = cclass.Base_
                CASE cclass == NONE ? ==> ;
            ; .
        
        */
        private Expression new_var(Type T)
        {
            Variable v = new Variable(comp(Parse));
            v.Line = Parse.Line;
            v.In_fun_ = this;
            v.Type_ = T;
            Local_var.Add(v);
            Parse.Scan_names(v.Names);
            foreach (string n in v.Names)
            {
                if (all_id.Contains(n))
                    err("Duplicating name: " + n);
                all_id.Add(n);
            }
            Parse.Check_names(v.Names);
            Parse.Check_reserved(v.Names);
            Parse.Check_local_names(v.Names);
            if (Parse.Symbol("["))
            {
                v.Is_array = true;
                if (Parse.Next_char() == "{")
                {
                    v.Is_fixed = true;
                    v.Size_n = Parse.Scan_type();
                    v.Size_type_ = Parse.Class_.Find_type(v.Size_n);
                }
                Parse.Wait("]");
            }
            //-------------------- indexing
            if (Parse.Symbol("INDEXING")) {
            	if (Parse.Symbol("(")) {
            		Parse.Skip_to(")");
            		Parse.Wait(")");
            	}
            	else Parse.Skip_to(" ");
            }
            
            Expression Result = new Expression();
            Result.Operation = Expression.Operation_kind.VAR;
            Result.Var_arg = v;
            return Result;
        }

        /*
     
        BOOL Fix_last_dest
        {Expr} Last_destination|_expression
        
        METHOD Last_dest|ination_read ==> {Expr} : RESULT = Last_destination .
        
        
		METHOD Set_last_dest(
			{Expr} Value|_to_set_as_last_dest,
			BOOL Fix|_value)
			:
			CASE Fix_last_dest ?
                 Parse.Err("Using '..' several times in a "
                 "statement"._EUsingDotDot ": [" Parse.Source[Parse.Line] "]")
			;
            Last_destination = Value
            Fix_last_dest = Fix .

        
        METHOD compile_simple(
        	{Statement} Block|_of_stmts[])
        	:
        	{Compiler} c|ompiler = comp(Parse)
            ---------------------------------- 'Starts from identifier always'
            INT pos0|_before = Parse.Pos
            CASE Parse.Symbol("..") ? 
                 STR id|entifier = ".."
                 BOOL start_from_dot_dot = TRUE
            ELSE id = Parse.Ident
            	 Fix_last_dest = FALSE ;
            Parse.Skip_sp
            ---------------------------------- 'Function call?'
            CASE Parse.Any_case ? STR id_sys|tem_fun = id.Upper
            ELSE id_sys = id ;
            CASE ?
            [id == "BASE"] ?
                 CASE Result != NONE ?
                      Parse.Err("It is not allowed to call a base function as "
                      "a standalone statement if a function is returning a "
                      "result"._Eitisnot4 )
                 ;
                 CASE Modifiers['REPLACE'] ?
                      Parse.Err("The method declared as replacing the "
                      "ancestor's can not call the BASE method"
                      ""._EBaseReplaced)
                 ;
                 {Fun} f|unction_to_call = Ancestor_
                 //DEBUG: INT iii|_temp = Parse.Line + 1 
                 //      << "Calls_base DETECTED at line " 
                 //      << iii.Str
                 //      << " in function " Names[0] " (class " 
                 //      << Class.Names[0] ")"#NL ;
                 Calls_base = TRUE
                 BOOL call_base_fun|ction_as_a_single_statement
                 CASE f == NONE ?
                      CASE f == NONE ? 
                           Parse.Err("BASE is not applicable: there is no base "
                           "method for"._Ebase " " Whole_name )
                      ;
                      CASE THIS == Class.Construct || THIS == Class.Destruct ?
                           Parse.Err("Direct call of base CONSTRUCT or "
                           "DESTRUCT"._Edirect )
                      ;
                 ;
            [id == ".."] ?
                 {Expr} left|_operand = Last_dest
            [Parse.Next_symbol("(") 
             && id_sys IN ["COUNT", "CLEAR", "LEN","LENGTH", "NAME", "INDEX",
             "STR", "STRING", "INT", "INTEGER", "NEXT", "PREV", "PREVIOUS",
             "FIRST", "LAST", "CLONE", "DISMISS", 
             "FIND", "INSERT", "ALLOCATE", "DELETE", "REMOVE", 
             "HEX", "HEXADECIMAL", "SHIFTL", "SHIFT_LEFT", "SHIFTLEFT",
             "SHIFTR", "SHIFT_RIGHT", "SHIFTRIGHT", "ROTATEL", "ROTATE_LEFT",
             "ROTATELEFT", "ROTATER", "ROTATE_RIGHT", "ROTATERIGHT", "SWAP",
             "Count", "Clear", "Len","Length", "Name", "Index",
             "Str", "String", "Int", "Integer", "Next", "Prev", "Previous",
             "First", "Last", "Clone", "Dismiss", 
             "Find", "Insert", "Allocate", "Delete", "Remove", 
             "Hex", "Hexadecimal", "ShiftL", "Shift_left", "ShiftLeft",
             "ShiftR", "Shift_Right", "ShiftRight", "RotateL", "Rotate_Left",
             "RotateLeft", "RotateR", "Rotate_Right", "RotateRight", "Swap"]] ?
                 //BOOL could_be_system|_function = TRUE
                  
                 {Expr} call_sys|tem_fun = System_function_traditional(
                 	id, Parse, pos0), >> All_expr[]
                 	
                 CASE call_sys != NONE ?
                      call_f|unction = {Assign}(Source = call_sys,
                      		Line = Parse.Line, Pos= ident_pos, Function_ = THIS, 
                      		Level = Current_level),
                      		>> Block[] ==> ;
                      		
                 f = c.Current_class.Search_fun(id, CASE_SEN|IMPORTED_CL, TRUE)
                 CASE f == NONE ? 
                      Parse.Err("System function is not applicable"._ESysNotApp
                      ": " id) ;
                      
            ELSE {Var} v|ariable = Search_var(id, !Parse.Any_case)
                 CASE v.In_type_ != NONE && Parse.Next_char == "(" ? v = NONE ;
                 CASE v == NONE ?
                 	  CASE !Parse.Case_insensitive ? INT sen|sitive = CASE_SEN ;
                      f = c.Current_class.Search_fun(id, sen|IMPORTED_CL, TRUE)
                 ;
            ;
            CASE f != NONE && !f.Is_public && !(
                 Class.Is_descend(f.Class, c)) && (
                 Class.Names[0] !IN f.Class.Friends[])
                 ?
                 STR er|ror_text = "Calling non-public function from a "
                 	"non-familiar class"._Ecalling 
                 	": " f.Class.Whole_name 
                 	
                 er = er "." f.Whole_name
                 Parse.Err(er)
            ;
            CASE f != NONE ?
                INT at_pos|ition = Parse.Pos
                CASE f !IN Call_functions_[] ? 
                     Call_functions_[] << f
                     STR c_from|_call = Class.Whole_name "." Names[0]
                     Call_from[] << c_from
                     f.Count_ref += 1
                     CASE !Is_test ?
                          //DEBUG:
                          //      CASE f.Total_fn == 12017 ?
                          //           << "+++++++++++++++++++++++++++++"
                          //           "  Usage_count++ for " f.Names[].Whole_name
                          //           " because: Compile_simple in context of "
                          //           "" Class.Names[0] "."  Names[].Whole_name
                          //           #NL
                          //      ;
                          //;
                          f.Warn_about_deprecated
                     	  f.Usage_count += 1 ;
                ;
                CASE ! f.Modifiers['STATIC'] && (
                	 c.Current_fun.Modifiers['STATIC'])
                     ?
                     PUSH Parse.Pos = pos0 :
                          Parse.Err("Calling non-static method"._Ecall2 
                          " (" f.Names[*]
                          ") " ("from static function without object "
                          "parameter"._Efrom3 )
                          ": " f.Class.Whole_name "." f.Whole_name) ;
                ;
                CASE ! f.Modifiers['STATIC'] ?
                     c.Current_fun.This_used = TRUE 
                     CASE call_base_fun ?
                          left = call_base_method, >> All_expr[]
                     ELSE
                          left = Operation_call_fun(f,
                            c.THIS_expr, Parse), >> All_expr[]
                     ;
                ELSE left = Operation_call_fun(f, NONE, Parse), >> All_expr[] ;
                CASE !Fix_last_dest && left != NONE ? 
                     Set_last_dest(left, FALSE) ;
            	CASE id == "BASE" ?
            	     left.Operation = 'BASE_FUN' ;
                CASE f.Result != NONE ?
                     left = left.Chain_operations(Parse, FALSE), >> All_expr[]
                ELSE Set_last_expr(left) ;
                CASE left.Operation IN ['VAR', 'FIELD'] ?
                     left.Var_arg.Assigned = TRUE
                     //CASE left.Var_arg.Modifiers['TRAP'] && (
                     // 	  c.Debugging || c.TEST_value)
                     //	  ?
                     //     {Expr} temp|_left_value = trap_assign_scalar(left)
                     //     left = temp ;
                     extract_new_operations(left, Block[], 0)
                     check_destination_var(left)
                     //CASE Parse.End_of_line || Parse.Next_symbol("==>") ?
                     //     Parse.Err("Attempt to call a variable like a function"
                     //     ""._EVarAsFun) ==> ;
                     Compile_assign(left, Block[])
                     check_assignment_indexing(Block[*]) ==>
                ;
                ------------------------------ 'only expression'
                CASE ?
                [left.Operation == 'FUN' && left.Fun_.Result != NONE
                 && !(Parse.Ignore_function_result
                 && left.Fun_.Result.Type_.Kind != 'CLASS')] ?
                     CASE Parse.Next_symbol("<<") ? 
                         BOOL want_r|ight_side = TRUE
                	 ELSE
	                     Parse.Err("Result of function"._Eresult2
	                     " " left.Fun_.Whole_name 
	                     " " ("is not assigned"._Eisnot16 ) ) ;
                [left.Operation IN ['VAR', 'FIELD', 'INDEX']] ?
                    want_r = Parse.Next_symbol("=")
                ;
                extract_new_operations(left, Block[], 0)
                
                CASE !want_r ?
	                 a|ssignment = {Assign}(Source = left, Line = Parse.Line,
	                 	Pos= ident_pos, Function_ = THIS, Level = Current_level),
	                 	>> Block[]
	                 ----------------------- 'call FORGET method?'
	                 CASE left.Operation != 'FUN' 
	                      || !f.Modifiers['FORGET']
	                      ?
	                      ==> ;
	                 FOR fld IN Class.Field[] :
	                     CASE !Starting(fld.Names[0], "_cache_") ?
	                          CONTINUE fld ;
	                          
	                     reset|_cache = {Assign}(
	                    	 Line = 0, Pos= 0, //Line = Parse.Line,
	                    	 Function_ = THIS,
	                    	 Level = Current_level,
	                    	 Work = 'ASSIGN',
	                    	 Source = {Expr}(
	                    		 Operation = {operation}.'CONST',
	                    		 Var_arg = fld.Initial_.Var_arg),
	                    	 Dest = {Expr}(
	                         	 Operation = 'VAR',
	                         	 Var_arg = fld)
	                     ), OWNED BY THIS
	                     
	                     Block[] << reset ;
	                 ==> ;
            ;
            CASE left == NONE ?
	             CASE v == NONE && id != ".." ? 
	                  v = Search_var(id, !Parse.Case_insensitive) ;
	             CASE v != NONE && !Modifiers['STATIC'] && (
	            	  v IN c.Current_class.Field[])
	                  ?
	                  This_used = TRUE ;
	             CASE v == NONE && id == "NONE" ?
	                  v = c.NONE_c
	                  CASE id == ".." ? left = Last_dest ;
	             ;
            ;
            ----------------------------------- 'Create new variable'
            CASE left == NONE && v == NONE && id != ".." 
                 && !Parse.Next_symbol("(")
                 ?
                 v = {Variable}(Line = Parse.Line, In_fun_ = THIS),
                     >> Local_var[]
                 v.Names[] << id
                 all_id[] << id
                 CASE Parse.Symbol("|") ?
                      v.Names[] << id Parse.Ident
                      CASE v.Names[*] IN all_id[] ?
                           err("Duplicating name"._Edup7 ": " v.Names[*]) ;
                      all_id[] << v.Names[*] ;
                 PUSH Parse.Pos :
                      CASE Parse.Symbol("=") && Parse.Next_symbol("{") ?
                           STR tn|ame_class = Parse.Scan_type
                           v.Type_ = c.Current_class.Find_type(tn)
                           c.Current_class.Can_be_imported(v.Type_, tn)
                      ELSE 
                           CASE c.Verbose ?
                                STR det|ails_on_error 
                                = error_details_unknown(id)
                           ;
                           STR sim|ilar_names[]
                           Find_similar(id, sim[])
                           Class.Find_similar(id, sim[], TRUE)
                           CASE sim[].Count > 0 ? 
                                FOR s IN sim[] :
                     				STR list_sim|ilar = list_sim "," s ;

                                Parse.Err("Name is not defined"._ENameNotDefined
                                ": " id ". " ("May be you mean one of"
                                ""._EMayBeYouMean2)
                                " (" list_sim.[1 TO *] ") ?")
                           ELSE
                           Parse.Err("Name"._Ename2 " " id 
                           " " ("is not defined"._Eisnot17 ) det) ==> ;
                      ;
                 ;
                 CASE id.[0].Upper == id.[0] && !Parse.Case_insensitive ?
                      warn("It is recommended to use names starting from "
                      "lower case letter for local variables"._Witis ": " id)
                 ;
                 CASE v.Names[*].Len < 8 ?
                      err("Full name of variable should exceed 7 characters "
                      "length"._Efull ": " v.Names[*])
                 ;
            ;
            ------------------------------- 'Work with v, new or existing'
            PUSH Fix_last_dest:
	             at_pos = Parse.Pos
	             CASE left == NONE ?
	                  CASE v.In_type_ == NONE ?
		            	   left = {Expr}(
		            	   		Operation = 'VAR',
		            	   		Var_arg = v), OWNED BY THIS
		            	   
	                  ELSE this_obj|_of_class_which_filed_is = {Expr}(
	                  			Operation = 'VAR',
	                  			Var_arg = comp(Parse).THIS_var,
	                  			Type_obj_ = v.In_type_), OWNED BY THIS
	                  			 
	                  	   left = {Expr}(
	                  	   		Operation = 'FIELD',
	                  	   		Var_arg = v,
	                  	   		Arg1_ = this_obj), OWNED BY THIS
	                  	   		
	                  	   This_used = TRUE
	                  ;
	            	  Set_last_dest(NONE, FALSE) ;
	             CASE v.Is_const ? left.Operation = {operation}.'CONST' ;
	             PUSH Left_side = TRUE :
	                  CASE ?
	                  [Parse.Symbol("..")] ?
	                       Set_last_dest(left, TRUE)
	                       start_from_dot_dot = TRUE 
	                  [Parse.Next_symbol(".")] ?
							CASE left.Var_arg.Is_loop
				       		     && left.Var_arg.For_.In_struct_array != NONE
					             ?
					             {Expr} old_l|eft = left
					             
					             left = {Expr}(Operation= 'INDEX',
					                  Arg1_= old_l.Var_arg.For_.In_struct_array,
					                  Arg2_= old_l), >> All_expr[]
				       		;	                  
	                  ;
	                  left = left.Chain_operations(Parse, FALSE), >> All_expr[]
	                  CASE !start_from_dot_dot && !Fix_last_dest 
	                  	   && left.Operation IN ['VAR', 'FIELD']
	                  	   ?
	                       Set_last_dest(left, FALSE) ;
	             ;
	             v.Used_for_w = TRUE
	             v.Count_ref += 1
	             CASE v.Declared_in_debug && !Compiling_debug ?
	                  Parse.Err("Variable"._Evar2 " " v.Whole_name 
	                  " " ("was declared in debug block and can not be "
	                  "used in regular code"._Evar3 ))
	             ;
	             Parse.Skip_sp
	             CASE Parse.End_of_line || Parse.Next_symbol("==>") || (
	                  Parse.Next_symbol(";"))
	                  ?
	                  CASE left.Var_arg == c.NONE_c ? ==> ;
	                  extract_new_operations(left, Block[], 0)
	                  CASE left.Operation IN ['VAR', 'FIELD', 'INDEX'] ? 
                          Parse.Err("Attempt to call a variable like a function"
                          ""._EVarAsFun) ==> ;
                          
	                  a = {Assign}(Source= left, 
	                  			   Line= Parse.Line, Pos= ident_pos,
	                               Function_ = THIS, Level = Current_level),
	                               >> Block[]
	                               
	                  CASE left.Operation == 'VAR' ?
	                       {Expr} tthis|_for_trap_call = left.Items_[0].This_
	                  ELSE tthis = left.Items_[0].Arg1_ ;
	                  CASE left.Operation == 'FUN' && (
	                       left.Items_[0].Operation IN ['FIELD', 'VAR']) && (
	                  	   left.Items_[0].Var_arg.Trap_add_ != NONE)
	                  	   ?
	                       CASE ?
	                       [left.Fun_ == c.SYSFUN_Insert] ?
		                       true_expr = {Expr}(Operation = 'CONST',
		                     	  Var_arg = c.TRUE_c),
		                     	  OWNED BY THIS
		                     	  
		                       t|rap_insert = {Assign}(
		                     	  Function_ = THIS, Line = 0, Pos= 0, //Line= Parse.Line,
		                     	  Level = Current_level,
		                     	  Source = {Expr}(
		                     	  Operation = 'FUN',
		                     	  Fun_ = left.Items_[0].Var_arg.Trap_add_,
		                     	  This_ = tthis,
		                     	  Items_[] << true_expr,
		                     	  Items_[] << left.Items_[1])), >> Block[]
		                     	  
		                     	  
	                       [left.Fun_ == c.SYSFUN_Delete] ?
		                       false_expr = {Expr}(Operation = 'CONST',
		                     	  Var_arg = c.FALSE_c),
		                     	  OWNED BY THIS
		                     	  
		                       dt|rap_delete = {Assign}(
		                     	  Function_ = THIS, Line= 0, Pos= 0, //Line= Parse.Line,
		                     	  Level = Current_level,
		                     	  Source = {Expr}(
		                     	  Operation = 'FUN',
		                     	  Fun_ = left.Items_[0].Var_arg.Trap_add_,
		                     	  This_ = tthis,
		                     	  Items_[] << false_expr,
		                     	  Items_[] << left.Items_[1])),
		                     	  OWNED BY THIS
		                     	  
		                       Block[].Insert(Block[].Count-1, dt) 
		                       
	                       [left.Fun_ == c.SYSFUN_Clear] ?
		                       false_expr = {Expr}(Operation = 'CONST',
		                     	  Var_arg = c.FALSE_c),
		                     	  OWNED BY THIS
		                     	  
		                       m1|_minus_one = {Expr}(Operation = 'CONST',
		                          Var_arg = {Var}(Is_const = TRUE,
		                          Type_ = c.TYPE_INT, Constant_value = "-1",
		                          Int_c = -1, Line = -1)),
		                          OWNED BY THIS
		                          
		                       ct|rap_clear = {Assign}(
		                     	  Function_ = THIS, 
		                     	  Line= 0, Pos= 0, //Line= Parse.Line,
		                     	  Level = Current_level,
		                     	  Source = {Expr}(
		                     	  Operation = 'FUN',
		                     	  Fun_ = left.Items_[0].Var_arg.Trap_add_,
		                     	  This_ = tthis,
		                     	  Items_[] << false_expr,
		                     	  Items_[] << m1)),
		                     	  OWNED BY THIS
		                     	  
		                       Block[].Insert(Block[].Count-1, ct) 
	                       ;
	                  ;
	                  CASE left.Fun_.System_fun IN ['SYSFUN_Allocate',
	                       'SYSFUN_Remove', 'SYSFUN_Clear', 'SYSFUN_Delete',
	                       'SYSFUN_Insert']
	                       ?
	                       left.Items_[0].Var_arg.Has_changing_size = TRUE
	                  ;
	                  CASE left.Operation ?
                      ['FUN', 'BASE_FUN', 'SYSTEM_FUN']:
                          CASE left.Fun_.Result != NONE 
                          	   && !Parse.Ignore_function_result
                          	   ?
                               err("Result of function is not "
                               "assigned"._Eresult3 )
                          ;
                      ['VAR', 'FIELD', 'INDEX']:
                  		  CASE Parse.End_of_line
                  		  	   && !Parse.Ignore_function_result
                  		  	   ?
                           	   err("Result of expression is not "
                               "assigned"._Eresult4 )
                  		  ; 
                      ['CONST']:
                          CASE left.Var_arg != c.NONE_c ?
                               err("Invalid using of "
                               "constant"._Einvalid3 )
                          ;
                      ['ARRAY', 'BINARY', 'NEW_OBJ', 'AS', 'UNKNOWN']:
	                  	  CASE !Parse.Ignore_function_result ?
	                           err("Result of expression is not "
	                           "assigned"._Eresult5 )
	                  	  ; 
                      ['INT2REAL', 'NOT_B', 'NOT', 'NEG']:
                  		  NONE ;
	             ELSE left.Var_arg.Assigned = TRUE
	             	  check_destination_var(left)
	                  Compile_assign(left, Block[]) 
	                  check_assignment_indexing(Block[*]) ;
	             INT jb|efore_just = Parse.Pos
	             CASE Parse.Symbol("==>") ?
	                  Block[] << {Case}(Work = 'RETURN', 
	                  					Line = Parse.Line, Pos= jb,
	                                    Function_ = THIS, Level = Current_level)
	                                    
	                  Has_return = TRUE
	             ;
	             CASE !Parse.End_of_line && Parse.Next_char !IN ";.}"
	                  && !Parse.Next_symbol("ELSE")
	                  && !Parse.Next_symbol("-->")
	                  && !Parse.Next_symbol("end")
	                  && !Parse.Next_symbol("END")
	                  ?
	                  Parse.Err("Ambiguous characters"._Eambig ": " Parse.Next20)
	                  Parse.Pos = Parse.Last
	                  Parse.Fin
	             ; 
            ; .
            
        METHOD check_assignment_indexing(
        {Statement} st|atement_assignment)
            :
	        CASE st.Work !IN ['ASSIGN', 'APPEND'] ? ==> ;
	        {Assign} a|ssignment = st.{Assignment} 
	        CASE a.Dest.Var_arg.Indexing_[].Count == 0 ? ==> ;
	        CASE ?
	        [a.Source.Var_arg.Indexing_[].Count > 0] ?
	            CASE Indexings_different(a.Dest.Var_arg.Indexing_[],
	            	 a.Source.Var_arg.Indexing_[], FALSE)
	            	 ?
	                 BOOL bad|_assignment = TRUE ;
	        [a.Source.Operation == 'BINARY' 
	         && a.Source.Arg1_.Var_arg.Indexing_[].Count > 0] ?
	            CASE Indexings_different(a.Dest.Var_arg.Indexing_[],
	            	 a.Source.Arg1_.Var_arg.Indexing_[], FALSE)
	            	 ?
	                 bad = TRUE ;
	        [a.Source.Operation == 'BINARY'
	         && a.Source.Arg2_.Var_arg.Indexing_[].Count > 0] ?
	            CASE Indexings_different(a.Dest.Var_arg.Indexing_[],
	            	 a.Source.Arg2_.Var_arg.Indexing_[], FALSE)
	            	 ?
	                 bad = TRUE ;
	        [a.Source.Operation == 'INDEX' 
	         && a.Source.Arg1_.Var_arg.Indexing_[].Count > 0] ?
	         	CASE Indexings_different(a.Dest.Var_arg.Indexing_[],
	            	 a.Source.Arg1_.Var_arg.Indexing_[], FALSE)
	            	 ?
	                 bad = TRUE ;
	        ;
	        CASE bad ?
	             Parse.Err("Bad assigning values having different INDEXING "
	             "types specified"._EBadAssignIndexing) ; .

        METHOD check_destination_var(
        {Expr} left|_side_of_assign)
            :
            CASE !left.Var_arg.Same_name_as_field ? ==> ;
            {Compiler} c|ompiler = comp(Parse)
            CASE c.Current_class.Search_field(last_ident) == NONE ? ==> ;
            
	        Parse.Err("It is not allowed to asign a variable "
	        "via its name identical to a field of class"
	        ""._AssignToNameIdenticalToClassField) .

        METHOD last_ident ==> STR :
			STR s|tring_in_line = Parse.Source[Parse.Line]
        	FOR i IN [Parse.Pos-1 DOWNTO -1] :
        		INT last|_position_in_identifier = i
        		CASE s.[i] !IN " "#TAB ? BREAK i ;
        	;
        	FOR i IN [last DOWNTO -1] :
        	    CASE i < 0 
        	         || !Parse.Is_letter(s.[i]) && s.[i] !IN "_0123456789"
        	         ?
        	         RESULT = s.[i+1 TO Parse.Pos-1].TrimR ==> ;
        	; .
            
	
        METHOD call_base_method ==> {Expr}, NEW :
            this_obj|ect = {Expr}(
            	Operation = 'VAR',
                Var_arg = comp(Parse).THIS_var,
                Type_obj_ = comp(Parse).Current_fun.Class.Base_),
                >> All_expr[]
                
            RESULT = {Expr}(
            	Operation = 'FUN',
            	Fun_ = Ancestor_,
            	This_ = this_obj)
            	 
            FOR p IN Param[] :
                par|ameter = {Expr}(
                	Operation = 'VAR',
                	Var_arg = p), >> All_expr[]
                	
                RESULT.Items_[] << par ; .

                                   
        METHOD error_details_unknown(
        	STR Id|entifier_unknown ) ==> STR
        	:
            RESULT = "if there is a new function, check if it is STATIC"._Eif2
            
            {Fun} f|unction_non_case = comp(Parse).Current_class.Search_fun(
                  Id, IMPORTED_CL, FALSE)
                  
            CASE f != NONE ?
                 RESULT = RESULT ", " ("may be you mean function"._Emaybe ) " "
                 RESULT = RESULT f.Class.Whole_name 
                 RESULT = RESULT "." f.Whole_name " ?"
            ELSE 
                 CASE !Parse.Next_symbol("(") ?
                      {Var} v|ariable = Search_var(Id, FALSE) ;
            ;
            CASE v != NONE ?
                 RESULT = RESULT ", " ("may be you mean variable"._Emaybe2 ) " "
                 "" v.Whole_name " ?"
            ;
            RESULT = " (" RESULT ")" .
        */
        static int CNT_compile_simple;
        Expression last_dest = null;

        private void compile_simple(List<Statement> Block)
        {
            if (++CNT_compile_simple == 6666)
            { }

            int pos0 = Parse.Pos;
            string id;
            if (Parse.Symbol("..")) id = "..";
            else id = Parse.Ident();
            
            Function f = comp(Parse).Current_class.Search_fun(id, false);
            if (f != null)
            {
                int at_pos = Parse.Pos;
                if (!f.Modifiers[(int)Function.Fun_mod.STATIC] &&
                    comp(Parse).Current_fun.Modifiers[(int)Function.Fun_mod.STATIC])
                {
                    int sav_Parse_pos = Parse.Pos;
                    Parse.Pos = pos0;
                    Parse.Err("Calling non-static method (" + f.Names[f.Names.Count-1] + 
                        ") from static function without object parameter: " + Parse.Next20());
                    Parse.Pos = sav_Parse_pos;
                }
                Expression left = Expression.Operation_call_fun(f, 
                    comp(Parse).THIS_expr, Parse);
                left = Expression.Chain_operations(left, Parse);
                if (left.Operation == Expression.Operation_kind.VAR ||
                    left.Operation == Expression.Operation_kind.FIELD) 
                {
                	last_dest = left;
                    Compile_assign(left, Block, at_pos);
                    return;
                }
                //------------------------------- 'only expression'
                if (left.Operation == Expression.Operation_kind.FUN &&
                    left.Fun_.Result != null)
                    Parse.Err("Result of function is not assigned");
                Assignment a = new Assignment();
                a.Source = left;
                a.Line = Parse.Line;
                Block.Add(a);
                return;
            }
            Variable v = Search_var(id);
            if (v == null && id == "NONE")
                v = comp(Parse).NONE_c;
            if (v == null && id != "..")
            {
                v = new Variable(comp(Parse));
                v.Line = Parse.Line;
                v.In_fun_ = this;
                Local_var.Add(v);
                v.Names.Add(id);
                all_id.Add(id);
                if (Parse.Symbol("|"))
                {
                    string s = id + Parse.Ident();
                    v.Names.Add(s);
                    if (all_id.Contains(s))
                        err("Duplicating name: " + s);
                    all_id.Add(s);
                }
                int save = Parse.Pos;
                try
                {
                    if (Parse.Symbol("=") && Parse.Next_symbol("{"))
                    {
                        string tn = Parse.Scan_type();
                        v.Type_ = comp(Parse).Current_class.Find_type(tn);
                    }
                    else
                    {
                        Parse.Err("Name " + id + " is not defined");
                        return;
                    }
                }
                finally { Parse.Pos = save; }
                if (((id + (char)0)[0] + "").ToUpper() == ((id + (char)0)[0] + ""))
                    warn("It is recommended to use names starting from " +
                         "lowercase letter for local variables" + 
                         ": " + id);
                if (v.Names[v.Names.Count - 1].Length < 8)
                    err("Full name of a variable should exceed 7 characters: " + v.Names[v.Names.Count - 1]);
            }
            //----------------------------- 'work with v, new or existing'
            {
                int at_pos = Parse.Pos;
                Expression Left;
                if (id == ".." && last_dest != null)
                	Left = last_dest;
                else
                {
	                Left = new Expression();
	                last_dest = Left;
	                Left.Operation = Expression.Operation_kind.VAR;
	                Left.Var_arg = v;
	                if (v.Is_constant) Left.Operation = Expression.Operation_kind.CONST;
                }
                Left = Expression.Chain_operations(Left, Parse);
                if (v != null) v.Used = true;
                Parse.Skip_sp();
                if (Parse.End_of_line() || Parse.Next_symbol("==>"))
                {
                    if (Left.Var_arg == comp(Parse).NONE_c) return;
                    Assignment a = new Assignment();
                    a.Source = Left;
                    a.Line = Parse.Line;
                    Block.Add(a);
                    if (Left.Operation == Expression.Operation_kind.FUN)
                    {
                        if (Left.Fun_.Result != null)
                            warn("Result of function is not assigned");
                    }
                    else if (Left.Operation == Expression.Operation_kind.VAR ||
                        Left.Operation == Expression.Operation_kind.FIELD ||
                        Left.Operation == Expression.Operation_kind.INDEX)
                    {
                        if (!Left.Inc && !Left.Dec)
                            err("Result of expression is not assigned");
                    }
                    else if (Left.Operation == Expression.Operation_kind.CONST)
                    {
                        if (Left.Var_arg != comp(Parse).NONE_c)
                            err("Invalid using of constant");
                    }
                    else err("Result of expression is not assigned");
                }
                else Compile_assign(Left, Block, at_pos);
                if (Parse.Symbol("==>"))
                {
                    Case r = new Case();
                    r.Work = Statement.Workflow.RETURN;
                    r.Line = Parse.Line;
                    Block.Add(r);
                }
            }
        }

        /*
        
		INT temp_local|_index
		BOOL has_assignments_to_fields
		BOOL In_new_obj|ect_creation
		
		{Expr} Assign_target
        
        METHOD Compile_assign(
        {Expr} Left|_side,
        {Statement} Block|_of_stmt[])
        :
        PUSH Assign_target = Left :
	        {Expr} left|_side_expression = Left
	        CASE ?
	        [left.Var_arg.Type_.Kind == 'CLASS'] ?
	             Is_deleting_obj = TRUE
	        [left.Operation == 'INDEX' 
	         && left.Arg1_.Type_expr.Kind == 'CLASS'] ?
	             Is_deleting_obj = TRUE
	        ;
       		CASE left.Var_arg.Is_loop
       		     && left.Var_arg.For_.In_struct_array != NONE
	             ?
	             left = {Expr}(Operation= 'INDEX',
	                  Arg1_= Left.Var_arg.For_.In_struct_array,
	                  Arg2_= Left), >> All_expr[]
       		;
       		CASE left.Var_arg.In_fun_ != NONE
       		     && NONE != left.Var_arg.In_local_
       		     && left.Var_arg.In_local_ != Current_local
       		     ? 
       		     Parse.Err("Can not assign to a variable declared in the LOCAL "
       		     "block out of its home block"._EAssignOutOfHome) ;
            has_assignments_to_fields = left.Operation == 'FIELD' || (
            	left.Operation=='INDEX' && left.Arg1_.Operation=='FIELD') || (
            	left.Operation=='VAR' && left.Var_arg.In_type_.Kind == 'CLASS')
            -------------------- 'field of structure returned by a function ?'
            CASE left.Operation == 'FIELD' && left.Arg1_.Operation == 'FUN'
                 && left.Arg1_.Fun_.Result.Type_.Kind == 'STRUCTURE'
                 ?
                 Parse.Err("It does not make sense to assign a value to a "
                 "field of a structure returned by a function"
                 ""._ENoSenseAssignToStrucField) ;
            ----------------- 'struct, BUT(list fileds) = another struct ?'
            BOOL left_is_struct = left.Type_expr.Kind == 'STRUCTURE'
            CASE left_is_struct && Parse.Symbol(",") ?
                 Parse.Wait("BUT")
                 assign_structure_but_list(left, Block[]) ==> ;
            ------------------------------------------------- 'scan operation'
            Parse.Skip_sp
            INT from|_pos = Parse.Pos
            CASE Parse.Next_char ?
                ["<"]: BOOL ok|_assignment = Parse.Symbol("<<")
                ["="]: ok = ! Parse.Next_symbol("==") 
                	   ok &&= Parse.Symbol("=")
                ["+"]: ok = Parse.Symbol("+=")
                ["-"]: ok = Parse.Symbol("-=")
                ["*"]: ok = Parse.Symbol("*=")
                ["/"]: ok = Parse.Symbol("/=")
                ["%"]: ok = Parse.Symbol("%=")
                ["&"]: ok = Parse.Symbol("&=")
                	   ok ||= Parse.Symbol("&&=")
                ["|"]: ok = Parse.Symbol("|=")
                	   ok ||= Parse.Symbol("||=")
                ["^"]: ok = Parse.Symbol("^=") ;
            STR op|eration = Parse.Source[Parse.Line].[from TO Parse.Pos-1].Trim
            //CASE op !IN ["=", "<<", ""] 
            //     && Parse.Syntax_name != "SEAL" 
            //     ?
            //     Parse.Warn("Operations +=, -=, *=, /=, %=, &=, &&=, |=, ||=, "
            //     "^= are deprecated except SEAL syntax and should be converted "
            //     "e.g. to = _+, =_- etc."._WOpsDeprec) ;
            ------------------------------ 'left side should not be read-only'
            BOOL l_is_arr|ay_left = left.Is_array
            CASE op == "<<" && !l_is_arr && left.Type_expr.Kind=='STR' ? 
                 Parse.Warn("It is not recommended to use '<<' operation to "
                 "append a string with a substring, use concatenations please"
                 ""._WNotRecommendedAppendingStr) ;
            CASE (op != "<<" || !l_is_arr) && is_read_only(left)
            	 && !(left.Var_arg.Setter_method_ != NONE 
            	 	  && Parse.Allow_assign_to_fields && op == "=")
            	 && !(left.Fun_.Setter_ != NONE
            	 	  && Parse.Allow_assign_to_fields && op == "=")
            	 ?
                 CASE ?
                 [In_new_obj && left.Var_arg.Modifier['INIT']] ? NONE
                 
                 [op == "<<" && left.Var_arg.Type_.Kind == 'CLASS'
                  && left.Var_arg.Type_.Search_fun("Write", CASE_SEN, FALSE) 
                  != NONE]? NONE
                  
                 ELSE
	                  Parse.Err("left side of assignment is a read only variable "
	                  "or field"._Eleft )
                 ;
            ;
            CASE l_is_arr && op == "<<" && left.Var_arg.Is_param ? 
                 left.Var_arg.Has_changing_size = TRUE ;
            CASE ! ok ?
                CASE left.Operation ?
                    ['FUN', 'BASE_FUN', 'SYSTEM_FUN']:
                        CASE left.Fun_.Result == NONE ?
                            a|ssignment_temp = {Assign}(
                            	Source = left,
                                Function_ = THIS,
                                Line = Parse.Line, Pos= ident_pos,
                                Level = Current_level)
                                
                            extract_new_operations(a.Source, Block[], 0)
                            Block[] << a ==>
                        ;
                        
                    ['CONST']:
                        CASE left.Var_arg == comp(Parse).NONE_c ? ==> ;
                        
                    ['BINARY', 'VAR', 'INDEX', 'FIELD', 'NEW_OBJ', 'ARRAY', 
                     'AS', 'UNKNOWN', 'INT2REAL', 'NOT_B', 
                     'NOT', 'NEG']: NONE ;
                     
                err("Waiting for assignment sign, but"._Ewait3 
                ": " Parse.Next20)
                
                Parse.Fin ==> ;
            -------------------------------- 'some checks'
            CASE left.Operation ?
            ['VAR']:
				CASE left.Var_arg.Is_loop && (
					 left.Var_arg.Type_.Kind == 'INT') && (
					 loop_by_range(left.Var_arg))
					 && left.Var_arg.For_.In_struct_array == NONE
					 ?
				     Parse.Err("Assigning a value to a loop variable in "
				     "case of loop based on range of values"
				     ""._EChangeLoopVar)
				;
			['INDEX']: NONE
            ['FIELD']: NONE 
            ['CONST']: 
                       CASE left.Var_arg != comp(Parse).NONE_c ?
                            err("Assigning value to a constant"._Eassign2 )
                       ;
            ['FUN', 'BASE_FUN', 'SYSTEM_FUN']: 
				CASE ?
				[left.Fun_.Trap_field.Trap_write_ == left.Fun_] ?
					 NONE
					 
				[left.Fun_.Names[0] == "." && (
				 left.Fun_.Setter_ != NONE)] ?
				     -------------------------------- '.[i,j] = value'
				     CASE op != "=" ?
				          Parse.Err("Only = operation is allowed for .[] "
				          "at the left side"._EOnlyAssign)
				     ;
				     call_setter_of_dot(left, Block[]) ==>
				     
				[left.Fun_.Trap_field != NONE
				 || left.Fun_.Setter_ != NONE 
				 && Parse.Allow_assign_to_fields] ? NONE
				 
                [op == "<<"] ? NONE
				     
				ELSE err("Function can not be at the left side of an "
					 "assignment"._Efunleft)
				;                     		
            ['ARRAY', 'NEW_OBJ', 'BINARY', 'AS', 'UNKNOWN', 'INT2REAL',
             'NOT_B', 'NOT', 'NEG']:
                
             	err("left side can not be assigned to"._Elseft )
            ;
            ------------------------------------------------------- '<<'
            CASE op == "<<" ?
                Parse.Pos = from
                CASE !Fix_last_dest ? Set_last_dest(left, FALSE) ;
                compile_append(left, Block[]) ==> ;
            ------------------------------------------------------- 'right side'
            INT pos_r|ight_side = Parse.Pos
            CASE op == "=" && In_new_obj && Parse.Next_symbol("_") ?
                 CASE Parse.Ident == "_" ? 
                      CASE Modifiers['STATIC'] ? 
                           Parse.Err("Can not init field by '_' in a static "
                           "function"._EInit_inStatic)
                      ;
                      {Var} ff|ield_find
                      ff = Class.Find_field(Left.Var_arg.Names[0])
                      
                      {Expr} a1_this|_argument = {Expr}(Operation= 'VAR',
                      		 Var_arg= comp(Parse).THIS_var,
                      		 Type_obj_= Class),
                      		 >> All_expr[]
                      
                      {Expr} e_ff|ield_expression = {Expr}(
                      		 Operation= 'FIELD', Arg1_= a1_this,
                      		 Var_arg= ff),
                      		 >> All_expr[]
                      		 
                      {Assign} ia|ssignment_to_init_field 
                      
                      ia = {Assign}(Source= e_ff, Dest= Left, Function_= THIS,
                      		Level = 0, Line= Parse.Line), 
                      		>> Block[]
                      ==>
                 ;
            	 Parse.Pos = pos_r
            ;
			INT ref|erences = left.Var_arg.Count_ref
			BOOL used_left = ref > 0
			left.Var_arg.Used_for_w = FALSE
			//PUSH Destination_type_ :
			     //CASE left != NONE ? Destination_type_ = left.Type_expr ;
 				 r|ight_side = {Expression}.Recognize(Parse), >> All_expr[]
        	//;
            ------------- 'all newly created objects should be created before'
            CASE left.Operation == 'INDEX' ?
            	 extract_new_operations(r, Block[], 1)
            ELSE extract_new_operations(r, Block[], 0) ;
            Check_structure_clone_dismiss(r, Parse)
			BOOL used_both|_sides = left.Var_arg.Count_ref > ref
			------------------------------------ 'right side creates new object'
            CASE r.Is_new ?
				CASE used_both && r.Operation == 'NEW_OBJ' ?
					 Parse.Err("It is not allowed to use the same variable or "
					 "field in both sides of new object creation "
                     "statement"._Eitis4
                     ": " left.Var_arg.Whole_name 
                     ) ;
                -------------------------------- 'right side is new object'
                right_side_is_new_object(left, r, pos_r)
                CASE r.Array_ != NONE ?
                     left.Var_arg.Used_for_r = TRUE
                     left.Var_arg.Count_ref += 1 ;
                ------------------------------ 'assigning to RESULT'
                CASE left.Type_expr.Kind != 'STRUCTURE'
                	 && left.Var_arg.Names[0] == "RESULT"
                	 ?
                     has_new = TRUE
                     CASE !Modifiers['NEW'] 
                     	  && r.Owned_ == NONE && r.Array_ == NONE
                     	  ?
                          Parse.Err("New object is assigned to RESULT, but the "
                          "function"._Enew " " Names[*] 
                          " " ("has no modifier NEW declared"._Ehasno2 )) ;
                ;
            ;
            ------------------------------ 'assign to more common type object'
        	{Type} type_L|eft = left.Type_expr
        	{Type} type_r|ight = r.Type_expr 
            BOOL diff|erent_types_dest_source = r.Is_new
            CASE diff ?
            	 diff &&= type_r != type_L
            	 diff &&= left != NONE
            	 diff &&= left.Operation != 'CONST' ; 
            CASE diff ?
                 ----------------------------- 'use temp var to assign'
                 {Var} temp_left = {Var}(
                 		Names[] << "_temp" temp_local.Str,
                 		Type_ = r.Type_expr,
                 		In_fun_ = THIS,
                 		Line = -1,
                 		Count_ref = 1,
                 		Used_for_w = TRUE), >> Local_var[]
                 		
                 temp_local += 1
                 	
                 a = {Assign}(
                 		Dest = {Expr}(
                 			Operation = 'VAR',
                 			Var_arg = temp_left),
                 		Source = r,
                 		Line = Parse.Line, Pos= ident_pos,
                 		Function_ = THIS,
                 		Level = Current_level), >> Block[]
                         
                 r = {Expression}(
                 		Operation = 'VAR',
                 		Var_arg = temp_left), >> All_expr[]
            ;
			left.Var_arg.Used_for_w ||= used_left
			---------------------------------------- 'right side must be scalar'
            CASE r.Is_array ?
                 PUSH Parse.Pos = pos_r :
                      Parse.Err("Assigning an array is not allowed"._Eassign3 
                      ": " Parse.Next20) ;
            ;
            CASE left.Type_expr == NONE && left.Operation == 'VAR' ?
                 CASE r.Type_expr.Kind == 'CLASS' ?
                      left.Var_arg.Type_ = r.Type_expr ;
            ;
            CASE left.Operation == 'VAR' && left.Var_arg.Type_ == NONE ?
                 left.Var_arg.Type_ = r.Type_expr ;
            ------------------------------------------------ 'make assignment'
            CASE type_r.Kind == 'INT' && type_L.Kind == 'REAL' ?
                 {Expr} int_r|ight_side = r
                 INT before_r = Parse.Pos
                 
                 r = {Expr}(Operation = 'INT2REAL', Arg1_ = int_r,
                 	 Type_obj_ = comp(Parse).TYPE_REAL), OWNED BY THIS
            ;
            BOOL ro|read_only_left_var = left.Is_read_only
            CASE ?
            [ro && left.Var_arg.Setter_method_ != NONE
             && Parse.Allow_assign_to_fields && op == "="] ?
                 ------------- 'assign to a property via Setter'
                 a = {Assign}(
                 	Dest= {Expr}(Operation= 'FUN',
                 		Fun_= left.Var_arg.Setter_method_,
                 		Items_[] << r, This_= left.Arg1_),
                 	Line= Parse.Line, Pos= ident_pos, 
                 	Function_= THIS, Level= Current_level),
                 >> Block[] ==>
                 
            [ro && left.Fun_.Setter_ != NONE
             && Parse.Allow_assign_to_fields && op == "="] ?
                 ------------ 'assign to a "method" via Setter'
                 a = {Assign}(
                 	Dest = {Expr}(Operation = 'FUN',
                 		Fun_ = left.Fun_.Setter_,
                 		Items_[] << r, This_= left.This_,
                 		Type_obj_= left.Fun_.Setter_.Result.Type_),
                 	Line= Parse.Line, Pos= ident_pos,
                 	Function_= THIS, Level= Current_level),
                 >> Block[] ==>
            ;
            a = {Assign}(
            		Dest = left,
            		Source = r,
            		Line = Parse.Line, Pos= ident_pos,
            		Function_ = THIS,
            		Level = Current_level), >> Block[]
                         
            CASE r.Is_array ?
                 CASE !r.Is_fixed ?
                 	  err("Assigning a dynamic array is not allowed"._Eassign4 )
                 ;
            ;
            CASE left.Is_array ?
                 CASE left.Is_fixed ?
                      err("Assigning value to a fixed array is not "
                      "allowed"._Eassign5)
                 ;
                 CASE !r.Is_array ?
                      err("Assigning a scalar to an array"._Eassign6 ) ;
            ELSE 
                 CASE r.Is_array ?
                      err("Assigning an array to a scalar"._Eassign7 ) ;
            ;
            CASE ?
            [left.Var_arg.Constant_value == "NONE"] ?
                 CASE r.Type_expr.Kind == 'STRUCTURE' ?
	                  err("It is not allowed to omit assigning a result of a "
	                  "function returning a structure"._EResultStructureToNONE)
                 ;
            [r.Type_expr.Kind == 'CLASS' 
             && "{}" !IN a.Dest.Type_expr.Names[]] ?
             	a.Source.Type_obj_ = a.Dest.Type_expr
            [r.Type_expr.Kind != left.Type_expr.Kind] ?
                {kind_type} k_left|_expr = left.Type_expr.Kind
                {kind_type} k_r|ight_exp = r.Type_expr.Kind
                CASE k_left == 'INT' && k_r == 'INT'
                     || k_left == 'REAL' && k_r == 'REAL'
                     ? 
                     NONE
                ELSE
	                 PUSH Parse.Pos = before_r :
	                      err("Kinds of left and right sides of an assignment "
	                      "are different"._EDiffKinds ": " Parse.Next20) ;
                ;
            [r.Type_expr.Kind == 'STRUCTURE' && r.Type_expr != left.Type_expr] ?
                PUSH Parse.Pos = before_r :
                     err("Source and distination structures are different"
                     ""._EDiffStructures ": " Parse.Next20 
                     ", " left.Type_expr.In_class_.Whole_name 
                     "." left.Type_expr.Whole_name 
                     " and " r.Type_expr.In_class_.Whole_name
                     "." r.Type_expr.Whole_name     
                     ) ;
            ;
            ---------------- 'collect all assignments to RESULT in NEW function'
            CASE left.Var_arg.Names[0] == "RESULT" && Modifiers['NEW'] ?
                 Assignments_to_RESULT[] << a ;
            --------- 'complex assignments combined with arithmetic, logic, ...'
            CASE op ?
                 ["+="]: a.Source = binary(left, 'PLUS', r)
                 ["-="]: a.Source = binary(left, 'MINUS', r)
                 ["*="]: a.Source = binary(left, 'MULT', r)
                 ["/="]: a.Source = binary(left, 'DIV', r)
                 ["%="]: a.Source = binary(left, 'REST', r)
                 ["&="]: a.Source = binary(left, 'AND_B', r)
                 ["|="]: a.Source = binary(left, 'OR_B', r)
                 ["^="]: a.Source = binary(left, 'XOR_B', r)
                 ["&&="]: a.Source = binary(left, 'AND', r)
                 ["||="]: a.Source = binary(left, 'OR', r)
                 ["="]: 
                        CASE left != NONE && r.Operation == 'FUN' && (
                             r.Fun_.Result == NONE) && !(
                             r.Fun_.Modifiers['TRAP_FUN'])
                             ?
                             err("Expression right to an assignment sign does "
                             "not return a value"._Eexpr )
                        ;
                        CASE !(left.Operation == 'CONST' && (
                             left.Var_arg == comp(Parse).NONE_c))
                             ?
                             CASE ?
                             [left.Operation IN ['FIELD', 'VAR']] ?
                                  left.Var_arg.Provide_traps
                             [left.Operation == 'INDEX'] ?
                                  left.Arg1_.Var_arg.Provide_traps
                             ;
                             CASE ?
                             [left.Operation == 'FIELD' && (
                              left.Var_arg.Trap_write_ != NONE) && !(
                              Modifiers['TRAP_FUN']) && (
                              comp(Parse).Debugging || (
                              comp(Parse).TEST_value))] ?
                                  ------ 'replace to TRAP_WRITE (field)'
                                  a.Source = {Expr}(Operation = 'FUN',
                                  	Fun_ = left.Var_arg.Trap_write_,
                                  	This_ = left.Arg1_,
                                  	Items_[] << r)
                                  	
                                  left.Var_arg.Trap_write_.Usage_count += 1
                                  a.Dest = NONE
                                  
                             [left.Operation == 'VAR' && (
                              left.Var_arg.Trap_write_ != NONE) && !(
                              Modifiers['TRAP_FUN']) && (
                              comp(Parse).Debugging || (
                              comp(Parse).TEST_value))] ?
                                  ------ 'replace to TRAP_WRITE (var)'
                                  a.Source = {Expr}(Operation = 'FUN',
                                  	Fun_ = left.Var_arg.Trap_write_,
                                  	This_ = left.This_,
                                  	Items_[] << r)
                                  	
                                  left.Var_arg.Trap_write_.Usage_count += 1
                                  a.Dest = NONE
                                  
                             [left.Operation == 'INDEX' && (
                              left.Arg1_.Var_arg.Trap_write_ != NONE) && !(
                              Modifiers['TRAP_FUN']) && (
                              comp(Parse).Debugging || (
                              comp(Parse).TEST_value))] ?
                                  ------ 'replace to TRAP_WRITE (index)'
                                  a.Source = {Expr}(Operation = 'FUN',
                                  	Fun_ = left.Arg1_.Var_arg.Trap_write_,
                                  	This_ = left.Arg1_.Arg1_,
                                  	Items_[] << left.Arg2_ << r)
                                  	
                                  left.Arg1_.Var_arg.Trap_write_.Usage_count+=1
                                  a.Dest = NONE
                             ;
                             Assign_check_compat(left, r)
                             ==> ;
                             
            ELSE err("Internal error - forgotten op"._Einternal3 
                     ": [" op "]") ==>
            ; 
            CASE !(left.Operation == 'CONST' && (
                 left.Var_arg == comp(Parse).NONE_c))
                 ?
                 -------------- 'compare with resulting source type'
                 Assign_check_compat(left, a.Source) ;
         	PUSH left.Type_obj_ = NONE :
         	PUSH r.Type_obj_ = NONE :
             	 CASE left.Type_expr.Kind=='CLASS'
             	      && r.Type_expr.Kind=='CLASS'
             	      && r.Var_arg.Constant_value != "NONE"
             	      && !r.Type_expr.Is_descend(left.Type_expr, 
             	      comp(Parse)) 
             	      ? 
             	      err("Assigning an incompatible object"
             	      ""._EAssignIncompat) ;
         	;
         	;
            ----------------------------------- 'assigning via a trap function'
            CASE left.Operation == 'INDEX' && (
            	 left.Arg1_.Var_arg.Trap_write_ != NONE) && (
            	 !Modifiers['TRAP_FUN']) && (
                 comp(Parse).Debugging || (
                 comp(Parse).TEST_value))
                 ?
                 a.Source = {Expr}(Operation = 'FUN',
                 	Fun_ = left.Arg1_.Var_arg.Trap_write_,
                 	This_ = left.Arg1_.Arg1_,
                 	Items_[] << left.Arg2_ << r)
                 left.Arg1_.Var_arg.Trap_write_.Usage_count += 1
                 a.Dest = NONE ;
        ;
        CASE a.Source == a.Dest ?
             Parse.Warn("The left side of the assignment is identical to "
        	     "the right side"._WAssignToItself) ; 
        .
            
        METHOD assign_structure_but_list(
        {Expr} Left|_side,
        {Statement} Block|_of_stmt[])
        	:
        	CASE Parse.Symbol("(") ?
		         FOR i|dummy IN [Parse.Pos TO Parse.Last] :
		             STR but_dest|ination_names[] << Parse.Ident
		             {Var} dest|ination_to_check 
		             dest = Left.Type_expr.Find_field(but_dest[*])
		             CASE dest.Is_array ?
		                  Parse.Wait("[")
		                  Parse.Wait("]") ;
		             CASE !Parse.Symbol(",") ? BREAK i ;
		         ;
		         Parse.Wait(")")
        	;
	        Parse.Wait("=")
	        --------------- 'right side structure'
	        INT was_pos|ition = Parse.Pos 
	        {Expr} source|_side = Recognize(Parse), >> All_expr[]
	        CASE source.Type_expr.Kind != 'STRUCTURE' ?
	             PUSH Parse.Pos = was_pos :
	             	  Parse.Err("Waiting for a structure at the right side "
	             	  "of the assignment"._EWaitingStruct ": " Parse.Next20)
	             ;
	        ;
	        BOOL has_fun|ctions_calls = Left.Has_function_calls
	        	 has_fun ||= source.Has_function_calls
	        CASE has_fun ?
	             Parse.Err("For structured value assignment with BUT exceptions"
	             ", it is not allowed to use function calls on both sides of "
	             "a statement"._EFunCallsAssigningStruct) ;
	        ---------------'it also can have its but-list:'
	        CASE Parse.Symbol(",") ?
	             Parse.Wait("BUT")
	             Parse.Wait("(")
	             FOR i|dummy IN [Parse.Pos TO Parse.Last] :
		            STR but_sour|ce_names[] << Parse.Ident
		            {Var} source_f|ield_to_check 
		            source_f = source.Type_expr.Find_field(but_sour[*])
		            CASE source_f.Is_array ?
		                 Parse.Wait("[")
		                 Parse.Wait("]") ;
		            CASE !Parse.Symbol(",") ? BREAK i ;
		        ;
		        Parse.Wait(")")
	        ;
	        ---------------- 'create assignments: 1 for each field'
	        FOR fl IN Left.Type_expr.Field[] :
	            FOR d IN but_dest[] :
	                CASE d IN fl.Names[] ?
	                     BREAK d, CONTINUE fl ;
	            ;
	            ------------ 'find correspondent field in source structure'
	            FOR fr IN source.Type_expr.Field[] :
	                CASE fr.Names[0] != fl.Names[0] ? CONTINUE fr ;
	                
	                FOR s IN but_sour[] :
	                    CASE s IN fr.Names[] ? BREAK s, BREAK fr, CONTINUE fl ;
	                ;     
	                CASE fr.Type_ != fl.Type_ ?
	                     Parse.Err("Types of fields in source and destination "
	                     "structures are not same for the field"._ENotSameType
	                     " " fr.Names[0]) ;
	                CASE fr.Is_array && !fl.Is_array ?
	                     Parse.Err("Assigning an array to a scalar, field of "
	                     "structure"._EArray2Scalar ": " fr.Names[0]) ;
	                CASE !fr.Is_array && fl.Is_array ?
	                     Parse.Err("Assigning a scalar to an array, field of "
	                     "structure"._EScalar2Array ": " fr.Names[0]) ;
	                CASE fr.Is_array && fr.Is_fixed != fl.Is_fixed ?
	                     Parse.Err("Fixed arrays can be assigned only to "
	                     "fixed arrays") ;
	                ---------------------- 'assign 1 field'
	                temp_Dest = fl
	                temp_Source = fr
	            	assign_1_field_structure(Left, source, Block[])
	                BREAK fr, CONTINUE fl ;
	                
	            Parse.Err("Source field was not found to assign for the "
	            "destination field"._ESourceFieldNotFound ": " fl.Names[0])
	        ; .
	        
        {Var} temp_Dest
        {Var} temp_Source
	        
        METHOD assign_1_field_structure(
        {Expr} Left|_side,
        {Expr} Right|_side,
        {Statement} Block|_of_stmt[])
        	:
        {Var} tDest|ination_field = temp_Dest
        {Var} tSource|_field = temp_Source
        	CASE !tDest.Is_array ?
        	     a|ssign_statement = {Assign}(
                 	Dest= {Expr}(Operation= 'FIELD', Arg1_= Left,
                 		Var_arg= tDest),
                 	Source= {Expr}(Operation= 'FIELD', Arg1_= Right,
                 		Var_arg= tSource),
                 	Line= 0, Pos= 0,//Parse.Line, 
                 	Function_= THIS, Level= Current_level),
                 >> Block[] 
                 
                 CASE tSource.Type_.Kind == 'STRUCTURE' ?
                 	  {Expr} f_to_c|lone_field = a.Source
                 	  All_expr[] << f_to_c
                 	  
                      a.Source = {Expr}(Operation= 'SYSTEM_FUN',
                      	Fun_= Parse.Compiler.SYSFUN_Clone,
                      	Items_[] << f_to_c)
                 ;
                 ==>
        	;
        	Parse.Err("Assigning array fields is not implemented for assign "
        	"structures with BUT exceptions"._EArraysNotImplemented)
       	.
        	     
            
        METHOD call_setter_of_dot(
        {Expr} Left|_side_dot_function,
        {Statement} Block|_to_add_resulting_statement[])
        	:
			{Assign} a|_simple_assign = {Assign}(
					 Line = Parse.Line, Pos= ident_pos,
			 		 Function_ = THIS, Level = Current_level,
                     Source = {Expr}(Operation = 'FUN',
                     	Fun_ = Left.Fun_.Setter_, This_ = Left.This_)),
				     >> Block[]
				     
			CASE Left.Fun_.Setter_ !IN Call_functions_[] ?
				 Call_functions_[] << Left.Fun_.Setter_ ;
			Left.Fun_.Setter_.Usage_count += 1
			Left.Fun_.Setter_.Count_ref += 1
			FOR p IN Left.Items_[] : a.Source.Items_[] << p ;
			
			{Expr} r|ight_side = Recognize_typed(Parse,
			    Left.Fun_.Setter_.Param[*].Type_.Kind), >> All_expr[]
			    
			CASE r.Is_array ?
			     Parse.Err("Value assigned to .[] should not be an array"
			     ""._EAssignedToDotArray)
			;
			CASE !Check_types_compat(Left.Fun_.Setter_.Param[*].Type_,
			     r.Type_expr)
			     ? Parse.Err("Type of value assigning to .[] is not compatible"
			       ""._ETypeAssignedToDot)
			;
			a.Source.Items_[] << r .
				 
        METHOD is_read_only({Expr} V|ariable) ==> BOOL,
        RECURSIVE
        	:
			BOOL a1_is_struc|ture = V.Arg1_.Type_expr.Kind == 'STRUCTURE'
            CASE ?
            [V.Var_arg.Modifiers[{var_mod}.'READ']] ?
                 CASE ?
                 [comp(Parse).Current_class.Is_descend(
                      V.Var_arg.In_type_, comp(Parse))] ? ==>
                 [comp(Parse).Current_class.Names[
                  0] IN V.Var_arg.In_type_.Friends[]] ? ==> 
                 ;
                 RESULT = TRUE
            [V.Var_arg.Names[0] == "RESULT"] ? RESULT = FALSE
            [V.Var_arg.Is_param && !V.Var_arg.Is_stored_param] ? RESULT = TRUE
            [V.Operation == 'FIELD' && a1_is_struc && is_read_only(V.Arg1_)] ?
                 RESULT = TRUE
            //[V.Operation == 'INDEX' && is_read_only(V.Arg1_)
            // && !V.Arg1_.Var_arg.Is_param] ? RESULT = TRUE
            ; .
        */
        static int CNT_Compile_assign;

        public void Compile_assign(Expression Left, List<Statement> Block)
        {
            Compile_assign(Left, Block, 0);
        }
        public void Compile_assign(Expression Left, List<Statement> Block, int At_pos)
        {
            if (CNT_Compile_assign++ == 74)
            { }

            Parse.Skip_sp();
            int from = Parse.Pos;
            bool ok = false;
            switch ((Parse.Next_char() + " ")[0])
            {
                case '<': ok = Parse.Symbol("<<"); break;
                case '=': ok = !Parse.Next_symbol("==") && Parse.Symbol("="); break;
                case '+': ok = Parse.Symbol("+="); break;
                case '-': ok = Parse.Symbol("-="); break;
                case '*': ok = Parse.Symbol("*="); break;
                case '/': ok = Parse.Symbol("/="); break;
                case '%': ok = Parse.Symbol("%="); break;
                case '&': ok = Parse.Symbol("&=") || Parse.Symbol("&&="); break;
                case '|': ok = Parse.Symbol("|=") || Parse.Symbol("||="); break;
                case '^': ok = Parse.Symbol("^="); break;
            }
            if (!ok)
            {
                if (Left != null && Left.Operation == Expression.Operation_kind.FUN)
                {
                    if (Left.Fun_.Result == null)
                    {
                        Assignment a1 = new Assignment();
                        a1.Source = Left;
                        a1.Line = Parse.Line;
                        Block.Add(a1);
                        return;
                    }
                }
                else if (Left != null && Left.Operation == Expression.Operation_kind.CONST)
                {
                    if (Left.Var_arg == comp(Parse).NONE_c)
                        return;
                }
                if (Left.Inc || Left.Dec)
                {
                    Assignment a2 = new Assignment();
                    a2.Source = Left;
                    a2.Line = Parse.Line;
                    Block.Add(a2);
                    return;
                }
                err("Waiting for assignment sign, but: " + Parse.Next20());
                Parse.Fin();
                return;
            }
            string op = from < Parse.Source[Parse.Line].Length && Parse.Pos < Parse.Source[Parse.Line].Length ? 
                Parse.Source[Parse.Line].Substring(from, Parse.Pos - from).Trim() : "";
            switch (Left.Operation)
            {
                case Expression.Operation_kind.VAR:
                case Expression.Operation_kind.INDEX: 
                case Expression.Operation_kind.FIELD:
                break;
                case Expression.Operation_kind.CONST:
                if (Left.Var_arg != comp(Parse).NONE_c)
                    err("Assigning valuie to a constant");
                break;
                default: err("Left side can not be assigned to"); break;
            }
            if (op == "<<")
            {
                Parse.Pos = from;
                last_dest = Left;
                compile_append(Left, Block, At_pos);
                return;
            }
            //-------------------------------------- 'right side'
            int pos_r = Parse.Pos;
            Expression r = Expression.Recognize(Parse);
            if (r!=null && r.Is_array())
            {
                int sav_parse_pos = Parse.Pos;
                Parse.Pos = pos_r;
                Parse.Err("Assigning an array is not allowed: " + Parse.Next20());
                Parse.Pos = sav_parse_pos;
            }
            if (r != null && r.Is_new())
            {
                if (comp(Parse).In_init_level == 0 && Parse.Symbol(","))
                    compile_owner(r, Parse);
                else
                {
                    if (Left.Var_arg.Names.Count > 0 && 
                        last_char(Left.Var_arg.Names[Left.Var_arg.Names.Count - 1]) == "_")
                    {
                        int sv = Parse.Pos;
                        Parse.Pos = pos_r;
                        Parse.Err("Assigning new object to a weak reference field: " +
                            Parse.Next20());
                        Parse.Pos = sv;
                    }
                    else if (is_local_var_only(Left) && 
                        !Left.Var_arg.Names[
                        Left.Var_arg.Names.Count-1].ToLower(
                        ).Contains("temp"))
                        Parse.Err("Assigning new object to a local variable only");
                }
                if (Left.Var_arg == Result)
                {
                    //has_new = true;
                    if (!Modifiers[(int)Fun_mod.NEW])
                        Parse.Err("New object is assigned to RESULT, but " +
                            "function " + Names[Names.Count-1] + " has no modifier NEW declared");
                }
            }
            Type LType = Left.Type_expr();
            Type rType = r == null ? null : r.Type_expr();
            if (LType == null && Left.Operation == Expression.Operation_kind.VAR &&
               rType != null && rType.Kind == Type.Kind_type.CLASS)
                Left.Var_arg.Type_ = r.Type_expr(); 
            if (Left.Operation == Expression.Operation_kind.VAR && Left.Var_arg.Type_ == null)
                Left.Var_arg.Type_ = r == null ? null : r.Type_expr();
            //------------------------------------------- 'make assignment'
            Assignment a = new Assignment();
            a.Dest = Left;
            a.Source = r;
            a.Line = Parse.Line;
            Block.Add(a);
            
            if (r != null && r.Is_array() && !r.Is_fixed())
                err("Assigning a dynamic array is not allowed");
            if (Left.Is_array())
            {
                if (Left.Is_fixed())
                    err("Assigning value to a fixed array is not allowed");
                if (!r.Is_array())
                    err("Assigning a scalar to an array");
            }
            else if (r != null && r.Is_array())
                err("assigning an array to a scalar");
            switch ((op + (Char)0)[0])
            {
                case '+': a.Source = binary(Left, Expression.Bin.PLUS, r); break;
                case '-': a.Source = binary(Left, Expression.Bin.MINUS, r); break;
                case '*': a.Source = binary(Left, Expression.Bin.MULT, r); break;
                case '/': a.Source = binary(Left, Expression.Bin.DIV, r); break;
                case '%': a.Source = binary(Left, Expression.Bin.REST, r); break;
                case '&': if (op == "&=")
                        a.Source = binary(Left, Expression.Bin.AND_B, r);
                    else a.Source = binary(Left, Expression.Bin.AND, r); break;
                case '|': if (op == "|=")
                        a.Source = binary(Left, Expression.Bin.OR_B, r);
                    else a.Source = binary(Left, Expression.Bin.OR, r); break;
                case '^': a.Source = binary(Left, Expression.Bin.XOR_B, r); break;
                case '=': Assign_check_compat(Left, r, At_pos); break;
                default: err("Internal error - forgotten op: " + op); break;
            }
        }

        private static string last_char(string s)
        {
            if (s == "") return "";
            return s.Substring(s.Length - 1);
        }

        /*
        
        METHOD is_local_var_only(
            {Expr} L|eft_part_of_assignment) ==> BOOL, RECURSIVE
            :
            ------------- 'Is the expression referring to a local variable?'
            CASE L.Var_arg == Result && Modifiers['NEW'] || L.Var_arg.Is_param ?
                 ==> ;
            CASE Parse.Temp_word IN L.Var_arg.Names[*].Upper ? ==> ;
            CASE L.Operation ?
                ['VAR']: 
                         CASE L.Var_arg IN Local_var[] ?
                              RESULT = TRUE ;
                              
                ['INDEX', 'INT2REAL', 'NOT_B', 'NOT', 'NEG']:
					RESULT = is_local_var_only(L.Arg1_)
					
                ['FIELD', 'BINARY', 'FUN', 'BASE_FUN', 'SYSTEM_FUN', 'NEW_OBJ',
                 'ARRAY', 'AS', 'CONST', 'UNKNOWN']: NONE ; .
        */
        private bool is_local_var_only(Expression L)
        {
            if (L.Var_arg == Result && Modifiers[(int)Fun_mod.NEW]) return false;
            if (L.Var_arg != null && L.Var_arg.Names.Count > 0 && 
                L.Var_arg.Names[L.Var_arg.Names.Count - 1].Contains("temp"))
                return false;
            switch (L.Operation)
            {
                case Expression.Operation_kind.VAR:
                    if (Local_var.Contains(L.Var_arg)) return true;
                    break;
                case Expression.Operation_kind.INDEX:
                    return L.Arg1_ != null && is_local_var_only(L.Arg1_);
            }
            return false;
        }
        /*
        
        METHOD compile_owner(
        	{Expr} E|xpression, {Parser} Parse|_src)
        	:
            Parse.Skip_sp
            INT pos|ition_owner = Parse.Pos
            CASE Parse.Next_char ?
                 [">"]: Parse.Wait(">>")
                 		CASE E.Type_expr.Kind != 'CLASS' ?
                 		     Parse.Err("Operation >> is not applicable for "
                 		     "type kind"._EAppendRNotApplicable 
                 		     ": " E.Type_expr.Kind.Name)
                 		;
                        Has_add = TRUE
                        E.Array_ = Recognize(Parse), >> All_expr[]
                        E.Array_.Var_arg.Used_for_w = TRUE
                        E.Array_.Var_arg.Count_ref += 1
                        E.Array_.Var_arg.Has_changing_size = TRUE
                        CASE E.Array_.Var_arg.Declared_in_debug && !(
                             Compiling_debug)
                             ?
                             Parse.Err("Variable"._Evar4 
                             " " E.Array_.Var_arg.Whole_name 
                             " " ("was declared in debug block and can"
                             " not be used in regular code"._Ewas2 ) )
                        ;
                        CASE E.Array_.Is_weak ?
                             Parse.Err("Placing new object to array of weak "
                             "references"._Eplac )
                        ;
                        PUSH Parse.Pos = pos :
                             CASE ?
                             [!E.Array_.Is_array] ?
                                  Parse.Err("Not is array"._Enot2 
                                  ": " Parse.Next20)
                                  
                             [E.Array_.Is_fixed] ?
                                  Parse.Err("Adding item to fixed array"._Eadd
                                  ": " Parse.Next20)
                                  
                             [E.Array_.Is_read_only && (
                         	  !(E.Array_.From_type(
                         	  comp(Parse).Current_class)))] ?
                                  Parse.Err("Adding item to read only "
                                  "array"._Eadd2 ": " Parse.Next20)
                             ;
                             Append_check_compat(E.Array_, E, ">>") ;
                        CASE E.Array_.Var_arg.Is_param ?
                             E.Array_.Var_arg.Used_to_add_to = TRUE ;
                 ["O"]: Parse.Wait("OWNED")
                        Parse.Wait("BY")
                        E.Owned_ = Recognize(Parse), >> All_expr[]
                        PUSH Parse.Pos = pos :
                             CASE ?
                             [E.Owned_.Type_expr.Kind == 'STRUCTURE'] ?
                                  Parse.Err("Owner can not be a STRUCTURE"
                                  ""._EownerStruc)
                                  
                             [E.Owned_.Type_expr.Kind !IN [
                              'CLASS', 'STRUCTURE']] ?
                                  Parse.Err("Owner is not an object"._Eowner 
                                  ": " Parse.Next20)
                                  
                             [E.Is_array] ?
                                  Parse.Err("An array can not be used "
                                  "as an owner for new object"._Eanarray )
                                  
                             [E.Operation == 'FUN'] ?
                                  Parse.Err("Owner can not be assigned to the "
                                  "object created in a function"._Eowner2 )
                             ;
                        ;
            ELSE Parse.Err("Waiting for an owner or add to array "
                 "operation, but: " Parse.Next20) ; .
        */
        private void compile_owner(Expression E, Parser Parse)
        {
            Parse.Skip_sp();
            int pos = Parse.Pos;
            switch ((Parse.Next_char() + (char)0)[0])
            {
                case '>':
                    Parse.Wait(">>");
                    Has_add = true;
                    E.Array_ = Expression.Recognize(Parse);
                    if (E.Array_ != null && E.Array_.Var_arg != null)
                        E.Array_.Var_arg.Used = true;
                    if (E.Array_.Is_weak())
                        Parse.Err("Placing new object to an array of weak references");
                    int save = Parse.Pos;
                    Parse.Pos = pos;
                    try
                    {
                        if (!E.Array_.Is_array())
                            Parse.Err("Not is array: " + Parse.Next20());
                        if (E.Array_.Is_fixed())
                            Parse.Err("Adding item to fixed array: " + Parse.Next20());
                        if (E.Array_.Is_read_only())
                            Parse.Err("Adding item to read only array: " + Parse.Next20());
                        Assign_check_compat(E.Array_, E, pos);
                    }
                    finally { Parse.Pos = save; }
                    break;
                case 'O':
                    Parse.Wait("OWNED");
                    Parse.Wait("BY");
                    E.Owned_ = Expression.Recognize(Parse);
                    save = Parse.Pos;
                    Parse.Pos = pos;
                    try
                    {
                        if (E.Owned_.Type_expr().Kind != Type.Kind_type.CLASS)
                            Parse.Err("Owner is not an object: " + Parse.Next20());
                        if (E.Is_array())
                            Parse.Err("An array can not be used as an owner for new object: " +
                                Parse.Next20());
                        if (E.Operation == Expression.Operation_kind.FUN)
                            Parse.Err("Owner can not be related to the object created in a function");
                    }
                    finally { Parse.Pos = save; }
                    break;
                default: Parse.Err("Waiting for an owner or add to array operation, but: " +
                    Parse.Next20());
                    break;
            }
        }

        /*
        //INT total_app|end_temp_vars
        BOOL Appending_to_DB

METHOD compile_append(
{Expr} Left|_side, 
{Statement} Block|_stmts[])
	:
	PUSH Appending_to_DB :
	PUSH Assign_target = Left :
		 {Expr} oce|xpression_owner_class = Left.Arg1_
		 FOR idummy IN [0 TO MAX_INT-1] :
		     CASE oce == NONE ? BREAK idummy ;
		     CASE oce.Type_expr.Kind == 'CLASS' ? BREAK idummy ;
		     oce = oce.Arg1_ ;
		 --------------- 'check for Write method call implicitly'
		 {Type} oc|lass_owner = oce.Type_expr
		 {Type} cc|urrent_class = Parse.Compiler.Current_class
		 CASE Left.Var_arg != NONE && !Left.Is_array
		      && !cc.Is_descend(oc, comp(Parse))
		      && cc.Names[0] !IN oc.Friends[]
			  ?
		      {Fun} write|_method = Left.Var_arg.Type_.Search_fun(
		     		 "Write", CASE_SEN, FALSE)
		     		  
		      CASE ?
		      [Left.Var_arg.Type_.Kind == 'CLASS'
		       && write.Param[].Count == 1] ?
		           BOOL use_write|_method = TRUE
		           {Type} type_arg|ument = write.Param[0].Type_
		      [Left.Is_read_only] ?
		       err("Appending to a read only target"._Append_read_only) ;
		 ;
		 ----------------------------------------- '<< expr << expr << ...'
		 Has_add = TRUE
		 //BOOL is_1st|_add = TRUE
		 FOR x|dummy IN [Parse.Pos TO Parse.Last] :
		     CASE !Parse.Symbol("<<") ? BREAK x ;
		          
			 CASE ?
			 [Left.Type_expr.Kind=='CLASS' 
			 && "{DB}" IN Left.Type_expr.Top_base.Names[]] ?
			      Appending_to_DB = TRUE
			      Assign_target = NONE
		    	  {Expr} r|ight_side = Recognize(Parse), >> All_expr[]
			 [!use_write] ?
		    	  r = Recognize(Parse), >> All_expr[]
			 [type_arg.Kind !IN ['CLASS', 'STRUCTURE']] ?
				  r = Recognize_typed(Parse, type_arg.Kind), >> All_expr[]
			 [type_arg.Kind == 'STRUCTURE'] ?
			     r = Recognize(Parse), >> All_expr[]
			     CASE r.Type_expr != type_arg ?
			          err("Write argument type is bad"._WriteArgBad) ;
			 [type_arg.Kind == 'CLASS'] ?
			     r = Recognize(Parse), >> All_expr[]
			     CASE !r.Type_expr.Is_descend(type_arg, Parse.Compiler) ?
			          err("Write argument class is bad"._WriteObjBad) ;
			 ;
			 CASE r==NONE ? 
			      err("Could not append"._ECouldNotAppend 
				  ": " Parse.Rest_of_line) ;
		    	 
		     Check_structure_clone_dismiss(r, Parse)
		     CASE r.Is_array ? err("Can not append an array"._Ecannot2 ) ;
		     PUSH extract_if_no_assignments = TRUE :
		    	  extract_new_operations(r, Block[], 1) //important: Level > 0
		     ;
		     ------------------ 'load data from DB'
		     CASE r.Type_expr.Kind == 'CLASS' 
		          && "{DB}" IN r.Type_expr.Top_base.Names[]
		          ?
		          {Fun} cf|unction_current = Parse.Compiler.Current_fun
		          CASE cf.Modifiers['STATIC'] ? 
		               err("Statement << to read data from {DB} can be "
		               "used only in methods, not in static functions"
		               ""._EOnlyInMethods)
		          ELSE This_used = TRUE ;
		          Parse.Wait(",")
		          Parse.Wait("BY")
		          Parse.Wait("TABLE")
		          STR table|_name = Parse.Ident
		          {Table} t|able_value = cc.Find_table(table)
		          t.Translate_read_from_db(Left, r, Block[]) ==>
		     ;
		     CASE ?
		     ["{DB}" IN Left.Type_expr.Top_base.Names[]] ?
		          NONE
		     //[r.Type_expr .Kind != 'STR'] ?
		          //err("Right side has not a value to add"._Eright ) 
		     ;
		          
		     a|ppend_stmt_temp = {Assign}(Work = 'APPEND', Dest = Left,
		          Function_ = THIS, Level = Current_level,
		          Source = r, Line = Parse.Line, Pos= 0), >> Block[]
		          
		     CASE Left.Is_array ?
		          CASE Left.Operation IN ['FIELD', 'VAR'] ?
		        	   Left.Var_arg.Provide_traps ;
		          {Expr} tthis|_for_trap_call = Left.This_
		          CASE Left.Operation == 'FIELD' ?
		               tthis = Left.Arg1_ ;
		          CASE Left.Operation IN ['FIELD', 'VAR'] && (
		        	   Left.Var_arg.Trap_add_ != NONE) && (
		        	   comp(Parse).Debugging || (
		        	   comp(Parse).TEST_value))
		        	   ?
		               const_TRUE = {Expr}(
		              		 Operation = 'CONST',
		              		 Var_arg = comp(Parse).TRUE_c),
		              		 OWNED BY THIS
		        	 			  
		               count_call = {Expr}(
		              		 Operation = 'SYSTEM_FUN',
		              		 Fun_ = comp(Parse).SYSFUN_Count,
		              		 Items_[] << Left), OWNED BY THIS
		        	 			  
		               const_1|_one = {Expr}(
		              		 Operation = 'CONST',
		              		 Var_arg = comp(Parse).N1_c), OWNED BY THIS
		              			  
		               count_m|inus_1 = {Expr}(
		              		 Operation = 'BINARY',
		              		 Sign = 'MINUS',
		              		 Arg1_ = count_call,
		              		 Arg2_ = const_1), OWNED BY THIS
		              			  
		        	   trap|_stmt = {Assign}(Work = 'ASSIGN',
		        	  	  Dest = NONE, Function_ = THIS, 
		        	  	  Line = Parse.Line, Pos= 0,
		        	 	  Level = Current_level,
		        	 	  Source = {Expr}(Operation = 'FUN',
		        	 		  Fun_ = Left.Var_arg.Trap_add_,
		        	 		  This_ = tthis,
		        	 		  Items_[] << const_TRUE,
		        	 		  Items_[] << count_m) ),
		        	 	  >> Block[]
		          ;  	  
		          Append_check_compat(Left, r, "<<")
		          CASE Left.Is_fixed ?
		               err("Appending item to fixed array"._Eappend ) ;
		     ELSE 
		          CASE Left.Type_expr.Kind == 'CLASS' ?
					    write = search_write(Left.Type_expr)
					    a.Work = 'ASSIGN'
					    a.Dest = NONE
					    
					    a.Source = {Expr}(
					   		 Operation = 'FUN',
					   		 Fun_ = write,
					   		 This_ = Left,
					   		 Items_[] << r)
					    
		                Call_method_write(write) ==> ;
		                
				  CASE Left.Type_expr.Kind != 'STR' ?
		               err("Destination for '<<' can be only STRING "
		               "or dynamic array or an object of a class having "
		               "a method Write"._Edest ) ;
		     ;
		 ;
	;
	; .
            
        BOOL extract_if_no_assignments
            
        METHOD extract_new_operations(
        	{Expr} E|xpression_to_handle,
        	{Statement} Block|_to_add_new_statements[],
        	INT Level|_extracting), RECURSIVE
        	:
        	CASE E == NONE ? ==> ;
        	----------------------- 'first extract nested levels'
			extract_new_operations(E.Arg1_, Block[], Level+1)
			extract_new_operations(E.Arg2_, Block[], Level+1)
			extract_new_operations(E.Arg3_, Block[], Level+1)
			extract_new_operations(E.This_, Block[], Level+1)
			FOR it IN E.Items_[] :
				extract_new_operations(it, Block[], Level+1) ; 
			----------------------- 'now extract top level'
			CASE ?
			[E.Operation == 'NEW_OBJ'
			 && Level > 0 && (
			 extract_if_no_assignments || E.Assignments_[].Count > 0)] ?
			     comp(Parse).Count_extr += 1
			     
			     {Var} loc|al_variable_to_store_new_object = {Var}(
			     	Line = 0, In_fun_ = THIS,
			     	Names[] << "_extr_new_" comp(Parse).Count_extr.Str,
			     	Type_ = E.Type_expr), >> Local_var[]
			     	
			     {Assign} extr|acted_statement_new = {Assign}(
			     	Line = -1, Pos= 0, Function_ = THIS, Level = 0,
			     	Source = {Expr}(Operation = 'NEW_OBJ',
			     		Type_obj_ = E.Type_obj_),
			     	Dest = {Expr}(Operation = 'VAR',
			     		Var_arg = loc)), >> Block[]
			     		
			     FOR a IN E.Assignments_[] : extr.Source.Assignments_[] << a ;
			     E.Assignments_[].Clear
			     ------------------ 'replace E with a reference to the variable'
			     E.Operation = 'VAR'
			     E.Var_arg = loc
			     
			[E.Operation IN ['FUN', 'SYSTEM_FUN', 'BASE_FUN'] && Level > 0
			 && E.Fun_.Result.Type_.Kind == 'STRUCTURE'] ?
			     comp(Parse).Count_extr += 1
			     
			     loc = {Var}(
			     	Line = 0, In_fun_ = THIS,
			     	Names[] << "_extr_tmp_" comp(Parse).Count_extr.Str,
			     	Type_ = E.Type_expr), >> Local_var[]
			     	
			     extr = {Assign}(
			     	Line = -1, Pos= 0, Function_ = THIS, Level = 0,
			     	Source = {Expr}(Operation = E.Operation,
			     		Fun_ = E.Fun_, Type_obj_ = E.Type_obj_,
			     		This_ = E.This_),
			     	Dest = {Expr}(Operation = 'VAR',
			     		Var_arg = loc)), >> Block[]
			     		
			     FOR p IN E.Items_[] : extr.Source.Items_[] << p ;
			     E.Items_[].Clear
			     		
			     FOR a IN E.Assignments_[] :
			     extr.Source.Assignments_[] << a ;
			     E.Assignments_[].Clear
			     ------------------ 'again replace E --> loc'
			     E.Operation = 'VAR'
			     E.Var_arg = loc
			; .
				
        METHOD disallow_new_operations(
        {Expr} E|xpression_to_check), RECURSIVE
        	:
        	CASE E == NONE ? ==> ;
			CASE E.Operation == 'NEW_OBJ' ?
			     Parse.Err("Creating new object or structure is not allowed "
			     "in branch conditions"._ENewObjInCases)
			;
			disallow_new_operations(E.Arg1_)
			disallow_new_operations(E.Arg2_)
			disallow_new_operations(E.Arg3_)
			disallow_new_operations(E.This_)
			FOR it IN E.Items_[] :
				disallow_new_operations(it) ; .
	
				     
            
		METHOD Call_method_write({Fun} M|ethod_called)
            :
            CASE M.Modifiers['STATIC'] ?
                 Parse.Err("Destination object's class function Write is "
                 "static (not a method), so it can not be replaced with "
                 "operator <<"._Edest3 )
            ;
            CASE M.Param[].Count != 1 || M.Param[0].Type_.Kind != 'STR' || (
                 M.Param[0].Is_array) || M.Result != NONE
                 ?
                 Parse.Err("Method Write of destination object's class can not "
                 "be replaced with << operator still it is not a single STR "
                 "scalar parameter method not returning a value"._Emethod8 )
            ; .
                 
		METHOD Call_method_wait|ing_some_function_calls(
            {Fun} M|ethod_called)
            :
			CASE M.Wait_names_f[].Count == 0 ? ==> ;
			Waiting_[] << NONE
			Lines_waiting[] << Parse.Line+1
			FOR wn IN M.Wait_names_f[] :
				{Fun} w|ait_function = M.Class.Find_fun(wn, TRUE)
				CASE w !IN Waiting_[] ? Waiting_[] << w
										Lines_waiting[] << 0 ;
			;
			Waiting_[] << NONE
			Lines_waiting[] << 0 .
				 

                 
        STR assign_verb = "ssign"   
        
		{Type} Classes_created_[]
        
        METHOD right_side_is_new_object(
            {Expr} Left|_side,
            {Expr} R|ight_side,
            INT Pos_r|ight_side)
            :
            CASE R.Type_expr !IN Classes_created_[] ?
                 Classes_created_[] << R.Type_expr ;
            CASE comp(Parse).In_init == 0 && Parse.Symbol(",") ?
                 compile_owner(R, Parse)
                 CASE R.Owned_ == NONE ?
                      CASE is_local_var_only(R.Array_) ?
                 	  	   CASE is_local_var_only(Left) ?
						   		BOOL is_local_only = TRUE ;
                      ;
                 ;                      
            ELSE 
                 CASE Left.Var_arg.Names[*].[*] == "_" ?
                      PUSH Parse.Pos = Pos_r :
                           CASE ?
                           [R.Type_expr.Kind == 'STRUCTURE'] ?
                            Parse.Err("Assigning a structure to a weak "
                            "reference variable"._EassignToWeak)
                            
                           [assign_verb == "ssign"] ?
                            Parse.Err("Assigning new object to a weak "
                            "reference field"._Eassign8 
                            " (" Left.Var_arg.Names[*] ") : " Parse.Next20)
                            
                           ELSE
                            Parse.Err("Appending new object to a weak "
                            "reference field"._Eappend2 
                            " (" Left.Var_arg.Names[*] ") : " Parse.Next20)
                           ;
                      ;
                 ;
                 CASE R.Type_expr.Kind != 'STRUCTURE' ?
                      CASE is_local_var_only(Left) ?
                           CASE R.Owned_ == NONE && (
		                        Left.Var_arg.Names[0] != "RESULT") && (
		                        !follow_owned_by(Parse))
		                        ?
	                      	    is_local_only = TRUE ;
                      ;
                 ;
            ;
            CASE is_local_only ?
                 CASE assign_verb == "ssign" ?
                     Parse.Err("New object is assigned only to a"
                     " local variable and such variable is not marked"
                     " as a 'temp' variable"._Enew2 ) 
                 ELSE
                     Parse.Err("New object is appended only to a"
                     " local variable and such variable is not marked"
                     " as a 'temp' variable"._Enew3 ) ;
            ; .

			
		FUN follow_owned_by( {Parser} Parse|_of_source ) ==> BOOL :
			PUSH Parse.Pos :
				 CASE Parse.Symbol(",") && Parse.Symbol("OWNED") && (
					  Parse.Symbol("BY"))
                      ?
                      RESULT = TRUE ;
			; .
			
		METHOD search_write( {Type} W|ritable_class ) ==> {Fun} :
			RESULT = W.Search_fun("Write", CASE_SEN, TRUE)
			CASE RESULT != NONE && RESULT.Param[].Count == 1 && (
				 RESULT.Param[0].Type_.Kind == 'STR') && !RESULT.Modifiers[
				 'STATIC']
                 ?
                 ==>
			;
			Parse.Err("Class"._Eclass " " W.Whole_name 
            " " ("has no method Write accepting single string "
            "parameter"._Ehasno3 ) ) .
        */
        int total_app = 0;

        static int CNT_compile_append;

        private void compile_append(Expression Left, List<Statement> Block, int At_pos)
        {
            if (++CNT_compile_append == 162)
            { }

            Has_add = true;
            for (int x = Parse.Pos; x <= Parse.Last(); x++)
            {
                if (!Parse.Symbol("<<")) break;
                Expression r = Expression.Recognize(Parse);
                if (r!=null && r.Is_array()) err("Can not append an array");
                if (r!=null && r.Operation == Expression.Operation_kind.NEW)
                {
                    Variable v = new Variable(comp(Parse));
                    v.Type_ = r.Type_expr();
                    v.Used = true;
                    v.Names.Add("_append" + (total_app++).ToString());
                    v.Line = Parse.Line;
                    Local_var.Add(v);
                    Assignment t = new Assignment();
                    t.Line = Parse.Line;
                    t.Dest = new Expression();
                    t.Dest.Operation = Expression.Operation_kind.VAR;
                    t.Dest.Var_arg = v;
                    t.Source = r;
                    Block.Add(t);
                    r = new Expression();
                    r.Operation = Expression.Operation_kind.VAR;
                    r.Var_arg = v;
                }
                Assignment a = new Assignment();
                a.Work = Statement.Workflow.APPEND;
                a.Dest = Left;
                a.Source = r;
                a.Line = Parse.Line;
                Block.Add(a);
                if (Left.Is_array())
                {
                    Assign_check_compat(Left, r, At_pos);
                    if (Left.Is_fixed())
                        err("Appending item to a fixed array");
                }
                else if (Left.Type_expr().Kind != Type.Kind_type.STR)
                    err("Destination for '<<' can be only STRING " +
                        "or dynamic array");
            }
        }

        /*
        
        METHOD Calls_fun|ction({Fun} F|unction_calling) :
			CASE F !IN Call_functions_[] ? Call_functions_[] << F ; .
        
        
        METHOD binary|_operation(
            {Expr} L|eft_operand,
            {Expr}.{bin} B|inary_op,
            {Expr} R|ight_operand) ==> {Expr}, NEW
            :
            --------------------------- 'Create binary operation {Expr} object'
            RESULT = {Expr}(Operation = 'BINARY', Sign = B, Arg1_ = L,
                Arg2_ = R, Type_obj_ = L.Type_expr)
                
            RESULT.Copy_location(L)
            BOOL arrays|_operation = L.Is_array
            	 arrays ||= R.Is_array
            CASE arrays ?
                 err("Arithmetic operations with arrays are not allowed"
                 ""._Earithmetic )
            ;
            --------- 'check operators if acceptable dependently on operation'
            {Type} type_L|eft_expr = L.Type_expr
            {Type} type_R|ight_expr = R.Type_expr
            {Type}.{kind_type} kL|eft_kind = type_L.Kind
            {kind_type} kR|right_kind = type_R.Kind
            CASE B ?
            ['UNDEFINED']: NONE
            ['PLUS', 'MINUS', 'MULT', 'DIV']:
				CASE kL IN ['CLASS', 'STRUCTURE'] || kR IN [
					 'CLASS', 'STRUCTURE']
					 ?
				     {Fun} operator = Search_operator(B, L, R)
				     CASE operator != NONE ?
				          operator.Count_ref += 1
				          operator.Usage_count += 1
				          comp(Parse).Current_fun.Calls_fun(operator)
				          RESULT.Operation = 'FUN'
				          RESULT.Fun_ = operator
				          RESULT.Items_[] << L << R
				          BOOL ok|_acceptable = TRUE ;
				          
				ELSE ok = kL IN ['INT', 'REAL'] && kR IN ['INT', 'REAL']
                	 
                     CASE RESULT.Type_obj_.Kind == 'INT' ?
                          RESULT.Type_obj_ = type_R ;
				;
            ['REST']: ok = kL == 'INT' && kR == 'INT'
            ['AND_B', 'OR_B', 'XOR_B']:
                ok = kL == 'INT' && kR == 'INT' 
                comp(Parse).Current_class.Detect('BITWISE')
            ['AND', 'OR']:
                ok = kL == 'BOOL' && kR == 'BOOL'
                RESULT.Type_obj_ = comp(Parse).TYPE_BOOL
            ['EQUAL', 'NOT_EQ']:
                ok = kL IN ['INT', 'REAL'] && kR IN ['INT', 'REAL']
                ok ||= type_L == type_R
                
                ok ||= kL == 'CLASS' && kR == 'CLASS' && (
                    type_L.Is_descend(type_R,
                    comp(Parse)) || (
                    type_R.Is_descend(type_L,
                    comp(Parse)) ) )
                    
                RESULT.Type_obj_ = comp(Parse).TYPE_BOOL
            ['LESS', 'LESS_OR_EQ', 'GREATER', 'GREATER_OR_EQ']:
                ok = kL IN ['INT', 'REAL'] && kR IN ['INT', 'REAL']
                ok ||= kL == kR && kL IN ['BOOL', 'STR'] 
                RESULT.Type_obj_ = comp(Parse).TYPE_BOOL
            ['IN', 'NOT_IN']:
                ok = kL == 'CLASS' && kR == 'CLASS' && (
                    type_L.Is_descend(type_R,
                    comp(Parse)) || (
                    type_R.Is_descend(type_L,
                    comp(Parse)) ) )
                ok ||= type_L == type_R
                ok &&= kL == kR && kL == 'STR' || R.Is_array
                ok &&= !L.Is_array
                RESULT.Type_obj_ = comp(Parse).TYPE_BOOL
            ['LIKE', 'UNLIKE']:
                ok = kL == kR && kL == 'STR' 
                ok &&= !R.Is_array 
                ok &&= !L.Is_array
                RESULT.Type_obj_ = comp(Parse).TYPE_BOOL
            ['CONCAT']: ok = kL == kR && kL == 'STR' ;
            CASE !ok ?
                err("Incompatible argument types for operation"._Eincompat
                " " B.Name) ; .
        */
        private Expression binary(Expression L, Expression.Bin B, Expression R)
        {
            Expression Result = new Expression();
            Result.Operation = Expression.Operation_kind.BINARY;
            Result.Sign = B;
            Result.Arg1_ = L;
            Result.Arg2_ = R;
            Result.Copy_location(L);
            bool ok = false;
            Type.Kind_type KL = L.Type_expr().Kind;
            Type.Kind_type KR = R.Type_expr().Kind;
            switch (B)
            {
                case Expression.Bin.PLUS:
                case Expression.Bin.MINUS:
                case Expression.Bin.MULT:
                case Expression.Bin.DIV:
                    ok = (KL == Type.Kind_type.INT || KL == Type.Kind_type.REAL) &&
                        (KR == Type.Kind_type.INT || KR == Type.Kind_type.REAL);
                    break;
                case Expression.Bin.REST:
                    ok = KL == Type.Kind_type.INT && KR == Type.Kind_type.INT;
                    break;
                case Expression.Bin.AND_B:
                case Expression.Bin.OR_B:
                case Expression.Bin.XOR_B:
                    ok = KL == Type.Kind_type.INT && KR == Type.Kind_type.INT;
                    comp(Parse).Current_class.Detect(Type.Class_mod.BITWISE);
                    break;
                case Expression.Bin.AND:
                case Expression.Bin.OR:
                    ok = KL == Type.Kind_type.BOOL && KR == Type.Kind_type.BOOL;
                    break;
                case Expression.Bin.EQUAL:
                case Expression.Bin.NOT_EQ:
                    ok = (KL == Type.Kind_type.INT || KL == Type.Kind_type.REAL) &&
                        (KR == Type.Kind_type.INT || KR == Type.Kind_type.REAL);
                    ok = ok || L.Type_expr() == R.Type_expr();
                    ok = ok || KL == Type.Kind_type.CLASS && KR == Type.Kind_type.CLASS &&
                        (L.Type_expr().Is_descendant_of(R.Type_expr(), comp(Parse)) ||
                        R.Type_expr().Is_descendant_of(L.Type_expr(), comp(Parse)));
                    break;
                case Expression.Bin.LESS:
                case Expression.Bin.LESS_OR_EQ:
                case Expression.Bin.GREATER:
                case Expression.Bin.GREATER_OR_EQ:
                    ok = (KL == Type.Kind_type.INT || KL == Type.Kind_type.REAL) &&
                        (KR == Type.Kind_type.INT || KR == Type.Kind_type.REAL) ||
                        KL == KR && (KL == Type.Kind_type.BOOL || KL == Type.Kind_type.STR);
                    break;
                case Expression.Bin.IN:
                case Expression.Bin.NOT_IN:
                    ok = KL == Type.Kind_type.CLASS && KR == Type.Kind_type.CLASS &&
                        (L.Type_expr().Is_descendant_of(R.Type_expr(), comp(Parse)) ||
                        R.Type_expr().Is_descendant_of(L.Type_expr(), comp(Parse)));
                    ok = ok || L.Type_expr() == R.Type_expr();
                    ok = ok && (KL == KR && KL == Type.Kind_type.STR || R.Is_array());
                    ok = ok && !L.Is_array();
                    break;
                case Expression.Bin.CONCAT:
                    ok = KL == Type.Kind_type.STR && KL == KR;
                    break;
                default: err("Internal error - forgot op: " + Expression.Bin_names[(int)B]);
                    break;
            }
            if (!ok)
                err("Incompatible argument types for operation " + Expression.Bin_names[(int)B]);
            return Result;
        }

        /*
        
        METHOD Assign_check_compat(
            {Expr} L|eft_operand, 
            {Expr} Right|_operand)
            :
			CASE Dummy_compile ? ==> ;
            -------------- 'Check left and right sides are compatible in assign'
            {Expr} r|ight_operand_actual = Right
            CASE r.Operation == 'FUN' && r.Fun_.Modifiers['TRAP_FUN'] ?
                 r = r.Original_variable_expr_ ;
            PUSH Parse.Pos = r.At_pos :
                 CASE ! Check_compat(L, r) ?
                      CASE L.Operation == 'VAR' && L.Var_arg == NONE ?
                           err("Destination is NONE and can not be "
                           "assigned this way"._AssignToNoneAgain)
                      ELSE
	                       err("Source and destination types are not "
	                       "compatible"._Esource2 
	                       ": " Parse.Next20 " (" ("left:"._Eleft2 ) 
	                       "" L.Type_expr.Kind.Name 
	                       "" L.Type_expr.complex_type_name
	                       ", right:"._Eright2 " " r.Type_expr.Kind.Name
						   "" r.Type_expr.complex_type_name ")")
                      ;
                      ==> ;
                 CASE L.Is_fixed && ! r.Is_fixed ?
                      warn("Waiting for fixed array operand"._Ewait4 
                      ": " Parse.Next20)
                 ;
                 CASE L.Is_array && ! r.Is_array ?
                      err("Waiting for an array operand"._Ewait5
                      ": " Parse.Next20)
                 ;
                 CASE ! L.Is_array && r.Is_array ?
                      err("Waiting for a scalar operand"._Ewait6 
                      ": " Parse.Next20)
                 ;
            ; .
			
		FUN complex_type_name( {Type} T|ype_which_name ) ==> STR :
			CASE T.Kind IN ['CLASS', 'STRUCTURE', 'ENUM'] ?
				 RESULT = " " T.Whole_name ; .

        METHOD Append_check_compat(
            {Expr} L|eft_operand, 
            {Expr} R|ight_operand,
            STR Op|eration_append)
            :
            -------------- 'Check left and right sides are compatible in assign'
            PUSH Parse.Pos = R.At_pos :
                 CASE ! Check_compat(L, R) ?
                      err("Source and destination types of the append "
                      "operation " Op " are not compatible"._Esource3 
                      ": " Parse.Next20) ==>
                 ;
                 CASE R.Is_array ?
                      err("Waiting for a scalar operand"._Ewait7 
                      ": " Parse.Next20) ;
            ; .
        */
        static int CNT_Assign_check_compat;

        public void Assign_check_compat(Expression L, Expression R, int At_pos)
        {
            if (++CNT_Assign_check_compat == 1093)
            { }

            bool ok = Check_compat(L, R);
            if (!ok)
            {
                int save = Parse.Pos;
                try
                {
                    Parse.Pos = At_pos;
                    string msg = "Source and destination types are not compatible" +
                            "(destination type: ";
                    try
                    {
                        msg += Type.Kind_type_names[(int)L.Type_expr().Kind] +
                            ", source type: ";
                        msg += Type.Kind_type_names[(int)R.Type_expr().Kind] + ")";
                    }
                    catch
                    { }
                    err(msg + ": " + Parse.Next20());
                }
                finally { Parse.Pos = save; }
            }
        }

        /*
        
        METHOD Check_compat(
            {Expr} L|eft_operand,
            {Expr} R|ight_operand) ==> BOOL
            :
            ----------------------------------- 'Check operands are compatible'
            {Type} type_L|eft_operand = L.Type_expr
            {Type} type_R|ight_operand = R.Type_expr
            BOOL mu|st_be_same_kind = L.Is_array
            mu &&= R.Is_array
            mu &&= type_L.Kind != 'CLASS'
            CASE mu ?
                 RESULT = type_L.Kind == type_R.Kind ==> ;
            CASE type_R.Kind ?
                 ['BOOL', 'STR', 'REAL']:
                     RESULT = type_L == type_R
                     RESULT ||= L.Var_arg == comp(Parse).NONE_c
                 ['INT']: RESULT = type_L.Kind IN ['INT', 'REAL']
                 ['ENUM', 'STRUCTURE']:
					 RESULT = type_L.Kind == type_R.Kind
					 RESULT &&= type_L.Names[0] == type_R.Names[0]
                	 RESULT &&= type_L.Names[1] == type_R.Names[1]
                	 RESULT &&= type_L.Base_ == type_R.Base_
                	 
                 ['CLASS']:
                     RESULT = type_R.Is_descendant_of(type_L,
                              comp(Parse))
                     RESULT ||= L.Var_arg == comp(Parse).NONE_c
                     RESULT ||= R.Var_arg == comp(Parse).NONE_c ; .

        METHOD Check_types_compat(
            {Type} L|eft_type,
            {Type} R|ight_type) ==> BOOL
            :
            ----------------------------------- 'Check operands are compatible'
            CASE R.Kind ?
                ['BOOL', 'STR', 'ENUM', 'REAL']:
                    RESULT = L == R
                ['INT']: RESULT = L.Kind IN ['INT', 'REAL']
                ['STRUCTURE']: RESULT = L == R
                ['CLASS']:
                    RESULT = R.Is_descendant_of(L, comp(Parse)) ; .

        METHOD Variables_compat|ible(
            {Var} L|eft_variable,
            {Var} R|ight_variable) ==> BOOL
            :
            ------------------------------ 'If two variables are compatible ?'
            exp1|_left_temp = {Expr}(Operation = 'VAR', Var_arg = L)
            exp2|_right_temp = {Expr}(Operation = 'VAR', Var_arg = R)
            RESULT = Check_compat(exp1, exp2) .
        */
        public bool Check_compat(Expression L, Expression R)
        {
            bool ok = false;
            Type L_Type = L == null ? null : L.Type_expr();
            Type R_Type = R == null ? null : R.Type_expr();
            Type.Kind_type k = R_Type != null ? R_Type.Kind : Type.Kind_type.BOOL;
            switch (k)
            {
                case Type.Kind_type.BOOL:
                case Type.Kind_type.STR:
                case Type.Kind_type.ENUM:
                case Type.Kind_type.REAL:
                    ok = L != null && L_Type == R_Type || L.Var_arg == comp(Parse).NONE_c;
                    break;
                case Type.Kind_type.INT:
                    ok = L_Type.Kind == Type.Kind_type.REAL || L_Type == R_Type;
                    break;
                case Type.Kind_type.CLASS:
                    ok = L != null && L_Type != null && R_Type.Is_descendant_of(L_Type, comp(Parse));
                    ok = ok || L.Var_arg == comp(Parse).NONE_c;
                    ok = ok || R.Var_arg == comp(Parse).NONE_c;
                    break;
            }
            return ok;
        }

        /*
        
        BOOL Compiling_output
        
        METHOD compile_output(
        {Statement} Block|_of_stmts[], BOOL Skip_f|irst_operation)
        	:
			BOOL skip|_1st_operation = Skip_f
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                CASE skip || Parse.Symbol("<<") ?
                     skip = FALSE
                     PUSH Compiling_output = TRUE : 
	                      o|utput_stmt_temp = {Assign}(Work = 'OUTPUT',
	                    	  Line = Parse.Line, Pos= ident_pos,
	                          Function_ = THIS,
	                          Level = Current_level)
	                          
	                      o.Source = {Expression}.Recognize_typed(Parse, 'STR')
	                      extract_new_operations(o.Source, Block[], 0)
	                      Block[] << o
	                      
	                      CASE o.Source.Type_expr.Kind != 'STR' ?
	                           Parse.Err("Source of output is not a string"
	                           ""._EOutputNotStr) ;
                     ;
                     CONTINUE x ;
                DONE
	                 CASE Parse.Next_symbol(">>") ?
	                      compile_input(Block[]) ==> ;
	                 INT p|osition_current = Parse.Pos
	                 CASE Parse.Symbol("==>") ?
	                      compile_return(Block[], p) ==> ;
	                 BREAK x ; .
        */
        private void compile_output(List<Statement> Block)
        {
            for (int x = Parse.Pos; x <= Parse.Last(); x++)
            {
                if (Parse.Symbol("<<"))
                {
                    Assignment o = new Assignment();
                    o.Work = Statement.Workflow.OUTPUT;
                    o.Line = Parse.Line;
                    Block.Add(o);
                    o.Source = Expression.Recognize_typed(Parse, Type.Kind_type.STR);
                    continue;
                }
                if (Parse.Next_symbol(">>"))
                {
                    compile_input(Block);
                    return;
                }
                if (Parse.Symbol("==>"))
                {
                    compile_return(Block);
                    return;
                }
                break;
            }
        }

        /*
        
        METHOD compile_input({Statement} Block|_stmts[]) :
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                INT was_p|osition = Parse.Pos
                CASE Parse.Symbol(">>") ?
                    INT pos|ition = Parse.Pos
                    
                    i|nput_stmt = {Assignment}(Work = 'INPUT',
                         Function_ = THIS, Line = Parse.Line, Pos= was_p,
                         Level = Current_level), >> Block[]
                         
                    CASE Parse.End_of_expr ? CONTINUE x ;
                    CASE Parse.Symbol("STRING") || Parse.Symbol("STR") ?
                         i.Dest = new_var(comp(Parse).TYPE_STR)
                         array_can_not_be_input(i.Dest)
                    ELSE i.Dest = Recognize_typed(Parse, 'STR') ;
                    CASE i.Dest.Operation !IN ['VAR', 'INDEX', 'FIELD']
                    	 || i.Dest.Is_array
                    	 ?
                         PUSH Parse.Pos = pos : 
                             Parse.Err("Destination for '>>' is not "
                             "a scalar variable"._EdestNotVar ": " Parse.Next20)
                         ;
                    ;
                    CONTINUE x ;
                DONE
                	was_p = Parse.Pos
	                CASE Parse.Symbol("==>") ?
	                    compile_return(Block[], was_p) ==> ;
	                BREAK x ; .
                
        METHOD array_can_not_be_input({Expr} Dest|ination) :
            CASE Dest.Is_array ?
                 Parse.Err("Array can not be used in an input "
                 "statement"._Earr3 ) ; .
        */
        private void compile_input(List<Statement> Block)
        {
            for (int x = Parse.Pos; x <= Parse.Last(); x++)
            {
                if (Parse.Symbol(">>"))
                {
                    int pos = Parse.Pos;
                    Assignment i = new Assignment();
                    i.Work = Statement.Workflow.INPUT;
                    i.Line = Parse.Line;
                    Block.Add(i);
                    if (!Parse.End_of_expr())
                        i.Dest = Expression.Recognize_typed(Parse, Type.Kind_type.STR);
                    if (i.Dest != null)
                    {
                        switch (i.Dest.Operation)
                        {
                            case Expression.Operation_kind.FIELD:
                            case Expression.Operation_kind.VAR:
                            case Expression.Operation_kind.INDEX: break;
                            default: int save = Parse.Pos;
                                try
                                {
                                    Parse.Err("Destination for '>>' is not a variable: " + Parse.Next20());
                                }
                                finally { Parse.Pos = save; }
                                break;
                        }
                    }
                    continue;
                }
                if (Parse.Symbol("==>"))
                {
                    compile_return(Block);
                    return;
                }
                break;
            }
        }

        /*
        
        METHOD compile_stop({Statement} Block|_of_stmts[]) :
            Has_stop = TRUE
            
            stop|_statement = {Case}(Work = 'STOP', 
            	Line = Parse.Line, Pos= ident_pos,
                Function_ = THIS, Level = Current_level), >> Block[]
                
            STR mess|age_on_stop = Scan_string_const(17)
            
            stop.Condition = {Expr}(
            		Operation = {operation}.'CONST',
                	Var_arg = {Var}(
                			Type_ = comp(Parse).TYPE_STR,
                			Is_const = TRUE, 
                			Str_c = mess,
                			Line = -1
                			)
                	)
                	
            comp(Parse).Current_class.Detect('STOPPING') .
            
            
        METHOD Scan_string_const|ants_concatenation(
        	INT Where|_pass_through) ==> STR
        	: RESULT = comp(Parse).Current_class.Scan_string_const(Where) .
            
        */
        private void compile_stop(List<Statement> Block)
        {
            Case s = new Case();
            s.Work = Statement.Workflow.STOP;
            s.Line = Parse.Line;
            Block.Add(s);
            string mess = Parse.String_const(false);
            s.Condition = new Expression();
            s.Condition.Operation = Expression.Operation_kind.CONST;
            s.Condition.Var_arg = new Variable(comp(Parse));
            s.Condition.Var_arg.Type_ = comp(Parse).TYPE_STR;
            s.Condition.Var_arg.Str_c = mess;
            comp(Parse).Current_class.Detect(Type.Class_mod.STOPPING);
        }

        /*
        INT assertions|_found

        METHOD compile_assert({Statement} Block|_of_stmt[]) :
            assertions += 1
            CASE !comp(Parse).Generating_test ?
                 Parse.Err("ASSERT is allowed only in TEST blocks"._Eassert) ;
            FOR n IN Nesting[] :
                CASE n.{For} != NONE ?
                     Parse.Err("ASSERT is not allowed in FOR loops"._Eassert2)
                ;
            ;
            INT from|_statement = Block[].Count
            
            {Expr} cond|ition_temp = Recognize_typed(Parse, 'BOOL')
            extract_new_operations(cond, Block[], 0)
            
            a|ssert_stmt_temp = {Case}(Work = 'ASSERT', 
            	Line = Parse.Line, Pos= 0,
                Function_ = THIS, Level = Current_level, Condition = cond)
                
            CASE Parse.Symbol(",") ?
                 a.Formatted = Recognize_typed(Parse, 'STR')
                 extract_new_operations(a.Formatted, Block[], 0)
            ;
            ---------------- 'all the extracted statements have the same Line'
            ---------------- 'this is important for ASSERT'
            FOR st IN [from TO Block[].Count-1] :
                Block[st].Line = Parse.Line ;
            Block[] << a
            .
        */
        private int assertions = 0;

        private void compile_assert(List<Statement> Block)
        {
            assertions++;
            if (!comp(Parse).Generating_test())
                Parse.Err("ASSERT is allowed only in TEST blocks");
            Case a = new Case();
            a.Work = Statement.Workflow.ASSERT;
            a.Line = Parse.Line;
            Block.Add(a);
            a.Condition = Expression.Recognize_typed(Parse, Type.Kind_type.BOOL);
            if (Parse.Symbol(","))
                Expression.Recognize_typed(Parse, Type.Kind_type.STR);
        }
        
        /*
        BOOL checked_recursive

METHOD Check_recursive ==> BOOL :
    ----------------------------- 'Check only once'
    CASE checked_recursive ?
         RESULT = Modifiers['RECURSIVE_FUN'] ==> ;
    checked_recursive = TRUE
    PUSH comp(Parse).Checking_recursive_fun = TRUE :
         CASE Overloaded_[].Count > 0 ? ==> ;
         ----------------------------- 'On first call, check if calls itself'
         CASE THIS IN Call_functions_[] ? BOOL call_itself = TRUE ;
         Parse.Line = Line_start
         CASE !call_itself ?
              FOR x|dummy IN [0 TO MAX_INT-1] :
                  INT added|_functions_count = 0
                  FOR cf IN Call_functions_[] :
                      added += add_calling(cf)  ;
                  CASE added == 0 ? BREAK x ;
              ;
         ;
         Recursive = THIS IN Call_functions_[]
         ---------------- 'If recursive via another recursive function?'
         CASE Recursive && !call_itself ?
              FOR cf IN Call_functions_[] :
                  CASE cf.Modifiers['RECURSIVE_FUN'] ?
                       BOOL other|_recursive_function_called = TRUE
                       BREAK cf ;
              ;
         ;
         CASE Recursive ?
              CASE Modifiers['RECURSIVE_FUN'] || other ?
                   RESULT = TRUE ==> ;
              ----------------------------------- 'set function be recursive'
              Modifiers['RECURSIVE_FUN'] = TRUE
              ------------------------ 'cases when recursion is impossible'
              CASE Is_test ?
                   Parse.Err("Test function"._Etest " " Whole_name 
                   " " ("is recursive. It is not allowed to create recursive"
                   " test functions"._Eis9 ) )
              ;
              CASE !other && comp(Parse).Verbose ?
                   FOR cf IN Call_functions_[] :
                       STR all|_recursive_functions = all cf.Class.Names[0]
                       "." cf.Whole_name
                       " <-- " Call_from[cf.Index] #NL
                   ;
                   Parse.Err("Function"._Efun6 " " Names[*] 
                   " " ("is recursive "
                   "but it is not marked with the symbol RECURSIVE"._Eis10 )
                   ": " all.[0 TO *-2])
              ;
              CASE !other ?
                   Parse.Err("Function"._Efun7 " " Names[*] 
                   " " ("is recursive"._Eis11 ) " " ("but it is not marked "
                   "with the symbol RECURSIVE"._Ebut3 ) ) ;
              ---------------------------- 'entire class should be RECURSIVE'
              comp(Parse).Current_class.Detect({class_mod}.'RECURSIVE')
              RESULT = TRUE ==> ;
         CASE Modifiers['RECURSIVE_FUN'] ?
              Parse.Warn("Function"._Wfun2 " " Names[*] 
              " " ("is marked as RECURSIVE but this is not correct"._Wis3 ))
         ; 
    ; .

        METHOD Calling_any_recursive_fun|ction ==> BOOL :
            NONE = Check_recursive
            FOR m IN Call_functions_[] :
                CASE m.Recursive ? RESULT = TRUE ==> ;
            ; .
            
        METHOD Overrides_any_calling_recursive_fun|ction ==> BOOL :
            {Fun} fb|ase_function = Ancestor_
            FOR i|dummy IN [1 TO 1000] :
                CASE fb == NONE ? ==> ;
                CASE fb.Calling_any_recursive_fun ? RESULT = TRUE ==> ;
                fb = fb.Ancestor_ ; .
            

        METHOD Calling_any_having_stop|_function ==> BOOL :
            NONE = Check_recursive
            FOR m IN Call_functions_[] :
                CASE m.Has_stop ? RESULT = TRUE ==> ;
            ; .
        */
        public bool Check_recursive()
        {
            Parse.Line = Line_start;
            bool other = false;
            while (true)
            {
                if (Call_.Contains(this))
                {
                    comp(Parse).Current_class.Detect(Type.Class_mod.RECURSIVE);
                    if (Modifiers[(int)Fun_mod.RECURSIVE] || other) return true; ;
                    if (!other)
                        Parse.Err("Function " + Names[Names.Count - 1] + " is recursive " +
                            "but it is not marked with the symbol RECURSIVE");
                    Modifiers[(int)Fun_mod.RECURSIVE] = true;
                    return true; 
                }
                foreach (Function cf in Call_)
                {
                    if (cf != null && cf.Modifiers[(int)Fun_mod.RECURSIVE])
                    {
                        other = true;
                        break;
                    }
                }
                int added = 0;
                for (int icf = 0; icf < Call_.Count; icf++)
                {
                    Function cf = Call_[icf];
                    added += add_calling(cf);
                }
                if (added == 0) break;
            }
            if (Modifiers[(int)Fun_mod.RECURSIVE])
                Parse.Warn("Function " + Names[Names.Count - 1] + " is marked as " +
                    "RECURSIVE but this is not correct");
            return false;
        }

        /*
        
        METHOD add_calling({Function} F|rom_called) ==> INT :
            FOR f IN F.Call_functions_[] :
                CASE f !IN Call_functions_[] ?
                    RESULT += 1
                    Call_functions_[] << f
                    STR c_from|_call = F.Class.Whole_name "." F.Names[0]
                    Call_from[] << c_from 
                    CASE !F.Is_test ?
                         //DEBUG:
                         //       CASE f.Total_fn == 12065 ?
                         //            << "+++++++++++++++++++++++++++++"
                         //            "  Usage_count++ for " f.Names[].Whole_name
                         //            " because: add calling from "
                         //            "" F.Class.Names[0] 
                         //            "." F.Names[].Whole_name #NL
                         //       ;
                         //;
                         {Compiler} comp2|iler_working = Parse.Compiler
                         CASE !comp2.Checking_recursive_fun ? 
	                          PUSH comp2.Current_class = F.Parse.Class_ :
	                          PUSH comp2.Current_fun = F :
	                          PUSH F.Parse.Line = F.Line_start :
	                          PUSH F.Parse.Pos = 0 :
		                           f.Warn_about_deprecated
	                          ;
	                          ;
	                          ;
	                          ;
                         ;
                    	 f.Usage_count += 1 
                    ;
                ;
            ; .
        */
        private int add_calling(Function F)
        {
            int Result = 0;
            if (F == null) return 0;
            foreach (Function f in F.Call_)
            {
                if (!Call_.Contains(f))
                {
                    Result++;
                    Call_.Add(f);
                }
            }
            return Result;
        }
        
        /*
        {Fun} functions_passed_to_[]
        
        
        METHOD Check_weak_arrays_passing|_as_parameters :
            FOR w IN Weak_arrays_passing[] :
                functions_passed_to_[].Clear
                CASE can_be_used_to_add_objects(
                     Passing_to_function_[w.Index], 
                     Passing_as_param[w.Index])
                     ?
                     PUSH comp(Parse).Current_class = Class :
                     PUSH Parse.Line = Passing_arrays[w.Index] :
                          Parse.Err("Passing weak array"._Epass 
                          " " w.Whole_name 
                          " " ("as a parameter to a function where it can be "
                          "used to add new objects (or to pass to other such "
                          "functions)"._Easa ) ) ;
                     ;
                ;
            ; .
            
            
        METHOD can_be_used_to_add_objects(
        {Fun} F|unction_pass_to, 
        INT P|arameter_index INDEXING {Var}) ==> BOOL, RECURSIVE
            :
            --------------------------------------------- 'prevent second calls'
            CASE F IN functions_passed_to_[] ? ==> ;
            functions_passed_to_[] << F
            --------------------------------------------- 'used?'
            CASE F.Param[P].Used_to_add_to ? RESULT = TRUE ==> ;
            --------------------------------- 'passed to functions, where used?'
            FOR f IN F.Param[P].Passed_to_other_[] :
                RESULT = can_be_used_to_add_objects(f, 
                    F.Param[P].Passed_as_param[f.Index])
                CASE RESULT ? ==> ;
            ; .
            
            
            
        //------------------------------- do basic function-level optimizations:
        //   C0 - remove case header for no branches
        // b C1 - CASE const ? ---------------> to single branch
        
        // e F0 - FOR x ... : ; --------------> remove loop not having body
        // c F1 - FOR x IN [y TO y] ----------> leave body only
        // d F2 - FOR x IN [] ----------------> remove entire loop never executed
        
        //   P0 - remove PUSH blocks having no body
        // f R0 - ==> ; ... ------------------> remove unreachable code
        
        // g V0 - unused var declared --------> remove
        
        // h E0 - call a nothing doing fun ---> remove
        // i E1 - call a fun returning const -> that const
        // k E1 - function returning expr ----> that expr
        // l E2 - final method returning expr > that expr
        
        // j V2 - two assignments to same var > leave only the last

        //   I0 - inline native function calls
        // m I1 - replace call to functions having <= 3 statements or rarely called
        // n I2 - replace call to final method (of same class)
            
        //----------------------------------------------------------------------
        
        METHOD should_optimize(
        	STR Flag|_optimize ) ==> BOOL
        	:
            RESULT = comp(Parse).Should_optimize(Flag) .


		
        METHOD Optimize_now(
        	{Statement} B|lock_of_statements[],
        	INT Level_op|timization_0_on_top_level ), RECURSIVE
        	:
            ------------------- 'optimize what is possible from a list of flags'
			{Compiler} c|ompiler_reference = comp(Parse)
        PUSH c.Current_class = Class:
            FOR i IN [B[].Count-1 DOWNTO 0] :
                {Statement} st|atement_in_block = B[i]
                ---------------------------- 'recursive call for nested blocks'
                CASE st.Block_[].Count > 0 ?
                     Optimize_now(st.Block_[], Level_op + 1) ;
                CASE st.{Case}.Top_case ? CONTINUE i ;
                -------------------- 'find following statement (to merge them)'
                {Statement} fo|llowing_statement = B[i+1]
                FOR j IN [i+2 TO B[].Count-1] :
                    CASE fo.Work != 'COMMENT' ? BREAK j ;
                    fo = B[j] ;
                --------------------------------------------- 'case of constant'
                CASE should_optimize("C1") && st.Work == 'CASE' && (
                	 st.{Case}.Top_case) && (
					 c.Count_C1 < c.Maximum_op("C1")) && ( 
                     st.{Case}.Condition.Operation == 'CONST') && (
					 st.{Case}.Condition.Localize_n == "")
                     ?
                     ------------- 'single branch in CASE of constant condition'
                     log_op(st, "C1[" c.Count_C1.Str "]")
                     c.Count_C1 += 1
                     //CASE comp(Parse).C1_optimizations < 3 ?
                     
                          //Console_color('CYAN')
                          //<< " C1: " comp(Parse).C1_optimizations.Str #NL
                          //Console_color('SILVER')
                     
                          Optimizations_G = FALSE
                          c.Optimizations_count += 1
                          case_to_single_branch(B[], i) 
                          CONTINUE i
                     //;
                ;
                --------------------------------------------- 'sequential case'
                CASE should_optimize("C1") && st.Work == 'CASE' && (
                     st.{Case}.Top_case && st.{Case}.Condition == NONE) && (
					 c.Count_C1 < c.Maximum_op("C1"))
                     ?
                     optimize_sequential_case(st.{Case}, B[], i) ;
                --------------------------------------------- 'empty case'
                CASE should_optimize("C0") && st.Work == 'CASE' && (
                	 st.{Case}.Top_case) && (
					 c.Count_C0 < c.Maximum_op("C0"))
                     ? 
                     ------------- 'CASE with no branches'
                     CASE all_branches_empty(st.{Case}) && (
                          is_simple_expr(st.{Case}.Condition))
                          ?
                          log_op(st, "C0")
                          Optimizations_G = FALSE
						  c.Count_C0 += 1
                          c.Optimizations_count += 1
                          
                          replace_statement(B[], i,
                              st.{Case}.Block_[0].{Case}.Block_[])
                     ;
                ;
                --------------------------------------------- 'empty push'
                CASE should_optimize("P0") && st.Work == 'PUSH' && (
					 c.Count_P0 < c.Maximum_op("P0"))
                     ? 
                     ------------- 'PUSH with no body'
                     CASE !has_statements(st.Block_[]) ?
                          log_op(st, "P0")
                          Optimizations_G = FALSE
						  c.Count_P0 += 1
                          c.Optimizations_count += 1
                          B[].Delete(i) ;
                ;
                CASE should_optimize("F0") && st.Work == 'FOR' && (
					 c.Count_F0 < c.Maximum_op("F0"))
                     ?
                     ----------- 'remove entire loop not having a body'
                     CASE for_remove_loop_not_having_body(B[], i) ?
                          log_op(st, "F0")
                          Optimizations_G = FALSE
						  c.Count_F0 += 1
                          c.Optimizations_count += 1
                          CONTINUE i ;
                ;
                CASE should_optimize("F2") && st.Work == 'FOR' && (
					 c.Count_F2 < c.Maximum_op("F2"))
                     ?
                     ----------- 'remove entire loop which is not executed'
                     CASE for_remove_loop_not_executing(B[], i) ?
                          log_op(st, "F2")
                          Optimizations_G = FALSE
						  c.Count_F2 += 1
                          c.Optimizations_count += 1
                          CONTINUE i ;
                ;
                CASE should_optimize("F1") && st.Work == 'FOR' && (
					 c.Count_F1 < c.Maximum_op("F1"))
                     ?
                     ----------- 'remove header of FOR loop which executes once'
                     CASE for_remove_header_for_once_executing(B[], i) ?
                          log_op(st, "F1")
                          Optimizations_G = FALSE
						  c.Count_F1 += 1
                          c.Optimizations_count += 1
                          CONTINUE i ;
                ;
                CASE should_optimize("R0") && i < B[].Count-1 && st.Is_jump && (
					 c.Count_R0 < c.Maximum_op("R0"))
                     ?
                     ----------- 'remove unreachable code'
                     log_op(st, "R0 at " i.Str)
					 c.Count_R0 += 1
                     c.Optimizations_count += 1
                     Optimizations_G = FALSE
                     FOR j IN [B[].Count-1 DOWNTO i+1] :
                         B[].Delete(j) ;
                     CASE Level_op == 0 && B[i].Work == 'RETURN' ?
                          B[].Delete(i) ;
                     //TODO: remove unreachable from inner blocks
                ;
                --------------------------------------------------- 'h'
                CASE should_optimize("E0") && st.Work == 'ASSIGN' && (
					 c.Count_E0 < c.Maximum_op("E0"))
                     ?
                     {Assign} a|ssign_stmt = st.{Assign}
                     CASE a.Dest == NONE && a.Source.Operation == 'FUN' && (
                          !has_statements(a.Source.Fun_.Block[])) && (
                          !a.Source.Fun_.Modifiers['NATIVE_FUN']) && (
                          !a.Source.Fun_.Is_system) && (
                          a.Source.Fun_.Modifiers['STATIC']) && (
                          a.Block_[].Count == 0) && (
                          a.Back_ == NONE)
                          ?
                          ---------------------- 'remove call to empty function'
                          log_op(st, "E0")
                          Optimizations_G = FALSE
						  c.Count_E0 += 1
                          c.Optimizations_count += 1
                          
                          comm|ent_stmt = {Assign}(Work = 'COMMENT',
                            Function_ = THIS, Line = a.Line, Pos= 0,
                            Level = Current_level,
                            Source = {Expr}(
                              Operation = {operation}.'CONST',
                              Var_arg = {Var}(Line = 0, Is_const= TRUE,
                              Type_= Compiler.TYPE_STR))),
                              >> Keep_statements[]
                              
                          comm.Source.Var_arg.Str_c = 
                            	"Removed call to function "
                              	"" a.Source.Fun_.Whole_name
                          ---------------------- 'replace onto comment'
                          B[i] = comm
                          CONTINUE i ;
                ;
                ----------------------------------------------------- 'j'
                CASE should_optimize("V2") && st.{Assign}.Dest != NONE && (
                     st.Work == 'ASSIGN') && fo.Work == 'ASSIGN' && (
                     st.{Assign}.Dest.Operation == 'VAR') && (
                     fo.{Assign}.Dest.Operation == 'VAR') && (
                     st.{Assign}.Dest.Var_arg == (
                     fo.{Assign}.Dest.Var_arg)) && (
                     fo.{Assign}.Source != NONE) && (
					 c.Count_V2 < c.Maximum_op("V2")) && (
                     is_simple_expr(st.{Assign}.Source))
                     ?
                     CASE !variable_used_in_st(
                     		fo, st.{Assign}.Dest.Var_arg)
                     	  ?
	                      log_op(st, "V2: " (
	                        st.{Assign}.Dest.Var_arg.Whole_name )
	                      )
                     	  ----------------- 'remove ambiguous assignment'
	                      Optimizations_G = FALSE
						  c.Count_V2 += 1
	                      c.Optimizations_count += 1
	                      B[].Delete(i)
	                      CONTINUE i ;
                ;
                CASE should_optimize("V3") && st.{Assign}.Dest == NONE && (
                     i < B[].Count-1) && fo.{Assign}.Dest == NONE && (
                     st.{Assign}.Source.Operation == 'FUN') && (
                     fo.{Assign}.Source.Operation == 'FUN') && (
					 c.Count_V3 < c.Maximum_op("V3"))
                     ?
                     {Expr} ei|_st_Source = st.{Assign}.Source
                     {Expr} nx|_Bi_1_Source = fo.{Assign}.Source
                     CASE ei.Fun_ == comp(Parse).SYSFUN_Clear && (
                          nx.Fun_ == ei.Fun_) && (
                          same_array_operand(ei.Items_[0], nx.Items_[0]))
                          ?
                          ----------------------- 'remove ambiguous Clear'
                          log_op(st, "V3" )
                          Optimizations_G = FALSE
						  c.Count_V3 += 1
                          c.Optimizations_count += 1
                          B[].Delete(i)
                          CONTINUE i ;
                ;
                CASE should_optimize("V4") && st.{Assign}.Dest != NONE && (
                     st.Work == 'ASSIGN') && fo.Work == 'ASSIGN' && (
					 c.Count_V4 < c.Maximum_op("V4"))
                     ?
                     {Assign} sta|ssign = st.{Assign}
                     {Assign} foa|ssign = fo.{Assign}
                     CASE sta.Dest.Operation == 'VAR' && (
                          foa.Dest.Operation == 'VAR') && (
                          sta.Dest.Var_arg == foa.Dest.Var_arg) && (
                          foa.Source.Operation == 'BINARY') && (
                          foa.Source.Arg1_.Operation == 'VAR') && (
                          foa.Source.Arg1_.Var_arg == a.Dest.Var_arg) && (
                          !variable_used_in_expr(foa.Source.Arg2_, 
                          foa.Dest.Var_arg) ) && (
                          !functions_called_in_expr(foa.Source))
                          ?
                          ----------------------------- 'unite assignments'
                          log_op(st, "V4: " sta.Dest.Var_arg.Whole_name)
                          Optimizations_G = FALSE
						  c.Count_V4 += 1
                          c.Optimizations_count += 1
						  ----------------------------- 'do it now'
                          foa.Source.Arg1_ = sta.Source
                          All_expr[] << sta.Source
                          B[].Delete(i)
                          CONTINUE i ;
                ;
                --------------------------------------- 'inlining of procedures'
                BOOL is_inline_fun|ction_call
                
                is_inline_fun = st.{Assign}.Source.Operation == 'FUN' && (
                	 st.{Assign}.Source.Fun_.Modifiers['INLINE']) && (
                	 st.{Assign}.Source.Fun_.Modifiers['STATIC'])
                	 
                CASE (is_inline_fun || should_optimize("I1") && (
                     st.Work == 'ASSIGN') && (
                     st.{Assign}.Source.Operation == 'FUN') && (
                     !before_assigns_in_params(
                     st.{Assign}.Source))) && (
					 c.Count_I1 < c.Maximum_op("I1"))
                     ?
                     {Fun} sfun|ction_called = st.{Assign}.Source.Fun_
                     CASE !sfun.Modifiers['INLINE'] && (
                     	  comp(Parse).Not_auto_inline) 
                     	  ?
                          CONTINUE i ;
                     BOOL ok|_sfun_inline = sfun.Modifiers['STATIC']
                     CASE ok ? BOOL static_fun|ction = TRUE
                     ELSE static_fun = FALSE ;
                     ----------------------------------- 'more conditions...' 
                     ok &&= st.Inline_index == ""
                     ok &&= !sfun.Is_system
                     ok &&= !sfun.Modifiers['NATIVE_FUN']
                     ok &&= !sfun.Modifiers['NEW']
                     
                     ok &&= !sfun.Modifiers['RECURSIVE_FUN'] && (
                            sfun !IN sfun.Call_functions_[])
                            
                     ok &&= !sfun.Uses_arrays
                     ------------------- 'conditions from a size of a function'
                     INT scount|_statements = statements_count(sfun.Block[])
                     
                     ok &&= scount <= 3 || scount * sfun.Usage_count <= 100 || (
                            sfun.Usage_count <= 3)
                            
                     ok &&= ! sfun.Has_return && ! sfun.Has_break_cont
                     ok &&= sfun.Overload_base_==NONE
                     CASE ok && !all_called_functions_in_import(sfun.Block[]) ?
                          ok = FALSE ;
                     
                     comp(Parse).I1_optimizations += 1
                     PUSH fun_inlining_ = sfun :
	                      CASE ok && (
	                           replace_call_fun_with_its_body2(B[], i))
	                           ?
	                           ----------- 'replace call to fun with its body'
	                           Inlined_calls += 1
	                           
	                           log_op(st, "I1: " sfun.Class.Names[0] 
	                          	 "." sfun.Whole_name)
	                           
	                           Optimizations_G = FALSE
							   c.Count_I1 += 1
	                           c.Optimizations_count += 1
	                           CONTINUE i ;
                     ;
                     CASE static_fun && sfun.Error_if_not_inlined ?
                          Parse.Err("Function can not be inlined though it is "
                          "marked as necessary to be inlined"._ECanNotInline
                          ": " sfun.Class.Whole_name 
                          "." sfun.Names[0]) ;
                ;
                is_inline_fun = st.{Assign}.Source.Operation == 'FUN' && (
                	 st.{Assign}.Source.Fun_.Modifiers['INLINE']) && (
                	 !st.{Assign}.Source.Fun_.Modifiers['STATIC'])
                	 
                CASE (is_inline_fun || should_optimize("I2") && (
                     st.Work == 'ASSIGN') && (
                     st.{Assign}.Source.Operation == 'FUN')) && (
					 !st.{Assign}.Source.Fun_.has_assignments_to_fields) && (
					 c.Count_I2 < c.Maximum_op("I2"))
                     ?
                     sfun = st.{Assign}.Source.Fun_
                     CASE !sfun.Modifiers['INLINE'] && (
                     	  comp(Parse).Not_auto_inline)
                     	  ?
                          CONTINUE i ;
                     ----------------------------- 'calculate conditions for I2'
                     ok = TRUE
                     CASE !is_inline_fun ?
                     	  ok = !sfun.Modifiers['STATIC']
                     	  ok &&= st.Inline_index == ""
                     	  ok &&= !Modifiers['STATIC'] ;
                     	  
                     ok &&= !sfun.Modifiers['RECURSIVE_FUN'] && (
                            sfun !IN sfun.Call_functions_[])
                            
                     ok &&= sfun.Class == Class
                     sta = st.{Assign}
                     
                     ----------------------------- 'additional conditions'
                     ok &&= sta.Source.This_.Operation == 'VAR'
                     
                     ok &&= sta.Source.This_.Var_arg == (
                     		comp(Parse).THIS_var)
                     		
                     ok &&= !sfun.Is_system
                     ok &&= !sfun.Modifiers['NATIVE_FUN']
                     ok &&= !sfun.Modifiers['NEW']
                     ok &&= sfun != sfun.Class.Construct
                     ok &&= sfun != sfun.Class.Destruct
 					                    
                     CASE !ok && is_inline_fun ? is_inline_fun = FALSE ;
                     ----------------------------- 'and these are not all yet'
                     //ok &&= !sfun.Class.Has_descendant
                     ok &&= !sfun.Overridden
                     CASE sfun.Overridden && is_inline_fun ?
                          Parse.Warn("The function is overridden somewhere so "
                          "it can not be inlined"._Woverridden 
                          ": " sfun.Whole_name)
                          
                          is_inline_fun = FALSE
                          sfun.Modifiers['INLINE'] = FALSE ;
                     ok &&= !sfun.Calls_base
                     CASE sfun.Calls_base && is_inline_fun ?
                          Parse.Warn("The function is calling BASE method so "
                          "it can not be inlined"._Wbase
                          ": " sfun.Whole_name)
                          
                          is_inline_fun = FALSE
                          sfun.Modifiers['INLINE'] = FALSE
                     ;
                     ok &&= ! sfun.Has_return && ! sfun.Has_break_cont
                     CASE !ok && is_inline_fun ?
                          Parse.Warn("The function has ==>, BREAK or CONTINUE "
                          "statements so it can not be inlined"._Wret
                          ": " sfun.Whole_name)
                          
                          is_inline_fun = FALSE
                          sfun.Modifiers['INLINE'] = FALSE ;

                     CASE ok && !is_inline_fun ?
	                      scount = statements_count(sfun.Block[])
	                      
	                      ok &&= (scount <= 4 || (
	                      		 scount * sfun.Usage_count <= 100) || (
	                             sfun.Usage_count <= 1))
                     ;
                     CASE !ok && sfun.Error_if_not_inlined ?
                          Parse.Err("Function can not be inlined though it is "
                          "marked as necessary to be inlined"._ECanNotInline2
                          ": " sfun.Class.Whole_name 
                          "." sfun.Names[0])
                     ;
                     CASE !ok ? CONTINUE i ;

                     PUSH inline_fun_ :
                     PUSH comp(Parse).Current_class = Class :
                     PUSH comp(Parse).Current_fun = THIS :
                     PUSH Parse.Line = B[i].Line :
                          CASE is_inline_fun ?
                               inline_fun_ = sfun ;
                          //DEBUG:
                          //      CASE c.Count_I2 == (
                          //      	 c.Maximum_op("I2") - 1)
                          //      	 ?
                          //        CASE "$I2" IN c.Defined_name[] ?
                          //        	INT i2_max|imum_count
                          //        	i2_max = c.Defined_value[
                          //         	   c.Defined_name[].Find(
                          //         	   "$I2")].snum
                          //        	<< "i2 max = " i2_max.Str #NL
                          //          //CASE I2_attempt++ > i2_max ?
                          //          //     CONTINUE i ;
                          //        ;
                          //           << "THIS IS THE I2.Count="
                          //           "" c.Count_I2.Str
                          //           "" //, attempt = " I2_attempt.Str
                          //           ", method:" Class.Names[].Whole_name
                          //           "." Names[0] 
                          //           ", line=" (Parse.Line+1).Str
                          //           #NL ;
                          //; 
	                      CASE ?
	                      [replace_call_fun_with_its_body2(B[], i)] ?
	                           --- 'replace call to method with its body'
	                           Inlined_calls += 1
	                           //DEBUG:
	                           //   CASE c.Count_I2 == (
	                           //     	   c.Maximum_op("I2") - 1)
	                           //     	   ?
	                           //     	   << "==> inline index="
	                           //            "" set_inline_index.Str #NL
	                           //   ;
	                           //;
	                           log_op(st, "I2: " sfun.Whole_name)
	                           Optimizations_G = FALSE
							   c.Count_I2 += 1
	                           c.Optimizations_count += 1
	                           CONTINUE i
	                      [sfun.Error_if_not_inlined] ?
	                           Parse.Err("Function can not be "
	                           "inlined though it is marked as "
	                           "necessary to be inlined"._ECanNotInline3
	                           ": " sfun.Class.Whole_name 
	                           "." sfun.Names[0])
	                      [inline_fun_ != NONE] ?
	                      	Parse.Warn("Could not inline function"._Wcouldnot
	                      	" " inline_fun_.Whole_name 
	                      	" (" reason_cannot ")")
	                      	//DEBUG: 
	                      	//      -------------- 'no reason'
	                      	//      CASE reason_cannot == "" ? NONE ;
	                      	//;
	                      ;
                     ;
                     ;
                     ;
                     ;
                ;
            ;
            CASE !Optimizations_G && (
                 should_optimize("E1") || should_optimize("E2"))
                 ?
                 ------------- 'replace calls to functions returning const'
                 BOOL set_Optimizations_G = TRUE
                 replace_calls_to_functions(Block[])
            ;
            CASE should_optimize("V0") && !Optimizations_G && (
                 !Modifiers['NATIVE_FUN']) && (
				 c.Count_V0 < c.Maximum_op("V0"))
                 ?
                 ------------- 'remove unused local variables'
                 set_Optimizations_G = TRUE
                 CASE remove_unused_vars ?
					  c.Count_V0 += 1
                      c.Optimizations_count += 1 ;
            ;
            CASE set_Optimizations_G ? Optimizations_G = TRUE ; 
        ; .
        
METHOD Uses_arrays ==> BOOL :
    FOR lvar IN Param[] :
        CASE lvar.Is_array ? RESULT = TRUE ==> ;
    ;
    FOR lvar IN Local_var[] :
        CASE lvar.Is_array ? RESULT = TRUE ==> ;
    ; .
        
        {Fun} fun_inlining_
		BOOL Union_done|_local_vars
		STR reason_cannot|_inline_function
		
		FUN functions_called_in_expr(
			{Expr} E|xpression) ==> BOOL, RECURSIVE
			:
			CASE E.Operation ?
			['FUN', 'BASE_FUN', 'SYSTEM_FUN', 'NEW_OBJ']: RESULT = TRUE
			
			['BINARY']: RESULT = E.Arg1_.functions_called_in_expr
						RESULT ||= E.Arg2_.functions_called_in_expr
						
			['INT2REAL', 'NOT_B', 'NOT', 'NEG']:
				RESULT = E.Arg1_.functions_called_in_expr
				
			['VAR', 'FIELD', 'ARRAY', 'CONST', 'UNKNOWN']: NONE
			
			['INDEX']: RESULT = E.Arg1_.functions_called_in_expr
					   RESULT ||= E.Arg2_.functions_called_in_expr
					   RESULT ||= E.Arg3_.functions_called_in_expr
						
			['AS']: RESULT = E.Arg1_.functions_called_in_expr ; .
            
        FUN before_assigns_in_params(
            {Expr} Call|_function_expression ) ==> BOOL
            :
            ---------------------------------------------------- ''
            FOR it IN Call.Items_[] :
                CASE it.Before_assign_[].Count > 0 ? RESULT = TRUE ==> ;
            ; .
            
        METHOD optimize_sequential_case({Case} Cas|e_statement, 
            {Statement} B|lock_of_statements_containing_Case[],
            INT Index|_where_Case_is_located)
            :
            ---------------------------- 'remove branches always false'
            FOR j IN [Cas.Block_[].Count-1 DOWNTO 0] :
                CASE Cas.Block_[j].Work == 'ELSE' ? CONTINUE j ;
                CASE Cas.Block_[j].{Case}.Condition.Operation == 'CONST' && (
                     Cas.Block_[j].{Case}.Condition.Var_arg.Int_c == 0)
                     ?
                     log_op(Cas, "[#" j.Str "]")
					 comp(Parse).Count_C1 += 1
                     comp(Parse).Optimizations_count += 1
                     Cas.Block_[].Delete(j) ;
            ;
            ---------------------- 'if the first is always TRUE, replace to it'
            CASE Cas.Block_[0].Work == 'ELSE' || (
                 Cas.Block_[0].{Case}.Condition.Operation == 'CONST') && (
                 Cas.Block_[0].{Case}.Condition.Var_arg.Int_c != 0)
                 ?
                 log_op(Cas, "C1[ELSE]")
				 comp(Parse).Count_C1 += 1
                 comp(Parse).Optimizations_count += 1
                 B[].Delete(Index)
                 FOR st IN Cas.Block_[0].Block_[] :
                     B[].Insert(Index + st.Index, st) ;
            ; .

        
        METHOD log_op|timizations_if_vv_specified( 
            {Statement} St|atement_optimizing, STR Text|_to_add )
            :
            CASE !comp(Parse).Verbose2 ? ==> ;
            
            Log(Text " Statement: Work = " St.Work.Name 
            ", Total_stmt=" St.Total_stmt.Str #NL) .
            
        METHOD log_expr|ession_optimization(
            {Expr} E|xpression_optimizing,
            STR Text|_add)
            :
            CASE !comp(Parse).Verbose2 ? ==> ;
            CASE E.Operation IN ['VAR', 'FIELD'] ?
                 STR var|iable_name = 
                     ", Variable = " E.Var_arg.Whole_name
            ;
            Log(Text " Expression: Operation = " E.Operation.Name var ) .
            
        METHOD log_var|iable_optimization(
            {Var} V|ariable_optimizing,
            STR Text|_add)
            :
            CASE !comp(Parse).Verbose2 ? ==> ;
            Log(Text " Variable: " V.Whole_name) .
            
            
        FUN Bool2Str( BOOL V|alue_boolean ) ==> STR :
            CASE V ? RESULT = "TRUE" ==> ;
            RESULT = "FALSE" .
            
        
        METHOD when_copy_expr_failed|_dummu( STR Reason|_why) :
			reason_cannot = Reason
            //CASE for_provide_construct ?
            //     Console_color('OLIVE')
            //     << "copy failed: " Reason #NL
            //     Console_color('SILVER') ; 
            .
            
        FUN same_array_operand(
        	{Expr} A|_operand, {Expr} B|_operand) ==> BOOL
        	:
            -------------------- 'TRUE if referencing the same array variable'
            CASE A.Operation != B.Operation ? ==> ;
            CASE A.Operation == 'VAR' ?
                 RESULT = A.Var_arg == B.Var_arg ==> ;
            CASE A.Operation == 'FIELD' ?
                 RESULT = A.Var_arg == B.Var_arg && A.Arg1_ == B.Arg1_ ; .
            
            
        FUN case_to_single_branch(
        {Statement} B|lock_of_stmt[],
        INT Index|_in_block INDEXING {Statement})
            :
            ---------------------- 'B[Index] is a CASE with constant condition'
            {Case} c|ase_with_constant_condition = B[Index].{Case}
            {Expr} cond|ition_constant = c.Condition
            CASE c.Condition.Type_expr.Kind == 'BOOL' ?
                 CASE c.Condition.Var_arg.Int_c != 0 ?
                      replace_statement(B[], Index, 
                                c.Block_[0].{Case}.Block_[]) ==>
                                
                 ELSE replace_statement(B[], Index,
                                c.Block_[1].{Case}.Block_[]) ==>
                 ;
            ;
            ---------------------- 'search a branch satisfying to the condition'
            FOR b|ranch IN c.Block_[] :
                CASE b.Work == 'ELSE' ?
                     replace_statement(B[], Index, b.Block_[]) ==> ; 
                {Case} br|anch_of_case = b.{Case}
                CASE satisfying_branch(cond, br) ?
                     replace_statement(B[], Index, b.Block_[]) ==> ; /////// ?????
            ;
            {Statement} no|_statements[]
            replace_statement(B[], Index, no[]) .
            
            
        FUN all_branches_empty({Case} Cas|e_statement) ==> BOOL :
            FOR st IN Cas.Block_[] :
                FOR st2 IN st.{Case}.Block_[] :
                    CASE st2.Work != 'COMMENT' ? ==> ;
                ;
            ;
            RESULT = TRUE .
            
            
        FUN satisfying_branch({Expr} Cond|ition_which_is_constant,
            {Case} Br|anch_of_case ) ==> BOOL
            :
            -------------------------- 'TRUE if the Br is a single executing'
            CASE Cond.Type_expr.Kind ?
            ['BOOL']: NONE
            ['INT', 'ENUM']:
                CASE Br.Range1 != NONE ?
                     RESULT = Cond.Var_arg.Int_c >= Br.Range1.Var_arg.Int_c && (
                     Cond.Var_arg.Int_c <= Br.Range2.Var_arg.Int_c) ==>
                ;
                FOR v IN Br.Values[] :
                    CASE v.Int_c == Cond.Var_arg.Int_c ? RESULT = TRUE ==> ;
                ;
            ['STR']:
                CASE Br.Range1 != NONE ?
                     RESULT = Cond.Var_arg.Str_c >= (
                     Br.Range1.Var_arg.Str_c) && (
                     Cond.Var_arg.Str_c <= Br.Range2.Var_arg.Str_c) ==>
                ;
                FOR v IN Br.Values[] :
                    CASE v.Str_c == Cond.Var_arg.Str_c ? RESULT = TRUE ==> ;
                ;
            ['CLASS', 'STRUCTURE', 'REAL']: NONE ; .
            
            
        FUN replace_statement({Statement} B|lock_of_statements[], 
            INT Index|_of_statement_to_replace, 
            {Statement} List|_of_statements_replacing_single_statement[])
            :
            -------- 'List[] represents a branch replacing entire CASE at Index'
            B[].Delete(Index)
            FOR i IN [List[].Count-1 DOWNTO 0] :
                B[].Insert(Index, List[i]) ; .
                
                
        METHOD for_remove_header_for_once_executing(
            {Statement} B|lock_of_stmts[], 
            INT Index|_of_FOR_statement INDEXING {Statement}) ==> BOOL
            :
            ------------------------------- 'FOR x IN y TO y :'
            {For} sfor|_statement = B[Index].{For}
            CASE sfor.Breaked || sfor.Continued || sfor.Array != NONE ? ==> ;
            CASE sfor.Range1.Operation == 'VAR' && (
                 sfor.Range2.Operation == 'VAR') && (
                 sfor.Range1.Var_arg == sfor.Range2.Var_arg) || (
                 sfor.Range1.Operation == 'CONST') && (
                 sfor.Range2.Operation == 'CONST') && (
                 sfor.Range1.Var_arg.Int_c == sfor.Range2.Var_arg.Int_c)
                 ?
                 RESULT = TRUE
                 INT i|ndex_of_sfor = Index
                 CASE sfor.Var.Used_for_r ?
                      a|ssignment_statement = {Assign}(Line = sfor.Line, Pos= 0,
                        Function_ = THIS, Level = Current_level,
                        Work = 'ASSIGN', 
                        Dest = {Expr}(Operation = 'VAR', Var_arg = sfor.Var),
                        Source = sfor.Range1), >> Keep_statements[]
                      B[].Insert(i, a) 
                      i += 1 ;
                 replace_statement(B[], i, sfor.Block_[]) ; .
                 
        FUN for_remove_loop_not_executing(
        	{Statement} B|lock_of_stmts[], 
            INT Index|_of_FOR_statement INDEXING {Statement}) ==> BOOL
            :
            ------------------------------- 'FOR x IN y TO y :'
            {For} sfor|_statement = B[Index].{For}
            CASE sfor.Range1.Operation == 'CONST' && (
                 sfor.Range2.Operation == 'CONST')
                 ?
                 CASE sfor.Downto && (
                      sfor.Range1.Var_arg.Int_c >= sfor.Range2.Var_arg.Int_c)
                      ?
                      ==> ;
                 CASE !sfor.Downto && (
                      sfor.Range1.Var_arg.Int_c <= sfor.Range2.Var_arg.Int_c)
                      ?
                      ==> ;
                 RESULT = TRUE
                 {Statement} no|_statements[]
                 replace_statement(B[], Index, no[]) ; .
                 
        FUN for_remove_loop_not_having_body(
        	{Statement} B|lock_of_stmts[], 
            INT Index|_of_FOR_statement INDEXING {Statement}) ==> BOOL
            :
            ------------------------------- 'FOR x IN y TO y :'
            {For} sfor|_statement = B[Index].{For}
            CASE sfor.Range1.Operation IN ['CONST', 'VAR', 'FIELD', 'INDEX']&&(
                 sfor.Range2.Operation IN ['CONST', 'VAR', 'FIELD', 'INDEX'])
                 ?
                 CASE sfor.Block_[].Count > 0 ? ==> ;
                 RESULT = TRUE
                 {Statement} no|_statements[]
                 replace_statement(B[], Index, no[]) ; .
                 
        METHOD remove_unused_vars ==> BOOL :
            ----------------------------- 'reset Used flag for local variables'
            FOR v IN Local_var[] :
                CASE v.Is_param ? v.Used_for_w = TRUE
                ELSE v.Used_for_r = FALSE
                	 v.Used_for_w = FALSE ;
            ;
            ----------------------------- 'walk through all the statements'
            walk_statements_marking_vars_used(Block[])
            ----------------------------- 'remove unused variables'
            FOR i IN [Local_var[].Count - 1 DOWNTO 0] :
                {Var} loc|al_varaiable = Local_var[i]
                CASE ?
                [loc.Replaced] ? CONTINUE i
                [loc == NONE] ? CONTINUE i
                [loc.Line < 0] ? CONTINUE i
                [loc.Type_.Kind == 'CLASS'] ? CONTINUE i
                [loc.Names[0].[0] == "_" || Starting(loc.Names[0], "X__extr")] ?
                     CONTINUE i
                [loc.Count_ref == 0 && !loc.Assigned && !(
                 loc.Used_for_r || loc.Used_for_w)] ?
                     log_var(loc, "V0")
                     ----------------------------- 'debug'
                     comp(Parse).Count_remove_local_var += 1
                     Console_color({Console}.{colors}.'RED')
                     //Console_color({colors}.'RED') // primary compiler has no
                     
                     //DEBUG:
                     //      CASE loc.Names[0] == "i4_fd" ? ;
                     //;
                     
                     << comp(Parse).Count_remove_local_var.Str
                     << " " ("removing"._Mremov ) ": " loc.Whole_name 
                     << " " ("in function"._Mfun ) ": " Whole_name #NL
                        
                     Console_color({colors}.'SILVER')
                     ----------------------------- 'remove unused var'
                     removing_var = loc
                     walk_statements_removing_dest(Block[])
                     RESULT = TRUE
                     //DEBUG:
                     //      CASE Local_var[i].Names[0] == "X__extr_tmp_286" ?
                     //           >> ;
                     //;
                     Local_var[].Delete(i) ;
            ; .
            
        FUN variable_used_in_st|atement({Statement} St|atement, 
            {Var} V|ariable) ==> BOOL
            :
            ------------------- 'TRUE if V used even as a Dest in assignments'
            PUSH V.Used_for_r = FALSE :
            PUSH V.Used_for_w = FALSE :
                 {Statement} b|lock_of_1[] << St
                 walk_statements_marking_vars_used(b[])
                 RESULT = V.Used_for_r || V.Used_for_w ; 
            ; .
                 
        FUN variable_used_in_expr|ession({Expr} E|xpression,
            {Var} V|ariable) ==> BOOL
            :
            -------------------- 'TRUE if V is used in E expression'
            PUSH V.Used_for_r = FALSE :
            PUSH V.Used_for_w = FALSE :
                 mark_used_variables(E)
                 RESULT = V.Used_for_r || V.Used_for_w ; 
            ; .
            
        FUN walk_statements_marking_vars_used(
            {Statement} B|lock_of_stmts[]), RECURSIVE
            :
            ---------------------------- ''
            FOR st IN B[] :
                CASE st.Work ?
                ['ASSIGN', 'APPEND', 'OUTPUT', 'INPUT', 'PUSH', 'ASSERT',
                 'DEBUG', 'COMMENT']: 
                    CASE st.{Assign}.Dest.Operation == 'VAR' ? NONE
                    ELSE mark_used_variables(st.{Assign}.Dest) ;
                    mark_used_variables(st.{Assign}.Source)
                    CASE st.{Assign}.Back_ != NONE ?
                         {Statement} back|_assign_for_push[] 
                         back[] << st.{Assign}.Back_
                         walk_statements_marking_vars_used(back[]) ;
                ['BREAK', 'CONTINUE', 'NEXT', 'FOR']: //, 'FOREVER']:
                    st.{For}.Var.Used_for_r = TRUE
                    mark_used_variables(st.{For}.Array)
                    mark_used_variables(st.{For}.Range1)
                    mark_used_variables(st.{For}.Range2)
                ['CASE', 'ELSE', 'RETURN', 'STOP', 'LIMIT', 'LOCAL']:
                    mark_used_variables(st.{Case}.Condition)
                    mark_used_variables(st.{Case}.Range1)
                    mark_used_variables(st.{Case}.Range2)
                    mark_used_variables(st.{Case}.Formatted)
                ['CALL_NATIVE']: NONE ;
                walk_statements_marking_vars_used(st.Block_[]) ; .
                
        {Var} removing_var|iable
        
        METHOD walk_statements_removing_dest
        	|ination_if_it_matches_removing_var(
            {Statement} B|lock_of_stmts[]), RECURSIVE
            :
            ---------------------------- ''
            FOR i IN [B[].Count-1 DOWNTO 0] :
                {Statement} st|atement_of_B = B[i]
                CASE st.Work ?
                ['ASSIGN', 'APPEND', 'OUTPUT', 'INPUT', 'PUSH', 'ASSERT',
                 'DEBUG', 'COMMENT']:
                    {Assign} sta|ssignment = st.{Assign}
                    BOOL dest_removed = FALSE
                    CASE sta.Dest.Operation == 'VAR' && (
                         sta.Dest.Var_arg == removing_var)
                         ?
                         sta.Dest = NONE
						 dest_removed = TRUE ;
                    CASE dest_removed && st.Work !IN ['INPUT']  && (
                         !is_fun(sta.Source))
                         ?
                         Console_color({colors}.'YELLOW')
                         
                         << "delete stmt"._Mdel ": " st.Total_stmt.Str 
                            " obj: " Total_obj_index(st).Str
                            " (line: " (st.Line+1).Str ")"  #NL
                            
                         Console_color({colors}.'SILVER')
                         
                         B[].Delete(i)
					;
                    CASE st.{Assign}.Back_ != NONE ?
                         {Statement} back|_assign_for_push[]
                         back[] << st.{Assign}.Back_
                         walk_statements_removing_dest(back[])
                    ;
                ['BREAK', 'NEXT', 'CONTINUE', 'FOR', 'CASE', 'ELSE', 'LIMIT',
                 'LOCAL', 'RETURN', 'STOP', 'CALL_NATIVE']: NONE
                ;
                walk_statements_removing_dest(st.Block_[]) ; .
				
		FUN is_fun|ction_call_expression(
			{Expr} E|xpression ) ==> BOOL
			:
			RESULT = E.Operation == 'FUN'
			CASE !RESULT ? ==> ;
			CASE E.Fun_.Is_system ? RESULT = FALSE ; .
				
        FUN mark_used_variables({Expr} E|xpression),
        	RECURSIVE
        	:
            --------------------------------- 'skip empty expressions'
            CASE E == NONE ? ==> ;
            mark_used_variables(E.Arg1_)
            mark_used_variables(E.Arg2_)
            mark_used_variables(E.Arg3_)
            mark_used_variables(E.This_)
            ---------------------------------- 'function parameters'
            FOR it IN E.Items_[] :
                mark_used_variables(it) ;
            ---------------------------------- 'var.Used = TRUE'
            CASE E.Operation == 'VAR' ?
                 CASE E.Var_arg.Replaced ?
                      E.Var_arg.Replace_to_.Used_for_w = TRUE ;
                 E.Var_arg.Used_for_r = TRUE ;
            ---------------------------------- 'additional walks'
            mark_used_variables(E.Array_)
            mark_used_variables(E.Owned_)
            walk_statements_marking_vars_used(E.Assignments_[])
            CASE E.Before_assign_[].Count > 0 ?
                 {Statement} before|_assign[]
                 FOR st IN E.Before_assign_[] : before[] << st ;
                 E.Before_assign_[].Clear
                 walk_statements_marking_vars_used(before[])
                 FOR st IN before[] : E.Before_assign_[] << st ;
            ; .
                
        FUN has_statements({Statement} B|lock_of_stmts[]) ==> BOOL :
            FOR st IN B[] :
                CASE st.Work != 'COMMENT' ? RESULT = TRUE ==> ;
            ; .
            
        METHOD replace_calls_to_functions(
            {Statement} B|lock_of_statement[]), RECURSIVE
            :
            -------------- 'search any expression containing call to a function'
            FOR st IN B[] :
                CASE st.Block_[].Count > 0 ?
                     replace_calls_to_functions(st.Block_[]) ;
                CASE st.Work ?
                ['ASSIGN', 'APPEND', 'OUTPUT', 'INPUT', 'PUSH', 'ASSERT',
                 'DEBUG', 'COMMENT']:
                    //DEBUG:
                    //    CASE st.Total_stmt == 1111 ?
                    //         << "stmt 1111" #NL ;
                    //;
                    replace_in_expr(st.{Assign}.Dest)
                    replace_in_expr(st.{Assign}.Source)
                    CASE st.{Assign}.Back_ != NONE ?
                         {Statement} back|_assign_for_push[] 
                         back[] << st.{Assign}.Back_
                         replace_calls_to_functions(back[]) ;
                    //DEBUG:
                    //    CASE st.Total_stmt == 12013 ?
                    //         << "stmt 1203: Work = " st.Work.Name
                    //         ", (Dest==NONE)=" (st.{Assign}.Dest == NONE).Str
                    //         ", Source.Operation=" 
                    //         "" st.{Assign}.Source.Operation.Name >> ;
                    //;
                    {Assign} a|ssign_st = st.{Assign}
                    CASE st.Work == 'ASSIGN' && (
                         a.Dest.Operation == 'CONST') && (
                         a.Dest.Var_arg == comp(Parse).NONE_c) && (
                         a.Source.Operation == 'CONST')
                         ?
                         st.Work = 'COMMENT'
                         a.Source.Var_arg.Str_c = "removed const"
                    ;
                ['BREAK', 'NEXT', 'CONTINUE', 'FOR']: //, 'FOREVER']:
                    st.{For}.Var.Used_for_r = TRUE
                    replace_in_expr(st.{For}.Array)
                    replace_in_expr(st.{For}.Range1)
                    replace_in_expr(st.{For}.Range2)
                ['CASE', 'ELSE', 'RETURN', 'STOP', 'LIMIT', 'LOCAL']:
                    replace_in_expr(st.{Case}.Condition)
                    replace_in_expr(st.{Case}.Range1)
                    replace_in_expr(st.{Case}.Range2)
                    replace_in_expr(st.{Case}.Formatted)
                ['CALL_NATIVE']: NONE ;
            ; .        
            
        INT level_expr|ession_replacing

        METHOD replace_in_expr({Expr} E|xpression), RECURSIVE :
            --------------------------------- 'skip empty expressions'
            CASE E == NONE || level_expr > 10 ? ==> ;
			{Compiler} c|ompiler_reference = comp(Parse)
            PUSH level_expr = level_expr + 1 :
                 replace_in_expr(E.Arg1_)
                 replace_in_expr(E.Arg2_)
                 replace_in_expr(E.Arg3_)
                 replace_in_expr(E.This_)
                 ---------------------------------- 'function parameters'
                 FOR it IN E.Items_[] :
                     replace_in_expr(it) ;
                 ---------------------------------- 'additional walks'
                 replace_in_expr(E.Array_)
                 replace_in_expr(E.Owned_)
                 replace_calls_to_functions(E.Assignments_[])
                 CASE E.Before_assign_[].Count > 0 ?
                      {Statement} before|_assign[]
                      FOR st IN E.Before_assign_[] : before[] << st ;
                      E.Before_assign_[].Clear
                      replace_calls_to_functions(before[])
                      FOR st IN before[] : E.Before_assign_[] << st ;
                 ;
                 ---------------------- 'if expression is a call to a function?'
                 CASE E.Operation == 'FUN' ?
                      FOR it IN E.Items_[] :
                          CASE is_field_of_variable(it) ? ==> ;
                      ;
                      CASE should_optimize("E1") && E.Fun_.Modifiers[
                           'STATIC'] && !E.Fun_.Modifiers['NATIVE_FUN'] && (
                           TRUE) && ( //!E.Fun_.Calls_stored_fun) && (
						   c.Count_E1 < c.Maximum_op("E1"))
                           ?
                           {Expr} const|ant_returning = E.Fun_.returning_const
                           CASE const != NONE ?
                                --------- 'replace call to function by const c'
                                log_expr(E, "E1")
								c.Count_E1 += 1
                                c.Optimizations_count += 1
                                E.Operation = 'CONST'
                                E.Var_arg = const.Var_arg ==> ;
                      ;
                      CASE should_optimize("E1") && E.Fun_.Modifiers[
                           'STATIC'] && !E.Fun_.Modifiers['NATIVE_FUN'] && (
                           TRUE ) && ( //!E.Fun_.Modifiers['STORE']) && (
                           TRUE ) && ( //!E.Fun_.Calls_stored_fun) && (
						   c.Count_E1 < c.Maximum_op("E1"))
                           ?
                           {Expr} e|xpression_only_returned 
                           e = E.Fun_.returning_single
                           CASE e != NONE && (
                                replace_call_fun_with_its_body(E, e, E.Fun_))
                                ?
                                ------------ 'replace call to fun by expression'
                                log_expr(E, "E1")
								c.Count_E1 += 1
                                c.Optimizations_count += 1 ==> ;
                      ;
                      CASE should_optimize("E2") && !E.Fun_.Modifiers[
                           'STATIC'] && !E.Fun_.Modifiers['NATIVE_FUN'] && (
                           !E.Fun_.Class.Has_descendant) && (
                           !E.Fun_.Calls_base) && (
						   c.Count_E2 < c.Maximum_op("E2"))
                           ?
                           BOOL allow|_replace = E.Fun_.Class == Class
                           
                           allow &&= E.This_.Operation == 'VAR' && (
                                 E.This_.Var_arg == comp(Parse).THIS_var)
                                 
                           CASE !allow ? ==> ;
                           e = E.Fun_.returning_single
                           
                           //BOOL can_try_E2 = FALSE
                           //CASE e != NONE && (
                           //     comp(Parse).Optimize_E2_counter < 46) ?
                           //     can_try_E2 = TRUE
                           //     comp(Parse).Optimize_E2_counter++
                           //     Console_color('MAROON')
                           //     << " E2 counter: " 
                           //     "" comp(Parse).Optimize_E2_counter.Str #NL
                           //     Console_color('SILVER') ;
                           
                           //CASE can_try_E2 && (
                           //     comp(Parse).Optimize_E2_counter == 46) ?
                           //     NONE ;
                           
                           CASE e != NONE && (//can_try_E2) && (
                                replace_call_fun_with_its_body(E, e, E.Fun_))
                                ?
                                ----------- 'replace method call by expression'
                                log_expr(E, "E2")
								c.Count_E2 += 1
                                c.Optimizations_count += 1 ;
                      ;
                 ;
            ; .
            
        METHOD returning_const ==> {Expr} :
		    ---------------------------- 'if a constant only is returning ?'
            FOR st IN Block[] :
                CASE st.Work == 'COMMENT' ? CONTINUE st ;
                CASE st.Work == 'ASSIGN' && (
                     st.{Assign}.Dest.Operation == 'VAR') && (
                     st.{Assign}.Dest.Var_arg == Result) && (
                     st.{Assign}.Source.Operation == 'CONST') 
                     ?
                     CASE st.Index < Block[].Count-1 ? ==> ;
                     RESULT = st.{Assign}.Source ==>
                ELSE RESULT = NONE ==> ;
            ; .
            
        FUN is_simple_expr|ession(
        	{Expr} E|xpression_check) ==> BOOL, 
            RECURSIVE
            :
            ------------------------- 'simple expression has not side effects !'
            CASE E.Operation ?
            ['CONST', 'VAR', 'UNKNOWN']:
                ----------------- 'constant or local variable or field of THIS'
                RESULT = TRUE
            ['BINARY']: 
                --------------------- 'any binary operation'
                RESULT = is_simple_expr(E.Arg1_) 
                RESULT &&= is_simple_expr(E.Arg2_)
            ['FUN', 'BASE_FUN', 'SYSTEM_FUN']: 
                --------------------- 'is function call simple ?'
                RESULT = E.Fun_.Modifiers['STATIC'] && !E.Fun_.Modifiers[
                        'NATIVE_FUN'] && !E.Fun_.Calling_natives
                        
                CASE !RESULT ? ==> ;
                ----------------------- 'all actual parameters also simple'
                FOR p IN E.Items_[] :
                    RESULT = is_simple_expr(p)
                    CASE !RESULT ? ==> ;
                ;
            ['INDEX']:
                --------------------- 'indexes are simple'
                RESULT = is_simple_expr(E.Arg2_)
                CASE RESULT ? 
                	 RESULT = E.Arg3_ == NONE
                	 RESULT ||= is_simple_expr(E.Arg3_) ;
                         
            ['INT2REAL', 'NOT_B', 'NOT', 'NEG']:
            	RESULT = is_simple_expr(E.Arg1_)
            ['FIELD']:
                --------------------- 'object is simple (variable/field?)'
                RESULT = is_simple_expr(E.Arg1_)
            ['NEW_OBJ', 'ARRAY', 'AS']: RESULT = FALSE ; .
            
        BOOL is_calling_natives
        BOOL found_is_calling_natives
        
        METHOD Calling_natives ==> BOOL :
            CASE !found_is_calling_natives ?
                 found_is_calling_natives = TRUE
                 FOR f IN Call_functions_[] :
                     CASE f.Modifiers['NATIVE_FUN'] ?
                          is_calling_natives = TRUE
                          BREAK f ;
                 ;
            ;
            RESULT = is_calling_natives .
            
        METHOD returning_single ==> {Expr} :
            ----------------------------- 'if the function is returning a value'
            CASE Result == NONE || Modifiers['NATIVE_FUN'] ? ==> ;
            FOR st IN Block[] :
                CASE st.Work == 'COMMENT' ? CONTINUE st ;
                CASE st.Work == 'ASSIGN' && (
                     st.{Assign}.Dest.Var_arg == Result) && (
                     !nested_statements(st.{Assign}.Source))
                     ?
                     CASE RESULT != NONE ? RESULT = NONE ==> ;
                     RESULT = st.{Assign}.Source
                     CASE has_assignments(RESULT) ?
                          RESULT = NONE ==> ;
                ELSE RESULT = NONE ==> ;
            ; .
            
        FUN has_assignments|_in_expression(
        {Expr} E|expression) ==> BOOL, RECURSIVE
        	:
        	CASE E == NONE ? ==> ;
        	RESULT = E.Assignments_[].Count > 0 
        	RESULT ||= E.Before_assign_[].Count > 0 
        	CASE RESULT ? ==> ;
        	     
        	RESULT = E.This_.has_assignments
        	RESULT ||= E.Arg1_.has_assignments
        	RESULT ||= E.Arg2_.has_assignments
        	RESULT ||= E.Arg3_.has_assignments
        	CASE RESULT ? ==> ;
        	
        	FOR it IN E.Items_[] :
        	    CASE it.has_assignments ? RESULT = TRUE ==> ;
        	; .
            
        FUN nested_statements|_are_present_in_expression(
            {Expr} E|xpression) ==> BOOL, RECURSIVE
            :
            -------------------- 'ensure that E is simple enough to replace it'
            CASE E == NONE ? ==> ;
            CASE E.Assignments_[].Count + E.Before_assign_[].Count > 0 ? 
                 RESULT = TRUE ==> ;
            -------------------- 'if it is a call of BASE method ?'
            CASE E.Operation == 'BASE_FUN' ? RESULT = TRUE ==> ;
            -------------------- 'check recursively'
            RESULT = nested_statements(E.Arg1_) 
            RESULT ||= nested_statements(E.Arg2_) 
            RESULT ||= nested_statements(E.Arg3_)
            RESULT ||= nested_statements(E.This_) 
            RESULT ||= nested_statements(E.Array_)
            RESULT ||= nested_statements(E.Owned_)
            CASE RESULT ? ==> ;
            
            FOR p IN E.Items_[] :
                CASE nested_statements(p) ? RESULT = TRUE ==> ;
            ; .
            
            
        {Var}   formal_p|arameters_of_function_called[]
        {Expr}  actual_p|arameters_to_be_set_in_place_of_formal[]
        {Expr}  actual_this
        
            
        METHOD replace_call_fun_with_its_body(
            {Expr} E|xpression, 
            {Expr} Body_of|_calling_function,
            {Fun} Calling|_function) ==> BOOL
            :
            //DEBUG: << "replace call to " Calling.Names[0] >> ;
            //==>
            -------------------------- 'correspond formal and actual parameters'
            CASE level_expr > 10 ? ==> ;
            PUSH level_expr = level_expr + 1 :
                 formal_p[].Clear
                 actual_p[].Clear
                 FOR p IN Calling.Param[] : formal_p[] << p ;
                 FOR e IN E.Items_[] :
                     CASE is_field_of_variable(e) ? ==> ;
					 actual_p[] << e ;
                 actual_this = E.This_
                 -------------- 'copy expression from the called function body'
                 failed_copy_expr = FALSE
                 {Expr} r|eplacer_expression_temp = Copy_expr(Body_of)
                 CASE r.Operation == 'FUN' && r.This_ != NONE && (
                      r.This_ != comp(Parse).THIS_expr)
                      ?
                      ==> ;
                      
                 CASE failed_copy_expr ? ==> ;
                 
                 CASE comp(Parse).Total_replace_index == 0 ?
                      INT dummy555 = 0 ;
                      
                 E.Replace_index = E.Replace_index
                    "iRepl" comp(Parse).Total_replace_index.Str "_"
                    
                 comp(Parse).Total_replace_index += 1
				 ----------------------------- 'assign attributes'
				 E.This_ = r.This_
                 E.Operation = r.Operation
                 E.Sign = r.Sign
                 E.Type_obj_ = r.Type_obj_
                 -------------------- 'assign arguments'
                 E.Arg1_ = r.Arg1_
                 E.Arg2_ = r.Arg2_
                 E.Arg3_ = r.Arg3_
                 E.Fun_ = r.Fun_
                 E.Items_[].Clear
                 FOR e IN r.Items_[] :
                 	 E.Items_[] << Copy_expr(e)
                 ;
                 -------------------- 'Var_arg'
                 E.Var_arg = r.Var_arg
				 
                 CASE E.This_ == NONE && !Calling.Modifiers['STATIC'] ?
                      E.This_ = {Expr}(Operation = 'VAR',
                      	Var_arg = {Var}(Names[] << "THIS",
                			Constant_value = "this", Line = -1,
                			Type_ = comp(Parse).Current_class)),
                      	OWNED BY E
                      E.This_.Var_arg.Set_final_name("this") 
                 ;
				 
                 E.Is_const = r.Is_const
                 RESULT = TRUE
            ; .
        
        
        INT level_copy
        BOOL final_replace_var|iable
        BOOL failed_copy_expr
        
        METHOD Copy_expr|ession(
            {Expr} Source|_expression) ==> {Expr}, RECURSIVE
            :
            ------------------------------ 'copy entire tree of sub-expressions'
            CASE Source == NONE ? ==> ;
            CASE Source.Operation == 'CONST' && (
            	 Source.Var_arg.Type_.Kind == 'CLASS') && (
            	 Source.Var_arg.Constant_value != "NONE")
            	 ?
                 reason_cannot = "Can not copy not a NONE object constant"
                 failed_copy_expr = TRUE ==> ;
            CASE Source.Operation == 'AS' ?
                 --------------------------- 'AS operation copy'
                 NONE ;
            PUSH level_copy = level_copy + 1 :
                 top|_expression = {Expr}(Operation = Source.Operation, 
                     Sign = Source.Sign, Fun_ = Source.Fun_,
                     Type_obj_ = Source.Type_obj_, Var_arg = Source.Var_arg,
                     Pass_by_ref = Source.Pass_by_ref),
                     OWNED BY THIS
                 CASE top.Var_arg.Replaced ?
                      top.Var_arg = top.Var_arg.Replace_to_ ;
                 CASE level_copy == 1 ?
                      //DEBUG:
                      //  CASE comp(Parse).Total_replace_index == 652 ?
                      //       ---------------------------- '555555555555'
                      //       INT dummy555 = 0 ;
                      //;
                      top.Replace_index = top.Replace_index 
                        "iCopy" comp(Parse).Total_replace_index.Str "_"
                        
                      comp(Parse).Total_replace_index += 1
                 ;
                 RESULT = top
                 ----------------------- 'Before_assign_[] present ?'
                 CASE Source.Before_assign_[].Count > 0 ?
                      when_copy_expr_failed("1 - before assign required")
                      
                      failed_copy_expr = TRUE ;
                 CASE Source.Array_ != NONE ?
                      top.Array_ = Copy_expr(Source.Array_) ;
                 ----------------------- 'if a localized string'
                 top.Localize_n = Source.Localize_n
                 top.Localize_i = Source.Localize_i
                 ----------------------- 'copy arguments & function parameters'
                 CASE Source.Arg1_ != NONE ?
                      top.Arg1_ = Copy_expr(Source.Arg1_) ;
                 CASE Source.Arg2_ != NONE ?
                      top.Arg2_ = Copy_expr(Source.Arg2_) ;
                 CASE Source.Arg3_ != NONE ?
                      top.Arg3_ = Copy_expr(Source.Arg3_) ;
                 FOR e IN Source.Items_[] : top.Items_[] << Copy_expr(e) ;
                 top.This_ = Copy_expr(Source.This_)
                 -------------------------------------- 'types available?'
                 CASE !failed_copy_expr && Source.Type_obj_ != NONE && (
                      Source.Type_obj_.Kind == 'CLASS') && (
                      Source.Type_obj_ != Class) && (
                      Source.Type_obj_ !IN Class.Import_[])
                      ?
                      when_copy_expr_failed("2 - class unavailable: " 
                      "" Source.Type_obj_.Whole_name)
                      failed_copy_expr = TRUE ;
                 CASE !failed_copy_expr && Source.Operation == 'FUN' && (
                      !Source.Fun_.Is_system) && (
                      Source.Fun_.Class != NONE) && (
                      Source.Fun_.Class != Class) && (
                      Source.Fun_.Class !IN Class.Import_[])
                      ?
                      when_copy_expr_failed(
                        "3 - function class is not in import")
                      failed_copy_expr = TRUE ;
                 CASE !failed_copy_expr && Source.Var_arg != NONE && (
                      Source.Var_arg.Type_.Kind == 'CLASS') && (
                      Source.Var_arg.Type_ != Class) && (
                      Source.Var_arg.Type_ != comp(Parse).TYPE_OBJ) && (
                      Source.Var_arg.Type_ !IN Class.Import_[])
                      ?
                      when_copy_expr_failed(
                        "4 - variable class is not in import: " 
                        "" Source.Var_arg.Type_.Whole_name
                        " " Source.Var_arg.Whole_name
                        ", in function " THIS.Whole_name)
                      failed_copy_expr = TRUE ;
                 -------------------------------------- 'method ?'
                 CASE Source.Operation == 'FUN' ?
                      {Fun} cf|unction_cur = comp(Parse).Current_fun
                      CASE Source.Fun_ !IN cf.Call_functions_[] ?
                           cf.Call_functions_[] << Source.Fun_ ;
                 	  CASE Source.This_ != NONE ?
	                       CASE Source.This_.Operation == 'VAR' && (
	                            actual_this != NONE) && (
	                            Source.This_.Var_arg == comp(Parse).THIS_var)
	                            ?
	                            top.This_ = actual_this ;
                 	  ELSE //!!! CAN NOT APPLY ANY METHOD TO NONE !!!
                 	       failed_copy_expr = TRUE
                 	  ;
                 ;
                 -------------------------------------- 'new object?'
                 FOR init|_field IN Source.Assignments_[] :
                     CASE init.{Assign} == NONE ?
                          Parse.Err("Wrong source statement while "
                          "copy"._Ewrong2) ;
                          
                     a|ssign_value = {Assign}(
                     		Line = -1, Pos= 0,
                     		Function_ = THIS,
                          	Level = init.Level,
                          	Work = init.Work), >> Keep_statements[]
                          
                     top.Assignments_[] << a
                     a.Dest = Copy_expr(init.{Assign}.Dest)
                     a.Source = Copy_expr(init.{Assign}.Source) ;
                 -------------------------------------- 'variable to replace ?'
                 CASE Source.Operation == 'VAR' && !final_replace_var ?
                      INT index|_of_parameter INDEXING {Expr} 
                      index = formal_p[].Find(Source.Var_arg)
                      CASE index >= 0 && actual_p[index] != NONE ?
                           ------------ 'yes, replace to an actual parameter'
                           PUSH final_replace_var = TRUE :
                                RESULT = Copy_expr(actual_p[index])
                                BOOL replaced|_to_actual = TRUE
                           ;
                      ;
                      CASE !replaced && Source.Var_arg.In_type_ != NONE && (
                           actual_this != NONE)
                           ?
                           ------------ 'field of THIS ?'
                           RESULT.Operation = 'FIELD'
                           RESULT.Var_arg = Source.Var_arg
                           RESULT.Arg1_ = Copy_expr(actual_this)
                           RESULT.Arg1_.Type_obj_ = Source.Var_arg.In_type_
                      ;
                 ;
            ; .
            
        FUN statements_count(
        	{Statement} B|lock_of_statements[]) ==> INT,
            RECURSIVE
            :
            ---------- 'though interested only if there are less or more then N'
            FOR st IN B[] :
                CASE st.Work == 'COMMENT' ? CONTINUE st ;
                RESULT += 1
                CASE st.Block_[].Count > 0 ?
                     RESULT += statements_count(st.Block_[]) ;
            ; .
            
        INT set_inline_index
        {Fun} inline_fun_|ction_
        
		FUN ToInt|_from_string(STR S|tring_containing_number) ==> INT :
			FOR i IN [0 TO S.Len-1] :
			    CASE S.[i] IN "0123456789" ?
			         RESULT = RESULT * 10 + S.[i].Ord - "0".Ord
			    ELSE ==> ;
			; .
            
        METHOD replace_call_fun_with_its_body2(
            {Statement} B|lock_of_statements[],
            INT Line|_to_replace INDEXING {Statement}) ==> BOOL
            :
            {Compiler} c|ompiler = comp(Parse)
	                      DEBUG:
	                            CASE c.Count_I2 == c.Maximum_op("I2")-1 ?
	                                 --------------- 'last__allowed__I2'
	                                 NONE ;
	                      ;
		PUSH Current_level = B[Line].Level :
            INT insert_pos = Line + 1
            CASE c.Max_count_call_replacements < -1 ?  
                 CASE "$MAXI2" !IN c.Defined_name[] ?
                      c.Max_count_call_replacements = -1
                      
                 ELSE c.Max_count_call_replacements = c.Defined_value[
                 	 	c.Defined_name[].Find("$MAXI2")].ToInt
                 ;
            ;
            CASE c.Max_count_call_replacements >= 0 && (
            	 c.Count_call_replacements >= c.Max_count_call_replacements)
            	 ?
                 ==> ;
            c.Count_call_replacements += 1
            //DEBUG:
            //      CASE c.Count_call_replacements == (
            //      	   c.Max_count_call_replacements)
            //      	   ?
            //           ------------------- 'the last allowed call replacement'
            //      ;
            //;
            -------------------------- 'total_inline_fun incremented'
            comp(Parse).Total_inline_fun += 1
            PUSH set_inline_index = comp(Parse).Total_inline_fun :
                 -------------------------- 'original statement to be replace:'
                 {Statement} st|atement_at_line = B[Line]
                 CASE level_expr > 10 ?
                      DEBUG:
                      		PUSH Parse.Line = st.Line :
                            Parse.Warn("level_expr > 10 -- INLINE ignored") ;
                      ;
                      CASE inline_fun_ != NONE ?
                           << "level expr = " level_expr.Str " > 10, "
                           "function is not inlined:"inline_fun_.Names[0]
                           #NL
                      ;
                      ==> ;
                 CASE st.Work IN ['ASSIGN', 'APPEND'] 
                 	  && st.{Assign}.Dest.Operation IN ['VAR', 'FIELD']
                 	  && var_present_in_expr(st.{Assign}.Source,
                 	  st.{Assign}.Dest.Var_arg)
                 	  ?
                      DEBUG:
                            CASE st.Line > 0 ? 
                                 PUSH Parse.Line = st.Line :
                                      STR n_inlining= fun_inlining_.Names[0]
                                      CASE n_inlining != "" ? 
                                           n_inlining = ": " n_inlining ;
                                 Parse.Warn("Dest is VAR/FIELD && it is "
                                 "present in source and dest expressions: "
                                 "INLINE will be ignored" n_inlining) ;
                            ;
                      ;
                      ==> ;
                 
                 CASE st.{Assign}.Is_decl ? ==> ;
                 CASE st.Work != 'ASSIGN' ? ==> ;
                 {Expr} e_f|unction_calling_expr = st.{Assign}.Source
                 {Fun} a_f|unction_actual_source = e_f.Fun_
                 -------------- 'correspond formal and actual parameters 2'
                 PUSH level_expr = level_expr + 1 :
                      FOR v IN a_f.Local_var[] :
                          CASE v.Type_.Kind == 'CLASS' && (
                               v.Type_ != Class) && (
                               v.Type_ !IN Class.Import_[])
                               ?
                               CASE inline_fun_ != NONE ?
                                    << "Parameter " v.Names[0] 
                                    " type is "
                                    "not imported, function "
                                    "can not be "
                                    "replaced: "inline_fun_.Names[0]
                                    #NL
                               ;
                               DEBUG: 
                                     PUSH Parse.Line = st.Line :
                                     Parse.Warn("parameter " v.Names[0] 
                                     " type is not imported") ;
                               ;
                               ==> ;                      
                      ;
                      debug_Expr = e_f
                      
                      //BOOL was_none_type_obj = (
                      //      debug_Expr.This_.Type_obj_ == NONE)
                            
                      comp(Parse).Debug_Attempt += 1
                      formal_p[].Clear
                      actual_p[].Clear
                      --------- 'assign parameters before using them'
                      {Statement} ins|erting_block[]
                      FOR e IN e_f.Items_[] :
                          CASE ?
                          [!e.Is_array && e.Operation IN ['VAR', 'FIELD',
                          	'CONST']] ?
                          	   actual_p[] << Copy_expr(e)
                          [!e.Is_array && has_fields_not_objects(e)] ?
                          	   t_v|ariable_temp = {Var}(Line = 0, 
                          	   		Type_ = e.Type_expr,
                          	   		Is_array = e.Is_array,
                          	   		Is_fixed = e.Is_fixed,
                          	   		In_fun_ = THIS,
                          	   		Is_inline_parameter = TRUE,
                          	   		Really_temp = TRUE,
                          	   		Names[] << "temp_inline" temp_inline.Str),
                          	   		>> Local_var[]
                          	   		
                          	   temp_inline += 1
                          	   t_v.Set_final_name(var_final_name(t_v.Names[]))
                          	   
                          	   e_t|emp_variable = {Expr}(Operation = 'VAR',
                          	   		Var_arg = t_v), OWNED BY THIS
                          	   -------------------- 'assign temporary'
                          	   t_a|ssign_to_t_v = {Assign}(
                          	   		Function_ = THIS, Line = 0, Pos= 0,
                          	   		Level = Current_level,
                          	   		Dest = e_t, Source = Copy_expr(e)),
                          	   		OWNED BY THIS
                          	   		
                          	   ins[] << t_a
                          	   actual_p[] << e_t
                          ELSE actual_p[] << Copy_expr(e) ;
                      ;
                      FOR p IN a_f.Param[] :
                          formal_p[] << p ;
                      actual_this = e_f.This_
                      actual_result = st.{Assign}.Dest
                      ------ 'local vars of inlined function are inlined too'
                      INT was_local_v|ariables = Local_var[].Count
                      FOR v IN a_f.Local_var[] :
                          CASE ?
                          [v == a_f.Result] ?
                               formal_p[] << v
                               actual_p[] << actual_result
                               CONTINUE v
                          [v.Final_name IN ["THIS", "this", "List_temps"]] ?
                               formal_p[] << v
                               actual_p[] << actual_this
                               CONTINUE v
                          [v.Is_param] ? CONTINUE v
                          ;
                          
                          add_v|ariable = {Var}(
                          		Line = 0,
                          		Type_ = v.Type_, 
                             	Is_array = v.Is_array,
                             	Is_fixed = v.Is_fixed, 
                             	In_fun_ = THIS, 
                             	Is_loop = v.Is_loop,
                             	Really_temp = TRUE,
                             	Declared_in_debug = v.Declared_in_debug,
                             	Count_ref = v.Count_ref),
                             	>> Local_var[]
                                     
                          v.Corresponding_ = add_v
                          CASE v.Final_name == "List_temps" ?
                               add_v.Set_final_name("List_temps")
                               
                          ELSE add_v.Set_final_name("i" 
                                     "" set_inline_index.Str 
                                     "_" v.Final_name 
                                     "_" comp(Parse).Next_copy_var_idx)
                                     
	                           FOR n IN v.Names[] :
	                               add_v.Names[] << n "_i" 
	                               "" set_inline_index.Str
	                           ;
                          ;
                          formal_p[] << v
                          
                          add_ex|pression_var = {Expr}(Operation = 'VAR',
                             Var_arg = add_v), OWNED BY THIS
                             
                          actual_p[] << add_ex
                          ----------------------- 'initialization of add_v'
                          CASE !add_v.Is_loop && (
                          	   add_v.Final_name != "List_temps")
                          	   ?
	                           init|_add_v = {Assign}(Function_ = THIS,
	                           	 Line = 0, Pos= 0, Level = Current_level,
	                          	 Dest = {Expr}(Operation = 'VAR',
	                          	 Var_arg = add_v),
	                          	 Source = None_const(add_v,
	                          	 comp(Parse))), OWNED BY THIS
	                           ins[] << init ;
                      ;
                      ------- 'default RESULT = ... if there are no statements'
                      //BOOL no_statements = a_f.Block[].Count == 0
                      //CASE no_statements && a_f.Result != NONE ?
                      CASE a_f.Result != NONE && !(
                           a_f.Block[0].{Assign}.Dest.Var_arg.Names[0]
                           =="RESULT")
                           ?
                           vres|ult_var = {Expr}(Operation = 'VAR', 
                           		Var_arg = {Var}(Names[] << "RESULT",
                           		Line = 0,
                           		Type_ = a_f.Result.Type_)),
                           		OWNED BY a_f
                           vres.Var_arg.Set_final_name("RESULT") 
                           CASE a_f.Result.Type_.Kind ?
                           ['BOOL']: def|ault_result = {Assign}(
                           		Function_ = a_f, Line = 0, Pos= 0,
                           		Level = Current_level,
                           		Dest = vres,
                           		Source = {Expr}(Operation = 'CONST',
                           		Var_arg = comp(Parse).FALSE_c)),
                           		>> a_f.Block[]
                           ['INT', 'ENUM', 'REAL']:
                                def = {Assign}(
                                Function_ = a_f, Line = 0, Pos= 0,
                                Level = Current_level,
                                Dest = vres,
                           		Source = {Expr}(Operation = 'CONST',
                           		Var_arg = comp(Parse).N0_c)),
                           		>> a_f.Block[]
                           ['STR']:
                                def = {Assign}(
                                Function_ = a_f, Line = 0, Pos= 0,
                                Level = Current_level,
                                Dest = vres,
                           		Source = {Expr}(Operation = 'CONST',
                           		Var_arg = comp(Parse).EMPTY_str)),
                           		>> a_f.Block[]
                           ['CLASS', 'STRUCTURE']:
                                def = {Assign}(
	                                Function_ = a_f, Line = 0, Pos= 0,
	                                Level = Current_level,
	                                Dest = vres,
	                           		Source = {Expr}(Operation = 'CONST',
	                           		Var_arg = comp(Parse).NONE_c,
	                           		Type_obj_ = a_f.Result.Type_)
                           		),
                           		>> a_f.Block[]
                           ;
                           a_f.Block[].Insert(0, a_f.Block[*])
                           a_f.Block[].Delete(a_f.Block[].Count-1)
                      ;
                      ------- 'replace statement at line to inlined statements'
                      CASE obtain_inlined_function_statements(
                           ins[], a_f.Block[], Line)
                           ?
                           -------------------- 'replace now'
                           FOR si IN ins[] :
                               B[].Insert(insert_pos, si) 
                               insert_pos += 1 ;
                           B[].Delete(Line)
                           RESULT = TRUE
                           
                      ELSE 
                           FOR i IN [Local_var[].Count-1 DOWNTO was_local_v] :
                           	   //DEBUG:
                           	   //CASE Local_var[i].Names[0] 
                           	   //     == "X__extr_tmp_286" ? >> ;
                           	   //;
                               Local_var[].Delete(i) ;
                      ;
                      -------------- 'remove added statement'
                      CASE a_f.Block[].Count == 0 && a_f.Result == NONE ?
                           a_f.Block[].Clear ;
                 ;
            ; 
		; .
            
		FUN None_const|ant(
		    {Var} Dest|ination_variable,
		    {Compiler} Comp|iler) ==> {Expr}, NEW
		    :
		    CASE Dest.Is_array ? ==> ;
		    CASE Dest.Type_.Kind ?
		    ['BOOL']: RESULT = {Expr}(Operation = 'CONST', 
					    Var_arg = Comp.FALSE_c), OWNED BY Dest
					    
		    ['INT', 'ENUM', 'REAL']:
			    RESULT = {Expr}(Operation = 'CONST',
					    Var_arg = Comp.N0_c), OWNED BY Dest
					    
		    ['STR']: RESULT = {Expr}(Operation = 'CONST',
					    Var_arg = Comp.EMPTY_str), OWNED BY Dest
					    
		    ['CLASS', 'STRUCTURE']: RESULT = {Expr}(
		    		Operation = 'CONST', Var_arg = Comp.NONE_c), OWNED BY Dest
		    ; .
		

            
        {Expr} actual_result
        INT temp_inline
        
        {Expr} debug_Expr
        
		FUN has_fields_not_objects(
			{Expr} E|xpression) ==> BOOL, RECURSIVE
			:
			CASE E.Operation ?
			['FIELD', 'VAR']: 
				RESULT = E.Type_expr.Kind !IN ['CLASS', 'STRUCTURE']
			['CONST', 'ARRAY', 'UNKNOWN']: RESULT = FALSE
			['AS']: RESULT = FALSE
			['BINARY', 'INDEX']:
				RESULT = E.Arg1_.has_fields_not_objects
				RESULT ||= E.Arg2_.has_fields_not_objects
				RESULT ||= E.Arg3_.has_fields_not_objects
			['INT2REAL', 'NOT_B', 'NOT', 'NEG']:
				RESULT = E.Arg1_.has_fields_not_objects
			['FUN', 'BASE_FUN', 'SYSTEM_FUN']: RESULT = TRUE
			['NEW_OBJ']: RESULT = TRUE
			; .
				    
            
        METHOD obtain_inlined_function_statements(
            {Statement} Dest|ination[],
            {Statement} Source|_block[],
            INT Line|_index) ==> BOOL, RECURSIVE
            :
            failed_copy_expr = FALSE
            FOR s IN Source[] :
                {Statement} d|estination_adding = NONE
                CASE s.{Assign} != NONE ?
                     {Assign} s_a|source_assignment = s.{Assign}
                     
                     a|ssign_dest = {Assign}(
                     	Line = Line, Pos= 0,
                     	Work = s.Work,
                     	Function_ = THIS,
                     	Level = Current_level), >> Keep_statements[]
                                
                     CASE s_a.Dest.Var_arg.Final_name == "RESULT" ?
                          a.Dest = Copy_expr(actual_result)
                     ELSE a.Dest = Copy_expr(s_a.Dest) ;
                     
                     CASE (a.Dest == NONE || (
                          a.Dest.Var_arg == comp(Parse).NONE_c)) && (
                          s.Work == 'ASSIGN') && (
                          s_a.Source.Operation IN ['VAR', 'FIELD', 'CONST'])
                          ?
                          ------------------- 'dummy statement'
                          CONTINUE s ;

                     a.Source = Copy_expr(s_a.Source)
                     
                     CASE s_a.Back_ != NONE ?
                          --------- 'back assign statement for PUSH'
                          b|ack_assignment = {Assign}(Line = 0, Pos= 0,
                          		Function_ = THIS, Level = Current_level),
                          		>> Keep_statements[]
                          		
                          a.Back_ = b
                          
                          a.Back_.{Assign}.Dest = Copy_expr(
                                s.{Assign}.Back_.{Assign}.Dest)
                                
                          a.Back_.{Assign}.Source = Copy_expr(
                                s.{Assign}.Back_.{Assign}.Source)
                     ;
                     CASE s_a.Source.Before_assign_[].Count > 0 ?
                     	  copy_before_assign_statements(a.Source, s_a.Source)
                     ;
                     d = a ;
                CASE s.{For} != NONE ?
                     for|_dest = {For}(Line = Line, Pos= 0, Work = s.Work, 
                            Function_ = THIS, Level = Current_level,
                            Downto = s.{For}.Downto, 
                            Breaked = s.{For}.Breaked,
                            Continued = s.{For}.Continued,
                            Unroll = s.{For}.Unroll,
                            Unroll_factor = s.{For}.Unroll_factor,
                            Loop_= s.{For}.Loop_.Corresponding_), 
                            >> Keep_statements[]
                            
                     s.{For}.Corresponding_ = for
                          
                     CASE s.{For}.Var != NONE ?
                          for.Var = s.{For}.Var.Corresponding_ ;
                     CASE s.{For}.Var != NONE && for.Var == NONE ?
                          Parse.Err("For loop variable was lost while "
                          "inlining"._Efor )
                     ;
                     for.Array = Copy_expr(s.{For}.Array)
                     for.Range1 = Copy_expr(s.{For}.Range1)
                     for.Range2 = Copy_expr(s.{For}.Range2)
                     d = for ;
                CASE s.{Case} != NONE ?
                     cas|e_dest = {Case}(Line = 0, Pos= 0, Work = s.Work,
                     		Top_case = s.{Case}.Top_case,
                            Function_ = THIS, Level = Current_level),
                            >> Keep_statements[]
                     cas.Condition = Copy_expr(s.{Case}.Condition)
                     cas.Range1 = Copy_expr(s.{Case}.Range1)
                     cas.Range2 = Copy_expr(s.{Case}.Range2)
                     FOR val IN s.{Case}.Values[] :
                         cas.Values[] << val ;
                     d = cas ;
                Dest[] << d
                d.Line = s.Line
                
                d.Inline_index = s.Inline_index
                	"i" set_inline_index.Str "_"
                     
                CASE s.Block_[].Count > 0 ?
                     CASE !obtain_inlined_function_statements(d.Block_[], 
                          s.Block_[], Line)
                          ?
                          ==> ;
                ;
                CASE d == NONE ?
                     Parse.Err("Can not copy statement while "
                     "inlining"._Ecannot4 ) ;
            ; 
            RESULT = !failed_copy_expr .
            
        FUN var_present_in_expr(
        {Expr} E|xpr_to_check, {Var} V|ar_to_find) ==> BOOL, RECURSIVE
        	:
        	CASE E == NONE ? ==> ;
        	CASE E.Var_arg == V ? RESULT = TRUE ==> ;
        	
        	RESULT = var_present_in_expr(E.This_, V)
        	RESULT ||= var_present_in_expr(E.Arg1_, V)
        	RESULT ||= var_present_in_expr(E.Arg2_, V)
        	RESULT ||= var_present_in_expr(E.Arg3_, V)
        	CASE RESULT ? ==> ;
        	
        	FOR it IN E.Items_[] :
        	    RESULT = var_present_in_expr(it, V)
        	    CASE RESULT ? ==> ;
        	; .
            
   		METHOD copy_before_assign_statements(
   			{Expr} Dest|ination_statement,
   			{Expr} Source|_statement)
   			:
			FOR st IN Source.Before_assign_[] :
			    CASE !obtain_inlined_function_statements(
			    	Dest.Before_assign_[], Source.Before_assign_[], st.Index)
			    	?
			    	==> ;
			    CASE failed_copy_expr ? ==> ;
			; .
            
        METHOD all_called_functions_in_import(
            {Statement} B|lock_of_stmt[]) ==> BOOL, RECURSIVE
            :
            FOR st IN B[] :
                CASE ?
                [st.{Assign} != NONE]?
                    {Assign} a|ssign_statement = st.{Assign}
                    RESULT = all_expr_in_import(a.Source) 
                    RESULT &&= all_expr_in_import(a.Dest)
                    
                [st.{Case} != NONE]?
                    {Case} c|ase_statement = st.{Case}
                    RESULT = all_expr_in_import(c.Condition)
                    RESULT &&= all_expr_in_import(c.Range1)
                    RESULT &&= all_expr_in_import(c.Range2)
                    RESULT &&= all_expr_in_import(c.Formatted)
                    
                [st.{For} != NONE]?
                    {For} f|or_statement = st.{For}
                    RESULT = all_expr_in_import(f.Array)
                    RESULT &&= all_expr_in_import(f.Range1)
                    RESULT &&= all_expr_in_import(f.Range2) ;
                CASE !RESULT ? ==> ;
                CASE st.Block_[].Count > 0 && !all_called_functions_in_import(
                     st.Block_[])
                     ?
                     RESULT = FALSE ==> ;
            ;
            RESULT = TRUE .
            
        METHOD all_expr_in_import(
            {Expr} E|xpression_to_check_in_import) ==> BOOL, RECURSIVE
            :
            CASE E == NONE ? RESULT = TRUE ==> ;
            RESULT = all_expr_in_import(E.Arg1_)
            RESULT &&= all_expr_in_import(E.Arg2_)
            RESULT &&= all_expr_in_import(E.Arg3_)
            RESULT &&= all_expr_in_import(E.This_)
            RESULT &&= all_expr_in_import(E.Array_)
            RESULT &&= all_expr_in_import(E.Owned_)
            CASE !RESULT ? ==> ;
            FOR it IN E.Items_[] :
                CASE !all_expr_in_import(it) ? RESULT = FALSE ==> ;
            ;
            CASE E.Operation != 'FUN' || E.Fun_.Class == NONE ? ==> ;
            RESULT = E.Fun_.Class IN comp(Parse).Current_class.Import_[]
            .
		
	   	-------------------- 'sheck for side effects'
	   	
	   	BOOL has_side_effects
	   	BOOL checking_now
	   	
	   	METHOD Has_side_effects ==> BOOL :
			CASE checking_now ? 
			     ==> ;
			PUSH checking_now = TRUE :
				 CASE has_side_effects ?
				      RESULT = TRUE ==> ;
				 
				 RESULT = Class.Compiler.Check_expressions_for_side_effects(
					 THIS, Block[])
					 
				 has_side_effects = RESULT ; .
				 
	   	METHOD Find_similar|_names(
	   	STR Base|_name, STR List|_similar[]) 
	   	    :
	   	    FOR m IN [1 TO 3] :
		   	    FOR v IN Local_var[] :
		   	        FOR n IN v.Names[] :
		   	        	CASE n IN List[] ? CONTINUE n ;
		   	        	PUSH Class.Max_diff= m :
		   	            	 CASE Class.Is_similar_to(n, Base, TRUE) ? 
		   	            	      List[] << n ;
		   	        	;
		   	        ;
		   	    ; 
		   	    CASE List[].Count > 1 ? ==> ;
	   	    ; .
	   	    
        */
    }
}
/*
END 
*/

