/*

CLASS {Type|_of_variable}, 
UNTESTED, RECURSIVE, BITWISE:

IMPORT: {Variable}, {Function}, {Compiler}, {Parser}, {Text_parser},
        {File_path}, {Text_file}, {String_functions}, {Console},
        {Statement}, {Assignment}, {Expression}, 
        {Source}, {Table}, {Localize_str}, {Generator} ;
        
IMPORT: {System_functions} ;

IMPORT: {Hash_names} ;

IMPORT: {Testing} ;

*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using AL4Compiler.Statements;
using AL4Compiler._CSharp;
using AL4;

namespace AL4Compiler
{
    public class Type
    {

        public Type()
        {
        }
        /*

        ENUMERATION {kind_type}: 'BOOL|EAN_TYPE',
                    'INT|EGER_NUMBER', 'REAL|_NUMBER', 'STR|ING_OF_CHARS',
                    'ENUM|ERATION', 'CLASS|_OF_OBJECTS', //'BYTE|_OF_8_BITS',
                    'STRUCTURE' .
        */
        public enum Kind_type { BOOL, INT, REAL, STR, ENUM, CLASS };

        public static string[] Kind_type_names = new string[] {
            "BOOL", "INT", "REAL", "STR", "ENUM", "CLASS" };

        /*
        
        ENUMERATION {class_mod|ifier}:
			'ABSTRACT|_CLASS',
            'NATIVE|_FUNCTIONS_PRESENT', 'BAD|_CODE_STYLE',
            'BITWISE|_OPERATIONS', 'BYTES|_ARE_USED', 'DESTRUCTORS|_USED', 
            'RECURSIVE|_FUNCTIONS_PRESENT', 'INFINITE|_LOOPS_USED',
            'UNTESTED|_CODE', 'TESTED|_CODE', 'STOPPING',
            'OPERATORS|_DECLARED', 'OPERATIONS|_USED',
            'INT64_REQUIRED', 'INT64_DESIRED',
            'DEPRECATED', 'ABANDONED', 'SAFE|_CODE' .
        */
        public enum Class_mod { ABSTRACT, NATIVE, BAD, BITWISE, DESTRUCTORS, 
                RECURSIVE, INFINITE, UNTESTED, STOPPING, SHORT_STR,
				 SAFE };

        public string[] Class_mod_names = new string[] { 
            "ABSTRACT_CLASS", "NATIVE_FUNCTIONS", "BAD_CODE_STYLE", 
            "BITWISE_OPERATIONS", "DESTRUCTORS_USED", 
            "RECURSIVE_FUNCTIONS", "INFINITE_LOOPS", "UNTESTED_CODE",
            "STOPPING_EXECUTION", "SAFE_CODE" };

        /*
        STR         Names|_of_type[]
        
        METHOD Name_of_class|_or_file_where_it_is_from ==> STR :
            CASE Names[].Count > 0 ? RESULT = Whole_name ==> ; 
            RESULT = "{" Change_ext(Path.Extract_file_name, "") "}" .
            
        STR			Names_low|ered[]
        
        METHOD Provide_names_lowered :
			CASE Names_low[]. Count > 0 ? ==> ;
			FOR n IN Names[] : Names_low[] << n.Lower ; .
			
		STR whole_name|_cached
		
		METHOD Whole_name ==> STR :
		    CASE whole_name != "" ? RESULT = whole_name ==> ;
		    whole_name = Whole_name_of(Names[])
		    RESULT = whole_name .

        */
        public string Name()
        {
            if (Names.Count > 0) return Names[Names.Count - 1];
            return Path.GetFileName(this.Path_class_source);
        }
        /*
        ------------------------------- 'type attributes'
        {kind_type} Kind|_of_type
        STR         Final_name
        BOOL        Compiled
        BOOL        Is_precompiled
        INT         Line|_where_defined INDEXING STR
        STR         Deprecate|d_or_abandoned_text
        ------------------------------- 'containing'
        {Var}       Items|_enumeration[]
        {Type}      Sets_constants_[]
        {Expr}      Constant_expr|essions_to_calculate_while_testing[]
        ------------------------------ 'class only + fields for class/structure'
        {Type}      Enums_|in_class_[]
        {Type}      Structures_|in_class_[]
        {Var}       Const|ants[]
        {Fun}       Method|s_of_class[]
        {Fun}       Sorted_method|s_of_class[]
        {Var}       Field|s_of_class_or_structure[]
        ------------------------------ 'removed due to optimizations'
        {Fun}		Removed_method|s[]
        ------------------------------ 'construction and destruction'
        {Fun}       Construct|_method
        {Fun}       Destruct|_method
        ------------------------------ 'import was specified for'
        {Type}		Specified_|imported_enums_structures_[]
        {Type}		Outer_|used_enums_structures_[]
        ------------------------------ 'base class'
        INT         base_line
        {Type}      Base_|type_or_container_class_for_enum_
        
        METHOD Top_base|_class ==> {Type} :
	        RESULT = THIS
	        FOR i|dummy IN [0 TO Compiler.All_classes[].Count] :
	            CASE RESULT == NONE || RESULT.Base_ == NONE ? ==> ;
	            RESULT = RESULT.Base_ ; .
        
        {Type}		In_class_|for_objects_structs_
        {Assign}    Create_base|_statement
        {Var}       Init|ialized_fields[]
        BOOL        Has_descendant|_classes
        BOOL        Has_instances|_created_in_code
        ------------------------------ 'modifers and detected'
        BOOL        Modifiers|_of_class[{class_mod}]
        BOOL        Detected|_things[{class_mod}]
        INT			Tested_by|_percents_as_specified_in_header = 100
        REAL		Tested_actually|_by_percents
        BOOL		Anyway|_do_not_remove_due_to_optimization
        ------------------------------ 'class as module'
        {Type}      Import_|list_[]
        {Type}      Debug_import_|list_[]
        STR			Friends|_classes[]
        {Type}      Back_import_|added_with_function_parameters_passed_[]
        {Type}      Used_imports_[]
        STR         Ending_lines|_after_END_accessible_as_DATA[]
        ------------------------------ 'testing'
        {Type}      Test_import_[]
        {Fun}       Test|_functions[]
        BOOL        Tested|_flag_set_by_generator_on_testing_stage
        BOOL		Was_changed|_after_last_tests
        INT         Total_lines_in_test
        ------------------------------ 'strings to localize'
        INT			Localize_1st_item|_index_in_all_localization_strings_array
        STR         Localize_n|ames_of_strings[]
        {Expr}      Localize_s|trings[]
        INT         Localize_line|s_where_strings_are_defined[] //???????
        
        METHOD Load_localizations|_stored_in_separate_file(
        STR Path_loc|alizations)
            :
            STR lines|_load[]
             
            {Text_file} temp|_loaded = {Text_file}(
            	Path= Path_loc, Encoding='UTF8')
            	
            NONE = temp.Load(lines[])
            Localize_n[].Clear
            Localize_s[].Clear
            FOR s IN lines[] :
                INT i|ndex_of_eq = s.Find("=") 
                Localize_n[] << s.[0 TO i-1]
                
                Localize_s[] << {Expr}(Operation='CONST', 
                	Var_arg= {Var}(Line= 0, 
                		Str_c= s.[i+1 TO *], Type_= comp.TYPE_STR))
            ; .
        ------------------------------ 'cached parameters'
        INT         Cached_parameters|_count
		------------------------------ 'TABLEs defined in class'
		{Table}	Table|s_defined[]
        ------------------------------ 'temp info on current compile'
        {Fun}   Last_fun|ction_precompiled
        {Var}   Last_var|iable_precompiled
        --------------------------- 'additional information for code Generator'
        STR     Generate_info|rmation_only_for_Generator[]
        BOOL	Not_for_test|s_only_imported
		------------------------------------ 'RTTI'
		INT		Type_total_index
		INT		Original_type_index
		------------------------------------ 'save position between stages'
		INT		Line_continue|_compiling
		INT		Pos_cont|inue
		---------------------- 'additional information for code generation'
		STR		Ex_info|rmation[]
		INT		Count_stored|_fields_auto
        */
        public List<string> Names = new List<string>();
        public Kind_type Kind;
        public string Final_name = "";
        public bool Compiled;
        //---------------------- 'containing'
        public List<string> All_id = new List<string>();
        public List<Variable> Items = new List<Variable>();
        public List<Function> Test = new List<Function>();
        //---------------------- 'class only'
        public List<Type> Enums_ = new List<Type>();
        public List<Variable> Field = new List<Variable>();
        public List<Variable> Const = new List<Variable>();
        public List<Function> Method = new List<Function>();
        public Function Construct_method;
        public Function Destruct_method;
        //---------------------- 'modifiers and detected'
        public bool[] Modifiers = new bool[(int)Class_mod.SAFE + 1];
        public bool[] Detected = new bool[(int)Class_mod.SAFE + 1];
        public bool Tested;
        //---------------------- 'base class'
        int base_line;
        public Type Base_;
        public Assignment Create_base;
        public List<Variable> Initialized_fields = new List<Variable>();
        public bool Want_q;
        //---------------------- 'class as module'
        public List<Type> Import_ = new List<Type>();
        public List<string> Ending_lines = new List<string>();
        //---------------------- 'localization of string'
        public List<string> Localize_n = new List<string>();
        public List<Expression> Localize_s = new List<Expression>();
        public List<int> Localize_line = new List<int>();

        /*
        
        FUNCTION Init_system_types({Compiler} C|ompiler) :
            --------------------------------- ''
            C.TYPE_BOOL = {Type}(Names[] << "{bool}" << "{boolean}",
                Kind = 'BOOL', Final_name = "bool",
                Type_total_index = 1, Original_type_index = 1)
                
            C.TYPE_BYTE = {Type}(Names[] << "{byte}" << "{byte_8_bits}",
                Kind  = 'ENUM', Final_name = "byte",
                Type_total_index = 2, Original_type_index = 2)
                
            C.TYPE_INT = {Type}(Names[] << "INT" << "INTEGER",
                Kind  = 'INT', Final_name = "int",
                Type_total_index = 3, Original_type_index = 3)
                
            C.TYPE_REAL = {Type}(Names[] << "REAL",
                Kind = 'REAL', Final_name = "double",
                Type_total_index = 4, Original_type_index = 4)
                
            C.TYPE_STR = {Type}(Names[] << "STR" << "STRING",
                Kind = 'STR',  Final_name = "string",
                Type_total_index = 5, Original_type_index = 5)
                
            C.TYPE_OBJ = {Type}(Names[] << "{}" << "{Object}",
                Kind = 'CLASS', Modifiers['ABSTRACT'] = TRUE,
                Final_name = "AL4_object", Original_type_index = 0)
                
            C.TYPE_ENUM = {Type}(Names[] << "{}", Kind = 'ENUM',
            	Original_type_index = -1) 
        .
        
        */
        public static void Init_system_types(Compiler Comp)
        {
            Comp.TYPE_BOOL = new Type();
            Comp.TYPE_BOOL.Names.Add("BOOL");
            Comp.TYPE_BOOL.Names.Add("BOOLEAN");
            Comp.TYPE_BOOL.Kind = Kind_type.BOOL;
            Comp.TYPE_BOOL.Final_name = "bool";

            Comp.TYPE_INT = new Type();
            Comp.TYPE_INT.Names.Add("INT");
            Comp.TYPE_INT.Names.Add("INTEGER");
            Comp.TYPE_INT.Kind = Kind_type.INT;
            Comp.TYPE_INT.Final_name = "int";

            Comp.TYPE_REAL = new Type();
            Comp.TYPE_REAL.Names.Add("REAL");
            Comp.TYPE_REAL.Kind = Kind_type.REAL;
            Comp.TYPE_REAL.Final_name = "real";

            Comp.TYPE_STR = new Type();
            Comp.TYPE_STR.Names.Add("STR");
            Comp.TYPE_STR.Kind = Kind_type.STR;
            Comp.TYPE_STR.Final_name = "string";

            Comp.TYPE_OBJ = new Type();
            Comp.TYPE_OBJ.Names.Add("" + obr + cbr);
            Comp.TYPE_OBJ.Names.Add(obr + "Object" + cbr);
            Comp.TYPE_OBJ.Kind = Kind_type.CLASS;
            Comp.TYPE_OBJ.Final_name = "obj";
            Comp.TYPE_OBJ.Modifiers[(int)Class_mod.ABSTRACT] = true;

            Comp.TYPE_ENUM = new Type();
            Comp.TYPE_ENUM.Names.Add("" + obr + cbr);
            Comp.TYPE_ENUM.Kind = Kind_type.ENUM;
        }

        /*
        STR Path|_class_source
        STR Time_source|_last_changed
        {Parser} Parse|_of_class_source
        INT store_file_size
        
        METHOD File_size ==> INT :
	        CASE store_file_size==0 ? 
	             REAL size|_real = Get_file_size(Path)
	             store_file_size = size.Str.Int ;
            RESULT = store_file_size .
            
        INT store_hash
            
		METHOD Hash_calc|ulate ==> INT :
			CASE store_hash != 0 ? RESULT = store_hash ==> ;
			FOR s IN Parse.Source[] :
			    FOR i IN [0 TO s.Len-1] :
			        //RESULT = (RESULT.ShiftLeft(1) | RESULT.ShiftRight(31)) ^ s[i].Ord
			        INT left|_part = (RESULT * 2)
			        INT right|_part = RESULT / 0x1_0000
			        right = right / 0x80000
			        RESULT = (left | right) ^ s.[i].Ord
			    ;
			; 
			store_hash = RESULT .
	
            

        METHOD comp|iler ==> {Compiler} :
			RESULT = Parse.Compiler_.{Compiler} .
			
        METHOD Compiler ==> {Compiler} : RESULT = comp .

        */
        public string Path_class_source = "";
        public Parser Parse;

        private Compiler comp() { return Parse.Compiler_; }

        /*
        
        //{CCC_load} ccc_load|er

        METHOD Load|_source(
        {Compiler} C|ompiler, BOOL Ascii|_encoding)
            :
            SILENT:
            Time_source = Get_file_modified_time_formatted(Path)
            ;
 
            temp|_source_loader = {Source}(
                Remove_comments= C.Merge_continued_lines,
                Check_len= Path.Ext.Lower != ".pas",
                Encoding_ascii= Ascii)
                
            temp.Load(THIS, C)

            //DEBUG:
            //      STR slashed|_text[]
            //      FOR s IN Parse.Source[] :
            //          slashed[] << s.Replace_all(#NL, "\n") ;
            //      Text_save(C.Destination.Trailing_slash Path.Extract_file_name
            //      "-merged.txt", slashed[]) ;
        .
        
        */
        public void Load(Compiler C)
        {
            Type save_cur_class = C.Current_class;
            try
            {
                C.Current_class = this;
                Parse = new Parser();
                Parse.Compiler_ = C;
                Parse.Class_ = this;
                Text_file F = new Text_file(Path_class_source);
                F.Load_strings(Parse.Source);
                int last_line = Parse.Remove_comments();
                Parse.Check_lines_len(last_line);
                Parse.Merge_continued(last_line);
            }
            finally { C.Current_class = save_cur_class; }
        }

        /*
 		INT Line_class, READ       
	
        METHOD Handle_header :
            ------------------------------ 'Initialize parser position'
            CASE Names[].Count > 0 ? ==> ; // already handled
        PUSH comp.Current_class = THIS :
            CASE comp.Verbose2 ?
                 << "handling header for"._Mhand " " Path #NL 
                 	": Parse.Line=" Parse.Line.Str " [" Parse.Source[Parse.Line]
                 	"]"#NL  ;
            ------------------------------ 'find the first non-comment line'
            Parse.Line = 0
            Parse.Pos = 0
            INT skip_to|_line = -1
            
            CASE Parse.Source[0].Trim IN ["(" "*" "/", "/" "*" ")"] ?
                 BOOL old|_comments = TRUE
            ELSE skip_to = find_ending("/" "*", 0) ;
            
            FOR y IN [0 TO Parse.Source[].Count-1] :
                CASE y <= skip_to ? CONTINUE y ;
                STR s|tring_at_y_trimmed = Parse.Source[y].Trim
                CASE s == "" ? CONTINUE y ;
                Parse.Line = y
                Parse.Pos = 0
                CASE s.[0] ?
                ["-"] :
                     Parse.Skip_sp
                     NONE = Parse.Skip_block_comment(all_comment[])
                     CONTINUE y
                ["("] :
                     CASE !old ? CONTINUE y ;
                     CASE s == "(" "*" "/" ? CONTINUE y ;
                     CASE s.[1] == "*" ?
                          skip_to = find_ending("*" ")", y+1)
                          CONTINUE y ;
                ["/"] :
                     CASE !old ? CONTINUE y ;
                     CASE s == "/" "*" ")" ? CONTINUE y ;
                     CASE s.[1] == "*" ?
                          skip_to = find_ending("*" "/", y+1) ;
                     CONTINUE y
                ["*"] :
                     CASE s.[1] ?
                     ["["]: skip_to = find_ending("]*", y+1) 
                     ["/"]: skip_to = find_ending("/" "*", y+1) 
                     ;
                     CONTINUE y
                ;
                DONE
	                 Parse.Line = y
	                 BREAK y ;
            ------------------------------ 'maybe [Language=XX, Syntax=YY]'
            CASE Parse.End_of_line ? Parse.Fin ;
            CASE Parse.Symbol("[") ?
            	 interprete_attributes_of_class
            	 Parse.Wait_det("]", "after language/syntax attributes")
            ;
            CASE Parse.Syntax_name != "" ?
                 //DEBUG: "syntax name = [" Parse.Syntax_name "]"#NL ;
                 STR syntax|_name_parts[]
                 Split(syntax[], Parse.Syntax_name.Upper, ".")
                 CASE syntax[0]=="PASCAL" ? Parse.Convert_from_pascal
            	 //["SEAL"]: Parse.Convert_SEAL
            	 ;
            ;
            //DEBUG: << "#1: Pos= " Parse.Line.S ":" Parse.Pos.S 
            //			" Last=" Parse.Last.S #NL 
            //		  " [" Parse.Rest_of_line "]" #NL 
            //		  " [" Parse.Source[Parse.Line+1] "]" #NL 
            //		  " [" Parse.Source[Parse.Line+2] "]" #NL 
            //		  " path=" Parse.Full_path 
            //		  " lines=" Parse.Source[].Count.S #NL ; 
            CASE Parse.End_of_line ? Parse.Fin ;
            //DEBUG: << "#2: Pos= " Parse.Line.S ":" Parse.Pos.S
            //			" Last=" Parse.Last.S #NL 
            //		  " [" Parse.Rest_of_line "]" #NL 
            //		  " [" Parse.Source[Parse.Line+1] "]" #NL 
            //		  " [" Parse.Source[Parse.Line+2] "]" #NL  
            //		  " path=" Parse.Full_path 
            //		  " lines=" Parse.Source[].Count.S #NL ; 

            Parse.Wait("CLASS")
            Line_class = Parse.Line
            ------------------------------ 'Names of class'
            Parse.Wait("{")
            Parse.Scan_names(Names[], "")
            Parse.Wait("}")
            FOR x IN [Names[].Count-1 DOWNTO 0] :
                CASE !Is_uppercase(Names[x].[0]) && !Any_case ?
                    Parse.Err(
                    "Class name must start from uppercase letter"._Eclass)
                ;
                Names[x] = "{" Names[x] "}"
                CASE Names[x] IN comp.All_class_names[] ?
                    warn("Duplicating class name"._Wdup ": " Names[x])
                    Names[].Delete(x) ;
            ;
            STR from|_path = "{" Change_ext(Extract_file_name(Path), 
                "").Lower "}"
                
            CASE from != Names[0].Lower && from != Names[1].Lower ?
                 Parse.Warn("It is desirable to match class name to its file "
                 "name"._Witis ": " Path 
                 " (" ("not matching"._Wnot) " " Names[0] 
                 " " ("or"._Wor) " "  Names[1] ")") 
			;
            Parse.Check_names(Names[])
            ------------------------------ 'Handle modifiers'
            FOR yy|dummy IN [Parse.Line TO Parse.Source[].Count-1] :
	            FOR xx|dummy IN [Parse.Pos TO Parse.Last] :
	                CASE !Parse.Symbol(",") ? BREAK xx, BREAK yy ;
	                CASE Parse.End_of_line ? Parse.Fin ;
	                handle_modifier(Parse.Ident) ;
            ;
            CASE Modifiers['SAFE'] ?
                BOOL u|nsafe_options = Modifiers['BAD']
                u ||= Modifiers['BITWISE']
                u ||= Modifiers['DESTRUCTORS']
                u ||= Modifiers['RECURSIVE']
                u ||= Modifiers['UNTESTED']
                u ||= Modifiers['STOPPING']
                //u ||= Modifiers['BYTES']
                CASE u ? err("Wrong using SAFE modifier"._Ewrong) ;
                CASE Modifiers['UNTESTED'] && Modifiers['TESTED'] ?
                     err(
                     "Modifiers TESTED and UNTESTED are contra versa"._Emod) ;
            ;
            CASE Parse.End_of_line ? Parse.Fin ;
            CASE Parse.Symbol(".") || Parse.Symbol(";") || Parse.Symbol(":")
                 || Parse.Symbol("begin")
                 ?
                 NONE
            ELSE Parse.Wait("BEGIN") ;
            Parse.Fin 
        ; .
        
    	FUN Is_uppercase(STR S|tring_checking) ==> BOOL :
    	    RESULT = S.Upper == S .
            
   		METHOD interprete_attributes_of_class :
			INT n|umber_of_commands
			FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                CASE ? [Parse.End_of_line] ? BREAK i
                	   [Parse.Next_symbol("]")] ? BREAK i ;
                -------------------------- 'recognize command'
                STR command|_detected = ""
                INT before_pos|ition_of_ident = Parse.Pos
                Parse.Skip_sp
                CASE Parse.Next_is_letter ?
                    CASE Parse.Ident.Lower ?
                    ["language"]:  command = "L"
                                   Parse.Wait("=")
                    ["syntax"]:    command = "S" 
                                   Parse.Wait("=")
                    ["encoding"]:  command = "E"
                    			   Parse.Wait("=")
                    ELSE Parse.Pos = before_pos ;
                ;
                CASE command == "" && n == 0 ? command = "L" ;
                CASE command == "" && n == 1 ? command = "S" ;
                ------------------------ 'handle command recognized'
                Parse.Skip_sp
                CASE command ?
                ["L"]: Parse.Wait("'")
                       Parse.Language_keyw = Parse.Ident
                       Parse.Wait("'")

                ["S"]: Parse.Syntax_name = Parse.String_const(TRUE)
                	   CASE !Starting(Parse.Syntax_name.Upper, "PASCAL") ?
			    		 	Parse.Err("SYNTAX="#QU"PASCAL"#QU
			    		 	" is supported only"._EPascalOnly
			    		 	" but found: [" Parse.Syntax_name "]") ;
			    		 	
                ["E"]: Parse.Wait("'")
                       STR encoding|_name = Parse.Ident.Upper
                       Parse.Wait("'")
                       CASE encoding ?
                       ["ASCII"]: 
                           		  Parse.Source[].Clear
                       			  PUSH Parse.Line :
                       			  PUSH Parse.Pos :
                       			  PUSH Parse.Syntax_name :
                       			  PUSH Parse.Language_keyw :
                       			  	   Load(comp, TRUE) ;
                       			  ;
                       			  ;
                       			  ;
                       			  
                       ["UTF8"]: NONE
                       ELSE Parse.Err("Only 'ASCII' and 'UTF8' are supported"
                       ""._OnlyAsciiAndUtf8) ;
                ;
                n += 1
                CASE !Parse.Symbol(",") ? CONTINUE i ;
            ; .
        
        */
        public void Handle_header()
        {
            Parse.Line = 0;
            Parse.Pos = 0;
            if (Parse.End_of_line())
                Parse.Fin();
            Parse.Wait("CLASS");
            //------------------------- 'names'
            Parse.Wait("{");
            Parse.Scan_names(Names);
            Parse.Wait("}");
            for (int x = Names.Count - 1; x >= 0; x--)
            {
                string L = (Names[x] + " ")[0] + "";
                if (L.ToUpper() != L)
                    Parse.Err("Class name must start from uppercase letter");
                Names[x] = "{" + Names[x] + "}";
                if (Parse.Compiler_.All_class_names.Contains(Names[x]))
                {
                    warn("Duplicating class name: " + Names[x]);
                    Names.RemoveAt(x);
                }
            }
            if (Names.Count == 0)
                err("There are no unique names for class");
            Parse.Check_names(Names);
            //------------------------- 'handle modifiers'
            for (int i = Parse.Pos; i <= Parse.Last(); i++)
            {
                if (!Parse.Symbol(",")) break;
                handle_modifier(Parse.Ident());
            }
            if (Modifiers[(int)Class_mod.SAFE])
            {
                bool U = Modifiers[(int)Class_mod.BAD] ||
                    Modifiers[(int)Class_mod.NATIVE] ||
                    Modifiers[(int)Class_mod.BITWISE] ||
                    Modifiers[(int)Class_mod.DESTRUCTORS] ||
                    Modifiers[(int)Class_mod.RECURSIVE] ||
                    Modifiers[(int)Class_mod.UNTESTED] || 
                    Modifiers[(int)Class_mod.STOPPING];
                if (U)
                    err("Wrong using SAFE modifier");
            }
            Parse.Wait(":");
            Parse.Fin();
        }

        /*
        
        METHOD err|ror_message(STR M|essage_show) :
            Parse.Err(M) .
        (***********************/
        private void err(string M)
        {
            Parse.Compiler_.Error(M);
        }

        /*
        
        METHOD warn|ing_message(STR M|essage_show) :
            Parse.Warn(M) .
        */
        private void warn(string M)
        {
            Parse.Compiler_.Warning(M);
        }

        /*
        
        METHOD handle_modifier(STR Id|entifier) :
            -------------------------------------- 'class modifiers'
            //DEBUG: << "*** handling modifer " Id ", previous value: "
            //		  "" get_modifier_by_name(Id)
            //;
            CASE Id.Upper ?
                ["ABSTRACT"]:   Modifiers['ABSTRACT'] = TRUE
                ["NATIVE"]:     Modifiers['NATIVE'] = TRUE
                ["BAD"]:        Modifiers['BAD'] = TRUE
                ["BITWISE"]:    Modifiers['BITWISE'] = TRUE
                ["BYTES"]:      NONE //Modifiers['BYTES'] = TRUE
                ["DESTRUCT", "DESTRUCTORS"]:  Modifiers['DESTRUCTORS'] = TRUE
                ["RECURSIVE", "RECURSIONS"]:  Modifiers['RECURSIVE'] = TRUE
                ["INFINITE"]:   Modifiers['INFINITE'] = TRUE
                ["UNTESTED"]:   Modifiers['UNTESTED'] = TRUE
                ["TESTED"]:     Modifiers['TESTED'] = TRUE
                				Tested_by = 100
                				CASE Parse.Symbol("(") ?
                				     Tested_by = Parse.Number
                				     Parse.Wait(")") ;
                ["SAFE"]:       Modifiers['SAFE'] = TRUE
                ["STOPPING"]:   Modifiers['STOPPING'] = TRUE
                                
                ["TRANSLATION"]: Parse.Err("Modifier TRANSLATION OF {...} "
                                "should be the first and single"._Emodifier )
                                
                ["OPERATORS"]:	Modifiers[{class_mod}.'OPERATORS'] = TRUE
                ["INT64"]: 
                    CASE ?
                    [Parse.Symbol("REQUIRED")] ?
                        Modifiers['INT64_REQUIRED'] = TRUE
                        CASE Parse.Compiler.Int32 ? 
                             Parse.Err("Class requires INT64 but INT32 "
                             "was specified for the project"._EClassReqInt64) ;
                    [Parse.Symbol("DESIRED")] ?
                        Modifiers['INT64_DESIRED'] = TRUE
                        CASE Parse.Compiler.Int32 ? 
                             Parse.Warn("Class desires INT64 but INT32 "
                             "was specified for the project"._WClassDesireInt64)
                        ;
                    ELSE Parse.Err("Waiting for REQUIRED or DESIRED but"
                    		""._EWaitDesiredRequired ": " Parse.Next20) 
                    ;
                ["DEPRECATED", "ABANDONED"]:
                    Parse.Wait("(")
                    Parse.Wait("''".[1])
                    INT from|_pos = Parse.Pos
                    NONE = Parse.Skip_to("''".[1])
                    ----------------------- 'warning/error message'
                    STR add_t|ext = Parse.Source[Parse.Line].[
                        from TO Parse.Pos-1]
                        
                    CASE "platform" IN add_t.Lower 
                         && "dependent" IN add_t.Lower 
                         ?
                         STR m|essage_text = "Class is DEPRECATED"
                         ""._Eclass2D
                    ELSE m= "Class is DEPRECATED, use instead"
                    	 ""._Eclass2 ;
                    
                    CASE Id.Upper == "ABANDONED" ?
                         CASE "use" IN add_t.Lower ?
                              m = "Class is ABANDONED, use instead"
                              ""._Eclass3
                         ELSE m = "Class is ABANDONED"._Eclass3A ;
                    ;
                    m = m ": " add_t
                        
                    CASE Id.Upper == "ABANDONED" ?
                         Modifiers['ABANDONED'] = TRUE
                         Parse.Err(m)
                    ELSE Modifiers['DEPRECATED'] = TRUE 
                         CASE !Parse.Compiler.Suppress_deprecated_warn ?
                              Parse.Warn(m) ;
                    ;
                    -------------------------- 'check exclusive'
                    Parse.Wait("''".[1])
                    Parse.Wait(")")
                    CASE Modifiers['ABANDONED'] && Modifiers[
                         'DEPRECATED']
                         ?
                         Parse.Err("Class can be either abandoned "
                         "or deprecated, not both"._Eclass4)
                    ;
            ELSE err("Unknown modifier"._Eunk ": " Id) ;
            //DEBUG: << " new value of modifier = " get_modifier_by_name(Id) #NL
            //	   //>> STR debug_input
            //;
            .
            
        */
        private void handle_modifier(string Id)
        {
            Id = Id.ToUpper();
            bool sw_ok = false;
            switch (Id[0])
            {
                case 'A': if (Id == "ABSTRACT")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.ABSTRACT] = true;
                    }
                    break;
                case 'N': if (Id == "NATIVE")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.NATIVE] = true;
                    }
                    break;
                case 'B':
                    if (Id == "BAD")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.BAD] = true;
                    }
                    else if (Id == "BITWISE")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.BITWISE] = true;
                    }
                    else if (Id == "BYTES")
                    {
                        sw_ok = true;
                    }
                    break;
                case 'D': 
                    if (Id == "DESTRUCTORS")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.DESTRUCTORS] = true;
                    }
                    break;
                case 'R':
                    if (Id == "RECURSIVE")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.RECURSIVE] = true;
                    }
                    break;
                case 'I':
                    if (Id == "INFINITE")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.INFINITE] = true;
                    }
                    break;
                case 'U':
                    if (Id == "UNTESTED")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.UNTESTED] = true;
                    }
                    break;
                case 'S':
                    if (Id == "SAFE")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.SAFE] = true;
                    }
                    else if (Id == "STOPPING")
                    {
                        sw_ok = true;
                        Modifiers[(int)Class_mod.STOPPING] = true;
                    }
					else if (Id == "SHORT_STR")
					{
						sw_ok = true;
						Modifiers[(int)Class_mod.SHORT_STR] = true;
					}
                    break;
                case 'T':
                    if (Id == "TESTED")
                        sw_ok = true;
                    break;
            }
            if (!sw_ok)
                err("Unknown modifier: " + Id);
        }

        /*
        STR all_comment|_labels[]
        
        
        METHOD Handle_import :
            CASE comp.Verbose2 ?
                 comp.Class_level += 1
                 
                 << "Handling import for class"._Mhand3 
                 " " Whole_name 
                 "------->" comp.Class_level.Str #NL 
            ; 
            PUSH comp.Error_prefix =
                 "(Handling import at line"._Mhand2 
                 " " (Parse.Line+1).Str  (": class is"._Mclass_is_cc) 
                 " " Whole_name "), " :
                ----------------------------- 'always import {Basic_types}' 
            	{Type} basic|_types = comp.Create_class("Basic_types")
            	Import_[] << basic
            	Used_imports_[] << basic
                 
                INT skip_to|_y_line = -1
                FOR y IN [Parse.Line TO Parse.Source[].Count] :
                    //DEBUG: << "[" Parse.Source[y] "]" #NL ;
                    CASE y <= skip_to ? CONTINUE y ;
                    STR s|tring_at_y_trimmed = Parse.Source[y].Trim
                    CASE s == "" ? CONTINUE y ;
                    ----------------- 'skip comments (if Source was not merged)'
                    Parse.Line = y
                    Parse.Pos = 0
                    CASE s.[0] ?
                    ["-"] :
                         Parse.Skip_sp
                         NONE = Parse.Skip_block_comment(all_comment[])
                         CONTINUE y
                    ["("] :
                         CASE s.[1] == "*" ?
                              skip_to = find_ending("*" ")", y+1)
                              CONTINUE y ;
                    ["/"] :
                         CASE s.[1] == "*" ?
                              skip_to = find_ending("*" "/", y+1) ;
                         CONTINUE y
                    ;
                    CASE Parse.Symbol("IMPORT") ? NONE
                    ELSE BREAK y ;
                    --------------------------- 'initializy flags'
                    BOOL anyway|_flag = FALSE
                    BOOL debug_imp|ort = FALSE
                    BOOL test_imp|ort = FALSE
                    BOOL friends_import = FALSE
                    FOR j|dummy IN [Parse.Pos TO Parse.Last] :
	                    CASE ?
	                    [! Parse.Symbol(",")] ? BREAK j
	                    [Parse.Symbol("ANYWAY")] ? anyway = TRUE
	                    [Parse.Symbol("DEBUG")] ? debug_imp = TRUE
	                    [Parse.Symbol("TEST")] ? test_imp = TRUE
	                    [Parse.Symbol("FRIENDS")] ? friends_import = TRUE
	                    
	                    ELSE Parse.Err("Unknown IMPORT modifier"._EUnknownImpMod
	                    	 ": " Parse.Next20)
	                    	 
	                    	 BREAK j ;
                    ;
                    CASE Parse.Symbol(":") ? NONE ;
                    CASE anyway && debug_imp && !comp.Debugging ?
                    	 //CASE Parse.End_of_line ? Parse.Fin ;
                         -------------- 'special case: import only is DEBUG'
                         anyway = FALSE
                         Parse.Pos = Parse.Last+1
                         Parse.Fin
                         CONTINUE y
                    ;
                    FOR i|dummy IN [Parse.Pos TO Parse.Pos + 1000_000] :
                        CASE Parse.Symbol("{{") ? 
                             STR m_import|_multiple[] << Parse.Ident
                             Parse.Wait("}}")
                             CASE ! Parse.Symbol(",") ? BREAK i ;
                             CONTINUE i ;
                        STR name|_of_class = Parse.Class_name
                        name = name.[1 TO *-1]
                        {Type} im|ported
                        ------------------------ 'import_one_class'
                        PUSH comp.Suppress_deprecated_warn :
                             CASE Modifiers['DEPRECATED'] ? 
                                  comp.Suppress_deprecated_warn = TRUE ;
                        	 im = comp.Create_class(name)
                        ;
                        CASE im == THIS ?
                             err(EImportItself) ;
                        CASE "{" name "}" !IN im.Names[] ? 
                             err("Importing class failed: searching class "
                             "{" name "} but found class " im.Whole_name) ;
                        im.Not_for_test = TRUE
                        //im.Translation_of_.Not_for_test = TRUE
                        CASE anyway ? im.Anyway = TRUE ;
                        CASE comp.Verbose2 ? 
                             << "added: " im.Whole_name #NL ;
                        -----------------
                        CASE im IN Import_[] ?
                             err("Already imported"._Ealready ": " name) ;
                        ----------------- 'import_errors'
                        CASE ?
                        [debug_imp] ? Debug_import_[] << im
                        [test_imp] ? Test_import_[] << im
                        ELSE Import_[] << im ;
                        CASE friends_import ? Friends[] << im.Names[0] ;
                        CASE name.Lower == Change_ext(Path, "").Lower ?
                             err(Erecur) ;
                        -------------------
                        CASE ! Parse.Symbol(",") ? BREAK i ;
          --------- 'allow splitting IMPORT list even if Source[] is not merged'
                        CASE Parse.End_of_line ? Parse.Fin ;
                        skip_to = y
                    ;
                    CASE ! Parse.Symbol(".") ? Parse.Wait(";") ;
                    Parse.Fin
                    //DEBUG: << "finned: [" Parse.Source[Parse.Line] "]" #NL ;
                    skip_to = Parse.Line - 1
                ;
                -------------- 'multi-import in {{double-figure-brackets}}'
                anyway = FALSE
                debug_imp = FALSE
                test_imp = FALSE
                friends_import = FALSE
                FOR s_m IN m_import[] :
                    STR found_im|port_file = ""
                	FOR s_path IN comp.Source_paths[] :
                	    CASE !Exists(s_path.Trailing_slash s_m ".import") ?
                	         CONTINUE s_path ;
                	    DONE
                	    found_im = s_path.Trailing_slash s_m ".import"
                	    BREAK s_path ;
                	CASE found_im=="" ? 
                	     Parse.Err("File {{...}} not found: " s_m ".import"
                	     ""._ImFileNotFound ) 
                	     CONTINUE s_m ;
                    STR s_im|port = File_to_string(found_im)
                    ----------------------------------- 'some replacements'
                    s_im = Replace_all(s_im, #CR, " ")
                    s_im = Replace_all(s_im, #LF, " ")
                    s_im = Replace_all(s_im, "  ", " ")
                    s_im = Replace_all(s_im, "}{", "} {")
                    STR t_im|port[]
                    Split(t_im[], s_im, " ")
                    FOR cl|ass_imported IN t_im[] :
                        name = cl.Trim
                        CASE name == "" ? CONTINUE cl ;
                        CASE name.[0]=="{" ? name = name.[1 TO *-1] ;
                        //DEBUG: "import one class from .import: " name #NL ;
                        --------------------- 'LIKE import_one_class'
                        im = comp.Create_class(name)
                        CASE im == THIS ?
                             err(EImportItself) ;
                        CASE "{" name "}" !IN im.Names[] ? 
                             err("Importing class failed: searching class "
                             "{" name "} but found class " im.Whole_name) ;
                        im.Not_for_test = TRUE
                        //im.Translation_of_.Not_for_test = TRUE
                        CASE anyway ? im.Anyway = TRUE ;
                        CASE comp.Verbose2 ? 
                             << "added: " im.Whole_name #NL ;
                        CASE im IN Import_[] ? CONTINUE cl ;
                        Used_imports_[] << im     
                        ----------------------- 'LIKE import_errors'
                        CASE ?
                        [debug_imp] ? Debug_import_[] << im
                        [test_imp] ? Test_import_[] << im
                        ELSE Import_[] << im ;
                        CASE friends_import ? Friends[] << im.Names[0] ;
                        CASE name.Lower == Change_ext(Path, "").Lower ?
                             err(Erecur) ; 
                    ;
                ;
            ; 
 			CASE comp.Verbose2 ?
			     << "end of handling import of class " Whole_name 
			     	"<-------" comp.Class_level.Str #NL
			     	
			     comp.Class_level -= 1
			; .
			
        FUN Erecur|sive ==> STR :
            RESULT = "Recursively importing self"._Erecur .
			
        FUN EImportItself ==> STR :
            RESULT = "Importing class itself"._EImportItself .
          
        FUN DONE|_working_in_a_loop : .
                
        METHOD find_ending(
        	STR Seq|unce_ending, INT From|_line) ==> INT
        	:
            FOR y IN [From TO Parse.Source[].Count-1] :
                STR s|tring_at_y_trimmed = Parse.Source[y].Trim
                CASE Ending(s, Seq) ? RESULT = y ==> ;
            ;
            RESULT = Parse.Source[].Count .
        */
        public void Handle_import()
        {
            for (int y = Parse.Line; y < Parse.Source.Count+1; y++)
            {
                if (!Parse.Symbol("IMPORT")) return;
                Parse.Wait(":");
                for (int i = Parse.Pos; i <= Parse.Last(); i++)
                {
                    if (Parse.End_of_line()) break;
                    string name = Parse.Class_name();
                    name = name.Substring(1, name.Length - 2);

                    Type im = Parse.Compiler_.Create_class(name);
                    if (im == null) return;
                    if (Import_.IndexOf(im) >= 0)
                        err("Already imported: " + name);
                    Import_.Add(im);
                    if (!Parse.Symbol(",")) break;
                }
                Parse.Wait(";");
                Parse.Fin();
            }
        }

        /*
        
        METHOD Handle_base|_class :
            ------------------------- 'first, handle the header'
        PUSH comp.Current_class = THIS :
            CASE Import_[].Count == 0 ?
                 ------------ 'IMPORT'
                 Handle_import 
            ;
            CASE Base_ == NONE ?
                 PUSH Parse.Line :
                 PUSH Parse.Pos :
                      CASE Parse.Symbol("BASE") ?
                           Parse.Wait("CLASS")
                           CASE Parse.Symbol(":") ? NONE ;
                           STR bn|ame_of_base_class = Parse.Scan_type
                           CASE Parse.Symbol(".") ? NONE ;
                           CASE bn.[0] != "{" || bn.[1].Upper != bn.[1] ?
                                Parse.Err("Base class name must be enclosed in "
                                "{} and first letter must be "
                                "uppercased"._Ebase) ==>
                           ;
                           Base_ = Find_type(bn)
                           Base_.Has_descendant = TRUE
                           ---------------- 'restrictions on key !max_desc'
                           check_restriction_on_max_desc
                      ;
                 ;
                 ;
            ;
        ; 
        Line_continue = Parse.Line
        Pos_cont = Parse.Pos .
        
        METHOD check_restriction_on_max_desc: 
        	INT i|ndex_in_Classes_to_restrict INDEXING (STR, INT)
            i = comp.Classes_to_restrict_anc[].Find(Base_.Names[0])
            CASE i < 0 ? ==> ;
            INT count|_desc = comp.N_desc[i]+1
            comp.Set_N_desc(i, count)
            comp.Add_to_descendents(i, Whole_name)
            CASE count <= comp.N_max_desc[i] ? ==> ;
                 
            Parse.Err("Amount of descandants "
            "from class " Base_.Names[0] " is "
            "greater then allowed (" count.Str " > " comp.N_max_desc[i].Str 
            "), all descendents are: " comp.All_desc[i]) .
	        
            
        METHOD Precompile ==> BOOL, RECURSIVE :
		PUSH comp.Current_class = THIS :
            ---------------------------- 'provide base class precompiled first'
            CASE Base_ != NONE && !Base_.Is_precompiled ?
                 RESULT = Base_.Precompile
                 CASE RESULT ? ==> ;
            ;
            CASE Is_precompiled ? ==> ;
            CASE precompiling ? RESULT = TRUE ;
            Is_precompiled = TRUE
            PUSH precompiling = TRUE :
	             ----------- 'provide sequencional Field_index for all the fields'
	             comp.Total_fun += 999
	             comp.Total_fun -= comp.Total_fun % 1000
	             -------------------------------------- 'start precompiling'
	             CASE comp.Verbose ?
	                 << "Precompiling"._Mprec
	                    ": " Names[*] " (" Parse.Class_.Path ")" #NL
	             ;
	             INT count_decl|arations_between_block_comments = 0
	             -------------------- 'restore position stored after Handle_base'
	             CASE Line_continue > 0 ?
		              Parse.Line = Line_continue
		              Parse.Pos = Pos_cont ;
	             CASE ?
	             [Parse.Symbol("BASE")] ?
	                  precompile_base
	             [Parse.Next_symbol("IMPORT")] ?
	                  Handle_import
	             ;
	             CASE Parse.Line == 0 && Parse.Pos == 0 ?
	                  BOOL skip_header|_directives = TRUE ;
	             FOR y|dummy IN [Parse.Line TO Parse.Source[].Count] :
	                 Parse.Skip_sp
	                 CASE Parse.End_of_line ?
	                      Parse.Fin
	                      CONTINUE y ;
	                 ----------------------- 'next interface declaration'
	                 CASE Parse.Next_char ?
	                     ["{"]:  precompile_var(Parse.Scan_type)
	                             count_decl += 1
	                     ["-"]:  
	                             CASE count_decl > 7 ?
	                                 warn("Amount of declarations between block"
	                                 " comments should not exceed 7"._Wamount)
	                             ;
	                             NONE = Parse.Skip_block_comment(all_comment[])
	                             count_decl = 0
	                             Last_fun = NONE
	                             Last_var = NONE
	                     //["("]:	Parse.Wait("(" "*$ifdef al4code*" ")")
	                     //        Parse.Fin
	                     //        copy_until_endif
	                     //        CONTINUE y
	                 ELSE 
	                 	  STR key|word_at_start = Parse.Ident
	                      CASE key.Lower==key ? key = key.Upper ;
	                      CASE skip_header && key IN [
	                     	   "CLASS", "BASE", "IMPORT", "DEBUG", "FRIENDS"]
	                           ? 
	                           Parse.Line += 1
	                           Parse.Pos = 0
	                           CONTINUE y ;
	                      skip_header = FALSE
	                      CASE key ?
	                           ["CONST", "CONSTANT"]: precompile_const
	                           ["TEST"]: precompile_test
	                           ["ENUM", "ENUMERATION"]: precompile_enum
	                           ["STRUCTURE"]: precompile_structure
	                           ["FUN", "FUNCTION", "METHOD"]:
	                						 precompile_fun(key)
	                						 count_decl = 0
	                           ["OVERRIDE"]: precompile_override
	                                         count_decl = 0
	                           ["CONSTRUCT", "CONSTRUCTION"]: precompile_construct
	                           ["DESTRUCT", "DESTRUCTION"]: precompile_destruct
	                           ["OPERATOR"]: precompile_operator
	                           ["BOOL"]:
	                                 precompile_var("{bool}")
	                                 count_decl += 1
	                           ["BYTE"]:
	                                 precompile_var("{byte}")
	                                 count_decl += 1
	                           ["INT", "REAL", "STR"]:
	                                 precompile_var(key)
	                                 count_decl += 1
	                           ["NATIVE"]: precompile_native
	                           ["TODO"]: precompile_todo
							   ["TABLE"]: precompile_table
	                           ["END"]:
	                 //DEBUG: << "END found, [" Parse.Rest_of_line "]" #NL
	                 //		  "next line is: [" Parse.Source[Parse.Line+1] 
	                 //		  "]"#NL
	                 //;
	                 			 -------------- 'END'
	                 			 CASE Parse.Rest_of_line.Trim=="" ? 
	                             //Parse.Skip_sp
	                             	  Parse.Line+=1
	                             	  Parse.Pos = 0
		                              BOOL end_f|ound = TRUE
		                              PUSH Parse.Line:
		                            	   collect_Ending ;
		                              precompile_history
		                              BREAK y
	                             ELSE
	                                  Parse.Fin
	                 			 ;
	                             
	                       ELSE err("Unknown keyword"._Eunk2 ": " key
	                            " " ("(on a class level)")._Eon)
	                            
	                            Parse.Line += 1 ;
	                       CASE key !IN ["FUN", "FUNCTION", "METHOD", 
	                            "OVERRIDE", "BOOL", "BYTE", "INT", "REAL", "STR"]
	                            ?
	                            Last_fun = NONE
	                            Last_var = NONE ;
	                 ;
	             ;
            ;
            CASE !end_f ? err( "Class must be ended with END"._Eclass5) ;
            CASE count_decl > 7 ?
                warn("Amount of declarations between "
                "block comments should not exceed 7"._Wamount2) ; 
		; .
		
		BOOL precompiling
		
        STR all_field_fun|ction_names[]
                
        METHOD Add_method|s_functions(
        {Fun} F|onction) 
            :
            Method[] << F
            F.Provide_names_lowered
            STR a_f0|_lowered_char = F.Names_low[0].[0].Lower
            CASE Sorted_method[].Count > 10 ? 
                 INT p|osition_to_insert= find_first_method_starting(a_f0,FALSE)
            ELSE 
            	p = Sorted_method[].Count
	            FOR i IN [0 TO Sorted_method[].Count-1] :
	                STR a_low0|_char = Sorted_method[i].Names[0].[0].Lower 
	                CASE ?
	                [a_low0 < a_f0] ? CONTINUE i
	                ELSE p = i
	                     BREAK i ;
	            ;
            ;
            Sorted_method[].Insert(p, F) .
            
        */
        static int CNT_Precompile;

        public void Precompile()
        {
            Parse.Compiler_.Total_fun_index += 999;
            Parse.Compiler_.Total_fun_index -= Parse.Compiler_.Total_fun_index % 1000;
            
            if (Parse.Compiler_.Verbose)
                Console.WriteLine("Precompiling: " + (Names.Count > 0 ? Names[Names.Count - 1] : "") +
                    " (" + Parse.Class_.Path_class_source + ")");
            Parse.Compiler_.Current_class = this;
            int count_decl = 0;
            int base_class = 0;
            if (Parse.End_of_line())
                Parse.Fin();
            for (int x = Parse.Line; x <= Parse.Source.Count; x++)
            {
                if (CNT_Precompile++ == 687)
                { }

                Parse.Skip_sp();
                if (Parse.End_of_source()) break;
                if (Parse.Next_char() == "{")   
                {
                    String type_n = Parse.Class_name();
                    if (Parse.Symbol("."))
                        type_n += "." + Parse.Class_name();
                    precompile_var(type_n);
                    count_decl++;
                }
                else if (Parse.Next_char() == "-")
                {
                    if (count_decl > 7)
                        warn("Amount of declarations between block comments should not exceed 7");
                    Parse.Skip_block_comment(All_id);
                    count_decl = 0;
                }
                else
                {
                    string key = Parse.Ident();
                    if (key == "") key = " ";
                    bool sw_ok = false;
                    switch (key[0])
                    {
                        case 'C':
                            if (key == "CONST" || key == "CONSTANT")
                            {
                                sw_ok = true;
                                precompile_const();
                            }
                            else if (key == "CONSTRUCT" || key == "CONSTRUCTION")
                            {
                                sw_ok = true;
                                precompile_construct();
                            }
                            break;
                        case 'D':
                            if (key == "DESTRUCT" || key == "DESTRUCTION")
                            {
                                sw_ok = true;
                                precompile_destruct();
                            }
                            break;
                        case 'T':
                            if (key == "TEST")
                            {
                                sw_ok = true;
                                precompile_test();
                          }
						    else if (key == "TODO")
							{
									sw_ok = true;
									precompile_todo();
							}
                            break;
                        case 'E':
                            if (key == "ENUM" || key == "ENUMERATION")
                            {
                                sw_ok = true;
                                precompile_enum();
                            }
                            else if (key == "END")
                            {
                                sw_ok = true;
                                Parse.Fin();
                                collect_Ending();
                                return;
                            }
                            break;
                        case 'F':
                            if (key == "FUN" || key == "FUNCTION")
                            {
                                sw_ok = true;
                                precompile_fun(key);
                                count_decl = 0;
                            }
                            break;
                        case 'M':
                            if (key == "METHOD")
                            {
                                sw_ok = true;
                                precompile_fun(key);
                                count_decl = 0;
                            }
                            break;
                        case 'B':
                            if (key == "BOOL")
                            {
                                sw_ok = true;
                                precompile_var(key);
                                count_decl++;
                            }
                            else if (key == "BASE")
                            {
                                sw_ok = true;
                                precompile_base(base_class++);
                            }
                            break;
                        case 'I':
                            if (key == "INT")
                            {
                                sw_ok = true;
                                precompile_var(key);
                                count_decl++;
                            }
                            break;
                        case 'R':
                            if (key == "REAL")
                            {
                                sw_ok = true;
                                precompile_var(key);
                                count_decl++;
                            }
                            break;
                        case 'S':
                            if (key == "STR")
                            {
                                sw_ok = true;
                                precompile_var(key);
                                count_decl++;
                            }
                            break;
                        case 'N':
                            if (key == "NATIVE")
                            {
                                sw_ok = true;
                                precompile_native();
                            }
                            break;
                    }
                    if (!sw_ok)
                    {
                        err("Unknown keyword: " + key);
                        Parse.Line++;
                    }
                }
            }
            if (count_decl > 7)
                warn("Amount of declarations between block comments should not exceed 7");
        }

        /*
        
        METHOD collect_Ending|_lines_to_DATA_array :
            FOR i IN [Parse.Line TO Parse.Source[].Count-1] :
                Ending_lines[] << Parse.Source[i] ;
            FOR s IN Ending_lines[] :
                FOR i IN [s.Len-1 DOWNTO 0] :
                    CASE s.[i] IN #NL ? s = s.[0 TO i-1]
                    ELSE BREAK i ;
                ;
                Ending_lines[s.Index] = s ; 
            FOR i IN [Ending_lines[].Count-1 DOWNTO 0] :
                CASE Ending_lines[i].Trim == "" ?
                     Ending_lines[].Delete(i)
                ELSE BREAK i ;
            ; .
        */
        private void collect_Ending()
        {
            for (int i = Parse.Line; i < Parse.Source.Count; i++)
                Ending_lines.Add(Parse.Source[i]);
        }

        /*
        
        METHOD precompile_base :
            base_line = Parse.Line
            Parse.Wait("CLASS")
            CASE Parse.Symbol(":") ? NONE ;
            Parse.Wait("{")
            STR id|ent_base_class = Parse.Ident
            CASE id.[0].Upper != id.[0] && !Any_case ?
                Parse.Err(
                "Base class name must start from uppercase letter"._Ebase2)
            ;
            Parse.Pos = Parse.Last + 1
            CASE Parse.Symbol(".") ? NONE ;
            Parse.Fin .
        */
        private void precompile_base(int Base_class)
        {
            base_line = Parse.Line;
            if (Base_class > 0)
            {
                int save = Parse.Pos;
                Parse.Pos = 0;
                Parse.Err("Only one base class is allowed: " + Parse.Next20());
                Parse.Pos = save;
            }
            Parse.Wait("CLASS");
            Parse.Wait("{");
            string id = Parse.Ident();
            if ((id[0] + "").ToUpper() != id[0] + "")
                Parse.Err("Base class name must start from uppercase letter");
            Parse.Pos = Parse.Last() + 1;
            Parse.Fin();
        }

        /*
        
        METHOD precompile_const
        	|ant_declaration
        	:
            ---------------------------------- 'Scan type'
            CASE Parse.Symbol("{") ?
                STR type_name = "{" Parse.Ident "}"
                    Parse.Wait("}")
            ELSE type_name = Parse.Ident ;
            ---------------------------------- '{set_name}'
            CASE Parse.Symbol("{") ?
                 set|_of_constants = {Type}(Kind = 'ENUM', Line = Parse.Line,
                 	Original_type_index = -1),
                 	OWNED BY THIS
                 Parse.Scan_names(set.Names[], "")
                 FOR n IN set.Names[] : set.Names[n.Index] = "{" n "}" ;
                 check_new_set_of_const(set)
                 Sets_constants_[] << set
                 Parse.Wait("}") ;
            Parse.Wait(":")
            CASE Parse.End_of_line ? Parse.Fin ;
            FOR y|dummy IN [Parse.Line TO Parse.Source[].Count] :
                {Var} c|onstant = {Var}(Is_const = TRUE, Type_n = type_name,
                    Line = Parse.Line), >> Const[]
                    
                CASE c.Type_n ?
                ["INT", "INTEGER"]: c.Type_ = comp.TYPE_INT
                ["REAL"]: c.Type_ = comp.TYPE_REAL
                ["STR"]: c.Type_ = comp.TYPE_STR
                ["BOOL"]: c.Type_ = comp.TYPE_BOOL
                ["BYTE"]: c.Type_ = comp.TYPE_BYTE ;
                
                CASE set != NONE ? set.Items[] << c ;
                ------------------------------- 'names of constant'
                Parse.Scan_names(c.Names[], "") 
                CASE c.Names[0] != c.Names[0] && !Any_case ?
                     warn("Constant name is not uppercased"._Wconst) ; 
                Parse.Check_names(c.Names[])
                Parse.Check_reserved(c.Names[])
                CASE Parse.Symbol("[") ?
                     c.Is_array = TRUE
                     c.Is_fixed = TRUE
                     c.In_type_ = THIS
                     CASE Parse.Symbol("*") ?
                          c.Size_n = "*"
                     ELSE c.Size_value = Parse.Number
                     	  c.Size_n = c.Size_value.Str ;
                     Parse.Wait("]")
                     CASE c.Size_n != "*" && c.Size_value < 1  ?
                          Parse.Err("Size of a constant array must be either "
                          "a number > 0 or '*' character"._EConstArraySize)
                     ;
                ;
                Parse.Wait("=")
                CASE c.Is_array ?
                     Parse.Wait("[")
                     assign_array_of_const(c)
                     Parse.Wait("]")
                     CASE ?
                     [c.Size_n == "*"] ?
                          c.Size_value = c.Items_[].Count
                          c.Size_n = c.Size_value.Str
                          
                     [c.Size_value != c.Items_[].Count] ?
                          Parse.Err("Actual array size does not match to the "
                          "size in the constant array specification"
                          ""._ESizeNotMatch)
                     ;
                ELSE c.Constant_value = Parse.Scan_expr ;
                //DEBUG:
                //      CASE c.Names[0] == "NATIVE_Console_color" ?
                //           << c.Constant_value.Replace_all(#NL, "\n"#LF#CR) 
                //           >>
                //      ;
                //;
                
                check_constant_not_duplicated(c)
                
                Parse.Skip_sp
                CASE Parse.End_of_line ? Parse.Fin ;
                CASE Parse.Next_symbol(".") ? BREAK y ;
            ;
            Parse.Wait(".")
            Parse.Fin .
            
        METHOD assign_array_of_const(
        {Var} c|onstant_array)
        	:
            FOR idummy IN [Parse.Pos TO Parse.Last] :
	            STR value|_in_array = Parse.Scan_expr
	            
	            item|_of_const_array = {Var}(Line = c.Line,
	                Is_const = TRUE, Constant_value = value, 
	                Type_n = c.Type_n, Type_ = c.Type_),
	                OWNED BY c
	                
	            c.Items_[] << item
	            CASE !Parse.Symbol(",") ? BREAK idummy ;
            ; .

            
        METHOD check_constant_not_duplicated(
        	{Var} C|onstant_defined )
        	:
            FOR c IN Const[] :
                CASE c == C ? CONTINUE c ;
                FOR n IN C.Names[] :
                    BOOL dup|lication_detected = n IN c.Names[]
                    BOOL again|_specified = dup && "again" IN C.Names[*].Lower
                    CASE dup && again 
                    	 && C.Constant_value.Trim != c.Constant_value.Trim
                    	 ?
                         Parse.Err("Duplicated constant"._Edup
                         " " n " " ("with redefined value"._Ewith)
                         " " C.Constant_value 
                         " (" ("earlier it was defined as"._Eearlier)
                         " " c.Constant_value ")")
                    ;
                    CASE dup && !again ?
                         Parse.Err("Constant"._Econst " " n
                         " " ("is redefined but has no a "
                         "specifier AGAIN in its name"._Eis)) ;
                ;
            ; .
            
            
        METHOD Find_set_of_constants(
        	STR Name|_of_set ) ==> {Type}, RECURSIVE
        	:
            FOR s IN Sets_constants_[] :
                CASE Name IN s.Names[] ?
                     RESULT = s ==> ;
            ;
            CASE comp.Current_class == THIS ?
                 FOR n_im INDEXING {Type} IN [
                 	 0 TO Import_[].Count + Test_import_[].Count - 1]
                 	 :
                     CASE ?
                     [n_im < Import_[].Count] ?
                          {Type} im|port_at_n = Import_[n_im]
                     [!comp.Current_fun.Is_test] ? BREAK n_im
                     ELSE im = Test_import_[n_im - Import_[].Count]
                     ;
                     RESULT = im.Find_set_of_constants(Name)
                     CASE RESULT != NONE ? ==> ;
                 ;
                 Parse.Err("Set of constants"._Eset " " Name 
                 " " ("is not defined"._Eis2)) ; .
                 
                 
        METHOD check_new_set_of_const(
        	{Type} New|_set_created )
        	:
            FOR s IN Sets_constants_[] :
                FOR n IN New.Names[] :
                    CASE n IN s.Names[] ?
                         Parse.Err("Duplicated name of a constants set"._Edup2 
                         ": " n
                         " (" ("was defined in line"._Ewas) " " s.Line.Str 
                         " " ("earlier"._Eearlier2) ")")
                         BREAK n, BREAK s ;
                ;
            ;
            CASE New.Names[0].[1].Upper == New.Names[0].[1] && !Any_case ?
                 Parse.Warn("It is recommended to use names starting from a "
                 "lower case letter to name sets of constants"._Witis2) ; .
                
                
        */
        public const char obr = '{';
        public const char cbr = '}';

        private void precompile_const()
        {
            int at = Parse.Line;
            string type_name = "";
            if (Parse.Symbol("" + obr))
            {
                type_name = obr + Parse.Ident() + cbr;
                Parse.Wait("" + cbr);
            }
            else type_name = Parse.Ident();
            Parse.Wait(":");
            if (Parse.End_of_line()) 
                Parse.Fin();
            for (int y = Parse.Line; y <= Parse.Source.Count; y++)
            {
                if (Parse.End_of_source())
                {
                    err("CONST block at " + at.ToString() + " is not ended with '.'");
                    return;
                }
                Variable c = new Variable(Parse.Compiler_);
                c.Type_n = type_name;
                c.Is_constant = true;
                c.Line = Parse.Line;
                Const.Add(c);
                Parse.Scan_names(c.Names);
                if (c.Names[c.Names.Count - 1].ToUpper() != c.Names[c.Names.Count - 1])
                    warn("Constant name is not uppercased");
                Parse.Check_names(c.Names);
                Parse.Check_reserved(c.Names);
                if (Parse.Symbol("["))
                {
                    c.Is_array = true;
                    Parse.Wait("]");
                    Parse.Wait("=");
                    c.Value = Parse.Scan_array();
                }
                else
                {
                    Parse.Wait("=");
                    c.Value = Parse.Scan_expr();
                }
                Parse.Skip_sp();
                if (Parse.Next_char() == ".") break;
                Parse.Fin();
            }
            Parse.Wait(".");
            Parse.Fin();
        }

        /*
        
        METHOD precompile_var
        	|iable_of_class( STR Type_n|ame )
        	:
            ----------------------------------- 'Create {Var} object'
            v|ariable = {Var}(Type_n = Type_n, In_type_ = THIS,
                Line = Parse.Line), >> Field[]
                
            Parse.Scan_names(v.Names[], "")
            CASE field_defined_in_base_class(Base_, v.Names[]) ?
                 Parse.Err("Field was already defined in an ancestor "
                 "class, use another names"._Efield5 ": " v.Whole_name)
            ;
            CASE v.Type_n.[0] == "{" && v.Type_n.[1].Lower == v.Type_n.[1]
            	 && v.Names[0].[*] == "_" && !Parse.Case_insensitive
            	 ?
                 Parse.Err("Weak references are allowed only onto objects of "
                 "classes, not structures or enumerations"._WeakToStruct)
            ;
            check_names_uniq(v.Names[], all_field_fun[], TRUE)
            ------------------------------------------------ 'array ?'
            Parse.Check_names(v.Names[])
            Parse.Check_reserved(v.Names[])
            CASE Parse.Symbol("[") ?
                 DEBUG:
                      CASE v.Names[0]=="Syn_tacts_in_envelope" ? 
                           ------------------- 'test1'
                      ;
                 ;                 
                 v.Is_array = TRUE
                 CASE ?
                 [Parse.Symbol("*")] ?
                      v.Is_fixed = TRUE
                      v.Size_n = "*"
                 [Parse.Next_char == "{"] ?
                     v.Is_fixed = TRUE
                     v.Size_n = Parse.Scan_type
                 [!Parse.Next_symbol("]")] ?
                      v.Is_fixed = TRUE
                      v.Size_value = Parse.Number
                      v.Size_n = v.Size_value.Str
                 ;
                 //CASE v.Is_fixed ?
                 //     //CASE v.Type_==NONE ? v.Type_ = Find_type(v.Type_n) ;
                 //     CASE v.Type_.Kind IN ['STRUCTURE', 'CLASS'] ?
                 //          Parse.Err("Fixed arrays of structures and objects "
                 //          "are not supported now"._EFixedArraysObjectsStruct)
                 //     ;
                 //;
                 Parse.Wait("]") ;
            ----------------------------------------- 'indexing {type} ?'
            CASE v.Type_n IN ["INT", "INTEGER", "BYTE"] ?     
	             BOOL is_index = Parse.Symbol("INDEXING")
	             CASE ?
	             [is_index && Parse.Symbol("(")] ? 
	                 v.Type_indexing = Parse.Skip_to(")")
	                 Parse.Wait(")")
	             [is_index] ? v.Type_indexing = Parse.Scan_type ;
            ;
            ----------------------------------------- 'initial value?'
            //CASE (v.Type_n[0] != "{" || v.Type_n IN ["{bool}", "{byte}"] || (
            //      v.Type_n[1].Upper == v.Type_n[1].Lower)) && Parse.Symbol("=")
            //CASE (v.Type_.Kind != 'STRUCTURE') && Parse.Symbol("=")
            CASE Parse.Symbol("=")
                ?
                CASE v.Is_array ?
                     //v.Constant_value = Parse.Scan_array
                     Parse.Err("Initialization of arrays is not supported. "
                     "Use initialization in the CONSTRUCT.") ;
                //CASE v.Type_ == NONE && v.Type_n.[0]=="{" ?
                //     v.Type_ = Find_type(v.Type_n) ;
                //CASE v.Type_.Kind == 'STRUCTURE' ?
                //     Parse.Err("Initialization of structures is not supported. "
                //     "Use initialization in the CONSTRUCT.") ;
                v.Constant_value = Parse.Scan_expr
            ;
            Parse.Skip_sp
            ---------------------------------------------- 'modifiers'
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                Parse.Wait(",")
                v.Handle_modifier
                Parse.Skip_sp
                CASE Parse.End_of_line ? BREAK x ;
            ;
            Parse.Fin
            Last_fun = NONE
            Last_var = v .
            
        FUNCTION field_defined_in_base_class(
            {Type} B|ase_class, STR Names|_field[]) ==> BOOL, RECURSIVE
            :
            CASE B == NONE ? ==> ;
            FOR f IN B.Field[] :
                FOR n IN Names[] :
                    CASE n IN f.Names[] ? RESULT = TRUE ==> ;
                ;
            ;
            RESULT = field_defined_in_base_class(B.Base_, Names[]) .
            
        */

        static int cnt_precompile_var;

        private void precompile_var(string Type_name)
        {
            if (++cnt_precompile_var == 190)
            { }
            Variable v = new Variable(Parse.Compiler_);
            v.Type_n = Type_name;
            v.In_class_ = this;
            v.Line = Parse.Line;
            Field.Add(v);
            Parse.Scan_names(v.Names);
            foreach (string n in v.Names)
            {
                if (All_id.Contains(n))
                    err("Duplicating name: " + n);
                All_id.Add(n);
            }
            Parse.Check_names(v.Names);
            Parse.Check_reserved(v.Names);
            if (Parse.Symbol("["))
            {
                if (Parse.Next_char() == "{")
                {
                    v.Is_fixed = true;
                    v.Size_n = Parse.Scan_type();
                }
                Parse.Wait("]");
                v.Is_array = true;
            }
            //----------------------- indexing
            if (Parse.Symbol("INDEXING")) {
            	if (Parse.Symbol("(")) {
            		Parse.Skip_to(")");
            		Parse.Wait(")");
            	}
            	else Parse.Skip_to(" ");
            }
            
            if (Parse.Symbol("="))
            {
                if (v.Is_array)
                    v.Value = Parse.Scan_array();
                else v.Value = Parse.Scan_expr();
            }
            Parse.Skip_sp();
            for (int xdummy = Parse.Pos; xdummy <= Parse.Last(); xdummy++)
            {
                Parse.Wait(",");
                v.Handle_modifier();
                Parse.Skip_sp();
                if (Parse.End_of_line()) break;
            }
            Parse.Fin();
        }

        /*
        
        METHOD precompile_native :
            Parse.Wait(":")
            CASE Parse.End_of_line ? Parse.Fin ;
            
            native_directive|temp = {Fun}(
            		Line_start = Parse.Line, 
                	Pos_start = Parse.Pos,
                	Modifiers['NATIVE_FUN'] = TRUE,
                	A_Name_1 = "-",
                	Final_name = "-",
                	Parse = Parse)
                	
            Method[] << native_directive
                	
            INT dummy_line = skip_to_end_of_fun(native_directive) .
        */
        static int CNT_precompile_native; 

        private void precompile_native()
        {
            if (++CNT_precompile_native == 2)
            { }

            Parse.Wait(":");
            if (Parse.End_of_line()) Parse.Fin();
            Function temp = new Function(Parse);
            temp.Parse = Parse;
            temp.Line_start = Parse.Line;
            temp.Modifiers[(int)Function.Fun_mod.NATIVE] = true;
            temp.Final_name = "-";
            Method.Add(temp);
            temp.Native_code = Parse.String_const(false);
            Parse.Wait(".");
            Parse.Fin();
        }

        /*
        
        METHOD precompile_todo:
            INT at|_line_todo = Parse.Line
            Parse.Wait(":")
            Parse.Skip_sp
            //CASE !Parse.Next_symbol("@") ?
            //     Parse.Wait(#QU) ;
            STR text|_to_do = Parse.String_const(FALSE)
            Parse.Wait(".")
            Parse.Fin
            PUSH Parse.Line = at :
                 PUSH comp.Todo_warn = TRUE :
                      Parse.Warn("TODO"._Wtodo ": " text) ;
            ; .
		*/
		public void precompile_todo()
		{
			Parse.Wait(":");
			Parse.Skip_sp();
			string text = Parse.String_const(false);
			Parse.Wait(".");
			Parse.Fin();
			Parse.Warn("TODO: " + text);
		}
		/*
		
		METHOD precompile_table :
			------------------------------- 'make TABLE'
			t|able_precompiled = {Table}, >> Table[]
			Parse.Scan_names(t.Names[], "")
			Parse.Check_names(t.Names[])
            check_names_uniq(t.Names[], all_field_fun[], TRUE)
			------------------------------- 'save position to compile from'
			Parse.Wait(":")
			t.Line = Parse.Line
			t.Pos = Parse.Pos
			INT dummy_line = skip_to_end_of_fun(NONE) .
			
        STR all_enum_structures|_names[]
        
        METHOD precompile_enum :
            -------------------------------- 'Create {Enum} object'
            e|numeration = {Type}(
            		Parse = Parse,
            		Base_ = THIS,
                	Kind = 'ENUM',
                	Line = Parse.Line,
                	Original_type_index = -1), OWNED BY THIS
                
            Enums_[] << e
            -------------------------------- 'Scan names'
            Parse.Wait("{")
            Parse.Scan_names(e.Names[], "")
            FOR n IN e.Names[] :
                e.Names[n.Index] = "{" n "}"
                CASE n.[0].Lower != n.[0] ?
                     Parse.Err("Enumeration name must start from "
                     "lowercase letter"._Eenum);
            ;
            Parse.Wait("}")
            --------------------- 'check override ENUM'
            {Type} base_c|lass = Base_
            FOR b|dummy IN [0 TO 999] :
                CASE base_c==NONE ? BREAK b ;
                FOR be IN base_c.Enums_[] :
                    CASE e.Names[0]==be.Names[0] ? 
                         Parse.Warn("Possible override ENUM"._WOverEnum
                         ": " e.Names[0])
                         
                         BREAK be, BREAK b 
                    ;
                ;
                base_c = base_c.Base_
            ;
            ------------------------------- 'Deprecated / Abandoned ?'
            CASE Parse.Symbol(",") ?
                 CASE Parse.Symbol("SYSTEM") ? 
                      CASE e.Names[0] ? 
                      ["{bool}"]: Parse.Compiler_.{Compiler}.TYPE_BOOL = e
                      			  Parse.Compiler_.{Compiler}.TRUE_c.Type_ = e
                      			  //Parse.Compiler_.{Compiler}.TRUE_c.Bool_c = TRUE
                      			  Parse.Compiler_.{Compiler}.FALSE_c.Type_ = e
                      			  e.Kind = 'BOOL'
                      ["{byte}"]: Parse.Compiler_.{Compiler}.TYPE_BYTE = e 
                      Parse.Compiler_.{Compiler}.SYSFUN_Byte.Result.Type_ = e
                      e.Final_name = "byte" //! if your final lang has
                      //! another name of the byte type, rename it later
                      ;
                 ELSE subtype_abandoned_or_deprecated(e) ;
            ;
            Parse.Wait(":")
            CASE Parse.End_of_line ? Parse.Fin ;
            Parse.Check_names(e.Names[])
            check_names_uniq(e.Names[], all_enum_structures[], TRUE)
            ------------------------------ 'List items'
            INT item_idx = 0
            FOR x|dummy IN [Parse.Pos TO Parse.Last] :
                CASE Parse.Symbol("--") ? 
                     Parse.Pos = Parse.Last+1
                     Parse.Fin
                     CONTINUE x ;
                CASE Parse.End_of_line ? Parse.Fin ;
                Parse.Wait("'")
                
                {Var} item|_enum = {Var}(
                	In_type_ = THIS,
                	Type_ = e,
                    Line = Parse.Line,
                    Is_const = TRUE,
                    Int_c = item_idx), >> e.Items[]
                    
                item_idx += 1
                Parse.Scan_names(item.Names[], "-0123456789")
                Parse.Wait("'")
                -------------------------- 'handle names of item'
                FOR n IN item.Names[] :
                    n = "'" n "'"
                    item.Names[n.Index] = n ;
                check_names_uniq(item.Names[], all_field_fun[], TRUE)
                Parse.Check_names(item.Names[])
                CASE !Parse.Symbol(",") ? BREAK x ;
            ;
            ------------------------------- 'Should not be > 256'
            CASE Parse.End_of_line ? Parse.Fin ;
            CASE e.Items[].Count > 256 ?
                 Parse.Err("Enumeration contains more then 256 items"._Eenum2) ;
            Parse.Wait(".")
            Parse.Fin .
            
        METHOD subtype_abandoned_or_deprecated(
        	{Type} Sub|_type)
        	:
            ------------------------------ 'which from ABANDONED / DEPRECATED ?'
            CASE Parse.Ident ?
            ["DEPRECATED"]: Sub.Modifiers['DEPRECATED'] = TRUE
            ["ABANDONED"]:  Sub.Modifiers['ABANDONED'] = TRUE
            ELSE Parse.Err("Unknown modifier"._Eunk3) ;
            ------------------------------- 'Parameter (what to use instead)'
            Parse.Wait("(")
            Parse.Wait("'")
            INT from|_pos = Parse.Pos
            NONE = Parse.Skip_to("'")
            Sub.Deprecate = Parse.Source[Parse.Line].[from TO Parse.Pos-1]
            Parse.Wait("'")
            Parse.Wait(")") .

   		FUN is_power_of_two(INT N|umber_to_check) ==> BOOL :
   			INT n|umber_shifted = N
   			FOR i|dummy IN [0 TO 1000] :
   			    CASE n == 0 ? ==> ;
   			    CASE n == 1 ? RESULT = TRUE ==> ;
   			    n = n / 2 ; .

        METHOD precompile_structure :
            --------------------------------------- 'Create {Type} object'
            obj|ect_type = {Type}(
            		Parse = Parse,
            		Base_ = NONE,
            		Kind = 'STRUCTURE',
            		In_class_ = THIS,
            		Line = Parse.Line,
            		Original_type_index = -1), OWNED BY THIS
                         
            Structures_[] << obj
            --------------------------------------- 'Scan names'
            Parse.Wait("{")
            Parse.Scan_names(obj.Names[], "")
            FOR n IN obj.Names[] :
                obj.Names[n.Index] = "{" n "}"
                CASE n.[0].Lower != n.[0] ?
                     Parse.Err(
                     "Structure type name must start from lowercase letter"
                     ""._Estruc) ;
            ;
            Parse.Wait("}")
            ---------------------------------------- 'Deprecated / Abandoned ?'
            CASE Parse.Symbol(",") ?
                 subtype_abandoned_or_deprecated(obj) ;
            Parse.Wait(":")
            Parse.Check_names(obj.Names[])
            CASE Parse.End_of_line ? Parse.Fin ;
            ------------------------------------ 'Fields of structure'
            STR all_field_n|ames[]
            FOR x|dummy IN [Parse.Line TO Parse.Source[].Count] :
                CASE Parse.Symbol(".") ? BREAK x ;
                CASE Parse.Symbol("--") ?
                     Parse.Line += 1
                     Parse.Pos = 0
                     CONTINUE x ;
                     
                --------------------------- 'get fields from another structure'
                CASE Parse.Symbol("LIKE") ?
                     STR s_from|_type = Parse.Scan_type
                     //DEBUG: << "LIKE [" s_from "]" #NL ;
                     {Type} t_from|_type = Find_type(s_from)
                     CASE t_from.Kind != 'STRUCTURE' ?
                          Parse.Err("Original type is not a structure"
                          ""._EOrigNotStruc ": " s_from) 
                     ;
                     FOR fld IN t_from.Field[] :
                         CASE obj.Search_field(fld.Names[0]) != NONE ?
                              Parse.Err("Duplicating field"._DupField
                              ": " fld.Names[0])
                         ;
                         field|_of_object = {Var}(
		                	Line = Parse.Line,
		                	In_type_ = obj,
		                	Type_= fld.Type_,
		                	Type_n= fld.Type_n,
		                	Is_array= fld.Is_array,
		                	Is_fixed= fld.Is_fixed,
		                	Size_n= fld.Size_n,
		                	Size_value= fld.Size_value,
		                	Modifiers['INIT']= fld.Modifiers['INIT'],
		                	Modifiers['CLAMP']= fld.Modifiers['CLAMP'],
		                	Names[] << fld.Names[0]), >> obj.Field[]
		                	
                         FOR i_n IN [1 TO fld.Names[].Count-1] : 
                             field.Names[] << fld.Names[i_n] ;
                         
                         //obj.Field[] << fld 
                     ;
                     CASE Parse.Symbol(".") ? BREAK x ;
                     Parse.Fin
                     CONTINUE x
                ;
                     
                field = {Var}(
                	Line = Parse.Line,
                	In_type_ = obj), >> obj.Field[]
                	
                field.Type_n = Parse.Scan_type
                Parse.Scan_names(field.Names[], "")
                
                INT fpos|ition_open_fig_bracket = Find_last(field.Type_n, "{")
                	
                CASE fpos >= 0  
                	 && field.Type_n.[fpos+1].Upper == field.Type_n.[fpos+1] // 'CLASS' field
                	 && field.Names[0].[*] != "_"
                	 ?
                     Parse.Err("Structure can have only weak references onto "
                     "objects of classes"._EStructToClass)
                ;
                
                FOR n IN field.Names[] :
                    CASE n IN all_field_n[] ?
                         Parse.Err("Duplicating name"._Edup7a ": " n) ;
                    all_field_n[] << n ;
                Parse.Check_names(field.Names[])
                -------------------------------------- '[dim] ?'
                CASE Parse.Symbol("[") ?
                     BOOL dim|ension_done = FALSE
                     field.Is_array = TRUE
                     CASE Parse.Symbol("]") ? dim = TRUE ;
                     CASE !dim && Parse.Next_symbol("{") ?
                          field.Is_fixed = TRUE
                          field.Size_n = Parse.Scan_type
                          dim = TRUE
                          Parse.Wait("]") ;
                     Parse.Skip_sp
                     CASE !dim && !Parse.Next_symbol("]") ?
                          field.Is_fixed = TRUE
                          field.Size_value = Parse.Integer ;
                     CASE !dim ? Parse.Wait("]") ;
                     CASE field.Is_fixed && field.Size_n == "" && (
                          field.Size_value <= 0 || (
                          field.Size_value > 1024 * 1024))
                          ?
                          Parse.Err("Fixed array size invalid"._Efix2a) ;
                ;
                ---------------- 'indexing ?'
                CASE field.Type_n IN ["INT", "INTEGER", "BYTE"] ?
	                 BOOL is_index = Parse.Symbol("INDEXING")
	                 CASE ?
	                 [is_index && Parse.Symbol("(")] ?
	                     field.Type_indexing = Parse.Skip_to(")")
	                     Parse.Wait(")")
	                 [is_index] ? field.Type_indexing = Parse.Scan_type ;
                ;
                ----------------------------------- ', CLAMP'
                FOR i|dummy IN [1 TO 2] :
                	CASE !Parse.Symbol(",") ? BREAK i ;
                	STR mod|ifier_name = Parse.Ident
                	CASE mod ?
                	["CLAMP"]: modifier_obj_CLAMP(field)
                	["INIT", "INITIALIZE"]: modifier_obj_INIT(field)
                	ELSE Parse.Err("Incorrect modifier"._EIncorrMod ": " mod) ;
                ;
                CASE Parse.Symbol(".") ? BREAK x ;
                Parse.Fin ;
            Parse.Fin .
            
        METHOD modifier_obj_CLAMP({Var} Field|_to_apply_to) :
        	 Field.Modifiers['CLAMP'] = TRUE
             INT size|_items = Field.Size_value
             CASE size == 0 || !size.is_power_of_two ?
                  Parse.Err("Only fixed array which size is "
                  "power of two, can be CLAMPing"._EonlyFixedArr2
                  " (" size.Str ")")
             ; .

             
        FUN modifier_obj_INIT({Var} Field|_to_apply_to) :
			Field.Modifiers['INIT'] = TRUE .
            
        */
        static int CNT_precompile_enum;

        private void precompile_enum()
        {
            if (++CNT_precompile_enum == 6)
            { }

            Type e = new Type();
            e.Base_ = this;
            e.Parse = Parse;
            e.Kind = Kind_type.ENUM;
            Enums_.Add(e);
            Parse.Wait("" + obr);
            Parse.Scan_names(e.Names);

            for (int INDEX = 0; INDEX < e.Names.Count; INDEX++)
            {
                string n = e.Names[INDEX];
                if ((n[0] + "").ToLower() != n[0] + "")
                    Parse.Err("Enumeration name must start from lowercase letter");
                e.Names[INDEX] = obr + n + cbr;
            }
            Parse.Wait("" + cbr);
            Parse.Wait(":");
            if (Parse.End_of_line()) Parse.Fin();
            Parse.Check_names(e.Names);
            //---------------------- 'list items'
            int item_idx = 0;
            for (int xdummy = Parse.Pos; xdummy <= Parse.Last(); xdummy++)
            {
                if (Parse.End_of_line()) break;
                Parse.Wait("''".Substring(1));
                Variable item = new Variable(Parse.Compiler_);
                item.Is_constant = true;
                item.Type_ = e;
                item.Line = Parse.Line;
                item.Int_c = item_idx++;
                e.Items.Add(item);
                Parse.Scan_names(item.Names);
                Parse.Wait("''".Substring(1));
                //------------------- 'handle names of item'
                for (int INDEX = 0; INDEX < item.Names.Count; INDEX++)
                {
                    string n = item.Names[INDEX];
                    n = "'" + n + "'";
                    item.Names[INDEX] = n;
                    if (All_id.Contains(n)) err("Duplicating name: " + n);
                    All_id.Add(n);
                }
                Parse.Check_names(item.Names);
                if (!Parse.Symbol(",")) break;
            }
            Parse.Wait(".");
            Parse.Fin();
        }

        /*
        
        METHOD precompile_fun|ction(
        STR Keyword|_starting_function )
        	:
            --------------------------- 'Create {Fun} object'
            {Fun} f|unction_to_precompile = {Fun}(
            	Parse = Parse,
            	Line_start = Parse.Line,
            	A_Name_1 = "",
                Header_line = Parse.Line), OWNED BY THIS
                
            CASE Keyword IN ["FUN", "FUNCTION"] ? f.Modifiers['STATIC'] = TRUE ;
            --------------------------- 'name(s)'
            CASE Parse.Symbol(".") ?
                 --------- 'METHOD .[...] - to implement {Vector}, {Matrix} etc'
                 CASE f.Modifiers['STATIC'] ?
                      Parse.Err("Only METHOD can be used as the .[] method"
                      ""._EOnlyMethodDot)
                 ;
                 f.Names[] << "."
                 FOR m IN Method[] :
                     CASE m.Names[0] == "." ?
                          Parse.Err("Method .[] must be exclusive but another "
                          "one was already declared at line"._EdtExcl 
                          ": " (m.Line_start + 1).Str)
                          BREAK m ;
                 ;
                 BOOL is_dot|_method = TRUE
            ELSE
	             Parse.Scan_names(f.Names[], "")
	             ----------------------------- 'Checks for names'
	             check_names_uniq(f.Names[], all_field_fun[], TRUE)
	             FOR n IN f.Names[] :
	                 CASE n.[*] == "_" ?
	                     warn("Function name should not be ended with '_'"._Wfun)
	                 ;
	             ;
            	 Parse.Check_names(f.Names[])
            	 Parse.Check_reserved(f.Names[])
            ;
            f.A_Name_1 = f.Names[0]
            Add_method(f)
            ---------------------------- 'Parameters'
            BOOL is_param|eters_list = is_dot && Parse.Symbol("[")
            	 is_param ||= !is_dot && Parse.Symbol("(")
            CASE is_param ?
                 CASE Parse.End_of_line ? Parse.Fin ;
                 STR all_param_n|ames[]
                 INT last|_x_vbound = Parse.Last
                 CASE last < Parse.Source[].Count ? last = Parse.Source[].Count;
                 FOR x|dummy IN [Parse.Pos TO last] :
                     CASE Parse.End_of_line ? Parse.Fin ;
                     
                     {Var} p|arameter = {Var}(
                    	 In_fun_ = f,
                    	 Line = Parse.Line,
                         Type_n = Parse.Scan_type,
                         Is_param = TRUE), >> f.Param[]
                         
                     CASE "," IN p.Type_n ?
                          BOOL is_overload|ing_function = TRUE ;
                     CASE ?
                     [is_overload && is_dot] ?
                          Parse.Err(".[...] functions can not be overloading "
                          "by types of parameters"._ECanNotOverload
                          ": " p.Type_n)
                     [is_overload && Keyword == "TEST"] ?
                          Parse.Err("TEST can not be overloading by types of "
                          "parameters"._ETestCanNotOverload)
                     [is_overload && Keyword == "OVERRIDE"] ?
                          Parse.Err("It is not allowed to override overloaded "
                          "method or overload a method while overriding it"
                          ""._ECantOverrideOverload)
                     ;
                     Parse.Scan_names(p.Names[], "")
                     Parse.Check_names(p.Names[])
                     Parse.Check_reserved(p.Names[])
                     check_names_uniq(p.Names[], all_param_n[], TRUE)
                     handle_array_param(p, Parse)
                     ------------------------ 'indexing parameter'
                     BOOL is_index = Parse.Symbol("INDEXING")
                     CASE ?
                     [is_index && Parse.Symbol("(")] ?
                         p.Type_indexing = Parse.Skip_to(")")
                     	 Parse.Wait(")")
                     [is_index] ? p.Type_indexing = Parse.Scan_type ;
                 	 ------------------------ 'final name is X_ + Names[0]'
                 	 p.Set_final_name("X_" p.Names[0])
                     ------------------------ 'to next parameter'
                     CASE !Parse.Symbol(",") ? BREAK x ;
                 ;
                 CASE is_dot ? Parse.Wait("]")
                 ELSE Parse.Wait(")") ;
            ;
            CASE Parse.End_of_line ?
                 FOR yy IN [Parse.Line+1 TO Parse.Source[].Count-1] :
                     CASE Parse.Source[yy].Trim == "" ? CONTINUE yy ;
                     DONE     
	                      CASE Starting(Parse.Source[yy].TrimL, "==>") ?
	                           Parse.Fin
	                           f.Line_start = Parse.Line ;
	                      BREAK yy ;
            ;
            ----------------------------- 'Result type'
            CASE Parse.Symbol("==>") ?
                f.Result = {Var}(In_fun_ = f, Type_n = Parse.Scan_type,
                    Names[] << "RESULT", Is_param = TRUE, Line = Parse.Line),
                    OWNED BY f
                f.Result.Set_final_name("RESULT")
                CASE Parse.Symbol("RESULT") ?
                     ------------------- '==> RESULT|comment'
                     CASE Parse.End_of_line ? Parse.Fin ;
                     Parse.Wait("|")
                     NONE = Parse.Ident ;
        	ELSE
        		 CASE is_dot ?
        		      Parse.Err("Method .[] should have a result type"
        		      ""._EDotResult) ;
            ;
            -------------------------------- 'Modifiers'
            FOR x|dummy IN [Parse.Pos TO Parse.Last+1000] :
                CASE Parse.Symbol(",") ?
                     CASE Parse.End_of_line ? Parse.Fin ;
                     f.Handle_modifier
                ELSE BREAK x ;
            ;
            CASE  ! f.Modifiers['STATIC'] && f.Modifiers['ABANDONED_FUN'] ?
                 f.Modifiers['REPLACE'] = TRUE ;
            //CASE ! f.Modifiers['NATIVE_FUN'] && f.Param[].Count > 3 ?
            //    Parse.Class_.Detect_bad("Too many parameters (more then 3)") ;
            CASE f.Modifiers['NATIVE_FUN'] && !f.Modifiers['STATIC'] ?
                 Parse.Err("Only static functions allowed to be NATIVE"
                 ""._EOnlyStaticNATIVE)
            ;
            CASE f.Stored_param != NONE ? 
                 f.Stored_param.Set_final_name("XS_" f.Names[0] ) ;
            CASE Parse.End_of_line ? Parse.Fin ;
            --------------- ':'  
            //PUSH Syntax_fun :
                 detect_syntax_fun
	             f.Pos_start = Parse.Pos
	             f.Line_start = Parse.Line
	             FOR pp IN f.Param[] :
	            	 CASE f.Is_public && pp.Names[0].[0].Lower == pp.Names[0].[0]
	            		  && !Any_case
	            		  ?
	                      warn("It is recommended to use names starting from "
	                      "an upper-case letter for function parameters "
	                      "in case of public functions and methods"._Witis3)
	            	 ;
	             ;
	             //DEBUG:
	             //      CASE p_debug ?
	             //           << "pos_start=" f.Pos_start.Str #NL ;
	             //;
	             ---------------------------- 'method / static function'
	             CASE Keyword == "METHOD" ?
	                  CASE f.Modifiers['STATIC'] ?
	                       Parse.Err("METHOD can not be STATIC"
	                       ""._EMethodCannotBeStatic) ;
	             ELSE 
	                  CASE ! f.Modifiers['STATIC'] ?
	                       Parse.Err("Method should be started with the keyword "
	                       "METHOD"._EMethodMethod) ;
	             ;
	             ---------------------------- 'check name is not overriding smth'
	             CASE Base_ != NONE && !f.Modifiers['STATIC']
	                  && Base_.Search_fun(f.Names[0], CASE_SEN, FALSE) != NONE 
	                  ?
	                  PUSH Parse.Line = f.Line_start :
	                       {Fun} base_m|ethod 
	                       = Base_.Search_fun(f.Names[0], CASE_SEN, FALSE)
	                        
	                       Parse.Err("Method"._Emethod " " f.Names[0] 
	                       " " ("is overriding an "
	                       "ancestor but OVERRIDE FUNCTION is not specified "
	                       "in the method handle")._Eis3
	                       ": " base_m.Class.Whole_name "." base_m.Whole_name ) 
	                  ;
	             ;
	             ------------------------------- 'Skip to end of function'
	             //DEBUG:
	             //      CASE p_debug ?
	             //           << "before finding end: Line=" Parse.Line.Str #NL ;
	             //;
	             f.Line_end = skip_to_end_of_fun(f)
            //;
            //DEBUG:
            //      CASE p_debug ?
            //           << "Line_end=" f.Line_end.Str #NL ;
            //;
            Last_var = NONE
            Last_fun = f 
            ------------------------------- 'overloading'
            CASE !is_overload ? ==> ;
            FOR pp IN f.Param[] :
                CASE "," IN pp.Type_n ?
                     STR pp_type|_splitted[]
                     Split(pp_type[], pp.Type_n, ",")
                     INT vn|umber_of_variants = pp_type[].Count
                     BREAK pp ;
            ;
            CASE vn == 0 ?
            	 PUSH Parse.Line = f.Line_start :
            	 PUSH Parse.Pos = 0 :
                 	  Parse.Err("Overloaded function error"._EOverloading) ;
            	 ;
            ;
            FOR i INDEXING STR IN [0 TO vn-1] :
                vf|unction_variant = {Fun}(Parse = Parse,
            		Line_start = f.Line_start,
            		Pos_start = f.Pos_start,
            		A_Name_1 = "",
                	Header_line = f.Header_line,
                	Line_end = f.Line_end,
                	Modifiers['STATIC'] = f.Modifiers['STATIC'],
                	Modifiers['RECURSIVE_FUN'] = f.Modifiers['RECURSIVE_FUN'],
                	Overload_base_ = f), OWNED BY THIS
                	
                FOR nm IN f.Names[] : vf.Names[] << nm ;
                vf.Provide_names_lowered
                f.Overloaded_[] << vf
                //Add_sorted(Method[], vf)
                Method[].Insert(Method[].Find(f)+1, vf)
                ----------------------- 'copy parameters, 1 type only'
                FOR pp IN f.Param[] :
                    p = {Var}(
                    	In_fun_ = f,
                    	Line = pp.Line,
                        Type_n = pp.Type_n,
                        Type_ = pp.Type_,
                        Is_array = pp.Is_array,
                        Is_fixed = pp.Is_fixed,
                        Is_param = TRUE), >> vf.Param[]
                        
                    FOR nm IN pp.Names[] : p.Names[] << nm ;
                    p.Set_final_name("X_" p.Names[0])
                    CASE "," !IN p.Type_n ? CONTINUE pp ;
                    pp_type[].Clear
                    Split(pp_type[], p.Type_n, ",")
                    CASE pp_type[].Count != vn ?
                         Parse.Err("Parameters have different amount of "
                         "variable types"._EParamDiffTypes
                         ": parameter #" (pp.Index+1).Str
                         " (" pp_type[].Count.Str ") but variants are: " vn.Str)
                    ;
                    p.Type_n = pp_type[i]
                ;
                CASE f.Result == NONE ? CONTINUE i ;
                ------------------------ 'copy Result, 1 type only'
                {Var} vf_result = {Var}(In_fun_ = vf, 
                	Type_n = f.Result.Type_n,
                	Type_ = f.Result.Type_,
                    Names[] << "RESULT", 
                    Is_param = TRUE, 
                    Line = f.Result.Line),
                    OWNED BY vf
                    
                vf.Result = vf_result
                vf.Result.Set_final_name("RESULT")
                CASE "," !IN vf.Result.Type_n ? CONTINUE i ;
                pp_type[].Clear
                Split(pp_type[], vf.Result.Type_n, ",")
                CASE pp_type[].Count != vn ?
                	 Parse.Err("Result has another amount of "
                         "variable types"._EResultDiffTypes)
                ;
                vf.Result.Type_n = pp_type[i]
            ; .

        
            
        METHOD precompile_override :
            -------------------------------- 'Create {Fun} object'
            CASE ?
            [Parse.Symbol("FUNCTION")] ? BOOL ambig|ous_function = TRUE
            [Parse.Symbol("FUN")] ? ambig = TRUE ;
            CASE ambig ?
                 Parse.Warn("Ambiguous symbol FUN|CTION after OVERRIDE") ;
            STR name|_method = Parse.Ident
            FOR idummy IN [0 TO Parse.Last] :
                CASE Parse.Symbol("||") || Parse.Symbol("|") ?
                     NONE = Parse.Ident
                ELSE BREAK idummy ;
            ;
            
            {Fun} f|un_override = {Fun}(
            	Parse = Parse,
            	Line_start = Parse.Line,
            	A_Name_1 = name,
            	Names[] << name), OWNED BY THIS
            	  
            Add_method(f)
            -------------------------------- 'Check for ancestor method'
            {Type} a|ncestor = Base_
            FOR x IN [0 TO 1000] :
                CASE a == NONE ?
                     Parse.Err("Method"._Emethod2 " " name 
                     " " ("was not found in ancestor classes"._Ewas2) 
                     ", x = " x.Str)
                     BREAK x ;
                f.Ancestor_ = a.Find_fun(name, TRUE)
                CASE f.Ancestor_ != NONE ?
                     f.Ancestor_.Overridden = TRUE
                     BREAK x ;
                a = a.Base_ ;
            --------------------------------- 'check duplication of OVERRIDE'
            FOR m IN Method[] :
                CASE m == f ? CONTINUE m ;
                CASE m.Ancestor_ == f.Ancestor_ ?
                     Parse.Err("Duplicated OVERRIDE for method (already defined"
                     " at line"._Edup8 " " m.Line_start.Str ")") ;
            ;
            --------------------------------- 'Check overriding UNCOOKED method'
            CASE f.Ancestor_.Modifiers['UNCOOKED'] ?
                 Parse.Warn("Overriding function"._Wover 
                 " " f.Ancestor_.Names[0] " " ("which"
                 " is probably not yet supported (marked UNCOOKED)"._Wwhich)) ;
            //CASE f.Ancestor_.Modifiers['CALLBACK'] ?
            //     f.Modifiers['CALLBACK'] = TRUE ;
            -------------------------------- 'Parameters'
            CASE f.Ancestor_.Param[].Count > 0 ?
                 Parse.Wait("(")
                 STR all_param_n|ames[]
                 FOR p IN f.Ancestor_.Param[] :
                     p2|_parameter = {Var}(In_fun_ = f, Line = Parse.Line,
                        Type_n = Parse.Scan_type, Is_param = TRUE,
                        Type_indexing= p.Type_indexing),
                        >> f.Param[]
                     Parse.Scan_names(p2.Names[], "")
                     Parse.Check_names(p2.Names[])
                     Parse.Check_reserved(p2.Names[])
                     CASE p2.Names[0].[0].Upper != p.Names[0].[0].Upper ?
                          STR er|ror_message = "Name of parameter must "
                          	 "start from the same letter as name of a "
                          	 "correspondent parameter of a "
                          	 "function which is override"._Ename
                          	 ": " p.Whole_name
                          	 
                          er = er " <-- " p2.Whole_name
                          Parse.Err(er)
                     ;
                     check_names_uniq(p2.Names[], all_param_n[], TRUE)
                     CASE p.Is_array ? 
                          p2.Is_array = TRUE
                          p2.Is_fixed = p.Is_fixed
                          wait_for_array(p, p2) ;
                     BOOL is_index = Parse.Symbol("INDEXING")
                     CASE ?
                     [is_index && Parse.Symbol("(")] ?
                          p2.Type_indexing = Parse.Skip_to(")")
                          Parse.Wait(")")
                     [is_index] ?  p2.Type_indexing = Parse.Scan_type
                     ;
                     ------------------------ 'final name is X_ + Names[0]'
                 	 p2.Set_final_name("X_" p.Names[0])
                     CASE p != f.Ancestor_.Param[*] ? Parse.Wait(",") ;
                 ;
                 Parse.Wait(")") ;
            -------------------------- 'Result type'
            CASE ?
            [f.Ancestor_.Result != NONE] ?
                 Parse.Wait("==>")
                 
                 f.Result = {Var}(
                 		In_fun_ = f,
                 		Type_n = Parse.Scan_type,
                     	Names[] << "RESULT",
                     	Is_param = TRUE,
                     	Line = Parse.Line), OWNED BY f
                     
                 f.Result.Set_final_name("RESULT")
            [Parse.Symbol("==>")] ?
                 Parse.Err("Ancestor method does not return a result"
                 ""._AncestorNotResult)
            ;
            -------------------------- 'Modifiers'
            FOR x IN [Parse.Pos TO Parse.Last] :
                CASE Parse.Symbol(",") ? f.Handle_modifier
                ELSE BREAK x ;
            ;
            CASE f.Stored_param != NONE ? 
                 f.Stored_param.Set_final_name("XS_" f.Names[0] ) ;
            CASE f.Ancestor_.Modifiers[{Fun}.{fun_mod}.'NEW'] && !f.Modifiers[
                 {fun_mod}.'NEW']
                 ?
                 Parse.Err("Overriding method with the NEW attribute must also "
                 "be marked as NEW object creating"._Eover)
            ;
            CASE f.Modifiers['NATIVE_FUN'] ?
                 Parse.Err("Only static functions allowed to be NATIVE"
                 ""._EOnlyStaticNATIVE_override) ;
            -------------------------- 'Skip the rest of function'
            CASE Parse.End_of_line ? Parse.Fin ;
            //PUSH Syntax_fun :
	             detect_syntax_fun
	             f.Pos_start = Parse.Pos
	             f.Line_end = skip_to_end_of_fun(f)
            //;
            Last_fun = f .

        METHOD wait_for_array|_parameter(
        	{Var} P|arameter_overriding,
            {Var} P2|_parameter_defining)
            :
            ------------------------- 'Want to see [...]'
            Parse.Wait("[")
            CASE P.Is_fixed ?
                 CASE P.Size_n[0] == "{" ?
                      P2.Size_n = Parse.Scan_type
                 ELSE Parse.Wait("*") ;
            ;
            Parse.Wait("]") .


        */
        private void precompile_fun(string Keyword)
        {
            Function f = new Function(Parse);
            if (Keyword == "FUNCTION" || Keyword == "FUN")
                f.Modifiers[(int)Function.Fun_mod.STATIC] = true;
            f.Parse = Parse;
            f.Line_start = Parse.Line;
            Method.Add(f);
            Parse.Scan_names(f.Names);
            //if (comp.Verbose)
            //    Console.WriteLine("Precompiling function: " + f.Names[0]);
            for (int INDEX = 0; INDEX < f.Names.Count; INDEX++)
            {
                string n = f.Names[INDEX];
                if (n[n.Length - 1] == '_')
                    warn("Function name should not be ended with '_'");
                if (All_id.Contains(n)) err("Duplicating name: " + n);
                All_id.Add(n);
            }
            Parse.Check_names(f.Names);
            Parse.Check_reserved(f.Names);
            //------------------------- 'parameter'
            if (Parse.Symbol("("))
            {
                List<string> all_param_n = new List<string>();
                for (int xdummy = Parse.Pos; xdummy <= Parse.Last(); xdummy++)
                {
                    Variable p = new Variable(Parse.Compiler_);
                    f.Param.Add(p);
                    p.In_fun_ = f;
                    p.Type_n = Parse.Scan_type();
                    
                    p.Is_param = true;
                    p.Line = Parse.Line;
                    Parse.Scan_names(p.Names);
                    Parse.Check_names(p.Names);
                    Parse.Check_reserved(p.Names);
                    if (((f.Names[0] + (char)0)[0] + "").ToLower() !=
                    	 (f.Names[0] + (char)0)[0] + "")
                	{
	                    if (((p.Names[0] + (char)0)[0] + "").ToLower() == 
	                         (p.Names[0] + (char)0)[0] + "")
	                        warn("It is recommended to use names starting from uppercase letter for function parameters");
                	} 
                    check_names_uniq(p.Names, all_param_n);
                    handle_array_param(p, Parse);
                    //------------------------indexing
                    if (Parse.Symbol("INDEXING")) {
		            	if (Parse.Symbol("(")) {
		            		Parse.Skip_to(")");
		            		Parse.Wait(")");
		            	}
		            	else Parse.Scan_type();
		            }
                    
                    if (!Parse.Symbol(",")) break;
                }
                Parse.Wait(")");
                //if (f.Param.Count > 3)
                //    Parse.Class_.Detect_bad("More then 3 parameters");
            }
            //------------------------- 'result type'
            if (Parse.Symbol("==>"))
            {
                f.Result = new Variable(Parse.Compiler_);
                f.Result.In_fun_ = f;
                f.Result.Type_n = Parse.Scan_type();
                
                f.Result.Names.Add("RESULT");
                f.Result.Final_name = "RESULT";
                f.Result.Is_param = true;
                f.Result.Line = Parse.Line;
            }
            //------------------------- 'modifiers'
            for (int xdummy = Parse.Pos; xdummy <= Parse.Last(); xdummy++)
            {
                if (Parse.Symbol(",")) f.Handle_modifier();
                else break;
            }
            Parse.Wait(":");
            f.Pos_start = Parse.Pos;
            //------------------------- 'skip to end of function'
            skip_to_end_of_fun(f);
        }

        /*
        
        METHOD check_names_uniq|ueness(
        	STR N|ames_to_check[], 
            STR A|ll_names[],
            BOOL Append|_new)
            :
            ---------------------------- 'For all names... '
            FOR n IN N[] :
                CASE n IN A[] ?
                     CASE Append ?
                          err("Duplicating name"._Edup9 ": " n)
                     ELSE err("Name is already in use"._Ename2 ": " n) ;
                ;
                CASE Append ? A[] << n ;
            ; .
        */
        private void check_names_uniq(List<string> Names, List<string> All)
        {
            foreach (string n in Names)
            {
                if (All.Contains(n)) err("Duplicating name: " + n);
                All.Add(n);
            }
        }

        /*
        
        FUNCTION handle_array_param|eter(
        	{Var} P|arameter,
            {Parser} Parse|_src)
            :
            ------------------------------------- '[], [*] or [{enum}]'
            CASE Parse.Symbol("[") ?
                P.Is_array = TRUE
                CASE Parse.Next_char ?
                     
                ["*"]: P.Is_fixed = TRUE
                        Parse.Skip_char
                        
                ["{"]: P.Is_fixed = TRUE
                	   P.Size_n = Parse.Scan_type
                	   
                	   Parse.Err("It is not allowed to use as parameters"
                        " arrays which size is ENUMERATION-based"
                        ""._EEnumBasedArraysParam) 
                ;
                Parse.Wait("]") ; .
                
        */
        private void handle_array_param(Variable P, Parser Parse)
        {
            if (Parse.Symbol("["))
            {
                P.Is_array = true;
                switch ((Parse.Next_char() + " ")[0])
                {
                    case '*':
                        P.Is_fixed = true;
                        Parse.Skip_char();
                        break;
                    case '{':
                        P.Is_fixed = true;
                        P.Size_n = Parse.Scan_type();
                        break;
                }
                Parse.Wait("]");
            }
        }

        /*
        
        METHOD precompile_construct :
            CASE Construct != NONE && Construct.Line_start == -1 && (
                 Construct.Block[].Count == 0)
                 ?
                 Method[].Remove(Construct)
                 Construct = NONE ;
            CASE Construct != NONE ? err("Duplicating CONSTRUCTION"._Edup10) ;
            //BOOL was|_construct_present = Construct != NONE
            Provide_construct
            
            CASE Parse.Symbol(",") ?
                 Parse.Wait("RECURSIVE")
                 Construct.Modifiers['RECURSIVE_FUN'] = TRUE
                 Detect({Type}.{class_mod}.'RECURSIVE') ;
                 
            //CASE !was ?
            //     << "%%%%%%%%%%%%%%%%%% provided at precompile_construct" 
            //        ", Method[].Count==" Method[].Count.Str
            //        ", Construct.Index ==" Method[].Find(Construct).Str #NL ;
            Construct.Line_start = Parse.Line
            handle_constr_destr(Construct) .
        */
        private void precompile_construct()
        {
            if (Construct_method != null) err("Duplicating CONSTRUCTION");
            Construct_method = new Function(Parse);
            Construct_method.Parse = Parse;
            Construct_method.Line_start = Parse.Line;
            Construct_method.Names.Add("_Construct");
            Method.Add(Construct_method);
            handle_constr_destr(Construct_method);
        }

        /*
        
        METHOD precompile_destruct :
            CASE Destruct != NONE ? err("Duplicating DESTRUCTION"._Edup11) ;
            
            Destruct = {Fun}(
            	Parse = Parse,
            	Line_start = Parse.Line,
                Names[] << "_Destruct",
                Final_name = "DESTRUCT",
                A_Name_1 = "DESTRUCT",
                Class_= THIS)
                
            Add_method(Destruct)
                
            handle_constr_destr(Destruct) .
        */
        private void precompile_destruct()
        {
            if (Destruct_method != null) err("Duplicating DESTRUCTION");
            Destruct_method = new Function(Parse);
            Destruct_method.Parse = Parse;
            Destruct_method.Line_start = Parse.Line;
            Destruct_method.Names.Add("_Destruct");
            Method.Add(Destruct_method);
            handle_constr_destr(Destruct_method);
        }

        /*
        
        STR Syntax1_fun|_ction = ":"
        
        METHOD detect_syntax_fun|ction :
            CASE ?
                 [Parse.Symbol(":")] ? Syntax1_fun = ":"
                 [Parse.Symbol("{")] ? Syntax1_fun = "{}"
                 [Parse.Symbol("BEGIN")] ? Syntax1_fun = "BEGIN END"
                 [Parse.Symbol("befgin")] ? Syntax1_fun = "begin end"
                 ELSE Parse.Err("Waiting for ':', '{' or BEGIN/begin")
            ; .
        
        
        METHOD handle_constr_destr(
        	{Fun} F|unction_constr_destr)
        	:
        	//PUSH Syntax_fun :
        	     detect_syntax_fun
	             ------------------------------ 'Initialize parser'
	             F.Pos_start = Parse.Pos
	             ----------------------- 'Find ancestor construct or destruct'
	             {Type} a|ncestor = Base_
	             FOR x|dummy IN [0 TO 1000] :
	                 CASE a == NONE ? BREAK x ;
	                 PUSH comp.Suppress_err = TRUE :
	                	  F.Ancestor_ = a.Search_fun(F.Names[0], CASE_SEN, FALSE) 
	                	  //or TRUE ?
	                 ;
	                 CASE F.Ancestor_ != NONE ? BREAK x ;
	                 a = a.Base_ ;
	             ------------------------------ 'Skip to end of function'
	             F.Line_end = skip_to_end_of_fun(F) 
        	//; 
        	.
        */
        private void handle_constr_destr(Function f)
        {
            f.Parse = Parse;
            f.Line_start = Parse.Line;
            Parse.Wait(":");
            f.Pos_start = Parse.Pos;
            //------------------------- 'skip to end of function'
            skip_to_end_of_fun(f);
        }

        /*
        
        METHOD precompile_test :
            -------------------------------- 'Create {Fun} object'
            {Fun} t|est_function = {Fun}(Parse = Parse,
                Modifiers['STATIC'] = TRUE, Is_test = TRUE,
                Line_start = Parse.Line, Header_line = Parse.Line,
                Is_test = TRUE, A_Name_1 = "TEST "), >> Test[]
            -------------------------------- 'Names[]'
            Parse.Scan_names(t.Names[], "")
            t.A_Name_1 = t.A_Name_1 "" t.Names[0]
            check_names_uniq(t.Names[], all_field_fun[], TRUE)
            Parse.Check_reserved(t.Names[])
            -------------------------------- 'Test with parameter'
            CASE Parse.Symbol("(") ?
                 STR all_p|aram_names[]
                 FOR i|dummy IN [Parse.Pos TO Parse.Last] :
                     p|arameter = {Var}(Line = Parse.Line, Is_param = TRUE,
                        Type_n = Parse.Scan_type, In_fun_ = t), >> t.Param[]
                     Parse.Scan_names(p.Names[], "")
                     Parse.Check_names(p.Names[])
                     Parse.Check_reserved(p.Names[])
                     CASE p.Names[0].[0].Lower == p.Names[0].[0] && !Any_case ?
                          warn("It is recommended to name parameters starting "
                          "uppercased"._Witis4 ": " p.Names[0])
                     ;
                     check_names_uniq(p.Names[], all_p[], TRUE)
                     handle_array_param(p, Parse)
                     p.Set_final_name("X_" p.Names[0])
                     CASE !Parse.Symbol(",") ? BREAK i ;
                 ;
                 Parse.Wait(")") ;
            CASE t.Param[].Count > 3 ?
                 Parse.Class_.Detect_bad("More then 3 parameters") ;
            -------------------------------- 'Test return value?'
            CASE Parse.Symbol("==>") ?
                 t.Result = {Var}(Line = Parse.Line, Type_n = Parse.Scan_type,
                 Names[] << "RESULT")
                 t.Result.Set_final_name("RESULT") ;
            -------------------------------- ', OPERATORS({Class1}, ...)'
            CASE Parse.Symbol(",") ?
                 Parse.Wait("OPERATORS")
                 t.Operators_modifier ;
            -------------------------------- 'Test import'
            Parse.Wait(":")
            CASE Parse.End_of_line ? Parse.Fin ;
            --------------------------------- 'Skip the rest of function'
            t.Line_start = Parse.Line
            t.Pos_start = Parse.Pos
            t.Line_end = skip_to_end_of_fun(t) .
            
        METHOD precompile_operator :
			{Fun} f_op|erator_function = {Fun}(
				Parse = Parse,
				Modifiers['STATIC'] = TRUE,
				Modifiers['INLINE'] = TRUE, 
				Line_start = Parse.Line,
				Header_line = Parse.Line,
				Modifiers['PUBLIC'] = TRUE,
				Is_operator = TRUE,
				A_Name_1 = "OPERATOR "), OWNED BY THIS
				
			Detect({class_mod}.'OPERATORS')
			------------------------------------ '-type | type <+|-|*|/> type'
			CASE Parse.Symbol("-") ?
			     f_op.Names[] << "_Minus"
			     STR type_A|_parameter = Parse.Scan_type
			ELSE type_A = Parse.Scan_type
				 Parse.Skip_sp
				 CASE Parse.Next_char ?
				 ["+"]: f_op.Names[] << "_Plus"
				 ["-"]: f_op.Names[] << "_Minus"
				 ["*"]: f_op.Names[] << "_Multiply"
				 ["/"]: f_op.Names[] << "_Divide" ;
				 Parse.Pos += 1
				 STR type_B|_parameter = Parse.Scan_type ;
			f_op.A_Name_1 = f_op.A_Name_1 f_op.Names[0]
			
			f_op.Param[] << {Var}(In_fun_ = f_op, Line = Parse.Line,
							Type_n = type_A, Is_param = TRUE, Names[] << "A",
							Final_name= "X_A")
							
			CASE type_B != "" ?
			     f_op.Param[] << {Var}(In_fun_ = f_op, Line = Parse.Line,
				   Type_n = type_B, Is_param = TRUE, Names[] << "B",
				   Final_name= "X_B") ;
			-------------------------------------- 'check duplications'
			FOR m IN Method[] :
			    CASE ?
			    [!m.Is_operator] ? CONTINUE m
			    [m.Names[0] != f_op.Names[0]] ? CONTINUE m
			    [m.Param[0].Type_n!= f_op.Param[0].Type_n] ? CONTINUE m
			    [m.Param[].Count != f_op.Param[].Count] ? CONTINUE m
			    
			    [m.Param[].Count != 1 && (
			     m.Param[1].Type_n != f_op.Param[1].Type_n)] ? CONTINUE m
			    ;
			    DONE
				    Parse.Err("Duplicated operator"._EDupOper ", "
				    "" ("defined earalier in line"._EDefinedEarlier)
				    " " (m.Line_start + 1).Str)
				    
				    BREAK m ;
			Add_method(f_op)
			-------------------------------------- '==> type'
			CASE Parse.End_of_line ? Parse.Fin ;
			Parse.Wait("==>")
			
			f_op.Result = {Var}(
				In_fun_ = f_op,
				Type_n = Parse.Scan_type,
				Names[] << "RESULT",
				Is_param = TRUE,
				Line = Parse.Line), OWNED BY f_op
				
			f_op.Result.Set_final_name("RESULT")
			FOR dummy IN [Parse.Pos TO Parse.Last] :
			    CASE !Parse.Symbol(",") ? BREAK dummy ;
			    CASE ?
			    [Parse.Symbol("OPERATORS")] ? f_op.Operators_modifier
			    [Parse.Symbol("NEW")] ? f_op.Modifiers['NEW'] = TRUE
			    ;
			;
			-------------------------------------- ': expr .'
			Parse.Wait(":")
			CASE Parse.End_of_line ? Parse.Fin ;
			f_op.Line_start = Parse.Line
			f_op.Pos_start = Parse.Pos
			f_op.Line_end = skip_to_end_of_fun(f_op) .
			
        */
        private void precompile_test()
        {
            Function t = new Function(Parse);
            t.Parse = Parse;
            t.Line_start = Parse.Line;
            t.Modifiers[(int)Function.Fun_mod.STATIC] = true;
            t.Is_test = true;
            Test.Add(t);
            Parse.Scan_names(t.Names);
            for (int INDEX = 0; INDEX < t.Names.Count; INDEX++)
            {
                string n = t.Names[INDEX];
                if (All_id.Contains(n)) err("Duplicating name: " + n);
                All_id.Add(n);
            }
            Parse.Check_reserved(t.Names);
            //------------------------------ 'test import'
            Parse.Wait(":");
            Parse.Fin();
            if (Parse.Symbol("IMPORT"))
            {
                Parse.Wait(":");
                for (int i = Parse.Pos; i <= Parse.Last(); i++)
                {
                    string name = Parse.Class_name();
                    name = name.Substring(1, name.Length - 2);
                    name += Parse.Compiler_.Extension;
                    Type im = Parse.Compiler_.Create_class(name);
                    if (im == null) break;
                    if (Import_.IndexOf(im) >= 0 || t.Test_import_.IndexOf(im) >= 0)
                        err("Already imported: " + name);
                    t.Test_import_.Add(im);
                    if (!Parse.Symbol(",")) break;
                }
                Parse.Wait(";");
                Parse.Fin();
            }
            t.Line_start = Parse.Line;
            t.Pos_start = 0;
            skip_to_end_of_fun(t);
        }

        /*
        
        METHOD skip_to_end_of_fun|ction({Fun} F|unction) ==> INT :
                //DEBUG:
                //      CASE F.Names[0] == "data_sort_helper" ?
                //           BOOL ddebug|ging_info_details = TRUE ;
                //;
            FOR x IN [Parse.Line TO Parse.Source[].Count-1] :
                Parse.Line = x
                Parse.Skip_sp
                //DEBUG:
                //	  CASE ddebug ?
                //	       << "line" x.Str ">" Parse.Rest_of_line #NL ;
                //;
                BOOL letter|_next = Parse.Next_is_letter
                CASE letter && Parse.Ident IN ["FUN", "FUNCTION", 
                	 "METHOD", "CONSTRUCT", "DESTRUCT", 
                     "CONST", "CONSTANT", "OVERRIDE", "TABLE", "STRUCTURE",
                     "ENUM", "ENUMERATION", "END", "TODO"]
                     ?
                     //DEBUG:
                     //      CASE ddebug ?
                     //           << "another class level declaration found"#NL ;
                     //;
					 CASE F != NONE ?
						  err("Function"._Efun4 " " F.Whole_name
                          " " ("started at line"._Estarted) 
                          " " (F.Line_start+1).Str
						  " " ("was not properly finished"._Ewas3))
						  
					 ELSE err("Previous declaration was not properly "
                          "finished"._Eprev)
					 ;
                     ==> ;
                CASE Parse.Ending_with_symbol(".") ?
                     //DEBUG:
                     //      CASE ddebug ? << "dot found" #NL ;
                     //;
                    RESULT = Parse.Line
                    Parse.Pos = Parse.Last + 1 
                    Parse.Fin ==> ;
                Parse.Pos = 0
            ; .
        */
        private void skip_to_end_of_fun(Function F)
        {
            for (int xdummy = Parse.Line; xdummy <= Parse.Source.Count - 1; xdummy++)
            {
                Parse.Line = xdummy;
                if (Parse.Symbol("FUN") || Parse.Symbol("FUNCTION"))
                    err("Function " + F.Names[F.Names.Count-1] + " was not properly finished");
                if (Parse.End_of_source()) break;
                if (Parse.Ending("."))
                {
                    Parse.Pos = Parse.Last() + 1;
                    Parse.Fin();
                    return;
                }
                Parse.Pos = 0;
            }
            int was_Line = Parse.Line;
            try
            {
                Parse.Line = F.Line_start;
                err("Function " + F.Names[F.Names.Count - 1] + " is not properly ended");
            }
            finally { Parse.Line = was_Line; }
        }

        /*
        BOOL History_present
        
 		METHOD precompile_history :
			CASE !Parse.Symbol("HISTORY") ? ==> ;
			History_present = TRUE
			CASE Parse.Symbol(":") ? NONE ;
			BOOL created|_present = FALSE
			FOR i|dummy IN [Parse.Line TO Parse.Source[].Count] :
			    CASE Parse.End_of_source ? ==> ;
			    CASE Parse.End_of_line ? Parse.Fin ;
			    CASE Parse.Symbol("HISTORY") ?
			    	 Parse.Wait("ENDED")
			         Parse.Fin ==> ;
			    CASE Parse.Symbol("--") ? 
			         Parse.Pos = Parse.Last + 1
			         Parse.Fin
			         CONTINUE i ;
			    STR tag|_of_history = Parse.Ident
			    CASE tag ?
			    ["CREATED"]:
			    	CASE created ? Parse.Warn("Duplicating tag CREATED in "
			    			"HISTORY"._WDupCreated)
			    	;
			    	created = TRUE
			    	history_created_updated
			    ["UPDATED"]:
			    	history_created_updated
			    ELSE Parse.Err("Unknown HISTORY tag"._EUnknownTag ": " tag) 
			    ;
			; .
			
 		METHOD history_created_updated:
 			Parse.Wait("(")
 			INT y|ear_date = Parse.Number
 			CASE y < 2016 ?
 			     Parse.Err("Year should be >= 2016"._EYear2016 ": " y.Str) ;
 			CASE !Parse.Symbol("/") ? Parse.Wait("-") ; 
 			INT m|onth_date = Parse.Number	
 			CASE m < 1 || m > 12 ?
 			     Parse.Err("Month should be in range [1 TO 12]"._EMonth 
 			     ": " m.Str)
 			;
 			CASE !Parse.Next_symbol(")") ?
	 			 CASE !Parse.Symbol("/") ? Parse.Wait("-") ;
	 			 INT d|ay_of_date = Parse.Number
	 			 CASE d < 1 || d > 31 ?
	 			      Parse.Err("Day number should be in range [1 TO 31]"._EDay
	 			      ": " d.Str) ;
 			;
 			Parse.Wait(")")
 			----------------------------- 'author(s) of changes'
 			CASE Parse.Symbol(",") ?
 			     CASE Parse.Symbol("VERSION") || Parse.Symbol("VER") ?
 			          STR ver|sion_number = Parse.String_const(TRUE) ;
 			     CASE Parse.Symbol("BY") ?
 			     	  STR author|_of_changes = Parse.String_const(TRUE) ;
 			     CASE ver == "" && author == "" ?
 			          Parse.Err("Waiting for version and/or author "
 			          "but"._EWaitVerAuth ": " Parse.Next20) ;
 			;
 			Parse.Wait(":")
 			----------------------------- 'changes described'
 			FOR i|dummy IN [Parse.Line TO Parse.Source[].Count]:
 			    CASE Parse.End_of_line ? Parse.Fin ;
 			    CASE Parse.End_of_source ? ==> ;
 			    CASE Parse.Symbol(".") ? Parse.Fin ==> ;
 			    INT pos_w|ork = Parse.Pos     
 			    STR doing|_what = Parse.Ident
 			    CASE doing !IN ["ADDED", "FIXED", "CHANGED", "REMOVED"] ?
 			         CASE doing IN ["UPDATED", "HISTORY"] ? 
 			              Parse.Pos = pos_w ==> ;
 			              
 			         Parse.Err("Unknown work for HISTORY record"._EUnknownWork
 			         ": "  doing)
 			    ;
 			    Parse.Wait(":")
 			    CASE Parse.End_of_line ? Parse.Fin ;
 			    items_added_fixed_changed
 			; .
 			
 		METHOD items_added_fixed_changed:
		    FOR j|dummy IN [Parse.Pos TO Parse.Last+ Parse.Source[].Count] :
		         CASE Parse.End_of_line ? Parse.Fin ;
		         CASE Parse.Next_symbol(".") ? ==> ;
		         CASE Parse.Symbol(";") ? 
		              Parse.Fin ==> ;
		         CASE Parse.End_of_line ? ==> ;
		         Parse.Skip_sp
		         CASE Parse.Next_symbol(#QU) ?
		              skip_string
		         ELSE STR id|entifier_method_funtion_field = Parse.Ident
		         	  {Fun} f|unction_found = Search_fun(id, CASE_SEN, FALSE)
		         	  {Var} v|ariable = NONE
		         	  CASE f == NONE ? v = Search_field(id) ;
		         	  CASE v == NONE && f == NONE ?
		         	       Parse.Warn("Neither function nor field "
		         	       "found"._WNoFunField ": " id "(" ("if it is "
		         	       "obsolete, quote it"._WIfObsolete) ")") ;
		         ;
		         CASE !Parse.Symbol(",") ? BREAK j ;
		         CASE Parse.End_of_line ?
		              Parse.Fin ;
		    ;
		    CASE Parse.Next_symbol(".") ? ==> ;
		    Parse.Wait(";")
		    Parse.Fin .
		    
		METHOD skip_string :
			FOR k|dummy IN [Parse.Line TO Parse.Source[].Count] :
				NONE = Parse.String_const(FALSE)
				CASE !Parse.End_of_line ? ==> ;
				STR next|_line = Parse.Source[Parse.Line+1].Trim
				CASE next.[0]  != #QU ? ==> ;
				Parse.Fin ; .
 			         	  
 		
	
        BOOL corresponded
        
        METHOD Correspond|_types :
            CASE corresponded ? ==> ;
            corresponded = TRUE
        PUSH comp.Current_class = THIS :
            CASE base_line > 0 ?
                Parse.Line = base_line
                Parse.Pos = 0
                Parse.Wait("BASE")
                Parse.Wait("CLASS")
                CASE Parse.Symbol(":") ? NONE ;
                Base_ = Find_type(Parse.Scan_type) ;
            ------------------------------------ 'types of fields of structures'
            FOR struc IN Structures_[] :
                FOR v IN struc.Field[] :
                    CASE v.Type_ != NONE ? CONTINUE v ;
                    Parse.Line = v.Line
                    v.Type_ = Find_type(v.Type_n)
                    CASE v.Is_fixed && v.Size_n != "" ?
                         v.Size_type_ = Find_enum(v.Size_n, FALSE, TRUE) ;
                    CASE v.Type_indexing != "" ?
                         STR xt|ypes_indexing[]
                         Split(xt[], v.Type_indexing, ",")
                         FOR x IN xt[] :
                         	 v.Indexing_[] << Find_type(x.Trim) ;
                    ;
                ;
            ;
            -------------------------------------- 'types of fields'
            FOR v IN Field[] :
                DEBUG:
                      CASE v.Names[0]=="Syn_tacts_in_envelope" ? 
                           ------------------- 'test1'
                      ;
                ;
                CASE v.Type_ == NONE ?
	                 Parse.Line = v.Line
	                 Can_be_imported(v.Type_, v.Type_n)
	                 v.Type_ = Find_type(v.Type_n) ;
                CASE v.Is_fixed && v.Size_n != "" 
                	 && v.Size_n[0] !IN "0123456789*"
                	 ?
                     v.Size_type_ = Find_enum(v.Size_n, FALSE, TRUE) ;
                CASE v.Is_weak && v.Type_.Kind == 'STRUCTURE' ?
                     Parse.Err("Structures can not be referenced with "
                     "weak links"._EStrucRefByWeak)
                ;
                CASE v.Type_indexing != "" ?
                     Split(xt[], v.Type_indexing, ",")
                     FOR x IN xt[] :
                         v.Indexing_[] << Find_type(x.Trim) ;
                ;
                CASE v.Type_.Kind == 'STRUCTURE' && v.Is_fixed ? 
                	 PUSH Parse.Line = v.Line :
                     	  Parse.Err("Fixed arrays of structures are not "
                     	  "supported"._EFixArrOfRecNotSupported) ;
                ;
                CASE v.Initial_ != NONE 
                     && (v.Type_.Kind !IN ['INT', 'STR', 'REAL', 'ENUM']
                     || v.Is_array)
                     ? 
                     PUSH Parse.Line = v.Line :
                     	  Parse.Err("Initializing of objects or structures "
                     	  "or arrays is not supported"._EInitStructures) ;
                ;
            ;
            ------------------------------------- 'constants'
            FOR c IN Const[] :
                Parse.Line = c.Line
                CASE c.Type_ != NONE ? CONTINUE c ;
                c.Type_ = Find_type(c.Type_n)
            ;
            ------------------------------------- 'functions, methods, tests'
            FOR f IN Method[] :
                method_correspond_types(f) ;
            FOR f IN Test[] :
                method_correspond_types(f) ;
        ; .
                
		METHOD Can_be_imported(
			{Type} T|ype_found, STR N|ame_of_type)
			:
			CASE "." IN N && T !IN Specified_[] ?
                 Specified_[] << T ;
            CASE (T.Kind == 'ENUM' && T.Base_ != THIS
            	 || T.Kind == 'STRUCTURE' && T.In_class_ != THIS)
            	 && T !IN Outer_[]
            	 && T.Names[0] !IN ["{bool}", "{byte}"]
            	 ?
                 Outer_[] << T ; .

                
        METHOD method_correspond_types({Fun} F|unction) :
			CASE F.Overloaded_[].Count > 0 ? ==> ;
		PUSH comp.Current_fun = F :
            Parse.Line = F.Line_start
            FOR p IN F.Param[] :
                CASE p.Type_ != NONE ? CONTINUE p ;
                p.Type_ = Find_type(p.Type_n)
                Can_be_imported(p.Type_, p.Type_n)
                CASE p.Is_fixed && p.Size_n != "" ?
                     p.Size_type_ = Find_enum(p.Size_n, FALSE, TRUE) ;
                CASE p.Type_indexing != "" ?
                     STR xt|ypes_indexing[]
                     Split(xt[], p.Type_indexing, ",")
                     FOR x IN xt[] :
                     	 p.Indexing_[] << Find_type(x.Trim) ;
                ;
            ;
            CASE F.Stored_param.Type_indexing != "" ?
                 Split(xt[], F.Stored_param.Type_indexing, ",")
                 FOR x IN xt[] :
                 	 F.Stored_param.Indexing_[] << Find_type(x.Trim) ;
            ;
            CASE F.Result != NONE && F.Result.Type_ == NONE ?
                 F.Result.Type_ = Find_type(F.Result.Type_n)
                 Can_be_imported(F.Result.Type_, F.Result.Type_n)
            ;
		; .
		
		METHOD Use_imported|_certain_class(
		{Type} C|lass_should_be_imported)
			:
			FOR im IN Import_[] :
			    CASE im == C ?
			         CASE C !IN Used_imports_[] ?
			              Used_imports_[] << C ;
			         ==> ;
			; .
			
        */
        public void Correspond_types()
        {
            Parse.Compiler_.Current_class = this;
            if (base_line > 0)
            {
                Parse.Line = base_line;
                Parse.Pos = 0;
                Parse.Wait("BASE");
                Parse.Wait("CLASS");
                Base_ = Find_type(Parse.Scan_type());
            }
            foreach (Variable v in Field)
            {
                Parse.Line = v.Line;
                v.Type_ = Find_type(v.Type_n);
                if (v.Is_fixed && v.Size_n != "")
                    v.Size_type_ = Find_enum(v.Size_n);
            }
            foreach (Variable c in Const)
            {
                Parse.Line = c.Line;
                c.Type_ = Find_type(c.Type_n);
                if (c.Is_fixed && c.Size_n != "")
                    c.Size_type_ = Find_enum(c.Size_n);
            }
            foreach (Function f in Method)
            {
                Parse.Line = f.Line_start;
                foreach (Variable p in f.Param)
                {
                    p.Type_ = Find_type(p.Type_n);
                    if (p.Is_fixed && p.Size_n != "")
                        p.Size_type_ = Find_enum(p.Size_n);
                }
                if (f.Result != null)
                    f.Result.Type_ = Find_type(f.Result.Type_n);
            }
        }

        /*
        
        {Hash_names} hash_types
        {Hash_names} hash_Ltypes
        
        METHOD Find_type( STR T|ype_name ) ==> {Type}, RECURSIVE :
            CASE "." IN T ?
                 INT p|osition_point = T.Find(".")
                 {Type} class_w|here_search = Find_type(T.[0 TO p-1])
                 CASE class_w == NONE ?
                      err("Class is not imported"._ENotImported 
                      ": " T.[0 TO p-1])
                 ;
                 RESULT = class_w.Find_type(T.[p+1 TO *])
                 CASE RESULT == NONE ?
                      err(T.[p+1 TO *] 
                      " - " ("type is not defined in the class"._EUndefinedType)
                      ": " class_w.Names[0])
                 ;
                 Can_be_imported(RESULT, T) ==> ;               
                 
            CASE T.[0] == "{" ?
            
                 CASE ?
                 [T IN ["{Object}", "{}"]] ?
                    RESULT = comp.TYPE_OBJ ==>
                 [T.[1].Lower == T.[1]] ?
                    RESULT = Find_enum(T, TRUE, !Parse.Case_insensitive)
                    CASE RESULT != NONE ? ==> ; 
                 [T IN Names[]] ?
                    RESULT = THIS  ==> 
                 [(Parse.Compiler.Current_class.Any_case || Any_case) 
                  && name_in_nocase(T, Names[])] ?
                    RESULT = THIS ==> 
                 ELSE NONE ;
                 
                 CASE hash_types == NONE ?
                      hash_types = {Hash_names}
                      hash_Ltypes = {Hash_names} ;
                 RESULT = hash_types.Search(T).{Type}
                 CASE RESULT == NONE ?
                      RESULT = hash_Ltypes.Search(T.Lower).{Type} ;
                 CASE RESULT != NONE ? ==> ;
                    
                 FOR n_im INDEXING {Type} IN [
                 	 0 TO Import_[].Count + Test_import_[].Count - 1] 
                 	 :
                     CASE ?
                     [n_im < Import_[].Count] ?
                          {Type} im|port_at_n = Import_[n_im]
                     [!comp.Current_fun.Is_test] ? BREAK n_im
                     ELSE im = Test_import_[n_im - Import_[].Count]
                     ;
					 CASE T !IN im.Names[] 
					 	  && !((im.Any_case || Any_case) 
					 	  && name_in_nocase(T, im.Names[]))
					 	  ?
					      CONTINUE n_im ;
					 DONE
	                      CASE im !IN Used_imports_[] ?
	                           Used_imports_[] << im ;
	                      RESULT = im
	                      
	                      CASE im.Any_case ?
	                           im.Provide_names_lowered
	                           hash_Ltypes.Add(im.Names_low[], im)
	                      ELSE hash_types.Add(im.Names[], im) ;
	                      
	                      ==> ;
                     
		         CASE ?
		         [Any_case] ?
		         	  Provide_names_lowered
		         	  CASE T.Lower IN Names_low[] ? RESULT = THIS ==> ;
		         [T IN Names[]] ? RESULT = THIS ==> ;
		          
                 CASE !comp.TEST_value ?
                      err("Unknown type"._Eunk4 ": " T maybe_debug(T)) ==> ;
            ;
            CASE T ?
                 ["BOOL", "BOOLEAN"]: RESULT = comp.TYPE_BOOL
                 ["BYTE"]           : RESULT = comp.TYPE_BYTE
                                      //Detect('BYTES')
                 ["INT", "INTEGER"] : RESULT = comp.TYPE_INT
                 ["REAL"]           : RESULT = comp.TYPE_REAL
                 ["STR", "STRING"]  : RESULT = comp.TYPE_STR
            ELSE err("Unknown type"._Eunk5 ": " T) ; .
            
        METHOD maybe_debug(STR T|ype_name) ==> STR :
            FOR im IN Debug_import_[] :
                CASE T IN im.Names[] ? 
                     RESULT = " (though it is listed in the debug import)" ==> ;
            ; .
            
        FUN name_in_nocase(
        STR Name|_checking, STR A|rray_checking_in[]) ==> BOOL
        	:
        	STR n|ame_lowered = Name.Lower
        	FOR a IN A[] :
        		RESULT ||= n == a.Lower ; .

        */
        static int CNT_Find_type;
        
        public Type Find_type(string T)
        {
            if (++CNT_Find_type == 1943)
            { }

            if (T.Contains('.'))
            {
                int i = T.IndexOf('.');
                string class_n = T.Substring(0, i);
                string rec_n = T.Substring(i + 1);
                Type class_t = Find_type(class_n);
                if (class_t == null)
                {
                    err("Unknown class: " + class_t);
                    return null;
                }
                return class_t.Find_type(rec_n);
            }

            if ((T + " ")[0] == obr)
            {
                if ((T[1] + "").ToLower() == T[1] + "")
                    return Find_enum(T);
                if (Names.Contains(T))
                    return this;
                if (T == "" + obr + "Object" + cbr)
                    return Parse.Compiler_.TYPE_OBJ;
                foreach (Type im in Import_)
                {
                    if (im.Names.Contains(T))
                        return im;
                }
                if (!Parse.Compiler_.Test())
                {
                    err("Unknown type: " + T);
                    return null;
                }
            }
            switch ((T + " ")[0])
            {
                case 'B':
                    if (T == "BOOL" || T == "BOOLEAN")
                        return comp().TYPE_BOOL;
                    break;
                case 'I':
                    if (T == "INT" || T == "INTEGER")
                        return comp().TYPE_INT;
                    break;
                case 'R':
                    if (T == "REAL")
                        return comp().TYPE_REAL;
                    break;
                case 'S':
                    if (T == "STR" || T == "STRING")
                        return comp().TYPE_STR;
                    break;
            }
            err("Unknown type: " + T);
            return null;
        }


        /*
        
        {Hash_names} hash_enums|_and_structs
        
        METHOD Find_enum(
        	STR T|ype_name, BOOL Structures|_allowed, 
        	BOOL Error|_if_not_found) ==> {Type}
        	:
        	CASE hash_enums == NONE ? hash_enums = {Hash_names} ;
            RESULT = find_enum_or_struct(T, Structures, Error)
            CASE RESULT != NONE && RESULT !IN Used_imports_[] ?
                 Used_imports_[] << RESULT ;
            CASE RESULT.Modifiers['ABANDONED'] && (
            	 !comp.Current_fun.Modifiers['NATIVE_FUN'])
            	 ?
                 Parse.Err("Type"._Etype " " T 
                 " " ("is abandoned, use instead"._Eis4) ": " RESULT.Deprecate)
            ;
            CASE RESULT.Modifiers['DEPRECATED'] && (
            	 !comp.Current_fun.Modifiers['NATIVE_FUN'])
            	 ?
                 Parse.Warn("Type"._Wtype " " T 
                 " " ("is deprecated, use instead"._Wis) ": "
                 "" RESULT.Deprecate) ; .
        
        METHOD find_enum_or_struct|ure(
        STR T|ype_name,
        BOOL Structures|_allowed,
        BOOL Error|_if_not_found) ==> {Type}, RECURSIVE
            :
	        RESULT = hash_enums.Search(T).{Type}
	        CASE RESULT != NONE ?
	             CASE Structures && RESULT.Kind == 'STRUCTURE'
	             	  || !Structures && RESULT.Kind == 'ENUM'
	             	  ?
	                  ==> ;
	        ;
            ------------------------------------ 'Enums of type itself'
            FOR en IN Enums_[] :
                CASE T IN en.Names[] ?
                     RESULT = en 
                     hash_enums.Add(en.Names[], en)
                     ==> ;
            ;
            ------------------------------------ 'Structures of type itself'
            CASE Structures ?
                 FOR struc IN Structures_[] :
                     CASE T IN struc.Names[] ?
                          RESULT = struc
                          BREAK struc ;
                 ;
                 CASE RESULT != NONE ?
                      hash_enums.Add(RESULT.Names[], RESULT)
                      ==> ;
            ;
            CASE comp.Current_class != THIS ? ==> ;
            ------------------------------------- 'Search in imported classes'
            FOR n_im INDEXING {Type} IN [
            	0 TO Import_[].Count + Test_import_[].Count - 1]
            	:
                CASE ?
                [n_im < Import_[].Count] ? {Type} im|port_at_n = Import_[n_im]
                [!comp.Current_fun.Is_test] ? BREAK n_im
                ELSE im = Test_import_[n_im - Import_[].Count]
                ;
                CASE im.Precompile ? 
                     Parse.Err("Cyclic reference of types."._ECyclicRef) ;
                RESULT = im.find_enum_or_struct(T, Structures, FALSE)
                CASE RESULT != NONE ?
                     CASE im !IN Used_imports_[] ?
                          Used_imports_[] << im ;
                     ==> ;
            ;
            -------------------------------------- 'Not found'
            CASE !Error ? ==> ;
                 
            err("Type"._Etype2 " " T " " ("was not found"._Ewas4)
            	" in class " Whole_name) .
        */
        public Type Find_enum(string T)
        {
            foreach (Type en in Enums_)
            {
                if (en.Names.Contains(T)) return en;
            }
            if (Parse.Compiler_.Current_class != this) return null;
            foreach (Type im in Import_)
            {
                Type Result = im.Find_enum(T);
                if (Result != null) return Result;
            }
            if (Parse.Compiler_.Test())
            {
                foreach (Type im in Parse.Compiler_.Current_fun.Test_import_)
                {
                    Type Result = im.Find_enum(T);
                    if (Result != null) return Result;
                }
            }
            err("Type " + T + " was not found");
            return null;
        }

        /*
        
        METHOD Find_enum_item(STR N|ame_of_item) ==> {Var} :
            RESULT = Search_enum_item(N)
            CASE RESULT == NONE ?
                err("Item"._Eitem " " N 
                " " ("was not found in enumeration"._Ewas5) " " Names[*]) ; .
        */
        public Variable Find_enum_item(string N)
        {
            Variable Result = Search_enum_item(N);
            if (Result == null)
                err("Item " + N + " was not found in enumeration " + Names[Names.Count - 1]);
            return Result;
        }

        /*
        
        METHOD Search_enum_item( STR N|ame_of_item ) ==> {Var} :
            CASE Kind !IN ['ENUM', 'BOOL'] ?
                err("Type"._Etype3 " " Names[*] 
                " " ("is not a enumeration so it can not contain"._Eis5) " " N)
            ;
            CASE Parse.Compiler.Current_class.Any_case ?
                 STR n|ame_lowered = N.Lower
                 FOR it IN Items[] :
                 	 it.Provide_names_lowered
                 	 CASE n IN it.Names_low[] ?
                 	      RESULT = it ==> ;
                 ;
                 ==>
            ;
                     
            FOR it IN Items[] :
                CASE N IN it.Names[] ? RESULT = it ==> ;
            ; .
			
		METHOD Find_table(
			STR Name|_table ) ==> {Table}, RECURSIVE
			:
			{Type} cc|lass_current = Parse.Compiler.Current_class 
			FOR t IN Table[] :
				CASE Name IN t.Names[] ?
					 CASE THIS !IN cc.Used_imports_[] ?
					      cc.Used_imports_[] << THIS ;
					 RESULT = t ==> ;
			;
			CASE THIS != comp.Current_class ? ==> ;
			     
            FOR n_im INDEXING {Type} IN [
            	0 TO Import_[].Count + Test_import_[].Count - 1] 
            	:
                CASE ?
                [n_im < Import_[].Count] ? {Type} im|port_at_n = Import_[n_im]
                [!comp.Current_fun.Is_test] ? BREAK n_im
                ELSE im = Test_import_[n_im - Import_[].Count]
                ;
				RESULT = im.Find_table(Name)
				CASE RESULT != NONE ? ==> ;
			;
			Parse.Err("Table"._Etable " " Name " " ("is not defined"._Eis6)) .
			
			
        */
        public Variable Search_enum_item(string N)
        {
            if (Kind != Kind_type.ENUM)
                err("Type " + Names[Names.Count - 1] + " is not a enumeration " +
                    "so it can not contain " + N);
            foreach (Variable it in Items)
            {
                if (it.Names.Contains(N)) return it;
            }
            return null;
        }

        /*
        
        METHOD Find_fun|ction(
        	STR N|ame_of_function,
        	BOOL Usage_inc|rement_if_found ) ==> {Fun}
        	:
			INT flags|_to_search = IMPORTED_CL
			CASE !Any_case ? flags |= CASE_SEN ; 
            RESULT = Search_fun(N, flags, Usage_inc)
            CASE RESULT != NONE ? ==> ;
            CASE comp.Verbose ?
                 {Fun} f|unction_not_case_sensitive = Search_fun(
                       N, IMPORTED_CL, Usage_inc)
                       
                 CASE f != NONE ?
                      STR er|ror_message =  "Function"._Efun5 " " N 
                      " " ("was not found, may be you mean"._Ewas6) " "
                      "" f.Class.Whole_name 
                      er = er "." f.Whole_name "?"
                           
                      err(er) ==> ;
            ;
            STR sim|ilar_fun[]
            Find_similar(N, sim[], TRUE)
            CASE sim[].Count > 0 ? 
                 FOR s IN sim[] :
                     STR list_sim|ilar = list_sim "," s ;
                     
                 err("Function was not found"._EFunNotFound ": " N
                 ". " ("May be you mean one of"._EMayBeYouMean) 
                 " (" list_sim.[1 TO *] ") ?") 
            ELSE
	             err("Function"._Efun6 " " N " " ("was not found"._Ewas7)
	            	 ": " Parse.Next20)
            ; .
        */
        public Function Find_fun(string N)
        {
            Function Result = Search_fun(N, false);
            if (Result == null)
                err("Function " + N + " was not found");
            return Result;
        }
        /*
        
        METHOD Find_fun_of_val(STR N|ame_of_function) ==> {Fun} :
            RESULT = Find_fun(N, TRUE)
            CASE !RESULT.Modifiers['STATIC'] ?
                err("Function"._Efun7 " " N 
                " " ("is not a static function, so it can not be called for "
                "such prefix"._Eis7)
                ": " Parse.Next20) ; .
        */
        public Function Find_fun_of_val(string N)
        {
            Function Result = Find_fun(N);
            if (Result != null && (!Result.Modifiers[(int)Function.Fun_mod.STATIC] || Result.Param.Count != 1))
                err("Function " + N + " is not a static single parameter function, " +
                    "so it can not be called using prefix style");
            return Result;
        }

        /*
        
        -------------------------------- 'search flags:'
        
 		CONST INT : 
			ONLY_ST|ATIC = 1
			ONLY_METHODS = 2
			CASE_SEN|SITIVE = 4
			IMPORTED_CL|ASSES = 8 .
	
		BOOL Disable_collecting_call|_from
		
        METHOD Search_fun|ction(
            STR N|ame_of_function,
            INT Flags|_searching,
            BOOL Usage_inc|rement_if_found) ==> {Fun}, RECURSIVE
            :
			{Type} cc|lass_compiling = comp.Current_class
            CASE cc == NONE ? cc = THIS ;
            ------------------------------------------ 'search the first found'
            RESULT = do_search_fun(N, Flags, Usage_inc)
            CASE RESULT.Redirect_ != NONE ?
                 RESULT = RESULT.Redirect_ ;
            CASE RESULT != NONE && Usage_inc && (
                 RESULT !IN comp.Current_fun.Call_functions_[])
                 ?
                 CASE !Disable_collecting_call
                      && !comp.Current_fun.Dummy_compile
                      ?
                 	  comp.Current_fun.Call_functions_[] << RESULT
                 	  CASE comp.Current_fun != NONE
                 	  	   && comp.Current_fun.Class != NONE
                 	  	   ?
                 	       STR reff|unction = comp.Current_fun.Class.Whole_name
	                 	       "." comp.Current_fun.Names[0]
	                 	       
	                 	   comp.Current_fun.Call_from[] << reff
                 	  ;
                 ;
                 CASE Usage_inc && !comp.Current_fun.Is_test 
                 	  && !comp.Current_fun.Dummy_compile
                 	  ?
                      //DEBUG:
                      //      CASE RESULT.Total_fn == 12065 ?
                      //           << "+++++++++++++++++++++++++++++"
                      //           "  Usage_count++ for " RESULT.Names[0]
                      //           " because: Search_fun in context of "
                      //           "" Names[].Whole_name #NL
                      //      ;
                      //;
                      CASE cc != RESULT.Class
                      	   && RESULT.Class !IN cc.Used_imports_[]
                      	   ?
                      	   cc.Used_imports_[] << RESULT.Class ;
                 	  RESULT.Usage_count += 1
                 ;
            ;
            CASE RESULT.Modifiers['STATIC'] && (
                 comp.Current_class == THIS)
                 ?
                 ----------------- 'if STATIC and Public, search for alternate'
                 FOR n_im INDEXING {Type} IN [
                 	 0 TO Import_[].Count + Test_import_[].Count - 1]
                 	 :
                     CASE ?
                     [n_im < Import_[].Count] ?
                          {Type} im|port_at_n = Import_[n_im]
                     [!comp.Current_fun.Is_test] ? BREAK n_im
                     ELSE im = Test_import_[n_im - Import_[].Count]
                     ;
                     CASE im == RESULT.Class ? CONTINUE n_im ;
                     INT fl|ags_pass = ONLY_ST | Flags & CASE_SEN
                     
                     {Fun} alt|ernative_function = NONE
                     CASE Flags & IMPORTED_CL != 0 ?
                          alt = im.Search_fun(N, fl, Usage_inc)
                          CASE !alt.Modifiers['STATIC'] ? alt = NONE ;
                          //DEBUG:
                          // CASE !alt.Modifiers['STATIC'] 
                          //      && Flags & ONLY_ST != 0
                          //      ?
                          //      << "searched only static, found not static "
                          //      "method!!!!!!!!" >> ;
                          //;
                     ;
                     		
                     CASE alt == RESULT || alt == NONE || !alt.Is_public?
                          CONTINUE n_im ;
                          
                     CASE !comp.Suppress_err ?
                          STR er|rpr_message = "Function"._Efun8 " " N
	                      " " ("is defined in several available "
	                      "classes (e.g., in"._Eis8)
	                      
	                      er = er " " RESULT.Class.Whole_name 
	                      
	                      er = er " " ("and in"._Eand) " " im.Whole_name
	                      "), " ("so it is necessary "
	                      "to specify the class in form {Name}.f()"._Eso)
	                      -------------
	                      Parse.Err(er) ==>
                     ;
                 ;
            ;
            CASE RESULT == NONE ? ==> ;
            CASE !RESULT.Is_system && !cc.Is_descend(RESULT.Class, comp) 
            	 && !cc.Importing(RESULT.Class)
            	 && !comp.Suppress_err
                 ?
                 {Type} base|_class = RESULT.Class
                 FOR b|dummy IN [1 TO 1_000] :
                     base = base.Base_
                     CASE base==NONE ? BREAK b ;
                     
                     {Fun} bf|unction_in_base_class = base.Search_fun(
                     	N, Flags | ONLY_METHODS, TRUE)
                     
                     CASE bf != NONE ?
                          RESULT = bf ==> ;
                 ;
                 er = "Function is from class"._EFun_from_class
                 " " RESULT.Class.Whole_name 
                 " " ("which is not imported"._Which_not_imported)
                 
                 er = er ": " RESULT.Whole_name
                 er = er " cc=" cc.Final_name
                 Parse.Err(er)
            ; .
            
        METHOD Search_fun_by_param(
             STR N|ame_of_function, {Type} Param_1|st_type) ==> {Fun}
            :
			{Type} cc|lass_compiling = comp.Current_class
            CASE cc == NONE ? cc = THIS ;
            ------------------------------------------ 'search the first found'
            RESULT = do_search_fun_by_param(N, Param_1, TRUE)
            CASE RESULT.Redirect_ != NONE ?
                 RESULT = RESULT.Redirect_ ;
            CASE RESULT != NONE && (
                 RESULT !IN comp.Current_fun.Call_functions_[])
                 ?
                 CASE !Disable_collecting_call
                      && !comp.Current_fun.Dummy_compile
                      ?
                 	  comp.Current_fun.Call_functions_[] << RESULT
                 	  CASE comp.Current_fun != NONE
                 	  	   && comp.Current_fun.Class != NONE
                 	  	   ?
                 	       STR reff|unction = comp.Current_fun.Class.Whole_name
                 	       	"." comp.Current_fun.Names[0]
                 	       	
	                 	   comp.Current_fun.Call_from[] << reff
                 	  ;
                 ;
                 CASE !comp.Current_fun.Is_test 
                 	  && !comp.Current_fun.Dummy_compile
                 	  ?
                      //DEBUG:
                      //      CASE RESULT.Total_fn == 12065 ?
                      //           << "+++++++++++++++++++++++++++++"
                      //           "  Usage_count++ for " RESULT.Names[0]
                      //           " because: Search_fun in context of "
                      //           "" Names[].Whole_name #NL
                      //      ;
                      //;
                      CASE cc != RESULT.Class
                      	   && RESULT.Class !IN cc.Used_imports_[]
                      	   ?
                      	   cc.Used_imports_[] << RESULT.Class ;
                 	  RESULT.Usage_count += 1
                 ;
            ;
            CASE !RESULT.Is_system && !cc.Is_descend(RESULT.Class, comp) 
            	 && !cc.Importing(RESULT.Class)
            	 && !comp.Suppress_err 
                 ?
                 STR er|ror_message = "Function is from class"._EFun1_from_class
                 " " RESULT.Class.Whole_name 
                 " " ("which is not imported"._Which_not_imported1)
                 
                 er = er ": " RESULT.Whole_name
                 er = er " cc=" cc.Final_name
                 Parse.Err(er)
            ; .
            
       	METHOD Importing|_class({Type} C|lass_checking) ==> BOOL :
			FOR im IN Import_[] :
			    CASE im == C ? RESULT = TRUE ==> ;
			;
			CASE comp.Current_fun.Compiling_debug ?
				 FOR im IN Debug_import_[] :
				     CASE im == C ? RESULT = TRUE ==> ;
				 ;
			;
			CASE comp.TEST_value ?
			     FOR im IN Test_import_[] :
				     CASE im == C ? RESULT = TRUE ==> ;
				 ;
			; .


METHOD find_first_method_starting|_from_letter(
STR L|etter_1st_should_be, BOOL F1st|_only) ==> INT
    :
    INT p|_at_left_side INDEXING {Fun} = 0
    INT q|_at_right_side INDEXING {Fun} = Sorted_method[].Count-1
    STR f|irst_letter_of_method_name = Sorted_method[q].Names_low[0].[0]
    CASE ?
    [f < L] ? RESULT = q + 1 ==> 
    [f==L && !F1st] ? RESULT = q + 1 ==> ;
    f = Sorted_method[p].Names_low[0].[0]
    CASE ?
    [f > L] ? ==> 
    [f==L && !F1st] ? ==> 
    [f < L] ? p += 1 ;
    FOR i|dummy IN [0 TO Sorted_method[].Count] :
        RESULT = (p + q)/2
        INT iR INDEXING {Fun} = RESULT
        f = Sorted_method[iR].Names_low[0].[0] 
        CASE ?
        [f < L] ? p = RESULT
        [f > L] ? q = RESULT
        ELSE 
        	CASE !F1st ? ==> ;
        	FOR j INDEXING {Fun} IN [RESULT-1 DOWNTO 0] :
        	    f = Sorted_method[j].Names_low[0].[0]
        	    CASE f != L ? RESULT = j+1 ==> ;
        	;
        	RESULT = 0 ==>
        ;
        CASE q - p <= 1 ?
             f = Sorted_method[p].Names_low[0].[0]
             CASE f < L ? p += 1 ;
             BREAK i ;
    ;
    RESULT = p .


        METHOD do_search_fun|ction(
            STR N|ame_of_function,
            INT Flags|_searching,
            BOOL Usage_inc|rement_if_found) ==> {Fun}, RECURSIVE
            :
            //DEBUG:
            //      CASE Method[].Count == 0 && !Is_precompiled ?
            //           << "type " Names[0] " is not precompiled!!!" #NL ;
            //;
            {Type} cc|lass_current = comp.Current_class
            BOOL only_static = Flags & ONLY_ST != 0
            BOOL only_methods = Flags & ONLY_METHODS != 0  
            //STR n|ame_lowered = N.Lower
            ------------------- 'faster search using hash12'
            //CASE Flags & CASE_SEN != 0 ?
            //     //provide_hash_table_functions
            //     CASE hash_static_fun == NONE ?
            //          hash_static_fun = {Hash_names}
            //          hash_methods = {Hash_names} ;
            //     CASE ?
            //     [only_static] ?
            //         RESULT = hash_static_fun.Search(N).{Fun}
            //     [only_methods] ?
            //         RESULT = hash_methods.Search(N).{Fun}
            //     ELSE
            //         RESULT = hash_static_fun.Search(N).{Fun}
            //         CASE RESULT == NONE ?
            //              RESULT = hash_methods.Search(N).{Fun} ;
            //     ;
            //     CASE RESULT != NONE ? ==> ;
            //ELSE 
            //     CASE hash_Lfun == NONE ?
            //          hash_Lfun = {Hash_names}
            //          hash_Lmethods = {Hash_names} ;
            //     CASE ?
            //     [only_static] ?
            //         RESULT = hash_Lfun.Search(n).{Fun}
            //     [only_methods] ?
            //         RESULT = hash_Lmethods.Search(n).{Fun}
            //     ELSE
            //         RESULT = hash_Lfun.Search(n).{Fun}
            //         CASE RESULT == NONE ?
            //              RESULT = hash_Lmethods.Search(n).{Fun} ;
            //     ;
            //     CASE RESULT != NONE ? ==> ;
            //;
            --------------------------------------- 'Search in methods of class'
            STR low_n0|_lowered_name_searching = N.[0].Lower
            INT start_from = 0
            CASE Method[].Count > 20 ? 
                 start_from = find_first_method_starting(low_n0, TRUE) ;
            FOR idx_f IN [start_from TO Sorted_method[].Count-1] :
                {Fun} f|unction_from_Sorted = Sorted_method[idx_f]
                CASE ?
                [f.Names_low[0].[0] < low_n0] ? CONTINUE idx_f 
                [f.Names_low[0].[0] > low_n0] ? BREAK idx_f ;
                CASE f.Modifiers['STATIC'] ?
                	 CASE only_methods ? CONTINUE idx_f ;
                ELSE
                	 CASE only_static ? CONTINUE idx_f ;
                ;
                CASE (Flags & CASE_SEN != 0) ?
                     FOR i IN [0 TO f.Names[].Count-1] :
                         CASE N != f.Names[i] ? CONTINUE i ;
                         DONE 
                    		  RESULT = f ==> ;
                	 CONTINUE idx_f
                ELSE
	                 STR n|ame_lowered = N.Lower
	                 FOR i IN [0 TO f.Names_low[].Count-1] :
	                     CASE n != f.Names_low[i] ? CONTINUE i ;
	                     DONE     
	                          RESULT = f ==> ;
                ;
            ;
            ------------------------------- 'search in tests'
            CASE comp.Current_fun.Is_test ?
                 FOR tf IN Test[] :
                     FOR i IN [0 TO tf.Names[].Count-1] :
                         CASE N == tf.Names[i] ? 
                         	  RESULT = tf ==> ;
                     ;
                 ;
            ;
            --------------------------------------- 'Search in base classes'
            CASE Base_ != NONE ?
                 INT fl|ags_pass = Flags & ONLY_ST | Flags & CASE_SEN
                 RESULT = Base_.Search_fun(N, fl, Usage_inc)
                 CASE RESULT != NONE ? ==> ;
            ;
            CASE Base_ != NONE && (
                 comp.Current_fun.Is_test) && (cc == THIS) 
                 ?
                 fl = Flags & ONLY_ST | Flags & CASE_SEN | Flags & IMPORTED_CL 
                 RESULT = Base_.Search_fun(N, fl, Usage_inc)
                 CASE RESULT != NONE ? ==> ;
            ;
            --------------------------------------- 'Search in imported classes'
            BOOL allow|_import = Flags & IMPORTED_CL != 0
            CASE !allow ? ==> ;
                 
            FOR n_im INDEXING {Type} IN [
            	0 TO Import_[].Count + Test_import_[].Count - 1]
            	:
                CASE ?
                [n_im < Import_[].Count] ? {Type} im|port_at_n = Import_[n_im]
                [!comp.Current_fun.Is_test] ? BREAK n_im
                ELSE im = Test_import_[n_im - Import_[].Count]
                ;
                fl = ONLY_ST | Flags & CASE_SEN
                RESULT = im.Search_fun(N, fl, Usage_inc)
                CASE RESULT != NONE ?
                     CASE !RESULT.Is_public && (RESULT.Class != cc) && (
                     	  cc.Names[0] !IN RESULT.Class.Friends[])
                     	  ?
                          STR e|rror_message = "Function"._Efun9 " " 
                          "" RESULT.Whole_name "" ("(found in class"._Efound)
                           
                          e = e " " RESULT.Class.Whole_name
                          ") " ("is not PUBLIC"._Eisnot10) ", current "
                               
                          e = e "class is " comp.Current_class.Whole_name
                          
                          Parse.Err(e)
                     ;
                     CASE im !IN Used_imports_[] ?
                          Used_imports_[] << im ;
                     ==> ;
            ;
            CASE Flags & CASE_SEN != 0 || !comp.Current_fun.Is_test ? ==> ;
            FOR tf IN Test[] :
                FOR i IN [0 TO tf.Names[].Count-1] :
                    CASE N.Lower == tf.Names[i].Lower ?
                         RESULT = tf ==> ;
                ;
            ; .
            
        METHOD do_search_fun_by_param(
            STR N|ame_of_function,
            {Type} Param_1|st_type,
            BOOL Allow_import) ==> {Fun}, RECURSIVE
            :
            //DEBUG:
            //      CASE Method[].Count == 0 && !Is_precompiled ?
            //           << "type " Names[0] " is not precompiled!!!" #NL ;
            //;
            {Type} cc|lass_current = comp.Current_class
            --------------------------------------- 'Search in methods of class'
            FOR f IN Method[] :
                CASE !f.Modifiers['STATIC'] || f.Param[0].Type_ != Param_1 
                	 || !Allow_import && !f.Modifiers['PUBLIC']
                	 ?
					 CONTINUE f ;
                FOR i IN [0 TO f.Names[].Count-1] :
                    CASE N != f.Names[i] ? CONTINUE i ;
                    DONE 
                         //CASE f.Modifiers['STATIC'] ?    
                         //     hash_static_fun.Add(f.Names[], f)
                         //ELSE hash_methods.Add(f.Names[], f) ;
                		 RESULT = f ==> ;
            ;
            --------------------------------------- 'Search in base classes'
            CASE Base_ != NONE ?
                 RESULT = Base_.do_search_fun_by_param(N, Param_1, FALSE)
                 CASE RESULT != NONE ? ==> ;
            ;
            --------------------------------------- 'Search in imported classes'
            CASE !Allow_import? ==> ;
                 
            FOR n_im INDEXING {Type} IN [
            	0 TO Import_[].Count + Test_import_[].Count - 1]
            	:
                CASE ?
                [n_im < Import_[].Count] ? {Type} im|port_at_n = Import_[n_im]
                [!comp.Current_fun.Is_test] ? BREAK n_im
                ELSE im = Test_import_[n_im - Import_[].Count]
                ;
                RESULT = im.do_search_fun_by_param(N, Param_1, FALSE)
                CASE RESULT != NONE ?
                     CASE !RESULT.Is_public && (RESULT.Class != cc) && (
                     	  cc.Names[0] !IN RESULT.Class.Friends[])
                     	  ?
                          STR e|rror_message = "Function"._Efun91 " " 
                          "" RESULT.Whole_name "" ("(found in class"._Efound1)
                          
                          e = e " " RESULT.Class.Whole_name
                          ") " ("is not PUBLIC"._E_isnot10) ", current "
                               
                          e = e "class is " comp.Current_class.Whole_name
                          
                          Parse.Err(e)
                     ;
                     CASE im !IN Used_imports_[] ?
                          Used_imports_[] << im ;
                     ==> ;
            ; .
            
        METHOD Search_test|_function(
        STR N|ame_of_function) ==> {Fun}
        	:
            FOR f IN Test[] :
                CASE N IN f.Names[] ?
                    RESULT = f ==> ;
            ; .       
            
            
        METHOD Search_operator(
        {Expr}.{bin} Op|eration,
        {Expr} A|_operand,
        {Expr} B|_operand) ==> {Fun}
        	:
			FOR f IN Method[] :
			    CASE !f.Is_operator ? CONTINUE f ;
			    CASE ?
			    [Op == 'PLUS']? STR w|ait_name = "_Plus"
			    [Op == 'MINUS']? w = "_Minus"
			    [Op == 'MULT']? w = "_Multiply"
			    [Op == 'DIV']? w = "_Divide" ;
			    CASE f.Names[0] != w ? CONTINUE f ;
			    ----------------------------------- 'check parameter 1'
			    {Expr} p1|_temp_expr = {Expr}(
			    		Operation = 'VAR', Var_arg = f.Param[0])
			    		
			    BOOL a_compat|ible = comp.Current_fun.Check_compat(p1, A)
			    {Type} a_type|_expression = A.Type_expr
			    BOOL a_array|_is = A.Is_array
			    	 
			    CASE ?
			    [!a_compat && a_type.Kind == 'INT' && !p1.Is_array && !a_array] ?
			         a_compat = comp.Current_fun.Check_types_compat(
			    	 p1.Var_arg.Type_, comp.TYPE_REAL)
			    	 
			    [!a_compat && p1.Var_arg.Type_.Kind == 'INT'] ?
			         a_compat = !p1.Is_array && !a_array
			         
			         a_compat &&= comp.Current_fun.Check_types_compat(
			    	 	comp.TYPE_REAL, A.Type_expr)
			    ;
			    CASE ?
			    [!a_compat] ? CONTINUE f
			    [B == NONE && f.Param[].Count == 2] ? CONTINUE f
			    [B != NONE && f.Param[].Count == 1] ? CONTINUE f ;
			    ---------------------------------- 'check parameter 2'
			    {Expr} p2|_temp_expr = {Expr}(
			    		Operation = 'VAR', Var_arg = f.Param[1])
			    		
			    BOOL b_compat|ible = comp.Current_fun.Check_compat(p2, B)
			    {Type} b_type|_expression = B.Type_expr
			    BOOL b_array|_is = B.Is_array
			    	 
			    CASE ?
			    [!b_compat && b_type.Kind == 'INT' && !p2.Is_array
			     && !b_array] ?
			         b_compat = comp.Current_fun.Check_types_compat(
			    	 	p2.Type_expr, comp.TYPE_REAL)
			    	 
			    [!b_compat && p2.Type_expr.Kind == 'INT'] ?
			     	 b_compat = !p2.Is_array && !b_array
			     	 
			         b_compat &&= comp.Current_fun.Check_types_compat(
			    	 	comp.TYPE_REAL, B.Type_expr)
			    ;
			    CASE !b_compat ? CONTINUE f ;
			    DONE     
				     ---------------- 'operator found'
				     RESULT = f ==> ; .
        */
        public Function Search_fun(string N, bool Only_static)
        {
            foreach (Function f in Method)
            {
                if (Only_static && !f.Modifiers[(int)Function.Fun_mod.STATIC])
                    continue;
                if (f.Names.Contains(N))
                    return f;
            }
            if (!Only_static && Base_ != null && ((N[0] + "").ToUpper() == (N[0] + "") ||
                Parse.Compiler_.Current_class == this))
            {
                Function R = Base_.Search_fun(N, Only_static);
                if (R != null) return R;
            }
            bool allow_import = Parse != null && Parse.Compiler_.Current_class == this;
            if (!allow_import) return null;
            foreach (Type im in Import_)
            {
                Function Result = im.Search_fun(N, true);
                if (Result != null) return Result;
            }
            if (!Parse.Compiler_.Test()) return null;
            foreach (Type im in Parse.Compiler_.Current_fun.Test_import_)
            {
                Function Result = im.Search_fun(N, true);
                if (Result != null) return Result;
            }
            return null;
        }

        /*
        
        METHOD Find_field( STR N|ame_of_field ) ==> {Var} :
            RESULT = Search_field(N)
            CASE RESULT == NONE ?
                 CASE Kind == 'CLASS' ?
                      STR alt|ernative_find = N
                      CASE N.[*] == "_" ? alt = N.[0 TO *-1]
                      ELSE alt = alt "_" ;
                      {Var} poss|ible_you_mean = Search_field(alt) ;
                 CASE poss != NONE ?
                 	  STR sim|ilar_fields[]
                 	  Find_similar_fields(N, sim[])
                 	  CASE sim[].Count > 0 ?
                 	       FOR s IN sim[] :
                 	           STR list_sim|ilar = list_sim "," s ;

                 	       err(N (
                 	       " -- Field did not found in class"._EFieldNotFound)
                 	       " " Whole_name ", "
                 	       "" ("May be you mean one of"._EOneOf) 
                 	       " (" list_sim.[1 TO *] ") ?") 
                 	  ELSE
	                       STR er|ror_message = "Field"._Efield " " N 
	                       	   " " ("is not found in class"._Eisnot ) 
	                       	   " " Whole_name
	                       	   
	                       er = er ", " ("may be you mean"._Emaybe )
	                       er = er " " poss.Whole_name "?"
	                       err(er)
                      ;
                      ==>
                 ;
				 CASE Kind == 'CLASS' ?
					  err("Field"._Efield1 " " N 
                      " " ("is not found in class"._Eisnot2) 
                      " " Whole_name) ==>
				 ;
				 CASE Kind == 'STRUCTURE' ?
				      er = "Field"._Efield2 " " N 
                      	   " " ("is not found in structure"._isnotInStruc)
                      	    
				      er = er " " Base_.Whole_name
				      er = er "." Whole_name
					  err(er) ==>
				 ;
				 err("Field"._Efield3 " " N 
                     " " ("was not found in an erroneous type"._Ewasnot))
			; .
        */
        public Variable Find_field(string N)
        {
            Variable Result = Search_field(N);
            if (Result == null)
                err("Field " + N + " is not found in class " + Names[Names.Count - 1]);
            return Result;
        }

        /*


{Hash_names} hash_fields        
{Hash_names} hash_Lfields|_lowered        
        
        METHOD Search_field(
        	STR Name|_of_field) ==> {Var}, RECURSIVE
        	:
	        RESULT = search_field_only(Name)
	        CASE RESULT == NONE ? ==> ;
            CASE RESULT.Redirect_ != NONE ?
                 RESULT = RESULT.Redirect_ ;
            comp.Current_fun.Check_var_abandoned_deprecated( RESULT ) . 
	             
        	
        METHOD search_field_only(
        	STR Name|_of_field) ==> {Var}, RECURSIVE
        	:
        	CASE Parse.Compiler_.{Compiler}.Current_class.Any_case ?
        	     BOOL any_case = TRUE
        	     STR n_low|ered = Name.Lower ;
        	CASE hash_fields == NONE ?
        	     hash_fields = {Hash_names}
        	     hash_Lfields = {Hash_names} ;
    	    RESULT = hash_fields.Search(Name).{Var}
    	    CASE RESULT != NONE ? ==> ;
        	CASE any_case ?
        	     RESULT = hash_Lfields.Search(n_low).{Var}
        	     CASE RESULT != NONE ? ==> ;
        	;     
            FOR f IN Field[] :
            	CASE any_case ? f.Provide_names_lowered ;
                CASE !any_case && Name IN f.Names[] 
                	 || any_case && n_low IN f.Names_low[]
                	 ? 
                     RESULT = f
                     hash_fields.Add(f.Names[], f)
                     f.Provide_names_lowered
                     hash_Lfields.Add(f.Names_low[], f) ==> ;
            ;
            CASE Base_ != NONE ?
                 RESULT = Base_.Search_field(Name) ; .
        */
        public Variable Search_field(string Name)
        {
            foreach (Variable f in Field)
                if (f.Names.Contains(Name)) return f;
            if (Base_ != null)
                return Base_.Search_field(Name);
            return null;
        }

        /*
        STR final_n|ames[]
        STR Prefix_f|inal_name
        BOOL made_final_names

        METHOD Make_final_names(
        	STR All_class_fin|al_names[]), RECURSIVE 
        	:
			CASE final_n[].Count == 0 ?
			     final_n[] << "F_OK".Lower ;
            CASE made_final_names ? ==> ;
            CASE Base_ != NONE && !Base_.made_final_names ?
                 Base_.Make_final_names(All_class_fin[]) ;
            made_final_names = TRUE
            ----------------------------------------------- 'for class'
            make_final_name("C_", All_class_fin[])
            ----------------------------------------------- 'for enums ?'
            FOR e IN Enums_[] :
                CASE e.Final_name != "" ? CONTINUE e ;
                e.make_final_name("E_", final_n[])
            ;
            ----------------------------------------------- 'for structures'
            Prefix_f = "f_"
            FOR struc IN Structures_[] :
                struc.make_final_name("St_", final_n[])
                FOR v IN struc.Field[] :
                    CASE v.Final_name == "" ?
                         struc.Prefix_f = Prefix_f
                         v.Set_final_name(
                         	struc.Next_final_name(v.Names[], TRUE)) ;
                ;
            ;
            ----------------------------------------------- 'for fields'
            Prefix_f = "F_"
            FOR v IN Field[] :
                CASE v.Final_name == "" ?
                     v.Set_final_name(Next_final_name(v.Names[], TRUE)) ;
            ;
            ----------------------------------------------- 'for constants'
            Prefix_f = "K_"
            FOR v IN Constants[] :
                CASE v.Final_name == "" ?
                     v.Set_final_name(Next_final_name(v.Names[], TRUE)) ;
            ;
            ----------------------------------------------- 'for methods'
            Prefix_f = "M_"
            FOR f IN Method[] :
                Set_method_final_name(f) ;
            ----------------------------------------------- 'for test methods'
            Prefix_f = "m_"
            FOR f IN Test[] :
                Set_method_final_name(f) ;
            .
            
        METHOD Set_method_final_name(
        {Fun} M|ethod_to_handle)
        	:
			CASE M.Overloaded_[].Count > 0 ? ==> ;
			CASE M.Final_name != "" ? ==> ;
			CASE M.Ancestor_ != NONE ?
				 M.Final_name = ancestor_method_final_name(M.Ancestor_)
				 
			ELSE M.Final_name = Next_final_name(M.Names[], 
					!M.Modifiers['CALLBACK']) ; .

        METHOD ancestor_method_final_name(
            {Fun} A|ncestor_method) ==> STR, RECURSIVE
            :
            -------------------- 'Provide Final_name for ancestor method'
            CASE A.Final_name == "" ?
                 CASE A.Ancestor_ != NONE ?
                      A.Final_name = ancestor_method_final_name(A.Ancestor_)
                 ELSE A.Final_name = Next_final_name(A.Names[], TRUE) ;
            ;
            RESULT = A.Final_name .
        */
        private List<string> final_names = new List<string>();
        private string Prefix_f = "";

        public void Make_final_names(List<string> All_class_fin)
        {
            make_final_name("C_", All_class_fin);
            if (Final_name == "" || Final_name == null)
                err("Can not make unique final name for class: " + Names[Names.Count - 1]);
            foreach (Type e in Enums_)
            {
                e.make_final_name("E_", All_class_fin);
                if (e.Final_name == "")
                    err("Can not make unique final name for enum: " + e.Names[e.Names.Count - 1]);
            }
            Prefix_f = "F_";
            foreach(Variable v in Field)
            {
                if (v.Total_index == 32)
                { }
                if (v.Final_name == "")
                    v.Final_name = Next_final_name(v.Names, true);
            }
            Prefix_f = "M_";
            foreach (Function f in Method)
            {
                //if (f.Total_fn == 915)
                //{ }
                if (f.Final_name == "")
                {
                    f.Final_name = Next_final_name(f.Names, 
                    	!f.Modifiers[(int)Function.Fun_mod.CALLBACK]);
                }
            }

        }


        /*
        
        METHOD make_final_name|_for_type(
            STR Pref|ix_str, STR All_class_fin[])
            :
            ----------------------------- 'Final name for our class'
            FOR x IN [0 TO comp.All_classes[].Count] :
                FOR nm IN Names[] :
                    STR c|lass_final_name = Pref Parse.Only_letters_dig(
                    	nm, SUPPORTS_NATIONAL_NAMES)
                    	
                    CASE x > 0 ? c = c x.Str ;
                    CASE c !IN All_class_fin[] ?
                        All_class_fin[] << c
                        Final_name = c ==> 
                    ELSE class_having_callback_functions_must_not_conflict ;
                ;
            ; .
            
        METHOD class_having_callback_functions_must_not_conflict :
            FOR m IN Method[] :
                CASE m.Modifiers['CALLBACK'] ?
                     BOOL has|_callback_functions = TRUE ;
            ;
            CASE has ?
                 Parse.Err("Class"._Eclass6 " " Whole_name 
                 " " ("has callback functions"
                 ", but it is conflicting by names with another class"._Ehas))
            ; .
        */
        private void make_final_name(string Pref, List<string> All_class_fin)
        {
            for (int x = 0; x <= Parse.Compiler_.All_classes.Count; x++)
            {
                foreach (string nm in Names)
                {
                    string class_fin = Pref + only_letters_digits(nm);
                    if (x > 0) class_fin += x.ToString();
                    if (!All_class_fin.Contains(class_fin))
                    {
                        All_class_fin.Add(class_fin);
                        Final_name = class_fin;
                        return;
                    }
                }
            }
        }

        /*
        
        */
        private static string only_letters_digits(string name)
        {
            string Result = "";
            for (int x = 0; x <= name.Length - 1; x++)
            {
                string c = name.Substring(x, 1);
                if (c == "_" || is_letter(c) || is_digit(c))
                    Result += c;
            }
            return Result;
        }

        private static bool is_letter(string c)
        {
            return c.ToUpper() != c.ToLower();
        }

        private static bool is_digit(string c)
        {
            return "0123456789".Contains(c);
        }

        /*
        
        METHOD Next_final_name(
        STR N|ames_of_object_DYN[], 
        BOOL Allow_mod|ifications_to_make_it_unique) ==> STR
            :
            FOR x IN [0 TO final_n[].Count + 10_000] :
                FOR n IN N[] :
                    STR c|lean_name = Parse.Only_letters_dig(
                    	n, SUPPORTS_NATIONAL_NAMES)
                    	
                    RESULT = Prefix_f c
                    CASE x != 0 ? RESULT = RESULT x.Str ;
                    CASE Base_.name_is_used(RESULT.Lower) ? CONTINUE n ;
                    CASE RESULT.Lower !IN final_n[] ?
                        final_n[] << RESULT.Lower ==> ;
                    //DEBUG: << "Name " RESULT " is already in list "
                    //        "(current class: " Names[0] #NL ;
                ;
                CASE !Allow_mod ? BREAK x ;
            ; 
            Parse.Err("Could not create unique name for " N[].Whole_name_of 
                " in class " Names[0]) .
            
        METHOD name_is_used|_as_final(
        	STR Name|_lowered) ==> BOOL, RECURSIVE
        	:
            CASE Name IN final_n[] ? RESULT = TRUE ==> ;
            CASE Base_ != NONE ? RESULT = Base_.name_is_used(Name) ; .
        
        */
        static int CNT_next_final_name;

        public string Next_final_name(List<string> N, bool Allow_mod)
        {
            if (CNT_next_final_name++ == 163)
            { }
            for (int x = 0; x <= final_names.Count; x++)
            {
                foreach (string n in N)
                {
                    string Result = Prefix_f + n;
                    if (x != 0) Result += x.ToString();
                    if (!final_names.Contains(Result.ToLower()))
                    {
                        final_names.Add(Result.ToLower());
                        return Result;
                    }
                }
                if (!Allow_mod) break;
            }
            err("Can not allocate unique final name for " + (N.Count > 0 ? N[N.Count - 1] : ""));
            return N.Count > 0 ? N[N.Count - 1] : "";
        }

        /*
        
        METHOD Calculate_const|ants :
            FOR c IN Const[] :
                CASE !c.Is_array ?
                     calculate_1_const(c)
                ELSE
                	FOR it IN c.Items_[] :
                		calculate_1_const(it) ;
                ;
            ; .
            
        METHOD calculate_1_const(
        {Var} c|onstant_to_calculate_scalar_only)
        	:
            CASE Construct == NONE ? Provide_construct ;
            Parse.Line = c.Line
            PUSH Parse.Line = c.Line-1 :
                 INT dummy_last_to_reset_cashed_line_length = Parse.Last ;
            PUSH Parse.Source[Parse.Line] = c.Constant_value :
                    Parse.Pos = 0
                    CASE c.Type_.Kind == 'REAL' ?
                         c.Initial_ = Recognize_typed(Parse, 'REAL'),
                         			  >> Construct.All_expr[]
                         			  
                    ELSE c.Initial_ = Construct.Expr,
                    				  >> Construct.All_expr[]
                    ;
                    CASE c.Initial_.Operation == 'NEG' ?
                         {Var} n|egative_initial = c.Initial_.Arg1_.Var_arg
                         
                         c.Initial_ = {Expr}(Operation= 'CONST',
                         	Var_arg = {Var}(Is_const = TRUE, Line=0, 
	                         	Type_= n.Type_,
	                         	Int_c = -n.Int_c,
	                         	Real_c = -n.Real_c)),
                         	OWNED BY c
                         	
                         CASE c.Type_.Kind == 'REAL' 
                              && c.Initial_.Var_arg.Type_.Kind == 'INT'
                              ?
                              c.Initial_.Var_arg.Real_c 
                              = c.Initial_.Var_arg.Int_c ;
                    ;
                    //c.Bool_c = c.Initial_.Var_arg.Bool_c
                    c.Int_c = c.Initial_.Var_arg.Int_c
                    c.Real_c = c.Initial_.Var_arg.Real_c
                    c.Str_c = c.Initial_.Var_arg.Str_c ; .
	
        */
        public void Calculate_const()
        {
            foreach (Variable c in Const)
            {
                if (c.Total_index == 674)
                { }

                if (Construct_method == null)
                {
                    Construct_method = new Function(Parse);
                    Construct_method.Parse = Parse;
                    Construct_method.Names.Add("CONSTRUCT");
                    Construct_method.Final_name = Next_final_name(
                    	Construct_method.Names, true);
                    Construct_method.Line_start = -1;
                    Method.Add(Construct_method);
                }
                Parse.Line = c.Line;
                string temp = Parse.Source[Parse.Line];
                Parse.Source[Parse.Line] = c.Value;
                try
                {
                    Parse.Pos = 0;
                    c.Initial_ = Construct_method.Expr();
                    if (c.Initial_.Operation == Expression.Operation_kind.CONST)
                    {
                        c.Bool_c = c.Initial_.Var_arg.Bool_c;
                        c.Int_c = c.Initial_.Var_arg.Int_c;
                        c.Real_c = c.Initial_.Var_arg.Real_c;
                        c.Str_c = c.Initial_.Var_arg.Str_c;
                    }
                }
                finally { Parse.Source[Parse.Line] = temp; }
            }
        }



        /*
        STR Enum_items_need_q|ualification[]
        STR Structure_fields_need_q|ualification[]
        STR Structures_need_q|ualification_or_enums[]
        STR Enums_need_q|ualification_or_enums[]
        
        STR all_enum_items[]
        STR all_structure_fields[]
        {Type} all_enums_[]
        {Type} all_structures_[]

        METHOD Check_surnamed_enums :
			Enum_items_need_q[].Clear
			Structures_need_q[].Clear
			Enums_need_q[].Clear
			Structure_fields_need_q[].Clear
			----------------------- 'clear accumulate arrays'
            all_enum_items[].Clear
            all_structure_fields[].Clear
            all_enums_[].Clear
            all_structures_[].Clear
            -----------------------
            mark_surnamed_enums(Enums_[])
            mark_surnamed_enums(Structures_[])
            FOR im IN Import_[] :
                mark_surnamed_enums(im.Enums_[])
                mark_surnamed_enums(im.Structures_[]) ;
            ----------------------- 'again clear accumulate arrays'
            all_enum_items[].Clear
            all_structure_fields[].Clear
            all_enums_[].Clear
            all_structures_[].Clear
            .
        */
        private List<Variable> all_enum_items = new List<Variable>();
        private List<Type> all_enums_ = new List<Type>();
        public void Check_surnamed_enums()
        {
            all_enum_items.Clear();
            all_enums_.Clear();
            mark_surnamed_enums(this);
            foreach (Type im in Import_)
                mark_surnamed_enums(im);
            foreach (Function t in Test)
                foreach (Type im in t.Test_import_)
                    mark_surnamed_enums(im);
        }

        /*
        
        METHOD mark_surnamed_enums|_structures(
        	{Type} Enums|_or_structures[])
        	:
            FOR e IN Enums[] :
            	CASE e IN all_enums_[] ? CONTINUE e ;
                check_mark_surnamed_enums(e) ; .
                
        METHOD check_mark_surnamed_enums(
        {Type} e|num_or_structure_to_check)
            :
            FOR ew IN all_enums_[] :
                FOR n IN e.Names[] :
                    CASE n !IN ew.Names[] ? CONTINUE n ;
                    CASE e.Kind=='ENUM' ? Enums_need_q[] << n 
                    ELSE Structures_need_q[] << n ;
                ;
            ;
            CASE e.Kind=='ENUM' ? all_enums_[] << e
            ELSE				  all_structures_[] << e ;     
            FOR it IN e.Items[] :   
           		FOR n IN it.Names[] :
            		CASE n IN all_enum_items[] ?
            			 Enums_need_q[] << n ;
            	all_enum_items[] << n ;
            ;
            FOR f IN e.Field[] :
            	FOR n IN f.Names[] :
                	CASE n IN all_structure_fields[] ?
                	     Structure_fields_need_q[] << n ;
            	all_structure_fields[] << n ;
            ; .
        */
        private void mark_surnamed_enums(Type C)
        {
            foreach (Type e in C.Enums_)
            {
                e.Want_q = false;
                foreach (Type ew in all_enums_)
                    if (surnamed(e.Names, ew.Names))
                    {
                        e.Want_q = true;
                        ew.Want_q = true;
                    }
                all_enums_.Add(e);
                foreach (Variable it in e.Items)
                {
                    it.Need_q = false;
                    mark_surnamed(it, all_enum_items);
                    all_enum_items.Add(it);
                }
            }
        }

        private void mark_surnamed(Variable It, List<Variable> All)
        {
            foreach (Variable v in All)
            {
                if (surnamed(It.Names, v.Names))
                {
                    if (v.Total_index == 572)
                    { }
                    v.Need_q = true;
                    It.Need_q = true;
                }
            }
        }


        private bool surnamed(List<string> X, List<string> Y)
        {
            foreach (string n in X)
                if (Y.Contains(n))
                    return true;
            return false;
        }

        /*
        
        METHOD Compile_code|_of_class, RECURSIVE :
			CASE Compiled ? ==> ;
            ----------------------------------- 'Prepare to compile the class'
            Compiled = TRUE
            CASE comp.Verbose ?
                 << "Compiling"._Mcomp ": " Names[0] 
                 " (" Parse.Class_.Path ")" #NL
            ;
            comp.Total_st += 999
            comp.Total_st -= comp.Total_st % 1000 
            ----------------------- 'clear localization strings'
            Localize_n[].Clear
            Localize_s[].Clear
            Localize_line[].Clear
            Localize_1st_item = 0
            ----------------------- 'start new objects index from new page'
            temp|_var = {Var}(Line = 0)
            INT curr|ent_index = {System_functions}.Total_obj_index(temp)
            INT next|_index = curr + 999
            next -= next % 999
            FOR i|dummy IN [curr+1 TO next] :
                temp = {Var}(Line = 0) ;
            ---------------- 'check names of fields in compare to base classes'
            FOR fld IN Field[] :
                FOR nfld IN fld.Names[] :
                    check_field_hides_defined_in_base_classes(nfld) ;
                fix_field_final_name(fld) ;
            ----------------------- 'start compiling the class code'
            PUSH comp.Current_class = THIS :
                 ----------------- 'check corresponding class name to file name'
                 STR fname|_of_class = Change_ext(Path.Extract_file_name, "")
                 CASE !Starting(fname.Lower, Names[0].[1 TO *-1].Lower) ?
                      Parse.Warn("Short name of class"._Wshort 
                      " " Names[0].[1 TO *-1]
                      " " ("should matching starting part of a class file "
                      "name"._Wshould) " (" fname ")") ;
                 ------------------------------------- 'construction BASE CLASS'
                 CASE Base_ != NONE && !Base_.Compiled ?
                      Base_.Compile_code ;
                 CASE base_line > 0 ?
                      temp_f|unction = {Fun}(Parse = Parse, A_Name_1 = "temp"),
                      	OWNED BY THIS
                      Parse.Line = base_line
                      Parse.Pos = 0
                      Parse.Wait("BASE")
                      Parse.Wait("CLASS")
                      CASE Parse.Symbol(":") ? NONE ;
                      NONE = Parse.Scan_type
                      PUSH comp.Current_fun = temp_f :
                           Create_base = {Assign}(Function_ = temp_f,
                              Level = 0, Pos = Parse.Pos,
                              Line = Parse.Line,
                              Source = {Expr}.Obtain_new(Parse, Base_, TRUE)) ;
                 ;
                 d|ata_array_field = {Var}(Line = -3, Is_array = TRUE,
                     Is_fixed = TRUE, Size_value = Ending_lines[].Count,
                     Modifiers[{Var}.{var_mod}.'READ'] = TRUE,
                     Names[] << "DATA", In_type_ = THIS, 
                     Type_ = comp.TYPE_STR,
                     Size_type_ = comp.TYPE_INT),
                     >> Field[]
                     
                 d.Set_final_name("DATA")
                 ----------------------------------------- 'methods'
                 FOR f IN Method[] :
                     f.Compile ;
                 PUSH comp.TEST_value = TRUE :
                      ------------------------------- 'save Used_imports_[]'
                      {Type} save_used_im|ports[]
                      FOR im IN Used_imports_[] : save_used_im[] << im ;
                      FOR t IN Test[] :
                          ---------- 'compile now'
                          t.Compile
                      ;
                      ----------------------- 'restore Used_imports_[] of class'
                      Used_imports_[].Clear
                      FOR im IN save_used_im[] : Used_imports_[] << im ;
                 ;
                 ------------------------------------ 'fields (initializations)'
                 FOR v IN Field[] :
                     CASE v.Constant_value != "" ?
                          temp_f = {Fun}(Parse = Parse, A_Name_1 = "temp"),
                          	OWNED BY THIS
                          	
                          Parse.Line = v.Line
                          PUSH comp.Current_fun = Construct :
                          PUSH Parse.Source[Parse.Line] = v.Constant_value:
                               Parse.Reset_cache_last_pos
                               Parse.Pos = 0
                               
                               CASE v.Type_.Kind == 'REAL' ?
                                    {Expr} etemp|_expr = Recognize_typed(
                                        Parse, 'REAL'), >> temp_f.All_expr[]
                                        
                                	v.Initial_ = etemp
                               ELSE
                                    v.Initial_ = temp_f.Expr,
                                               >> temp_f.All_expr[]
                               ;
                               CASE v.Initial_.Type_expr.Kind != v.Type_.Kind ?
                                    Parse.Err("Type of variable does not "
                                    "match the type of its initial value. "
                                    " Variable: " v.Whole_name) ;
                          ;
                          ;
                     ;
                 ;
                --------------------- 'check imported classes are used actually'
                FOR im IN Import_[] :
                    CASE im !IN Used_imports_[] && im.Method[].Count + (
                         im.Field[].Count + im.Const[].Count) > 0 && !(
                         im.Anyway)
                         ?
                         INT count_amb|igous = count_amb + 1
                         STR ambig|ous_use = ambig im.Whole_name ", " ;
                ;
                CASE ambig != "" ?
                     Parse.Line = 0
                     CASE ?
                     [Parse.Syntax_name != ""] ? NONE
                     [count_amb == 1] ?
                          Parse.Warn("Class"._Wclass " " ambig.[0 TO *-2] 
                              " " ("was imported "
                              "but it is not used in class"._Wwas) 
                              " " Whole_name
                              " " ("actually (or used only in TEST "
                              "functions)"._Wactual ))
                     ELSE Parse.Warn("Classes"._Wclass6 
                          " " ambig.[0 TO *-2] " " ("were imported"
                              " but these are not used in the class"._Wwere) 
                              " " Whole_name " " ("actually "
                              "(or used only in TEST functions)"._Wactual2 )) ;
                ;
                --------------------------- 'data[] used ?'
                CASE !d.Used_for_r ? Ending_lines[].Clear ;
                ---------------------------------------- 'need destructor?'
                CASE Destruct == NONE ?
	                 FOR fld IN Field[] :
	                     CASE fld.Is_array && ! fld.Is_fixed ?
	                          BOOL need_destructor = TRUE
	                          BREAK fld ;
	                     CASE fld.Type_.Kind IN ['CLASS', 'STRUCTURE']
	                     	  ?
	                          need_destructor = TRUE
	                          BREAK fld ;
                         //CASE fld.Type_.Kind == 'STR'
                         //     && comp.Is_fpc
                         //     ?
                         //     need_destructor = TRUE
                         //     BREAK fld ;
	                 ;
	                 CASE need_destructor || (comp.Want_report_leaks)
	                      ?
	                      Destruct = {Fun}(Parse = Parse, Line_start = 0,
	                      Names[] << "_Destruct", Final_name = "DESTRUCT",
	                      A_Name_1 = "DESTRUCT")
	                      
	                      Add_method(Destruct)
	                 ;
	                 CASE Construct == NONE && (
	                      comp.Defined_name[].Find(
	                      "$REPORT_LEAKS") >= 0)
	                      ?
	                      Provide_construct ;
                ;
                ---------------------------- 'check test imports not ambiguous'
                //STR non_s|pecified_home = ""
                FOR er IN Outer_[] :
                    CASE er IN Specified_[] ? CONTINUE er ;
                	PUSH Parse.Line :
                	PUSH Parse.Pos :
	                    STR s_type|_only = er.Whole_name
	                    CASE "|" IN s_type ? 
	                         s_type = s_type.[0 TO s_type.Find("|")-1] ;
	                    FOR ii IN [0 TO Parse.Source[].Count-1] :
	                        STR ss|tring_at_i = Parse.Source[ii]
	                        CASE ss.Find(s_type) >= 0 ? 
	                             Parse.Line = ii
	                 			 Parse.Pos = ss.Find(s_type)             
	                             BREAK ii ;
	                    ;
	                    Parse.Warn("A structure/enumeration type should have at "
	                    "least once home class specification"._WOuter1
	                    ": " er.Base_.Whole_name "." er.Whole_name)
                	;
                	;
                    //non_s << #NL er.Base_.Whole_name
                    //    "." er.Whole_name ", "
                ;
                //CASE non_s != "" && Parse.Syntax_name == "" ?
                //    Parse.Warn("There are structure/enumeration types used "
                //    "from imported classes without specifying its home "
                //    "classes at least once"._WOuter ": " non_s.[0 TO *-2])
                //; 
	            ---------------------- 'check not referenced private functions'
	            FOR f IN Method[]:
	                CASE f.Modifiers['PUSH_METHOD'] && f.Pop_method_ == NONE ?
	                     PUSH Parse.Line = f.Line_start :
	                          Parse.Err("For PUSH method there is no a POP "
	                          "method corresponding"._EPUSHnoPOP) ;
	                ;
	                CASE ?
	                [f.Is_test] ? CONTINUE f
	                [f.Names[0].[0].Upper == f.Names[0].[0]] ? CONTINUE f
	                [f.Is_public] ? CONTINUE f
	                [f.Modifiers['TRAP_FUN']] ? CONTINUE f
	                [f.Modifiers['CALLBACK']] ? CONTINUE f
	                [f.Modifiers['POP']] ? CONTINUE f
	                [f.Ancestor_ != NONE] ? CONTINUE f
	                ["local" IN f.Names[*].Lower] ? CONTINUE f
	                [f.Getter_field_ != NONE || f.Getter_method_ != NONE] ?
	                     CONTINUE f
	                [f.Overload_base_!=NONE] ? CONTINUE f
	                [f.Count_ref == 0 && !f.Modifiers['DEBUG_FUN'] && (
	                 !f.Modifiers['DEPRECATED_FUN']) && (
	                 !f.Modifiers['ABANDONED_FUN']) 
	                 && Parse.Syntax_name == ""] ?
	                     PUSH Parse.Line = f.Line_start :
	                          CASE f.Modifiers['STATIC'] ?
	                          	   Parse.Warn("Private function is not "
	                          	   "referenced in the class"._WPrivateFun
	                          	   ": " f.Whole_name)
	                          ELSE Parse.Warn("Private method is not "
	                          	   "referenced in the class"._WPrivateMethod
	                          	   ": " f.Whole_name) ;
	                     ;
	                ;
	            ;
	            ---------------------- 'check not referenced private fields'
	            FOR v IN Field[]:
	                //DEBUG:
	                //      CASE f.Names[0] == "copy_line" ? NONE ;
	                //;
	                CASE ?
	                [v.Is_public || v.Modifiers['DEBUG_VAR']] ? CONTINUE v
	                ["local" IN v.Names[*].Lower] ? CONTINUE v
	                [v.Count_ref == 0 && Parse.Syntax_name == ""] ?
	                     PUSH Parse.Line = v.Line :
	                          Parse.Warn("Private field is not "
	                          	   "referenced in the class and has no "
	                          	   "substring 'local' in its "
	                          	   "name"._WPrivateField
	                          	   ": " v.Whole_name) ;
	                ;
	            ;
	            Warn_not_used_reused
            ;
            //CASE Parse.Compiler.Errors_count > 0 ? ==> ;
            //Save_ccc 
            . 
            
        METHOD check_field_hides_defined_in_base_classes(
        	STR Name|_of_field )
        	:
            {Type} base|_class = THIS
            FOR i|dummy IN [1 TO 100] :
                base = base.Base_
                CASE base == NONE ? ==> ;
                FOR fld IN base.Field[] :
                    CASE Name IN fld.Names[] ?
                         Parse.Warn("Field " Name " hides same named field from"
                         " the base class " base.Whole_name) ==> ;
                ;
            ; .
            
        METHOD fix_field_final_name(
        	{Var} Field|_to_fix_final_name )
        	:
            INT attempt|_to_fix = 1
            {Type} base|_class = THIS
            FOR i|dummy IN [1 TO 10000] :
                base = base.Base_
                CASE base == NONE ? ==> ;
                FOR fld IN base.Field[] :
                    CASE Field.Final_name == fld.Final_name ?
                         Field.Set_final_name(fld.Final_name.remove_ending_index
                         	"_" attempt.Str)
                         attempt += 1
                         base = THIS
                         BREAK fld, CONTINUE i ;
                ;
            ;
            Parse.Err("Internal error: can not fix field final name"._Einternal
            ": " Field.Whole_name) .
            
        FUN remove_ending_index(
        	STR Name|_to_remove_index ) ==> STR
        	:
            RESULT = Name
            INT pos|ition_underscore = Find_last(Name, "_")
            CASE pos < 0 ? ==> ;
            FOR i IN [pos+1 TO Name.Len-1] :
                CASE Name.[i] !IN "0123456789" ? ==> ;
            ;
            RESULT = Name.[0 TO pos-1] .
			
		METHOD Ensure_table_compiled(
			{Table} Table|_to_check_if_compiled )
			:
			---------------------------- 'table need to be compiled ?'
			CASE Table.Compiled ? ==> ;
			Table.Name_actual = Table.Names[0]
			PUSH comp.Current_class = THIS :
				 PUSH Parse.Line = Table.Line :
				 PUSH Parse.Pos = Table.Pos :
					  CASE Parse.End_of_line ? Parse.Fin ;
					  --------------------- 'base STRUCTURE (single)'
					  Parse.Wait("{")
					  Table.Base_ = Find_type("{" Parse.Ident "}")
					  Parse.Wait("}")
					  CASE Table.Base_.Kind != 'STRUCTURE' ?
							Parse.Err("TABLE must be based on a STRUCTURE, not "
							"on"._EtableStructure " " Table.Base_.Kind.Name)
					  ;
					  FOR f|ield IN Table.Base_.Field[] :
						  Check_table_base_structure_field_type(f, Parse) ;
					  CASE Parse.End_of_line ? Parse.Fin ;
					  ---------------------- 'additional TABLE definitions'
					  FOR i|dummy IN [Parse.Line TO Parse.Source[].Count-1] :
						  CASE Parse.Symbol(".") ? ==> ;
						  Table.Handle_specification(Parse)
						  CASE Parse.Symbol(".") ? ==> ;
						  Parse.Fin ;
				 ;
				 ;
			; .
			
				 
            
        */
        public void Compile()
        {
            Compiled = true;
            if (Parse.Compiler_.Verbose)
                Console.WriteLine("Compiling: " + Names[0]);
            if (Base_ != null && !Base_.Compiled)
                Base_.Compile();
            Parse.Compiler_.Current_class = this;
            if (base_line > 0)
            {
                Function temp_f = new Function(Parse);
                temp_f.Parse = Parse;
                Parse.Line = base_line;
                Parse.Pos = 0;
                Parse.Wait("BASE");
                Parse.Wait("CLASS");
                Parse.Scan_type();
                Function save_fun = Parse.Compiler_.Current_fun;
                Parse.Compiler_.Current_fun = temp_f;
                try
                {
                    Create_base = new Assignment();
                    Create_base.Line = Parse.Line;
                    Create_base.Source =
                        Expression.Obtain_new_obj(Parse, Base_, true);
                }
                finally { Parse.Compiler_.Current_fun = save_fun; }
            }
            Variable d = new Variable(Parse.Compiler_);
            {
                d.Names.Add("DATA");
                d.Final_name = "DATA";
                d.Type_ = Parse.Compiler_.TYPE_STR;
                d.Is_array = true;
                d.Is_fixed = true;
                d.Size_type_ = Parse.Compiler_.TYPE_INT;
                d.Modifiers[(int)Variable.Var_mod.READ] = true;
                Field.Add(d);
            }
            //------------------------------------ 'methods'
            foreach (Function f in Method)
            {
                f.Compile();
            }
            bool save_TEST_c = Parse.Compiler_.TEST_c.Bool_c;
            Parse.Compiler_.TEST_c.Bool_c = true;
            try
            {
                foreach (Function t in Test)
                {
                    int N = Import_.Count;
                    foreach (Type im in t.Test_import_)
                        Import_.Add(im);
                    t.Compile();
                    for (int i = Import_.Count - 1; i > N; i--)
                        Import_.RemoveAt(i);
                }
            }
            finally { Parse.Compiler_.TEST_c.Bool_c = save_TEST_c; }
            foreach (Variable v in Field)
            {
                if (v.Value != "")
                {
                    Function temp_f = new Function(Parse);
                    {
                        temp_f.Parse = Parse;
                    }
                    Parse.Line = v.Line;
                    string temp = Parse.Source[Parse.Line];
                    Parse.Source[Parse.Line] = v.Value;
                    try
                    {
                        Parse.Pos = 0;
                        v.Initial_ = temp_f.Expr();
                    }
                    finally { Parse.Source[Parse.Line] = temp; }
                }
            }
        }

        /*
        
        METHOD Provide_construct :
            CASE Construct == NONE ?
                 Construct = {Fun}(Parse = Parse, Line_start = -1,
                     Names[] << "CONSTRUCT", A_Name_1 = "CONSTRUCT",
                     Final_name = "CONSTRUCT", Class_= THIS)
                     
                 Add_method(Construct)
            ; .
            
        */
        private void provide_construct()
        {
            if (Construct_method == null)
            {
                Construct_method = new Function(Parse);
                Construct_method.Parse = Parse;
                Construct_method.Names.Add("CONSTRUCT");
                Construct_method.Final_name = Next_final_name(
                	Construct_method.Names, true);
                Construct_method.Line_start = -1;
            }
        }

        /*
        
        METHOD Detect_bad(STR Text|_why_bad) :
            CASE Detected['BAD'] ? ==> ;
            Detected['BAD'] = TRUE
            CASE Modifiers['BAD'] ? ==> ;
            
            err("Bad code style detected but the class is not marked with "
            "'BAD' modifier"._Ebad ": " Text) .
        */
        public void Detect_bad(string Text)
        {
            if (Detected[(int)Class_mod.BAD]) return;
            Detected[(int)Class_mod.BAD] = true;
            if (Modifiers[(int)Class_mod.BAD]) return;
            err("Bad code style detected but the class is not marked with " +
                "'BAD' modifier: " + Text);
        }

        /*
        
        METHOD Detect_descr|ibed(
        	{class_mod} A|ttribute, STR Descr|iption)
        	:
            CASE Detected[A] ? ==> ;
            Detected[A] = TRUE
            CASE Modifiers[A] ? ==> ;
            
            err("Attribute"._Eattr " " A.Name 
            " " ("must be present in the class"._Emust) 
            " " Whole_name " " ("header"._Eheader) ": " Descr) .

        METHOD Detect|_attribute({class_mod} A|ttribute) :
            CASE Detected[A] ? ==> ;
            Detected[A] = TRUE
            CASE Modifiers[A] ? ==> ;
            
            err("Attribute"._Eattr2 " " A.Name 
            " " ("must be present in the class"._Emust2)
            " " Whole_name " header") .
        */
        public void Detect(Class_mod A)
        {
            if (Detected[(int)A]) return;
            Detected[(int)A] = true;
            if (Modifiers[(int)A]) return;
            err("Class attribute " + Class_mod_names[(int)A] +
                " must be present but it is not declared");
        }

        /*
        
        METHOD Is_descend|ant_of({Type} B|ase_class,
                {Compiler} C|ompiler) ==> BOOL
            :
            ---------------------------------------- 'B -> B1 -> B2 -> ... C ?'
            {Type} c|lass_this = THIS
            CASE B == C.TYPE_OBJ ? RESULT = TRUE ==> ;
            FOR x|dummy IN [0 TO 1000] :
                CASE c == NONE ? ==> ;
                CASE c == B ? RESULT = TRUE ==> ;
                CASE c.Kind != c.Base_.Kind ? ==> ;
                c = c.Base_ ; 
            .
        */
        public bool Is_descendant_of(Type B, Compiler C)
        {
            Type c = this;
            if (B == C.TYPE_OBJ) return true;
            for (int x = 0; x <= 1000; x++)
            {
                if (c == null) return false;
                if (c == B) return true;
                c = c.Base_;
            }
            err("Internal error - too many ancestors for " + Names[Names.Count - 1]);
            return false;
        }

        /*
        
        BOOL Force_any_case
        
        METHOD Any_case ==> BOOL :
	        CASE Force_any_case ? RESULT = TRUE ==> ;
			{Type} cc|urrent_class = Parse.Compiler_.{Compiler}.Current_class 
			RESULT = Parse.Case_insensitive || cc.Parse.Case_insensitive .
        
        METHOD Search_const|ant(
        	STR Name|_of_constant,
        	BOOL Allow_nesting|_imports) ==> {Var}, RECURSIVE
        	:
        	{Type} cc|urrent_class = comp.Current_class
            FOR c IN Const[] :
            	CASE ?
            	[Any_case || cc.Any_case] ?
            	     c.Provide_names_lowered
            	     CASE Name.Lower IN c.Names_low[] ?
            	          BOOL found|_const = TRUE ;
                [Name IN c.Names[]] ? found = TRUE ;
                CASE ?
                [found && c.Redirect_ != NONE] ? RESULT = c.Redirect_==>
                [found] ? RESULT = c ==> ;
            ; 
            CASE !Allow_nesting || cc != THIS ? ==> ;
                 
            {Var} earlier_found|_one = NONE
            STR where_found[]
            FOR n_im INDEXING {Type} IN [
            	0 TO Import_[].Count + Test_import_[].Count - 1]
            	:
                CASE ?
                [n_im < Import_[].Count] ? {Type} im|port_at_n = Import_[n_im]
                [!comp.Current_fun.Is_test] ? BREAK n_im
                ELSE im = Test_import_[n_im - Import_[].Count]
                ;
                RESULT = im.Search_const(Name, FALSE)
                CASE RESULT != NONE ?
                     where_found[] << Import_[n_im].Names[0] 
                     CASE earlier_found != NONE ? 
                          Parse.Err("Ambiguous constant name (defined in "
                          "several imported classes). "
                          "It needs to be clarified"._EAmbigConst
                          ": " Name " was found in: " Merge(where_found[], ",")) 
                     ;
                     CASE im !IN Used_imports_[] ?
                          Used_imports_[] << im ;
                     earlier_found = RESULT 
                ;
            ; 
            RESULT = earlier_found .
        */
        public Variable Search_const(string Name)
        {
            foreach (Variable c in Const)
            {
                if (c.Names.Contains(Name))
                    return c;
            }
            if (Parse.Compiler_.Current_class != this)
                return null;
            foreach (Type imp in Import_)
            {
                Variable Result = imp.Search_const(Name);
                if (Result != null) return Result;
            }
            if (!Parse.Compiler_.Test()) return null;
            foreach (Type im in Parse.Compiler_.Current_fun.Test_import_)
            {
                Variable Result = im.Search_const(Name);
                if (Result != null) return Result;
            }
            return null;
        }
        
        /*
        
        METHOD Check_recursive :
        PUSH comp.Current_class = THIS :
            BOOL any|_recursive = FALSE
            FOR f IN Method[] :
                CASE f.Check_recursive ? any = TRUE ;
            ;
            FOR f IN Test[] :
                CASE f.Check_recursive ?
                     Parse.Line = f.Line_start
                     Parse.Err("Test must not be recursive"._Etest) ;
            ;
            CASE Construct != NONE && Construct.Check_recursive ? any = TRUE ;
            CASE Destruct != NONE && Destruct.Check_recursive ? any = TRUE ;
            CASE !any && Modifiers['RECURSIVE'] ?
                Parse.Line = 1
                
                Parse.Warn("Class"._Wclass4 " " Whole_name 
                " " ("is marked as RECURSIVE but this is not correct"._Wis2))
            ; 
        ; .

        METHOD Check_structure_recursive(
            {Type} St|ructure_to_check,
            INT Total_struc|tures_count)
            :
        PUSH comp.Current_class = St.In_class_ :
            Parse.Line = St.Line
            {Type} all_t|ypes_used_to_define_fields_of_structure[]
            add_types_of_struc(St, all_t[])
            FOR i|dummy IN [1 TO Total_struc * 2] :
                INT was_count|_all_types = all_t[].Count
                FOR t IN all_t[] :
                    CASE t.Kind != 'STRUCTURE' ? CONTINUE t ;
                    add_types_of_struc(t, all_t[]) ;
                CASE St IN all_t[] ?
                     Parse.Err("Recursive definition of the structure type"
                     ""._ErecurSt ": " St.Whole_name) ==>
                ;
                CASE was_count == all_t[].Count ? BREAK i ;
            ;
        ; .

        FUN add_types_of_struc|ture(
        {Type} St|tructure_type, {Type} All_t|ypes[])
        	:
            FOR f IN St.Field[] :
                CASE f.Type_ !IN All_t[] ? All_t[] << f.Type_ ;
            ; .

        */
        public void Check_recursive()
        {
            Parse.Compiler_.Current_class = this;
            bool any = false;
            foreach (Function f in Method)
                any = any || f.Check_recursive();
            if (Construct_method != null)
                any = any || Construct_method.Check_recursive();
            if (Destruct_method != null)
                any = any || Destruct_method.Check_recursive();
        }

        /*
        
        METHOD Check_tested :
			CASE !Class_needs_testing(THIS) ? ==> ;
            -------------------------------------------- 'If class tested?'
            CASE Tested || Method[].Count + Test[].Count == 0
            	 ?
                 ==> ;
            CASE comp.Verbose ?
                 << "Analysing if class"._Mana 
                    " " Whole_name " " ("tested"._Mtes ) #NL
            ;
            PUSH comp.Current_class = THIS :
                 STR path|_test_results = comp.Destination
                 path = path.Trailing_slash Final_name ".test"
                 CASE path.Exists ?
                      CASE Modifiers['UNTESTED'] ?
                           PUSH Parse.Line = Line_class :
                           		warn("Class is marked UNTESTED"._Wclass5) ;
                      ;
                      analyse_tests(path, "")
                      CASE Base_.Modifiers['ABSTRACT'] ?
                           path = comp.Destination.Trailing_slash
                           "" Final_name "." Base_.Final_name ".test"
                           CASE path.Exists && total > 0 ?
                                PUSH comp.Current_class = Base_ :
                                     Base_.analyse_tests(path,
                                     (" (call from"._Mcall )
                                     " " Whole_name ")")
                                     total += Base_.total
                                     tested += Base_.tested  ;
                           ;
                      ;
                      ------------------------------- 'Report tested percentage'
                      CASE total > 0 ?
                           Console_color(color_depending_on_percentage(tested,
                               total))
                           Tested_actually = tested * 100.0 / total
                           CASE Tested_actually < Tested_by - 5 ?
                                Console_color({colors}.'RED') ;
                                
                           << "Class"._MClass " " Whole_name 
                           " " ("was tested on"._MWasTested) 
                           " " Tested_actually.Str " %"
                           
                           CASE Tested_by < 100 ?
                                << " (" ("proclaimed"._MProclaimed )
                                ": " Tested_by.Str " %)"
                           ;
                           << #NL 
                           Console_color({colors}.'SILVER') ;
                      //DEBUG: << "Tested_actually = " Tested_actually.S
                      //			" Tested_by = " Tested_by.S
                      //			", x<y-5?" (Tested_actually < Tested_by-5).S
                      //			"" #NL ;
                      CASE Tested_actually < Tested_by - 5 && (
                           ! Modifiers['ABSTRACT']) && total > 0
                           ?
                           Detect_descr('UNTESTED', "tested lines:" tested.Str
                           ", total:" total.Str " (Base:" Base_.tested.Str 
                           "/" Base_.total.Str "), "
                           "" ("percents tested actually"._EPercentsTested)
                           ": " Tested_actually.Str 
                           " " ("though at least was proclaimed"._EThough
                           ": ") Tested_by.Str )
                      ;
                      Testing_done(THIS, Tested_actually)
                      ==>
                 ;
                 Testing_failed(THIS)
                 CASE comp.Verbose ?
                      << "- " "file"._Mfile " " path 
                         " " ("was not created"._Mwasnot ) "." #NL
                 ;
                 CASE !Modifiers['ABSTRACT'] ?
                      FOR m IN Method[] :
                          CASE m.Block[].Count > 0 ?
                               Detect_descr('UNTESTED', 
                               "Method"._Mmethod 
                               " " m.Whole_name 
                               " " ("is not empty"._Misnot ) ) 
                               BREAK m ;
                      ;
                 ;
                 FOR t IN Test[] :
                     CASE t.Param[].Count == 0 ?
                          BOOL has_tests|_to_execute = TRUE ;
                 ;
                 CASE has_tests && Tests_available ?
                      Parse.Err("Tests failed"._Etest2) ;
            ; .
            
        FUN color_depending_on_percentage( INT Tested|_lines, 
            INT Total|_lines ) ==> {Console}.{colors}
            :
            ----------------------------------- 'green if 100%, olive otherwise'
            CASE Tested >= Total ? RESULT = {colors}.'GREEN' ==> ;
            RESULT = {colors}.'OLIVE' .
        */
        public void Check_tested()
        {
            if (Tested) return;
            if (Method.Count == 0) return;
            Parse.Compiler_.Current_class = this;
            string path = StringFunctions.Trailing_slash(Parse.Compiler_.Destination) +
                Final_name + ".test";
            if (File.Exists(path))
            {
                if (Modifiers[(int)Class_mod.UNTESTED])
                    warn("Class is marked UNTESTED");
                analyse_tests(path);
                return;
            }
            //-------------------------- 'comment to compile primary compiler:'
            //Detect(Class_mod.UNTESTED);
            //--------------------------
            if (Test.Count > 0)
                Parse.Err("Tests failed");
        }
        
        /*
        INT tested|_lines
        INT total|_lines
        INT untested|_lines

        METHOD analyse_tests|_results_of_class( 
            STR Path|_test_results_file,
            STR Call|_from_class)
            :
			CASE Method[].Count == 0 ? ==> ; 
            ------------------------------- 'Load testing results'
            tf|ile_text_tests_temp = {Text_file}(Path = Path)
            
            p|arse_temp = {Parser}(Compiler_ = comp, Class_ = THIS,
            	Warning_80= comp.Warning_80)
            	
            NONE = tf.Load_strings(p.Source[])
            INT index|_line_in_class_source
            tested = 0
            untested = 0 
            total = 0
            ------------------------------- 'Report untested lines'
            FOR line IN [0 TO p.Source[].Count-1] :
                p.Line = line
                p.Pos = 0
                p.Skip_sp
                CASE p.End_of_line ? 
                     p.Fin
                     CONTINUE line ;
                --------------------------- 'skip source: in first line'
                CASE p.Line == 0 && p.Symbol("source") ?
                     CASE p.Symbol(":") ? CONTINUE line ;
                ;
                --------------------------- 'until * (assertion failed reports)'
                CASE p.Next_symbol("*") ? BREAK line ;
                FOR x|dummy IN [0 TO p.Last] :
                    p.Skip_sp
                    CASE p.End_of_line ? BREAK x ;
                    index += 1
                    INT n|umber_executions = p.Integer
                    CASE n < 0 ? CONTINUE x ;
                    total += 1
                    CASE n == 0 && untested < 5 ?
                         untested += 1
                         Parse.Line = index-1
                         //comp.Current_class.Detect('UNTESTED')
                         warn("Untested line"._Wuntested " " Call) ;
                    CASE n > 0 ? tested += 1 ;
                ;
            ;
            -------------- 'Check if total lines not less then at compile stage'
            CASE total == 0 && Total_lines_in_test > 0 ?
                 err("Too low lines in test report"._Etoo " (" total.Str 
                 " " ("instead of"._Einsteadof) 
                 " " Total_lines_in_test.Str ")") ;
            ------------------------------- 'Report assertions failed'
            INT assertions|_reported
            CASE p.Symbol("*") ?
                 p.Pos = p.Last + 1
                 p.Fin
                 FOR line IN [p.Line TO p.Source[].Count-1] :
                     p.Line = line
                     p.Pos = 0
                     CASE p.End_of_line ? CONTINUE line ;
                     INT a|ssertion_failed_in_line = p.Number
                     p.Skip_sp
                     
                     STR formatted|_assertion_description = p.Source[
                         p.Line].[p.Pos TO *].Trim
                         
                     CASE formatted != "" ? formatted = ": " formatted ;
                     assertions += 1
                     CASE assertions <= 10 ?
                          Parse.Line = a
                          
                          Parse.Err("Assertion failed"._Eassert 
                          " " Call formatted)
                          
                     ELSE BREAK line ;
                 ;
            ; .
        */
        private void analyse_tests(string Path_test)
        {
            Text_file tf = new Text_file(Path_test);
            Parser p = new Parser();
            p.Compiler_ = Parse.Compiler_;
            tf.Load_strings(p.Source);
            int index = 0;
            int total = 0;
            int tested = 0;
            int untested = 0;
            for (int line = 0; line < p.Source.Count; line++)
            {
                p.Line = line;
                p.Pos = 0;
                if (p.Next_symbol("*")) break;
                for (int x = 0; x <= p.Last(); x++)
                {
                    p.Skip_sp();
                    if (p.End_of_line()) break;
                    index++;
                    int N = p.Integer();
                    if (N < 0) continue;
                    total++;
                    if (N == 0)
                    {
                        if (untested++ < 5)
                        {
                            Parse.Line = index - 1;
                            //--------------------- 'comment to compile primary'
                            //Detect(Class_mod.UNTESTED);
                            //---------------------------
                            warn("Untested line");
                        }
                    }
                    else tested++;
                }
            }
            int assertions = 0;
            if (p.Symbol("*"))
            {
                p.Pos = p.Last() + 1;
                p.Fin();
                for (int line = p.Line; line < p.Source.Count; line++)
                {
                    p.Line = line;
                    p.Pos = 0;
                    Parse.Line = p.Number();
                    if (assertions++ < 10)
                        Parse.Err("Assertion failed");
                    else break;
                }
            }
            if (Parse.Compiler_.Verbose)
                Console.WriteLine("Class " + Name() + " tested on " + (tested * 100.0 / total).ToString() +
                    " %");
        }

        /*
        {Type} all_hard_|references_to_classes_[]

        METHOD Collect_ref|erences_to_classes :
			//DEBUG: << "************************Collect_ref for " Names[0] #NL ;
            FOR v IN Field[] :
                CASE v.Type_.Kind != 'CLASS' ? CONTINUE v ;
                CASE v.Names[0].[*] == "_" ? CONTINUE v ;
                {Type} t|ype_to_collect = v.Type_
                FOR i|dummy IN [1 TO 10_000] :
                     CASE t !IN all_hard_[] ?
                          //DEBUG: << "var " v.Names[0] 
                          //			" type " t.Names[0] #NL ; 
                          all_hard_[] << t ;
                     t = t.Base_
                     CASE t == NONE ? BREAK i ;
                ;
            ; .
        */
        private List<Type> all_hard_ = new List<Type>();

        public void Collect_ref()
        {
            foreach (Variable v in Field)
            {
            	if (v.Type_ == null) continue; // ????????????????
                if (v.Type_.Kind != Kind_type.CLASS) continue;
                if (v.Names[0].Substring(v.Names[0].Length - 1, 1) == "_") continue;
                if (!all_hard_.Contains(v.Type_))
                    all_hard_.Add(v.Type_);
            }
        }

        /*
        
        METHOD Check_ref|erences_not_recursive :
        PUSH comp.Current_class = THIS :
            {Type} hard|_references[]
            FOR t IN all_hard_[] :
                hard[].Clear
                hard[] << t
                FOR c IN comp.All_classes[] :
                    CASE c !IN hard[] && (
                         c.Is_descend(t, comp) || t.Is_descend(
                         c, comp))
                         ?
                         hard[] << c ;
                ;
                FOR i|dummy IN [0 TO comp.All_classes[].Count] :
                    CASE THIS IN hard[] ?
                         message_hard_ref(t) ;
                    CASE !add_types_ref(hard[]) ?
                         BREAK i ;
                ;
            ;
        ; .
        */
        static int CNT_check_ref;

        public void Check_ref()
        {
            if (++CNT_check_ref == 4)
            { }
            Parse.Compiler_.Current_class = this;
            List<Type> hard = new List<Type>();
            foreach (Type t in all_hard_)
            {
                hard.Clear();
                hard.Add(t);
                for (int i = 0; i <= Parse.Compiler_.All_classes.Count; i++)
                {
                    if (hard.Contains(this)) message_hard_ref(t);
                    if (!add_types_ref(hard)) break;
                }
            }
        }

        /*
        
        METHOD add_types_ref|erenced(
        	{Type} Hard|_references[]) ==> BOOL
        	:
            FOR t IN Hard[] :
                CASE t == THIS ? CONTINUE t ;
                FOR r IN t.all_hard_[] :
                    CASE r IN Hard[] ? CONTINUE r ;
                    Hard[] << r
                    RESULT = TRUE ;
            ; .
        */
        private bool add_types_ref(List<Type> hard)
        {
            bool Result = false;
            int was_hard_last = hard.Count-1;
            for (int i = 0; i <= was_hard_last; i++)
            {
                Type t = hard[i];
                if (t == this) continue;
                foreach (Type r in t.all_hard_)
                {
                    if (hard.Contains(r)) continue;
                    hard.Add(r);
                    Result = true;
                }
            }
            return Result;
        }

        /*
        
        METHOD message_hard_ref|erence_is_recirsive(
        	{Type} T|ype_of_vars)
        	:
            FOR v IN Field[] :
                CASE v.Type_ != T || v.Is_weak ? CONTINUE v ;
                Parse.Line = v.Line
                
                Parse.Err("Field"._Efield4 " " v.Names[0] 
                " " ("is a hard reference creating "
                "a hard loop reference. Use weak_ reference instead."._Eis9))
            ; .
        */
        private void message_hard_ref(Type t)
        {
            foreach (Variable v in Field)
            {
                if (v.Type_ != t || v.Is_weak()) continue;
                Parse.Line = v.Line;
                Parse.Err("Field " + v.Names[0] + " is a hard reference creating " +
                "a hard loop reference. Use weak_ reference instead.");
            }
        }

        /*
        
        METHOD Has_destructors
        	|_in_class_or_its_relatives ==> BOOL
        	:
            CASE Destruct != NONE ? RESULT = TRUE ==> ;
            {Compiler} c|ompiler_temp = comp
            FOR t IN c.All_classes[] :
                CASE t.Is_descend(THIS, c) || Is_descend(t, c) ?
                     RESULT = TRUE ==> ;
            ; .
            

        METHOD Scan_string_const|ants_concatenation(INT Where|_dummy) ==> STR :
			//DEBUG:
			//      CASE Where == 3 ?
			//           << "Scan_string_const: " Parse.Rest_of_line >> ;
			//;
            ------------------------ 'named STR constans and "literals"'
            BOOL ending|_characters_included
            FOR i|dummy IN [Parse.Pos TO Parse.Last + 1000000] :
                ----------------------------------------- 'skip spaces'
                CASE Parse.Next_char IN #CR #LF ?
                     CASE ending ?
                          RESULT = RESULT Parse.Next_char
                          Parse.Skip_char
                          CONTINUE i ;
                ;
                CASE Parse.Next_char.Ord < #SP.Ord ?
                     Parse.Skip_char
                     CONTINUE i ;
                CASE Parse.Symbol("@") ?
                     ending = TRUE
                     CASE Parse.End_of_line ? Parse.Fin ;
                     CONTINUE i ;
                ----------------------------------------- 'string literal'
                BOOL s_const|_is_next = Parse.Next_symbol("#")
                	 s_const ||= Parse.Next_symbol(#QU)
                	 s_const ||= Parse.Next_symbol("''")  
                CASE s_const ?
                     RESULT = RESULT Parse.String_const(TRUE)
                     Parse.Skip_sp_only
                     
                     CASE Parse.End_of_line ? 
                          Parse.Fin 
                          CASE ending ? RESULT = RESULT #NL ;
                     ;
                     //DEBUG:
                     //	CASE Where == 3 ?
                     //	     << "RESULT = [" RESULT.Replace_all(#NL, "\n"#LF#CR)
                     //	        "]"#NL ;
                     //;
                     CONTINUE i ;
                ----------------------------------------- 'class constant from'
                {Type} cc|lass_current = THIS
                BOOL want_named = FALSE
                CASE Parse.Next_symbol("{") ?
                     cc = Find_type(Parse.Scan_type)
                     Parse.Wait(".") 
                     want_named = TRUE ;
                ----------------------------------------- 'named string const'
                CASE Parse.Next_char.Lower != Parse.Next_char.Upper ?
                     STR name|_constant = Parse.Ident
                     {Var} const|ant = cc.Search_const(name, TRUE)
                     CASE const == NONE ? 
                          Parse.Err("Constant"._Econst2 " " name 
                          " " ("was not found in class"._Ewasnot2) 
                          " " cc.Whole_name)
                     ;
                     CASE const.Is_array ?
                          Parse.Err("Constant"._Econst3 " " name 
                          " " ("is array, not supported"._Eis10))
                     ;
                     CASE const.Type_.Kind != 'STR' ?
                          Parse.Err("Constant"._Econst4 " " name 
                          " " ("is of type"._Eis11)
                          " " const.Type_.Kind.Name 
                          ", " ("not 'STR'"._Enot))
                     ;
                     RESULT = RESULT const.Str_c ==>
                     //DEBUG:
                     // CASE Where == 3 ?
                     //      << "NAMED CONST: [" RESULT.Replace_all(
                     //      #NL, "\n"#LF#CR) "]" >> ;
                     //;
                ELSE 
                	CASE want_named ? 
                	     Parse.Err("Waiting for a named string constant") ;
                	==>
                ;
            ; .
        
        METHOD Create_constants_calc
        	|ulation_function
        	:
            -------------------------------- 'if there are constant expressions'
            CASE Constant_expr[].Count == 0 ? ==> ;
            -------------------------------- 'find {System_functions} class'
            {Type} sys|tem_function_class = Find_type("{System_functions}")
            CASE sys == NONE ? 
                 Parse.Warn("{System_functions} was not found: could not "
                 "re-calculate constant expressions"._Wsystem) ==> ;
            -------------------- 'create a test function to calculate constants'
            f|unction_to_calculate_constant_expressions = {Fun}(Line_start = -1,
                Is_test = TRUE, A_Name_1 = "Calculate_constants",
                Parse = Parse, Modifiers['STATIC'] = TRUE), >> Test[]
                
            f.Set_final_name("Calculate_constants")
            
            resulting|_strings_variable = {Var}(Line = -3,
                Names[] << "Out", Is_array = TRUE, 
                Type_ = comp.TYPE_STR),
                >> f.Local_var[]
                
            resulting.Set_final_name("Out")
            ------------------------------- 'for each constant expression'
            FOR e IN Constant_expr[] :
                ------------------------ 'except single CONST expressions'
                CASE e.Total_const == 0 || e.Is_array ? CONTINUE e ;
                {Var} v|ariable_temp = result_of_type(e.Type_expr, f)
                
                st|atement_calculating_const_expr = {Assign}(Line = 0,
                              Function_ = f, Level = 0, Pos= 0,
                              Dest = {Expr}(Operation = 'VAR', Var_arg = v),
                              Source = e), >> f.Block[]
                              
                gen_save_result(e.Total_const, v, f) ;
            ---------------------------- 'finally save resulting Out[] to file'
            param1|_value = {Expr}(Operation = 'VAR', Var_arg = resulting),
                OWNED BY f
                
            param2|_value = {Expr}(Operation = 'CONST', Var_arg = {Var}(
                Line = 0, Is_const = TRUE, Type_ = comp.TYPE_STR,
                Str_c = Final_name ".constants")),
                OWNED BY f
                
            text|_save_statement = {Assign}(Line= 0, Pos= 0, Level= 0,
                Function_= f, 
                Source= {Expr}(
	                Operation= 'FUN', 
	                Fun_= sys.Find_fun("Save_DynAStr_to_file", TRUE),
	                Items_[] << param1,
	                Items_[] << param2)), 
                >> f.Block[] .
                          
        FUN result_of_type(
        	{Type} T|ype_of_variable, {Fun} F|unction) ==> {Var}, NEW
            :
            --------------------------------- 'if already created, return it:'
            FOR v IN F.Local_var[] :
                CASE !v.Is_array && v.Type_ == T ? RESULT = v ==> ;
            ;
            RESULT = {Var}(Line = 0, Type_ = T),
            	>> F.Local_var[]
            	
            RESULT.Set_final_name("v" F.Local_var[].Count.Str) .
                
        METHOD gen_save_result(
            INT Index|_of_constant,
            {Var} V|ariable_to_save,
            {Fun} F|unction_calculating_constants)
            :
            ---------------------------- 'two lines: number of const and value'
            source|_expression = {Expr}(Operation = 'VAR', Var_arg = V),
                OWNED BY F
                
            CASE V.Type_.Kind ?
            ['BOOL']: {Fun} conv|ert_function = comp.SYSFUN_BoolStr
            //['BYTE', 'INT', 'ENUM']: conv = comp.SYSFUN_Str
            ['INT', 'ENUM']: conv = comp.SYSFUN_Str
            ['REAL']: conv = comp.SYSFUN_RealStr
            ['STR']: conv = comp.SYSFUN_StrHex16
            ['CLASS', 'STRUCTURE']: ==> ;
            ------------------------------------------- 'Out[] array'
            {Var} out|put_array = F.Search_var("Out", TRUE)
            ------------------------------------------- 'dest: Out[]'
            dest|ination_array_var = {Expr}(
                Operation = 'VAR', Var_arg = out), OWNED BY F
            ------------------------------------------- 'argument appending'
            arg|ument_appending = {Expr}(Operation = 'VAR', Var_arg = V),
                OWNED BY F
            ------------------------------------------- 'statement saving #'
            st|atement_save = {Assign}(Function_= F,
                Work= 'APPEND', Line= 0, Pos= 0, Level= 0,
                Dest= dest,
                Source = {Expr}(Operation = 'CONST', Var_arg = {Var}(Line = 0,
                   Type_ = comp.TYPE_STR, Str_c = Index.Str))),
                >> F.Block[]
            ------------------------------------------- 'statement saving value'    
            st = {Assign}(Function_ = F, Work= 'APPEND',
            	Line= 0, Pos= 0, Level= 0,
                Dest= dest,
                Source= {Expr}(Operation= 'FUN', Fun_= conv, Items_[] << arg)),
                >> F.Block[] .
        
        
        METHOD Optimize|_by_a_list_of_flags :
            ----------------------- 'start new statements index from new p[age'
            comp.Total_st += 99
            comp.Total_st -= comp.Total_st % 100
            ----------------------- 'start new objects index from new page'
            temp|_var = {Var}(Line = 0)
            INT curr|ent_index = {System_functions}.Total_obj_index(temp)
            INT next|_index = curr + 99
            next -= next % 99
            FOR i|dummy IN [curr+1 TO next] :
                temp = {Var}(Line = 0) ;
            ------------------------ 'optimize functions of the class'
            FOR if IN [Method[].Count-1 DOWNTO 0] :
                {Fun} f|unction_at_if = Method[if]
                PUSH comp.Current_fun = f :
                	 f.Optimize_now(f.Block[], 0) ; 
            ; .
            
--------- 'control REUSED comments'

INT Reused_comments|_lines[]

METHOD Warn_not_used_reused|_comments :
    CASE Reused_comments[].Count == 0 ? ==> ;
    FOR r INDEXING STR IN Reused_comments[] :
        //STR s|tring_with_line_numbers << ", " (r+1).Str 
        STR comm|ent_text = Parse.Source[r]
        comm = comm.[comm.Find("'")+1 TO *]
        comm = "'" comm.[0 TO comm.Find("'")]
        FOR i IN [r+1 TO Parse.Source[].Count-1] :
            STR s|ource_line = Parse.Source[i]
            CASE comm IN s ? BREAK i, CONTINUE r ;
        ;
        PUSH Parse.Line = r :
             Parse.Warn("Block comment marked as REUSED but it is not re-used "
             "actually"._WReusedNotUsed
             ": " Parse.Source[r].Trim) ;
    ; .

--------- 'check if array parameters are declared as dynamic ambigouously'

METHOD Check_dynamic_array_parameters :
    FOR f IN Method[] :
        CASE f.Modifiers['NATIVE_FUN'] 
             || f.Overload_base_!=NONE || f.Overloaded_[].Count > 0
             || !f.Modifiers['PUBLIC'] && f.Names[0].[0] == f.Names[0].[0].Lower
             ?
             CONTINUE f ;
    	STR rep|ort_parameters = ""
        FOR p IN f.Param[] :
            CASE p.Is_array && !p.Is_fixed 
                 && !p.Has_changing_size && !p.Passed_as_dynamic
                 ?
	             CASE "dyn" IN Replace_all(p.Whole_name.Lower, "|", "") ? 
	                  CONTINUE p ;
                 rep = rep ", " p.Whole_name ;
        ;
    	CASE rep.Len == 0 ? CONTINUE f ;
    	------------------------------------
    	CASE f.Modifiers['ABANDONED_FUN'] ? CONTINUE f ;
    	PUSH Parse.Line = f.Line_start :
    	     Parse.Warn(f.Whole_name " - " ("Method has parameters which "
    	     "declared as dynamic arrays though these do not use specific "
    	     "operations and could be safely replaced with fixed arrays"
    	     ""._WDynamicCanBeFixed)
    	     " " ("(Or use 'dyn' as a part of parameter name to remove this "
    	     "varning)"._MDyn) ":"#NL rep.[1 TO *]) ;
    ; .

METHOD Find_similar|_names(
STR Base|_name, STR List|_similar[], BOOL Allow_imported) 
    :
	FOR i IN [1 TO 3] :
		PUSH Max_len_diff = i :
		     Find_similar_1(Base, List[], Allow_imported) ;
	    CASE List[].Count > 1 ? ==> ;
	; .
	
INT Max_len_diff|erence
	
METHOD Find_similar_1(
STR Base|_name, STR List|_similar[], BOOL Allow_imported), RECURSIVE
	: 
	Max_diff= Max_len_diff
    FOR v IN Field[] :
        FOR n IN v.Names[] :
            CASE n IN List[] ? CONTINUE n ;
            CASE Is_similar_to(n, Base, TRUE) ? List[] << n ;
        ;
    ; 
    FOR m IN Method[] :
        FOR n IN m.Names[] :
            CASE n IN List[] ? CONTINUE n ;
            CASE Is_similar_to(n, Base, TRUE) ? List[] << n ;
        ;
    ;
    FOR v IN Const[] :
        FOR n IN v.Names[] :
            CASE n IN List[] ? CONTINUE n ;
            CASE Is_similar_to(n, Base, TRUE) ? List[] << n ;
        ;
    ; 
    FOR s IN Structures_[] :
        FOR v IN s.Field[] :
            FOR n IN v.Names[] :
            	CASE n IN List[] ? CONTINUE n ;
	            CASE Is_similar_to(n, Base, TRUE) ? List[] << n ;
	        ;
        ;
    ;
    CASE Base_ != NONE ? 
         Base_.Find_similar_1(Base, List[], FALSE) ;
    CASE !Allow_imported ? ==> ;
    FOR im IN Import_[] :
        im.Find_similar_1(Base, List[], FALSE)
    ; .	
    
METHOD Find_similar_2|_fields_only(
STR Base|_name, STR List|_similar[], INT Max_len_diff), RECURSIVE
	: 
	Max_diff= Max_len_diff
    FOR v IN Field[] :
        FOR n IN v.Names[] :
            CASE n IN List[] ? CONTINUE n ;
            CASE Is_similar_to(n, Base, TRUE) ? List[] << n ;
        ;
    ;
    CASE Base_ == NONE ? ==> ;
    Base_.Find_similar_2(Base, List[], Max_len_diff) .     

INT Max_diff= 3

METHOD Find_similar_fields(
STR Base|_name, STR List|_similar[]) 
    :
	FOR i IN [1 TO 3] :
	    Find_similar_2(Base, List[], i)
	    CASE List[].Count > 1 ? ==> ;
	; .
	

    
METHOD Is_similar_to(
STR Name1|_checking, STR Name2|_base, BOOL Can_swap) ==> BOOL, 
RECURSIVE
    :
    INT diff|erence = Name1.Len - Name2.Len 
    CASE diff < 0 ? diff = -diff ;
    CASE diff > Max_diff ? ==> ;
    CASE Name1==Name2 ? ==> ;
    STR name1|_lowered= Name1.Lower     
    STR name2|_lowered= Name2.Lower
    CASE name1.Len < name2.Len ? 
         CASE Can_swap ?
              name1= name2
              name2= Name1.Lower 
         ELSE ==> ;
    ;
    CASE Name1.Len == Name2.Len ? 
         CASE name1==name2 ? RESULT= TRUE ==> ;
         FOR i IN [0 TO Name1.Len-1] :
             CASE name1.[i]!=name2.[i] ? INT count_diff|erent_chars += 1 ;
         ;
         RESULT = count_diff <= Max_diff && count_diff <= name1.Len / 2 ==>
    ;
    CASE name1.[0]==name2.[0] && name1.[*]==name2.[*]
         || name1.[0 TO 1]==name2.[0 TO 1]
         || name1.[*-1 TO *]==name2.[*-1 TO *]
         ? 
         NONE 
    ELSE ==> ;
    FOR i IN [0 TO name1.Len-1] :
        RESULT = Is_similar_to(name1.[0 TO i-1] name1.[i+1 TO *],
        	name2, FALSE)
        	
        CASE RESULT ? ==> ;
    ; .

    
	
        */
    }
}
/*
END
*/

