/*

//[diagram:AL-IV_compiler.dia]

CLASS {Compiler},
STOPPING, UNTESTED, RECURSIVE, BITWISE, INFINITE :

IMPORT: {File_path}, {Text_file}, {Console},
        {String_functions}, {System_functions}, {Mathematics}, {Date_time} ;

IMPORT: {Type}, {Text_parser}, {Parser}, {Variable}, {Expression}, {Function},
		{Statement}, {Assignment}, {Case}, {For}, {Generator} ;
IMPORT: {Localize_str}, {Log_html}, {Testing} ;

IMPORT: {Table} ;
IMPORT: {Version} ;

//IMPORT: {CCC_load} ;
//IMPORT: {CCC_load} ;

*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using AL4Compiler.Generate;
using AL4;


namespace AL4Compiler
{
    public class Compiler
    {
        /*
        -------------------------- 'common types' 
        {Type} TYPE_BOOL
        {Type} TYPE_BYTE
        {Type} TYPE_INT
        {Type} TYPE_REAL
        {Type} TYPE_STR
        {Type} TYPE_OBJ
        {Type} TYPE_ENUM
        -------------------------- 'common constants & var THIS'
		{Var} TRUE_c|onst
		{Var} FALSE_c|onst
        {Var} NONE_c|onst
        {Var} N0_c|onst
        {Var} N1_c|onst
        {Var} M1_c|onst
        ------------------------- 'expressions to use as 0 and 1'
        {Expr} e0|_constant_stored
        {Expr} e1|_constant_stored
        {Expr} em1|_constant_stored
        
        METHOD E0|_constant ==> {Expr} :
			CASE e0 == NONE ? e0 = {Expr}(Operation = 'CONST', Var_arg = N0_c) ;
			RESULT = e0 .
        
        METHOD E1|_constant ==> {Expr} :
			CASE e1 == NONE ? e1 = {Expr}(Operation = 'CONST', Var_arg = N1_c) ;
			RESULT = e1 .
			
        METHOD EM1|_constant ==> {Expr} :
			CASE e1 == NONE ? em1 = {Expr}(
				 Operation = 'CONST', Var_arg = M1_c) ;
			RESULT = em1 .
			
        {Expr} e_Max_int
			
        METHOD Max_int|_constant ==> {Expr} :
			CASE e_Max_int == NONE ?
			     e_Max_int = {Expr}(Operation = 'CONST', Var_arg = {Var}(
			     	Line= 0, Type_= TYPE_INT, Int_c= MAX_INT, 
			     	Is_const= TRUE))
			;
			RESULT = e_Max_int .
        
        {Var} EMPTY_str
        {Fun} TEST_f|unction_returns_true_on_test_stage
        -------------------------- 'THIS variable and expression'
        {Var} THIS_var
        {Expr} THIS_expr
        {Var} INFINITY_c|onst
        {Var} NAN_c|onst
        -------------------------- 'system functions'
        {Fun} SYSFUN_Index
        {Fun} SYSFUN_Len
        {Fun} SYSFUN_Count
        {Fun} SYSFUN_Name
        {Fun} SYSFUN_Find_str
        -------------------------- 'system array functions'
        {Fun} SYSFUN_Clear // but implement as A[].Delete(0, MAX_INT)
        {Fun} SYSFUN_Insert
        {Fun} SYSFUN_Delete
        {Fun} SYSFUN_Allocate
        {Fun} SYSFUN_Remove
        {Fun} SYSFUN_Find_item
        {Fun} SYSFUN_Swap
        -------------------------- 'conversions'
        {Fun} SYSFUN_Str
        {Fun} SYSFUN_RealStr
        {Fun} SYSFUN_BoolStr
        {Fun} SYSFUN_StrInt
        {Fun} SYSFUN_RealInt
        {Fun} SYSFUN_StrHex16
        {Fun} SYSFUN_Byte
        -------------------------- 'enumerations specific'
        {Fun} SYSFUN_EnumInt
        {Fun} SYSFUN_First
        {Fun} SYSFUN_Next
        {Fun} SYSFUN_Previous
        {Fun} SYSFUN_Last
        -------------------------- 'bit rotations'
        {Fun} SYSFUN_Shl
        {Fun} SYSFUN_Shr
        {Fun} SYSFUN_Rol
        {Fun} SYSFUN_Ror
        -------------------------- 'optimized sub-string comparisons'
        {Fun} SYSFUN_Compare_substrings
        {Fun} SYSFUN_Compare_substr1
    	-------------------------- 'special functions for STRUCTURE assigning'
    	{Fun} SYSFUN_Clone
    	{Fun} SYSFUN_Dismiss
        -------------------------- 'recognize enumeration'
        {Type} Enumeration_wait|ing_as_expression
        -------------------------- 'for recognize expressions'
        BOOL And_or_operations_present
        -------------------------- 'interpreter ignores tests!'
        BOOL Want_tests
        

        
        INT Debug_Attempt
        */
        public Type TYPE_BOOL;
        public Type TYPE_INT;
        public Type TYPE_REAL;
        public Type TYPE_STR;
        public Type TYPE_OBJ;
        public Type TYPE_ENUM;

        public Variable TRUE_c;
        public Variable FALSE_c;
        public Variable NONE_c;
        public Variable N0_c;
        public Variable N1_c;
        public Variable EMPTY_str;
        public Variable TEST_c;
        public Variable INF_c;
        public Variable THIS_var;
        public Variable NAN_c;

        public Expression THIS_expr;

        public Function SYSFUN_Index;
        public Function SYSFUN_Len;
        public Function SYSFUN_Count;
        public Function SYSFUN_Name;
        public Function SYSFUN_Find_str;

        public Function SYSFUN_Insert;
        public Function SYSFUN_Delete;
        public Function SYSFUN_Remove;
        public Function SYSFUN_Clear;
        public Function SYSFUN_Find_item;

        public Function SYSFUN_Str;
        public Function SYSFUN_RealStr;

        /*
        
        
        
        INT Total_temp_var|iables
        
		FUN get_command_line ==> STR :
			FOR i IN [0 TO Count_param-1] :
			    RESULT = RESULT Parameter(i) " " ;
			RESULT = RESULT.TrimR .
			
        INT total_constant_expr|ession_index_counter
        
		CONSTRUCT:
			//W_directory = Get_working_dir
		
			t|ype_temp = {Type}(Parse = {Parser}(Compiler_ = THIS,
				Class_ = NONE, Warning_80= Warning_80),
				Original_type_index = -1)
				
			t.Parse.Class_ = t
			Init_system_types(THIS)
			Init_const(t.Parse)
			----------------------- 'set console colors silver on black'
			Console_colors({colors}.'SILVER', {colors}.'BLACK') // does not work in LINUX
			Console_ANSI_colors(TRUE)
			Destination = "Compiled"
			
			---------------------- 'init some fields'
			Merge_continued_lines = TRUE
			.
			
		METHOD Allow_save_unlocalized ==> BOOL :
			RESULT = !Do_not_save_unlocalized .
			
        //------------------- 'for compiling code specific for FPC (free pascal)'
			
		-------------------- 'just for speedy check'
		
		INT want_report_leaks
		
		METHOD Want_report_leaks ==> BOOL :
			CASE want_report_leaks == 0 ?
			     CASE Defined_name[].Find("$REPORT_LEAKS") >= 0 ? 
			          want_report_leaks = 1
			     ELSE want_report_leaks = -1 ;
			;
			RESULT = want_report_leaks > 0 .
        
        ------------------- 'main compiling procedure'
        
		{Date_time}.{date_time} Time_start0|_of_compile
		{Date_time}.{date_time} Time_start_pre|compile
		{Date_time}.{date_time} Time_start_compile
		{Date_time}.{date_time} Time_start1|_of_build_final_version
		STR Executable|_path_of_created_executable
		{date_time} Time_finished|_creating_executable
		{colors} Back_color
		BOOL Rebuild_all
        
        METHOD Compile|_project :
            //DEBUG: << "++++++++++++++++++++++ Compile_project" #NL
            //<< Cc('RED') "parameters: " get_command_line Cc('SILVER') #NL ;
			Time_start0 = Now
            stop_html_log = FALSE
           	//Set_maximum_recursion(4096)
           	Set_maximum_recursion(1024)
           	//W_directory = Get_working_dir
           	//DEBUG: Total_csf = -1 ;
            ------------------------------ 'prepare to localize: directory'
            STR s_lang|uage_select[]
            STR p_lang|uage_files_path = Start_dir
            CASE ?
            [(p_lang "Compiler_language.cfg").Exists] ?
                 << "Localization configuration"._Mloc1 
                    ": " p_lang "Compiler_language.cfg" #NL 
                    
            ELSE p_lang = p_lang "..".Trailing_slash ;
            Set_directory_lang(p_lang)
			------------------------------ 'initialize console'
            Console_colors({colors}.'LIME', Back_color)
            
            << "AL/4 to " TARGET_LANG(THIS)
            << " compiler (C) 2016-2023 Vladimir Kladov" #NL
            STR vers|ion_in_Version_class = {Version}.Get
        	CASE vers != "" ? << vers #NL ;
            
            Console_colors({colors}.'SILVER', {colors}.'BLACK')
            ------------------------------ 'command line'
            Parse_command_line
			CASE "$COMPILER" IN Defined_name[] ?
			     Back_color = {colors}.'MAROON'
			;
            Console_colors({colors}.'SILVER', Back_color)
            CASE Errors_count > 0 ?
                << #NL
                << get_command_line #NL
                
                << @"Usage: AL4Compiler [/option]... filename"
                    "/err n        | /errors n"
                    "/warn n       | /warnings n"
                    "/warn80       | /warning80"
                    "/warn -style  | /warnings -style"
                    "/warn -index  | /warnings -indexing"
                    "/src_test path| /source_test path"
                    "/src path     | /source path"
                    "/src path\*   | /source path with subdirs recursively"
                    "/dst path     | /destination path"
                    "/prj name     | /project name"
                    "/ext ext      | /extension ext"
                    "/ext2 ext"
                    "/ext3 ext"
                    "/int32"     
                    "/v            | /verbose"
                    "/vv           | /verbose2"
                    "/f            | /final"
                    "/d            | /debug"
                    "/diag efl	   | /diagnostics except-functions-list"     
                    "/op +/-/flags | /optimizations +/-/flags"
                    "/noc          | /noconsole"
                    "/t +/-        | /testreport +/-"
                    "/t+SHOW       | /testreport+SHOW"
                    "/r            | /run"
                    "/param[param] | /parameters [param]"
                    "/@            | /at config"
                    "/ok           | /okwarnings"
                    "/okok         | /okerrors"
                    "/!autoinline"
                    "/!unroll"
                    "/!loc		   | /!localize or /do_not_localize"
                    "/!uloc		   | /!write_unlocalized"
                    "/!platform    | /!platform_dependent"
                    "/!max_desc {type},n"
                    "------------------------------------"
                    "efl: {Class1}.fun1,{Class2}.fun2,DC1,DC2"
                    "DCn=diagnostics code before colon in a diagnostic message"     
                    "" ==>
            ;
            ------------------------------ 'localize to the specified language'
            CASE !Do_not_localize ?
                 CASE Get_environment_var("AL4lang") != "" ?
                      s_lang[].Clear
                      s_lang[] << Get_environment_var("AL4lang")
                      //DEBUG: "ENV(AL4lang)=" s_lang[0] #NL ;
                 ELSE
		              p_lang = p_lang "Compiler_language.cfg"
		              Text_load(p_lang, s_lang[])
                      //DEBUG: "AL4lang not found, p_lang=" p_lang #NL ;
                 ;
	             FOR s IN s_lang[] :
	                 CASE s.Trim == "" || Starting(s, "#") ? CONTINUE s ;
	                 << "Localizing compiler messages, language"._Mloc2 " " s  #NL
	                 Localize(s, "E", Allow_save_unlocalized)
	                 Localize(s, "W", Allow_save_unlocalized)
	                 Localize(s, "M", Allow_save_unlocalized)
	                 //DEBUG:
	                 //<< "localized"._Mloc3 #NL
	                 ////Profiler_save_reset 
	                 //;
	             ;
            ;
            CASE Verbose ?
                 << "Compiler path"._Mcomp ": " Start_dir #NL ;
            -------------------------------------- 'collect classes'
            Delete_file(Destination.Trailing_slash "Compiler_messages.html")
            Collect_all_classes
            -------------------------------------- 'find {System_functions}'
            FOR c IN All_classes[] :
                CASE "{System_functions}" IN c.Names[] ?
                    {Type} sys|tem_functions_class = c
                    BREAK c ;
            ;
            //DEBUG: Console_color('LIME') 
            //       << "From Time_start0 to pre-compile: " 
            //       << Now.Seconds_diff(Time_start0).S_float(1) #NL
            //       Console_color('SILVER') ;
            Time_start_pre = Now
            -------------------------------------- 'pre-compile classes'
            CASE Errors_count == 0 ?
                 BOOL additional|_classes_should_be_called = TRUE
                 FOR a|ttempts_dummy IN [1 TO 200_000] :
                     INT n|umber_of_class = All_classes[].Count
                     FOR c IN All_classes[] :
                         CASE c.Compiled ? CONTINUE c ;
                         c.Handle_base ;
                     CASE n < All_classes[].Count ? CONTINUE a ;
                     FOR c IN All_classes[] :
                         CASE c.Compiled ? CONTINUE c ;
                         NONE = c.Precompile 
                     ;
                     CASE additional ? Additional_classes(THIS)
                     				   additional = FALSE ;
                     CASE n == All_classes[].Count ? BREAK a ;
                 ;
            ;
            //DEBUG: Console_color('LIME')
            //        << "from pre-compile to compile: "
            //        << Now.Seconds_diff(Time_start_pre).S_float(1) #NL
            //       Console_color('SILVER') ;
            Time_start_compile = Now
            {Generator} g|enerator_temp = Prepare_project_generator(THIS)
            -------------------------------------- 'compile classes'
            CASE Errors_count == 0 ?
                 FOR c IN All_classes[] : c.Correspond ;
                 ------------------------------------- 'tables on structures'
                 FOR c IN All_classes[] :
				 	 FOR table IN c.Table[] :
				 	     c.Ensure_table_compiled(table) ;
                 ;				 	 
                 ---------------------------- 'some names should not be used'
                 STR all_class_fin|al_names[]
                 FOR c IN All_classes[] :
                     Current_class = c
                     c.Make_final_names(all_class_fin[]) ;
                 FOR c IN All_classes[] :
                     Current_class = c
                     c.Calculate_const ;
                 FOR c IN All_classes[] :
                     Current_class = c
                     c.Check_surnamed_enums ;
                 FOR c IN All_classes[] :
                     CASE !Rebuild_all && !g.Need_compile(c) ?
                          STR path_loc = g.Output_path_class(c) ".localize"
                          CASE !path_loc.Exists ? CONTINUE c ;
                          c.Load_localizations(path_loc)     
                          CONTINUE c ;
                     //DEBUG: Console_color('LIGHT_BLUE') 
                     //   << "class need compile: " c.Names[0] #NL
                     //   Console_color('SILVER') ;
                     Current_class = c
                     CASE !c.Compiled ? c.Compile_code ;
                 ;
                 FOR c IN All_classes[] :
                     CASE !c.Compiled ? CONTINUE c ;
                     Current_class = c 
                     c.Check_dynamic_array_parameters ;
            ;
            ------------------------
            CASE Errors_count == 0 ?
                 -------------------------------------------- 'checks'
                 INT total_struc|ture_types_in_all_classes = 0
                 FOR c IN All_classes[] :
                     total_struc += c.Structures_[].Count ;
                 FOR c IN All_classes[] :
                     CASE !c.Compiled ? CONTINUE c ;
                     Current_class = c
                     FOR st IN c.Structures_[] :
                         c.Check_structure_recursive(st, total_struc) ;
                 ;
                 FOR c IN All_classes[] :
                     CASE !c.Compiled ? CONTINUE c ;
                     Current_class = c
                     c.Check_recursive ;
                 FOR c IN All_classes[] : c.Collect_ref ;
                 FOR c IN All_classes[] : c.Check_ref ;
                 FOR c IN All_classes[] :
                     CASE !c.Compiled ? CONTINUE c ;
                     FOR f IN c.Method[] :
                         f.Check_weak_arrays_passing ;
                 ;
            ;
            //DEBUG: Console_color('LIME')
            //       <<  "Compile classes ended for "
            //       << Now.Seconds_diff(Time_start_compile).S_float(1) #NL 
            //       Console_color('SILVER') ;
            CASE Errors_count > 0 ? ==> ;
            -------------------------------------- 'check Main'
            Current_class = All_classes[0]
            //DEBUG: << "methods count = " Current_class.Method[].Count.Str #NL ;
            FOR f IN Current_class.Method[] :
            	//DEBUG: << "searching main... f=" f.Names[0] #NL ;
                CASE "Main" IN f.Names[] ?
                     {Fun} main|_function = f
                     Current_class.Parse.Line = f.Line_start
                     BREAK f ;
            ;
            CASE ?
            [main == NONE] ?
                STR er|ror_message = "Function Main is not present in class"
                	""._Emain
                er = er All_classes[0].Whole_name
                er = er " (path " All_classes[0].Path ")"
                er = er ", classes count=" All_classes[].Count.Str
                	
                Error(er)
                 
            [!main.Modifiers['STATIC']] ?
                 Error("Main function must be static"._Emain2) ;
            ------------------- 'prepare code to calculate constant expressions'
            total_constant_expr = 1
            FOR c IN All_classes[] :
                FOR e IN c.Constant_expr[] :
                    CASE e.Operation != 'CONST' ?
                         e.Total_const = total_constant_expr
                         total_constant_expr += 1 ;
                ;
                FOR im IN c.Import_[] :
                    CASE "{System_functions}" == im.Names[0] ?
                         {Type} imp|orted_system_functions = im
                         BREAK im ;
                ;
                CASE imp == NONE ? c.Import_[] << sys ;   
                c.Create_constants_calc ;
            -------------------------------------- 'renumber all the functions'
            renumber_all_functions
            ---------- 'check expressions for side effects in functions called'
            FOR c IN All_classes[] :
                FOR f IN c.Method[] :
                    NONE = Check_expressions_for_side_effects(f, f.Block[]) ;
            ;
            -------------------------------------- 'generate code'
            //DEBUG: << "....................................................."
            //		  #NL "generate code: Errors_count=" Errors_count.S
            //		  " TEST_value=" TEST_value.S
            //		  " Need_any_tests(THIS)=" Need_any_tests(THIS).S #NL ;
            BOOL skip_tests|_stage = !Need_any_tests(THIS)
            //DEBUG:
            //      Console_color('RED')
            //      << "skip_tests=" skip_tests.S #NL 
            //      Console_color('SILVER') ;
            //{Generator} g|enerator_temp = Prepare_project_generator(THIS)
            //g.W_directory = W_directory
            //CASE Errors_count == 0 && (!TEST_value || !skip_tests) ?
            CASE Errors_count == 0 && !skip_tests ?
                 Current_class = NONE
                 --------------------------------- 'create test project'
                 PUSH TEST_value = TRUE :
                      //DEBUG:
                      //      FOR s IN Source_paths[]:
                      //          CASE s != Source_test_paths[s.Index] ?
                      //               << "source paths are different: "
                      //               "" s " != " Source_test_paths[s.Index] #NL
                      //               >> ;
                      //      ;
                      //;
                      ---------------- 'replace source paths/files for TEST'
                      STR save_source_paths[]
                      STR save_copy_files[]
                      FOR s IN Source_paths[] : save_source_paths[] << s ;
                      FOR s IN Copy_files[] : save_copy_files[] << s ;
                      Source_paths[].Clear
                      Copy_files[].Clear
                      FOR s IN Source_test_paths[] : Source_paths[] << s ;
                      FOR s IN Copy_files_test[] : Copy_files[] << s ;
                      ----------------------- 'generate/execute tests'
                 PUSH Destination = Destination.Trailing_slash "TEST$" :
                     PUSH path_log = "" :
                          FOR c IN All_classes[] :
                              CASE !c.Class_needs_testing
                              	   && g.Output_test_path_class(c).Exists
                              	   ?
                                   //DEBUG: "skip generating class " c.Names[0]
                                   //       " for testing"#NL ;
                                   CONTINUE c ;
                              At_least_1_class_need_testing = TRUE
                              CASE !c.Modifiers[
                                   'UNTESTED'] || (
                                   c.Test[].Count > 0)
                                   ?
                                   Want_tests = Tests_available ;
                                   
                              STR test_p|ath = Destination.Trailing_slash
                                  "" c.Final_name ".test"
                                  
                              Delete_file(test_path) 
                          ;
                          CASE Want_tests || "$ALLTESTS" IN Defined_name[] 
                               || At_least_1_class_need_testing
                               ?
                               //DEBUG: "create test project NOW -----------"#NL ;
                               CASE !Create_project(g, THIS) ?
                                    Error("Tests generation failed"
                                    ""._Etest) ==> ;
                          ;
                          CASE Want_tests || "$ALLTESTS" IN Defined_name[] ?
                               FOR c IN All_classes[] :
                                   c.Check_tested ;
                          ;
                     ;
                 ;
                      ------------------- 'restore source paths/copy files'
                      Source_paths[].Clear
                      Copy_files[].Clear
                      FOR s IN save_source_paths[] : Source_paths[] << s ;
                      FOR s IN save_copy_files[] : Copy_files[] << s ;
                 ;
                 CASE !skip_tests && !No_test_report ? do_test_report ;
                 CASE Errors_count > 0 ? ==> ;
                 CASE !skip_tests 
                 	  && !(Want_tests || "$ALLTESTS" IN Defined_name[])
                 	  && Tests_available
                 	  ? 
                      ==> ;
            ;
            //DEBUG: << "create final project" #NL ;
            --------------------------------------- 'create final project'
            //DEBUG: Console_color('LIME')
            //    << "Time from start0 to create final project: " 
            //    << Now.Seconds_diff(Time_start0).S_float(1) #NL 
            //    Console_color('SILVER')
            //    ;
            Time_start1 = Now
            FOR i IN [All_classes[].Count-1 DOWNTO 1]:
                CASE ?
                ["$INC" IN Defined_name[] 
                 || "$INCREMENTAL" IN Defined_name[]] ? CONTINUE i
                 
                //[All_classes[i].Not_for_test || (
                // All_classes[i].Translation_of_.Not_for_test)] ?
                //     CONTINUE i
                     
                [All_classes[i].Not_for_test] ?
                     CONTINUE i
                     
                [All_classes[i].Modifiers['NATIVE']] ? CONTINUE i
                ;
                CASE Verbose2 ?
                     << " -- removing class " 
                     << "" All_classes[i].Whole_name
                     << " --> " All_classes[i].Final_name
                     << "  still it is used only for tests !!!!!!!!!!!!"
                     << #NL
                ;
                All_classes[].Delete(i) ;
            CASE "a" IN Optimizations ?
                 load_and_apply_constants_calculated ;
            //DEBUG: << #NL#NL"---- call do_other_optimizations ----"#NL ;
            do_other_optimizations
            cascade_functions_flags
            CASE Verbose2 ?
                 << "List of classes to compile"._MListOfClasses ":" #NL
                 FOR c IN All_classes[] :
                     << "        " c.Whole_name 
                     << " --> " c.Final_name #NL ;
            ;
            PUSH TEST_value = FALSE :
                 renumber_all_functions
                 warn_untested_classes
                 BOOL untested_warned = TRUE
	             ----------------- 'CREATE PROJECT NOW!!!!!!!!!!!!!!!!'
                 CASE ?
                 [!Create_project(g, THIS)] ?
                      Error("Project generation failed"._Eproj) ==>
                      
                 ["$TARGET" IN Defined_name[]
                  && "$TEST_IN_WINDOWS" IN Defined_name[]] ? 
                      ==>
                 ;
                 CASE Executable != "" && !Executable.Exists ?
                      Error("Executable file was not created"._Eexecutable
                      ": [" Executable "]") ;
            ;

            CASE !untested_warned ? warn_untested_classes ;
            -------------------- 'free memory'
            All_classes[].Clear .
            
    BOOL At_least_1_class_need_testing
            
        METHOD warn_untested_classes :
          ---------------------- 'warning about UNTESTED classes'
          << ".............." #NL
          Current_class = NONE
          STR unt|ested_classes[]
          FOR c IN All_classes[] :
              CASE c.Modifiers['UNTESTED'] ?
                   unt[] << c.Names[*]
                   STR u|ntested_list = u c.Whole_name ", " ;
          ;
          CASE u != "" ?
               u = u.[0 TO *-2]
               Warning("UNTESTED classes are used"._Wuntest
               		" (" u ")") ;
          ---------------------- 'warnings for not safe classes'
          u = ""
          FOR c IN All_classes[] :
              CASE c.Names[*] IN unt[] ? CONTINUE c ;
              CASE !c.Modifiers['SAFE'] ?
                   u = u c.Names[*] ", " ;
          ;
          CASE u != "" ?
               u = u.[0 TO *-2] 
               Warning("UNSAFE classes are used"._Wunsafe " (" u ")") 
          ; .
            
            
        BOOL Has_LIMIT_FUNC
        BOOL Has_LIMIT_LOOPS
            
        METHOD cascade_functions_flags :
			FOR pass|dummy IN [0 TO All_classes[].Count] :
				INT found|_count = cascade_all_deleting_fun 
				CASE found == 0 ? ==> ;
			; .
			
        METHOD cascade_all_deleting_fun ==> INT :
			FOR c IN All_classes[] :
			    FOR f IN c.Method[] :
			        CASE f.Is_deleting_obj ? CONTINUE f ;
			        FOR cf IN f.Call_functions_[] :
			            CASE !cf.Is_deleting_obj ? CONTINUE cf ;
		                f.Is_deleting_obj = TRUE
		                RESULT += 1
			        ;
			    ;
			; .
	
            
		{Type} Changed_classes[]
			
		FUNCTION structure_match(
			{Type} R1|_structure, {Type} R2|_structure) ==> BOOL, RECURSIVE
			:
			CASE R1.Field[].Count != R2.Field[].Count ?
			     //DEBUG: << "count fields: " R1.Field[].Count.S 
			     //		   " <> " R2.Field[].Count.S #NL ;
			     ==> ;
			FOR f IN R1.Field[] :
				{Var} aF|ield_from_R2 = R2.Field[f.Index] 
			    CASE ?
			    [f.Names[0] != aF.Names[0]] ?
			         //DEBUG: << "names(" f.Index.S "): [" f.Names[0] 
			         //		   "]<>[" aF.Names[0] "]" #NL ; 
			         ==>
			    [f.Type_.Kind != aF.Type_.Kind] ?
			         //DEBUG: << "kinds(" f.Index.S "): [" f.Type_.Kind.Name 
			         //		   "]<>[" aF.Type_.Kind.Name "]" #NL ; 
			         ==>
			    [f.Type_.Kind == 'CLASS' && f.Type_ != aF.Type_] ? 
			         //DEBUG: << "object types(" f.Index.S "): [" f.Type_.Names[0] 
			         //		   "]<>[" aF.Type_.Names[0] "]" #NL ; 
			         ==>
			    [f.Type_.Kind == 'STRUCTURE'] ?
			         CASE !structure_match(f.Type_, aF.Type_) ? 
			              ==> ;
				;
			;
			RESULT=TRUE .

			        
   		FUNCTION redirect_var_class(
   			{Var} V|ariable_to_redirect_class,
   			{Type} Old|_class, {Type} New|_class)
   			:
   			CASE ?
		        [V.Type_ == Old] ? V.Type_ = New
		        [V.Type_.Kind IN ['STRUCTURE', 'ENUM'] && V.Type_.Base_ == Old]
		        	? 
		        	{Type} t|ype_to_replace 
		        			= New.Find_type(V.Type_.Base_.Names[0])
		        			
		        	V.Type_.Base_ = t ; .

		METHOD redirect_structure(
			{Type} St|ructure_type_to_redirct,
			{Type} Old|_class, {Type} New|_class), RECURSIVE
			:
			FOR v IN St.Field[] :
			    CASE v.Type_.Kind == 'STRUCTURE' ?
			         redirect_structure(v.Type_, Old, New)
			    ELSE redirect_var_class(v, Old, New) ;
			; .

        METHOD Init_const|ants({Parser} Parse|_of_source):
            --------------------------- 'shortcut for compiler'
            {Compiler} c|ompiler_shortcut = THIS
            --------------------------- 'TRUE, FALSE, NONE, 0, 1, "", TEST'
			c.TRUE_c = {Var}(Is_const = TRUE, Type_ = c.TYPE_BOOL,
			    Constant_value = "true", Int_c = 1, Line = -1)
                
			c.FALSE_c = {Var}(Is_const = TRUE, Type_ = c.TYPE_BOOL,
			    Constant_value = "false", Line = -1)
                
            c.NONE_c = {Var}(Is_const= TRUE, Type_= c.TYPE_OBJ,
                Constant_value = "NONE", Line = -1)
                
            c.N0_c = {Var}(Is_const = TRUE, Type_ = c.TYPE_INT, 
                Constant_value = "0", Line = -1)
                
            c.N1_c = {Var}(Is_const = TRUE, Type_ = c.TYPE_INT, 
                Constant_value = "1", Int_c = 1, Line = -1)
                
            c.M1_c = {Var}(Is_const = TRUE, Type_ = c.TYPE_INT, 
                Constant_value = "1", Int_c = -1, Line = -1)
                
            c.EMPTY_str = {Var}(Is_const = TRUE, Type_ = c.TYPE_STR,
                Constant_value = #QU #QU, Line = -1)
            ------------------------------------------- 'to check is TEST now'
            c.TEST_f = {Fun}(Names[] << "TEST", Parse = Parse,
                Is_system = TRUE, A_Name_1 = "TEST", 
                Result = {Var}(Type_ = c.TYPE_BOOL, Line = -1),
                Modifiers['STATIC'] = TRUE)
            ---------------------------------------------- 'THIS'
            c.THIS_var = {Var}(Type_ = c.TYPE_OBJ, Names[] << "THIS",
                Constant_value = "this", Line = -1)
                
            c.THIS_var.Set_final_name("this")
            c.THIS_expr = {Expr}(Operation = 'VAR', Var_arg = c.THIS_var)
            
            c.INFINITY_c = {Var}(Type_ = c.TYPE_REAL, Names[] << "INF" <<
                "INFINITY", Line = -1, Real_c = INF, Is_const= TRUE)
                
            c.INFINITY_c.Set_final_name("INF")
            
            c.NAN_c = {Var}(Type_ = c.TYPE_REAL, Names[] << "NAN", Line = -1,
            	Real_c = NAN, Constant_value = "Double.NaN", Is_const= TRUE)
            	
            c.NAN_c.Set_final_name("Double.NAN")
            ---------------------------------------------- 'SYSTEM functions'
            c.SYSFUN_Index = {Fun}(Names[] << "Index", A_Name_1 = "Index",
            	Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
            	Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                System_fun = 'SYSFUN_Index', Modifiers['STATIC'] = TRUE)
                
            c.SYSFUN_Len = {Fun}(Names[] << "Len" << "Length", A_Name_1 = "Len",
                Is_system = TRUE, Param[] << {Var}(Type_ = c.TYPE_STR,
                Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Parse = Parse, Modifiers['STATIC'] = TRUE,
                System_fun = 'SYSFUN_Len')
                
            c.SYSFUN_Count = {Fun}(Names[] << "Count", A_Name_1 = "Count",
                Is_system = TRUE, Param[] << {Var}(Is_array = TRUE,
                Is_fixed= TRUE, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Parse = Parse, Modifiers['STATIC'] = TRUE,
                System_fun = 'SYSFUN_Count'), OWNED BY c
                
            c.SYSFUN_Name = {Fun}(Names[] << "Name", Parse = Parse,
            	A_Name_1 = "Name", Is_system = TRUE,
                Param[] << {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Result = {Var}(Type_ = c.TYPE_STR, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Name')
                
            c.SYSFUN_Find_str = {Fun}(Parse = Parse,
                Names[] << "Find" << "Find_string", A_Name_1 = "Find",
                Is_system = TRUE, Param[] << {Var}(Type_ = c.TYPE_STR,
                Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_STR, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Find_str')
                
            c.SYSFUN_Find_str.Set_final_name("Find_str")
            ----------------------------------------- 'array functions'
            c.SYSFUN_Insert = {Fun}(Names[] << "Insert", Parse = Parse,
                Is_system = TRUE, A_Name_1 = "Insert",
                Param[] << {Var}(Is_array = TRUE, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Insert')
                
            c.SYSFUN_Delete = {Fun}(Names[] << "Delete", A_Name_1 = "Delete",
            	Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Is_array = TRUE, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Delete')
                
            c.SYSFUN_Allocate = {Fun}(Names[] << "Allocate",
            	A_Name_1 = "Allocate",
            	Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Is_array = TRUE, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Allocate')
                
            c.SYSFUN_Remove = {Fun}(Names[] << "Remove", A_Name_1 = "Remove",
            	Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Is_array = TRUE, Line = -1),
                Param[] << {Var}(Type_ = NONE, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Remove')
                
            c.SYSFUN_Clear = {Fun}(Names[] << "Clear", A_Name_1 = "Clear",
            	Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Is_array = TRUE, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Clear')
                
            c.SYSFUN_Find_item = {Fun}(Parse = Parse, Is_system = TRUE, 
                Names[] << "Find" << "Find_item", A_Name_1 = "Find",
                Param[] << {Var}(Is_array= TRUE, Is_fixed= TRUE, Line = -1),
                Param[] << {Var}(Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Find_item')
                
            c.SYSFUN_Swap = {Fun}(Parse = Parse, Is_system = TRUE,
                Names[] << "Swap" << "Swap_items", A_Name_1 = "Swap",
                Param[] << {Var}(Is_array= TRUE, Is_fixed= TRUE, Line= -1),
                Param[] << {Var}(Line = -1, Type_ = c.TYPE_INT),
                Param[] << {Var}(Line = -1, Type_ = c.TYPE_INT),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Swap')
            ------------------------------------------ 'conversion functions'
            c.SYSFUN_Str = {Fun}(Names[] << "Str" << "S", A_Name_1 = "Str",
            	Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
            	Result = {Var}(Type_ = c.TYPE_STR, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Str')
                
            c.SYSFUN_Str.Set_final_name("Str")
            
            c.SYSFUN_RealStr = {Fun}(Names[] << "Str" << "S" << "Sreal",
            	A_Name_1 = "Str", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_REAL, Line = -1),
            	Result = {Var}(Type_ = c.TYPE_STR, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_RealStr')
                
            c.SYSFUN_RealStr.Set_final_name("Str")
            
            c.SYSFUN_BoolStr = {Fun}(Names[] << "Str" << "S" << "Sbool",
            	A_Name_1 = "Str", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_BOOL, Line = -1),
            	Result = {Var}(Type_ = c.TYPE_STR, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_BoolStr')
                
            c.SYSFUN_BoolStr.Set_final_name("Str")
            ----------------- 'to number from Str:'
            c.SYSFUN_StrInt = {Fun}(Names[] << "Int" << "Integer_from_string",
            	A_Name_1 = "Int", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_STR, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_StrInt')
                
            c.SYSFUN_StrInt.Set_final_name("Int")
            
            c.SYSFUN_RealInt = {Fun}(Names[] << "Int" << "Integer",
            	A_Name_1 = "Int", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_REAL, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_RealInt')
                
            c.SYSFUN_RealInt.Set_final_name("RealAsInt")
            
            c.SYSFUN_StrHex16 = {Fun}(Names[] << "StrHex16",
            	A_Name_1 = "StrHex16", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_STR, Line = -1),
                Result = {Var}(Type_ = c.TYPE_STR, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_StrHex16')
                
            c.SYSFUN_StrHex16.Set_final_name("StrHex16")
        	-------------------------- 'enumerations functions'
            c.SYSFUN_First = {Fun}(Names[] << "First", A_Name_1 = "First",
                Parse = Parse, Is_system = TRUE,
                Param[] << {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Result = {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_First')
                
            c.SYSFUN_Last = {Fun}(Names[] << "Last", A_Name_1 = "Last",
                Parse = Parse, Is_system = TRUE,
                Param[] << {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Result = {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Last')
                
            c.SYSFUN_Next = {Fun}(Names[] << "Next", A_Name_1 = "Next",
                Parse = Parse, Is_system = TRUE,
                Param[] << {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Result = {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Next')
                
            c.SYSFUN_Previous = {Fun}(Names[] << "Prev" << "Previous",
            	A_Name_1 = "Prev", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Result = {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Previous')
            ----------------------------------------------- 'dummy functions'
            c.SYSFUN_EnumInt = {Fun}(Names[] << "EnumAsInt",
            	A_Name_1 = "EnumAsInt", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_ENUM, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_EnumInt')
                
            c.SYSFUN_EnumInt.Set_final_name("EnumAsInt")
            
            c.SYSFUN_Byte = {Fun}(Names[] << "IntToByte",
            	A_Name_1 = "IntToByte", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Result = {Var}(Type_ = c.TYPE_BYTE, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Byte')
                
            //c.SYSFUN_Byte.Set_final_name("IntToByte")
            ----------------------------------------- 'bit rotation functions'
            c.SYSFUN_Shl = {Fun}(Names[] << "ShiftL" << "ShiftLeft",
            	A_Name_1 = "ShiftL", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1), 
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Shl')
                
            c.SYSFUN_Shl.Set_final_name("ShiftLeft")
            
            c.SYSFUN_Shr = {Fun}(Names[] << "ShiftR" << "ShiftRight",
            	A_Name_1 = "ShiftR", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Shr')
                
            c.SYSFUN_Shr.Set_final_name("ShiftRight")
            ---------------- 'rol, ror'
            c.SYSFUN_Rol = {Fun}(Names[] << "RotateL" << "RotateLeft",
            	A_Name_1 = "RotateL", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, System_fun = 'SYSFUN_Rol')
                
            c.SYSFUN_Rol.Set_final_name("RotateLeft")
            
            c.SYSFUN_Ror = {Fun}(Names[] << "RotateR" << "RotateRight",
            	A_Name_1 = "RotateR", Parse = Parse, Is_system = TRUE,
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
            	Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                Modifiers['STATIC'] = TRUE, Final_name = "RotateRight",
                System_fun = 'SYSFUN_Ror')
                
            c.SYSFUN_Ror.Set_final_name("RotateRight")
            -------------------------------- 'optimized sub-string comparisons'
            c.SYSFUN_Compare_substrings = {Fun}( Is_system = TRUE,
            	Names[] << "CompareSubstrings",
            	A_Name_1 = "CompareSubstrings",
            	Parse = Parse, Modifiers['STATIC'] = TRUE, 
                Param[] << {Var}(Type_ = c.TYPE_STR, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_STR, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                System_fun = 'SYSFUN_Compare_substrings')
                
            c.SYSFUN_Compare_substrings.Set_final_name("CompareSubstrings")
            
            c.SYSFUN_Compare_substr1 = {Fun}( Is_system = TRUE,
            	Names[] << "CompareSubstr1",
            	A_Name_1 = "CompareSubstr1",
                Parse = Parse, Modifiers['STATIC'] = TRUE, 
                Param[] << {Var}(Type_ = c.TYPE_STR, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_INT, Line = -1),
                Param[] << {Var}(Type_ = c.TYPE_STR, Line = -1),
                Result = {Var}(Type_ = c.TYPE_INT, Line = -1),
                System_fun = 'SYSFUN_Compare_substr1')
                
            c.SYSFUN_Compare_substr1.Set_final_name("CompareSubstrWithStr")
        	------------------------------- 'STRUCTURE functions'
            c.SYSFUN_Clone = {Fun}( Is_system = TRUE,
            	A_Name_1 = "Clone", Names[] << "Clone",
                Parse = Parse, Modifiers['STATIC'] = TRUE, 
                Param[] << {Var}(Line = -1),
                Result = {Var}(Line = -1),
                System_fun = 'SYSFUN_Clone')
        	
            c.SYSFUN_Dismiss = {Fun}( Is_system = TRUE,
            	A_Name_1 = "Dismiss", Names[] << "Dismiss",
                Parse = Parse, Modifiers['STATIC'] = TRUE, 
                Param[] << {Var}(Line = -1),
                Result = {Var}(Line = -1),
                System_fun = 'SYSFUN_Dismiss')
            .

	
            
		METHOD renumber_all_functions:
			INT global_n|umber_counter = 0
            FOR c IN All_classes[]:
                FOR f IN c.Method[]:
                    CASE f.Final_name == "-" ? CONTINUE f ;
                    global_n += 1
                    f.Global_n = global_n ;
            ; .

            

            
		FUNCTION StrZ|ero_leading(
			INT N|umber_to_convert, INT D|igits_count) ==> STR
			:
			RESULT = N.Str
			FOR i|dummy IN [RESULT.Len+1 TO D] :
			    RESULT = "0" RESULT ; .
        
        */
        public List<string> All_localize_n  = new List<String>();
        public List<Expression> All_localize_s = new List<Expression>();
        
        public void collect_localized_strings()
        {
            for (int i= 0; i < All_classes.Count; i++)
            {
                Type c = All_classes[i];
                if (c.Localize_n.Count == 0) continue;
                All_localize_n.Add(c.Names[0]);
                All_localize_n.Add(null);
                for (int j = 0; j < c.Localize_s.Count; j++)
                {
                    Expression ex = c.Localize_s[j];
                    ex.Localize_i = All_localize_n.Count;
                    All_localize_n.Add(c.Localize_n[j]);
                    All_localize_s.Add(ex);
                }
            }
        }
        
        /*
                 
        METHOD do_test_report :
            STR test_app|lication_path = Get_environment_var("AL4_TEST_REPORT")
            //DEBUG :
            //<< test_app >> STR in|_test_app
            //;
            CASE test_app == "" ?
                 CASE "$LINUX" IN Defined_name[] || "$MAC" IN Defined_name[] ?
                      test_app = Decode_env("%AL%/AL4/Tools/Test_report/")
                 ELSE test_app = Decode_env("%AL4%\AL4\Tools\Test_report\")
                 	  STR exe_ext|ension = ".exe"
                 ;
                 //DEBUG: << "decoding %AL%: " test_app #NL 
                 //		>> STR dummy_input ;
                 CASE !(test_app "Test_report.exe").Exists ?
                      test_app = test_app "Compiled\" ;
            ;
            CASE "linux" IN Platform_info.Lower ? ==> ;
            test_app = test_app.Trailing_slash "Test_report" exe_ext
            CASE ! test_app.Exists ?
                 Warning("Application"._Wapp " " test_app 
                 " " ("was not found - report was not created"._Wwasnot ))
                 ==> ;
            CASE Test_report_show ?
                 NONE = Execute_program(test_app, Destination, 1) 
                 STR index|_path = Destination.Trailing_slash "TEST$\index.html"
                 CASE index.Exists ?
                      NONE = Execute_program(index, "", 0) ;
            ELSE NONE = Execute_program(test_app, Destination, 0) ; .
                 
        METHOD load_and_apply_constants_calculated :
            ------------------------------- 'load values for all classes'
            STR val|ues_claculated[]
            FOR c IN All_classes[] :
                STR path|_constants_calculated = Destination.Trailing_slash
                "TEST$\" c.Final_name ".constants"
                loader|_temp = {Text_file}(Path = path)
                STR lines|_from_constants_file[]
                lines[].Clear
                NONE = loader.Load_strings(lines[])
                FOR i IN [0 TO lines[].Count-2] :
                    CASE i % 2 == 1 ? CONTINUE i ;
                    INT n|umber_of_constant INDEXING STR
                    n = string_to_int(lines[i])
                    FOR j|dummy IN [val[].Count TO n] :
                        val[] << "" ;
                    val[n] = "=" lines[i + 1] ;
            ;
            ------------------------------- 'apply loaded values'
            FOR c IN All_classes[] :
                FOR e IN c.Constant_expr[] :
                    n = e.Total_const
                    CASE e.Total_const == 0 || val[n] == "" ?
                         CONTINUE e ;
                    STR const|ant_value = val[n].[1 TO *]
                    
                    v|ariable_representing_constant = {Var}(
                    	Line = -1,
                        Type_ = e.Type_expr), OWNED BY c
                        
                    CASE v.Type_.Kind ?
                    ['BOOL', 'INT', 'ENUM']: v.Int_c = string_to_int(const)
                    ['REAL']: v.Real_c = string_to_real(const)
                    ['STR']: v.Str_c = hex_to_string(const)
                    ['CLASS', 'STRUCTURE']: CONTINUE e ;
                    e.Calculated = TRUE
                    e.Operation = 'CONST'
                    e.Var_arg = v ;
            ; 
            .
            
            
        //FUN string_to_bool( STR S|tring_constant ) ==> BOOL :
        //    CASE S == "TRUE" ? RESULT = TRUE ; .
            
            
            
        FUN string_to_int|eger( STR S|tring_parameter ) ==> INT :
            CASE S.[0] ?
            ["-"]: BOOL neg|ative_value = TRUE
                   INT scan|_from_index = 1
            ["+"]: scan = 1 ;
            FOR j INDEXING STR IN [scan TO S.Len-1] :
                CASE S.[j] IN "0123456789" ?
                     RESULT = RESULT * 10 + S.[j].Ord - "0".Ord ;
            ;
            CASE neg ? RESULT = -RESULT ; .
            
            
            
        FUN string_to_real( STR S|tring_parameter ) ==> REAL :
            CASE S.[0] ?
            ["-"]: BOOL neg|ative_value = TRUE
                   INT scan|_from_index = 1
            ["+"]: scan = 1 ;
            INT stop_p|osition = S.Len
            FOR j INDEXING STR IN [scan TO S.Len-1] :
                CASE S.[j] IN "0123456789" ?
                     RESULT = RESULT * 10 + S.[j].Ord - "0".Ord
                ELSE stop_p = j
                     BREAK j ;
            ;
            CASE S.[stop_p] == "." ?
                 stop_p = S.Len
                 REAL m|ultiplier = 1
                 FOR j INDEXING STR IN [stop_p + 1 TO S.Len-1] :
                     CASE S.[j] IN "0123456789" ?
                          m /= 10
                          RESULT = RESULT + (S.[j].Ord - "0".Ord) * m
                     ELSE stop_p = j
                          BREAK j ;
                 ;
            ;
            CASE S.[stop_p] IN "Ee" ?
                 INT exp|onent = string_to_int(S.[stop_p+1 TO *])
                 RESULT = RESULT * {Mathematics}.Power(10, exp) ;
            CASE neg ? RESULT = -RESULT ; .
            
            
        FUN hex_to_string( STR Hex|adecimals_string_4digits_per_char ) ==> STR :
            FOR i IN [0 TO Hex.Len / 4 - 1] :
                INT char|_value = 0
                FOR j IN [i*4 TO i*4+3] :
                    CASE Hex.[j] IN "0123456789" ?
                         char = char * 16 + Hex.[j].Ord - "0".Ord
                    ELSE char = char * 16 + Hex.[j].Ord - "A".Ord + 10 ;
                ;
                RESULT = RESULT char.Char ; .
            
            
        */
        public void Compile()
        {
            Type T = new Type();
            T.Parse = new Parser();
            T.Parse.Compiler_ = this;
            T.Parse.Class_ = T;
            Type.Init_system_types(this);
            Variable V = new Variable(this);
            V.In_class_ = T;
            V.Line = 0;
            V.Init_constants();
            Console.WriteLine("AL/4 to " + Generator.TARGET_LANG + 
                " compiler (C) 2016 Vladimir Kladov");
            Parse_command_line();
            if (Errors_count > 0)
            {
                Console.WriteLine();
                Console.WriteLine("Usage: ALIV [/option]... filename");
                Console.WriteLine("/err n      | /errors n");
                Console.WriteLine("/warn n     | /warnings n");
                Console.WriteLine("/src parth  | /source path");
                Console.WriteLine("/dst path   | /destination path");
                Console.WriteLine("/prj name   | /project name");
                Console.WriteLine("/ext ext    | /extension ext");
                Console.WriteLine("/v          | /verbose");
                return;
            }
            collect_all_classes();
            if (Errors_count == 0)
            {
                for (int i = 0; i < All_classes.Count; i++)
                {
                    Type c = All_classes[i];
                    c.Precompile();
                }
                foreach (Type c in All_classes)
                    c.Correspond_types();
                List<string> All_class_final_names = new List<string>();
                foreach (Type c in All_classes)
                    c.Make_final_names(All_class_final_names);
                foreach (Type c in All_classes)
                    c.Calculate_const();
                foreach (Type c in All_classes)
                    c.Check_surnamed_enums();
                foreach (Type c in All_classes)
                    if (!c.Compiled)
                        c.Compile();
                foreach (Type c in All_classes)
                    c.Check_recursive();
                foreach (Type c in All_classes)
                    c.Collect_ref();
                foreach (Type c in All_classes)
                    c.Check_ref();
            }
            //----------------------------------- 'check main'
            Function main_f = null;
            if (All_classes.Count > 0)
            {
                Current_class = All_classes[0];
                foreach (Function f in All_classes[0].Method)
                {
                    if (f.Names.Contains("Main"))
                    {
                        main_f = f;
                        Current_class.Parse.Line = f.Line_start;
                        break;
                    }
                }
            }
            if (main_f == null && All_classes.Count > 0)
                Error("Function Main is not present in class " + All_classes[0].Name());
            if (main_f != null && !main_f.Modifiers[(int)Function.Fun_mod.STATIC])
                Error("Main function must be static");
            //---------------------------------- 'generate code'
            if (Errors_count == 0)
            {
                bool save_Test_c = TEST_c.Bool_c;
                string save_dest = Destination;
                try
                {
                    TEST_c.Bool_c = true;
                    Destination = StringFunctions.Trailing_slash(Destination) + "TEST$";
                    bool want_test = false;
                    foreach (Type c in All_classes)
                    {
                        if (!c.Modifiers[(int)Type.Class_mod.UNTESTED])
                            want_test = true;
                        string test_path = StringFunctions.Trailing_slash(Destination) +
                            c.Final_name + ".test";
                        if (File.Exists(test_path))
                            File.Delete(test_path);
                    }
                    if (want_test)
                    {
                        if (!Generator.Create_project(this))
                        {
                            Console.WriteLine("Tests generation failed");
                            return;
                        }
                        foreach (Type c in All_classes)
                            c.Check_tested();
                    }
                }
                finally { 
                    TEST_c.Bool_c = save_Test_c;
                    Destination = save_dest;
                }
                if (Errors_count > 0) return;
                if (!Generator.Create_project(this))
                {
                    Console.WriteLine("Project generation failed");
                    return;
                }
            }
        }

        /*
        ------------------------- 'options'
        STR Ext|ension = ".AL4"
        STR Ext2|_second = ".AL4"
        STR Ext3|_third = ".AL4"
        INT Max_err|ors = 5
        INT Max_warn|ings = 1000
        BOOL Warning_80
        ---------------------------- '/final ?'
        BOOL Final|_code
        ---------------------------- '/debug ?'
        BOOL Debugging|_code
        ---------------------------- '/diagnostics ?'
        BOOL Diagnostics|_mode
        BOOL Diagnostics_light
        STR Diag_except|_classes_list[]
        ---------------------------- '/t [+]/-/SHOW'
        BOOL No_test_report
        BOOL Test_report_show
        ---------------------------- '/op +/-/flags'
        STR Optimizations|_flags
        BOOL Local_optimizations|_only
            // g V0 - remove local variables not used
            // a V1 - calculate constant expressions, replace it by calculated values
            // j V2 - remove first assignment overridden by the next to the same var
            // + V3 - remove duplicated Clears for the same array variable
            // + V4 - unite several assignments to the same variable (=, +=, -=, ...)
            // + V5 - reuse local variables of same type and array dimension
            
            // + C0 - remove case header for no branches
            // b C1 - CASE const ? replace with a branch only correspond to a true condition
            
            // e F0 - remove FOR-loop, not containing any code in a body,
            // c F1 - remove a header of a FOR loop in case a single step only,
            // d F2 - remove entire FOR-loop which is never executing,
            // .-- F3 - unroll FOR loop executing <= 100 fixed statements 
            // .-- F4 - unroll FOR loop by several sequential loops
            
            // ? P0 - remove PUSH blocks having no body
            
            // h E0 - remove calls to functions which do nothing and do not return values,
            // i    - replace calls to functions returning constant values to that constants,
            // k E1 - replace call to functions only returning an expression
            // l E2 - replace call to final method only returning an expression
            // .-- E3 - replace call to native function to inline of it
            
            // m I1 - replace call to functions having <= 3 statements or rarely called
            // n I2 - replace call to final method (of same class)
            // .-- I3 - inline native function calls
            
            // f R0 - remove code which is not reachable,
            // o R1 - remove static functions which are never called,
            // p-- R2 - remove native functions which are never called,
            // q.. R3 - remove final methods which are never called,
            // r.. R4 - remove classes which are not actually used.
            
            // .-- S1 - separate functions by constant parameters
        ------------------------- 'defined $vars'
        STR Defined_name|s[]
        STR Defined_value|s[]
        ------------------------- 'messaging'
        BOOL Verbose|_mode
        BOOL Verbose2|_mode
        BOOL Verbose3|_mode
        BOOL Noconsole|_if_true_console_is_not_created_by_default
        BOOL Ok|_warnings
        BOOL Ok2|_errors
        ----------- 'not show warnings:'
        BOOL Do_not_show_platform_dependent
        ------------------------- 'localization options'
        BOOL Do_not_localize
        BOOL Do_not_save_unlocalized
        ------------------------- 'running compiled program'
        BOOL Run|_if_compiled_ok
        STR Param|eters_to_pass_running_application
        ------------------------- 'paths'
        STR Source_files[]
        STR Source_paths[]
        STR Source_test_paths[]
        STR Destination|_path //= "Compiled"
        STR Project|_name
        ------------------------- 'files to copy: / / / COPY: etc'
        STR Copy_files[]
        {Type} Copy_for_class|_specified_in_NATIVE_directive_in_class[]
        STR Copy_files_test[]
        ------------------------- 'compiling'
        {Type}  All_classes[]
        {Type}	Removed_classes|_due_to_optimization[]
        STR     All_class_names[]
        //{Type}  All_modules|_imported_in_classes[]
        INT     In_init|_level
        {Var}   Incremented|_decremented_variables[]
		//------------------------- 'compiling generic function'
		//BOOL	Compiling_generic
		//STR		Generic_call_from
		//INT		Generic_errors
		------------------------- 'optimizations'
		BOOL	Not_auto_inline
		BOOL	Not_unroll
        ------------------------- 'testing'
        BOOL TEST_value
        BOOL	Precompiling_test|_rather_then_normal_function_method
        //METHOD TEST|_is_running ==> BOOL : -- moved to {System_functions}
        //    RESULT = TEST_value .
        METHOD Generating_test|_block ==> BOOL :
            RESULT = Current_fun.Is_test .
        ------------------------- 'errors / warnings'
        {Type}  Current_class
        {Fun}   Current_fun|ction
        {Expr}  Current_array
        INT     Errors_count
        INT     Warnings_count
        ------------------------- 'debugging'
        INT     Total_fun|_index = 1
        INT     Total_var|_index
        //INT     Total_for|_index
        INT     Total_st|atement_index = 1
        ------------------------- 'localization'
        BOOL    Compiling_LIKE|_REVERT_while_true_not_extend_dictionary
        */
        public string Extension = ".AL4";
        public int Max_errors = 5;
        public int Max_warnings = 10000;
        public bool Verbose = false;
        public List<string> Source_files = new List<string>();
        public List<string> Source_paths = new List<string>();
        public string Destination = "Compiled";
        public string Project_name = "Project1";
        public List<string> Copy_files = new List<string>();
        public bool Ok_warn;
        //------------------------------------ 'compiling'
        public List<Type> All_classes = new List<Type>();
        public List<string> All_class_names = new List<string>();
        public int In_init_level;
        public List<Variable> Incremented = new List<Variable>();
        public bool Test()
        {
            return TEST_c.Bool_c;
        }
        public bool Generating_test()
        {
            return Current_fun != null && Current_fun.Is_test;
        }
        //------------------------------------ 'errors / warnings'
        public Type Current_class = null;
        public Function Current_fun = null;
        public Expression Current_array = null;
        public int Errors_count;
        public int Warnings_count;
        //------------------------------------ 'debugging'
        public int Total_fun_index;
        public int Total_var_index;

        public class STOP : Exception
        {
            public string Stop_message;

            public STOP(string message)
            {
                Stop_message = message;
                Stop_message = message;
            }
        }

        /*
        ------------------------- 'messages'
        {Type}  prev_class_|error_
        INT     prev_line|_error
		STR		Error_prefix
		INT		Error_Called_from_line
        BOOL    Do_not_stop
        
        METHOD Reset_err|or:
            prev_class_ = NONE
            prev_line = -1
            Error_prefix = ""
            Errors_count = 0 .
            
        INT color_log|_text = 0xFF_FF_FF
        INT back_color_log = 0
        STR path_log|_html
        BOOL stop_html_log|ging
        
        METHOD Console_color(
        {Console}.{colors} C|olor_text)
        	:
            {Console}.Console_color(C)
            CASE C ?
            ['BLACK']:             color_log = 0xFF_40_40_40 //BLACK
            ['WHITE']:             color_log = 0xFF_FF_FF_FF //WHITE
            ['BLUE', 'LIGHT_BLUE', 'CYAN']: color_log = 0xFF_FF_00_00 //BLUE
            ['GREEN']:             color_log = 0xFF_00_80_00 //GREEN
            ['LIME']:              color_log = 0xFF_00_FF_00 //LIME
            ['TEAL']:              color_log = 0xFF_80_80_00 //TEAL
            ['MAROON']:            color_log = 0xFF_00_00_80 //MAROON
            ['MAGENTA']:		   color_log = 0xFF_80_00_80 //PURPLE
            ['FUCHSIA']:		   color_log = 0xFF_FF_00_FF
            ['OLIVE']:             color_log = 0xFF_00_80_80 //OLIVE
            ['YELLOW']:            color_log = 0xFF_00_FF_FF //YELLOW
            ['GRAY', 'SILVER']:    color_log = 0xFF_40_40_40 //DK_GRAY
            ['RED']:               color_log = 0xFF_00_00_FF //RED
            ; .
            
        METHOD Console_colors(
        {colors} F|oreground, {colors} B|ackground)
        	:
            Console_color(B)
            back_color_log = color_log
            Console_color(F)
            {Console}.Console_colors(F, B)
            .
            
            
        METHOD Write_m|essage_to_log_and_console(
        	STR Text|_to_write, STR Flag|_E_W)
        	:
            << Text
            CASE TEST ? ==> ;
            //DEBUG: ==> ;
            CASE stop_html_log ? ==> ;
            CASE path_log == "" ?
                 STR dir|ectory_path = Destination
                 CASE !dir.Directory_exists && !TEST ? Create_dir(dir) ; 
                 CASE !dir.Directory_exists ? dir = Start_dir ; 
                 dir = dir.Trailing_slash
                 
                 CASE ?
                 [{System_functions}.TEST] ? NONE
                 
                 [Ending(dir.Upper, "TEST$".Trailing_slash)] ?
                      dir = Remove_trailing(dir, "TEST$".Trailing_slash)
                      dir = dir.Trailing_slash ;
                      
                 path_log = dir "Compiler_messages.html"
                 //DEBUG: << "+++++++++++++++++++++++++++++++++++++++++++++"
                 //	" setting path_log to: " #NL path_log #NL
                 //	"++++++++++++++++++++++++++++++++++++++++++++" #NL ;
            ;
            Log_path(path_log)
            //DEBUG: << "~~~~ logging to: " path_log #NL ;
            STR m|essage_to_log = Text
            CASE ?
            [Flag == "E"] ? m = "[E]" Text
            [Flag == "W"] ? m = "[W]" Text ;
            Log_colored2(color_log, back_color_log, m)
            .
            
        INT Add_to_line|_offset_to_compile_on_temp_source
        STR Additional_text
        BOOL Suppress_err|ors_searching_fun
        INT at_line|_number
        
        METHOD calculate_at ==> STR :
        	RESULT = Additional_text
            CASE Current_class != NONE ?
            	 {Parser} p|arser_of_class = Current_class.Parse
                 -------------------- 'calculate inner line in the statement'
                 STR before|_current_position = p.Source[p.Line].[0 TO p.Pos-1]
                 FOR i IN [0 TO before.Len-1] :
                     CASE before.[i] == #LF ? 
                          INT inner|_line = inner + 1
                          INT pLF|_position = i ;
                 ;
                 CASE Current_class.Whole_name != "" ?
                 	  RESULT = RESULT " " Current_class.Whole_name " "
                 ELSE RESULT = RESULT " (" Current_class.Path ") " ;
                 INT iLine_n|umber INDEXING (STR,INT) = p.Line
                 at_line = p.Line_number(iLine_n)+Add_to_line+inner 
                 RESULT = RESULT at_line.Str "/" (before.Len - pLF + 1).Str
            ; .

        METHOD Error|_message(STR Text|_of_error) :
	        //CASE Current_fun.Dummy_compile ? ==> ;
            -------------------------------------- 'single message from a line'
            BOOL same|_point = prev_class_ == Current_class 
            	 && Current_class != NONE 
            	 && prev_line == Current_class.Parse.Line
                 
            CASE same ? ==> ;
            prev_class_ = Current_class
            prev_line = Current_class.Parse.Line
            ------------------------------ 'prepare position info'
            STR at|_position = calculate_at 
            ------------------------------- 'colored message'
            Console_color({colors}.'YELLOW')
            Write_m("ERROR"._Merror, "E")
            Console_color({colors}.'RED')
            CASE 0 != Error_Called_from_line 
                 && Error_Called_from_line != at_line - 1
                 ?
            	 Write_m(Error_prefix, "") 
            	 BOOL prefixed = TRUE ;
            Console_color({colors}.'YELLOW')
            Write_m(at ": " Text, "")
            Console_color({colors}.'SILVER')
            CASE Error_prefix != "" && !prefixed ? 
                 Write_m(" " Error_prefix, "") ;
            Write_m(#NL #NL, "")
            ------------------------------- 'Errors_count++'
            CASE Errors_count > 1000 ? stop_html_log = TRUE ;
            Errors_count += 1
            
            //DEBUG:
            //	CASE !TEST ?
            //      << Trace_stack(100) #NL >>
            //      STOP "the end" ;
            //;
                  
            CASE Errors_count > Max_errors && Errors_count >= 5 && (
                !Do_not_stop)
                ?
                CASE "$INC" !IN Defined_name[] && (
                	 "$INCREMENTAL" !IN Defined_name[])
                	 ?
                	 STOP "Too many errors, compiler will stop" ; 
            ; 
            CASE Verbose2 ? >> ;
            //DEBUG: >> ; 
            .
        */
        private Type prev_class_ = null;
        private int prev_line = 0;

        public void Error(string Text)
        {
            if (prev_class_ == Current_class &&
                Current_class != null && prev_line == Current_class.Parse.Line) return;
            prev_class_ = Current_class;
            prev_line = Current_class == null ? 0 : Current_class.Parse.Line;
            //-------------------------------- 'message show'
            string at = "";
            if (Current_class != null)
                at = " " + Current_class.Name() +
                    " " + (Current_class.Parse.Line+1).ToString();
            Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            Console.WriteLine("ERROR" + at + ": " + Text + "\r\n");
            if (Errors_count++ >= Max_errors)
            {
                throw new STOP("Too many errors, compiler will stop");
            }
        }

        /*
        {Type} prev_class_w_|arning_
        INT prev_line_w|arning
        BOOL Todo_warn
        
        //BOOL First_warn|ing = TRUE //, DEBUG
        BOOL Is_silent|_mode_No_warning
        
        BOOL No_style_warn|ings
        BOOL Is_style_warn|ings
        
        BOOL No_indexing_warn|ings
        BOOL Is_indexing_warn|ing
        BOOL Checking_recursive_fun|ction_or_not


        METHOD Warning|_message(STR Text|_of_warning) :
        	//DEBUG: 
        	//      CASE First_warn ? 
        	//           First_warn = FALSE 
        	//           Profiler_save_reset ;
        	//;
        	CASE Is_silent ? ==> ;
			CASE Errors_count > 0 ? ==> ;
			CASE No_style_warn && Is_style_warn ? ==> ;     
			CASE No_indexing_warn && Is_indexing_warn ? ==> ;     
        	//CASE Current_fun.Dummy_compile ? ==> ;
            ------------------------------ 'only one message from the same line'
            BOOL s|ame_point = prev_class_w_ == Current_class && (
                 Current_class != NONE)
                 
            s &&= prev_line_w == Current_class.Parse.Line
            CASE s ? ==> ;
            prev_class_w_ = Current_class
            prev_line_w = Current_class.Parse.Line
            ------------------------------ 'prepare position info'
            STR at|_position = calculate_at 
            ------------------------------ 'output warning'
            Console_color({colors}.'WHITE')
            Write_m("WARNING"._Mwarn Error_prefix at ": ", "W")
			CASE Todo_warn ?
				 Console_colors({colors}.'CYAN', {colors}.'OLIVE') ;
            Write_m(Text #NL #NL, "")
            Console_colors({colors}.'SILVER', Back_color)
            Warnings_count += 1
            CASE Warnings_count > Max_warnings && !Do_not_stop ?
                Error("ings"._Enum ": " Warnings_count.Str 
                ", " "max"._Emax ": " Max_warnings.Str)
                CASE "$INC" !IN Defined_name[] && (
                	 "$INCREMENTAL" !IN Defined_name[])
                	 ?
                	 STOP "Too many warnings, compiler will stop" ;
            ; .
        */
        private Type prev_class_w_ = null;
        private int prev_line_w;
        
        public static bool Is_silent;

        public void Warning(string Text)
        {
        	if (Is_silent) return;
            if (prev_class_w_ == Current_class &&
                Current_class != null && prev_line_w == Current_class.Parse.Line) return;
            prev_class_w_ = Current_class;
            prev_line_w = Current_class == null ? 0 : Current_class.Parse.Line;
            //-------------------------------- 'message show'
            string at = "";
            if (Current_class != null)
                at = " " + Current_class.Names[0] + " " + (Current_class.Parse.Line+1).ToString();
            Console.WriteLine("WARNING" + at + ": " + Text + "\r\n");
            if (Warnings_count++ >= Max_warnings)
            {
                throw new STOP("Too many errors, compiler will stop");
            }
        }

        /*
 		BOOL NO_USE_PARAMETERS
 		STR section|_to_get_parameters_from     
 		BOOL Int32|_option 
	
        METHOD Parse_command_line:
            -------------------------------- 'Get command line'
            //DEBUG: << "get command line .........................."#NL ;
            c|ommand_line_temp = {Parser}(Compiler_ = THIS, Class_ = NONE,
            	Warning_80= Warning_80, Dont_remove_dollar= TRUE)
            	
            CASE !NO_USE_PARAMETERS ?
                 //DEBUG: << "Count parameters: " Count_param.Str #NL ;
                 STR cl|_parameters = ""
               	 FOR i IN [0 TO Count_param-1] :
               	 	 //DEBUG: << "Parameter[" i.Str "] = " Parameter(i) #NL ;
               	     cl = cl Parameter(i) " " ;
               	 //DEBUG: << "Command line restored from parameters:" #NL cl #NL
               	 //;
            ;
            CASE cl.Trim == "" ?
	             cl = get_command_line
	             //DEBUG: << cl #NL 
	             //    "_______________________________________________" #NL ;
	             //Source_paths[] << Get_working_dir
            ;
            cl = cl.Trim
            c.Source[] << cl
            //DEBUG: << "command line: " c.Source[0] " Line=" c.Line.S 
            //			" Pos=" c.Pos.S " c.Next_char=[" c.Next_char "]" #NL ;
            --------------------------- 'Skip the executable path in command'
            CASE c.Next_char == #QU ? NONE = c.String_const(TRUE)
            ELSE NONE = c.Skip_to(" ") ;
            --------------------------- 'Parse options & files'
            FOR x|dummy IN [0 TO 1000_000] :
                c.Skip_sp
                CASE c.End_of_line ? c.Fin ;
                //DEBUG: << ">|" c.Rest_of_line #NL ;
                c.Skip_sp
                CASE c.End_of_source ? BREAK x ;
                STR path|scanned = ""
                STR option|scanned = ""
                INT from|_pos = c.Pos
                ------------------------------ 'scan path or option'
                CASE c.Next_char ?
                     [#QU]: path = c.String_const(TRUE)
                     ["/", "-"]: c.Skip_char
                                 CASE ?
                                 [section == "" && c.Symbol("[")] ?
                                 	section = c.Skip_to("]")
                                 	c.Wait("]")
                                 	CONTINUE x
                                 [c.Symbol("@")] ? option = "@"
                                 [c.Symbol("!")] ? option = "!" c.Ident.Lower 
                                 ;
                                 CASE option == "" && c.Symbol("$") ?
                                      option = "$" ;
                                 CASE option == "" ?
                                      -------------- '/$option'
                                      option = c.Ident.Lower
                                      //DEBUG: << "option as ident=[" option 
                                      //		 "]"#NL  #NL ; 
                                 ;
                ELSE path = c.Skip_to(" ") ;
            	----------------------------- 'decode %yyy%zzzzz'
            	path = Decode_env(path)
                CASE path != "" ?
                     -------------------------- 'handle path'
                     CASE ! path.Exists ?
                          path = Change_ext(path, Extension) ;
                     CASE ! path.Exists ?
                          path = Change_ext(path, Ext2) ;
                     CASE ! path.Exists ?
                          path = Change_ext(path, Ext3) ;
                     CASE ! path.Exists ?
                          path = Change_ext(path, ".AL4") ;
                     CASE ! path.Exists ?
                          Error("File not found: " path) ;
                     Source_files[] << path
                     CASE Source_files[].Count == 1 && Project == "" ?
                          Project = Change_ext(path.Extract_file_name, "") ;
                     collect_source_paths(path)
                     CONTINUE x ;
                ------------------------------ 'handle option'
                c.Skip_sp
                from = c.Pos
                //DEBUG: << " <<<<<<<<<<<<<<option " option " path " path #NL ;
               CASE option ?
               ["src", "source", "src_test", "source_test"]:
                   ----------------------------------- 'source path'
                   PUSH for_test = Ending(option, "_test") :
	                    path = get_path(c)
	                    CASE Ending(path, Path_sep "*") ?
	                         add_path_with_subdirs(path.[0 TO *-1])
	                    ELSE add_source_path(path) ;
                   ;
               ["dst", "dest", "destination"]:
                   ----------------------------------- 'destination path'
                   CASE c.Next_char == #QU ?
                        Destination = Decode_env(c.String_const(TRUE))
                   ELSE Destination = get_path(c) ;
                   Destination = Absolute_path(Destination).Trailing_slash
                   CASE from == c.Pos ?
                        Error("Destination path is not specified"._Edest) ;
               ["err", "errors"]: 
                   ---------------------------------- 'maximum errors'
                   Max_errors = c.Number
               ["warn", "warnings"]:
                   CASE c.Symbol("-") ?
                   		STR w_key|_ident = c.Ident     
                        CASE w_key.Lower ?
                        ["style"]: No_style_warn = TRUE
                        ["index", "indexing"]: No_indexing_warn = TRUE
                        
                        ELSE Error("Unknown option"._EUnkOp 
                        	 ": /warnings -" w_key)
                        ;
                   ELSE
	                    ---------------------------------- 'maximum warnings'
	                    Max_warnings = c.Number ;
               ["warn80", "warning80"]: 
                   ----------------- 'warnings on too long lines (not errors)'
                   Warning_80 = TRUE
               ["noind", "noindex", "noindexing"]:
                   No_indexing_warn = TRUE
               ["int32"]:
               	   ----------------- 'integers will be 32 bit'
                   Int32 = TRUE
               ["v", "verbose"]: 
                   ---------------------------------- 'verbose'
                   Verbose = TRUE
               ["v2", "vv", "verbose2"]: 
                   ---------------------------------- 'verbose2'
                   Verbose2 = TRUE
               ["ext", "extension"]: 
                   ---------------------------------- 'extension'
                   Extension = "." c.Ident
               ["ext2"]: 
                   ---------------------------------- 'extension 2'
                   Ext2 = "." c.Ident
               ["ext3"]: 
                   ---------------------------------- 'extension 3'
                   Ext3 = "." c.Ident
               ["prj", "proj", "project"]:
                   ---------------------------------- 'project name'
                   Project = c.Ident
               ["@", "at"]: 
                   ---------------------------------- 'options in file'
                   path = get_path(c)
                   CASE from == c.Pos ?
                        Error(
                        "Options file is not specified for /@"._Eopt)
                   ;
                   CASE !path.Exists ?
                        Error("File not found"._Efile2 ": " path) ;
                   ------------------------------------ 'load options file'
                   //c.Source[].Clear
                   text|_temp = {Text_file}(Path = path)
                   STR lines|_text[]
                   NONE = text.Load(lines[])
                   only_one_section(lines[])
                   remove_options_comments(lines[])
                   FOR ss IN lines[] :
                       c.Source[].Insert(c.Line+1 + ss.Index, ss) ;
                   -------------- 'add at the end the rest of command line'
                   c.Source[] << c.Source[c.Line].[c.Pos TO *]
                   c.Line += 1
                   c.Pos = 0
                   path = path.Extract_path
                   CASE path != "" ? Set_working_dir(path) ;
               ["$"]:
                   -------------------------------- 'defined variable'
                   path = c.Ident
                   CASE path IN Defined_name[] ?
                        Warning("$" path 
                        " " ("is defined more then once"._Wis ) ": " 
                        "" c.Next20)
                   ;
                   Defined_name[] << "$" path
                   CASE ?
                   [c.Symbol("=")] ?
                        Defined_value[] << get_path(c)
                   [c.Symbol(".")] ?
                        Defined_name[*] = Defined_name[*] "." c.Ident
                   ELSE Defined_value[] << "" ;
               ["copy"]:
                   -------------------------------- 'copy additional file'
                   //INT pos|ition_before = c.Pos
                   CASE c.Symbol("-") ?
                   		BOOL is_binary|_copy = c.Symbol("binary")
                   		is_binary ||= c.Symbol("BINARY")
                   		BOOL is_append|_to_file = c.Symbol("append")
                   		is_append ||= c.Symbol("APPEND")
                   		CASE is_append && is_binary ? 
                   		     Error("Either -APPEND or -BINARY should be "
                   		     "specified"._EAppendOrBinary) ;
                   ;
                   path = get_path(c)
                   CASE ?
                   [is_binary] ?
                        STR prefix_p|ath = "<bin>"
                   ELSE //c.Pos = pos
                        prefix_p = "" ;
                        
                   PUSH path :
                        CASE !path.Exists && "\" !IN path ?
                             path = find_in_source(path) ;
                        CASE path.[0] == "%" ?
                             path = replace_environment_var(path) ;
                        CASE !path.Exists ?
                             Error("File (to copy) not found"._Efile3 
                             ": " path)
                        ;
                        Copy_files[] << prefix_p path ;
                   ---------------------- 'find in Source_test_paths[]'
                   CASE !path.Exists && "\" !IN path ?
                        path = find_in_test_source(path) ;
                   CASE path.[0] == "%" ?
                        path = replace_environment_var(path) ;
                   CASE !path.Exists ?
                        Error("File (to copy) not found"._Efile31 
                        ": " path)
                   ;
                   Copy_files_test[] << prefix_p path
               ["f", "final"]: 
                   --------------------- 'no debug code in result sources'
                   Final = TRUE
                   // DEBUG: ... ; statements are not compiled !
                   // CNT_function_name are not created / counted
               ["debug"]:
                   --------------------- 'step-by-step debugging ?'
                   Debugging = TRUE
               ["debug-", "nodebug"]:
                   --------------------- 'step-by-step debugging ?'
                   Debugging = FALSE
               ["diag", "diagnostics"]:
                   --------------------- 'diagnostics mode ?'
                   Diagnostics = TRUE
                   Diagnostics_light = option == "diag"
                   CASE c.Next_char != "/" ? 
                   		Split(Diag_except[], c.Skip_to(" "), "," )
                   		FOR i_ex IN [0 TO Diag_except[].Count-1] :
                   		    Diag_except[i_ex] = #QU Diag_except[i_ex].Trim #QU ;
                   ;
                   		
               ["op", "optimizations"]:
                   --------------------- 'optimization flags'
                   Optimizations = get_path(c).Trim
                   check_optimizations_flags
                   //STR in|_optdummy
                   //<< "Optimizations: " Optimizations >> in
               ["noc", "noconsole"]:
                   --------------------- 'GUI only code'
                   Noconsole = TRUE
               ["t", "testreport"]:
                   CASE ?
                        [c.Symbol("-")] ? No_test_report = TRUE
                        [c.Symbol("+")] ? NONE
                        [c.Symbol("SHOW")] ? Test_report_show = TRUE ;
               ["run", "r"]:
                   --------------------- 'run after successful compile'
                   Run = TRUE
                   //DEBUG: << "Run=TRUE" #NL >> ;
               ["norun"]: 
                   //DEBUG: << "------------------- NO RUN ----------------"
                   //    "" #NL ;
                   Run = FALSE
                   Ok = TRUE
                   Ok2 = TRUE
               ["param", "parameters"]:
                   --------------------- 'command line  parameters to run'
                   c.Wait("[")
                   from = c.Pos
                   Param = c.Skip_to("]")
                   c.Wait("]")
               ["ok", "okwarnings"]:
                   --------- 'don t wait input if compiling was successful'
                   Ok = TRUE
               ["ok2", "okok", "okerrors"]:
                   --------- 'don t wait input if compiling was successful'
                   Ok = TRUE
                   Ok2 = TRUE
               ["!autoinline"]:
                   Not_auto_inline = TRUE
               ["!unroll"]:
                   Not_unroll = TRUE
               ["do_not_localize", "!loc", "!localize"]:
               	   Do_not_localize = TRUE
               ["!uloc", "!write_unlocalized"]:
               	   Do_not_save_unlocalized = TRUE
               ["!platform", "!platform_dependent"]:
               	   Do_not_show_platform_dependent = TRUE
               ["!max_desc"]:
                   c.Wait("{")
                   STR class_anc|estor = "{" c.Ident "}"
                   c.Wait("}")
                   c.Wait(",")
                   -------------------------------------- 'set for 1 class'
                   Classes_to_restrict_anc[] << class_anc
                   INT value_max = c.Number
                   N_max_desc[] << value_max
                   N_desc[] << 0
                   All_desc[] << ""
                   
               ELSE Error("Unknown compiler option"._EunkCompilerOption 
               	    ": " option) ;
            ;
            -------------------------- 'Default optimizations'
            CASE Optimizations == "" ?
                 Optimizations = "ABCDEFGHIJK_MNOPQRSTUVWXYZ" ;
            CASE Debugging ?
                 Optimizations = "" ;
            -------------------------- 'Scan results'
            CASE Source_files[].Count == 0 ?
                 Error("There are no source files specified"._Ethe) ;
            CASE Destination=="" ? 
                 Destination = Source_files[0].Trailing_slash 
                 	"Compiled" Path_sep 
            ;
            CASE ":" !IN Destination && ":" IN Source_paths[0] ?
                 Destination = Source_paths[0].Trailing_slash Destination ;
            CASE Verbose ?
                 << "Destination"._Mdest ": " Destination #NL ;
            CASE Final && Defined_name[].Find("$REPORT_LEAKS") >= 0 ?
                 Error(
                 "Options /final and $REPORT_LEAKS are not compatible"._Eopt2) 
            ;
            CASE Final && Debugging ?
                 Warning("Options /final and /debug are not compatible"._Eopt3) 
            ;
            CASE Diagnostics && !Debugging ? 
                 Error(
                 "Option /diagnostics requires also the /debug option to be "
                 "turned on"._EDiagReqDebug) ;
            -------------------------- 'check options are the same as last time'
            FOR i IN [c.Source[].Count-1 DOWNTO 0] :
                CASE c.Source[i].Trim=="" ? c.Source[].Delete(i) 
                ELSE BREAK i ;
            ;
            
            STR old_options[]
            Text_load(Destination.Trailing_slash "compilation.options", 
            	old_options[])
            	
            FOR i IN [old_options[].Count-1 DOWNTO 0] :
                CASE old_options[i].Trim=="" ? old_options[].Delete(i)
                ELSE BREAK i  ;
            ;
            	
            BOOL same|_options = old_options[].Count == c.Source[].Count
            CASE same ? 
                 FOR i IN [0 TO old_options[].Count-1] :
                     same = old_options[i].Trim == c.Source[i].Trim
                     CASE !same ? BREAK i ;
                 ;
            ;
            CASE !same ? Rebuild_all = TRUE ; 
            -------------- 'anyway, save new options'     
            {Text_file} saver|_options_TEMP = {Text_file}(
            	Path= Destination.Trailing_slash "compilation.options")
            	
            NONE = saver.Save(c.Source[]) .

BOOL for_test|_stage_Source_path_is_purposed
            
METHOD add_path_with_subdirs(STR path|_root), RECURSIVE :
    add_source_path(path) 
    STR cat|alog_directories[]
    Catalog(path, cat[])
    FOR s IN cat[] :
        CASE s.[*] != Path_sep ? CONTINUE s ;
        CASE "compiled" IN s.Lower ? CONTINUE s ;
        add_path_with_subdirs(path s Path_sep) ; .
            
METHOD add_source_path(STR Path|_to_add) :
	STR path|_copy = Path
	CASE path == "" ?
	    Error("Source path is not specified for /src") ==> ;
	CASE path.[0] == "." ?
	    path = Absolute_path(path) ;
	CASE path.[0] == "%" ?
	    path = Decode_env(path) ;
	CASE ! path.Directory_exists ?
	    path = path.Trailing_slash ;
	CASE ! path.Directory_exists ?
	    Error("Directory not found"._Edir ": " path) ==> ;
	CASE ?
	[path != "" && for_test && path !IN Source_test_paths[]] ?
	    Source_test_paths[] << path
	[path != "" && path !IN Source_paths[]] ?
	   CASE Verbose2 ? 
	        << "adding path: " path #NL ;
	   Source_paths[] << Absolute_path(path) ;
	CASE Source_test_paths[].Count < Source_paths[].Count ?
	    Source_test_paths[] << Absolute_path(path) ; .
            
STR Classes_to_restrict_anc|esting_from[]
INT N_max_desc|endents[]   
INT N_desc|endents_counted[]     
STR All_desc|endents[]

METHOD Add_to_descendents(INT I|ndex_of_item INDEXING STR, STR C|lass_name) :
	All_desc[I] = All_desc[I] " " C .

METHOD Set_N_desc(
INT I|ndex_of_item INDEXING INT, INT V|alue_to_assign)
    :
	N_desc[I] = V .

METHOD only_one_section(STR Lines | loaded[]) :
	-------------------- 'extract section [Common]'
	FOR i IN [0 TO Lines[].Count-1] :
	    CASE Lines[i].Trim.Lower != "[common]" ? CONTINUE i ;
	    FOR j IN [i+1 TO Lines[].Count-1] :
	        CASE Starting(Lines[j].Trim, "[") ?
	             INT last_line|_to_remove = j-1
	             BREAK j ;
	        STR common|_lines[] << Lines[j] ;
	    FOR j IN [last_line DOWNTO i] : Lines[].Delete(j) ;
	    CASE TRUE ? BREAK i ; 
	;
	-------------------- 'only one section'
	CASE section == "" ?
	     INT start|ing_line = 0
	ELSE
		 start = Lines[].Count
		 FOR s IN Lines[] :
		     //DEBUG: << "searching in: `" s "`" #NL ;
		     CASE s.[0] == "[" && s.Trim == "[" section "]" ?
		          start = s.Index+1
		          BOOL found|_section = TRUE
		          //DEBUG: << "found: " s " in line " s.Index.S #NL ;
		          BREAK s ;
		 ;
	;
	FOR i IN [start-1 DOWNTO 0] :
	    Lines[].Delete(i) ;
	FOR s IN Lines[] :
	    CASE s.[0] == "[" ?
	         FOR i IN [Lines[].Count-1 DOWNTO s.Index] :
	             Lines[].Delete(i) ;
	         BREAK s ;
	;
	------------------------- 'check if section was found'
	CASE section != "" && Lines[].Count == 0 && !found ?
		 Console_colors({colors}.'RED', {colors}.'YELLOW')
	     << "Section [" section "] was not found"
	     Console_colors({colors}.'SILVER', {colors}.'BLACK')
	     << #NL ;
	------------------------- 'append common part'
	FOR s IN common[] :
	    Lines[].Insert(s.Index, s) ; .
                 
                 
        METHOD check_optimizations_flags :
            CASE Optimizations == "+" ?
                 Optimizations = "ABCDEFGHIJK_MNOPQRSTUVWXYZ" ;
            CASE Optimizations.Upper ?
            ["-"]: Optimizations = " " 
            ["L"]: Optimizations = "ABCDEFGHIJK_MNOPQRSTUVWXYZ"
            	   Local_optimizations = TRUE ;
            CASE "L" IN Optimizations.Upper ? 
                 Local_optimizations = TRUE ;
            Optimizations = {Generator}.Allow_optimizations(THIS, Optimizations)
            .


        METHOD replace_environment_var( 
            STR Path|_starting_from_environment_var ) ==> STR
            :
            --------------------- '%name%\path\file.name -> full\path\file.name'
            STR source|_file_path = Path.[1 TO *]
            INT pos|ition_percent_char = source.Find("%")
            STR env|ironment_variable = source.[0 TO pos-1]
            STR var|iable_value = Get_environment_var(env)
            CASE ! var.Directory_exists ?
                 Error("Directory"._Edir3 " " var
                 " (" ("from environment variable"._Efrom) " "
                 "%" env "%) " ("does not exist"._Edoes))
            ;
            RESULT = var source.[pos+1 TO *] .
                 


        FUN remove_options_comments(STR S|ource_text[]) :
            FOR s IN S[] :
                CASE s.TrimL[0] == "#" ?
                     S[s.Index] = "" ;
                S[s.Index] = S[s.Index].TrimR ; .

                

        FUN get_path({Parser} P|arser_command_line) ==> STR :
            CASE P.Next_char == #QU ?
                 RESULT = P.String_const(TRUE)
            ELSE RESULT = P.Skip_to(" ") ; 
            RESULT = Decode_env(RESULT) .



        METHOD find_in_source|_paths(STR F|ile_name) ==> STR :
            FOR s IN Source_paths[] :
                RESULT = s.Trailing_slash F
                CASE RESULT.Exists ? ==> ;
            ;
            Error("File not found"._Efile4 ": " F) .
            
        METHOD find_in_test_source|_paths(STR F|ile_name) ==> STR :
            FOR s IN Source_test_paths[] :
                RESULT = s.Trailing_slash F
                CASE RESULT.Exists ? ==> ;
            ;
            Error("File not found"._Efile41 ": " F 
            " " ("(for test stage only)"._EForTest)) .
            
   		FUNCTION Decode_env|ironment_variable_at_start(
   			STR Path|_to_decode) ==> STR
   			:
   			RESULT = Path
            CASE Path.[0] IN "$%" ?
                 CASE Path.[0] == "$" ?
                      INT pp|osition_of_slash = Path.Find("/")
	        	 ELSE pp = Find_from(Path, 2, "%") ;
	             STR var|iable_in_environment = Path.[1 TO pp-1]
	             //CASE Platform_info LIKE "%linux%" ? var = "$" var ;
	             STR val|ue_of_variable = Get_environment_var(var)
	             //DEBUG: << "---------------------------------------------"#NL 
	             //		"env var " var " -->> " val #NL ;
	             CASE var == "AL4" && val == "" ?
	             	  CASE Platform_info.Lower.Find("linux") >= 0 ?
	             	       val = "/mnt/AL-IV/"
	             	  ELSE val = "C:\AL-IV\" ;
	             ELSE val = val.Trailing_slash ; 
	             val = val.Trailing_slash
	             CASE Path.[pp+1] == "\" ? pp += 1 ; 
	             RESULT = val Path.[pp+1 TO *] ;
            //DEBUG: "after decode [" Path "]==>[" RESULT "]"#NL#NL ;
            CASE Path_sep == "/" ? 
                 RESULT = Replace_all(RESULT,"\", "/")
            ELSE RESULT = Replace_all(RESULT,"/", "\") ; .

        */
        public string find_in_source(string F)
        {
            foreach (string s in Source_paths)
            {
                string Result = StringFunctions.Trailing_slash(s) + F;
                if (File.Exists(Result)) return Result;
            }
            Error("File not found: " + F);
            return "";
        }

        public void Parse_command_line()
        {
            string CL = Environment.CommandLine;
            Parser C = new Parser();
            C.Compiler_ = this;
            C.Class_ = null;
            C.Source.Add(CL);
            //-------------------------------- 'skip the executable path'
            switch (C.Next_char())
            {
                case "\"": C.String_const(true); break;
                default: C.Skip_to(" "); break;
            }
            //-------------------------------- 'parse options & files'
            for (int x = 0; x <= CL.Length - 1; x++)
            {
                C.Skip_sp();
                if (C.End_of_line()) break;
                string path = "";
                string option = "";
                int from = C.Pos;
                //----------------------'scan path or option'
                switch (C.Next_char()[0])
                {
                    case '\"': path = C.String_const(true); break;
                    case '/':
                    case '-': C.Skip_char(); option = C.Ident().ToLower();
                    	break;
                    default: C.Skip_to(" ");
                        path = get_path(CL.Substring(from, C.Pos - from));
                        break;
                }
                if (path != "")
                {
                    //------------------ 'handle path'
                    if (!File.Exists(path))
                        path = Path.ChangeExtension(path, Extension);
                    if (!File.Exists(path))
                        Error("File not found: " + path);
                    Source_files.Add(path);
                    collect_source_paths(path);
                    continue;
                }
                //----------------------- 'handle option'
                C.Skip_sp();
                from = C.Pos;
                bool sw_ok = false;
                if (option != "")
                switch (option[0])
                {
                    case 's':
                        if (option == "src" || option == "source")
                        {
                            sw_ok = true;
                            if (C.Next_char() == "\"")
                                path = get_path(C.String_const(true));
                            else
                            {
                                from = C.Pos;
                                C.Skip_to(" ");
                                path = get_path(CL.Substring(from, C.Pos - from));
                            }
                            if (from == C.Pos)
                                Error("Source path is not specified for /src");
                            if (!Directory.Exists(path))
                                Error("Directory not found: " + path);
                            Source_paths.Add(path);
                        }
                        break;
                    case 'd':
                        if (option == "dst" || option == "dest" || option == "destination")
                        {
                            sw_ok = true;
                            if (C.Next_char() == "\"")
                                Destination = C.String_const(true);
                            else Destination = C.Ident();
                            if (from == C.Pos)
                                Error("Destination path is not specified");
                        }
                        break;
                    case 'e':
                        if (option == "err" || option == "errors")
                        {
                            sw_ok = true;
                            Max_errors = C.Number();
                        }
                        else if (option == "ext" || option == "extension")
                        {
                            sw_ok = true;
                            Extension = "." + C.Ident();
                        }
                        break;
                    case 'w':
                        if (option == "warn" || option == "warnings")
                        {
                            sw_ok = true;
                            Max_warnings = C.Number();
                        }
                        break;
                    case 'v':
                        if (option == "v" || option == "verbose")
                        {
                            sw_ok = true;
                            Verbose = true;
                        }
                        break;
                    case 'p':
                        if (option == "prj" || option == "proj" || option == "project")
                        {
                            sw_ok = true;
                            Project_name = C.Ident();
                        }
                        break;
                    case 'c':
                        if (option == "copy")
                        {
                            sw_ok = true;
                            path = C.String_const(true);
                            if (!File.Exists(path))
                                path = find_in_source(path);
                            if (!File.Exists(path))
                                Error("File (to copy) not found: " + path);
                            Copy_files.Add(path);
                        }
                        break;
                    case 'o':
                         if  (option == "ok" || option == "okwarnings")
                         {
                             sw_ok = true;
                             Ok_warn = true;
                         }
                         else if (option == "okok" || option == "ok2" ||
                         	option == "okerrors")
                         {
                         	sw_ok = true;
                         }
                         break;
                }
                if (!sw_ok)
                {
                    Error("Unknown option: " + option);
                }
            }
            //---------------------------- 'scan results'
            if (Source_files.Count == 0)
                Error("There are no source files specified");
            if (!Destination.Contains(":") && Source_paths.Count > 0 &&
                Source_paths[0].Contains(":"))
                Destination = StringFunctions.Trailing_slash(Source_paths[0]) + Destination;
            if (!Directory.Exists(Destination))
                Directory.CreateDirectory(Destination);
            if (!Directory.Exists(Destination))
                Error("Directory is not exists: " + Destination);
        }
        
        public static string get_path(string s)
        {
            if (s[0] == '%')
            {
                string varname = s.Substring(1);
                int e = varname.IndexOf('%');
                if (e < 0) return s;
                varname = varname.Substring(0, e);
                s = Environment.GetEnvironmentVariable(varname) + s.Substring(2 + varname.Length);
            }
            return s;
        }



        /*
        
        METHOD Find_source_to_copy(
        	STR S|ource_file_name_asterisk,
        	STR Where_search|_paths_DYN[] ) ==> STR
        	:
            STR what|_find = S
            CASE Ending(S, ".*") ? what = Change_ext(S, "") ;
            FOR p IN Where_search[] :
                p = p.Trailing_slash
                //<< "search " p what Ext #NL
                CASE (p what Ext).Exists ? RESULT = what Ext ==> ;
                //<< "search " p what Ext2 #NL
                CASE (p what Ext2).Exists ? RESULT = what Ext2 ==> ;
                //<< "search " p what Ext3 #NL
                CASE (p what Ext3).Exists ? RESULT = what Ext3 ==> ;
            ;
            Error("Could not find source to copy"._Ecould ": " S) .
        
        METHOD collect_source_paths(STR Path|_to_add) :
            CASE Source_paths[].Count == 0 ?
                CASE "\" IN Path || "/" IN Path ?
                     Source_paths[] << Absolute_path(Path.Extract_path) 
                	 CASE Source_test_paths[].Count < Source_paths[].Count ?
                	 	  Source_test_paths[] << Absolute_path(Path.Extract_path)
                	 ;
				;
            ;
            CASE Destination == "Compiled" ?
                 Destination = Add_trail(Path.Extract_path, "\")
                 "Compiled" ; .
        */
        private void collect_source_paths(string path)
        {
            if (Source_paths.Count == 0)
            {
                if (path.Contains('\\'))
                    Source_paths.Add(Path.GetDirectoryName(path));
                else Source_paths.Add("");
            }
            if (Destination == "Compiled")
                Destination = StringFunctions.Add_trailing(
                    (Path.GetDirectoryName(path)), "\\") + "Compiled";
        }

        /*
        
        METHOD Collect_all_classes:
            NONE = Create_class(Source_files[0])
            INT i|ndex_of_class INDEXING {Type} = 0
            FOR x|dummy IN [0 TO MAX_INT-1] :
                CASE i >= All_classes[].Count ? BREAK x ;
                PUSH Current_class = All_classes[i] :
                	 Current_class.Handle_header
                	 Current_class.Handle_import ;
                i += 1 ; .
        */
        private void collect_all_classes()
        {
            Create_class(Source_files[0]);
            int i = 0;
            for (int x = 0; x <= 0x7FFFFFFF; x++)
            {
                if (i >= All_classes.Count) break;
                Current_class = All_classes[i];
                Current_class.Handle_header();
                Current_class.Handle_import();
                i++;
            }
        }

        /*
        BOOL Merge_continued_lines
        INT Class_level|_handling_import
        
        METHOD Create_class(
        	STR Path|_of_file) ==> {Type} //, RECURSIVE
        	:
            //DEBUG:
            //    CASE "Localize" IN Path ? 
            //    << "CRRRRRRRRRRRRRRRRRRRRRRRREATE CLASS: " Path #NL >> ; 
            //;
            CASE "\" !IN Path && "/" !IN Path ?
                 FOR c IN All_classes[] :
                     CASE "{" Path "}" IN c.Names[] ?
                         RESULT = c ==> ;
                 ;
            ;
            //DEBUG: << "-- create class: " Path #NL ;
            ----------------------------------- 'search on disk'
            //CASE Verbose2 ? << "Search class " Path " on disk" #NL ;
            STR path_f|ile_class = find_class_path(Path, TRUE)
            CASE ! path_f.Exists || "\" !IN path_f && "/" !IN path_f ?
                path_f = find_class_path(Path, FALSE) 
            ;
            CASE ! path_f.Exists || "\" !IN path_f && "/" !IN path_f ?
                Error("File was not found for class"._Efile5 ": " Path) ==> ;
            STR path_L|owered = path_f.Lower
            FOR c IN All_classes[] :
                CASE path_L == c.Path.Lower ? RESULT = c ==> ;
            ;
            ------------------------------------ 'create new class'
            CASE Verbose2 ? << "Create new class " Path ".............." #NL ;
            
            new_class = {Type}(Path = path_f, Kind = 'CLASS',
            	Original_type_index = -1), >> All_classes[]
            //new_class.Parse.Full_path = path_f
            	
            //DEBUG: << "New class " Path " was created" #NL ;
            RESULT = new_class
            NONE = class_just_created(RESULT) .
             
		METHOD class_just_created(
		{Type} C|lass_created) ==> {Type} 
			: 
	 		RESULT = C
            PUSH Current_class = RESULT :
            	 RESULT.Load(THIS, FALSE)
	             //DEBUG: << "Loaded -- Merge_continued_lines = "
	             //       "" Merge_continued_lines.S #NL ;
	             ------------------------------------ '[Language=XX, Syntax=YY]'
	             {Parser} p|arser_of_class = RESULT.Parse
	             CASE C.Path != "" ? p.Full_path = C.Path ;
	             //DEBUG: << "Class just created, path = " C.Path >> ;
	             p.Line = 0
	             p.Pos = 0
	             //DEBUG: << "New class " C.Path " was loaded " 
	             //	"" p.Source[].Count.S " lines" #NL ;
	             CASE p.End_of_line ? p.Fin ;
	             CASE p.Symbol("[") ?
	                  //DEBUG: <<"calling change_language_syntax"#NL ;
	                  change_language_syntax(p) ;
	             -------------------------------------- 'merge lines ?'
	             CASE p.Syntax_name == "" ? 
					  CASE Verbose2 ? << "checked, merging..." ;
			          p.Merge_continued(-1)
			          CASE Verbose2 ? << "merged"#NL ;
	             ;
	             -------------------------------------- 'handle header'
	             p.Line = 0
	             p.Pos = 0
	             RESULT.Handle_header 
	             ------------------- 'skip all block comments'
	             FOR ii|dummy IN [0 TO p.Source[].Count-1] :
	                 CASE p.Symbol("--") ? 
	                      p.Pos = p.Last+1
	                      p.Fin
	                 ELSE BREAK ii ;
	             ;
	             -------------------------------------- 'LIKE CLASS {...} ?'
	             CASE p.Symbol("LIKE") ?
	                  p.Wait("CLASS")
	                  STR name|_base_class_like_on = p.Class_name
	                  CASE name.[0]=="{" ? name = name.[1 TO *-1] ;
	                  STR path|_found = find_class_path(name, FALSE)
	                  CASE !path.Exists ? 
	                       p.Err("Class not found: " name) ;
	                  {Type} base_c|lass_TEMP = {Type}(Path = path, 
	                  		Kind = 'CLASS',
            				Original_type_index = -1)
	                  ----------------- 'now do replacements'
	                  PUSH Merge_continued_lines = FALSE :
	                       base_c.Load(THIS, FALSE) ;
	                  CASE p.Symbol(",") ? 
	                       p.Wait("BUT")
	                  ;
	             ;
	             FOR i|dummy IN [0 TO 1_000_000] :
	                 CASE base_c==NONE ? BREAK i ;
	                 p.Wait("(")
	                 STR from|_pattern = p.Skip_to("==>").Trim
	                 CASE from.[0]=="'" && from.[*]=="'" ? 
	                      from = from.[1 TO *-1] ;
	                 CASE from=="" ? p.Err("Incorrect empty pattern to replace "
	                      "in the LIKE CLASS"._EEmptyPatterLikeClass) ;
	                 p.Wait("==>")
	                 STR to_t|ext2 = p.Skip_to(")").Trim
	                 CASE to_t.[0]=="'" && to_t.[*]=="'" ? 
	                      to_t = to_t.[1 TO *-1] ;
	                 p.Wait(")")
	                 INT numb|er_replacements = 1
	                 CASE p.Symbol("*") ?
	                      CASE p.Symbol("?") ? numb = 0 
	                      ELSE numb = p.Number
	                           CASE numb <= 0 ? 
	                                p.Err("*n with n <= 0 (use ?) to "
	                                "skip checking count of replaces") ;
	                      ;
	                 ;
	                 ------------------------------ 'do replaces'
	                 INT c_repl|ased_count = 0
	                 FOR s IN base_c.Parse.Source[] :
	                 	 INT last_p|osition_find_from = s.Len-1
	                     FOR j|dummy IN [s.Len-1 DOWNTO 0] :
	                         INT f_pos|ition_found_in 
	                         = Find_last(s.[0 TO last_p],from)
	                         
	                         CASE f_pos < 0 ? BREAK j ;
	                         s = s.[0 TO f_pos-1] to_t s.[f_pos+from.Len TO *]
	                         last_p = f_pos-1
	                         c_repl += 1     
	                     ;
	                     base_c.Parse.Source[s.Index] = s
	                 ;
	                 CASE ?
	                 [c_repl != numb && numb > 0] ?
	                      p.Err("Amount of patterns (" from 
	                      ") was specified (" numb.Str ")"
	                      " but actual amount was " c_repl.Str)
	                 [numb==0 && c_repl==0] ?
	                     p.Err("Pattern (" from ") was not sound in the "
	                     "source text"._EPattern_not_found)
	                 ;
	                 CASE !p.Symbol(",") ? 
	                      p.Fin
	                      BREAK i ;
	             ;
	             CASE base_c != NONE ? 
	                  p.Source[].Clear
	                  FOR s IN base_c.Parse.Source[] :
	                      p.Source[] << s ;
	                  -------------------- 're-scan class'
	                  p = RESULT.Parse
		              INT end_line|_to_merge = p.Remove_comments
		              p.Merge_continued_lines(end_line)
	                  p.Line = 0
		              p.Pos = 0
		              RESULT.Names[].Clear
		              RESULT.Handle_header 
	             ;
            ; .
            
		BOOL Suppress_deprecated_warn|ings
            
        FUN change_language_syntax(
        {Parser} P|arser_of_class)
        	:
            INT n|umber_of_commands_in_bracket = 0
            FOR i|dummy IN [P.Pos TO P.Last] :
                CASE ?
                [P.End_of_line] ? BREAK i
                [P.Next_symbol("]")] ? BREAK i ;
                -------------------------- 'recognize command'
                STR command|_detected = ""
                INT before_pos|ition_of_ident = P.Pos
                P.Skip_sp
                CASE P.Next_is_letter ?
                    CASE P.Ident.Lower ?
                    ["syntax"]:    command = "S" 
                                   P.Wait("=")
                    ELSE P.Pos = before_pos ;
                ;
                CASE command == "" && n == 0 ? command = "L" ;
                CASE command == "" && n == 1 ? command = "S" ;
                ------------------------ 'handle command recognized'
                P.Skip_sp
                CASE command ?
                ["S"]: P.Syntax_name = P.String_const(TRUE)
                ;
                n += 1
                CASE !P.Symbol(",") ? CONTINUE i ;
            ;
            P.Wait("]") .
        
        */
        static int CNT_Create_class;

        public Type Create_class(string Path)
        {
            if (++CNT_Create_class == 59)
            { }
            string path_f = find_class_path(Path, true);
            if (!File.Exists(path_f))
                path_f = find_class_path(Path, false);
            if (!File.Exists(path_f))
            {
                Error("File was not found for class: " + Path);
                return null;
            }
            string path_L = path_f.ToLower();
            foreach (Type c in All_classes)
            {
                if (path_L == c.Path_class_source.ToLower())
                    return c;
            }
            Type Result = new Type();
            Result.Kind = Type.Kind_type.CLASS;
            Result.Path_class_source = path_f;
            All_classes.Add(Result);
            Result.Load(this);
            return Result;
        }

        /*
        
        STR cache_dir|ectories_search_source[]
        
        METHOD exists|_in_cached_dirs(
        STR path|_to_check) ==> BOOL
            :
            CASE cache_dir[].Count == 0 ? RESULT = path.Exists ==> ;
	        RESULT = path.Lower IN cache_dir[] .
        
        METHOD find_class_path(
            STR Path|_of_class_file, 
            BOOL Sub|path_only) ==> STR
            :
            CASE cache_dir[].Count == 0 ? 
                 FOR i IN [0 TO Source_paths[].Count-1] :
                     STR cat|alogue_i[]
                     Catalog(Source_paths[i], cat[])
                     FOR s IN cat[] :
                     	 CASE Ending(s, Path_sep) ? CONTINUE s ;
                         //STR e|xtension = s.Ext.Lower
                         CASE s != Ext && s != Ext2 && s != Ext3 ? 
                              CONTINUE s ;
                         cache_dir[] << s.Lower
                     ;
                 ;
            ;
            ------------------------------ 'Path is a path not just file name?'
            CASE Path_sep == "/" ? 
                 RESULT = Replace_all(Path, "\", Path_sep)
            ELSE RESULT = Replace_all(Path, "/", Path_sep) ;
            //DEBUG: << RESULT #NL ;
            
            CASE Path_sep IN RESULT && exists(RESULT) ? 
                 CASE Verbose ?
                      << "Found path: " RESULT #NL ;
                 ==>
            ;
            CASE Current_class != NONE ?
            	 STR ccp|ath_of_current_class 
            	 = Current_class.Path.Extract_path.Lower
            ;
            ------------------------------ 'Search in all source search paths'
            FOR i IN [0 TO Source_paths[].Count] :
                STR src|_from_list_or_empty = Source_paths[i]
                CASE Verbose2 ? 
                     << "searching in " src #NL ;
                CASE i == Source_paths[].Count ?
                     src = Source_files[0].Extract_path ;
                CASE Path_sep == "/" ? 
                     src = Replace_all(src, "\", Path_sep)
                ELSE src = Replace_all(src, "/", Path_sep) ;
                CASE Sub && src.[0 TO ccp.Len-1].Lower != ccp && src != "" ?
                    CONTINUE i ;
                STR path_e|xtended = src.Trailing_slash RESULT
                CASE ("\" IN path_e || "/" IN path_e) && (
                     Change_ext(RESULT, "") != RESULT) && (
                     exists(path_e))
                     ?
                     RESULT = path_e ==> ;
                --------------------------------------- 'check all extensions'
                path_e = Change_ext(path_e, Extension)
                CASE exists(path_e) ? RESULT = path_e ==> ;
                path_e = Change_ext(path_e, Ext2)
                CASE exists(path_e) ? RESULT = path_e ==> ;
                path_e = Change_ext(path_e, Ext3)
                CASE exists(path_e) ? RESULT = path_e ==> ;
                path_e = Change_ext(path_e, ".al4")
                CASE exists(path_e) ? RESULT = path_e ==> ;
                path_e = Change_ext(path_e, ".AL4")
                CASE exists(path_e) ? RESULT = path_e ==> ;
            ; .
        */
        private string find_class_path(string Path, bool Sub)
        {
            string Result = Path;
            if (/*File.Exists(Result) ||*/ Result.Contains("\\") || Result.Contains("/")) return Result;
            string ccp = Current_class.Path_class_source.ToLower();
            foreach (string src in Source_paths)
            {
                string path_e = StringFunctions.Add_trailing(src, "\\") + Result;
                if (File.Exists(path_e))
                    return path_e;
                if (File.Exists(path_e + ".cs"))
                    return path_e + ".cs";
                if (File.Exists(path_e + ".al4"))
                    return path_e + ".al4";
            }
            Error("File not found: " + Path);
            return Result;
        }
        
        /*
        
        INT Optimizations_count
        {Fun} Functions_used|_from_main[]
        {Fun} observed|_while_collect_Functions_used[]
        {Type} Classes_objects_created|_actually_calling_constructors[]
        {Type} Classes_used|_from_main[]
		INT Count_C0|_optimizations
		INT Count_C1|_optimizations
		INT Count_C2|_optimizations
		INT Count_E0|_optimizations
		INT Count_E1|_optimizations
		INT Count_E2|_optimizations
		INT Count_F0|_optimizations
		INT Count_F1|_optimizations
		INT Count_F2|_optimizations
		INT Count_I1|_optimizations
		INT Count_I2|_optimizations
		INT Count_call_replacements|_I2
		INT Max_count_call_replacements|_I2 = -2

		INT Count_P0|_optimizations
		INT Count_R0|_optimizations
		INT Count_R1|_optimizations
		INT Count_R2|_optimizations
		INT Count_R3|_optimizations
		INT Count_R4|_optimizations
		INT Count_V0|_optimizations
		INT Count_V2|_optimizations
		INT Count_V3|_optimizations
		INT Count_V4|_optimizations
		INT Count_V5|_optimizations
		
		
        
        METHOD Should_optimize( STR Flag|_optimize ) ==> BOOL :
            //DEBUG: << "Optimizations=[" Optimizations "] ? " Flag #NL
            //        >> ;
            CASE Flag IN Optimizations ? RESULT = TRUE ==> ;
            CASE Flag.Len <= 1 ? ==> ;
            INT pf|lag_position = Optimizations.Find(Flag.[0])
            CASE pf < 0 ? ==> ;
            CASE Optimizations.[pf+1] !IN "0123456789" ? RESULT=TRUE ;
            .
			
		METHOD Maximum_op|timizations(
			STR Flag|_optimize ) ==> INT
			:
			INT pos|ition_flag = Optimizations.Find(Flag "<")
			CASE pos < 0 ? RESULT = MAX_INT ==> ;
			pos += 1 + Flag.Len
			FOR i IN [pos TO Optimizations.Len-1] :
				CASE Optimizations.[i] IN "0123456789" ?
					 RESULT = RESULT * 10 + Optimizations.[i].Ord - "0".Ord
				ELSE ==> ;
			; .
			
		METHOD method_level_optimizations:
            FOR c IN All_classes[] : c.Has_descendant = FALSE ;
            FOR c IN All_classes[] :
                CASE c.Base_ != NONE ? c.Base_.Has_descendant = TRUE ;
            ;
            FOR c IN All_classes[] :
                c.Optimize ; .
	
			
        METHOD do_other_optimizations :
        	CASE Optimizations.Trim == "" ? ==> ;
        	BOOL incremental = "$INC" IN Defined_name[]
        	incremental ||= "$INCREMENTAL" IN Defined_name[]
         	CASE incremental ? ==> ;
         	CASE Local_optimizations ? ==> ;
            ------------------------------ 'do until no more optimizations done'
            FOR j|dummy IN [1 TO 100] :
            	Optimizations_count = 0
                method_level_optimizations
                CASE Optimizations_count == 0 ? BREAK j ;
            ;
            {Fun} main_f|unction
            FOR j IN [1 TO 100] :
	            -------------------------- 'collect used classes'
	            Functions_used[].Clear
	            observed[].Clear
	            Classes_used[].Clear
	            
	            PUSH Current_class = All_classes[0] :
		             main_f = All_classes[0].Search_fun(
		            	 "Main", ONLY_ST|CASE_SEN, FALSE)
	            ; 
	            	
	            CASE main_f == NONE ?
	                 Current_class = All_classes[0]
	                 Error("Main function was not found"._Emain3) ;
	            FOR cl IN All_classes[] :
	            	collect_callback_functions(cl) ;
	            collect_functions_used(main_f)
	            finish_collecting_classes_used
	            FOR fn IN Functions_used[] :
	                CASE fn.Modifiers['UNSUPPORTED'] ?
	                     PUSH Current_class = fn.Class :
	                     PUSH Current_fun = fn :
	                     PUSH Current_class.Parse.Line = fn.Line_start :
	                          Error("Unsupported function is called"._Eunsup
	                          ": " fn.Deprecate)
	                     ;
	                     ;
	                     ;
	                ;
	            ;
	            ------------------------------ 'now global optimizations'
	            CASE !Should_optimize("R1") && !Should_optimize("R2") && (
	                 !Should_optimize("R3")) && !Should_optimize("R4")
	                 ?
	                 ==> ;
                Optimizations_count = 0
                //DEBUG: << #NL "clear Functions_used[], start again ..........."
                //		  #NL ;
                Functions_used[].Clear
                observed[].Clear
                Classes_used[].Clear
                FOR cl IN All_classes[] :
                	collect_callback_functions(cl) ;
                collect_functions_used(main_f)
                finish_collecting_classes_used
                add_native_directives
                //CASE !Any_class_from_ccc ?
	                 CASE Should_optimize("R4") && (
						  Count_R4 < Maximum_op("R4"))
	                      ?
			              //DEBUG:
			              // << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& used classes"#NL
			              // FOR c IN Classes_used[] :
			              //     << c.Names[].Whole_name #NL
			              //       CASE c.Names[0] == "{Text_file}" ?
			              //      		 << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
			              //      		    " {Text_file} is presented in"
			              //      		    "Classes_used[] "
			              //      		    "after collecting functions used" #NL 
			              //      		 >> STR in|_dummy
			              //       ;
			              // ;
			              //;
	                      remove_unused_classes ;
	                 CASE Should_optimize("R1") && (
						  Count_R1 < Maximum_op("R1"))
	                      ?
	                      remove_unused_static_functions ;
	                 CASE Should_optimize("R2") && (
						  Count_R2 < Maximum_op("R2"))
	                      ?
	                      remove_unused_native_functions ;
	                 CASE Should_optimize("R3") && (
						  Count_R3 < Maximum_op("R3"))
	                      ?
	                      remove_unused_final_methods ;
                //ELSE
                //    CASE Should_optimize("R") ?
                //         Warning("While CCC files are used to speed up "
                //         "compiling, some optimizations are not applied "
                //         "even when specified explicitly. Use $CCC=no to "
                //         "stop using CCC if you need optimiztions working."
                //         ""._CCC_no_optimize) ;
                //;
                ---------------------------------- 'one more time ?'
                INT remove_opt|imizations = Optimizations_count
                Optimizations_count = 0
                method_level_optimizations
                //DEBUG: << #NL"Optimizations_count=" Optimizations_count.Str #NL;
                CASE Optimizations_count + remove_opt == 0 ? BREAK j ;
            ; 
			.
            
            
        METHOD add_native_directives|_from_classes_used :
            FOR c IN Classes_used[] :
                FOR fn IN c.Method[] :
                    CASE fn.Final_name == "-" && fn !IN Functions_used[] ?
                         Functions_used[] << fn ;
                ;
            ; .

                
        INT Total_replace_index = 1
        INT Total_inline_fun|ction_prefix_index
        INT Total_optimizations_n
        INT C1_optimizations
        INT I1_optimizations
        INT Optimize_E2_counter
        INT Count_remove_local_var|iable_V0
        INT Count_union_local_var|iables_V5
        
        //BOOL debug_collect
        
		STR indent_c|ollection_level
		//INT report_i|ndex_collecting
		
        METHOD collect_functions_used(
        	{Fun} F|unction_from), RECURSIVE
        	:
			CASE F == NONE || F.Final_name == "-" ? ==> ;
			//DEBUG:
			//      STR s|tring_prepared_to_output 
			//      s = "collect functions from " F.Class.Names[0] 
			//      "." F.Whole_name
			//      << s #NL
			//      CASE s == "collect from {Game_control}.Draw" ? NONE ;
			//	//CASE Classes_used[].Count == 0 ? << "----------------------"
			//	//"----------------------------------------------------" #NL ;
			//;
			     
        PUSH indent_c = indent_c "a  ":
        	--------------- 'dependances in list NATIVE(...)'
        	PUSH indent_c = indent_c "x" :
	        	 FOR dep IN F.Depends[]:
	        	     STR spl|itted[]
	        	     Split(spl[], dep, ".")
	        	     {Type} cdep|ends_on_class = F.Class.Find_type(spl[0])
	        	     CASE cdep !IN Classes_used[] ?
	        	          collect_class_type_used(cdep) ;
	        	     CASE spl[].Count > 1 ?
	        	          PUSH Current_class = F.Class :
	        	          PUSH Current_class.Parse.Line = F.Line_start :
	        	               
	        	          {Fun} fdep|ends_on_function = cdep.Find_fun(
	        	          	spl[1], TRUE)
	        	          	
	        	          add_called_to_functions_used(fdep) ;
	        	          ;
	        	     ;
	        	 ;
        	;
            --------------- 'collect function and all called from its functions'
            CASE F !IN Functions_used[] ?
                 //DEBUG: 
                 //      CASE F.Total_fn == 18062 ?
                 //           << "000000000000000000000000000000000000000000"
                 //           	" " F.Names[].Whole_name " is used: 1"#NL ;
                 //;
                 
                 //DEBUG: report_i += 1 
                 //      << report_i.Str " [add function to used]"
                 //	   ": " indent_c "+ " F.Class.Names[0] "." F.Names[0] #NL ;
                 Functions_used[] << F
                 FOR fov IN F.Overloaded_[] :
                     Functions_used[] << fov ;
                 CASE F.Pop_method_ != NONE 
                 	  && F.Pop_method_ !IN Functions_used[]
                 	  ?
                      Functions_used[] << F.Pop_method_ ;
            ;
            collect_class_type_used(F.Class)
            add_classes_from_method(F)
            FOR f IN F.Call_functions_[] : 
                //DEBUG: 
                //      s = "--> call_[" f.Class.Names[0] "." f.Names[0] "]"
                //      CASE f.Is_overload ?
                //           s << "(" f.Param[0].Type_.Names[0] ")" ;
                //      << Repeat("  ", level_add) s #NL
                //      CASE s == "--> call_[{Geometry}.S]" ? ; 
                //;

                //CASE f !IN observed[] ?
                //     observed[] << f
                //     collect_functions_used(f) ;
                add_called_to_functions_used(f)
            ;
            FOR f IN F.Use_functions_[] : 
                add_called_to_functions_used(f) ;
            FOR t IN F.Classes_created_[]:
            	CASE t !IN Classes_objects_created[] ?
			         //DEBUG: << "#########################################"
			         //" found constructor called for class " t.Names[0] 
			         //#NL#NL ;
			         Classes_objects_created[] << t ;
			;
        ;
            .
            
        METHOD collect_callback_functions(
        {Type} C|lass_which_callbacks_to_add)
        	:
		    FOR m IN C.Method[] :
		        CASE m.Modifiers['STATIC'] || !m.is_callback ?
		             CONTINUE m ;
		        CASE m !IN Functions_used[] ?
		             //DEBUG: Console_color('OLIVE')
		             //		<< "method " C.Names[0] 
		             //		"." m.Names[0] " is CALLBACK"#NL ;
		             CASE m.Usage_count == 0 ? m.Usage_count = 1 ; 
		             Functions_used[] << m
		             FOR mov IN m.Overloaded_[] : Functions_used[] << mov ;
		             CASE m.Pop_method_ != NONE 
                 	  	  && m.Pop_method_ !IN Functions_used[]
                 	  	  ?
                      	  Functions_used[] << m.Pop_method_ ;
		             collect_functions_used(m) 
		        ;
			; .
			
        INT level_add|_called_to
            
        METHOD add_called_to_functions_used(
        	{Fun} F|unction_from), RECURSIVE
        	:
		PUSH indent_c = indent_c "b  ":
		PUSH level_add = level_add + 1 :
             CASE F !IN Functions_used[] ?
                  Functions_used[] << F
                  //DEBUG:
                  //      STR s|tring_to_out
                  //	  CASE F.Names[0] == "Merge" ?
                  //	       Console_color('RED') ;
                  //    s = "--> add [" F.Class.Names[0] "." F.Names[0] "]"
                  //    CASE F.Is_overload ?
                  //         s << "(" F.Param[0].Type_.Names[0] ")" ;
                  //    CASE F.Overloaded_[].Count > 0 ?
                  //         s << " ... overloaded<" F.Overloaded_[].Count.S ">" ;
                  //    << Repeat("  ", level_add) s #NL
                  //    CASE s == "--> add [{Geometry}.S]" ? ;
                  //    Console_color('SILVER')     
                  //;     
                  
                  FOR fov IN F.Overloaded_[] : Functions_used[] << fov ;
                  CASE F.Pop_method_ != NONE 
                 	   && F.Pop_method_ !IN Functions_used[]
                 	   ?
                       Functions_used[] << F.Pop_method_ ;
                  //DEBUG: 
                  //      CASE F.Total_fn == 18062 ?
                  //           << "000000000000000000000000000000000000000000"
                  //           	" " F.Names[].Whole_name " is used: 2"#NL ;
                  //;
     			  CASE !F.Modifiers['STATIC'] ?
     			  	   add_all_ancestors_and_descendants_of_method(F) ;
             ;
             CASE F.Class !IN Classes_used[] ?
            	  //DEBUG:
            	  //         CASE F.Class.Names[0] == "{Mathematics}" ?
            	  //         		<< "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
            	  //         		   " {Mathematics} is used from its function "
            	  //         		   "" F.Names[].Whole_name #NL ;
            	  //;
            	  //DEBUG: << report_i++.Str ": " indent_c "++++++++++++++++++++ "
            	  //	 "" F.Class.Names[0] #NL ;
                  Classes_used[] << F.Class ;
             FOR f IN F.Call_functions_[] : 
                 //DEBUG: "??? " f.Names[0] #NL ;
                 
             	 //used[] << f ;
                 CASE f !IN Functions_used[] ?
                 	 //DEBUG: 
                 	 //     CASE F.Names[0] == "Is_NAN" ?
                 	 //          << "000000000000000000000000000000000000000000"
                 	 //          	" " F.Names[].Whole_name " is used: 2"#NL ;
                 	 //;
	                 add_classes_from_method(f)
	                 CASE f !IN observed[] ? 
	                      observed[] << f
	                      add_called_to_functions_used(f) ;
                 ;
             ;
             FOR f IN F.Use_functions_[] :
                 add_classes_from_method(f) ;
		;
		;
            .
            
		METHOD add_all_ancestors_and_descendants_of_method(
			{Fun} F|unction_virtual)
			:
			FOR c IN All_classes[]:
			    CASE c.Is_descend(F.Class, THIS) ?
			         add_descending_method(F, c)
			         CONTINUE c ;
			    CASE F.Class.Is_descend(c, THIS) ?
			         add_ancesting_method(F, c) ;
			; .
			
   		METHOD add_descending_method(
   			{Fun} F|unction_base,
   			{Type} C|lass_in_which_descending_method_is)
   			:
	        FOR m IN C.Method[]:
	            CASE m.Names[0] == F.Names[0] ?
	                 CASE m !IN Functions_used[] ?
	                      collect_functions_used(m)
	                      //Functions_used[] << m
	                 ;
	                 ==> ;
	        ; .
			
   		METHOD add_ancesting_method(
   			{Fun} F|unction_base,
   			{Type} C|lass_in_which_ancesting_method_is)
   			:
	        FOR m IN C.Method[]:
	            CASE m.Names[0] == F.Names[0] ?
	                 CASE m !IN Functions_used[] ?
	                      collect_functions_used(m)
	                      //Functions_used[] << m
	                 ;
	                 ==> ;
	        ; .
			
            
        METHOD add_classes_from_method(
        	{Fun} F|unction)
        	:
        PUSH indent_c = indent_c "c  ":
             CASE F.Class !IN Classes_used[] && F.Class.Path != "" ?
                  collect_class_type_used(F.Class)
             	  //DEBUG: << report_i++.Str 
             	  //		 ": " indent_c "++++++++++++++++++++(" F.Names[0] 
             	  //		 ")<- " F.Class.Names[0] #NL ;
             	  //Classes_used[] << F.Class
             ;
            ------------------------- 'collect all used classes'
            FOR v IN F.Param[] :
                CASE ?
                [v.Type_.Kind == 'CLASS' && v.Type_ !IN Classes_used[]] ?
	                 //DEBUG:
	                 //      CASE F.Class.Names[0] == "{Text_file}" ?
	                 //      		<< "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
	                 //      		   " {Text_file} is used from local variables "
	                 //      		   "" v.Names[].Whole_name
	                 //      		   " of function " F.Names[].Whole_name #NL ;
	                 //;
	                 //DEBUG: << report_i++.Str 
	                 //		   ": " indent_c "++++++++++++++++++++(" v.Names[0] 
	                 //		   ") " v.Type_.Names[0] #NL ;
                     Classes_used[] << v.Type_
                [v.Type_.Kind == 'STRUCTURE'
                 && v.Type_.In_class_ !IN Classes_used[]] ?
                 	 Classes_used[] << v.Type_.In_class_
                ;
            ;
            FOR v IN F.Local_var[] :
                CASE ?
                [v.Type_.Kind == 'CLASS' && v.Type_ !IN Classes_used[]] ?
	                 //DEBUG:
	                 //      CASE F.Class.Names[0] == "{Text_file}" ?
	                 //      		<< "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
	                 //      		   " {Text_file} is used from local variables "
	                 //      		   "" v.Names[].Whole_name
	                 //      		   " of function " F.Names[].Whole_name #NL ;
	                 //;
	                 //DEBUG: << report_i++.Str 
	                 //		   ": " indent_c "++++++++++++++++++++(" v.Names[0] 
	                 //		   ") " v.Type_.Names[0] #NL ;
                     Classes_used[] << v.Type_
                [v.Type_.Kind == 'STRUCTURE'
                 && v.Type_.In_class_ !IN Classes_used[]] ?
                     Classes_used[] << v.Type_.In_class_
                ;
            ;
            CASE ?
            [F.Result.Type_.Kind == 'CLASS'
             && F.Result.Type_ !IN Classes_used[]] ?
                 //DEBUG: << report_i++.Str 
                 //		": " indent_c "++++++++++++++++++++ "
                 //		"" F.Result.Type_.Names[0] #NL ;
                 Classes_used[] << F.Result.Type_
            [F.Result.Type_.Kind == 'STRUCTURE'
             && F.Result.Type_.In_class_ !IN Classes_used[]] ?
                 Classes_used[] << F.Result.Type_.In_class_
            ;
        ;
            .
            
        METHOD finish_collecting_classes_used,
        	RECURSIVE
        	:
		PUSH indent_c = indent_c "d  ":
            ----------------------- 'check which classes still have descendants'
            FOR c IN All_classes[] : c.Has_descendant = FALSE ;
            FOR c IN All_classes[] :
                CASE c.Base_ != NONE ?
                     c.Base_.Has_descendant = TRUE ;
                CASE c.Anyway && c !IN Classes_used[] ?
                     collect_class_type_used(c) ;
            ;
            INT was_classes = Classes_used[].Count
            FOR c IN Classes_used[] :
                //DEBUG: << "finish collecting by class " c.Names[].Whole_name 
                //			#NL;
                PUSH indent_c = indent_c c.Names[0] :
                     FOR im IN c.Import_[]:
                         CASE !im.Anyway ? CONTINUE im ;
                         PUSH indent_c = indent_c "A":
                     	 	  collect_class_type_used(im) ;
                     ;
	                 CASE ?
	                 [c.Base_ != NONE && c.Base_ !IN Classes_used[]] ?
	                      Classes_used[] << c.Base_
	                 [c.In_class_ != NONE && c.In_class_ !IN Classes_used[]] ?
	                      Classes_used[] << c.In_class_
	                 ;
	                 PUSH indent_c = indent_c "1" :
	                      collect_functions_used(c.Construct) ;
	                 PUSH indent_c = indent_c "2" :
	                      collect_functions_used(c.Destruct) ;
	                 ----------------------- 'add classes referenced by fields'
	                 FOR v IN c.Field[] :
	                     CASE v.Type_.Kind !IN ['CLASS' ,'ENUM', 'STRUCTURE']
	                     	  ?
	                          CONTINUE v ;
	                     //DEBUG:
	                     //      CASE v.Type_ !IN Classes_used[] ?
	                     //           << "adding type " v.Type_.Final_name 
	                     //           	" by field "
	                     //           	"" c.Names[].Whole_name 
	                     //           	"." v.Names[0]
	                     //           	#NL ;
	                     //;
	                	 collect_class_type_used(v.Type_)
	                 ;
	                 FOR m IN c.Method[]:
	                     CASE is_callback(m) ?
	                          collect_functions_used(m) ;
	                     collect_class_type_used(m.Result.Type_)
	                     FOR p IN m.Param[]:
	                         collect_class_type_used(p.Type_) ;
	                 ;
	                 CASE !c.Anyway ? CONTINUE c ;
	                 PUSH indent_c = indent_c "3" :
	                      collect_class_type_used(c)
	                 ;
                ;
            ;
            CASE Classes_used[].Count > was_classes ?
                 finish_collecting_classes_used ;
		;
            .
            
		FUNCTION is_callback({Fun} M|ethod_to_check) ==> BOOL:
			{Fun} f|unction_or_its_predecessor = M
			FOR i|dummy IN [0 TO MAX_INT-1]:
			    CASE f == NONE ? ==> ;
			    CASE f.Modifiers['CALLBACK'] ? RESULT = TRUE ==> ;
			    f = f.Ancestor_ ; .
                 
   		METHOD collect_class_type_used(
   			{Type} T|ype_used), RECURSIVE
   			:
			CASE T.Path == "" ? ==> ;

		PUSH indent_c = indent_c "e  ":
   			CASE T.Kind == 'CLASS' && T !IN Classes_used[] ?
                 //DEBUG: << report_i++.Str ": " indent_c 
                 //			"++++++++++++++++++++" T.Names[0] #NL ;
                 Classes_used[] << T
                 PUSH indent_c = indent_c "1" :
                 collect_functions_used(T.Construct) ;
                 PUSH indent_c = indent_c "2" : 
                 collect_functions_used(T.Destruct) ; 
                 PUSH indent_c = indent_c "3" : 
                 	FOR v IN T.Field[]:
                 	    CASE v.Type_.Kind IN ['CLASS', 'STRUCTURE'] ?
                 	         collect_class_type_used(v.Type_) ;
                 	;
                 ;
                 PUSH indent_c = indent_c "4" :
                      FOR f IN T.Method[]:
                          CASE f.Depends[].Count==0 ? CONTINUE f ;
                          //DEBUG: << "Ddddddddddddddddddddddddddddddddddd"
                          //"epends found: " f.Names[0] "(" f.Depends[].Count.Str
                          //")" #NL ;
                          PUSH Current_class = T :
                          PUSH Current_class.Parse.Line = f.Line_start :
	                          FOR d IN f.Depends[]:
	                          	  collect_class_depending_on(d, T) ;
                          ;
                          ;
                      ;
                 ;
                 PUSH indent_c = indent_c "5" :
                 	  FOR v IN T.Field[] :
                      	  CASE !Debugging ? BREAK v ;
                      	  CASE !v.Modifiers['TRAP'] ? CONTINUE v ;
                      	  CASE v.Trap_read_ != NONE ?
                      	  	   collect_functions_used(v.Trap_read_) ;
                      	  CASE v.Trap_write_ != NONE ?
                      	       collect_functions_used(v.Trap_write_) ;
                 	  ;
                 ;
   			;
            CASE T.Kind == 'STRUCTURE' && T.In_class_ !IN Classes_used[] ?
                 Classes_used[] << T.In_class_ ;
		;
            .
            
            
		METHOD collect_class_depending_on(
			STR D|ependence_definition,
			{Type} Search_in|_class)
			:
		PUSH indent_c = indent_c "g  ":
			STR name_c|lass = D
			CASE "." IN D ?
			     INT p|osition_of_dot = D.Find(".")
			     STR name_f|unction = D.[p+1 TO *] 
			     name_c = D.[0 TO p-1] ;
			{Type} c|lass_to_add = Search_in.Find_type(name_c)
			//DEBUG: << report_i++.Str ": " indent_c
			//		"~~~~~~~~~~~~~ depending on class " c.Names[0]
			//		CASE c !IN Classes_used[] ?
			//		     << " ADDDDDDDDDDDDDDDDDDDDDDED!!!!!!!!!!" ;
			//		<< #NL ;
			collect_class_type_used(c)
			CASE name_f == "" ? ==> ;
			{Fun} f|unction_depending_on = c.Find_fun(name_f, TRUE)
			collect_functions_used(f)
		; 
			. 

                 
        
        INT count_removed_static_f|unctions
        
        METHOD remove_unused_static_functions :
			//DEBUG:
			//	CASE Any_class_from_ccc ?
			//	     << "remove_unused_classes called!!!" #NL >> ;
			//;
            -------------------------------- 'optimization R1'
            FOR c IN All_classes[] :
                //DEBUG: << "__________ removing static functions in: "
                //		  "" c.Names[0] " (" c.Final_name ")" #NL ;
                FOR i IN [c.Method[].Count-1 DOWNTO 0] :
                    {Fun} m|ethod_of_class_c = c.Method[i]
                    CASE m.Final_name == "-" ? CONTINUE i ;
                    //DEBUG:
                    //      CASE m.Total_fn == 12017 ?
                    //           << #NL "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"
                    //           " function " m.Names[].Whole_name " is under "
                    //           "consideration Static=" m.Modifiers['STATIC'].S
                    //           " Generic=" (m.Generic_prototype_ != NONE).S
                    //           " Native=" m.Modifiers['NATIVE_FUN'].S
                    //           " used=" (m IN Functions_used[]).S
                    //           " Usage_count=" m.Usage_count.S
                    //           " Count_R1=" Count_R1.S
                    //           " Actual_function_param=" 
                    //           "" m.Is_actual_function_param.S #NL ;
                    //;  
                    //CASE m.Modifiers['POP'] && m.Usage_count > 0 ?
                    //     CONTINUE i ;
                    CASE m.Modifiers['STATIC'] && (
                         !m.Modifiers['NATIVE_FUN']) && (
                         m !IN Functions_used[]) && !m.Modifiers['CALLBACK']
                         && ( //m.Usage_count == 0) && (
                         Count_R1 < Maximum_op("R1")) && (
                         Count_R0 + Count_R1 + Count_R2 + Count_R3 + Count_R4 <(
                         Maximum_op("R")))
                         ?
                         //&& !(m.Usage_count > 0 && m.Is_overload)
                         ------------------------- 'can remove static function'
                         //DEBUG:
                         //      CASE m.Total_fn == 13000 ?
                         //           << "!!!!!!!!!!!!!!!!!! REMOVED "
                         //           "" m.Total_fn.S #NL >> STR debug_rrrr ;
                         //;
                         count_removed_static_f += 1
                         Console_color({colors}.'CYAN')
                         report_remove_method(m, "R1", Count_R1)
                         //DEBUG: 
                         //      CASE Count_R1 == 30 ? NONE ;
                         //;
                         Count_R1 += 1
                         Optimizations_count += 1
                         //c.Method[].Delete(i)
                         ---------------- 'should not left a code referencing m'
                         remove_references_to_method(m)
					;
                ;
            ; .
                
        METHOD remove_unused_native_functions :
			//DEBUG:
			//	CASE Any_class_from_ccc ?
			//	     << "remove_unused_native_functions!!!" #NL >> ;
			//;
            ---------------------------------- 'optimization R2'
            {Fun} save_functions_used[]
            FOR fu IN Functions_used[] : save_functions_used[] << fu ;
            {Fun} can|_remove[]
            FOR c IN All_classes[] :
                CASE c.Anyway ?
                     //DEBUG: << "ccccccccccccccccccccccclass " c.Names[0]
                     //		" marked as ANYWAY ANYWAY ANYWAY ANYWAY ANYWAY "#NL
                     //;
                     CONTINUE c ;
                FOR i IN [c.Method[].Count-1 DOWNTO 0] :
                    {Fun} m|ethod_of_class_c = c.Method[i]
                    CASE ?
                    [m.Final_name == "-"] ? CONTINUE i
                    [m.Depends[].Count > 0] ? CONTINUE i
                    [m.Removed] ? CONTINUE i 
                    [m.Usage_count > 0] ? CONTINUE i //++++++++++++++++++
                    [m IN can[]] ? CONTINUE i ;
                    //CASE m.Usage_count > 0 ? CONTINUE i ;
                    //CASE m.Modifiers['POP'] ? CONTINUE i ;
                    CASE m.Modifiers['STATIC'] && m.Modifiers['NATIVE_FUN'] && (
                         m !IN Functions_used[]) && m.Final_name != "-" && (
                         Count_R2 < Maximum_op("R2"))  && (
                         Count_R0 + Count_R1 + Count_R2 + Count_R3 + Count_R4 <(
                         Maximum_op("R")))
                         ?
                         ------------------------ 'can remove native function'
                         can[] << m
                         //c.Method[].Delete(i)
                         //remove_references_to_method(m)
                    ;
                ;
            ;
            FOR c IN All_classes[] :
                CASE c.Anyway ? CONTINUE c ;
                FOR i IN [c.Method[].Count-1 DOWNTO 0] :
                    m = c.Method[i]
                    CASE ?
                    [m.Removed] ? CONTINUE i
                    [m.Usage_count == 0 || m.Count_ref == 0] ? CONTINUE i 
                    ;
                    CASE m !IN can[] ? collect_functions_used(m) ;
                ;
            ;
            FOR c IN All_classes[] :
                CASE c.Anyway ? CONTINUE c ;
                FOR i IN [c.Method[].Count-1 DOWNTO 0] :
                    m = c.Method[i]
                    CASE m IN Functions_used[] || m !IN can[] ? CONTINUE i ;
                    m.Removed = TRUE
                    ------------------- 'report removing native function'
                         Console_color({colors}.'YELLOW')
                         report_remove_method(m, "R2", Count_R2)
                         Count_R2 += 1
                         Optimizations_count += 1
                    ------------------- 'remove it'
                    remove_references_to_method(m) ;
            ; 
            --------------- 'restore Functions_used[]'
            Functions_used[].Clear
            FOR fu IN save_functions_used[] : Functions_used[] << fu ;
            .
                
        METHOD remove_unused_final_methods :
			//DEBUG:
			//	CASE Any_class_from_ccc ?
			//	     << "remove_unused_final_methods called!!!" #NL >> ;
			//;
			{Fun} save_functions_used[]
            FOR fu IN Functions_used[] : save_functions_used[] << fu ;
            {Fun} can|_remove[]
            ------------------------------------- 'optimization R3'
            FOR c IN All_classes[] :
                CASE c.Anyway ? CONTINUE c ;
                //CASE c.Has_descendant ? CONTINUE c ;
                FOR i IN [c.Method[].Count-1 DOWNTO 0] :
                    {Fun} m|ethod_of_class_c = c.Method[i]
                    CASE ?
                    [is_callback(m)] ? CONTINUE i
                    [m.Final_name == "-"] ? CONTINUE i
                    
                    [m == m.Class.Construct || m == m.Class.Destruct]? 
                        CONTINUE i
                    
                    [m.Modifiers['TRAP_FUN']] ? CONTINUE i
                    [m.Modifiers['STATIC'] || m.Modifiers['NATIVE_FUN']
                     || m IN Functions_used[]] ?
                         CONTINUE i
                    [m.Getter_field_.Used_for_w || (
                     m.Getter_method_ != NONE) && (
                     m.Getter_method_ IN Functions_used[])] ?
                         CONTINUE i ;
                    //DEBUG:
                    //      << "tttttttttttttttttttttry to remove method "
                    //         "" c.Names[0] "." m.Names[0] " ???????????" #NL
                    //; 
                    STR e|xcept_nothing[]
                    CASE m.Ancestor_ != NONE || Overridden(
                    	 m.Names[0], c.Names[0], e[])
                    	 ?
                         CONTINUE i ;
                    ------------------------ 'can remove native function'
                    can[] << m
                ;
            ;
            FOR c IN All_classes[] :
                CASE c.Anyway ? CONTINUE c ;
                //CASE c.Has_descendant ? CONTINUE c ;
                FOR i IN [c.Method[].Count-1 DOWNTO 0] :
                    m = c.Method[i]
                    CASE is_callback(m) ? CONTINUE i ;
                    CASE m.Final_name == "-" ? CONTINUE i ;
                    CASE ?
                    [m.Removed] ? CONTINUE i
                    [m.Usage_count == 0 || m.Count_ref == 0] ? CONTINUE i 
                    ;               
                    CASE m !IN can[] ?
                         collect_functions_used(m) ;
                ;
            ;
            FOR c IN All_classes[] :
                CASE c.Anyway ? CONTINUE c ;
                FOR i IN [c.Method[].Count-1 DOWNTO 0] :
                    m = c.Method[i]
                    CASE m IN Functions_used[] || m !IN can[] ? CONTINUE i ;
                    //CASE m.Modifiers['POP'] ? CONTINUE i ;
                    CASE m != m.Class.Construct && m != m.Class.Destruct && (
                         Count_R3 < Maximum_op("R3"))  && (
                         Count_R0 + Count_R1 + Count_R2 + Count_R3 + Count_R4 <(
                         Maximum_op("R")))
                         ?
                         m.Removed = TRUE
                         --------------------- 'can remove final virtual method'
                         //DEBUG:
                         //      CASE m.Total_fn == 13000 ?
                         //           << "!!!!!!!!!!!!!!!!!! REMOVED "
                         //           "" m.Total_fn.S #NL >> STR debug_rrrr ;
                         //;
                         Console_color({colors}.'OLIVE')
                         report_remove_method(m, "R3", Count_R3)
                         Console_color({colors}.'SILVER')
						 Count_R3 += 1
                         Optimizations_count += 1
                         //c.Method[].Delete(i)
                         remove_references_to_method(m)
                    ;
                ;
            ;
            --------------- 'restore Functions_used[]'
            Functions_used[].Clear
            FOR fu IN save_functions_used[] : Functions_used[] << fu ;
            .
            
        //INT cnt_remove_ref|erence
            
        METHOD remove_references_to_method(
        	{Fun} M|ethod_to_unreference)
        	:
            FOR c IN All_classes[] :
                FOR f IN c.Method[] :
                    CASE M !IN f.Call_functions_[]
                    	 && M !IN f.Use_functions_[]
                    	 || f.Modifiers['POP'] 
                    	 ? 
                         CONTINUE f ;
                    //CASE f.Modifiers['POP'] ?
                    //     DEBUG: << "want to remove method " f.Names[0] " body "
                    //     		" because it is calling " M.Names[0] " which is"
                    //     		" marked to remove!!!!!!!!!!!!!!!!!!!!"#NL ;
                    //     CONTINUE f ; // otherwise problems in Android
                    //DEBUG:
                    //      cnt_remove_ref += 1
                    //      << "Removing block from method " c.Names[0]
                    //      "." f.Whole_name " to remove references"
                    //      " to method " M.Class.Names[0]
                    //      "." M.Whole_name " #" cnt_remove_ref.Str #NL ;
                    f.Block[].Clear
                    f.Call_functions_[].Clear 
                    f.Use_functions_[].Clear
                ;
            ; .
                
        METHOD remove_unused_classes :
            FOR i IN [All_classes[].Count-1 DOWNTO 0] :
                {Type} c|lass_at_i = All_classes[i]
            	CASE c.Modifiers['NATIVE'] && c.Structures_[].Count > 0 ?
            	     CONTINUE i ;
                CASE c.Anyway || has_used_descendant(c) ?
                     //DEBUG:
                     //	CASE c.Anyway ? << c.Names[0] " is anyway anyway" #NL 
                     //	ELSE << "has used descendants: " c.Names[0] #NL ;
                     //;
                     CONTINUE i ;

                FOR u IN All_classes[]:
                    CASE class_methods_call_functions_of_class(u, c) ?
                         BREAK u, CONTINUE i ;
                    CASE class_methods_use_types_of_class(u, c) ?
                         BREAK u, CONTINUE i ;
                ;
                        
                CASE c !IN Classes_used[] && (
                     Count_R4 < Maximum_op("R4"))  && (
                         Count_R0 + Count_R1 + Count_R2 + Count_R3 + Count_R4 <(
                         Maximum_op("R")))
                     && c.Structures_[].Count == 0 //todo: 1st remove unused structures
                     ?
                     Console_color({colors}.'RED')
                     << " removing unused class: " c.Whole_name #NL
                     Console_color({colors}.'SILVER')
                     
					 Count_R4 += 1
                     Optimizations_count += 1
                     Removed_classes[] << All_classes[i]
                     All_classes[].Delete(i) ;
            ; .
            
   		FUN class_methods_call_functions_of_class(
   			{Type} From|_class,
   			{Type} To|_class) ==> BOOL
   			:
			FOR f IN From.Method[] :
			    FOR called IN f.Call_functions_[]:
			        //DEBUG:
			        //      CASE f.Total_fn == 17011 ?
			        //           << "------------- fn " f.Total_fn.S 
			        //           	  ", named " f.Names[].Whole_name 
			        //           	  " calls method / function " 
			        //           	  "" called.Class.Names[0] 
			        //           	  "." called.Names[].Whole_name #NL ;
			        //;
			        CASE called.Class == To ? RESULT = TRUE ==> ;
			    ;
			; .
			
		FUN class_methods_use_types_of_class(
			{Type} From|_class,
   			{Type} To|_class) ==> BOOL
   			:
   			FOR f IN From.Method[] :
   			    FOR v IN f.Local_var[] :
   			        CASE v.Type_ == To || (
   			        	 v.Type_.Kind == 'STRUCTURE' && v.Type_.In_class_ == To)
   			        	 ?
   			             RESULT = TRUE ==> ;
   			    ;
   			; .
            
		METHOD has_used_descendant(
			{Type} C|lass_to_check) ==> BOOL
			:
			FOR u IN Classes_used[] :
			    CASE u != C && u.Is_descend(C, THIS) ? RESULT = TRUE ==> ;
			; .
                
        METHOD report_remove_method( {Fun} M|ethod_removed,
            STR Rule|_name, INT Count|_removed )
            :
			INT i|ndex_in_methods INDEXING {Fun} = M.Class.Method[].Find(M)
            M.Class.Method[i] = NONE
            FOR j|dummy IN [M.Class.Removed_method[].Count TO i] :
                M.Class.Removed_method[] << NONE ;
            M.Class.Removed_method[i] = M
            M.Removed = TRUE
            ------------------------------- 'report removing methods'
            CASE !Verbose2 ?
                 CASE Maximum_op(Rule) == MAX_INT && Maximum_op(
                      Rule.[0]) == MAX_INT
                      ?
                      ==> ;
            ;
            ------------------------------- 'removing: method/function'
            << "removing function" 
            ": " M.Class.Names[0] "." M.Whole_name " (" ("rule"._Mrule ) 
            ": " Rule ", " ("usage"._Musag ) ":"
            "" M.Usage_count.Str ")"
            " " ("count_removed"._Mcount ) ": " Count.Str #NL
            
            //DEBUG:
            //      CASE Count == 29 ? ;
            //;
            Console_color({colors}.'SILVER') .
            
		METHOD Overridden(
			STR Method|_main_part_of_name,
			STR Base_class|_name_which_descendants_should_be_checked,
			STR Except|_classes_descandant_DYN[]) ==> BOOL
			:
			------------------------------- 'find base class'
			FOR c IN All_classes[] :
				CASE c.Names[0] == Base_class ?
					 {Type} b|ase_class_type = c
					 BREAK c ;
			;
			CASE b == NONE ? ==> ;
			-------------------------- 'check all classes descendant from b'
			FOR c IN All_classes[] :
				CASE c.Names[0] IN Except[] ? CONTINUE c ;
			    CASE c == b || !c.Is_descend(b, THIS) ? CONTINUE c ;
			    //DEBUG: << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(" 
			    //		  "" Method ")"#NL
			    //		  "class " c.Names[].Whole_name " decscending"#NL ;
			    FOR f IN c.Method[]:
			        //DEBUG: << f.Names[0] " " ;
			        //CASE f.Ancestor_ == NONE ? CONTINUE f ;
			        CASE f.Names[0] == Method.Trim ?
			             //DEBUG: << "__________________________________"#NL
			             //"method " Method " is overridden in "
			             //"class " c.Names[].Whole_name //>> STR in|_dummy
			             //;
			        	 RESULT = TRUE ==> ;
			    ;
			; .
			
		INT total_copy_var|_index
		
		METHOD Next_copy_var_idx ==> STR :
			RESULT = total_copy_var.Str 
			total_copy_var += 1 .
			
        INT Count_extr|acted_new_object_creations = 0
        
-------------------------- 'check for side effects'

	BOOL no_side_effects
	BOOL got_no_side_effects
        
        METHOD Check_expressions_for_side_effects(
        {Fun} F|unction_checking,
        {Statement} B|lock_statements_DYN[]) ==> BOOL, RECURSIVE
        	:
        	CASE !got_no_side_effects ? 
        	     no_side_effects = "$NO_SIDE_EFFECTS" IN Defined_name[]
        	     || "$NOSIDEEFFECTS" IN Defined_name[] 
        	;
	        CASE no_side_effects ? ==> ;
			//DEBUG:
			//      CASE F.Total_fn == 18070 ?
			//           NONE ;
			//;
			BOOL total_result = FALSE
			FOR st IN B[] :
			    ------------------- 'check certain statement'
			    //DEBUG:
			    //      CASE st.Total_stmt == 34614 ?
			    //           NONE ;
			    //;
			    CASE st.Work ?
			    ['ASSIGN', 'APPEND', 'INPUT', 'OUTPUT', 'PUSH', 'STOP']:
			    	{Assign} a|ssignment = st.{Assign}
			    	RESULT = check_expressions_of_statement( F, st, a.Dest)
			    	
			    	BOOL source_side_e|ffects_possible 
			    		 = check_expressions_of_statement(F, st, a.Source)
			    		 
			    	RESULT ||= source_side_e
			    	
			    	CASE !RESULT && a.Dest.Operation == 'FIELD' ?
			    		 RESULT = a.Dest.Arg1_.Type_expr.Kind == 'CLASS' 
			    	;
			    	
			    ['CASE', 'DEBUG', 'ASSERT', 'ELSE', 'LIMIT', 'LOCAL']:
			    	RESULT = check_expressions_of_statement(
			    			F, st, st.{Case}.Condition)
			    			
			    	RESULT ||= Check_expressions_for_side_effects(F, st.Block_[])

			    ['FOR']:
			    	RESULT = check_expressions_of_statement(
			    			F, st, st.{For}.Array)
			    			
			    	RESULT ||= check_expressions_of_statement(
			    			F, st, st.{For}.Range1)
			    			
			    	RESULT ||= check_expressions_of_statement(
			    			F, st, st.{For}.Range2)
			    			
			    	RESULT ||= Check_expressions_for_side_effects(F, st.Block_[])
			    	
			    ['BREAK','NEXT','CONTINUE','RETURN','CALL_NATIVE','COMMENT']:
			    	NONE ;
			   total_result ||= RESULT
			; 
			RESULT = total_result .
			
        METHOD check_expressions_of_statement(
        {Fun} F|unctions_checking,
        {Statement} St|atement_if_line_is_necessary,
        {Expr} E|xpression_to_check) ==> BOOL, RECURSIVE
        	:
        	CASE E == NONE ? ==> ;
        	
        	BOOL before|_statements_have_side_effects 
        		 = Check_expressions_for_side_effects(F, E.Before_assign_[])
        		 
			CASE E.Operation ?
			['BINARY']:
				INT count_det|ected_side_effects = 0
				INT count_field|_access_possible = 0
				CASE E.Items_[].Count == 0 ?
				     CASE ?
				     [check_expressions_of_statement(F,  St, E.Arg1_)] ?
				          count_det += 1
				     [accessing_fields(E.Arg1_)] ?
				          count_field += 1
				     ;
					 CASE ?
					 [check_expressions_of_statement(F, St, E.Arg2_)] ?
					      count_det += 1
					 [accessing_fields(E.Arg2_)] ?
					      count_field += 1
					 ;
				     CASE count_det > 0 && count_field > 0
				     	  && E.Sign IN ['CONCAT', 'PLUS', 'MINUS', 'MULT',
				     	  'DIV', 'REST', 'AND', 'OR', 'AND_B', 'OR_B', 'XOR_B']
				     	  || count_det >= 2 
				     	  ?
				          side_effects_in_expr(F, St, E) ;
				     RESULT = count_det > 0 || before ==> ;
				FOR it IN E.Items_[] :
					CASE ?
					[check_expressions_of_statement(F, St, it)] ?
					     count_det += 1
					[accessing_fields(it)] ?
					     count_field += 1
					;
					CASE count_det > 0 && count_field > 0 || count_det >= 2 ?
					     side_effects_in_expr(F, St, it) ==> ;
				;
				RESULT = count_det > 0 || before
				
			['FUN', 'BASE_FUN', 'SYSTEM_FUN'] :
				FOR it IN E.Items_[] :
					CASE check_expressions_of_statement(F, St, it) ?
					     count_det += 1 ;
					CASE count_det >= 2 ?
					     side_effects_in_expr(F, St, E) ==> ;
				;
				RESULT = count_det > 0
				RESULT ||= check_expressions_of_statement(F, St, E.This_)
				RESULT ||= before
				RESULT ||= E.Fun_.Has_side_effects
				
			['INDEX'] :
				CASE ?
				[check_expressions_of_statement(F, St, E.Arg1_)] ?
				     count_det += 1
				[accessing_fields(E.Arg1_)] ?
				     count_field += 1
				;
				CASE ?
				[check_expressions_of_statement(F, St, E.Arg2_)] ?
				     count_det += 1
				[accessing_fields(E.Arg2_)] ?
				     count_field += 1
				;
				CASE ?
				[check_expressions_of_statement(F, St, E.Arg3_)] ?
				     count_det += 1
				[accessing_fields(E.Arg3_)] ?
				     count_field += 1
				;
				CASE count_det > 0 && count_field > 0 || count_det >= 2 ?
					 side_effects_in_expr(F, St, E) ;
				RESULT = count_det > 0 || before
				
			['FIELD', 'VAR']:
				RESULT = check_expressions_of_statement(F, St, E.Arg1_)
						 || before
				
			['NEW_OBJ']:
				RESULT = Check_expressions_for_side_effects(F, E.Assignments_[])
						 || before
				
			['INT2REAL', 'NOT', 'NOT_B', 'NEG', 'AS']:
				RESULT = check_expressions_of_statement(F, St, E.Arg1_)
						 || before
				
			['UNKNOWN', 'ARRAY', 'CONSTANT']: NONE ; .
			
        FUN accessing_fields({Expr} E|xpression_to_check) ==> BOOL :
        	RESULT = E.Operation == 'FIELD'
        	RESULT ||= E.Operation == 'VAR' && E.Arg1_ != NONE .
			
        FUNCTION side_effects_in_expr(
        {Fun} F|unction_of_expression,
        {Statement} St|atement_with_problem,
        {Expr} E|xpression_with_problem)
        	:
        	PUSH F.Class.Compiler.Current_class = F.Class :
        	PUSH F.Class.Compiler.Current_fun = F :
			PUSH F.Class.Parse.Line = St.Line :
			PUSH F.Class.Parse.Pos = E.At_pos :
			     CASE E.At_line > 0 ? F.Class.Parse.Line = E.At_line ;
			     
			     F.Class.Compiler.Error("Expression operands are calling "
			     "functions having side effects so order "
			     "of calculation can be important."
			     " It is necessary to separate the statement onto several "
			     "sequent statements to specify the calculation order "
			     "explicitly."._ESideEffect ": " F.Class.Parse.Next20)
			;
			;
			;
			; .
        
        */

    }
}
/*
END
*/

